@agile-team/wl-skills-kit 2.11.0 → 2.11.2

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 (95) hide show
  1. package/CHANGELOG.md +47 -9
  2. package/README.md +41 -23
  3. package/bin/wl-skills.js +133 -39
  4. package/docs/agent-pipeline-runbook.md +3 -3
  5. package/docs//345/205/250/347/233/230/345/210/206/346/236/220/344/270/216/346/231/272/350/203/275/344/275/223/346/220/255/345/273/272/346/214/207/345/215/227.md +4 -4
  6. package/files/.wl-skills/copilot-instructions-full.md +233 -233
  7. package/files/.wl-skills/docs/jh-pagination.md +505 -505
  8. package/files/.wl-skills/docs/page-spec-schema.md +109 -0
  9. package/files/.wl-skills/docs/request.md +940 -940
  10. package/files/.wl-skills/guides/architecture.md +1 -1
  11. package/files/.wl-skills/skills/core/convention-audit/SKILL.md +3 -3
  12. package/files/.wl-skills/skills/core/page-codegen/SKILL.md +10 -4
  13. package/files/.wl-skills/skills/core/spec-doc-parse/SKILL.md +332 -332
  14. package/files/.wl-skills/skills/core/spec-doc-parse/USAGE.md +97 -97
  15. package/files/.wl-skills/skills/sync/permission-sync/USAGE.md +107 -107
  16. package/files/.wl-skills/src/components/global/C_ParentView/index.vue +3 -3
  17. package/files/.wl-skills/src/components/global/C_RightToolbar/index.vue +157 -157
  18. package/files/.wl-skills/src/components/global/C_SvgIcon/index.vue +31 -31
  19. package/files/.wl-skills/src/components/global/C_SvgIcon/svgicon.js +10 -10
  20. package/files/.wl-skills/src/components/global/C_TagStatus/README.md +264 -264
  21. package/files/.wl-skills/src/components/global/C_TagStatus/config.ts +192 -192
  22. package/files/.wl-skills/src/components/global/C_TagStatus/index.vue +106 -106
  23. package/files/.wl-skills/src/components/global/C_TagStatus/types.ts +64 -64
  24. package/files/.wl-skills/src/components/global/C_Tree/README.md +153 -153
  25. package/files/.wl-skills/src/components/global/C_Tree/index.scss +42 -42
  26. package/files/.wl-skills/src/components/global/C_Tree/index.vue +78 -78
  27. package/files/.wl-skills/src/components/global/C_Tree/types.ts +59 -59
  28. package/files/.wl-skills/src/components/local/c_formModal/README.md +235 -235
  29. package/files/.wl-skills/src/components/local/c_formModal/data.ts +95 -95
  30. package/files/.wl-skills/src/components/local/c_formModal/index.scss +8 -8
  31. package/files/.wl-skills/src/components/local/c_formModal/index.vue +107 -107
  32. package/files/.wl-skills/src/components/local/c_formSections/data.ts +175 -175
  33. package/files/.wl-skills/src/components/local/c_formSections/index.scss +280 -280
  34. package/files/.wl-skills/src/components/local/c_formSections/index.vue +429 -429
  35. package/files/.wl-skills/src/components/local/c_listModal/data.ts +41 -41
  36. package/files/.wl-skills/src/components/local/c_listModal/index.vue +136 -136
  37. package/files/.wl-skills/src/components/local/c_spliterTitle/index.scss +25 -25
  38. package/files/.wl-skills/src/components/local/c_spliterTitle/index.vue +21 -21
  39. package/files/.wl-skills/src/components/remote/AGGrid/README.md +530 -530
  40. package/files/.wl-skills/src/components/remote/BaseForm/README.md +508 -508
  41. package/files/.wl-skills/src/components/remote/BaseQuery/README.md +865 -865
  42. package/files/.wl-skills/src/components/remote/BaseTable/README.md +941 -941
  43. package/files/.wl-skills/src/components/remote/BaseToolbar/README.md +496 -496
  44. package/files/.wl-skills/src/types/page.ts +24 -24
  45. package/files/.wl-skills/standards/04-coding-basics.md +39 -1
  46. package/files/.wl-skills/standards/09-typescript.md +26 -3
  47. package/files/.wl-skills/standards/14-layout-containers.md +6 -6
  48. package/files/.wl-skills/standards/index.md +2 -2
  49. package/files/.wl-skills/templates/README.md +44 -44
  50. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add/api.md +54 -54
  51. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add/data.ts +346 -346
  52. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add/index.scss +1 -1
  53. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add/index.vue +28 -28
  54. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add-form/data.ts +115 -115
  55. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add-form/index.scss +44 -44
  56. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add-form/index.vue +43 -43
  57. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-change/data.ts +338 -338
  58. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-change/index.scss +1 -1
  59. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-change/index.vue +28 -28
  60. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-change-form/data.ts +115 -115
  61. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-change-form/index.scss +44 -44
  62. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-change-form/index.vue +43 -43
  63. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-archive/api.md +88 -88
  64. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-archive/data.ts +601 -601
  65. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-archive/index.scss +1 -1
  66. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-archive/index.vue +64 -64
  67. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-detail/api.md +67 -67
  68. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-detail/data.ts +286 -286
  69. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-detail/index.scss +139 -139
  70. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-detail/index.vue +318 -318
  71. package/files/.wl-skills/templates/produce/aiflow/mmwr-temp-customer-archive/api.md +98 -98
  72. package/files/.wl-skills/templates/produce/aiflow/mmwr-temp-customer-archive/data.ts +543 -543
  73. package/files/.wl-skills/templates/produce/aiflow/mmwr-temp-customer-archive/index.scss +1 -1
  74. package/files/.wl-skills/templates/produce/aiflow/mmwr-temp-customer-archive/index.vue +52 -52
  75. package/files/.wl-skills/templates/sale/demo/add-demo/data.ts +518 -518
  76. package/files/.wl-skills/templates/sale/demo/billet-flame-cut-plan/data.ts +524 -524
  77. package/files/.wl-skills/templates/sale/demo/billet-flame-cut-plan/index.scss +154 -154
  78. package/files/.wl-skills/templates/sale/demo/billet-flame-cut-plan/index.vue +117 -117
  79. package/files/.wl-skills/templates/sale/demo/domestic-trade-order/data.ts +308 -308
  80. package/files/.wl-skills/templates/sale/demo/domestic-trade-order/index.scss +99 -99
  81. package/files/.wl-skills/templates/sale/demo/domestic-trade-order/index.vue +77 -77
  82. package/files/.wl-skills/templates/sale/demo/heat-batch-return/data.ts +367 -367
  83. package/files/.wl-skills/templates/sale/demo/heat-batch-return/index.scss +100 -100
  84. package/files/.wl-skills/templates/sale/demo/heat-batch-return/index.vue +170 -170
  85. package/files/.wl-skills/templates/sale/demo/heat-batch-return/meltDialog.vue +320 -320
  86. package/files/.wl-skills/templates/sale/demo/metallurgical-spec/data.ts +824 -824
  87. package/lib/ast-rules.js +304 -9
  88. package/lib/page-spec.js +588 -0
  89. package/lib/safe-fix.js +115 -0
  90. package/mcp/config.js +47 -47
  91. package/mcp/registry.js +6 -1
  92. package/mcp/tools/projectTools.js +19 -1
  93. package/package.json +16 -11
  94. package/files/.wl-skills/src/components/global/C_Splitter/index.scss +0 -61
  95. package/files/.wl-skills/src/components/global/C_Splitter/index.vue +0 -149
@@ -1,543 +1,543 @@
1
- import {
2
- AbstractPageQueryHook,
3
- BaseQueryItemDesc,
4
- ActionButtonDesc,
5
- TableColumnDesc
6
- } from "@/types/page";
7
- import type { BaseFormItemDesc } from "@jhlc/common-core/src/components/form/common/type";
8
- import { postAction } from "@jhlc/common-core/src/api/action";
9
- import envConfig from "@jhlc/common-core/src/store/env-config";
10
- import * as XLSX from "xlsx";
11
- import { h, resolveComponent } from "vue";
12
-
13
- /** 状态色块映射 */
14
- const STATUS_TAG_MAP: Record<string, Record<string, string>> = {
15
- convertStatus: { 已转化: "success", 未转化: "info" },
16
- customerStatus: { 临时客户: "warning", 正式客户: "success" },
17
- verifyStatus: { 已核实: "success", 未核实: "info" }
18
- };
19
- function renderStatusTag(row: any, field: string) {
20
- const val = row[field];
21
- const type = STATUS_TAG_MAP[field]?.[val];
22
- if (type === undefined) return val;
23
- return h(
24
- resolveComponent("ElTag") as any,
25
- { type, effect: "light", size: "small" },
26
- () => val
27
- );
28
- }
29
-
30
- export const API_CONFIG = {
31
- list: "/sale/tempCustomerArchive/list",
32
- remove: "/sale/tempCustomerArchive/remove",
33
- getById: "/sale/tempCustomerArchive/getById",
34
- save: "/sale/tempCustomerArchive/save",
35
- update: "/sale/tempCustomerArchive/update",
36
- convert: "/sale/tempCustomerArchive/convert",
37
- cancel: "/sale/tempCustomerArchive/cancel",
38
- claim: "/sale/tempCustomerArchive/claim",
39
- assign: "/sale/tempCustomerArchive/assign",
40
- recycle: "/sale/tempCustomerArchive/recycle",
41
- returnBack: "/sale/tempCustomerArchive/return",
42
- export: "/sale/tempCustomerArchive/export"
43
- } as const;
44
-
45
- /** Tab 类型 */
46
- export type TabType = "temp" | "formal" | "pool";
47
-
48
- const OPTS = {
49
- customerStatus: [
50
- { label: "临时客户", value: "临时客户" },
51
- { label: "正式客户", value: "正式客户" }
52
- ],
53
- customerType: [
54
- { label: "SYCSR001-交易客户", value: "SYCSR001-交易客户" },
55
- { label: "SYCSR002-直采客户", value: "SYCSR002-直采客户" }
56
- ],
57
- useOrg: [
58
- { label: "不锈鋼接單中心", value: "不锈鋼接單中心" },
59
- {
60
- label: "江阴华新特殊合金材料有限公司",
61
- value: "江阴华新特殊合金材料有限公司"
62
- },
63
- { label: "採瞒管理中心", value: "採瞒管理中心" },
64
- { label: "烟台华鑫再生资源有限公司", value: "烟台华鑫再生资源有限公司" }
65
- ],
66
- businessDept: [
67
- { label: "業務管理處", value: "業務管理處" },
68
- { label: "線材銷售部", value: "線材銷售部" },
69
- { label: "無縫管銷售處", value: "無縫管銷售處" },
70
- { label: "華南銷售科", value: "華南銷售科" },
71
- { label: "汽車產業銷售科", value: "汽車產業銷售科" },
72
- { label: "大陸行銷部", value: "大陸行銷部" },
73
- { label: "冷精棒業管部(台北)", value: "冷精棒業管部(台北)" },
74
- { label: "業管科", value: "業管科" },
75
- { label: "華東銷售科", value: "華東銷售科" }
76
- ],
77
- applicant: [
78
- { label: "魏子明", value: "魏子明" },
79
- { label: "龚辉鉴", value: "龚辉鉴" },
80
- { label: "宋书迪", value: "宋书迪" },
81
- { label: "李锋", value: "李锋" },
82
- { label: "杨松", value: "杨松" },
83
- { label: "王之勤", value: "王之勤" },
84
- { label: "邹建军", value: "邹建军" },
85
- { label: "龙成金", value: "龙成金" }
86
- ],
87
- product: [
88
- { label: "热轧", value: "热轧" },
89
- { label: "盘元", value: "盘元" },
90
- { label: "冷精", value: "冷精" },
91
- { label: "汽车", value: "汽车" }
92
- ],
93
- verifyStatus: [
94
- { label: "未核实", value: "未核实" },
95
- { label: "已核实", value: "已核实" }
96
- ],
97
- convertStatus: [
98
- { label: "已转化", value: "已转化" },
99
- { label: "未转化", value: "未转化" }
100
- ]
101
- };
102
-
103
- export { OPTS };
104
-
105
- /** c_formModal 配置 */
106
- export const modalConfig = {
107
- titlePrefix: "临时客户",
108
- width: "850px",
109
- columns: 2,
110
- labelWidth: "110px",
111
- formItems: [
112
- {
113
- name: "customerCode",
114
- label: "客户编号",
115
- disabled: true,
116
- placeholder: "系统自动生成"
117
- },
118
- {
119
- name: "customerName",
120
- label: "客户名称",
121
- required: true,
122
- placeholder: "请输入客户名称"
123
- },
124
- {
125
- name: "customerType",
126
- label: "客户类型",
127
- component: () => ({ tag: "jh-select", items: OPTS.customerType })
128
- },
129
- {
130
- name: "product",
131
- label: "产品别",
132
- component: () => ({ tag: "jh-select", items: OPTS.product })
133
- },
134
- { name: "contactPerson", label: "联系人", placeholder: "请输入联系人" },
135
- { name: "phone", label: "联系电话", placeholder: "请输入联系电话" },
136
- { name: "businessPerson", label: "业务员", placeholder: "请输入业务员" },
137
- { name: "applyReason", label: "申请原因", placeholder: "请输入申请原因" }
138
- ] as BaseFormItemDesc<any>[],
139
- api: {
140
- getById: API_CONFIG.getById,
141
- save: API_CONFIG.save,
142
- update: API_CONFIG.update
143
- }
144
- };
145
-
146
- let _editModalRef: any = null;
147
-
148
- const DETAIL_ROUTE = "/aiflow/mmwrCustomerDetail";
149
- /** 查看临时客户详情(跳转详情页) */
150
- function handleCustomerCodeClick(row: any) {
151
- const router = envConfig()?.router;
152
- if (!router) {
153
- ElMessage.error("路由未初始化,请刷新页面重试");
154
- return;
155
- }
156
- location.href = router.resolve({
157
- path: DETAIL_ROUTE,
158
- query: { id: row.id }
159
- }).href;
160
- }
161
-
162
- let PageRef: any = null;
163
-
164
- export function createPage(editModalRef?: any) {
165
- _editModalRef = editModalRef;
166
- const activeTab = ref<TabType>("temp");
167
-
168
- let Page = new (class extends AbstractPageQueryHook {
169
- constructor() {
170
- super({ url: { list: API_CONFIG.list, remove: API_CONFIG.remove } });
171
- }
172
-
173
- queryDef(): BaseQueryItemDesc<any>[] {
174
- return [
175
- { name: "customerCode", label: "客户编码", placeholder: "请输入" },
176
- {
177
- name: "customerStatus",
178
- label: "客户状态",
179
- component: () => ({ tag: "jh-select", items: OPTS.customerStatus })
180
- },
181
- {
182
- name: "useOrg",
183
- label: "使用组织",
184
- component: () => ({ tag: "jh-select", items: OPTS.useOrg })
185
- },
186
- { name: "customerName", label: "客户名称", placeholder: "请输入" },
187
- {
188
- name: "businessDept",
189
- label: "业务部门",
190
- component: () => ({ tag: "jh-select", items: OPTS.businessDept })
191
- },
192
- {
193
- name: "applicant",
194
- label: "申请人",
195
- component: () => ({ tag: "jh-select", items: OPTS.applicant })
196
- },
197
- {
198
- name: "convertStatus",
199
- label: "转换状态",
200
- component: () => ({ tag: "jh-select", items: OPTS.convertStatus })
201
- },
202
- {
203
- name: "product",
204
- label: "产品别",
205
- component: () => ({ tag: "jh-select", items: OPTS.product })
206
- },
207
- {
208
- name: "businessPerson",
209
- label: "业务员",
210
- component: () => ({ tag: "jh-select", items: OPTS.applicant })
211
- },
212
- {
213
- name: "verifyStatus",
214
- label: "核实状态",
215
- component: () => ({ tag: "jh-select", items: OPTS.verifyStatus })
216
- },
217
- {
218
- name: "createDate",
219
- startName: "createDateStart",
220
- endName: "createDateEnd",
221
- label: "建立日期",
222
- component: () => ({
223
- tag: "jh-date",
224
- type: "daterange",
225
- rangeSeparator: "至",
226
- showFormat: "YYYY-MM-DD",
227
- valueFormat: "YYYY-MM-DD"
228
- })
229
- },
230
- {
231
- name: "lastFollowDate",
232
- startName: "lastFollowDateStart",
233
- endName: "lastFollowDateEnd",
234
- label: "最后跟进时间",
235
- component: () => ({
236
- tag: "jh-date",
237
- type: "daterange",
238
- rangeSeparator: "至",
239
- showFormat: "YYYY-MM-DD",
240
- valueFormat: "YYYY-MM-DD"
241
- })
242
- }
243
- ];
244
- }
245
-
246
- toolbarDef(): ActionButtonDesc[] {
247
- return [
248
- {
249
- name: "primary",
250
- label: "新增",
251
- onClick: () => _editModalRef?.value?.open()
252
- },
253
- {
254
- label: "分配",
255
- plain: true,
256
- onClick: () => {
257
- const rows = this.tableRef.value?.getSelectionRows();
258
- if (!rows?.length) {
259
- ElMessage.warning("请先选择数据");
260
- return;
261
- }
262
- const ids = rows.map((r: any) => r.id);
263
- ElMessageBox.confirm("确定分配选中客户?", "提示", { type: "info" })
264
- .then(() => {
265
- postAction(API_CONFIG.assign, { ids }).then(() => {
266
- ElMessage.success("分配成功");
267
- this.select();
268
- });
269
- })
270
- .catch(() => {});
271
- }
272
- },
273
- {
274
- label: "作废",
275
- type: "danger",
276
- plain: true,
277
- onClick: () => {
278
- const rows = this.tableRef.value?.getSelectionRows();
279
- if (!rows?.length) {
280
- ElMessage.warning("请先选择数据");
281
- return;
282
- }
283
- const ids = rows.map((r: any) => r.id);
284
- ElMessageBox.confirm("确定作废选中客户?", "提示", {
285
- type: "warning"
286
- })
287
- .then(() => {
288
- postAction(API_CONFIG.cancel, { ids }).then(() => {
289
- ElMessage.success("作废成功");
290
- this.select();
291
- });
292
- })
293
- .catch(() => {});
294
- }
295
- },
296
- {
297
- label: "导出",
298
- plain: true,
299
- onClick: async () => {
300
- const data = this.list.value;
301
- if (!data?.length) {
302
- ElMessage.warning("无数据可导出");
303
- return;
304
- }
305
- const exportData = data.map((row: any) => ({
306
- 客户编号: row.customerCode,
307
- 客户名称: row.customerName,
308
- 客户类型: row.customerType,
309
- 使用组织: row.useOrg,
310
- 产品别: row.product,
311
- 业务员: row.businessPerson,
312
- 业务部门: row.businessDept,
313
- 核实状态: row.verifyStatus,
314
- 转换状态: row.convertStatus,
315
- 创建时间: row.createTime
316
- }));
317
- const ws = XLSX.utils.json_to_sheet(exportData);
318
- const wb = XLSX.utils.book_new();
319
- XLSX.utils.book_append_sheet(wb, ws, "临时客户档案");
320
- XLSX.writeFile(wb, "临时客户档案.xlsx");
321
- ElMessage.success("导出成功");
322
- }
323
- },
324
- {
325
- label: "回收",
326
- type: "warning",
327
- plain: true,
328
- onClick: () => {
329
- const rows = this.tableRef.value?.getSelectionRows();
330
- if (!rows?.length) {
331
- ElMessage.warning("请先选择数据");
332
- return;
333
- }
334
- const ids = rows.map((r: any) => r.id);
335
- ElMessageBox.confirm("确定回收选中客户?", "提示", {
336
- type: "warning"
337
- })
338
- .then(() => {
339
- postAction(API_CONFIG.recycle, { ids }).then(() => {
340
- ElMessage.success("回收成功");
341
- this.select();
342
- });
343
- })
344
- .catch(() => {});
345
- }
346
- },
347
- {
348
- label: "转化",
349
- type: "success",
350
- plain: true,
351
- onClick: () => {
352
- const rows = this.tableRef.value?.getSelectionRows();
353
- if (!rows?.length) {
354
- ElMessage.warning("请先选择数据");
355
- return;
356
- }
357
- const ids = rows.map((r: any) => r.id);
358
- ElMessageBox.confirm("确定将选中临时客户转化为正式客户?", "提示", {
359
- type: "info"
360
- })
361
- .then(() => {
362
- postAction(API_CONFIG.convert, { ids }).then(() => {
363
- ElMessage.success("转化成功");
364
- this.select();
365
- });
366
- })
367
- .catch(() => {});
368
- }
369
- },
370
- {
371
- label: "认领",
372
- type: "success",
373
- plain: true,
374
- onClick: () => {
375
- const rows = this.tableRef.value?.getSelectionRows();
376
- if (!rows?.length) {
377
- ElMessage.warning("请先选择数据");
378
- return;
379
- }
380
- const ids = rows.map((r: any) => r.id);
381
- ElMessageBox.confirm("确定认领选中客户?", "提示", { type: "info" })
382
- .then(() => {
383
- postAction(API_CONFIG.claim, { ids }).then(() => {
384
- ElMessage.success("认领成功");
385
- this.select();
386
- });
387
- })
388
- .catch(() => {});
389
- }
390
- },
391
- {
392
- label: "退回",
393
- type: "warning",
394
- plain: true,
395
- onClick: () => {
396
- const rows = this.tableRef.value?.getSelectionRows();
397
- if (!rows?.length) {
398
- ElMessage.warning("请先选择数据");
399
- return;
400
- }
401
- const ids = rows.map((r: any) => r.id);
402
- ElMessageBox.confirm("确定退回选中客户?", "提示", {
403
- type: "warning"
404
- })
405
- .then(() => {
406
- postAction(API_CONFIG.returnBack, { ids }).then(() => {
407
- ElMessage.success("退回成功");
408
- this.select();
409
- });
410
- })
411
- .catch(() => {});
412
- }
413
- }
414
- ];
415
- }
416
-
417
- columnsDef(): TableColumnDesc<any>[] {
418
- return [
419
- { type: "selection" },
420
- { type: "index" },
421
- {
422
- label: "客户编号",
423
- name: "customerCode",
424
- minWidth: 140,
425
- defaultSlot: ({ row }: any) => {
426
- return h(
427
- "span",
428
- {
429
- style:
430
- "color: #409eff; cursor: pointer; text-decoration: underline;",
431
- onClick: () => handleCustomerCodeClick(row)
432
- },
433
- row.customerCode
434
- );
435
- }
436
- },
437
- {
438
- label: "使用组织",
439
- name: "useOrg",
440
- minWidth: 180,
441
- showOverflowTooltip: true
442
- },
443
- { label: "产品别", name: "product", minWidth: 100 },
444
- { label: "申请原因", name: "applyReason", minWidth: 120 },
445
- { label: "业务员", name: "businessPerson", minWidth: 100 },
446
- { label: "业务部门", name: "businessDept", minWidth: 140 },
447
- {
448
- label: "核实状态",
449
- name: "verifyStatus",
450
- minWidth: 100,
451
- defaultSlot: ({ row }: any) => renderStatusTag(row, "verifyStatus")
452
- },
453
- { label: "创建人", name: "creator", minWidth: 100 },
454
- { label: "创建时间", name: "createTime", minWidth: 160 },
455
- { label: "最近跟进人", name: "lastFollowPerson", minWidth: 100 },
456
- { label: "最近跟进日期", name: "lastFollowDate", minWidth: 130 },
457
- {
458
- label: "转化状态",
459
- name: "convertStatus",
460
- minWidth: 100,
461
- fixed: "right",
462
- defaultSlot: ({ row }: any) => renderStatusTag(row, "convertStatus")
463
- },
464
- {
465
- label: "客户状态",
466
- name: "customerStatus",
467
- minWidth: 100,
468
- fixed: "right",
469
- defaultSlot: ({ row }: any) => renderStatusTag(row, "customerStatus")
470
- },
471
- {
472
- label: "操作",
473
- width: 140,
474
- fixed: "right",
475
- operations: [
476
- {
477
- name: "edit",
478
- label: "修改",
479
- show: (row: any) => row.verifyStatus === "已核实",
480
- onClick: (row: any) => _editModalRef?.value?.edit(row.id)
481
- },
482
- {
483
- name: "danger",
484
- label: "作废",
485
- show: (row: any) => row.verifyStatus === "已核实",
486
- onClick: (row: any) => {
487
- ElMessageBox.confirm("确定作废该客户?", "提示", {
488
- type: "warning"
489
- })
490
- .then(() => {
491
- postAction(API_CONFIG.cancel, { ids: [row.id] }).then(
492
- () => {
493
- ElMessage.success("作废成功");
494
- PageRef?.select();
495
- }
496
- );
497
- })
498
- .catch(() => {});
499
- }
500
- },
501
- {
502
- name: "edit",
503
- label: "编辑",
504
- show: (row: any) => row.verifyStatus !== "已核实",
505
- onClick: (row: any) => _editModalRef?.value?.edit(row.id)
506
- },
507
- {
508
- name: "remove",
509
- label: "删除",
510
- show: (row: any) => row.verifyStatus !== "已核实",
511
- onClick: (row: any) => {
512
- ElMessageBox.confirm("确定删除该客户?", "提示", {
513
- type: "warning"
514
- })
515
- .then(() => {
516
- postAction(API_CONFIG.remove, { id: row.id }).then(() => {
517
- ElMessage.success("删除成功");
518
- PageRef?.select();
519
- });
520
- })
521
- .catch(() => {});
522
- }
523
- }
524
- ]
525
- }
526
- ];
527
- }
528
- })();
529
-
530
- PageRef = Page;
531
- let result = (Page as any).create() as any;
532
-
533
- /** Tab 切换 */
534
- const handleTabChange = (val: TabType) => {
535
- activeTab.value = val;
536
- result.queryParam.value.tabType = val;
537
- result.select();
538
- };
539
-
540
- result.activeTab = activeTab;
541
- result.handleTabChange = handleTabChange;
542
- return result;
543
- }
1
+ import {
2
+ AbstractPageQueryHook,
3
+ BaseQueryItemDesc,
4
+ ActionButtonDesc,
5
+ TableColumnDesc
6
+ } from "@/types/page";
7
+ import type { BaseFormItemDesc } from "@jhlc/common-core/src/components/form/common/type";
8
+ import { postAction } from "@jhlc/common-core/src/api/action";
9
+ import envConfig from "@jhlc/common-core/src/store/env-config";
10
+ import * as XLSX from "xlsx";
11
+ import { h, resolveComponent } from "vue";
12
+
13
+ /** 状态色块映射 */
14
+ const STATUS_TAG_MAP: Record<string, Record<string, string>> = {
15
+ convertStatus: { 已转化: "success", 未转化: "info" },
16
+ customerStatus: { 临时客户: "warning", 正式客户: "success" },
17
+ verifyStatus: { 已核实: "success", 未核实: "info" }
18
+ };
19
+ function renderStatusTag(row: any, field: string) {
20
+ const val = row[field];
21
+ const type = STATUS_TAG_MAP[field]?.[val];
22
+ if (type === undefined) return val;
23
+ return h(
24
+ resolveComponent("ElTag") as any,
25
+ { type, effect: "light", size: "small" },
26
+ () => val
27
+ );
28
+ }
29
+
30
+ export const API_CONFIG = {
31
+ list: "/sale/tempCustomerArchive/list",
32
+ remove: "/sale/tempCustomerArchive/remove",
33
+ getById: "/sale/tempCustomerArchive/getById",
34
+ save: "/sale/tempCustomerArchive/save",
35
+ update: "/sale/tempCustomerArchive/update",
36
+ convert: "/sale/tempCustomerArchive/convert",
37
+ cancel: "/sale/tempCustomerArchive/cancel",
38
+ claim: "/sale/tempCustomerArchive/claim",
39
+ assign: "/sale/tempCustomerArchive/assign",
40
+ recycle: "/sale/tempCustomerArchive/recycle",
41
+ returnBack: "/sale/tempCustomerArchive/return",
42
+ export: "/sale/tempCustomerArchive/export"
43
+ } as const;
44
+
45
+ /** Tab 类型 */
46
+ export type TabType = "temp" | "formal" | "pool";
47
+
48
+ const OPTS = {
49
+ customerStatus: [
50
+ { label: "临时客户", value: "临时客户" },
51
+ { label: "正式客户", value: "正式客户" }
52
+ ],
53
+ customerType: [
54
+ { label: "SYCSR001-交易客户", value: "SYCSR001-交易客户" },
55
+ { label: "SYCSR002-直采客户", value: "SYCSR002-直采客户" }
56
+ ],
57
+ useOrg: [
58
+ { label: "不锈鋼接單中心", value: "不锈鋼接單中心" },
59
+ {
60
+ label: "江阴华新特殊合金材料有限公司",
61
+ value: "江阴华新特殊合金材料有限公司"
62
+ },
63
+ { label: "採瞒管理中心", value: "採瞒管理中心" },
64
+ { label: "烟台华鑫再生资源有限公司", value: "烟台华鑫再生资源有限公司" }
65
+ ],
66
+ businessDept: [
67
+ { label: "業務管理處", value: "業務管理處" },
68
+ { label: "線材銷售部", value: "線材銷售部" },
69
+ { label: "無縫管銷售處", value: "無縫管銷售處" },
70
+ { label: "華南銷售科", value: "華南銷售科" },
71
+ { label: "汽車產業銷售科", value: "汽車產業銷售科" },
72
+ { label: "大陸行銷部", value: "大陸行銷部" },
73
+ { label: "冷精棒業管部(台北)", value: "冷精棒業管部(台北)" },
74
+ { label: "業管科", value: "業管科" },
75
+ { label: "華東銷售科", value: "華東銷售科" }
76
+ ],
77
+ applicant: [
78
+ { label: "魏子明", value: "魏子明" },
79
+ { label: "龚辉鉴", value: "龚辉鉴" },
80
+ { label: "宋书迪", value: "宋书迪" },
81
+ { label: "李锋", value: "李锋" },
82
+ { label: "杨松", value: "杨松" },
83
+ { label: "王之勤", value: "王之勤" },
84
+ { label: "邹建军", value: "邹建军" },
85
+ { label: "龙成金", value: "龙成金" }
86
+ ],
87
+ product: [
88
+ { label: "热轧", value: "热轧" },
89
+ { label: "盘元", value: "盘元" },
90
+ { label: "冷精", value: "冷精" },
91
+ { label: "汽车", value: "汽车" }
92
+ ],
93
+ verifyStatus: [
94
+ { label: "未核实", value: "未核实" },
95
+ { label: "已核实", value: "已核实" }
96
+ ],
97
+ convertStatus: [
98
+ { label: "已转化", value: "已转化" },
99
+ { label: "未转化", value: "未转化" }
100
+ ]
101
+ };
102
+
103
+ export { OPTS };
104
+
105
+ /** c_formModal 配置 */
106
+ export const modalConfig = {
107
+ titlePrefix: "临时客户",
108
+ width: "850px",
109
+ columns: 2,
110
+ labelWidth: "110px",
111
+ formItems: [
112
+ {
113
+ name: "customerCode",
114
+ label: "客户编号",
115
+ disabled: true,
116
+ placeholder: "系统自动生成"
117
+ },
118
+ {
119
+ name: "customerName",
120
+ label: "客户名称",
121
+ required: true,
122
+ placeholder: "请输入客户名称"
123
+ },
124
+ {
125
+ name: "customerType",
126
+ label: "客户类型",
127
+ component: () => ({ tag: "jh-select", items: OPTS.customerType })
128
+ },
129
+ {
130
+ name: "product",
131
+ label: "产品别",
132
+ component: () => ({ tag: "jh-select", items: OPTS.product })
133
+ },
134
+ { name: "contactPerson", label: "联系人", placeholder: "请输入联系人" },
135
+ { name: "phone", label: "联系电话", placeholder: "请输入联系电话" },
136
+ { name: "businessPerson", label: "业务员", placeholder: "请输入业务员" },
137
+ { name: "applyReason", label: "申请原因", placeholder: "请输入申请原因" }
138
+ ] as BaseFormItemDesc<any>[],
139
+ api: {
140
+ getById: API_CONFIG.getById,
141
+ save: API_CONFIG.save,
142
+ update: API_CONFIG.update
143
+ }
144
+ };
145
+
146
+ let _editModalRef: any = null;
147
+
148
+ const DETAIL_ROUTE = "/aiflow/mmwrCustomerDetail";
149
+ /** 查看临时客户详情(跳转详情页) */
150
+ function handleCustomerCodeClick(row: any) {
151
+ const router = envConfig()?.router;
152
+ if (!router) {
153
+ ElMessage.error("路由未初始化,请刷新页面重试");
154
+ return;
155
+ }
156
+ location.href = router.resolve({
157
+ path: DETAIL_ROUTE,
158
+ query: { id: row.id }
159
+ }).href;
160
+ }
161
+
162
+ let PageRef: any = null;
163
+
164
+ export function createPage(editModalRef?: any) {
165
+ _editModalRef = editModalRef;
166
+ const activeTab = ref<TabType>("temp");
167
+
168
+ let Page = new (class extends AbstractPageQueryHook {
169
+ constructor() {
170
+ super({ url: { list: API_CONFIG.list, remove: API_CONFIG.remove } });
171
+ }
172
+
173
+ queryDef(): BaseQueryItemDesc<any>[] {
174
+ return [
175
+ { name: "customerCode", label: "客户编码", placeholder: "请输入" },
176
+ {
177
+ name: "customerStatus",
178
+ label: "客户状态",
179
+ component: () => ({ tag: "jh-select", items: OPTS.customerStatus })
180
+ },
181
+ {
182
+ name: "useOrg",
183
+ label: "使用组织",
184
+ component: () => ({ tag: "jh-select", items: OPTS.useOrg })
185
+ },
186
+ { name: "customerName", label: "客户名称", placeholder: "请输入" },
187
+ {
188
+ name: "businessDept",
189
+ label: "业务部门",
190
+ component: () => ({ tag: "jh-select", items: OPTS.businessDept })
191
+ },
192
+ {
193
+ name: "applicant",
194
+ label: "申请人",
195
+ component: () => ({ tag: "jh-select", items: OPTS.applicant })
196
+ },
197
+ {
198
+ name: "convertStatus",
199
+ label: "转换状态",
200
+ component: () => ({ tag: "jh-select", items: OPTS.convertStatus })
201
+ },
202
+ {
203
+ name: "product",
204
+ label: "产品别",
205
+ component: () => ({ tag: "jh-select", items: OPTS.product })
206
+ },
207
+ {
208
+ name: "businessPerson",
209
+ label: "业务员",
210
+ component: () => ({ tag: "jh-select", items: OPTS.applicant })
211
+ },
212
+ {
213
+ name: "verifyStatus",
214
+ label: "核实状态",
215
+ component: () => ({ tag: "jh-select", items: OPTS.verifyStatus })
216
+ },
217
+ {
218
+ name: "createDate",
219
+ startName: "createDateStart",
220
+ endName: "createDateEnd",
221
+ label: "建立日期",
222
+ component: () => ({
223
+ tag: "jh-date",
224
+ type: "daterange",
225
+ rangeSeparator: "至",
226
+ showFormat: "YYYY-MM-DD",
227
+ valueFormat: "YYYY-MM-DD"
228
+ })
229
+ },
230
+ {
231
+ name: "lastFollowDate",
232
+ startName: "lastFollowDateStart",
233
+ endName: "lastFollowDateEnd",
234
+ label: "最后跟进时间",
235
+ component: () => ({
236
+ tag: "jh-date",
237
+ type: "daterange",
238
+ rangeSeparator: "至",
239
+ showFormat: "YYYY-MM-DD",
240
+ valueFormat: "YYYY-MM-DD"
241
+ })
242
+ }
243
+ ];
244
+ }
245
+
246
+ toolbarDef(): ActionButtonDesc[] {
247
+ return [
248
+ {
249
+ name: "primary",
250
+ label: "新增",
251
+ onClick: () => _editModalRef?.value?.open()
252
+ },
253
+ {
254
+ label: "分配",
255
+ plain: true,
256
+ onClick: () => {
257
+ const rows = this.tableRef.value?.getSelectionRows();
258
+ if (!rows?.length) {
259
+ ElMessage.warning("请先选择数据");
260
+ return;
261
+ }
262
+ const ids = rows.map((r: any) => r.id);
263
+ ElMessageBox.confirm("确定分配选中客户?", "提示", { type: "info" })
264
+ .then(() => {
265
+ postAction(API_CONFIG.assign, { ids }).then(() => {
266
+ ElMessage.success("分配成功");
267
+ this.select();
268
+ });
269
+ })
270
+ .catch(() => {});
271
+ }
272
+ },
273
+ {
274
+ label: "作废",
275
+ type: "danger",
276
+ plain: true,
277
+ onClick: () => {
278
+ const rows = this.tableRef.value?.getSelectionRows();
279
+ if (!rows?.length) {
280
+ ElMessage.warning("请先选择数据");
281
+ return;
282
+ }
283
+ const ids = rows.map((r: any) => r.id);
284
+ ElMessageBox.confirm("确定作废选中客户?", "提示", {
285
+ type: "warning"
286
+ })
287
+ .then(() => {
288
+ postAction(API_CONFIG.cancel, { ids }).then(() => {
289
+ ElMessage.success("作废成功");
290
+ this.select();
291
+ });
292
+ })
293
+ .catch(() => {});
294
+ }
295
+ },
296
+ {
297
+ label: "导出",
298
+ plain: true,
299
+ onClick: async () => {
300
+ const data = this.list.value;
301
+ if (!data?.length) {
302
+ ElMessage.warning("无数据可导出");
303
+ return;
304
+ }
305
+ const exportData = data.map((row: any) => ({
306
+ 客户编号: row.customerCode,
307
+ 客户名称: row.customerName,
308
+ 客户类型: row.customerType,
309
+ 使用组织: row.useOrg,
310
+ 产品别: row.product,
311
+ 业务员: row.businessPerson,
312
+ 业务部门: row.businessDept,
313
+ 核实状态: row.verifyStatus,
314
+ 转换状态: row.convertStatus,
315
+ 创建时间: row.createTime
316
+ }));
317
+ const ws = XLSX.utils.json_to_sheet(exportData);
318
+ const wb = XLSX.utils.book_new();
319
+ XLSX.utils.book_append_sheet(wb, ws, "临时客户档案");
320
+ XLSX.writeFile(wb, "临时客户档案.xlsx");
321
+ ElMessage.success("导出成功");
322
+ }
323
+ },
324
+ {
325
+ label: "回收",
326
+ type: "warning",
327
+ plain: true,
328
+ onClick: () => {
329
+ const rows = this.tableRef.value?.getSelectionRows();
330
+ if (!rows?.length) {
331
+ ElMessage.warning("请先选择数据");
332
+ return;
333
+ }
334
+ const ids = rows.map((r: any) => r.id);
335
+ ElMessageBox.confirm("确定回收选中客户?", "提示", {
336
+ type: "warning"
337
+ })
338
+ .then(() => {
339
+ postAction(API_CONFIG.recycle, { ids }).then(() => {
340
+ ElMessage.success("回收成功");
341
+ this.select();
342
+ });
343
+ })
344
+ .catch(() => {});
345
+ }
346
+ },
347
+ {
348
+ label: "转化",
349
+ type: "success",
350
+ plain: true,
351
+ onClick: () => {
352
+ const rows = this.tableRef.value?.getSelectionRows();
353
+ if (!rows?.length) {
354
+ ElMessage.warning("请先选择数据");
355
+ return;
356
+ }
357
+ const ids = rows.map((r: any) => r.id);
358
+ ElMessageBox.confirm("确定将选中临时客户转化为正式客户?", "提示", {
359
+ type: "info"
360
+ })
361
+ .then(() => {
362
+ postAction(API_CONFIG.convert, { ids }).then(() => {
363
+ ElMessage.success("转化成功");
364
+ this.select();
365
+ });
366
+ })
367
+ .catch(() => {});
368
+ }
369
+ },
370
+ {
371
+ label: "认领",
372
+ type: "success",
373
+ plain: true,
374
+ onClick: () => {
375
+ const rows = this.tableRef.value?.getSelectionRows();
376
+ if (!rows?.length) {
377
+ ElMessage.warning("请先选择数据");
378
+ return;
379
+ }
380
+ const ids = rows.map((r: any) => r.id);
381
+ ElMessageBox.confirm("确定认领选中客户?", "提示", { type: "info" })
382
+ .then(() => {
383
+ postAction(API_CONFIG.claim, { ids }).then(() => {
384
+ ElMessage.success("认领成功");
385
+ this.select();
386
+ });
387
+ })
388
+ .catch(() => {});
389
+ }
390
+ },
391
+ {
392
+ label: "退回",
393
+ type: "warning",
394
+ plain: true,
395
+ onClick: () => {
396
+ const rows = this.tableRef.value?.getSelectionRows();
397
+ if (!rows?.length) {
398
+ ElMessage.warning("请先选择数据");
399
+ return;
400
+ }
401
+ const ids = rows.map((r: any) => r.id);
402
+ ElMessageBox.confirm("确定退回选中客户?", "提示", {
403
+ type: "warning"
404
+ })
405
+ .then(() => {
406
+ postAction(API_CONFIG.returnBack, { ids }).then(() => {
407
+ ElMessage.success("退回成功");
408
+ this.select();
409
+ });
410
+ })
411
+ .catch(() => {});
412
+ }
413
+ }
414
+ ];
415
+ }
416
+
417
+ columnsDef(): TableColumnDesc<any>[] {
418
+ return [
419
+ { type: "selection" },
420
+ { type: "index" },
421
+ {
422
+ label: "客户编号",
423
+ name: "customerCode",
424
+ minWidth: 140,
425
+ defaultSlot: ({ row }: any) => {
426
+ return h(
427
+ "span",
428
+ {
429
+ style:
430
+ "color: #409eff; cursor: pointer; text-decoration: underline;",
431
+ onClick: () => handleCustomerCodeClick(row)
432
+ },
433
+ row.customerCode
434
+ );
435
+ }
436
+ },
437
+ {
438
+ label: "使用组织",
439
+ name: "useOrg",
440
+ minWidth: 180,
441
+ showOverflowTooltip: true
442
+ },
443
+ { label: "产品别", name: "product", minWidth: 100 },
444
+ { label: "申请原因", name: "applyReason", minWidth: 120 },
445
+ { label: "业务员", name: "businessPerson", minWidth: 100 },
446
+ { label: "业务部门", name: "businessDept", minWidth: 140 },
447
+ {
448
+ label: "核实状态",
449
+ name: "verifyStatus",
450
+ minWidth: 100,
451
+ defaultSlot: ({ row }: any) => renderStatusTag(row, "verifyStatus")
452
+ },
453
+ { label: "创建人", name: "creator", minWidth: 100 },
454
+ { label: "创建时间", name: "createTime", minWidth: 160 },
455
+ { label: "最近跟进人", name: "lastFollowPerson", minWidth: 100 },
456
+ { label: "最近跟进日期", name: "lastFollowDate", minWidth: 130 },
457
+ {
458
+ label: "转化状态",
459
+ name: "convertStatus",
460
+ minWidth: 100,
461
+ fixed: "right",
462
+ defaultSlot: ({ row }: any) => renderStatusTag(row, "convertStatus")
463
+ },
464
+ {
465
+ label: "客户状态",
466
+ name: "customerStatus",
467
+ minWidth: 100,
468
+ fixed: "right",
469
+ defaultSlot: ({ row }: any) => renderStatusTag(row, "customerStatus")
470
+ },
471
+ {
472
+ label: "操作",
473
+ width: 140,
474
+ fixed: "right",
475
+ operations: [
476
+ {
477
+ name: "edit",
478
+ label: "修改",
479
+ show: (row: any) => row.verifyStatus === "已核实",
480
+ onClick: (row: any) => _editModalRef?.value?.edit(row.id)
481
+ },
482
+ {
483
+ name: "danger",
484
+ label: "作废",
485
+ show: (row: any) => row.verifyStatus === "已核实",
486
+ onClick: (row: any) => {
487
+ ElMessageBox.confirm("确定作废该客户?", "提示", {
488
+ type: "warning"
489
+ })
490
+ .then(() => {
491
+ postAction(API_CONFIG.cancel, { ids: [row.id] }).then(
492
+ () => {
493
+ ElMessage.success("作废成功");
494
+ PageRef?.select();
495
+ }
496
+ );
497
+ })
498
+ .catch(() => {});
499
+ }
500
+ },
501
+ {
502
+ name: "edit",
503
+ label: "编辑",
504
+ show: (row: any) => row.verifyStatus !== "已核实",
505
+ onClick: (row: any) => _editModalRef?.value?.edit(row.id)
506
+ },
507
+ {
508
+ name: "remove",
509
+ label: "删除",
510
+ show: (row: any) => row.verifyStatus !== "已核实",
511
+ onClick: (row: any) => {
512
+ ElMessageBox.confirm("确定删除该客户?", "提示", {
513
+ type: "warning"
514
+ })
515
+ .then(() => {
516
+ postAction(API_CONFIG.remove, { id: row.id }).then(() => {
517
+ ElMessage.success("删除成功");
518
+ PageRef?.select();
519
+ });
520
+ })
521
+ .catch(() => {});
522
+ }
523
+ }
524
+ ]
525
+ }
526
+ ];
527
+ }
528
+ })();
529
+
530
+ PageRef = Page;
531
+ let result = (Page as any).create() as any;
532
+
533
+ /** Tab 切换 */
534
+ const handleTabChange = (val: TabType) => {
535
+ activeTab.value = val;
536
+ result.queryParam.value.tabType = val;
537
+ result.select();
538
+ };
539
+
540
+ result.activeTab = activeTab;
541
+ result.handleTabChange = handleTabChange;
542
+ return result;
543
+ }