adspecs 0.1.39 → 0.1.41
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codebuddy-plugin/plugin.json +1 -1
- package/.qoder-plugin/plugin.json +1 -1
- package/.workbuddy-plugin/plugin.json +1 -1
- package/README.md +1 -1
- package/bin/adspecs.js +2 -2
- package/hooks/commit-queue.js +4 -5
- package/hooks/hooks.json +11 -11
- package/hooks/platform.js +6 -2
- package/hooks/session-logger.js +2 -1
- package/hooks/session-start.js +10 -33
- package/hooks/wiki-queue.js +2 -1
- package/package.json +65 -65
- package/references/vue3-front-standard/INDEX.md +54 -0
- package/references/vue3-front-standard/api-i18n-rules.md +65 -0
- package/references/vue3-front-standard/gushen-components.md +174 -0
- package/references/vue3-front-standard/page-development-rules.md +262 -0
- package/references/vue3-front-standard/page-template-index.md +374 -0
- package/references/vue3-front-standard/project-overview.md +48 -0
- package/skills/project-init/SKILL.md +25 -21
- package/src/lib/scaffolder.js +43 -4
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# Gushen 前端组件规则
|
|
2
|
+
|
|
3
|
+
本工程依赖:
|
|
4
|
+
|
|
5
|
+
- `@gushen/gushen-common-components`
|
|
6
|
+
- `@gushen/gushen-form-render`
|
|
7
|
+
|
|
8
|
+
当前目标工程未安装 `@gushen/gushen-work-flow`。如果需求涉及工作流组件(如 `flow-container`、`flow-ea-buttons`、`flow-commit`),先确认依赖、注册方式和运行时子应用边界,不要直接生成组件用法。
|
|
9
|
+
|
|
10
|
+
使用组件前,优先读取组件源码:`node_modules/@gushen/gushen-common-components/src/packages/components`。
|
|
11
|
+
|
|
12
|
+
## 全局注册
|
|
13
|
+
|
|
14
|
+
`src/core/initMain.ts` 已执行:
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import GsComponents from '@gushen/gushen-common-components'
|
|
18
|
+
instance.use(GsComponents)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
因此 `gs-*` 公共组件可直接在模板中使用。当前本地全局组件仅包含 `GsIconDialog`、`GsIcon`、`SvgIcon`、`UploadImg`,注册位置为 `src/components/global-register.ts`。
|
|
22
|
+
|
|
23
|
+
常见公共组件分类:
|
|
24
|
+
|
|
25
|
+
- 表格:`GsTable`、`GsCustomizeTable`、`GsVxeTable`、`GsSuperTable`
|
|
26
|
+
- 查询/输入:`GsSearchBar`、`GsInput`、`GsSelect`、`GsRadio`、`GsSwitch`
|
|
27
|
+
- 选择器:`GsSelectTreeTable`、`GsPersonnelSelector`、`GsDepartmentSelector`、`GsPageSelect`、`GsDialogSelector`
|
|
28
|
+
- 上传/导入导出:`GsUpload`、`GsAttachmentList`、`UploadImg`、`GsImportData`、`GsExportData`
|
|
29
|
+
- 弹层/布局:`GsDialog`、`GsDrawer`、`GsCard`、`GsGridLayout`
|
|
30
|
+
|
|
31
|
+
## `GsCustomizeTable` / `gs-table`
|
|
32
|
+
|
|
33
|
+
源码路径:`node_modules/@gushen/gushen-common-components/src/packages/components/GsCustomizeTable`。
|
|
34
|
+
|
|
35
|
+
### 推荐用途
|
|
36
|
+
|
|
37
|
+
- 后端分页列表页。
|
|
38
|
+
- 需要列设置、表头查询、刷新、导入导出、关键字搜索的业务列表。
|
|
39
|
+
- 页面模板统一从 `page-template-index.md` 选择;本规则只说明组件 API 和约束。
|
|
40
|
+
|
|
41
|
+
### 核心配置
|
|
42
|
+
|
|
43
|
+
组件级常用 props:
|
|
44
|
+
|
|
45
|
+
- `gridConfig`:核心表格配置,和源码 `defaultConfig()` 合并。
|
|
46
|
+
- `queryParams`:请求参数,常见结构为 `{ params: { pageIndex, pageRows, params: {} }, queryUrl }`。
|
|
47
|
+
- `fixedParams`:固定参数,搜索重置时保留。
|
|
48
|
+
- `tableParams`:表头搜索附加参数。
|
|
49
|
+
- `method`:请求方法,默认 `post`。
|
|
50
|
+
- `tableHeight` / `maxHeight`:高度控制。
|
|
51
|
+
- `reserveSelection`:跨页保留勾选,需配合 `rowKey`。
|
|
52
|
+
- `readonly`:只读禁用交互。
|
|
53
|
+
- `isParamsOutSearch`:为 true 时抛出 `paramsOutSearch`,由父组件接管请求。
|
|
54
|
+
- `reqBeforeHandler` / `resDataHandler`:请求前和响应数据处理钩子。
|
|
55
|
+
|
|
56
|
+
常用顶层配置来自 `common/defaultConfig.js`:
|
|
57
|
+
|
|
58
|
+
- `columns`:列配置。
|
|
59
|
+
- `queryUrl`:远程查询接口。
|
|
60
|
+
- `selectable`:是否显示勾选列。
|
|
61
|
+
- `showIndex`:是否显示序号列。
|
|
62
|
+
- `slotArr`:需要自定义插槽渲染的列字段。
|
|
63
|
+
- `needPagination` / `paged`:是否分页。
|
|
64
|
+
- `hideSearchBtn`:是否隐藏表头查询切换。
|
|
65
|
+
- `showSetting`:是否显示列设置。
|
|
66
|
+
- `showRefresh`:是否显示刷新按钮。
|
|
67
|
+
- `importable` / `exportable`:是否启用导入导出。
|
|
68
|
+
- `enableCustomizeFilter`:是否启用高级筛选。
|
|
69
|
+
- `isVirtualList`:是否启用虚拟滚动。
|
|
70
|
+
- `localstorageName`:列设置缓存 key。
|
|
71
|
+
- `rowKey`:跨页勾选、虚拟列表建议设置,默认常用 `id`。
|
|
72
|
+
- `showKeyWordSearch`:是否显示关键字搜索。
|
|
73
|
+
- `isScrollRequest`:是否启用滚动加载。
|
|
74
|
+
|
|
75
|
+
列默认配置来自 `common/columnDefaultConfig.js`:
|
|
76
|
+
|
|
77
|
+
- `prop`、`label`、`width`、`align`、`headerAlign`、`fixed`。
|
|
78
|
+
- `isShow`、`hidden`、`hiddenFlag` 控制显示。
|
|
79
|
+
- `sortable` 默认 `true`。
|
|
80
|
+
- `showOverflowTooltip` 默认 `true`。
|
|
81
|
+
- `dataType` 默认 `string`。
|
|
82
|
+
- `dictCode` 可配合字典数据做显示转换。
|
|
83
|
+
- `list` 可提供下拉选项。
|
|
84
|
+
- `component`、`componentAttr`、`list` 可用于表头搜索控件。
|
|
85
|
+
- `sortableType: 'all'` 表示远程排序。
|
|
86
|
+
- `hideSearh` 用于禁用表头搜索(源码拼写如此)。
|
|
87
|
+
|
|
88
|
+
### 插槽
|
|
89
|
+
|
|
90
|
+
- `#table-title`:表格标题。
|
|
91
|
+
- `#btn`:表格头部左侧按钮。
|
|
92
|
+
- `#btn-r`:头部浮动按钮区域。
|
|
93
|
+
- `#expand`:展开行。
|
|
94
|
+
- `#pager`:自定义分页区域。
|
|
95
|
+
- 字段插槽:字段名必须加入 `slotArr`,例如 `slotArr: ['readStatus', 'action']` 后可写 `#readStatus`、`#action`。
|
|
96
|
+
|
|
97
|
+
### 事件
|
|
98
|
+
|
|
99
|
+
常用事件:
|
|
100
|
+
|
|
101
|
+
- `@inited`:表格初始化完成,返回表格实例。
|
|
102
|
+
- `@updateTableData`:表格数据更新。
|
|
103
|
+
- `@update:tableTotal`:总数更新。
|
|
104
|
+
- `@requestError`:请求异常。
|
|
105
|
+
- `@pageChange`、`@sizeChange`:分页变化。
|
|
106
|
+
- `@row-click`:行点击。
|
|
107
|
+
- `@select-all`:全选变化。
|
|
108
|
+
- `@sort-change`:排序变化。
|
|
109
|
+
- `@header-dragend`:列宽拖拽结束。
|
|
110
|
+
- `@needSearchChange`:表头查询开关变化。
|
|
111
|
+
- `@paramsOutSearch`:外部接管查询参数。
|
|
112
|
+
- `@import-success`、`@exportSuccess`:导入导出成功。
|
|
113
|
+
|
|
114
|
+
### 实例方法
|
|
115
|
+
|
|
116
|
+
通过 `ref` 可调用:
|
|
117
|
+
|
|
118
|
+
- `refresh(hasLoading, isClearSelection = true)`:刷新数据。
|
|
119
|
+
- `getData(...)`:按当前配置查询。
|
|
120
|
+
- `outSearch(isKeepPage?, noLike?, hasLoading?, index?)`:外部搜索条件变化后触发查询。
|
|
121
|
+
- `tableSearch(isKeepPage?, index?)`:表头查询。
|
|
122
|
+
- `getSelection()`:获取勾选行。
|
|
123
|
+
- `setRowSelection(row, flag, key?)`:切换指定行选中。
|
|
124
|
+
- `getCurrentParams()`:获取当前请求参数。
|
|
125
|
+
- `resetTable()` / `init()` / `doTableLayout()`:重置、初始化、重排布局。
|
|
126
|
+
- `setFirstRow()`:选中首行并触发 `getfirstdata`。
|
|
127
|
+
|
|
128
|
+
### 生成代码约束
|
|
129
|
+
|
|
130
|
+
- 普通值展示优先使用列配置和 `dictCode`,不要为了纯文本显示滥用插槽。
|
|
131
|
+
- 需要 `el-tag`、按钮、链接、富文本等复杂渲染时,字段必须加入 `slotArr`。
|
|
132
|
+
- 操作列使用 `prop: 'action'`、`fixed: 'right'`,并加入 `slotArr`。
|
|
133
|
+
- 表头查询字段使用 `component`、`componentAttr`、`list`;字典字段优先配置 `dictCode`。
|
|
134
|
+
- 每个列表页设置唯一 `localstorageName`,避免列设置缓存串页。
|
|
135
|
+
- 外部查询条件变化后更新 `queryParams.params.params`,再调用 `tableRef.value?.outSearch(false)`;普通刷新调用 `tableRef.value?.refresh(true)`。
|
|
136
|
+
- 勾选场景必须设置 `rowKey`。
|
|
137
|
+
|
|
138
|
+
## `GsTable`
|
|
139
|
+
|
|
140
|
+
源码路径:`node_modules/@gushen/gushen-common-components/src/packages/components/GsTable/index.vue`。
|
|
141
|
+
|
|
142
|
+
- 适合简单本地或远程表格。
|
|
143
|
+
- `columns` 控制列,`options`/工具配置控制搜索、刷新、列设置、选择列、序号列、加减行。
|
|
144
|
+
- `#header` 放头部按钮,`#cell` 用于可编辑或自定义单元格。
|
|
145
|
+
- 旧代码中 `<gs-table :columns="columns" :options="options" :remote="remoteData">` 是可参考写法。
|
|
146
|
+
|
|
147
|
+
## `GsSearchBar`
|
|
148
|
+
|
|
149
|
+
源码路径:`node_modules/@gushen/gushen-common-components/src/packages/components/GsSearchBar/index.vue`。
|
|
150
|
+
|
|
151
|
+
- `searchConfig.items` 描述查询项,字段名使用 `field`。
|
|
152
|
+
- `fixedParams` 会合并进查询参数。
|
|
153
|
+
- `btnPosition` 支持 `top` / `bottom`。
|
|
154
|
+
- 查询项 `type` 直接映射 Element Plus 组件,如 `el-input`、`el-select`、`el-cascader`。
|
|
155
|
+
- `el-select` 的选项使用 `options: [{ label, value }]`。
|
|
156
|
+
- `#prepend`、`#append` 可插入按钮。
|
|
157
|
+
- 事件:`@search="handleSearch"`、`@reset="handleReset"`、`@expand="handleExpand"`。
|
|
158
|
+
- 可通过实例方法 `setFormItemValue(field, value)` 设置查询字段。
|
|
159
|
+
|
|
160
|
+
## 上传与图片
|
|
161
|
+
|
|
162
|
+
- 本地全局 `UploadImg` 来自 `src/components/UploadImg/index.vue`。
|
|
163
|
+
- 公共组件库也提供 `GsUpload`、`UploadImg`,使用前对照源码确认事件和字段。
|
|
164
|
+
- 文件上传 API 参考 `src/api/attachment.ts` 和 `src/components/GsUpload`。
|
|
165
|
+
|
|
166
|
+
## 动态表单
|
|
167
|
+
|
|
168
|
+
- 依赖 `@gushen/gushen-form-render` 已安装。
|
|
169
|
+
- 动态表单组件来自 `@gushen/gushen-form-render`,常用注册名是 `FormRender` / `<form-render>`;不存在 `GsForm` 业务组件。
|
|
170
|
+
- 当前 `src/core/initMain.ts` 中插件注册是注释状态;新增 `<FormRender />` 前,先确认是否需要解除注释:
|
|
171
|
+
- `import GushenFormRender from '@gushen/gushen-form-render'`
|
|
172
|
+
- `import '@gushen/gushen-form-render/lib/gushen-form-render.css'`
|
|
173
|
+
- `instance.use(GushenFormRender)`
|
|
174
|
+
- 现有动态表单入口:`src/views/dynamic-form/index.vue`。
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
# 页面开发规则
|
|
2
|
+
|
|
3
|
+
## 默认页面形态
|
|
4
|
+
|
|
5
|
+
新增业务页面优先使用:
|
|
6
|
+
|
|
7
|
+
- Vue 3 `script setup lang="ts"`。
|
|
8
|
+
- Element Plus 布局组件。
|
|
9
|
+
- `@gushen/gushen-common-components` 的表格、查询栏、上传等组件。
|
|
10
|
+
- `src/api/<module>/index.ts` 管理请求。
|
|
11
|
+
- `src/lang/modules/<module>/{zh-cn,en-us,zh-tw}.ts` 管理文案。
|
|
12
|
+
|
|
13
|
+
维护已有旧页面时,可以保留 Options API;新增页面不要主动复制旧页面里的 `console.log`、`@ts-nocheck`、硬编码文案和隐式 any。
|
|
14
|
+
|
|
15
|
+
## 列表页
|
|
16
|
+
|
|
17
|
+
推荐结构:
|
|
18
|
+
|
|
19
|
+
```text
|
|
20
|
+
src/views/<module>/<page>/
|
|
21
|
+
├── index.vue
|
|
22
|
+
├── components/
|
|
23
|
+
│ └── <可选子组件>.vue
|
|
24
|
+
└── config/
|
|
25
|
+
└── gridConfig.ts
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
列表页默认使用 `GsCustomizeTable` / `<gs-table>`:
|
|
29
|
+
|
|
30
|
+
- 查询按钮放在表格 `#btn` 或页面顶部查询区。
|
|
31
|
+
- 列配置单独抽到 `config/gridConfig.ts`,复杂列通过 `slotArr` 开启插槽。
|
|
32
|
+
- 列表请求函数放在 `src/api/<module>/<page>/index.ts`。
|
|
33
|
+
- 成功判断用 `reqIsSucceed`,不要写死单一成功码,除非维护旧接口已有固定协议。
|
|
34
|
+
|
|
35
|
+
## 表单页
|
|
36
|
+
|
|
37
|
+
推荐结构:
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
src/views/<module>/<page>/
|
|
41
|
+
├── index.vue
|
|
42
|
+
└── components/
|
|
43
|
+
└── BasicForm.vue
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
表单规则:
|
|
47
|
+
|
|
48
|
+
- 使用 `el-form`、`el-row`、`el-col` 组织字段。
|
|
49
|
+
- 新增/编辑共用表单组件,通过 `disabled` 或 `readonly` 控制只读。
|
|
50
|
+
- 保存入参按后端要求包裹 `{ params: formData }`。
|
|
51
|
+
- 表单初始化、回显映射、保存映射拆成小函数。
|
|
52
|
+
- 复杂弹窗或选择器优先封装为独立子组件,不要在主页面堆大量弹窗逻辑。
|
|
53
|
+
|
|
54
|
+
## 流程页面
|
|
55
|
+
|
|
56
|
+
流程表单模板统一从 `page-template-index.md` 选择,不再以当前工程旧页面作为模板入口。
|
|
57
|
+
|
|
58
|
+
流程页面需要保留方法契约:
|
|
59
|
+
|
|
60
|
+
- `get_process_variables()`:返回流程变量。
|
|
61
|
+
- `ap_save()`:保存草稿,返回 Promise。
|
|
62
|
+
- 包装页通过 props 接收 `isSubmit`、`editStatus`、`bpm_businessKey`、`taskServiceParams`、`curTaskName`。
|
|
63
|
+
|
|
64
|
+
## 动态表单页
|
|
65
|
+
|
|
66
|
+
参考:`src/views/dynamic-form/index.vue`。
|
|
67
|
+
|
|
68
|
+
- 当前页面只挂载 `<FormRender ref="formRenderRef" />`。
|
|
69
|
+
- 使用 IntersectionObserver 在页面可见时向事件总线发送当前路由信息。
|
|
70
|
+
- 使用前确认 `@gushen/gushen-form-render` 插件是否已在 `src/core/initMain.ts` 注册。
|
|
71
|
+
|
|
72
|
+
## 路由与菜单
|
|
73
|
+
|
|
74
|
+
- 普通业务页默认由后台菜单动态加载,只需确保页面路径存在。
|
|
75
|
+
- 菜单 `menuUrl` / `originalAddr` 会在 `src/permission.ts` 中映射到 `@/views${componentPath}/index.vue`。
|
|
76
|
+
- 例如后台菜单路径 `/test-menu/demo1` 对应 `src/views/test-menu/demo1/index.vue`。
|
|
77
|
+
- 静态壳内页面才补 `src/router/index.ts`。
|
|
78
|
+
- 新增路由 meta 至少包含 `title`、`enTitle`、`noCache`、`hideInMenu`、`isBootstrap`。
|
|
79
|
+
- 动态表单菜单通过 `parameter.menu_type === 'DYNAMIC_FORM'` 进入固定 `FormRender` 容器,一般不新建手写业务页。
|
|
80
|
+
|
|
81
|
+
## 样式
|
|
82
|
+
|
|
83
|
+
- 页面根节点使用唯一 class,例如 `<section class="xxx-page">`。
|
|
84
|
+
- 页面级样式使用 `<style scoped lang="scss">`。
|
|
85
|
+
- 不要把布局高度写死到固定 px;优先使用 flex 和 `min-height: 0`。
|
|
86
|
+
|
|
87
|
+
## 生成后自检
|
|
88
|
+
|
|
89
|
+
- 页面能被路由加载。
|
|
90
|
+
- API 路径、请求方法、参数包装与现有接口一致。
|
|
91
|
+
- 表格远程刷新、分页、勾选、操作列能闭环。
|
|
92
|
+
- 用户可见文案进入语言包。
|
|
93
|
+
- 无新增 TypeScript / Vue 诊断。
|
|
94
|
+
|
|
95
|
+
## 常见问题与修复指南
|
|
96
|
+
|
|
97
|
+
以下是开发过程中已验证的高频问题及修复方案,生成页面时务必逐项检查。
|
|
98
|
+
|
|
99
|
+
### 1. gs-table 操作列不显示
|
|
100
|
+
|
|
101
|
+
**现象**:表格渲染正常,但操作列(`prop: 'action'`)和自定义内容列(如状态 Tag)显示空白。
|
|
102
|
+
|
|
103
|
+
**根因**:`GsTable` 组件的 `#cell` 插槽仅在列的 `editable: true` 时才渲染。源码逻辑:
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
// GsTable/index.vue
|
|
107
|
+
if (type === "cell") {
|
|
108
|
+
const { editable } = column || {};
|
|
109
|
+
return editable === true;
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**修复**:需要自定义内容渲染的列必须加 `editable: true`:
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
{ prop: 'forecastStatus', label: '状态', editable: true },
|
|
117
|
+
{ prop: 'action', label: '操作', searchable: false, editable: true },
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### 2. gs-table 数据请求方式选择
|
|
121
|
+
|
|
122
|
+
**原则**:优先使用项目中已验证的 `:columns` + `:options` + `:remote` 模式(参照 `mdmCustomer`),而非 `GsCustomizeTable` 的 `:grid-config` + `:query-params` 模式。
|
|
123
|
+
|
|
124
|
+
**原因**:两种组件的数据响应格式不同:
|
|
125
|
+
- `GsCustomizeTable` 内部期望 `res.data.data` 是行数组 + `res.data.count` 是总数
|
|
126
|
+
- `:remote` 模式由开发者自行处理响应格式转换,兼容性更好
|
|
127
|
+
|
|
128
|
+
```html
|
|
129
|
+
<gs-table
|
|
130
|
+
ref="tableRef"
|
|
131
|
+
:columns="columns"
|
|
132
|
+
:options="tableOptions"
|
|
133
|
+
:remote="remoteData"
|
|
134
|
+
>
|
|
135
|
+
<template #header>
|
|
136
|
+
<el-button type="primary" @click="openAddDialog">新增</el-button>
|
|
137
|
+
</template>
|
|
138
|
+
<template #cell="{ column, row }">
|
|
139
|
+
<template v-if="column.prop === 'action'">
|
|
140
|
+
<!-- 操作按钮 -->
|
|
141
|
+
</template>
|
|
142
|
+
</template>
|
|
143
|
+
</gs-table>
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
`remoteData` 函数必须返回 `{ data: rows[], total: number, number: pageIndex, size: pageRows }` 格式:
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
async function remoteData(otherParams: any = {}) {
|
|
150
|
+
const { number, size, params } = otherParams || {}
|
|
151
|
+
const res = await findPagination({ pageIndex: number, pageRows: size, params })
|
|
152
|
+
if (res.code === 800) {
|
|
153
|
+
const d = res.data || {}
|
|
154
|
+
return { data: d.rows || [], number, size, total: Number(d.total) || 0 }
|
|
155
|
+
}
|
|
156
|
+
return { data: [], number, size, total: 0 }
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### 3. Mock 模式下 GET 请求的查询参数丢失
|
|
161
|
+
|
|
162
|
+
**现象**:详情页打开后空白,控制台报 `Cannot read properties of undefined (reading 'data')`。
|
|
163
|
+
|
|
164
|
+
**根因**:axios 的 `params` 配置项在所有请求拦截器执行**之后**才拼接到 URL。Mock 拦截器运行时 URL 上没有查询参数,导致 mock router 提取不到 `id` 等参数。
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
// ❌ 错误:params 在拦截器之后拼接,mock 拿不到 id
|
|
168
|
+
export function getById(id: number) {
|
|
169
|
+
return request({ url: '/api/forecast/get-id', method: 'get', params: { id } })
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// ✅ 正确:参数直接拼在 URL 上
|
|
173
|
+
export function getById(id: number) {
|
|
174
|
+
return request({ url: `/api/forecast/get-id?id=${id}`, method: 'get' })
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**适用范围**:所有 GET 请求的 mock API 都必须将参数直接拼入 URL 字符串,不能依赖 axios 的 `params` 配置。
|
|
179
|
+
|
|
180
|
+
### 4. 语言包 key 结构与 i18n 引用不匹配
|
|
181
|
+
|
|
182
|
+
**现象**:页面上显示原始 key 名(如 `forecast-order.listTitle`)而非翻译文案。
|
|
183
|
+
|
|
184
|
+
**根因**:语言包模块通过 `import.meta.glob` 自动加载,文件夹名作为模块 key(如 `forecast-order`)。`$t('forecast-order.listTitle')` 按**嵌套对象路径**解析,而非扁平 key。语言包必须使用嵌套对象结构:
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
// ✅ 正确:嵌套对象,$t('forecast-order.status.DRAFT') 可以解析
|
|
188
|
+
export default {
|
|
189
|
+
status: { DRAFT: '草稿', SUBMITTED: '已提交' },
|
|
190
|
+
msg: { saveSuccess: '保存成功' },
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// ❌ 错误:扁平 key,$t('forecast-order.status.DRAFT') 无法解析为 'forecast-order'['status']['DRAFT']
|
|
194
|
+
export default {
|
|
195
|
+
'status.DRAFT': '草稿',
|
|
196
|
+
'msg.saveSuccess': '保存成功',
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**自检清单**:
|
|
201
|
+
- 所有 `$t('forecast-order.xxx')` 引用能在语言包中找到对应嵌套路径
|
|
202
|
+
- 特别注意模板字符串中的动态 key:`` $t(`forecast-order.status.${val}`) ``
|
|
203
|
+
- 语言包有 `{ immediate: true }` 的 watch 不能遗漏语言初始化时机
|
|
204
|
+
|
|
205
|
+
### 5. mock 菜单路由出现双斜杠 `//`
|
|
206
|
+
|
|
207
|
+
**现象**:点击左侧菜单跳转报错,URL 变成 `//forecast-order`。
|
|
208
|
+
|
|
209
|
+
**根因**:`permission.ts` 的 `generatePath` 函数拼接路由时 `parentPath=''`,结果为 `'' + '/' + '/forecast-order'` = `'//forecast-order'`。去双斜杠逻辑需要 `!item.originalAddr` 为 `true` 才生效。
|
|
210
|
+
|
|
211
|
+
**修复**:mock 菜单中 `originalAddr` 设为 `null`,不需要该字段:
|
|
212
|
+
|
|
213
|
+
```ts
|
|
214
|
+
export const mockMenus = [
|
|
215
|
+
{
|
|
216
|
+
menuId: 1001,
|
|
217
|
+
menuCode: 'forecast-order',
|
|
218
|
+
menuUrl: '/forecast-order',
|
|
219
|
+
menuName: '销售预测',
|
|
220
|
+
originalAddr: null, // ← 关键:不能设为非空值
|
|
221
|
+
children: [],
|
|
222
|
+
// ...
|
|
223
|
+
},
|
|
224
|
+
]
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### 6. drawer/dialog 组件 v-model 循环同步
|
|
228
|
+
|
|
229
|
+
**现象**:弹窗打开后空白,或者关闭后无法再打开。
|
|
230
|
+
|
|
231
|
+
**根因**:手动用 `ref` + `watch` 同步 `props.visible ↔ internal visible` 加上 `el-drawer v-model` 内部也有自己的响应式逻辑,造成循环触发或事件丢失。
|
|
232
|
+
|
|
233
|
+
**修复**:直接用 `:model-value` + `@update:model-value` 模式,不创建内部 visible ref:
|
|
234
|
+
|
|
235
|
+
```html
|
|
236
|
+
<el-drawer
|
|
237
|
+
:model-value="props.visible"
|
|
238
|
+
@update:model-value="onVisibleChange"
|
|
239
|
+
>
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
```ts
|
|
243
|
+
function onVisibleChange(val: boolean) {
|
|
244
|
+
if (!val) { /* 清理状态 */ }
|
|
245
|
+
emit('update:visible', val)
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### 7. 硬编码文案遗漏
|
|
250
|
+
|
|
251
|
+
**现象**:表单校验错误提示、ElMessage 弹窗消息、el-drawer 标题等始终显示中文,不随语言切换变化。
|
|
252
|
+
|
|
253
|
+
**检查范围**:
|
|
254
|
+
- `el-form` 的 `:rules` 中 `message` 字段
|
|
255
|
+
- `ElMessage.success/warning/error()` 调用
|
|
256
|
+
- `ElMessageBox.confirm()` 的 `title`、`message`
|
|
257
|
+
- 弹窗/抽屉的 `:title` 属性
|
|
258
|
+
- 表格列配置中 `placeholder`、`searchOptions.loop` 的 `label`
|
|
259
|
+
- `'是'/'否'`、`'确定'/'取消'` 等通用词
|
|
260
|
+
|
|
261
|
+
**修复**:以上所有位置统一使用 `t('module.key')` 或 `$t('module.key')`。需要先在语言包中定义对应 key。
|
|
262
|
+
|