@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,167 @@
1
+ <!--
2
+ * @Author: ChenYu ycyplus@gmail.com
3
+ * @Date: 2025-12-29 15:38:58
4
+ * @LastEditors: ChenYu ycyplus@gmail.com
5
+ * @LastEditTime: 2026-01-03 00:46:17
6
+ * @FilePath: \cx-ui-sale\src\views\sale\demo\add-demo\index.vue
7
+ * @Description: 新增编辑页示例 - 视图层(订单新增编辑表单、项次信息管理)
8
+ * Copyright (c) 2025 by CHENY, All Rights Reserved 😎.
9
+ -->
10
+ <template>
11
+ <div class="main-maintenance-container">
12
+ <!-- C_Splitter 包裹表单区和项次信息 -->
13
+ <C_Splitter direction="vertical" class="main-splitter">
14
+ <!-- 🆕 使用增强版组件(集成所有功能) -->
15
+ <c_formSections
16
+ :sections="sectionsConfig"
17
+ :form="form"
18
+ v-model:activeNames="activeNames"
19
+ show-header
20
+ header-title="主档维护"
21
+ :header-actions="headerActions"
22
+ show-toolbar
23
+ show-required-filter
24
+ show-layout-switch
25
+ :default-layout="5"
26
+ :layout-options="[2, 3, 4, 5]"
27
+ show-nav-tabs
28
+ nav-tabs-position="left"
29
+ :nav-tabs="navTabsConfig"
30
+ label-width="100px"
31
+ label-position="right"
32
+ :gutter="20"
33
+ class="form-card"
34
+ >
35
+ <!-- 特殊需求区块插槽 -->
36
+ <template #special-3>
37
+ <el-row :gutter="20">
38
+ <el-col :span="24">
39
+ <el-button type="primary" plain @click="addSpecialRequirement">
40
+ + 添加需求
41
+ </el-button>
42
+ </el-col>
43
+ </el-row>
44
+ </template>
45
+ </c_formSections>
46
+
47
+ <el-card
48
+ shadow="never"
49
+ class="items-card"
50
+ :initialSize="220"
51
+ :minSize="150"
52
+ >
53
+ <div class="child-items-section">
54
+ <div class="section-header">
55
+ <div class="title-group">
56
+ <el-icon class="collapse-icon"><ArrowDown /></el-icon>
57
+ <span>项次信息</span>
58
+ </div>
59
+ <el-icon
60
+ class="fullscreen-icon"
61
+ :title="isItemTableFullscreen ? '退出全屏' : '全屏'"
62
+ @click="toggleItemTableFullscreen"
63
+ >
64
+ <component :is="isItemTableFullscreen ? 'Close' : 'FullScreen'" />
65
+ </el-icon>
66
+ </div>
67
+ <BaseTable
68
+ :data="paginatedItemData"
69
+ :columns="itemColumnsConfig"
70
+ border
71
+ class="child-table"
72
+ height="100%"
73
+ />
74
+ <!-- 分页 -->
75
+ <div class="items-pagination">
76
+ <div class="drag-hint">
77
+ <span class="drag-icon">⇕</span>
78
+ <span class="hint-text">长按拖动,可调整两个区域所占高度</span>
79
+ </div>
80
+ <jh-pagination
81
+ v-show="itemTotal && itemTotal > 0"
82
+ :total="itemTotal || 0"
83
+ v-model:currentPage="currentPage"
84
+ v-model:pageSize="pageSize"
85
+ @current-change="refreshItemData"
86
+ @size-change="refreshItemData"
87
+ />
88
+ </div>
89
+ </div>
90
+ </el-card>
91
+ </C_Splitter>
92
+
93
+ <!-- 全屏模式 - 使用 Teleport 传送到 body -->
94
+ <Teleport to="body">
95
+ <div v-if="isItemTableFullscreen" class="fullscreen-overlay">
96
+ <el-card shadow="never" class="items-card-fullscreen">
97
+ <div class="child-items-section">
98
+ <div class="section-header">
99
+ <div class="title-group">
100
+ <el-icon class="collapse-icon"><ArrowDown /></el-icon>
101
+ <span>项次信息</span>
102
+ </div>
103
+ <el-icon
104
+ class="fullscreen-icon"
105
+ title="退出全屏"
106
+ @click="toggleItemTableFullscreen"
107
+ >
108
+ <Close />
109
+ </el-icon>
110
+ </div>
111
+ <BaseTable
112
+ :data="paginatedItemData"
113
+ :columns="itemColumnsConfig"
114
+ border
115
+ class="child-table"
116
+ height="100%"
117
+ />
118
+ <!-- MARK: 分页(推荐平台统一封装的,保持一致,个性化定制不能满足的时候可以自行拓展 el-pagination) -->
119
+ <div class="items-pagination">
120
+ <jh-pagination
121
+ v-show="itemTotal && itemTotal > 0"
122
+ :total="itemTotal || 0"
123
+ v-model:currentPage="currentPage"
124
+ v-model:pageSize="pageSize"
125
+ @current-change="refreshItemData"
126
+ @size-change="refreshItemData"
127
+ />
128
+ </div>
129
+ </div>
130
+ </el-card>
131
+ </div>
132
+ </Teleport>
133
+ </div>
134
+ </template>
135
+
136
+ <script setup lang="ts">
137
+ import { onMounted } from "vue";
138
+ import { ArrowDown, Close } from "@element-plus/icons-vue";
139
+ import C_Splitter from "@/components/global/C_Splitter/index.vue";
140
+ import c_formSections from "@/components/local/c_formSections/index.vue";
141
+ import {
142
+ form,
143
+ activeNames,
144
+ sectionsConfig,
145
+ navTabsConfig,
146
+ headerActions,
147
+ isItemTableFullscreen,
148
+ itemColumnsConfig,
149
+ itemTotal,
150
+ paginatedItemData,
151
+ currentPage,
152
+ pageSize,
153
+ addSpecialRequirement,
154
+ toggleItemTableFullscreen,
155
+ refreshItemData,
156
+ initPage
157
+ } from "./data";
158
+
159
+ // 页面初始化
160
+ onMounted(() => {
161
+ initPage();
162
+ });
163
+ </script>
164
+
165
+ <style scoped lang="scss">
166
+ @import "./index.scss";
167
+ </style>
@@ -0,0 +1,524 @@
1
+ /*
2
+ * @Author: ChenYu ycyplus@gmail.com
3
+ * @Date: 2025-06-13 18:38:58
4
+ * @LastEditors: ChenYu ycyplus@gmail.com
5
+ * @LastEditTime: 2026-01-01 10:00:00
6
+ * @FilePath: \cx-ui-sale\src\views\sale\demo\billet-flame-cut-plan\data.ts
7
+ * @Description: 钢坯火切计划 - 数据逻辑层
8
+ * Copyright (c) 2025 by CHENY, All Rights Reserved 😎.
9
+ */
10
+ import { ref, reactive, type Ref, h } from "vue";
11
+ import { BaseQueryItemDesc } from "@jhlc/common-core/src/components/form/base-query/type";
12
+ import { BaseFormItemDesc } from "@jhlc/common-core/src/components/form/common/type";
13
+ import { ActionButtonDesc } from "@jhlc/common-core/src/components/toolbar/type";
14
+ import { TableColumnDesc } from "@jhlc/common-core/src/components/table/base-table/type";
15
+ import { ElMessage, ElMessageBox } from "element-plus";
16
+
17
+ // ==================== 类型定义 ====================
18
+ export interface TableRow {
19
+ id: number;
20
+ meltNo: string;
21
+ slabNo: string;
22
+ planHeatNo: string;
23
+ slabType: string;
24
+ cutCount: number;
25
+ thickness: string;
26
+ width: string;
27
+ totalLength: string;
28
+ weight: string;
29
+ multipleNo: string;
30
+ actualSteel: string;
31
+ planCutTime: string;
32
+ cutOperator: string;
33
+ }
34
+
35
+ // ==================== 表格渲染类型 ====================
36
+ export const renderType = ref<"dataTable" | "agGrid">("dataTable");
37
+
38
+ // ==================== 搜索项配置 ====================
39
+ export const queryItemsConfig: BaseQueryItemDesc<any>[] = [
40
+ {
41
+ name: "slabNo",
42
+ label: "钢坯号",
43
+ placeholder: "请输入"
44
+ },
45
+ {
46
+ name: "planHeatNo",
47
+ label: "计划炉号",
48
+ placeholder: "请输入"
49
+ },
50
+ {
51
+ name: "meltNo",
52
+ label: "熔炼号",
53
+ placeholder: "请输入"
54
+ },
55
+ {
56
+ name: "dateRange",
57
+ type: "range",
58
+ startName: "startDate",
59
+ endName: "endDate",
60
+ label: "切断时间",
61
+ rangeSeparator: "至",
62
+ placeholder: "开始",
63
+ widthScale: 1.5
64
+ }
65
+ ];
66
+
67
+ // ==================== 工具栏配置 ====================
68
+ export const getToolbarConfig = (callbacks: {
69
+ onAdd: () => void;
70
+ onSave: () => void;
71
+ onExport: () => void;
72
+ onReset: () => void;
73
+ }): ActionButtonDesc[] => [
74
+ {
75
+ name: "add",
76
+ label: "新增",
77
+ type: "primary",
78
+ onClick: callbacks.onAdd
79
+ },
80
+ {
81
+ name: "save",
82
+ label: "保存",
83
+ type: "success",
84
+ onClick: callbacks.onSave
85
+ },
86
+ {
87
+ name: "export",
88
+ label: "导出",
89
+ onClick: callbacks.onExport
90
+ },
91
+ {
92
+ name: "reset",
93
+ label: "重置",
94
+ onClick: callbacks.onReset
95
+ }
96
+ ];
97
+
98
+ // ==================== 事件处理函数 ====================
99
+ function handleMeltNoClick(row: TableRow) {
100
+ ElMessage.info(`查看熔炼号: ${row.meltNo} 的详细信息`);
101
+ // 这里可以添加跳转到熔炼号详情页面或打开详情弹窗的逻辑
102
+ }
103
+
104
+ // ==================== 计划信息表格列配置 ====================
105
+ export const getPlanColumnsConfig = (callbacks: {
106
+ onEdit: (row: TableRow) => void;
107
+ onDelete: (row: TableRow) => void;
108
+ }): TableColumnDesc<TableRow>[] => [
109
+ { type: "selection" },
110
+ { label: "序号", type: "index", width: 60 },
111
+ {
112
+ label: "熔炼号",
113
+ name: "meltNo",
114
+ width: 120,
115
+ defaultSlot: ({ row }: any) => {
116
+ return h(
117
+ "span",
118
+ {
119
+ style: "color: #409eff; cursor: pointer; text-decoration: underline;",
120
+ onClick: () => handleMeltNoClick(row)
121
+ },
122
+ row.meltNo
123
+ );
124
+ }
125
+ },
126
+ { label: "板坯号", name: "slabNo", width: 140 },
127
+ { label: "计划炉号", name: "planHeatNo", width: 120 },
128
+ { label: "坯料类型", name: "slabType", width: 100 },
129
+ { label: "切割块数", name: "cutCount", width: 100, align: "right" },
130
+ { label: "厚度", name: "thickness", width: 80, align: "right" },
131
+ { label: "宽度", name: "width", width: 80, align: "right" },
132
+ { label: "总长度", name: "totalLength", width: 100, align: "right" },
133
+ { label: "重量", name: "weight", width: 100, align: "right" },
134
+ { label: "倍尺数", name: "multipleNo", width: 80, align: "right" },
135
+ { label: "实际钢种", name: "actualSteel", width: 120 },
136
+ { label: "计划切割时间", name: "planCutTime", width: 160 },
137
+ { label: "切割人员", name: "cutOperator", width: 100 },
138
+ {
139
+ label: "操作",
140
+ width: 140,
141
+ fixed: "right",
142
+ operations: [
143
+ {
144
+ name: "edit",
145
+ label: "编辑",
146
+ onClick: (row: TableRow) => callbacks.onEdit(row)
147
+ },
148
+ {
149
+ name: "delete",
150
+ label: "删除",
151
+ onClick: (row: TableRow) => callbacks.onDelete(row)
152
+ }
153
+ ]
154
+ } as any
155
+ ];
156
+
157
+ // ==================== 切割信息表格列配置 ====================
158
+ export const cutColumnsConfig: TableColumnDesc<TableRow>[] = [
159
+ { type: "selection" },
160
+ { label: "序号", type: "index", width: 60 },
161
+ {
162
+ label: "熔炼号",
163
+ name: "meltNo",
164
+ width: 120,
165
+ defaultSlot: ({ row }: any) => {
166
+ return h(
167
+ "span",
168
+ {
169
+ style: "color: #409eff; cursor: pointer; text-decoration: underline;",
170
+ onClick: () => handleMeltNoClick(row)
171
+ },
172
+ row.meltNo
173
+ );
174
+ }
175
+ },
176
+ { label: "板坯号", name: "slabNo", width: 140 },
177
+ { label: "计划炉号", name: "planHeatNo", width: 120 },
178
+ { label: "坯料类型", name: "slabType", width: 100 },
179
+ { label: "切割块数", name: "cutCount", width: 100, align: "right" },
180
+ { label: "厚度", name: "thickness", width: 80, align: "right" },
181
+ { label: "宽度", name: "width", width: 80, align: "right" },
182
+ { label: "总长度", name: "totalLength", width: 100, align: "right" },
183
+ { label: "重量", name: "weight", width: 100, align: "right" },
184
+ { label: "倍尺数", name: "multipleNo", width: 80, align: "right" },
185
+ { label: "实际钢种", name: "actualSteel", width: 120 },
186
+ { label: "计划切割时间", name: "planCutTime", width: 160 },
187
+ { label: "切割人员", name: "cutOperator", width: 100 },
188
+ {
189
+ label: "订单材/余材",
190
+ width: 120,
191
+ align: "center",
192
+ defaultSlot: () => "--"
193
+ }
194
+ ];
195
+
196
+ // ==================== 弹窗配置 ====================
197
+ export const modalConfig = {
198
+ titlePrefix: "计划信息",
199
+ width: "800px",
200
+ columns: 2,
201
+ labelWidth: "120px",
202
+ api: {
203
+ getById: "/api/billet-flame-cut-plan/getById",
204
+ save: "/api/billet-flame-cut-plan/save",
205
+ update: "/api/billet-flame-cut-plan/update"
206
+ },
207
+ formItems: [
208
+ {
209
+ name: "meltNo",
210
+ label: "熔炼号",
211
+ placeholder: "请输入熔炼号",
212
+ required: true
213
+ },
214
+ {
215
+ name: "slabNo",
216
+ label: "板坯号",
217
+ placeholder: "请输入板坯号",
218
+ required: true
219
+ },
220
+ {
221
+ name: "planHeatNo",
222
+ label: "计划炉号",
223
+ placeholder: "请输入计划炉号",
224
+ required: true
225
+ },
226
+ {
227
+ name: "slabType",
228
+ label: "坯料类型",
229
+ placeholder: "请选择坯料类型",
230
+ required: true,
231
+ type: "select" as const,
232
+ options: [
233
+ { label: "热轧", value: "热轧" },
234
+ { label: "冷轧", value: "冷轧" },
235
+ { label: "中厚板", value: "中厚板" }
236
+ ]
237
+ },
238
+ {
239
+ name: "cutCount",
240
+ label: "切割块数",
241
+ placeholder: "请输入切割块数",
242
+ required: true,
243
+ type: "number" as const
244
+ },
245
+ {
246
+ name: "thickness",
247
+ label: "厚度",
248
+ placeholder: "请输入厚度",
249
+ required: true,
250
+ type: "number" as const
251
+ },
252
+ {
253
+ name: "width",
254
+ label: "宽度",
255
+ placeholder: "请输入宽度",
256
+ required: true,
257
+ type: "number" as const
258
+ },
259
+ {
260
+ name: "totalLength",
261
+ label: "总长度",
262
+ placeholder: "请输入总长度",
263
+ required: true,
264
+ type: "number" as const
265
+ },
266
+ {
267
+ name: "weight",
268
+ label: "重量",
269
+ placeholder: "请输入重量",
270
+ required: true,
271
+ type: "number" as const
272
+ },
273
+ {
274
+ name: "multipleNo",
275
+ label: "倍尺数",
276
+ placeholder: "请输入倍尺数",
277
+ required: true
278
+ },
279
+ {
280
+ name: "actualSteel",
281
+ label: "实际钢种",
282
+ placeholder: "请输入实际钢种",
283
+ required: true
284
+ },
285
+ {
286
+ name: "planCutTime",
287
+ label: "计划切割时间",
288
+ placeholder: "请选择计划切割时间",
289
+ required: true,
290
+ type: "datetime" as const
291
+ },
292
+ {
293
+ name: "cutOperator",
294
+ label: "切割人员",
295
+ placeholder: "请输入切割人员",
296
+ required: true
297
+ }
298
+ ] as BaseFormItemDesc<TableRow>[]
299
+ };
300
+
301
+ // ==================== 创建页面 Hook ====================
302
+ export function createPageHook(modalRef: Ref<any>) {
303
+ // 顶部标签页
304
+ const activeTab = ref("plan");
305
+
306
+ // 查询参数
307
+ const queryParam = reactive({
308
+ slabNo: "",
309
+ planHeatNo: "",
310
+ meltNo: "",
311
+ startDate: "",
312
+ endDate: ""
313
+ });
314
+
315
+ // 分页
316
+ const page = reactive({
317
+ current: 1,
318
+ size: 10,
319
+ total: 0
320
+ });
321
+
322
+ // 表格
323
+ const tableRef = ref();
324
+ const list = ref<TableRow[]>([]); // 分页显示的计划数据
325
+ const fullPlanData = ref<TableRow[]>([]); // 完整的计划数据
326
+ const cutList = ref<TableRow[]>([]);
327
+ const loading = ref(false);
328
+
329
+ // 查询项
330
+ const queryItems = queryItemsConfig;
331
+
332
+ // 工具栏
333
+ const toolbars = getToolbarConfig({
334
+ onAdd: () => modalRef.value?.open(),
335
+ onSave: handleSave,
336
+ onExport: handleExport,
337
+ onReset: handleReset
338
+ });
339
+
340
+ // 表格列(带操作)
341
+ const columns = getPlanColumnsConfig({
342
+ onEdit: (row) => modalRef.value?.edit(row.id.toString()),
343
+ onDelete: handleDelete
344
+ });
345
+
346
+ // 切割信息列
347
+ const cutColumns = cutColumnsConfig;
348
+
349
+ // 生成模拟数据
350
+ // 生成计划信息数据(24条)
351
+ function generatePlanMockData(): TableRow[] {
352
+ const meltNos = [
353
+ "25300001",
354
+ "25300002",
355
+ "25300003",
356
+ "25300004",
357
+ "25300005",
358
+ "25300006",
359
+ "25300007",
360
+ "25300008"
361
+ ];
362
+ const slabTypes = ["热轧", "冷轧", "中厚板"];
363
+ const operators = [
364
+ "王志鹏",
365
+ "李小明",
366
+ "张华",
367
+ "刘强",
368
+ "陈明",
369
+ "王强",
370
+ "李华",
371
+ "张明"
372
+ ];
373
+
374
+ const data: TableRow[] = [];
375
+ for (let i = 1; i <= 24; i++) {
376
+ data.push({
377
+ id: i,
378
+ meltNo: meltNos[Math.floor(Math.random() * meltNos.length)],
379
+ slabNo: `BC3BD3BF${String(i).padStart(3, "0")}`,
380
+ planHeatNo: `PH${String(Math.floor(Math.random() * 999) + 1).padStart(
381
+ 3,
382
+ "0"
383
+ )}`,
384
+ slabType: slabTypes[Math.floor(Math.random() * slabTypes.length)],
385
+ cutCount: Math.floor(Math.random() * 10) + 1,
386
+ thickness: (Math.random() * 50 + 10).toFixed(1),
387
+ width: (Math.random() * 1000 + 500).toFixed(0),
388
+ totalLength: (Math.random() * 5000 + 1000).toFixed(0),
389
+ weight: (Math.random() * 10 + 2).toFixed(2),
390
+ multipleNo: String(Math.floor(Math.random() * 5) + 1),
391
+ actualSteel: "Q235B",
392
+ planCutTime: "2025-01-01 12:00:00",
393
+ cutOperator: operators[Math.floor(Math.random() * operators.length)]
394
+ });
395
+ }
396
+ return data;
397
+ }
398
+
399
+ // 生成切割信息数据(5条)
400
+ function generateCutMockData(): TableRow[] {
401
+ const meltNos = [
402
+ "25300001",
403
+ "25300002",
404
+ "25300003",
405
+ "25300004",
406
+ "25300005"
407
+ ];
408
+ const slabTypes = ["热轧", "冷轧", "中厚板"];
409
+ const operators = ["王志鹏", "李小明", "张华", "刘强", "陈明"];
410
+
411
+ const data: TableRow[] = [];
412
+ for (let i = 1; i <= 5; i++) {
413
+ data.push({
414
+ id: i,
415
+ meltNo: meltNos[Math.floor(Math.random() * meltNos.length)],
416
+ slabNo: `BC3BD3BF${String(i).padStart(3, "0")}`,
417
+ planHeatNo: `PH${String(Math.floor(Math.random() * 999) + 1).padStart(
418
+ 3,
419
+ "0"
420
+ )}`,
421
+ slabType: slabTypes[Math.floor(Math.random() * slabTypes.length)],
422
+ cutCount: Math.floor(Math.random() * 10) + 1,
423
+ thickness: (Math.random() * 50 + 10).toFixed(1),
424
+ width: (Math.random() * 1000 + 500).toFixed(0),
425
+ totalLength: (Math.random() * 5000 + 1000).toFixed(0),
426
+ weight: (Math.random() * 10 + 2).toFixed(2),
427
+ multipleNo: String(Math.floor(Math.random() * 5) + 1),
428
+ actualSteel: "Q235B",
429
+ planCutTime: "2025-01-01 12:00:00",
430
+ cutOperator: operators[Math.floor(Math.random() * operators.length)]
431
+ });
432
+ }
433
+ return data;
434
+ }
435
+
436
+ // 查询
437
+ async function select() {
438
+ loading.value = true;
439
+ try {
440
+ // 模拟API请求
441
+ await new Promise((resolve) => setTimeout(resolve, 500));
442
+ // 首次加载时生成完整数据
443
+ if (fullPlanData.value.length === 0) {
444
+ fullPlanData.value = generatePlanMockData();
445
+ cutList.value = generateCutMockData();
446
+ }
447
+ // 根据分页参数切片计划数据
448
+ const startIndex = (page.current - 1) * page.size;
449
+ const endIndex = startIndex + page.size;
450
+ list.value = fullPlanData.value.slice(startIndex, endIndex);
451
+ page.total = fullPlanData.value.length;
452
+ } finally {
453
+ loading.value = false;
454
+ }
455
+ }
456
+
457
+ // 保存
458
+ function handleSave() {
459
+ ElMessage.success("保存成功");
460
+ }
461
+
462
+ // 导出
463
+ function handleExport() {
464
+ ElMessage.success("导出成功");
465
+ }
466
+
467
+ // 重置
468
+ function handleReset() {
469
+ Object.assign(queryParam, {
470
+ slabNo: "",
471
+ planHeatNo: "",
472
+ meltNo: "",
473
+ startDate: "",
474
+ endDate: ""
475
+ });
476
+ select();
477
+ }
478
+
479
+ // 删除
480
+ function handleDelete(row: TableRow) {
481
+ ElMessageBox.confirm(`确定要删除板坯号 "${row.slabNo}" 吗?`, "删除确认", {
482
+ confirmButtonText: "确定",
483
+ cancelButtonText: "取消",
484
+ type: "warning"
485
+ })
486
+ .then(() => {
487
+ const index = fullPlanData.value.findIndex(
488
+ (item) => item.id === row.id
489
+ );
490
+ if (index > -1) {
491
+ fullPlanData.value.splice(index, 1);
492
+ // 重新计算分页数据
493
+ const startIndex = (page.current - 1) * page.size;
494
+ const endIndex = startIndex + page.size;
495
+ list.value = fullPlanData.value.slice(startIndex, endIndex);
496
+ page.total = fullPlanData.value.length;
497
+ ElMessage.success("删除成功");
498
+ }
499
+ })
500
+ .catch(() => {});
501
+ }
502
+
503
+ return {
504
+ // 状态
505
+ activeTab,
506
+ queryParam,
507
+ page,
508
+ tableRef,
509
+ list,
510
+ cutList,
511
+ loading,
512
+
513
+ // 配置
514
+ queryItems,
515
+ toolbars,
516
+ columns,
517
+ cutColumns,
518
+ renderType,
519
+ modalConfig,
520
+
521
+ // 方法
522
+ select
523
+ };
524
+ }