@qilitt-mickey/vue3-temp-skill 1.1.11 → 1.1.13

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.
@@ -1,49 +1,42 @@
1
1
  ---
2
2
  skill: core-kernel
3
- description: 始终加载的架构内核。硬约束、应用壳、CRUD 积木、工程摘要、核心/附加资产分层。业务开发前必读;不因「改 Vite/入口」单独命中。
3
+ description: 始终加载的架构内核。硬约束、应用壳摘要、样式契约、工程摘要。业务开发前必读。
4
4
  scope: project
5
5
  tags: [vue3, kernel, conventions, layout, router, http, crud, inventory]
6
6
  ---
7
7
 
8
8
  # 核心内核(core-kernel)
9
9
 
10
- > **始终加载。** 覆盖「中后台默认骨架」。
11
- > Vite / 包管理 / 入口启动链 **不是**独立 Skill,仅在本文件做只读摘要。
12
- > 完整库与组件清单见同目录 `project-inventory.md`(一并查阅)。
10
+ 始终加载。库/组件/安装表见 `project-inventory.md`(按需)。列表完整样板见 `crud-pages`;详情跳转见 `detail-page`;HTTP 细节见 `http-api`。
13
11
 
14
-
15
- ---
16
-
17
- ## 一、硬约束(违反即不合格)
12
+ ## 一、硬约束
18
13
 
19
14
  | # | 约定 |
20
15
  |---|------|
21
- | 1 | HTTP 只用 `import { http } from '@/utils/http'`,禁止页面内直接 axios/fetch |
22
- | 2 | 响应类型用全局 **`Result<T>`**(`types/global.d.ts`):常用 `status` / `statusText` / `data` |
23
- | 3 | 默认 **POST**,参数放 **`data`** |
16
+ | 1 | HTTP 只用 `import { http } from '@/utils/http'` |
17
+ | 2 | 响应用全局 **`Result<T>`**(`status` / `statusText` / `data`) |
18
+ | 3 | 方法跟后端文档,**允许 GET / POST**;POST → `data`,GET → `params` |
24
19
  | 4 | 列表用 `useTableSearch`,方法名 **`onSearch` / `reset`** |
25
- | 5 | 业务路由模块 **禁止** 再次 `component: Layout` |
26
- | 6 | 页面权限 `meta.roles`;按钮 `v-auth` / `ReAuth` |
27
- | 7 | 环境只用 `import.meta.env.VITE_*`,禁止硬编码域名 |
28
- | 8 | i18n:`$t('中文key')`,key 即中文文案 |
29
- | 9 | 禁止用 `v-html` 渲染不可信内容 |
30
- | 10 | 新三方依赖必须用户确认;已有封装须复用,选型表指定库勿擅自替换 |
31
- | 11 | **查询列表页布局硬约束**(见下方黄金样板):`el-card` + `ref="content"` + **固定 `height`**(非 `minHeight`);查询区与表格区分区;表格用 `tableHeight`;分页放在 `ReTableBar` 内;查询条件以外的模块绑 `otherRef` 参与高度扣除 |
32
- | 11 | addon 缺失时按 `project-inventory` 第九节**精确版本**安装;禁止 `@latest` / 无版本号;Vite 插件与 `build/plugins/*` 成套核对 |
33
- | 12 | **样式契约**(见「四之二」):UnoCSS 类名必须连字符形态(`p-5`/`w-full`,禁止 `p5`/`w100%`);颜色按语义取 `--el-*`/`--vts-*` 变量(禁止 `bg-[#fff] dark:bg-[#303030]` 成对硬编码);组件尺寸按场景档位(查询/工具栏 `small`、表格 `:size="size"`、弹窗表单 default、整屏主表单 `large`);`design-tokens.scss` 存在时零新增硬编码裸值 |
34
-
35
- ---
36
-
37
- ## 二、应用壳(架构整体)
20
+ | 5 | 业务路由 **禁止** 再挂 `component: Layout` |
21
+ | 6 | 独立详情/编辑:路由与跳转按 **`detail-page`**(`showLink` / `activePath` / `toDetail` / `initToDetail`) |
22
+ | 7 | 页面权限 `meta.roles`;按钮 `v-auth` / `ReAuth` |
23
+ | 8 | 环境只用 `import.meta.env.VITE_*` |
24
+ | 9 | i18n:`$t('中文key')` |
25
+ | 10 | 禁止用 `v-html` 渲染不可信内容 |
26
+ | 11 | 新依赖须用户确认;已有封装须复用;选型表指定库勿擅自替换 |
27
+ | 12 | 列表布局按 **`crud-pages` 黄金样板**(`el-card.vts-page-card`+`content`+固定 height、`tableHeight`、`otherRef`、分页在 ReTableBar 内;仅表格体内滚动) |
28
+ | 13 | addon 按 `project-inventory` 第九节精确版本安装;禁止 `@latest` |
29
+ | 14 | 样式契约见下文「样式契约」 |
30
+
31
+ ## 二、应用壳
38
32
 
39
33
  ### 路由
40
34
 
41
35
  ```typescript
42
- // src/router/modules/xxx.ts
43
36
  export default {
44
37
  path: "/xxx",
45
38
  redirect: "/xxx/list",
46
- meta: { title: "客户管理", icon: "ep:user", rank: 10 }, // 图标约定见 references/icons.md
39
+ meta: { title: "客户管理", icon: "ep:user", rank: 10 },
47
40
  children: [
48
41
  {
49
42
  path: "/xxx/list",
@@ -51,9 +44,9 @@ export default {
51
44
  component: () => import("@/views/xxx/list/index.vue"),
52
45
  meta: { title: "客户列表", roles: ["admin", "common"] },
53
46
  },
47
+ // 独立详情:兄弟路由 + showLink/activePath,完整约定见 detail-page
54
48
  ],
55
49
  } satisfies RouteConfigsTable;
56
- // ❌ 不要在业务模块根上再挂 Layout
57
50
  ```
58
51
 
59
52
  ### 权限
@@ -63,418 +56,105 @@ export default {
63
56
  <ReAuth :value="['admin']"><!-- 区域 --></ReAuth>
64
57
  ```
65
58
 
66
- ### Store / 多标签 / 主题
59
+ ### Store / 主题
67
60
 
68
- - 核心 Store:`user` / `app` / `setting` / `theme` / `lang` / `router` / `multiTags` / `baseCode`
69
- - 详情跳转写标签:`useDetail`(见 `detail-page`)
70
- - 主题:`useTheme` + `--vts-*` / `--vts-theme-*`(详见 `layout-theme`)
71
-
72
- ---
61
+ - Store:`user` / `app` / `setting` / `theme` / `lang` / `router` / `multiTags` / `baseCode`
62
+ - 顶部 tag + 详情跳转:`useDetail` → `detail-page`
63
+ - 主题:`useTheme` + `--vts-*` → `layout-theme`
73
64
 
74
65
  ## 三、数据通道
75
66
 
76
67
  ```typescript
77
68
  import { http } from "@/utils/http";
78
69
 
79
- /** 分页列表 — 可被 useTableSearch 作为 searchFn */
80
70
  export function getCustomerList(data: CustomerQuery, url: string) {
81
71
  return http.request<Result<CustomerPage>>("post", url, { data });
82
72
  }
83
-
84
- /** 详情 */
85
- export function getCustomerDetail(data: { id: string }) {
86
- return http.request<Result<Customer>>(
87
- "post",
88
- `${import.meta.env.VITE_API_BASE_URL}/console/customer/detail`,
89
- { data },
90
- );
91
- }
92
73
  ```
93
74
 
94
- - 方法以后端为准,允许 GET/POST;POST→`data`,GET→`params`。细节见 `http-api` / `api-check`
95
- - 加解密由 `VITE_ENCODE_SWITCH` 全局控制(**无**单请求 `crypto: true`),细节见 `http-api`
96
- - 字典:`useApp().baseCodeGet` / `filterValue`,见 `base-code-dict`
97
- - 提示:`import { message } from '@/utils/message'`
98
-
99
- ---
75
+ 细则:`http-api`。字典:`base-code-dict`。提示:`import { message } from '@/utils/message'`。
100
76
 
101
- ## 四、CRUD 积木(核心组件 / Hook)
102
-
103
- ### 核心 Hook
104
-
105
- | Hook | 用途 |
106
- |------|------|
107
- | `useApp` | headerHeight、字典、svgLoading 等 |
108
- | `useTableSearch` | 列表查询分页(`onSearch`/`reset`) |
109
- | `useDetail` | 详情跳转与参数 |
110
- | `useFormCheck` | 多表单校验聚合 |
111
- | `useTags` / `useTheme` | 标签 / 主题 |
77
+ ## 四、CRUD 积木
112
78
 
113
- ### 核心 Re*(默认应存在于模板)
79
+ | Hook | 用途 | 详例 |
80
+ |------|------|------|
81
+ | `useApp` | headerHeight、字典、svgLoading | — |
82
+ | `useTableSearch` | 列表查询分页 | `crud-pages` |
83
+ | `useDetail` | 详情跳转与顶部 tag | `detail-page` |
84
+ | `useFormCheck` | 多表单校验 | `data-writeback` |
114
85
 
115
- ReAuth、ReDialog、ReGrid、ReGridItem、RePagination、ReTableBar、ReTableOperate、ReHeaderPage、ReSvgIcon(图标细则见 `icons`)、ReText、ReLanguageSwitch、ReSegmented、ReSelectQuery、ReCascader、ReDatePicker、ReDateRangePicker、ReCollapsible
86
+ 核心 Re*:ReAuth、ReDialog、ReGrid、ReGridItem、RePagination、ReTableBar、ReTableOperate、ReHeaderPage、ReSvgIcon、ReText、ReLanguageSwitch、ReSegmented、ReSelectQuery、ReCascader、ReDatePicker、ReDateRangePicker、ReCollapsible
116
87
 
117
- > **弹窗写法**:`ReDialog` / `ReDialogResize` 完整示例见 `form-advanced`(关键词「弹窗」即命中),勿业务页直接裸写 `el-dialog`。
88
+ 弹窗完整示例 → `form-advanced`。列表页完整示例 → `crud-pages`。
118
89
 
119
- ### 列表黄金样板
90
+ ## 五、样式契约
120
91
 
121
- > **布局真相源即本样板**(技能自包含,不依赖业务仓库是否存在演示页)。生成查询列表页必须完整按下方结构输出,禁止简化成「表单 + 裸表格 + 裸分页」——否则会出现字段挤在一起、查询与展示区分不清、无数据时分页贴查询区、页面高度不饱满。
122
-
123
- #### 布局硬约束(违反即不合格)
124
-
125
- | # | 必须 | 说明 |
126
- |---|------|------|
127
- | L1 | `el-card` + `ref="content"` | `useTableSearch` 通过 `content.$el` 算高度;`ref` 必须挂在 **组件**(`el-card`)上,禁止挂在原生 `div` |
128
- | L2 | 卡片用固定 **`height`** | `height: calc(100vh - 2 * var(--vts-margin) - ${headerHeight}px)`;**禁止**只写 `minHeight`(否则 `tableHeight` 算不准,表格无法撑满) |
129
- | L3 | 查询区与展示区分开 | 查询:`el-form` + `class="bg-bg_color p-5"`;展示:`ReTableBar class="bg-bg_color"`;两区视觉分离 |
130
- | L4 | `ReGrid` 间距与栅格 | `:gap="[0, 20]"` + `:cols="{ xs: 1, sm: 2, md: 2, lg: 3, xl: 4 }"`;表单项 `class="w-[100%] !mr-0"`;事件为 `@should-show-collapse` |
131
- | L5 | 操作按钮用 `suffix` | `<ReGridItem suffix>`,勿用随意 `index=99` 冒充后缀列 |
132
- | L6 | 表格动态高度 | `:style="{ height: \`${tableHeight}px\` }"`;分页 **必须在** `ReTableBar` 的 `#default` 内、表格下方,保证空数据时仍占满剩余高度 |
133
- | L7 | `RePagination` 真实 API | `:pagination="pagination"` + `@handle-current-change` / `@handle-size-change`;**禁止**虚构的 `v-model:current-page` |
134
- | L8 | 查询条件之外的模块必须绑 `otherRef` | 卡片内除查询表单、表格+分页外还有任何模块(统计块/页签/提示条/子面板等),外层包一个根元素并 `ref="otherRef"`;`tableHeight` 会自动减去它的高度,不绑则表格高度算错(溢出或被压扁)。多个模块合并进**一个**根容器,禁止逐个散落 |
135
-
136
- ```vue
137
- <script setup lang="ts">
138
- import type { OperateButton } from "@/components/ReTableOperate";
139
- import type { Customer, CustomerQuery } from "@/api/customer";
140
- import { getCustomerList } from "@/api/customer";
141
- import { ReGrid } from "@/components/ReGrid";
142
- import { ReGridItem } from "@/components/ReGridItem";
143
- import { RePagination } from "@/components/RePagination";
144
- import { ReTableBar } from "@/components/ReTableBar";
145
- import { ReTableOperate } from "@/components/ReTableOperate";
146
- import { useApp } from "@/hooks/useApp";
147
- import { useTableSearch } from "@/hooks/useTableSearch";
148
- import { message } from "@/utils/message";
149
-
150
- defineOptions({ name: "CustomerList" });
151
-
152
- const { headerHeight, svgLoading } = useApp();
153
- const formQuery = reactive<CustomerQuery>({ keyword: "", status: undefined });
154
-
155
- const {
156
- content,
157
- otherRef,
158
- tableHeight,
159
- paginationRef,
160
- loading,
161
- formRef,
162
- multipleTableRef,
163
- pagination,
164
- onSearch,
165
- tableData,
166
- gridRef,
167
- showCollapse,
168
- collapsed,
169
- collapsedToggle,
170
- upBold,
171
- downBold,
172
- reset,
173
- } = useTableSearch(
174
- formQuery,
175
- getCustomerList,
176
- `${import.meta.env.VITE_API_BASE_URL}/console/customer/list`,
177
- );
178
-
179
- const tableList = computed(() => tableData.value.tableList as Customer[]);
180
-
181
- const operateButtons: OperateButton[] = [
182
- {
183
- label: $t("删除"),
184
- type: "danger",
185
- icon: "i-ep:delete",
186
- onClick: (row) => handleDelete(row as Customer),
187
- },
188
- ];
189
-
190
- onMounted(() => {
191
- onSearch();
192
- });
193
-
194
- function handleDelete(row: Customer) {
195
- message($t("删除成功"), { type: "success" });
196
- onSearch();
197
- }
198
-
199
- function handleCurrentChange(cur: number) {
200
- pagination.currentPage = cur;
201
- onSearch();
202
- }
203
-
204
- function handleSizeChange(size: number) {
205
- pagination.pageSize = size;
206
- onSearch();
207
- }
208
- </script>
209
-
210
- <template>
211
- <div>
212
- <!-- L1/L2:ref=content 必须在 el-card;用 height 非 minHeight -->
213
- <el-card
214
- ref="content"
215
- shadow="never"
216
- :style="{
217
- height: `calc(100vh - 2 * var(--vts-margin) - ${headerHeight}px)`,
218
- }"
219
- >
220
- <!-- L3:查询区独立背景与内边距(formRef 高度自动参与 tableHeight 计算) -->
221
- <div>
222
- <el-form
223
- ref="formRef"
224
- :inline="true"
225
- :model="formQuery"
226
- class="bg-bg_color p-5"
227
- >
228
- <!-- L4:gap + cols;事件名 should-show-collapse -->
229
- <ReGrid
230
- ref="gridRef"
231
- :collapsed="collapsed"
232
- :gap="[0, 20]"
233
- :cols="{ xs: 1, sm: 2, md: 2, lg: 3, xl: 4 }"
234
- style="max-height: 300px; overflow-y: auto;"
235
- @should-show-collapse="(val) => (showCollapse = val)"
236
- >
237
- <ReGridItem index="0">
238
- <el-form-item :label="$t('关键词')" prop="keyword" class="w-[100%] !mr-0">
239
- <el-input
240
- v-model="formQuery.keyword"
241
- clearable
242
- :placeholder="$t('请输入')"
243
- />
244
- </el-form-item>
245
- </ReGridItem>
246
- <ReGridItem index="1">
247
- <el-form-item :label="$t('状态')" prop="status" class="w-[100%] !mr-0">
248
- <el-select v-model="formQuery.status" clearable :placeholder="$t('请选择')">
249
- <el-option :label="$t('启用')" :value="1" />
250
- <el-option :label="$t('禁用')" :value="0" />
251
- </el-select>
252
- </el-form-item>
253
- </ReGridItem>
254
- <!-- L5:操作列用 suffix -->
255
- <ReGridItem suffix>
256
- <div class="flex flex-end">
257
- <el-button
258
- type="primary"
259
- :loading="loading"
260
- @click="pagination.currentPage = 1; pagination.pageSize = 10; onSearch()"
261
- >
262
- {{ $t("查询") }}
263
- </el-button>
264
- <el-button @click="reset">
265
- {{ $t("重置") }}
266
- </el-button>
267
- <el-button
268
- v-if="showCollapse"
269
- type="primary"
270
- link
271
- class="!font-size-12"
272
- @click="collapsedToggle"
273
- >
274
- {{ collapsed ? $t("展开") : $t("收起") }}
275
- <el-icon class="el-icon--right">
276
- <component :is="collapsed ? downBold : upBold" />
277
- </el-icon>
278
- </el-button>
279
- </div>
280
- </ReGridItem>
281
- </ReGrid>
282
- </el-form>
283
- </div>
284
-
285
- <!-- L8:查询条件以外的模块统一包一个根元素绑 otherRef(无额外模块时整段删除);
286
- tableHeight 公式会自动减去它的高度:
287
- content 高 − formRef 高 − paginationRef 高 − otherRef 高 − 50;
288
- 模块自身间距写在内部内容上,根容器保持零高度余量 -->
289
- <div ref="otherRef">
290
- <!-- 统计/页签/提示等额外模块放这里 -->
291
- </div>
292
-
293
- <!-- L3/L6:展示区在 ReTableBar 内;表格+分页同槽,保证空数据也撑满 -->
294
- <ReTableBar class="bg-bg_color" :columns="[]" @refresh="onSearch">
295
- <template #title>
296
- <span class="truncate font-size-16 font-bold">{{ $t("展示列表") }}</span>
297
- </template>
298
- <template #buttons>
299
- <el-button type="primary" v-auth="['admin']">
300
- {{ $t("新增") }}
301
- </el-button>
302
- </template>
303
- <template #default="{ size }">
304
- <div class="vl-parent">
305
- <el-table
306
- ref="multipleTableRef"
307
- v-loading.lock="loading"
308
- :element-loading-text="$t('加载中')"
309
- :element-loading-spinner="svgLoading"
310
- element-loading-svg-view-box="0, 0, 20, 20"
311
- :style="{ height: `${tableHeight}px` }"
312
- :size="size"
313
- :data="tableList"
314
- :header-cell-style="{
315
- background: 'var(--el-fill-color-light)',
316
- color: 'var(--el-text-color-primary)',
317
- }"
318
- row-key="id"
319
- >
320
- <el-table-column prop="code" :label="$t('编号')" min-width="120" />
321
- <el-table-column prop="name" :label="$t('名称')" min-width="140" />
322
- <el-table-column :label="$t('操作')" width="160" fixed="right">
323
- <template #default="{ row, $index }">
324
- <ReTableOperate :list="operateButtons" :row="row" :index="$index" />
325
- </template>
326
- </el-table-column>
327
- </el-table>
328
-
329
- <!-- L7:真实分页 API;ref=paginationRef 参与 tableHeight 计算 -->
330
- <RePagination
331
- ref="paginationRef"
332
- :size="size"
333
- :pagination="pagination"
334
- @handle-current-change="handleCurrentChange"
335
- @handle-size-change="handleSizeChange"
336
- />
337
- </div>
338
- </template>
339
- </ReTableBar>
340
- </el-card>
341
- </div>
342
- </template>
343
- ```
344
-
345
- `useTableSearch(formQuery, searchFn, url)`:`searchFn` 签名为 `(query, url) => Promise<Result<T>>`,分页字段为 `pageNo` / `pageSize`,列表数据取 `data.content`,总数 `data.totalCount`。返回值中的 `content` / `tableHeight` / `paginationRef` / `formRef` 必须按样板绑定,否则动态高度失效。
346
-
347
- **动态高度真相**:`tableHeight = content.offsetHeight − formRef 高 − paginationRef 高 − otherRef 高 − 50`(ResizeObserver 实时计算)。`content` / `formRef` / `paginationRef` 是固定三件套;**页面出现查询条件以外的模块时必须解构 `otherRef` 并绑到这些模块的统一根元素上**(多个模块包进同一个根容器),高度随模块显隐/伸缩自动重算。禁止用写死像素、`calc()` 猜值或自行手写 ResizeObserver 替代该机制。
348
-
349
- ---
92
+ ### UnoCSS
350
93
 
351
- ## 四之二、样式契约(所有生成代码必须遵循)
94
+ `presetRemToPx({ baseFontSize: 4 })`:间距数字即 px。类名**必须带连字符**:
352
95
 
353
- > 本节是**生成任何页面/组件代码时的样式真相源**:尺寸、间距、边距、颜色、组件档位全部按此执行。任意上游设计类 Skill 产出规范后,经 `design-system` 模块归一化并**修改**项目 `design-tokens.scss`(默认值来自 Vue 模版,不由本 Skill 写死);此后生成代码只准引用令牌,本节约束依然生效。
354
-
355
- ### 1. UnoCSS 类名形态(写错 = 样式静默失效)
356
-
357
- 项目 `presetRemToPx({ baseFontSize: 4 })`:**间距数字即像素**(`p-5` = 5px)。类名**必须带连字符**,无连字符写法不会产出任何 CSS(已用 dist 产物实证):
358
-
359
- | ❌ 无效(无 CSS 产出) | ✅ 有效 | 说明 |
360
- |---|---|---|
361
- | `p5` / `p10` / `p20` / `m10` / `mt20` / `px5` / `gap10` | `p-5` / `p-10` / `p-20` / `m-10` / `mt-20` / `px-5` / `gap-10` | 间距类必须带连字符 |
362
- | `w100%` / `h100%` / `w-100%` / `h-[100%]` | `w-full` / `h-full` | 满宽满高统一 `full` |
363
- | `p-b-16` | `pb-16` | 方向前缀连写 |
364
- | `bg-[#fff]` + `dark:bg-[#303030]` | `bg-bg_color` | 背景按语义取变量,自动适配暗黑 |
365
-
366
- - 间距取 **4px 基数**(4/8/12/16/20);`p-5`(查询区内边距)等模版既有值保持原样。
367
- - shortcuts 白名单:`flex-center` / `flex-end` / `flex-middle` / `flex-between` / `flex-col-center` / `break-word` / `ellipsis`,布局优先用它们。
368
- - 字号用显式 px 档位:`text-xs`=12 / `text-sm`=14 / `text-base`=16 / `text-lg`=18 / `text-xl`=20 / `text-2xl`=24 / `text-3xl`=30。
369
-
370
- ### 2. 颜色纪律(按语义取变量,禁止成对硬编码)
96
+ | 无效 | 有效 |
97
+ |------|------|
98
+ | `p5` / `w100%` | `p-5` / `w-full` |
99
+ | `bg-[#fff] dark:bg-[#303030]` | `bg-bg_color` |
371
100
 
372
- | 语义 | 用法 |
373
- |---|---|
374
- | 页面/卡片背景 | `bg-bg_color`(桥接 `--el-bg-color`);布局底 `--el-bg-color-page`;浮层 `--el-bg-color-overlay` |
375
- | 文字 | `--el-text-color-primary` / `regular` / `secondary` / `placeholder` |
376
- | 边框 | `--el-border-color`(及 `-light` / `-lighter` / `-dark`) |
377
- | 浅填充(表头/hover 底) | `--el-fill-color-light` |
378
- | 主色与梯度 | `--el-color-primary`(及 `-light-3/5/7/9`、`-dark-2`) |
379
- | 状态色 | `--el-color-success` / `warning` / `danger` / `info` |
380
- | 表格表头 | `--vts-table-header-bg` / `--vts-table-header-text`(el-table 与 vxe 共用) |
381
- | 弹窗背景 | `--vts-dialog-bg` ← `--ds-dialog-bg`(主题渐变:`primary-bg → component-bg`) |
382
- | 弹窗内边距 | `--dialog-header-padding` / `--dialog-body-padding` / `--message-box-content-padding` / `--dialog-footer-padding` |
101
+ - 间距 4px 基数;shortcuts:`flex-center` / `flex-end` / `flex-between` 等
102
+ - 字号:`text-xs`=12 … `text-3xl`=30
383
103
 
384
- Canvas / 图谱 / 连线库等**必须传具体色值字符串**的场景,用统一工具从运行时读取变量,禁止把十六进制写死在业务代码里:
104
+ ### 颜色
385
105
 
386
- ```typescript
387
- /** 读取 CSS 变量(canvas/G6/jsPlumb 等需要具体色值时使用) */
388
- const getCssVar = (name: string, fallback = "") =>
389
- getComputedStyle(document.documentElement).getPropertyValue(name).trim() || fallback;
106
+ 语义变量:`bg-bg_color`、`--el-text-color-*`、`--el-border-color`、`--el-color-primary*`、`--vts-table-header-*`、`--vts-dialog-bg`。Canvas/G6 等需实色时用 `getComputedStyle` 读变量,禁止业务写死 hex。
390
107
 
391
- // 示例:G6 边样式
392
- edge: { type: "line", style: { stroke: getCssVar("--el-color-primary-light-5", "#9DC5EA") } }
393
- ```
108
+ ### 组件尺寸
394
109
 
395
- ### 3. 组件尺寸纪律(small / default / large 按场景定档)
110
+ | 场景 | 档位 |
111
+ |------|------|
112
+ | 查询区表单/按钮、工具栏按钮 | default(不写 size) |
113
+ | 表格 / 分页 | `:size="size"`(ReTableBar 透出) |
114
+ | 弹窗内表单 | default |
115
+ | 登录/整屏主表单 | `large` |
116
+ | 移动端 Vant | 见 `mobile-h5` |
396
117
 
397
- | 场景 | 档位 | 说明 |
398
- |---|---|---|
399
- | **查询区 `el-form`(含输入/选择/按钮)** | **default(不写 size)** | 中号 32px,与 `--control-height` / `--el-component-size` 一致;**禁止**只给按钮写 `small` 而表单走 default |
400
- | 查询区按钮(查询/重置/展开收起) | 随 `el-form` 继承 | **禁止**单独写 `size="small"` 导致与输入框档位不一致 |
401
- | `ReTableBar` 工具栏按钮(新增/导入/导出/删除) | default(不写 size) | 列表页工具栏与查询区同档(中号) |
402
- | 表格 | `:size="size"`(`ReTableBar` 插槽透出) | **禁止写死**,密度切换由用户控制 |
403
- | 分页 | `RePagination :size="size"` | 跟随表格密度 |
404
- | 弹窗内表单 | default(不写 size)+ `label-width="96px"` | `ReDialog` / `ReDialogResize` 内表单 |
405
- | 登录页 / 整屏主表单 | `size="large"` | 低频全屏操作放大档位 |
406
- | 移动端 Vant | 独立尺寸体系 | 不与 EP 档位混用,见 `mobile-h5` |
118
+ 存在 `design-tokens.scss` 时:零新增硬编码裸值;适配流程见 `design-system`。
407
119
 
408
- 设计规范生效期(`design-tokens.scss` 存在):档位高度由令牌驱动——`small ↔ --ds-control-height-sm`、`default ↔ --ds-control-height`、`large ↔ --ds-control-height-lg`(经 `--el-component-size*` 映射)。**禁止**在业务代码里写裸控件高度(如 `.el-input { height: 36px }`)绕过档位。
120
+ ### 独立功能页容器
409
121
 
410
- ### 4. 页面容器黄金形态
122
+ 定高且内部滚动(与列表卡同类场景):
411
123
 
412
124
  ```vue
413
- <!-- 独立功能页(图谱/流程图等常规页) -->
414
125
  <div
415
126
  :style="{ height: `calc(100vh - 2 * var(--vts-margin) - ${headerHeight}px)` }"
416
127
  class="pos-relative bg-bg_color p-5 overflow-hidden"
417
128
  >
418
129
  ```
419
130
 
420
- - 高度公式固定:`calc(100vh - 2 * var(--vts-margin) - ${headerHeight}px)`(`headerHeight` 来自 `useApp()`)。
421
- - 容器内边距默认 `p-5`;区块之间用 `mb-10` / `gap-10` 等 4 基数间距。
422
-
423
- ### 5. 设计规范生效期(design-tokens.scss 存在时)
424
-
425
- 1. 生成代码前先确认 `src/styles/design-tokens.scss` 是否存在;存在则进入「规范期」。
426
- 2. 规范期**零新增硬编码**:颜色/控件高度/内边距/圆角/字号一律引用令牌或语义变量;设计稿与令牌冲突时回填令牌层,不在页面里写裸值。
427
- 3. 间距/边距仍按 4px 基数,优先对齐令牌 `--space-unit` 的倍数。
428
- 4. 命中 `design-system` 时按其工作流执行适配与存量扫描,本节约束与其一致不冲突。
429
-
430
- ---
431
-
432
- ## 五、资产分层(核心 vs 附加)
131
+ 查询列表定高卡 → `crud-pages`(`el-card.vts-page-card` + `tableHeight`)。
132
+ ## 六、资产分层
433
133
 
434
- ### 附加 Hook(按功能模块加载,勿塞进每个 CRUD)
134
+ 附加 Hook/组件按功能模块加载(WebSocket、微信、附件、图表等)→ 见各专项与 `project-inventory`。
435
135
 
436
- | Hook | 模块 |
437
- |------|------|
438
- | `useWebSocket` | websocket-realtime |
439
- | `useWechat` | wechat-js / mobile-h5 |
440
-
441
- ### 附加组件(示例)
442
-
443
- 附件/预览、ECharts、富文本、验证码、码、图谱、工作流、移动选择器、反馈展示类等 → 见各专项模块与 `project-inventory.md`。
444
-
445
- ### 附加 Utils
446
-
447
- `uploadManager` / `imageCompression` → file;`changeSummaryService` → data-compare;`websocket/**` / `wechat/**` / `vantRules` → 对应专项;`particles` / `particlesOptions` → **particles**;`motion` → feedback-ui / 登录页入场动画。
448
-
449
- ---
450
-
451
- ## 六、工程摘要(只读,非日常生成目标)
136
+ ## 七、工程摘要(只读)
452
137
 
453
138
  | 项 | 说明 |
454
139
  |----|------|
455
- | 包管理 | pnpm;脚本 `dev` / `build` / `type-check` / `lint` / `lint:fix`(质量闸门必跑后两者) |
456
- | 默认插件 | Vue/JSX、AutoImport、SVG、UnoCSS、Favicon、Mock(`VITE_USE_MOCK`)、Gzip、Visualizer、混淆、DevTools |
457
- | 去 console | `build/build.ts`:非 `VITE_DEBUGGER` 时 Terser `drop_console`(**无** vite-plugin-remove-console) |
458
- | 功能附属插件 | FileViewer → `file-management`;vConsole → `mobile-h5`;精确版本与 `pnpm` 命令见 `project-inventory` 第九节 |
459
- | addon 安装 | 裁剪项目缺依赖时:查 `package.json` → 按第九节精确版本征得确认后 `pnpm add` / `pnpm add -D` |
460
-
461
- 除非用户明确要求改构建配置,否则生成业务代码时**不要**改 `vite.config.ts` / `build/**`。
140
+ | 包管理 | pnpm;`dev` / `build` / `type-check` / `lint` / `lint:fix` |
141
+ | 默认插件 | Vue/JSX、AutoImport、SVG、UnoCSS、Mock、Gzip 等 |
142
+ | addon | FileViewer → `file-management`;vConsole → `mobile-h5`;安装见 inventory 第九节 |
462
143
 
463
- ---
144
+ 非用户要求不改 `vite.config.ts` / `build/**`。
464
145
 
465
- ## 七、环境变量(骨架)
146
+ ## 八、环境变量
466
147
 
467
- `VITE_TITLE` / `VITE_PUBLIC_PATH` / `VITE_USE_MOCK` / `VITE_API_BASE_URL` / `VITE_ENCODE_*` / `VITE_SSO` / `VITE_NO_CUS_LOGO` / `VITE_GZIP` / `VITE_VSUALIZER` / `VITE_BUNDLE_OBFUSCATOR` / `VITE_DEBUGGER`
148
+ `VITE_TITLE` / `VITE_PUBLIC_PATH` / `VITE_USE_MOCK` / `VITE_API_BASE_URL` / `VITE_ENCODE_*` / `VITE_SSO` / `VITE_DEBUGGER` 等;附加 `VITE_WS_URL`、`VITE_VCONSOLE` 随专项。
468
149
 
469
- 附加:`VITE_WS_URL`、`VITE_VCONSOLE`(随专项模块)。
150
+ ## 九、模块指针
470
151
 
471
- ---
472
-
473
- ## 八、与其它模块的衔接
474
-
475
- - 写接口细节 → `http-api`
476
- - 完整 CRUD 变体、表单页 → `crud-pages`
477
- - 详情跳转 → `detail-page`
478
- - 主题布局深挖 → `layout-theme`
479
- - 设计规范适配 / 项目存在 `design-tokens.scss` → `design-system`(样式契约随之进入「规范期」,见四之二第 5 节)
480
- - 选型对照与全量组件表 → `project-inventory.md`
152
+ | 需求 | 模块 |
153
+ |------|------|
154
+ | 接口 | `http-api` |
155
+ | 列表/表单 CRUD | `crud-pages` |
156
+ | 详情跳转 | `detail-page` |
157
+ | 主题布局 | `layout-theme` |
158
+ | 设计规范适配 | `design-system` + 有产出时 `design-handoff` |
159
+ | 版本/安装 | `project-inventory` |
160
+ | 生成后审查 | `code-quality` |