dlzn-ui 2.0.54 → 2.0.56

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -109,7 +109,7 @@
109
109
  "> 1%",
110
110
  "not dead"
111
111
  ],
112
- "version": "2.0.54",
112
+ "version": "2.0.56",
113
113
  "scripts": {
114
114
  "dev": "vite --config play/vite.config.ts"
115
115
  }
@@ -0,0 +1,17 @@
1
+ ---
2
+ description: 修改代码后必须通过项目 TypeScript 校验(pnpm type-check)
3
+ alwaysApply: true
4
+ ---
5
+
6
+ # 修改后 TypeScript 校验
7
+
8
+ 在本仓库**每次完成代码修改**(含新增/删除文件)后,结束任务前必须执行类型检查并处理与本次改动相关的结果:
9
+
10
+ ```bash
11
+ pnpm type-check
12
+ ```
13
+
14
+ - 等价于 `vue-tsc --build`,以项目 `tsconfig` 为准;不要仅用 `vue-tsc --noEmit` 代替。
15
+ - 若报错路径属于**本次修改的文件**,必须修到通过再结束。
16
+ - 若报错在未改动的历史文件,说明现状即可;不要为通过全量检查而扩大无关改动范围。
17
+ - 与页面迁移 skill 一致:除 TS 外,对改动的 `.vue`/`.ts` 仍应执行 `pnpm eslint <路径>`。
@@ -37,7 +37,7 @@ Task Progress:
37
37
  - [ ] 3. 在 qc-ui 同路径创建 index.vue
38
38
  - [ ] 4. 按映射表转换配置
39
39
  - [ ] 5. 内联新增/编辑表单(不迁移 PageListItemForm)
40
- - [ ] 6. 对**本次修改的文件**执行 `pnpm eslint <路径>` 与 `pnpm vue-tsc --noEmit`,确认无 ESLint/TS 报错后再结束
40
+ - [ ] 6. 对**本次修改的文件**执行 `pnpm eslint <路径>` 与 `pnpm type-check`,确认无 ESLint/TS 报错后再结束(见 `.cursor/rules/type-check-after-edit.mdc`)
41
41
  ```
42
42
 
43
43
  ### Step 1:分析原页面
@@ -165,8 +165,22 @@ $confirm({
165
165
  | `responseType: 'blob'` 导出 | `apis.export.method: '.../export'`(POST) |
166
166
  | `refreshCache` 且原定义为 delete | `$alova.Delete('.../refreshCache', ...)` |
167
167
  | `unlock/{userName}` 且无 method | `$alova.Get('monitor/logininfor/unlock/${userName}', ...)` |
168
+ | `useDataResult: false`(如 online/list) | list 请求保留 `meta: { useDataResult: false }`(响应 `{ rows, total }` 在顶层,不在 `data` 内) |
169
+ | `online/{tokenId}` + `method: 'delete'` | `$alova.Delete('monitor/online/${row.tokenId}', undefined, { meta: { useSuccessMsg: true } })` |
168
170
 
169
- 路径占位符 `{userName}`、`{id}` 在目标项目中通常拼进 URL 字符串,如 `` `monitor/logininfor/unlock/${row.userName}` ``。
171
+ 路径占位符 `{userName}`、`{id}`、`{tokenId}` 在目标项目中通常拼进 URL 字符串,如 `` `monitor/logininfor/unlock/${row.userName}` ``。
172
+
173
+ **原 api 带 `useDataResult: false` 的 list**(如 `getOnlineList`):
174
+
175
+ ```typescript
176
+ list: {
177
+ method: (o: Record<string, any>) =>
178
+ $alova.Get('monitor/online/list', {
179
+ meta: { useDataResult: false },
180
+ params: o,
181
+ }),
182
+ },
183
+ ```
170
184
 
171
185
  **`$alova` 参数个数**(勿与 axios 混用;写完后对照项目内已有调用):
172
186
 
@@ -205,8 +219,37 @@ list: {
205
219
  | `title: 'xxx'` | `title: 'xxx'`(不变) |
206
220
  | `type: 'checkbox'` | 由 `apis.delete.showBatch: true` 自动处理 |
207
221
  | `field: 'c-action'` | `colKey: '_operation'` |
222
+ | `field: 'c-action'` + `fixed: 'right'` | **不要**写 `fixed: 'right'`;TTable 对 `colKey: '_operation'` 默认右固定 |
208
223
  | 删除按钮 | 由 TPageList 根据 `apis.delete` 自动追加 |
209
224
  | `field: 'remark'` / `title: '备注'` | 加 `resize: { maxWidth: 300 }`(内容可能很长) |
225
+ | slot / 模板拼 `${row.xxx}%` | `align: 'right'` + `FormatNumber` | 见下方「百分比列」 |
226
+
227
+ ### 百分比列
228
+
229
+ 原项目用 slot 或 `cell: (_, { row }) => \`${row.usage}%\`` 拼百分号时,迁移改用 `FormatNumber`:
230
+
231
+ - **靠右对齐**:数字/百分比列加 `align: 'right'`
232
+ - **空值安全**:后端字段(如 `usage`)可能为空/无效,`FormatNumber` 返回空字符串,避免 `undefined%`
233
+ - **勿手写 `%`**:由 `config.unit: 'percent'` 格式化
234
+
235
+ ```typescript
236
+ {
237
+ align: 'right',
238
+ cell: {
239
+ component: 'FormatNumber',
240
+ config: {
241
+ style: 'unit',
242
+ unit: 'percent',
243
+ },
244
+ },
245
+ colKey: 'usage',
246
+ title: '已用百分比',
247
+ }
248
+ ```
249
+
250
+ 纯数字列(非百分比)同理:`align: 'right'` + `cell: { component: 'FormatNumber' }`(无 `unit`)。
251
+
252
+ 参考:`qc-ui/src/views/monitor/server/index.vue` 磁盘「已用百分比」列。
210
253
 
211
254
  ### 权限
212
255
 
@@ -214,7 +257,7 @@ list: {
214
257
 
215
258
  ### 即时请求操作需 popconfirm
216
259
 
217
- `operations` 中点击即发请求的操作(刷新缓存、同步、重置等),**必须**用 `popconfirm` 二次确认,不用 `onClick` 直接请求:
260
+ `operations` 与操作列 `Buttons` 中点击即发请求的操作(强退、解锁、刷新缓存、同步、重置等),**必须**用 `popconfirm` 二次确认,不用 `onClick` 直接请求;原项目 `$confirm` + `$api` 一律改为 `popconfirm.onConfirm` + `$alova`:
218
261
 
219
262
  ```typescript
220
263
  {
@@ -233,6 +276,12 @@ list: {
233
276
 
234
277
  新增/编辑等打开弹窗的操作不需要 popconfirm。
235
278
 
279
+ ### 仅列表 + 行内操作(无 CRUD)
280
+
281
+ 部分 monitor 页只有 list 与行内自定义按钮(如在线用户强退),**不配置** `apis.delete` / `export`,也无需 `tableOtherProps.rowKey`(无批量删)。操作列手写 `Buttons` + `popconfirm`;成功后 `pageListRef.value!.query()` 刷新。原项目未写 `permission` 的按钮,目标也**不要**自行添加。
282
+
283
+ 参考:`qc-ui/src/views/monitor/online/index.vue`(原 `yq-monitor-front/src/views/monitor/online/index.vue`)。
284
+
236
285
  ### 只读详情弹窗($dialog)
237
286
 
238
287
  原项目用旧式 `$dialog({ title, showCancel: false, confirmText: '关闭' }, Component)` 展示只读详情时,目标项目**直接用 `h(TForm, ...)` 内联**,与 `formItemMap` 共用,**不单独建 `modules/Detail.vue`**:
@@ -296,6 +345,9 @@ onClick: () => {
296
345
  | 系统页参考(dlzn-ui) | `dlzn-ui/packages/dlzn-ui/views/system/post/index.vue` |
297
346
  | 含 dateRange + 刷新缓存 | `dlzn-ui/packages/dlzn-ui/views/system/dict/index.vue` |
298
347
  | 只读详情弹窗 | `qc-ui/src/views/monitor/operlog/index.vue` |
348
+ | 仅列表 + 行内强退 | `qc-ui/src/views/monitor/online/index.vue` |
349
+ | 原:仅列表 + 行内强退 | `yq-monitor-front/src/views/monitor/online/index.vue` |
350
+ | 百分比列 FormatNumber | `qc-ui/src/views/monitor/server/index.vue`(usage 列) |
299
351
 
300
352
  更多 before/after 片段见 [examples.md](examples.md)。
301
353
 
@@ -303,12 +355,15 @@ onClick: () => {
303
355
 
304
356
  - [ ] 路径与原项目一致(`src/views/.../index.vue`)
305
357
  - [ ] 筛选、分页列表正常
306
- - [ ] 新增、编辑、单删、批量删、导出
307
- - [ ] 自定义 operations(如刷新缓存)
358
+ - [ ] 新增、编辑、单删、批量删、导出(仅列表页可跳过 CRUD 项)
359
+ - [ ] 自定义 operations / 行内 Buttons(如强退、解锁、刷新缓存)
360
+ - [ ] `_operation` 列未重复写 `fixed: 'right'`
361
+ - [ ] 原 list 带 `useDataResult: false` 时已保留 `meta`
362
+ - [ ] 百分比列用 `FormatNumber` + `align: 'right'`,未手写 `` `${row.xxx}%` ``
308
363
  - [ ] 权限码与后端一致
309
364
  - [ ] 每个非 CRUD 操作(unlock、clean、refreshCache 等)的 HTTP 方法已与原 `@/api` 定义逐项核对
310
365
  - [ ] 无路由组件缺失报错
311
366
  - [ ] 修改文件 ESLint 通过(`pnpm eslint <文件路径>`)
312
- - [ ] 修改文件 TS 通过(`pnpm vue-tsc --noEmit`,或至少无本次文件相关报错)
367
+ - [ ] 修改文件 TS 通过(`pnpm type-check`,至少无本次文件相关报错)
313
368
  - [ ] `$alova.Get` 仅两参;带 meta 时写在第二参 config 对象内
314
369
  - [ ] `formItemMap` 使用 `satisfies Record<string, FormItem>`;条件显示用 `__others`
@@ -259,3 +259,121 @@ export const refreshConfigCache = { url: `${prefix}/config/refreshCache`, method
259
259
  ```
260
260
 
261
261
  `prefix` 通常为 `system`,目标直接使用 `system/config/...` 路径。
262
+
263
+ ## 完整案例:monitor/online 在线用户
264
+
265
+ | 文件 | 项目 |
266
+ |------|------|
267
+ | 原 | `yq-monitor-front/src/views/monitor/online/index.vue` |
268
+ | 目标 | `qc-ui/src/views/monitor/online/index.vue` |
269
+
270
+ 特点:仅 list + 行内「强退」,无新增/编辑/删除/导出,无 `PageListItemForm`。
271
+
272
+ ## 原项目:list 带 useDataResult: false
273
+
274
+ ```typescript
275
+ // yq-monitor-front/src/api/monitor.ts
276
+ export const getOnlineList: apiConfig = {
277
+ url: `${prefix}/online/list`,
278
+ useDataResult: false,
279
+ }
280
+ ```
281
+
282
+ RuoYi 分页 `{ rows, total }` 在响应顶层,须保留 `useDataResult: false`。
283
+
284
+ ## 目标项目:等效写法
285
+
286
+ ```typescript
287
+ apis: {
288
+ list: {
289
+ method: (o: Record<string, any>) =>
290
+ $alova.Get('monitor/online/list', {
291
+ meta: { useDataResult: false },
292
+ params: o,
293
+ }),
294
+ },
295
+ },
296
+ ```
297
+
298
+ ## 原项目:强退($confirm + delete)
299
+
300
+ ```typescript
301
+ {
302
+ text: '强退',
303
+ onClick: async ({ row }) => {
304
+ await $confirm(`是否确认强退名称为${row.userName}的用户?`)
305
+ await $api(forceOnlineLogout, { tokenId: row.tokenId })
306
+ pageListRef.value!.query()
307
+ },
308
+ }
309
+
310
+ // api
311
+ export const forceOnlineLogout: apiConfig = {
312
+ url: `${prefix}/online/{tokenId}`,
313
+ method: 'delete',
314
+ msgOnSuccess: true,
315
+ }
316
+ ```
317
+
318
+ ## 目标项目:等效写法
319
+
320
+ ```typescript
321
+ {
322
+ cell: {
323
+ buttons: [
324
+ ({ row }) => ({
325
+ default: '强退',
326
+ popconfirm: {
327
+ content: `是否确认强退名称为${row.userName}的用户?`,
328
+ onConfirm: async () => {
329
+ await $alova.Delete(`monitor/online/${row.tokenId}`, undefined, {
330
+ meta: { useSuccessMsg: true },
331
+ })
332
+ pageListRef.value!.query()
333
+ },
334
+ },
335
+ }),
336
+ ],
337
+ component: 'Buttons',
338
+ },
339
+ colKey: '_operation',
340
+ title: '操作',
341
+ // 不要写 fixed: 'right',TTable 对 _operation 默认右固定
342
+ }
343
+ ```
344
+
345
+ ## _operation 列勿写 fixed
346
+
347
+ TTable 内置:`colKey === '_operation'` 时默认 `fixed: 'right'`。迁移时去掉原 `field: 'c-action'` 列上的 `fixed: 'right'`,避免重复配置。
348
+
349
+ ## 百分比列:slot / 模板 → FormatNumber
350
+
351
+ 场景:服务监控磁盘「已用百分比」等;后端 `usage` 可能为空。
352
+
353
+ ### 错误 ❌
354
+
355
+ ```typescript
356
+ // 手写 cell 或 slot 拼 %
357
+ cell: (_, { row }) => `${row.usage}%`
358
+ ```
359
+
360
+ `usage` 为空时显示 `undefined%`;数字列未右对齐。
361
+
362
+ ### 正确 ✅
363
+
364
+ ```typescript
365
+ {
366
+ align: 'right',
367
+ cell: {
368
+ component: 'FormatNumber',
369
+ config: {
370
+ style: 'unit',
371
+ unit: 'percent',
372
+ },
373
+ },
374
+ colKey: 'usage',
375
+ title: '已用百分比',
376
+ }
377
+ ```
378
+
379
+ 参考:`qc-ui/src/views/monitor/server/index.vue`。
@@ -0,0 +1 @@
1
+ export default import.meta.glob('./**/*.vue') as Record<string, AsyncVueComponentLoaderDefault>
@@ -0,0 +1,4 @@
1
+ export default import.meta.glob('./**/*/index.vue') as Record<
2
+ string,
3
+ AsyncVueComponentLoaderDefault
4
+ >