adspecs 0.1.18 → 0.1.19

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 (29) hide show
  1. package/.adspecs/extensions/git/commands/adspecs.git.initialize.md +4 -4
  2. package/.adspecs/extensions/git/extension.yml +1 -1
  3. package/.adspecs/extensions/git/git-config.yml +17 -2
  4. package/.adspecs/extensions.yml +32 -0
  5. package/.adspecs/paths.json +17 -0
  6. package/.adspecs/templates/02-/344/272/247/345/223/201/351/234/200/346/261/202/350/257/264/346/230/216/344/271/246/346/250/241/346/235/277.md +4 -0
  7. package/.adspecs/workflows/adspecs/workflow.yml +5 -4
  8. package/.claude-plugin/marketplace.json +1 -1
  9. package/.claude-plugin/plugin.json +1 -1
  10. package/.qoder-plugin/plugin.json +1 -1
  11. package/package.json +1 -1
  12. package/references/antd-front-demo/.env +4 -4
  13. package/references/antd-front-demo/.env.develop +12 -0
  14. package/references/antd-front-demo/.env.production +5 -0
  15. package/references/antd-front-demo/package-lock.json +2 -2
  16. package/references/antd-front-demo/package.json +1 -1
  17. package/skills/adspecs-front-prototype/SKILL.md +405 -0
  18. package/skills/adspecs-git-commit/SKILL.md +23 -8
  19. package/skills/adspecs-git-initialize/SKILL.md +54 -0
  20. package/src/lib/prompts.js +23 -21
  21. package/references/antd-front-demo/src/pages/aps/coil/components/CoilDrawer.tsx +0 -141
  22. package/references/antd-front-demo/src/pages/aps/coil/index.tsx +0 -209
  23. package/references/antd-front-demo/src/pages/aps/optimization/index.tsx +0 -192
  24. package/references/antd-front-demo/src/pages/aps/order/components/OrderDrawer.tsx +0 -251
  25. package/references/antd-front-demo/src/pages/aps/order/index.tsx +0 -273
  26. package/references/antd-front-demo/src/pages/aps/param/index.tsx +0 -153
  27. package/references/antd-front-demo/src/pages/aps/plan/components/CuttingPlanVisualization.tsx +0 -821
  28. package/references/antd-front-demo/src/pages/aps/plan/index.tsx +0 -254
  29. package/references/antd-front-demo/src/pages/aps/task/index.tsx +0 -190
@@ -1,141 +0,0 @@
1
- import { useEffect } from 'react';
2
- import { Drawer, Form, Input, InputNumber, DatePicker, Select, Button, Space, Card, message } from 'antd';
3
- import { useTranslation } from 'react-i18next';
4
- import { getCoil, createCoil, updateCoil } from '@/api/aps/coil';
5
- import type { CoilSaveParams } from '@/types/aps/coil';
6
- import dayjs from 'dayjs';
7
-
8
- interface CoilDrawerProps {
9
- open: boolean;
10
- id: number | null;
11
- onSuccess: () => void;
12
- onClose: () => void;
13
- }
14
-
15
- const CoilDrawer: React.FC<CoilDrawerProps> = ({ open, id, onSuccess, onClose }) => {
16
- const { t } = useTranslation('aps/coil');
17
- const { t: tc } = useTranslation('common');
18
- const [form] = Form.useForm();
19
- const isEdit = id !== null;
20
-
21
- useEffect(() => {
22
- if (open && id) {
23
- getCoil(id).then((res) => {
24
- form.setFieldsValue({
25
- ...res.data,
26
- inDate: dayjs(res.data.inDate),
27
- });
28
- });
29
- } else {
30
- form.resetFields();
31
- }
32
- }, [open, id, form]);
33
-
34
- const handleOk = async () => {
35
- try {
36
- const values = await form.validateFields();
37
- const params: CoilSaveParams = {
38
- ...values,
39
- id: id || undefined,
40
- inDate: values.inDate.format('YYYY-MM-DD'),
41
- };
42
- if (isEdit) {
43
- await updateCoil(params);
44
- } else {
45
- await createCoil(params);
46
- }
47
- message.success(tc('success'));
48
- onSuccess();
49
- } catch {
50
- // Validation failed
51
- }
52
- };
53
-
54
- return (
55
- <Drawer
56
- title={isEdit ? tc('edit') : tc('create')}
57
- open={open}
58
- onClose={onClose}
59
- size={256}
60
- closable={{ placement: 'end' }}
61
- destroyOnHidden={true}
62
- mask={{ closable: false }}
63
- styles={{ body: { background: '#f5f5f5' } }}
64
- footer={
65
- <Space style={{ float: 'right' }}>
66
- <Button onClick={onClose}>{tc('cancel')}</Button>
67
- <Button type="primary" onClick={handleOk}>
68
- {tc('confirm')}
69
- </Button>
70
- </Space>
71
- }
72
- >
73
- <Card style={{ border: 'none' }}>
74
- <Form form={form} layout="vertical">
75
- <Form.Item
76
- name="coilId"
77
- label={t('coilId')}
78
- rules={[{ required: true, message: tc('required') }]}
79
- >
80
- <Input />
81
- </Form.Item>
82
- <Form.Item
83
- name="alloy"
84
- label={t('alloy')}
85
- rules={[{ required: true, message: tc('required') }]}
86
- >
87
- <Select
88
- options={[
89
- { value: '3003', label: '3003' },
90
- { value: '5052', label: '5052' },
91
- ]}
92
- />
93
- </Form.Item>
94
- <Form.Item
95
- name="temper"
96
- label={t('temper')}
97
- rules={[{ required: true, message: tc('required') }]}
98
- >
99
- <Select
100
- options={[
101
- { value: 'H24', label: 'H24' },
102
- { value: 'H18', label: 'H18' },
103
- { value: 'O', label: 'O' },
104
- ]}
105
- />
106
- </Form.Item>
107
- <Form.Item
108
- name="width"
109
- label={t('width')}
110
- rules={[{ required: true, message: tc('required') }]}
111
- >
112
- <InputNumber min={0} max={2500} style={{ width: '100%' }} />
113
- </Form.Item>
114
- <Form.Item
115
- name="thickness"
116
- label={t('thickness')}
117
- rules={[{ required: true, message: tc('required') }]}
118
- >
119
- <InputNumber min={0} max={10} step={0.1} style={{ width: '100%' }} />
120
- </Form.Item>
121
- <Form.Item
122
- name="weight"
123
- label={t('weight')}
124
- rules={[{ required: true, message: tc('required') }]}
125
- >
126
- <InputNumber min={0} max={30} step={0.1} style={{ width: '100%' }} />
127
- </Form.Item>
128
- <Form.Item
129
- name="inDate"
130
- label={t('inDate')}
131
- rules={[{ required: true, message: tc('required') }]}
132
- >
133
- <DatePicker style={{ width: '100%' }} />
134
- </Form.Item>
135
- </Form>
136
- </Card>
137
- </Drawer>
138
- );
139
- };
140
-
141
- export default CoilDrawer;
@@ -1,209 +0,0 @@
1
- import { useRef, useState } from 'react';
2
- import { Button, Space, Tag, Popconfirm, Upload, message } from 'antd';
3
- import { PlusOutlined, UploadOutlined, DownloadOutlined } from '@ant-design/icons';
4
- import { ProTable } from '@ant-design/pro-components';
5
- import type { ActionType, ProColumns } from '@ant-design/pro-components';
6
- import { useTranslation } from 'react-i18next';
7
- import { Access } from '@/components/Access';
8
- import { getCoilPage, deleteCoil, importCoils, exportCoils, downloadCoilTemplate } from '@/api/aps/coil';
9
- import type { CoilVO } from '@/types/aps/coil';
10
- import { COIL_STATUS } from '@/types/aps/coil';
11
- import CoilDrawer from './components/CoilDrawer';
12
-
13
- const CoilPage: React.FC = () => {
14
- const { t } = useTranslation('aps/coil');
15
- const { t: tc } = useTranslation('common');
16
- const actionRef = useRef<ActionType>(null);
17
- const [drawerOpen, setDrawerOpen] = useState(false);
18
- const [editId, setEditId] = useState<number | null>(null);
19
-
20
- const handleDelete = (id: number) => async () => {
21
- await deleteCoil(id);
22
- message.success(tc('success'));
23
- actionRef.current?.reload();
24
- };
25
-
26
- const handleImport = async (file: File) => {
27
- const result = await importCoils(file);
28
- if (result.data.failCount === 0) {
29
- message.success(t('importSuccess', { count: result.data.successCount }));
30
- } else {
31
- message.warning(t('importFailed', { count: result.data.failCount }));
32
- }
33
- actionRef.current?.reload();
34
- return false;
35
- };
36
-
37
- const handleExport = async () => {
38
- await exportCoils({});
39
- message.success(tc('success'));
40
- };
41
-
42
- const handleDownloadTemplate = async () => {
43
- await downloadCoilTemplate();
44
- message.success(tc('success'));
45
- };
46
-
47
- const columns: ProColumns<CoilVO>[] = [
48
- {
49
- title: t('coilId'),
50
- dataIndex: 'coilId',
51
- ellipsis: true,
52
- width: 120,
53
- },
54
- {
55
- title: t('alloy'),
56
- dataIndex: 'alloy',
57
- valueType: 'select',
58
- valueEnum: {
59
- '3003': { text: '3003' },
60
- '5052': { text: '5052' },
61
- },
62
- width: 100,
63
- },
64
- {
65
- title: t('temper'),
66
- dataIndex: 'temper',
67
- search: false,
68
- width: 80,
69
- },
70
- {
71
- title: t('width'),
72
- dataIndex: 'width',
73
- search: false,
74
- width: 100,
75
- },
76
- {
77
- title: t('thickness'),
78
- dataIndex: 'thickness',
79
- search: false,
80
- width: 100,
81
- },
82
- {
83
- title: t('weight'),
84
- dataIndex: 'weight',
85
- search: false,
86
- width: 100,
87
- },
88
- {
89
- title: t('inDate'),
90
- dataIndex: 'inDate',
91
- search: false,
92
- width: 120,
93
- },
94
- {
95
- title: t('status'),
96
- dataIndex: 'status',
97
- valueType: 'select',
98
- valueEnum: {
99
- 0: { text: COIL_STATUS[0].label, status: 'Default' },
100
- 1: { text: COIL_STATUS[1].label, status: 'Processing' },
101
- 2: { text: COIL_STATUS[2].label, status: 'Success' },
102
- 3: { text: COIL_STATUS[3].label, status: 'Error' },
103
- },
104
- width: 100,
105
- render: (_, record) => {
106
- const item = COIL_STATUS[record.status as keyof typeof COIL_STATUS];
107
- return item ? <Tag color={item.color}>{item.label}</Tag> : '-';
108
- },
109
- },
110
- {
111
- title: t('createTime'),
112
- dataIndex: 'createTime',
113
- search: false,
114
- width: 180,
115
- },
116
- {
117
- title: tc('operation'),
118
- key: 'action',
119
- fixed: 'right',
120
- search: false,
121
- width: 150,
122
- render: (_, record) => (
123
- <Space>
124
- <Access code="aps:coil:update">
125
- <a
126
- onClick={() => {
127
- setEditId(record.id);
128
- setDrawerOpen(true);
129
- }}
130
- >
131
- {tc('edit')}
132
- </a>
133
- </Access>
134
- <Access code="aps:coil:delete">
135
- <Popconfirm title={t('deleteConfirm')} onConfirm={handleDelete(record.id)}>
136
- <a style={{ color: '#ff4d4f' }}>{tc('delete')}</a>
137
- </Popconfirm>
138
- </Access>
139
- </Space>
140
- ),
141
- },
142
- ];
143
-
144
- return (
145
- <>
146
- <ProTable<CoilVO>
147
- columns={columns}
148
- actionRef={actionRef}
149
- rowKey="id"
150
- headerTitle={t('title')}
151
- request={async (params) => {
152
- const { current, pageSize, ...rest } = params;
153
- const { data } = await getCoilPage({
154
- pageNo: current!,
155
- pageSize: pageSize!,
156
- ...rest,
157
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
158
- } as any);
159
- return { data: data.list, total: data.total, success: true };
160
- }}
161
- pagination={{ defaultPageSize: 10, showSizeChanger: true }}
162
- scroll={{ x: 1200 }}
163
- toolBarRender={() => [
164
- <Access code="aps:coil:create" key="add">
165
- <Button
166
- type="primary"
167
- icon={<PlusOutlined />}
168
- onClick={() => {
169
- setEditId(null);
170
- setDrawerOpen(true);
171
- }}
172
- >
173
- {tc('create')}
174
- </Button>
175
- </Access>,
176
- <Access code="aps:coil:import" key="import">
177
- <Upload
178
- accept=".xlsx,.xls"
179
- showUploadList={false}
180
- beforeUpload={handleImport}
181
- >
182
- <Button icon={<UploadOutlined />}>{t('import')}</Button>
183
- </Upload>
184
- </Access>,
185
- <Access code="aps:coil:export" key="export">
186
- <Button icon={<DownloadOutlined />} onClick={handleExport}>
187
- {t('export')}
188
- </Button>
189
- </Access>,
190
- <Button key="template" icon={<DownloadOutlined />} onClick={handleDownloadTemplate}>
191
- {t('downloadTemplate')}
192
- </Button>,
193
- ]}
194
- />
195
-
196
- <CoilDrawer
197
- open={drawerOpen}
198
- id={editId}
199
- onSuccess={() => {
200
- setDrawerOpen(false);
201
- actionRef.current?.reload();
202
- }}
203
- onClose={() => setDrawerOpen(false)}
204
- />
205
- </>
206
- );
207
- };
208
-
209
- export default CoilPage;
@@ -1,192 +0,0 @@
1
- import { useState, useEffect } from 'react';
2
- import { Card, Form, Select, Button, Space, message, Alert, Row, Col, Transfer } from 'antd';
3
- import { useTranslation } from 'react-i18next';
4
- import { useNavigate } from 'react-router-dom';
5
- import { Access } from '@/components/Access';
6
- import { getCoilPage } from '@/api/aps/coil';
7
- import { getOrderPage } from '@/api/aps/order';
8
- import { submitSingleCoilTask, submitGlobalTask } from '@/api/aps/task';
9
- import type { CoilVO } from '@/types/aps/coil';
10
- import type { OrderVO } from '@/types/aps/order';
11
-
12
- const OptimizationPage: React.FC = () => {
13
- const { t } = useTranslation('aps/task');
14
- const { t: tc } = useTranslation('common');
15
- const [form] = Form.useForm();
16
- const navigate = useNavigate();
17
- const [loading, setLoading] = useState(false);
18
-
19
- const [coils, setCoils] = useState<CoilVO[]>([]);
20
- const [orders, setOrders] = useState<OrderVO[]>([]);
21
- const [targetCoilIds, setTargetCoilIds] = useState<string[]>([]);
22
- const [targetOrderIds, setTargetOrderIds] = useState<string[]>([]);
23
-
24
- const loadData = async () => {
25
- const [coilRes, orderRes] = await Promise.all([
26
- getCoilPage({ pageNo: 1, pageSize: 1000, status: 0 }),
27
- getOrderPage({ pageNo: 1, pageSize: 1000, status: 0 }),
28
- ]);
29
- setCoils(coilRes.data.list);
30
- setOrders(orderRes.data.list);
31
- };
32
-
33
- useEffect(() => {
34
- // eslint-disable-next-line react-hooks/set-state-in-effect
35
- loadData();
36
- }, []);
37
-
38
- const handleSubmitSingle = async () => {
39
- if (targetCoilIds.length !== 1) {
40
- message.warning('请选择一个母卷');
41
- return;
42
- }
43
- if (targetOrderIds.length === 0) {
44
- message.warning('请至少选择一个订单');
45
- return;
46
- }
47
-
48
- setLoading(true);
49
- try {
50
- const strategy = form.getFieldValue('strategy') || 'AUTO';
51
- await submitSingleCoilTask({
52
- coilIds: targetCoilIds,
53
- orderIds: targetOrderIds,
54
- strategy,
55
- });
56
- message.success(tc('success'));
57
- navigate('/aps/task');
58
- } catch {
59
- message.error(tc('error'));
60
- } finally {
61
- setLoading(false);
62
- }
63
- };
64
-
65
- const handleSubmitGlobal = async () => {
66
- if (targetCoilIds.length < 2) {
67
- message.warning('请至少选择两个母卷');
68
- return;
69
- }
70
- if (targetOrderIds.length < 2) {
71
- message.warning('请至少选择两个订单');
72
- return;
73
- }
74
-
75
- setLoading(true);
76
- try {
77
- const strategy = form.getFieldValue('strategy') || 'AUTO';
78
- await submitGlobalTask({
79
- coilIds: targetCoilIds,
80
- orderIds: targetOrderIds,
81
- strategy,
82
- });
83
- message.success(tc('success'));
84
- navigate('/aps/task');
85
- } catch {
86
- message.error(tc('error'));
87
- } finally {
88
- setLoading(false);
89
- }
90
- };
91
-
92
- const coilTransferData = coils.map((c) => ({
93
- key: c.coilId,
94
- title: `${c.coilId} - ${c.alloy}/${c.temper} - ${c.width}×${c.thickness}mm - ${c.weight}吨`,
95
- description: c.coilId,
96
- }));
97
-
98
- const orderTransferData = orders.map((o) => ({
99
- key: o.orderId,
100
- title: `${o.orderId} - ${o.customerName} - ${o.width}mm - ${o.demand}吨`,
101
- description: o.orderId,
102
- }));
103
-
104
- return (
105
- <Form form={form} layout="vertical">
106
- <Card title={t('submitTask')} style={{ marginBottom: 16 }}>
107
- <Alert
108
- message="单卷方案:选择一个母卷和多个订单,生成该母卷的所有可行裁剪方案"
109
- description="全局优化:选择多个母卷和多个订单,系统自动进行匹配分组和全局优化"
110
- type="info"
111
- showIcon
112
- style={{ marginBottom: 16 }}
113
- />
114
-
115
- <Form.Item name="strategy" label={t('strategy')} initialValue="AUTO">
116
- <Select
117
- options={[
118
- { value: 'AUTO', label: t('strategies.AUTO') },
119
- { value: 'LENGTH_FIRST', label: t('strategies.LENGTH_FIRST') },
120
- { value: 'WIDTH_FIRST', label: t('strategies.WIDTH_FIRST') },
121
- ]}
122
- style={{ width: 200 }}
123
- />
124
- </Form.Item>
125
- </Card>
126
-
127
- <Row gutter={16}>
128
- <Col span={12}>
129
- <Card title={t('selectCoils')} size="small">
130
- <Transfer
131
- dataSource={coilTransferData}
132
- titles={['可选母卷', '已选母卷']}
133
- targetKeys={targetCoilIds}
134
- onChange={(keys) => setTargetCoilIds(keys as string[])}
135
- render={(item) => item.title as string}
136
- listStyle={{ width: '100%', height: 300 }}
137
- showSearch
138
- filterOption={(inputValue, item) =>
139
- (item.title as string).includes(inputValue) ||
140
- (item.description as string).includes(inputValue)
141
- }
142
- />
143
- </Card>
144
- </Col>
145
- <Col span={12}>
146
- <Card title={t('selectOrders')} size="small">
147
- <Transfer
148
- dataSource={orderTransferData}
149
- titles={['可选订单', '已选订单']}
150
- targetKeys={targetOrderIds}
151
- onChange={(keys) => setTargetOrderIds(keys as string[])}
152
- render={(item) => item.title as string}
153
- listStyle={{ width: '100%', height: 300 }}
154
- showSearch
155
- filterOption={(inputValue, item) =>
156
- (item.title as string).includes(inputValue) ||
157
- (item.description as string).includes(inputValue)
158
- }
159
- />
160
- </Card>
161
- </Col>
162
- </Row>
163
-
164
- <Card style={{ marginTop: 16 }}>
165
- <Space>
166
- <Access code="aps:task:create">
167
- <Button
168
- type="primary"
169
- onClick={handleSubmitSingle}
170
- loading={loading}
171
- disabled={targetCoilIds.length !== 1 || targetOrderIds.length === 0}
172
- >
173
- {t('singleCoil')}
174
- </Button>
175
- </Access>
176
- <Access code="aps:task:create">
177
- <Button
178
- type="primary"
179
- onClick={handleSubmitGlobal}
180
- loading={loading}
181
- disabled={targetCoilIds.length < 2 || targetOrderIds.length < 2}
182
- >
183
- {t('globalOptimization')}
184
- </Button>
185
- </Access>
186
- </Space>
187
- </Card>
188
- </Form>
189
- );
190
- };
191
-
192
- export default OptimizationPage;