@agile-team/wl-skills-kit 1.0.0

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.
Files changed (112) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +328 -0
  3. package/bin/wl-skills.js +104 -0
  4. package/files/.github/copilot-instructions.md +211 -0
  5. package/files/.github/docs/SYS_MENU_INFO.md +247 -0
  6. package/files/.github/docs/menu-sync-design.md +265 -0
  7. package/files/.github/docs/use-skill.md +379 -0
  8. package/files/.github/docs/wl-skills-kit.md +266 -0
  9. package/files/.github/skills/api-contract/SKILL.md +247 -0
  10. package/files/.github/skills/convention-extract/SKILL.md +355 -0
  11. package/files/.github/skills/menu-sync/SKILL.md +255 -0
  12. package/files/.github/skills/menu-sync/env/guide.md +73 -0
  13. package/files/.github/skills/page-codegen/SKILL.md +825 -0
  14. package/files/.github/skills/page-codegen/TPL-CHANGE-HISTORY.md +281 -0
  15. package/files/.github/skills/page-codegen/TPL-DETAIL-TABS.md +1112 -0
  16. package/files/.github/skills/page-codegen/TPL-DRIVEN.md +124 -0
  17. package/files/.github/skills/page-codegen/TPL-FORM-ROUTE.md +441 -0
  18. package/files/.github/skills/page-codegen/TPL-LIST.md +196 -0
  19. package/files/.github/skills/page-codegen/TPL-MASTER-DETAIL.md +153 -0
  20. package/files/.github/skills/page-codegen/TPL-OPERATION-STATION.md +442 -0
  21. package/files/.github/skills/page-codegen/TPL-RECORD-FORM.md +376 -0
  22. package/files/.github/skills/page-codegen/TPL-TREE-LIST.md +191 -0
  23. package/files/.github/skills/prototype-scan/SKILL.md +414 -0
  24. package/files/demo/README.md +44 -0
  25. package/files/demo/produce/aiflow/mmwr-customer-apply-add/api.md +54 -0
  26. package/files/demo/produce/aiflow/mmwr-customer-apply-add/data.ts +346 -0
  27. package/files/demo/produce/aiflow/mmwr-customer-apply-add/index.scss +1 -0
  28. package/files/demo/produce/aiflow/mmwr-customer-apply-add/index.vue +28 -0
  29. package/files/demo/produce/aiflow/mmwr-customer-apply-add-form/data.ts +115 -0
  30. package/files/demo/produce/aiflow/mmwr-customer-apply-add-form/index.scss +44 -0
  31. package/files/demo/produce/aiflow/mmwr-customer-apply-add-form/index.vue +43 -0
  32. package/files/demo/produce/aiflow/mmwr-customer-apply-change/data.ts +338 -0
  33. package/files/demo/produce/aiflow/mmwr-customer-apply-change/index.scss +1 -0
  34. package/files/demo/produce/aiflow/mmwr-customer-apply-change/index.vue +28 -0
  35. package/files/demo/produce/aiflow/mmwr-customer-apply-change-form/data.ts +115 -0
  36. package/files/demo/produce/aiflow/mmwr-customer-apply-change-form/index.scss +44 -0
  37. package/files/demo/produce/aiflow/mmwr-customer-apply-change-form/index.vue +43 -0
  38. package/files/demo/produce/aiflow/mmwr-customer-apply-change-history/data.ts +196 -0
  39. package/files/demo/produce/aiflow/mmwr-customer-apply-change-history/index.scss +150 -0
  40. package/files/demo/produce/aiflow/mmwr-customer-apply-change-history/index.vue +79 -0
  41. package/files/demo/produce/aiflow/mmwr-customer-archive/api.md +88 -0
  42. package/files/demo/produce/aiflow/mmwr-customer-archive/data.ts +601 -0
  43. package/files/demo/produce/aiflow/mmwr-customer-archive/index.scss +1 -0
  44. package/files/demo/produce/aiflow/mmwr-customer-archive/index.vue +64 -0
  45. package/files/demo/produce/aiflow/mmwr-customer-detail/api.md +67 -0
  46. package/files/demo/produce/aiflow/mmwr-customer-detail/data.ts +286 -0
  47. package/files/demo/produce/aiflow/mmwr-customer-detail/index.scss +139 -0
  48. package/files/demo/produce/aiflow/mmwr-customer-detail/index.vue +318 -0
  49. package/files/demo/produce/aiflow/mmwr-temp-customer-archive/api.md +98 -0
  50. package/files/demo/produce/aiflow/mmwr-temp-customer-archive/data.ts +543 -0
  51. package/files/demo/produce/aiflow/mmwr-temp-customer-archive/index.scss +1 -0
  52. package/files/demo/produce/aiflow/mmwr-temp-customer-archive/index.vue +52 -0
  53. package/files/demo/sale/demo/add-demo/data.ts +518 -0
  54. package/files/demo/sale/demo/add-demo/index.scss +207 -0
  55. package/files/demo/sale/demo/add-demo/index.vue +167 -0
  56. package/files/demo/sale/demo/billet-flame-cut-plan/data.ts +524 -0
  57. package/files/demo/sale/demo/billet-flame-cut-plan/index.scss +155 -0
  58. package/files/demo/sale/demo/billet-flame-cut-plan/index.vue +117 -0
  59. package/files/demo/sale/demo/domestic-trade-order/data.ts +308 -0
  60. package/files/demo/sale/demo/domestic-trade-order/index.scss +99 -0
  61. package/files/demo/sale/demo/domestic-trade-order/index.vue +77 -0
  62. package/files/demo/sale/demo/heat-batch-return/data.ts +367 -0
  63. package/files/demo/sale/demo/heat-batch-return/index.scss +100 -0
  64. package/files/demo/sale/demo/heat-batch-return/index.vue +170 -0
  65. package/files/demo/sale/demo/heat-batch-return/meltDialog.vue +320 -0
  66. package/files/demo/sale/demo/metallurgical-spec/data.ts +825 -0
  67. package/files/demo/sale/demo/metallurgical-spec/index.scss +264 -0
  68. package/files/demo/sale/demo/metallurgical-spec/index.vue +309 -0
  69. package/files/docs/jh-date-range.md +257 -0
  70. package/files/docs/jh-date.md +222 -0
  71. package/files/docs/jh-dept-picker.md +190 -0
  72. package/files/docs/jh-drag-row.md +590 -0
  73. package/files/docs/jh-file-upload.md +216 -0
  74. package/files/docs/jh-pagination.md +505 -0
  75. package/files/docs/jh-picker.md +218 -0
  76. package/files/docs/jh-select.md +148 -0
  77. package/files/docs/jh-text.md +248 -0
  78. package/files/docs/jh-user-picker.md +197 -0
  79. package/files/docs/page-query-hook-best-practices.md +362 -0
  80. package/files/docs/request.md +925 -0
  81. package/files/src/components/global/C_ParentView/index.vue +3 -0
  82. package/files/src/components/global/C_RightToolbar/index.vue +459 -0
  83. package/files/src/components/global/C_Splitter/index.vue +195 -0
  84. package/files/src/components/global/C_SvgIcon/index.vue +61 -0
  85. package/files/src/components/global/C_SvgIcon/svgicon.js +10 -0
  86. package/files/src/components/global/C_TagStatus/README.md +264 -0
  87. package/files/src/components/global/C_TagStatus/config.ts +192 -0
  88. package/files/src/components/global/C_TagStatus/index.vue +127 -0
  89. package/files/src/components/global/C_TagStatus/types.ts +64 -0
  90. package/files/src/components/global/C_Tree/README.md +153 -0
  91. package/files/src/components/global/C_Tree/index.scss +42 -0
  92. package/files/src/components/global/C_Tree/index.vue +119 -0
  93. package/files/src/components/global/C_Tree/types.ts +59 -0
  94. package/files/src/components/local/c_formModal/README.md +235 -0
  95. package/files/src/components/local/c_formModal/data.ts +95 -0
  96. package/files/src/components/local/c_formModal/index.scss +8 -0
  97. package/files/src/components/local/c_formModal/index.vue +107 -0
  98. package/files/src/components/local/c_formSections/README.md +496 -0
  99. package/files/src/components/local/c_formSections/data.ts +175 -0
  100. package/files/src/components/local/c_formSections/index.scss +280 -0
  101. package/files/src/components/local/c_formSections/index.vue +429 -0
  102. package/files/src/components/local/c_listModal/data.ts +41 -0
  103. package/files/src/components/local/c_listModal/index.vue +136 -0
  104. package/files/src/components/local/c_spliterTitle/index.scss +25 -0
  105. package/files/src/components/local/c_spliterTitle/index.vue +21 -0
  106. package/files/src/components/remote/AGGrid/README.md +530 -0
  107. package/files/src/components/remote/BaseForm/README.md +508 -0
  108. package/files/src/components/remote/BaseQuery/README.md +865 -0
  109. package/files/src/components/remote/BaseTable/README.md +941 -0
  110. package/files/src/components/remote/BaseToolbar/README.md +496 -0
  111. package/files/src/types/page.ts +24 -0
  112. package/package.json +31 -0
@@ -0,0 +1,346 @@
1
+ import {
2
+ AbstractPageQueryHook,
3
+ BaseQueryItemDesc,
4
+ ActionButtonDesc,
5
+ TableColumnDesc
6
+ } from "@/types/page";
7
+ import { postAction } from "@jhlc/common-core/src/api/action";
8
+ import envConfig from "@jhlc/common-core/src/store/env-config";
9
+ import { ElMessage, ElMessageBox } from "element-plus";
10
+ import { h, resolveComponent } from "vue";
11
+
12
+ // ===== 状态色块渲染 =====
13
+ const STATUS_TAG_MAP: Record<string, Record<string, string>> = {
14
+ approvalStatus: {
15
+ 开立审批中: "",
16
+ 审批完成: "success",
17
+ 驳回: "danger",
18
+ 流程终止: "info"
19
+ },
20
+ verifyStatus: { 已核实: "success", 未核实: "info" }
21
+ };
22
+ function renderStatusTag(row: any, field: string) {
23
+ const val = row[field];
24
+ const typeMap = STATUS_TAG_MAP[field];
25
+ if (!typeMap) return val;
26
+ const type = Object.prototype.hasOwnProperty.call(typeMap, val)
27
+ ? typeMap[val]
28
+ : undefined;
29
+ if (type === undefined) return val;
30
+ return h(
31
+ resolveComponent("ElTag") as any,
32
+ { type: type || "", effect: "light", size: "small" },
33
+ () => val
34
+ );
35
+ }
36
+
37
+ export const API_CONFIG = {
38
+ list: "/sale/customerApply/addList",
39
+ remove: "/sale/customerApply/remove",
40
+ getById: "/sale/customerApply/getById",
41
+ save: "/sale/customerApply/save",
42
+ update: "/sale/customerApply/update",
43
+ submit: "/sale/customerApply/submit",
44
+ withdraw: "/sale/customerApply/withdraw",
45
+ export: "/sale/customerApply/export"
46
+ } as const;
47
+
48
+ const OPTS = {
49
+ approvalProduct: [
50
+ { label: "热轧", value: "热轧" },
51
+ { label: "盘元", value: "盘元" },
52
+ { label: "冷精", value: "冷精" },
53
+ { label: "汽车", value: "汽车" }
54
+ ],
55
+ applyOrg: [
56
+ { label: "不锈鋼接單中心", value: "不锈鋼接單中心" },
57
+ {
58
+ label: "江阴华新特殊合金材料有限公司",
59
+ value: "江阴华新特殊合金材料有限公司"
60
+ },
61
+ { label: "揉瞒管理中心", value: "揉瞒管理中心" },
62
+ { label: "烟台华鑫再生资源有限公司", value: "烟台华鑫再生资源有限公司" }
63
+ ],
64
+ applyType: [
65
+ { label: "新增", value: "新增" },
66
+ { label: "变更", value: "变更" }
67
+ ],
68
+ applyDept: [
69
+ { label: "業務管理處", value: "業務管理處" },
70
+ { label: "線材銷售部", value: "線材銷售部" },
71
+ { label: "無縫管銷售處", value: "無縫管銷售處" },
72
+ { label: "華南銷售科", value: "華南銷售科" },
73
+ { label: "汽車產業銷售科", value: "汽車產業銷售科" }
74
+ ],
75
+ applicant: [
76
+ { label: "魏子明", value: "魏子明" },
77
+ { label: "龚辉鉴", value: "龚辉鉴" },
78
+ { label: "宋书迪", value: "宋书迪" },
79
+ { label: "李锋", value: "李锋" },
80
+ { label: "杨松", value: "杨松" }
81
+ ],
82
+ approvalStatus: [
83
+ { label: "开立审批中", value: "开立审批中" },
84
+ { label: "审批完成", value: "审批完成" },
85
+ { label: "驳回", value: "驳回" },
86
+ { label: "流程终止", value: "流程终止" }
87
+ ],
88
+ verifyStatus: [
89
+ { label: "已核实", value: "已核实" },
90
+ { label: "未核实", value: "未核实" }
91
+ ]
92
+ };
93
+
94
+ const FORM_ROUTE = "/aiflow/mmwrCustomerApplyAddForm";
95
+
96
+ function navigateToForm(query?: Record<string, string>) {
97
+ const router = envConfig()?.router;
98
+ if (!router) {
99
+ ElMessage.error("路由未初始化,请刷新页面重试");
100
+ return;
101
+ }
102
+ const target: any = { path: FORM_ROUTE };
103
+ if (query) target.query = query;
104
+ location.href = router.resolve(target).href;
105
+ }
106
+
107
+ export function createPage() {
108
+ const Page = new (class extends AbstractPageQueryHook {
109
+ constructor() {
110
+ super({ url: { list: API_CONFIG.list, remove: API_CONFIG.remove } });
111
+ }
112
+
113
+ queryDef(): BaseQueryItemDesc<any>[] {
114
+ return [
115
+ { name: "customerCode", label: "客户编码", placeholder: "请输入" },
116
+ {
117
+ name: "approvalProduct",
118
+ label: "审批产品别",
119
+ component: () => ({ tag: "jh-select", items: OPTS.approvalProduct })
120
+ },
121
+ {
122
+ name: "applyOrg",
123
+ label: "申请组织",
124
+ component: () => ({ tag: "jh-select", items: OPTS.applyOrg })
125
+ },
126
+ { name: "customerName", label: "客户名称", placeholder: "请输入" },
127
+ {
128
+ name: "applyType",
129
+ label: "申请类型",
130
+ component: () => ({ tag: "jh-select", items: OPTS.applyType })
131
+ },
132
+ {
133
+ name: "applyDept",
134
+ label: "申请部门",
135
+ component: () => ({ tag: "jh-select", items: OPTS.applyDept })
136
+ },
137
+ {
138
+ name: "applicant",
139
+ label: "申请人",
140
+ component: () => ({ tag: "jh-select", items: OPTS.applicant })
141
+ },
142
+ {
143
+ name: "approvalStatus",
144
+ label: "审批状态",
145
+ component: () => ({ tag: "jh-select", items: OPTS.approvalStatus })
146
+ },
147
+ {
148
+ name: "applyDate",
149
+ startName: "applyDateStart",
150
+ endName: "applyDateEnd",
151
+ label: "申请日期",
152
+ component: () => ({
153
+ tag: "jh-date",
154
+ type: "daterange",
155
+ rangeSeparator: "至",
156
+ showFormat: "YYYY-MM-DD",
157
+ valueFormat: "YYYY-MM-DD"
158
+ })
159
+ },
160
+ {
161
+ name: "verifyStatus",
162
+ label: "核实状态",
163
+ component: () => ({ tag: "jh-select", items: OPTS.verifyStatus })
164
+ }
165
+ ];
166
+ }
167
+
168
+ toolbarDef(): ActionButtonDesc[] {
169
+ return [
170
+ {
171
+ name: "primary",
172
+ label: "新增申请",
173
+ onClick: () => navigateToForm()
174
+ },
175
+ {
176
+ label: "提交",
177
+ type: "primary",
178
+ plain: true,
179
+ onClick: () => {
180
+ const rows = this.tableRef.value?.getSelectionRows();
181
+ if (!rows?.length) {
182
+ ElMessage.warning("请先选择数据");
183
+ return;
184
+ }
185
+ const ids = rows.map((r: any) => r.id);
186
+ ElMessageBox.confirm("确定提交选中申请?", "提示", { type: "info" })
187
+ .then(() => {
188
+ postAction(API_CONFIG.submit, { ids }).then(() => {
189
+ ElMessage.success("提交成功");
190
+ this.select();
191
+ });
192
+ })
193
+ .catch(() => {});
194
+ }
195
+ },
196
+ {
197
+ label: "删除",
198
+ type: "danger",
199
+ plain: true,
200
+ onClick: () => {
201
+ const rows = this.tableRef.value?.getSelectionRows();
202
+ if (!rows?.length) {
203
+ ElMessage.warning("请先选择数据");
204
+ return;
205
+ }
206
+ this.removeBatch();
207
+ }
208
+ },
209
+ {
210
+ label: "审批驳回",
211
+ type: "danger",
212
+ plain: true,
213
+ onClick: () => {
214
+ const rows = this.tableRef.value?.getSelectionRows();
215
+ if (!rows?.length) {
216
+ ElMessage.warning("请先选择数据");
217
+ return;
218
+ }
219
+ const ids = rows.map((r: any) => r.id);
220
+ ElMessageBox.confirm("确定驳回选中申请?", "提示", {
221
+ type: "warning"
222
+ })
223
+ .then(() => {
224
+ postAction(API_CONFIG.update, {
225
+ ids,
226
+ approvalStatus: "驳回"
227
+ }).then(() => {
228
+ ElMessage.success("已驳回");
229
+ this.select();
230
+ });
231
+ })
232
+ .catch(() => {});
233
+ }
234
+ },
235
+ {
236
+ label: "审批通过",
237
+ type: "success",
238
+ plain: true,
239
+ onClick: () => {
240
+ const rows = this.tableRef.value?.getSelectionRows();
241
+ if (!rows?.length) {
242
+ ElMessage.warning("请先选择数据");
243
+ return;
244
+ }
245
+ const ids = rows.map((r: any) => r.id);
246
+ ElMessageBox.confirm("确定审批通过?", "提示", { type: "success" })
247
+ .then(() => {
248
+ postAction(API_CONFIG.update, {
249
+ ids,
250
+ approvalStatus: "审批完成"
251
+ }).then(() => {
252
+ ElMessage.success("审批通过");
253
+ this.select();
254
+ });
255
+ })
256
+ .catch(() => {});
257
+ }
258
+ },
259
+ {
260
+ label: "导出",
261
+ plain: true,
262
+ onClick: () => {
263
+ postAction(API_CONFIG.export, this.queryParam.value).then(() => {
264
+ ElMessage.success("导出成功");
265
+ });
266
+ }
267
+ }
268
+ ];
269
+ }
270
+
271
+ columnsDef(): TableColumnDesc<any>[] {
272
+ return [
273
+ { type: "selection" },
274
+ { type: "index" },
275
+ {
276
+ label: "申请编码",
277
+ name: "applyCode",
278
+ minWidth: 160,
279
+ defaultSlot: ({ row }: any) =>
280
+ h(
281
+ "span",
282
+ {
283
+ style:
284
+ "color:#409eff;cursor:pointer;text-decoration:underline;",
285
+ onClick: () => navigateToForm({ id: row.id })
286
+ },
287
+ row.applyCode
288
+ )
289
+ },
290
+ { label: "申请类型", name: "applyType", minWidth: 100 },
291
+ { label: "客户编码", name: "customerCode", minWidth: 120 },
292
+ {
293
+ label: "客户名称",
294
+ name: "customerName",
295
+ minWidth: 200,
296
+ showOverflowTooltip: true
297
+ },
298
+ { label: "审批产品别", name: "approvalProduct", minWidth: 100 },
299
+ { label: "申请原因", name: "applyReason", minWidth: 120 },
300
+ { label: "申请人", name: "applicant", minWidth: 100 },
301
+ { label: "申请部门", name: "applyDept", minWidth: 130 },
302
+ {
303
+ label: "申请组织",
304
+ name: "applyOrg",
305
+ minWidth: 180,
306
+ showOverflowTooltip: true
307
+ },
308
+ { label: "创建人", name: "creator", minWidth: 100 },
309
+ { label: "创建时间", name: "createTime", minWidth: 160 },
310
+ {
311
+ label: "审批状态",
312
+ name: "approvalStatus",
313
+ minWidth: 110,
314
+ fixed: "right",
315
+ defaultSlot: ({ row }: any) => renderStatusTag(row, "approvalStatus")
316
+ },
317
+ {
318
+ label: "核实状态",
319
+ name: "verifyStatus",
320
+ minWidth: 100,
321
+ fixed: "right",
322
+ defaultSlot: ({ row }: any) => renderStatusTag(row, "verifyStatus")
323
+ },
324
+ {
325
+ label: "操作",
326
+ width: 140,
327
+ fixed: "right",
328
+ operations: [
329
+ {
330
+ name: "edit",
331
+ label: "编辑",
332
+ onClick: (row: any) => navigateToForm({ id: row.id })
333
+ },
334
+ {
335
+ name: "remove",
336
+ label: "删除",
337
+ onClick: (row: any) => this.remove(row.id)
338
+ }
339
+ ]
340
+ }
341
+ ];
342
+ }
343
+ })();
344
+
345
+ return (Page as any).create() as any;
346
+ }
@@ -0,0 +1 @@
1
+ // 新增申请列表页样式
@@ -0,0 +1,28 @@
1
+ <template>
2
+ <div class="app-container app-page-container">
3
+ <BaseQuery :form="queryParam" :items="queryItems" @select="select" @reset="select" />
4
+ <BaseToolbar :items="toolbars" />
5
+ <BaseTable ref="tableRef" :data="list" :columns="columns" showToolbar />
6
+ <jh-pagination
7
+ v-show="page.total && page.total > 0"
8
+ :total="page.total || 0"
9
+ v-model:currentPage="page.current"
10
+ v-model:pageSize="page.size"
11
+ @current-change="select"
12
+ @size-change="select"
13
+ />
14
+ </div>
15
+ </template>
16
+
17
+ <script setup lang="ts">
18
+ import { createPage } from "./data";
19
+
20
+ const Page = createPage();
21
+ const { tableRef, page, queryParam, list, queryItems, columns, toolbars, select } = Page;
22
+
23
+ onMounted(() => select());
24
+ </script>
25
+
26
+ <style scoped lang="scss">
27
+ @import "./index.scss";
28
+ </style>
@@ -0,0 +1,115 @@
1
+ import { postAction, getAction } from "@jhlc/common-core/src/api/action";
2
+ import { ElMessage } from "element-plus";
3
+ import { useRouter } from "vue-router";
4
+ import { createAddMockData } from "@/components/local/c_customerTabs/data";
5
+ import envConfig from "@jhlc/common-core/src/store/env-config";
6
+
7
+ export const API_CONFIG = {
8
+ getById: "/sale/customerApply/getById",
9
+ save: "/sale/customerApply/save",
10
+ submit: "/sale/customerApply/submit",
11
+ changeHistory: "/sale/customerApply/changeHistory"
12
+ } as const;
13
+
14
+ export function useApplyAddForm(tabsRef: any) {
15
+ const router = useRouter();
16
+ const loading = ref(false);
17
+ const isEdit = ref(false);
18
+ const currentId = ref<string>("");
19
+
20
+ async function loadDetail(id: string) {
21
+ loading.value = true;
22
+ isEdit.value = true;
23
+ currentId.value = id;
24
+ try {
25
+ const res = await getAction(API_CONFIG.getById, { id });
26
+ if (res?.data) tabsRef.value?.loadData(res.data);
27
+ } finally {
28
+ loading.value = false;
29
+ }
30
+ }
31
+
32
+ function loadMockData() {
33
+ tabsRef.value?.loadData(createAddMockData());
34
+ }
35
+
36
+ async function handleSave() {
37
+ const valid = await tabsRef.value?.validate();
38
+ if (!valid) {
39
+ ElMessage.warning("请完善必填项");
40
+ return;
41
+ }
42
+ loading.value = true;
43
+ try {
44
+ const formData = tabsRef.value?.collectFormData();
45
+ const payload = isEdit.value
46
+ ? { ...formData, id: currentId.value }
47
+ : formData;
48
+ const res = await postAction(API_CONFIG.save, payload);
49
+ if (res?.code === 200) {
50
+ ElMessage.success("保存成功");
51
+ if (!isEdit.value && res.data?.id) {
52
+ currentId.value = res.data.id;
53
+ isEdit.value = true;
54
+ }
55
+ }
56
+ } finally {
57
+ loading.value = false;
58
+ }
59
+ }
60
+
61
+ async function handleSaveAndChange() {
62
+ const valid = await tabsRef.value?.validate();
63
+ if (!valid) {
64
+ ElMessage.warning("请完善必填项");
65
+ return;
66
+ }
67
+ loading.value = true;
68
+ try {
69
+ const formData = tabsRef.value?.collectFormData();
70
+ const payload = isEdit.value
71
+ ? { ...formData, id: currentId.value }
72
+ : formData;
73
+ const saveRes = await postAction(API_CONFIG.save, payload);
74
+ if (saveRes?.code === 200) {
75
+ const id = currentId.value || saveRes.data?.id;
76
+ const submitRes = await postAction(API_CONFIG.submit, { ids: [id] });
77
+ if (submitRes?.code === 200) ElMessage.success("保存并变更成功");
78
+ }
79
+ } finally {
80
+ loading.value = false;
81
+ }
82
+ }
83
+
84
+ const HISTORY_ROUTE = "/aiflow/mmwrCustomerApplyChangeHistory";
85
+ function handleChangeHistory() {
86
+ if (!currentId.value) {
87
+ ElMessage.warning("请先保存申请后再查看变更历史");
88
+ return;
89
+ }
90
+ const router = envConfig()?.router;
91
+ if (!router) {
92
+ ElMessage.error("路由未初始化,请刷新页面重试");
93
+ return;
94
+ }
95
+ location.href = router.resolve({
96
+ path: HISTORY_ROUTE,
97
+ query: { id: currentId.value }
98
+ }).href;
99
+ }
100
+
101
+ function handleCancel() {
102
+ router.back();
103
+ }
104
+
105
+ return {
106
+ loading,
107
+ isEdit,
108
+ loadDetail,
109
+ loadMockData,
110
+ handleSave,
111
+ handleSaveAndChange,
112
+ handleChangeHistory,
113
+ handleCancel
114
+ };
115
+ }
@@ -0,0 +1,44 @@
1
+ .app-page-container {
2
+ overflow-y: auto;
3
+ padding-bottom: 24px;
4
+ }
5
+
6
+ .page-header {
7
+ display: flex;
8
+ align-items: center;
9
+ margin-bottom: 8px;
10
+
11
+ .page-title {
12
+ font-size: 18px;
13
+ font-weight: 600;
14
+ margin-right: 12px;
15
+ }
16
+
17
+ .page-tag {
18
+ display: inline-block;
19
+ padding: 2px 8px;
20
+ font-size: 12px;
21
+ border-radius: 4px;
22
+ margin-right: 8px;
23
+
24
+ &--add {
25
+ background-color: var(--el-color-primary-light-9);
26
+ color: var(--el-color-primary);
27
+ border: 1px solid var(--el-color-primary-light-7);
28
+ }
29
+
30
+ &--status {
31
+ background-color: var(--el-color-warning-light-9);
32
+ color: var(--el-color-warning);
33
+ border: 1px solid var(--el-color-warning-light-7);
34
+ }
35
+ }
36
+
37
+ .only-required-check {
38
+ margin-left: 8px;
39
+ }
40
+ }
41
+
42
+ .page-toolbar {
43
+ margin-bottom: 12px;
44
+ }
@@ -0,0 +1,43 @@
1
+ <template>
2
+ <div class="app-container app-page-container" v-loading="loading">
3
+ <div class="page-header">
4
+ <span class="page-title">客户申请详情</span>
5
+ <span class="page-tag page-tag--add">新增</span>
6
+ <span class="page-tag page-tag--status">未审核</span>
7
+ <el-checkbox v-model="onlyRequired" class="only-required-check">只看必填项</el-checkbox>
8
+ </div>
9
+ <div class="page-toolbar">
10
+ <el-button type="danger" @click="handleSaveAndChange">保存并变更</el-button>
11
+ <el-button type="warning" @click="handleSave">保存</el-button>
12
+ <el-button type="primary" plain @click="handleChangeHistory">变更历史查询</el-button>
13
+ <el-button @click="handleCancel">取消</el-button>
14
+ </div>
15
+ <c_customerTabs ref="tabsRef" mode="add" :only-required="onlyRequired" />
16
+ </div>
17
+ </template>
18
+
19
+ <script setup lang="ts">
20
+ import { useRoute } from "vue-router";
21
+ import { useApplyAddForm } from "./data";
22
+ import c_customerTabs from "@/components/local/c_customerTabs/index.vue";
23
+
24
+ const tabsRef = ref();
25
+ const route = useRoute();
26
+ const onlyRequired = ref(false);
27
+
28
+ const { loading, loadDetail, loadMockData, handleSave, handleSaveAndChange, handleChangeHistory, handleCancel } =
29
+ useApplyAddForm(tabsRef);
30
+
31
+ onMounted(() => {
32
+ const id = route.query.id as string;
33
+ if (id) {
34
+ loadDetail(id);
35
+ } else {
36
+ loadMockData();
37
+ }
38
+ });
39
+ </script>
40
+
41
+ <style scoped lang="scss">
42
+ @import "./index.scss";
43
+ </style>