@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,77 @@
1
+ <!--
2
+ * @Author: ChenYu ycyplus@gmail.com
3
+ * @Date: 2025-12-31 11:03:17
4
+ * @LastEditors: ChenYu ycyplus@gmail.com
5
+ * @LastEditTime: 2026-01-01 22:21:41
6
+ * @FilePath: \cx-ui-sale\src\views\sale\demo\domestic-trade-order\index.vue
7
+ * @Description: 内贸订单 - 视图层(内贸订单列表的查询、新增、编辑、删除)
8
+ * Copyright (c) 2025 by CHENY, All Rights Reserved 😎.
9
+ -->
10
+ <template>
11
+ <div class="app-container app-page-container">
12
+ <!-- 搜索栏 -->
13
+ <BaseQuery
14
+ :form="queryParam"
15
+ :items="queryItems"
16
+ :columns="5"
17
+ :auto-select="false"
18
+ @select="select"
19
+ @reset="select"
20
+ />
21
+ <!-- 工具栏 -->
22
+ <BaseToolbar :items="toolbars" :rightItems="rightToolbars" />
23
+ <!-- 表格 -->
24
+ <BaseTable
25
+ ref="tableRef"
26
+ :data="list"
27
+ :columns="columns"
28
+ :render-type="renderType"
29
+ showToolbar
30
+ />
31
+ <!-- 分页 -->
32
+ <jh-pagination
33
+ v-show="page.total && page.total > 0"
34
+ :total="page.total || 0"
35
+ v-model:currentPage="page.current"
36
+ v-model:pageSize="page.size"
37
+ @current-change="select"
38
+ @size-change="select"
39
+ />
40
+ </div>
41
+ <!-- 表单弹窗 -->
42
+ <c_formModal ref="modalRef" v-bind="modalConfig" @ok="select" />
43
+ </template>
44
+
45
+ <script setup lang="ts">
46
+ import c_formModal from "@/components/local/c_formModal/index.vue";
47
+ import { createPage, renderType, modalConfig } from "./data";
48
+
49
+ // 弹窗引用
50
+ const modalRef = ref<InstanceType<typeof c_formModal>>();
51
+
52
+ // 创建页面Hook实例
53
+ const Page = createPage(modalRef);
54
+
55
+ // 解构使用
56
+ const { page, queryParam, list, queryItems, toolbars, columns, select } = Page;
57
+
58
+ // TODO: 右侧工具栏 - 临时用于切换表格类型演示,未来需删除除)
59
+ const rightToolbars = [
60
+ {
61
+ label: "切换表格",
62
+ classnames: ["glass-button"],
63
+ onClick: () => {
64
+ renderType.value = renderType.value === "dataTable" ? "agGrid" : "dataTable";
65
+ }
66
+ }
67
+ ];
68
+
69
+ // 初始化
70
+ onMounted(() => {
71
+ select();
72
+ });
73
+ </script>
74
+
75
+ <style scoped lang="scss">
76
+ @import "./index.scss";
77
+ </style>
@@ -0,0 +1,367 @@
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-04 08:52:20
6
+ * @FilePath: \cx-ui-sale\src\views\sale\demo\heat-batch-return\data.ts
7
+ * @Description: 炉次返送 - 数据逻辑层
8
+ * Copyright (c) 2025 by CHENY, All Rights Reserved 😎.
9
+ */
10
+ import { ref, reactive, h } from "vue";
11
+ import { TableColumnDesc } from "@jhlc/common-core/src/components/table/base-table/type";
12
+ import { ActionButtonDesc } from "@jhlc/common-core/src/components/toolbar/type";
13
+ import type { BaseFormItemDesc } from "@jhlc/common-core/src/components/form/common/type";
14
+ import axios from "axios";
15
+ import { ElMessage } from "element-plus";
16
+
17
+ // 计划炉号点击处理函数
18
+ function handlePlanFurnaceNoClick(row: any) {
19
+ ElMessage.info(`查看计划炉号: ${row.plannedFurnaceNumber} 的详细信息`);
20
+ // 这里可以添加跳转到计划炉号详情页面或打开详情弹窗的逻辑
21
+ }
22
+
23
+ /**
24
+ * 表格列配置 - 待返送
25
+ */
26
+ export const pendingColumnsConfig: TableColumnDesc<any>[] = [
27
+ { type: "selection", width: 55 },
28
+ {
29
+ label: "计划炉号",
30
+ name: "plannedFurnaceNumber",
31
+ defaultSlot: ({ row }: any) => {
32
+ return h(
33
+ "span",
34
+ {
35
+ style: "color: #409eff; cursor: pointer; text-decoration: underline;",
36
+ onClick: () => handlePlanFurnaceNoClick(row)
37
+ },
38
+ row.plannedFurnaceNumber
39
+ );
40
+ }
41
+ },
42
+ { label: "计划顺序号", name: "plannedSequenceNumber", width: 120 },
43
+ { label: "熔炼号", name: "smeltingNumber", width: 150 },
44
+ { label: "内部钢种", name: "internalSteelGrade", width: 120 },
45
+ { label: "铸机号", name: "castingMachineNumber", width: 120 }
46
+ ];
47
+
48
+ /**
49
+ * 表格列配置 - 已返送
50
+ */
51
+ export const returnedColumnsConfig: TableColumnDesc<any>[] = [
52
+ { type: "selection", width: 55 },
53
+ {
54
+ label: "计划炉号",
55
+ name: "plannedFurnaceNumber",
56
+ defaultSlot: ({ row }: any) => {
57
+ return h(
58
+ "span",
59
+ {
60
+ style: "color: #409eff; cursor: pointer; text-decoration: underline;",
61
+ onClick: () => handlePlanFurnaceNoClick(row)
62
+ },
63
+ row.plannedFurnaceNumber
64
+ );
65
+ }
66
+ },
67
+ { label: "计划顺序号", name: "plannedSequenceNumber", width: 120 },
68
+ { label: "熔炼号", name: "smeltingNumber", width: 150 },
69
+ { label: "内部钢种", name: "internalSteelGrade", width: 120 },
70
+ { label: "铸机号", name: "castingMachineNumber", width: 120 }
71
+ ];
72
+
73
+ /**
74
+ * Loading状态
75
+ */
76
+ export const pendingLoading = ref(false);
77
+ export const returnedLoading = ref(false);
78
+
79
+ /**
80
+ * 待返送数据
81
+ */
82
+ export const pendingData = reactive({
83
+ list: [] as any[],
84
+ total: 0
85
+ });
86
+
87
+ /**
88
+ * 已返送数据
89
+ */
90
+ export const returnedData = reactive({
91
+ list: [] as any[],
92
+ total: 0
93
+ });
94
+
95
+ /**
96
+ * 待返送分页
97
+ */
98
+ export const pendingPagination = reactive({
99
+ page: 1,
100
+ pageSize: 15
101
+ });
102
+
103
+ /**
104
+ * 已返送分页
105
+ */
106
+ export const returnedPagination = reactive({
107
+ page: 1,
108
+ pageSize: 15
109
+ });
110
+
111
+ /**
112
+ * 选中的行
113
+ */
114
+ export const pendingSelectedRows = ref<any[]>([]);
115
+ export const returnedSelectedRows = ref<any[]>([]);
116
+
117
+ /**
118
+ * API 配置 - 统一管理所有接口地址
119
+ */
120
+ export const API_CONFIG = {
121
+ list: "/api/furnace-batch/list",
122
+ save: "/api/furnace-batch/save",
123
+ update: "/api/furnace-batch/update",
124
+ getById: "/api/furnace-batch/getOneById"
125
+ } as const;
126
+
127
+ /**
128
+ * 获取待返送数据
129
+ */
130
+ export const fetchPendingData = async () => {
131
+ pendingLoading.value = true;
132
+
133
+ try {
134
+ const params = {
135
+ page: pendingPagination.page,
136
+ pageSize: pendingPagination.pageSize,
137
+ type: "pending"
138
+ };
139
+
140
+ const response = await axios.get(API_CONFIG.list, { params });
141
+
142
+ if (response.data.code === 200) {
143
+ pendingData.list = response.data.data.list;
144
+ pendingData.total = response.data.data.total;
145
+ } else {
146
+ ElMessage.error(response.data.message || "获取数据失败");
147
+ }
148
+ } catch (error) {
149
+ console.error("获取待返送数据失败:", error);
150
+ ElMessage.error("获取数据失败");
151
+ } finally {
152
+ pendingLoading.value = false;
153
+ }
154
+ };
155
+
156
+ /**
157
+ * 获取已返送数据
158
+ */
159
+ export const fetchReturnedData = async () => {
160
+ returnedLoading.value = true;
161
+
162
+ try {
163
+ const params = {
164
+ page: returnedPagination.page,
165
+ pageSize: returnedPagination.pageSize,
166
+ type: "returned"
167
+ };
168
+
169
+ const response = await axios.get(API_CONFIG.list, { params });
170
+
171
+ if (response.data.code === 200) {
172
+ returnedData.list = response.data.data.list;
173
+ returnedData.total = response.data.data.total;
174
+ } else {
175
+ ElMessage.error(response.data.message || "获取数据失败");
176
+ }
177
+ } catch (error) {
178
+ console.error("获取已返送数据失败:", error);
179
+ ElMessage.error("获取数据失败");
180
+ } finally {
181
+ returnedLoading.value = false;
182
+ }
183
+ };
184
+
185
+ /**
186
+ * 待返送分页变化
187
+ */
188
+ export const handlePendingPageChange = (page: number) => {
189
+ pendingPagination.page = page;
190
+ fetchPendingData();
191
+ };
192
+
193
+ export const handlePendingSizeChange = (size: number) => {
194
+ pendingPagination.pageSize = size;
195
+ pendingPagination.page = 1;
196
+ fetchPendingData();
197
+ };
198
+
199
+ /**
200
+ * 已返送分页变化
201
+ */
202
+ export const handleReturnedPageChange = (page: number) => {
203
+ returnedPagination.page = page;
204
+ fetchReturnedData();
205
+ };
206
+
207
+ export const handleReturnedSizeChange = (size: number) => {
208
+ returnedPagination.pageSize = size;
209
+ returnedPagination.page = 1;
210
+ fetchReturnedData();
211
+ };
212
+
213
+ /**
214
+ * 选择变化
215
+ */
216
+ export const handlePendingSelectionChange = (selection: any[]) => {
217
+ pendingSelectedRows.value = selection;
218
+ };
219
+
220
+ export const handleReturnedSelectionChange = (selection: any[]) => {
221
+ returnedSelectedRows.value = selection;
222
+ };
223
+
224
+ /**
225
+ * 查询
226
+ */
227
+ export const handleQuery = () => {
228
+ pendingPagination.page = 1;
229
+ returnedPagination.page = 1;
230
+ fetchPendingData();
231
+ fetchReturnedData();
232
+ };
233
+
234
+ /**
235
+ * 新增返送炉次弹窗配置
236
+ */
237
+ export const modalConfig = {
238
+ titlePrefix: "返送炉次",
239
+ width: "60%",
240
+ columns: 4,
241
+ labelWidth: "90px",
242
+ formItems: [
243
+ {
244
+ name: "ponoNumber",
245
+ label: "PONO号",
246
+ placeholder: "请输入"
247
+ },
248
+ {
249
+ name: "continuousCasterNumber",
250
+ label: "连铸机号",
251
+ required: true,
252
+ placeholder: "请选择",
253
+ customProps: () => ({
254
+ clearable: true,
255
+ options: [
256
+ { label: "1", value: "1" },
257
+ { label: "2", value: "2" },
258
+ { label: "3", value: "3" }
259
+ ]
260
+ })
261
+ },
262
+ {
263
+ name: "internalSteelGrade",
264
+ label: "内部钢种",
265
+ required: true,
266
+ placeholder: "请输入"
267
+ },
268
+ {
269
+ name: "castSlabType",
270
+ label: "铸坯类型",
271
+ required: true,
272
+ placeholder: "请选择",
273
+ customProps: () => ({
274
+ clearable: true,
275
+ options: [
276
+ { label: "类型1", value: "type1" },
277
+ { label: "类型2", value: "type2" },
278
+ { label: "类型3", value: "type3" }
279
+ ]
280
+ })
281
+ },
282
+ {
283
+ name: "slabCount",
284
+ label: "坯数",
285
+ required: true,
286
+ placeholder: "请输入",
287
+ rules: [
288
+ { required: true, message: "请输入坯数", trigger: "blur" },
289
+ { pattern: /^\d+$/, message: "坯数必须为数字", trigger: "blur" }
290
+ ]
291
+ },
292
+ {
293
+ name: "thickness",
294
+ label: "厚度",
295
+ required: true,
296
+ placeholder: "请输入",
297
+ rules: [
298
+ { required: true, message: "请输入厚度", trigger: "blur" },
299
+ { pattern: /^\d+(\.\d+)?$/, message: "厚度必须为数字", trigger: "blur" }
300
+ ]
301
+ },
302
+ {
303
+ name: "width",
304
+ label: "宽度",
305
+ required: true,
306
+ placeholder: "请输入",
307
+ rules: [
308
+ { required: true, message: "请输入宽度", trigger: "blur" },
309
+ { pattern: /^\d+(\.\d+)?$/, message: "宽度必须为数字", trigger: "blur" }
310
+ ]
311
+ },
312
+ {
313
+ name: "length",
314
+ label: "长度",
315
+ required: true,
316
+ placeholder: "请输入",
317
+ rules: [
318
+ { required: true, message: "请输入长度", trigger: "blur" },
319
+ { pattern: /^\d+(\.\d+)?$/, message: "长度必须为数字", trigger: "blur" }
320
+ ]
321
+ },
322
+ {
323
+ name: "lengthUpperLimit",
324
+ label: "长度上限",
325
+ required: true,
326
+ placeholder: "请输入",
327
+ rules: [
328
+ { required: true, message: "请输入长度上限", trigger: "blur" },
329
+ {
330
+ pattern: /^\d+(\.\d+)?$/,
331
+ message: "长度上限必须为数字",
332
+ trigger: "blur"
333
+ }
334
+ ]
335
+ },
336
+ {
337
+ name: "widthUpperLimit",
338
+ label: "宽度上限",
339
+ required: true,
340
+ placeholder: "请输入",
341
+ rules: [
342
+ { required: true, message: "请输入宽度上限", trigger: "blur" },
343
+ {
344
+ pattern: /^\d+(\.\d+)?$/,
345
+ message: "宽度上限必须为数字",
346
+ trigger: "blur"
347
+ }
348
+ ]
349
+ }
350
+ ] as BaseFormItemDesc<any>[],
351
+ api: {
352
+ getById: API_CONFIG.getById,
353
+ save: API_CONFIG.save,
354
+ update: API_CONFIG.update
355
+ }
356
+ };
357
+
358
+ /**
359
+ * 工具栏配置生成
360
+ */
361
+ export const getToolbarConfig = (callbacks: {
362
+ onReturn: () => void;
363
+ onQuery: () => void;
364
+ }): ActionButtonDesc[] => [
365
+ { label: "炉次返送", type: "primary", onClick: callbacks.onReturn },
366
+ { label: "查询", type: "primary", onClick: callbacks.onQuery }
367
+ ];
@@ -0,0 +1,100 @@
1
+ /**
2
+ * 炉次返送 - 样式层
3
+ */
4
+
5
+ .furnace-batch-page-container {
6
+ width: 100%;
7
+ height: calc(100% - 16px);
8
+ padding: 8px;
9
+ background-color: #f5f5f5;
10
+ }
11
+
12
+ .furnace-batch-page {
13
+ width: 100%;
14
+ height: 100%;
15
+ background-color: #fff;
16
+ box-sizing: border-box;
17
+ display: flex;
18
+ flex-direction: column;
19
+ }
20
+
21
+ // 工具栏容器
22
+ .toolbar-container {
23
+ flex-shrink: 0;
24
+ padding: 16px 16px 0 16px;
25
+ margin-bottom: 16px;
26
+ }
27
+
28
+ .page-container {
29
+ display: flex;
30
+ gap: 6px;
31
+ flex: 1;
32
+ overflow: hidden;
33
+ }
34
+
35
+ // 左右区块通用样式
36
+ .section {
37
+ flex: 1;
38
+ display: flex;
39
+ flex-direction: column;
40
+ background-color: #fff;
41
+ position: relative;
42
+ padding: 0 16px 16px 16px;
43
+ overflow: hidden;
44
+
45
+ &.left-section {
46
+ padding-right: 8px;
47
+ }
48
+
49
+ &.right-section {
50
+ padding-left: 8px;
51
+ }
52
+ }
53
+
54
+ // 表格容器
55
+ .table-box {
56
+ flex: 1;
57
+ overflow: hidden;
58
+ }
59
+
60
+ // 区块标题
61
+ .section-header {
62
+ display: flex;
63
+ align-items: center;
64
+ margin-bottom: 16px;
65
+ height: 24px;
66
+ background: rgba(67, 104, 255, 0.1);
67
+
68
+ .title-bar {
69
+ width: 4px;
70
+ height: 80%;
71
+ background-color: #4368FF;
72
+ margin-right: 6px;
73
+ margin-left: 8px;
74
+ }
75
+
76
+ .section-title {
77
+ margin: 0;
78
+ font-size: 14px;
79
+ font-weight: 500;
80
+ color: #000000;
81
+ }
82
+ }
83
+
84
+ // 分页容器
85
+ .pagination-container {
86
+ margin-top: 16px;
87
+ display: flex;
88
+ justify-content: space-between;
89
+ align-items: center;
90
+
91
+ .pagination-info {
92
+ font-size: 14px;
93
+ color: #666;
94
+ }
95
+ }
96
+
97
+ // 分页样式调整
98
+ :deep(.el-pagination) {
99
+ position: sticky;
100
+ }
@@ -0,0 +1,170 @@
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-04 08:29:26
6
+ * @FilePath: \cx-ui-sale\src\views\sale\demo\heat-batch-return\index.vue
7
+ * @Description: 炉次返送 - 视图层(待炉次返送与已炉次返送数据管理)
8
+ * Copyright (c) 2025 by CHENY, All Rights Reserved 😎.
9
+ -->
10
+ <template>
11
+ <div class="furnace-batch-page-container">
12
+ <div class="furnace-batch-page">
13
+ <!-- 工具栏单独占一行 -->
14
+ <div class="toolbar-container">
15
+ <BaseToolbar :items="pendingToolbarItems" />
16
+ </div>
17
+
18
+ <!-- 表格内容区域 -->
19
+ <div class="page-container">
20
+ <!-- 左侧:待炉次返送 -->
21
+ <div class="section left-section">
22
+ <!-- 标题 -->
23
+ <div class="section-header">
24
+ <div class="title-bar"></div>
25
+ <h2 class="section-title">待炉次返送</h2>
26
+ </div>
27
+
28
+ <!-- 表格 -->
29
+ <div class="table-box">
30
+ <BaseTable
31
+ :data="pendingData.list"
32
+ :columns="pendingColumnsConfig"
33
+ :loading="pendingLoading"
34
+ border
35
+ stripe
36
+ size="small"
37
+ height="100%"
38
+ @selection-change="handlePendingSelectionChange"
39
+ />
40
+ </div>
41
+
42
+ <!-- 分页 -->
43
+ <div class="pagination-container">
44
+ <div class="pagination-info">共{{ pendingData.total }}条</div>
45
+ <jh-pagination
46
+ v-model:currentPage="pendingPagination.page"
47
+ v-model:pageSize="pendingPagination.pageSize"
48
+ :total="pendingData.total"
49
+ :page-sizes="[15, 30, 50, 100]"
50
+ layout="prev, pager, next, sizes, jumper"
51
+ size="small"
52
+ @current-change="handlePendingPageChange"
53
+ @size-change="handlePendingSizeChange"
54
+ />
55
+ </div>
56
+ </div>
57
+
58
+ <!-- 右侧:已炉次返送 -->
59
+ <div class="section right-section">
60
+ <!-- 标题 -->
61
+ <div class="section-header">
62
+ <div class="title-bar"></div>
63
+ <h2 class="section-title">已炉次返送</h2>
64
+ </div>
65
+
66
+ <!-- 表格 -->
67
+ <div class="table-box">
68
+ <BaseTable
69
+ :data="returnedData.list"
70
+ :columns="returnedColumnsConfig"
71
+ :loading="returnedLoading"
72
+ border
73
+ stripe
74
+ size="small"
75
+ height="100%"
76
+ @selection-change="handleReturnedSelectionChange"
77
+ />
78
+ </div>
79
+
80
+ <!-- 分页 -->
81
+ <div class="pagination-container">
82
+ <div class="pagination-info">共{{ returnedData.total }}条</div>
83
+ <jh-pagination
84
+ v-model:currentPage="returnedPagination.page"
85
+ v-model:pageSize="returnedPagination.pageSize"
86
+ :total="returnedData.total"
87
+ :page-sizes="[15, 30, 50, 100]"
88
+ layout="prev, pager, next, sizes, jumper"
89
+ size="small"
90
+ @current-change="handleReturnedPageChange"
91
+ @size-change="handleReturnedSizeChange"
92
+ />
93
+ </div>
94
+ </div>
95
+ </div>
96
+ </div>
97
+
98
+ <!-- 新增返送弹窗 -->
99
+ <c_formModal
100
+ ref="modalRef"
101
+ :form-items="modalConfig.formItems"
102
+ :api="modalConfig.api"
103
+ :width="modalConfig.width"
104
+ :columns="modalConfig.columns"
105
+ :label-width="modalConfig.labelWidth"
106
+ :title-prefix="modalConfig.titlePrefix"
107
+ @ok="handleModalOk"
108
+ />
109
+ </div>
110
+ </template>
111
+
112
+ <script setup lang="ts">
113
+ import { ref, computed, onMounted } from "vue";
114
+ import c_formModal from "@/components/local/c_formModal/index.vue";
115
+ import {
116
+ pendingColumnsConfig,
117
+ returnedColumnsConfig,
118
+ pendingLoading,
119
+ returnedLoading,
120
+ pendingData,
121
+ returnedData,
122
+ pendingPagination,
123
+ returnedPagination,
124
+ fetchPendingData,
125
+ fetchReturnedData,
126
+ handlePendingPageChange,
127
+ handlePendingSizeChange,
128
+ handleReturnedPageChange,
129
+ handleReturnedSizeChange,
130
+ handlePendingSelectionChange,
131
+ handleReturnedSelectionChange,
132
+ handleQuery,
133
+ getToolbarConfig,
134
+ modalConfig
135
+ } from "./data";
136
+ import "./index.scss";
137
+
138
+ // 弹窗引用
139
+ const modalRef = ref<InstanceType<typeof c_formModal>>();
140
+
141
+ // 待返送工具栏配置
142
+ const pendingToolbarItems = computed(() =>
143
+ getToolbarConfig({
144
+ onReturn: () => modalRef.value?.open(),
145
+ onQuery: handleQuery
146
+ })
147
+ );
148
+
149
+ // 弹窗操作成功回调
150
+ const handleModalOk = () => {
151
+ fetchPendingData();
152
+ fetchReturnedData();
153
+ };
154
+
155
+ // 初始化数据
156
+ onMounted(() => {
157
+ fetchPendingData();
158
+ fetchReturnedData();
159
+ });
160
+ </script>
161
+
162
+ <style scoped lang="scss">
163
+ @import "./index.scss";
164
+
165
+ .input-suffix {
166
+ color: #909399;
167
+ font-size: 12px;
168
+ padding-right: 0px;
169
+ }
170
+ </style>