1c9bc538
Shinner
修复问题
|
1
|
import React, { useEffect, useMemo, useState } from "react";
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
2
3
|
import {
InputNumber,
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
4
5
6
7
8
|
Divider,
Form,
message,
Table,
Button,
|
3b0d1ee6
Shinner
增加零售任务分配菜单静态页面
|
9
10
|
Row,
Tag,
|
d8aedefd
Shinner
单个门店支持分配到门店和顾问
|
11
|
Modal,
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
12
13
14
|
} from "antd";
import { PlusOutlined } from "@ant-design/icons";
import * as API from "../../../api";
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
15
|
import styles from "../index.less";
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
16
|
import { useStore } from "../../../store";
|
3b0d1ee6
Shinner
增加零售任务分配菜单静态页面
|
17
|
import _ from "lodash";
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
18
|
import EditableCell from "./EditableCell";
|
3b0d1ee6
Shinner
增加零售任务分配菜单静态页面
|
19
|
import SeriesModal from "./SeriesModal";
|
1aa6dd0a
Shinner
调试零售任务分配接口
|
20
|
import { history, useRequest } from "umi";
|
1c9bc538
Shinner
修复问题
|
21
|
import { MAX_NUM } from "../../../entity";
|
75f10597
Shinner
回刷页面
|
22
|
import "../../../components/index.less";
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
23
|
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
24
25
|
const { Column } = Table;
|
a8fb2c8c
Shinner
优化销顾任务保存草稿逻辑
|
26
27
|
interface ShopTaskProps {
form: any;
|
75f10597
Shinner
回刷页面
|
28
|
onRefresh: () => void;
|
a8fb2c8c
Shinner
优化销顾任务保存草稿逻辑
|
29
30
|
}
|
75f10597
Shinner
回刷页面
|
31
|
export default function ShopTask({ form, onRefresh }: ShopTaskProps) {
|
263b8790
Shinner
优化分配任务前端数据更新逻辑
|
32
33
34
35
36
37
38
|
const {
shopTaskItem,
isReadOnly,
setShopSeriesRow,
deleteShopSeriesRow,
addShopSeriesRow,
} = useStore();
|
a1e7edf3
Shinner
调试零售任务分配接口
|
39
|
const [seriesForm] = Form.useForm();
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
40
|
const [editingKey, setEditingKey] = useState(-1); // 编辑表格 key
|
3b0d1ee6
Shinner
增加零售任务分配菜单静态页面
|
41
|
const [seriesVisible, setSeriesVisible] = useState(false);
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
42
|
|
1aa6dd0a
Shinner
调试零售任务分配接口
|
43
44
45
46
47
|
const saveShopSaleTaskHook = useRequest(API.saveShopSaleTask, {
manual: true,
throwOnError: true,
});
|
1c9bc538
Shinner
修复问题
|
48
49
50
51
52
53
|
// 车系去重
const selectedIds = useMemo(() => {
if (!shopTaskItem) return [];
return shopTaskItem.seriesTaskList.map((item) => String(item.seriesId));
}, [shopTaskItem]);
|
4ddb4140
Shinner
调试零售任务分配接口
|
54
55
56
57
58
59
|
// 计算车系任务总数自动填写
useEffect(() => {
const total = shopTaskItem?.seriesTaskList.reduce(
(total, currItem) => total + currItem.taskCount,
0
);
|
eb77f47f
Shinner
增加表单交互
|
60
|
form.setFieldValue("seriesTaskCount", total);
|
4ddb4140
Shinner
调试零售任务分配接口
|
61
62
|
}, [shopTaskItem]);
|
a1e7edf3
Shinner
调试零售任务分配接口
|
63
64
|
const isEditing = (record: API.SeriesTaskItem) => {
return record.seriesId === Number(editingKey);
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
65
66
|
};
|
a1e7edf3
Shinner
调试零售任务分配接口
|
67
68
|
const setSeriesRow = (id: number) => {
seriesForm
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
69
70
71
|
.validateFields()
.then((row: any) => {
setEditingKey(-1);
|
263b8790
Shinner
优化分配任务前端数据更新逻辑
|
72
|
setShopSeriesRow(id, row);
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
73
74
75
76
77
78
|
})
.catch((error: any) => {
message.error(error.message ?? "表单校验失败");
});
};
|
a1e7edf3
Shinner
调试零售任务分配接口
|
79
80
81
|
const editSeriesRow = (record: API.SeriesTaskItem) => {
seriesForm.setFieldsValue({ ...record });
setEditingKey(record.seriesId);
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
82
83
|
};
|
1c9bc538
Shinner
修复问题
|
84
|
// 添加车系
|
3b0d1ee6
Shinner
增加零售任务分配菜单静态页面
|
85
|
const handleSelectSeries = (values: any) => {
|
263b8790
Shinner
优化分配任务前端数据更新逻辑
|
86
|
addShopSeriesRow(values);
|
a1e7edf3
Shinner
调试零售任务分配接口
|
87
|
setSeriesVisible(false);
|
3b0d1ee6
Shinner
增加零售任务分配菜单静态页面
|
88
89
|
};
|
1aa6dd0a
Shinner
调试零售任务分配接口
|
90
91
92
93
94
95
96
|
const handleGoBack = () => {
history.goBack(); // todo 提示是否有未保存的修改
};
const handleSaveTask = async () => {
await form.validateFields();
const values = form.getFieldsValue();
|
df7d79e7
Shinner
调试零售任务分配接口
|
97
|
const { taskId, ...other } = shopTaskItem!;
|
1aa6dd0a
Shinner
调试零售任务分配接口
|
98
|
saveShopSaleTaskHook
|
df7d79e7
Shinner
调试零售任务分配接口
|
99
|
.run({ ...other, ...values, id: taskId })
|
1aa6dd0a
Shinner
调试零售任务分配接口
|
100
101
|
.then(() => {
message.success("保存草稿成功");
|
75f10597
Shinner
回刷页面
|
102
|
onRefresh();
|
1aa6dd0a
Shinner
调试零售任务分配接口
|
103
104
|
})
.catch((error: any) => {
|
436c6c9d
Shinner
报错显示后端提示信息
|
105
|
message.error(error.message ?? "请求失败");
|
1aa6dd0a
Shinner
调试零售任务分配接口
|
106
107
108
|
});
};
|
d8aedefd
Shinner
单个门店支持分配到门店和顾问
|
109
110
111
112
113
114
115
116
|
// 分配到门店和顾问
const autoAssignOneShop = async () => {
await form.validateFields();
const values = form.getFieldsValue();
Modal.confirm({
title: (
<span>
确认分配到
|
75f10597
Shinner
回刷页面
|
117
|
<span className="tip">此门店和顾问</span>
|
d8aedefd
Shinner
单个门店支持分配到门店和顾问
|
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
吗?
</span>
),
zIndex: 1002,
onOk: async () => {
const hide = message.loading("分配中,请稍候", 0);
const { taskId, id, ...other } = shopTaskItem!;
API.autoAssignOneShop({
...other,
...values,
orderTaskApplyId: taskId,
orderShopTaskId: id,
})
.then((res) => {
message.success("分配成功");
|
75f10597
Shinner
回刷页面
|
133
|
onRefresh();
|
d8aedefd
Shinner
单个门店支持分配到门店和顾问
|
134
135
136
137
138
139
140
141
142
143
144
|
})
.catch((error: any) => {
message.error(error.message ?? "请求失败");
})
.finally(() => {
hide();
});
},
});
};
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
145
146
147
148
149
150
151
152
153
154
155
156
|
const layout = {
labelCol: { span: 5 },
wrapperCol: { span: 19 },
};
const components = {
body: {
cell: EditableCell,
},
};
return (
|
4c5bad19
Shinner
预览任务按钮显示与是否审批无关;调整样式
|
157
|
<>
|
1aa6dd0a
Shinner
调试零售任务分配接口
|
158
|
<div style={{ width: 880, margin: "0 auto", paddingTop: 24 }}>
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
159
160
161
162
|
<Form
{...layout}
labelAlign="left"
form={form}
|
11ea8143
Shinner
调试零售任务分配接口
|
163
|
initialValues={shopTaskItem!}
|
75f10597
Shinner
回刷页面
|
164
|
disabled={isReadOnly}
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
165
|
>
|
3b0d1ee6
Shinner
增加零售任务分配菜单静态页面
|
166
|
<Form.Item name="taskCount" label="零售任务:" required>
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
167
168
169
170
|
<InputNumber
formatter={(value) => `${value}台`}
parser={(value: any) => value.replace("台", "")}
min={0}
|
1c9bc538
Shinner
修复问题
|
171
|
max={MAX_NUM}
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
172
|
style={{ width: "100%" }}
|
1c9bc538
Shinner
修复问题
|
173
|
precision={0}
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
174
175
|
/>
</Form.Item>
|
3b0d1ee6
Shinner
增加零售任务分配菜单静态页面
|
176
177
178
|
<Form.Item
noStyle
shouldUpdate={(prevValues, currentValues) => {
|
1aa6dd0a
Shinner
调试零售任务分配接口
|
179
180
181
|
if (prevValues.taskCount !== currentValues.taskCount) {
form.setFieldValue(
"clueDealTaskCount",
|
22729ea6
Shinner
修复编辑顾问任务分配
|
182
183
|
(
currentValues.taskCount *
|
1aa6dd0a
Shinner
调试零售任务分配接口
|
184
|
((shopTaskItem?.clueDealTaskRate ?? 100) / 100)
|
22729ea6
Shinner
修复编辑顾问任务分配
|
185
|
).toFixed(2)
|
1aa6dd0a
Shinner
调试零售任务分配接口
|
186
187
|
);
}
|
3b0d1ee6
Shinner
增加零售任务分配菜单静态页面
|
188
189
190
|
return prevValues.taskCount !== currentValues.taskCount;
}}
>
|
1aa6dd0a
Shinner
调试零售任务分配接口
|
191
|
{() => {
|
3b0d1ee6
Shinner
增加零售任务分配菜单静态页面
|
192
|
return (
|
eb77f47f
Shinner
增加表单交互
|
193
194
195
196
197
|
<Form.Item
name="clueDealTaskCount"
label="线索到店零售台数:"
required
>
|
3b0d1ee6
Shinner
增加零售任务分配菜单静态页面
|
198
199
200
201
|
<InputNumber
formatter={(value) => `${value}台`}
parser={(value: any) => value.replace("台", "")}
min={0}
|
1c9bc538
Shinner
修复问题
|
202
|
max={MAX_NUM}
|
3b0d1ee6
Shinner
增加零售任务分配菜单静态页面
|
203
|
style={{ width: "100%" }}
|
1c9bc538
Shinner
修复问题
|
204
|
precision={2}
|
3b0d1ee6
Shinner
增加零售任务分配菜单静态页面
|
205
206
207
208
|
/>
</Form.Item>
);
}}
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
209
|
</Form.Item>
|
eb77f47f
Shinner
增加表单交互
|
210
|
<Form.Item
|
9d18f86b
Shinner
回退台数交互
|
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
|
name="newEnergyTaskCount"
label="新能源车任务台数:"
required
dependencies={["taskCount", "fuelVehicleTaskCount"]}
rules={[
({ getFieldValue }) => ({
validator(_, value) {
const taskCount = getFieldValue("taskCount");
const fuelVehicleTaskCount = getFieldValue(
"fuelVehicleTaskCount"
);
if (
value >= 0 &&
fuelVehicleTaskCount + value === taskCount
) {
return Promise.resolve();
}
return Promise.reject(
new Error(
"规则:新能源车任务台数 + 传统燃油车任务台数 = 零售任务台数"
)
);
},
}),
]}
|
eb77f47f
Shinner
增加表单交互
|
236
|
>
|
9d18f86b
Shinner
回退台数交互
|
237
238
239
240
241
242
|
<InputNumber
formatter={(value) => `${value}台`}
parser={(value: any) => value.replace("台", "")}
min={0}
max={MAX_NUM}
style={{ width: "100%" }}
|
9d18f86b
Shinner
回退台数交互
|
243
244
|
precision={0}
/>
|
eb77f47f
Shinner
增加表单交互
|
245
|
</Form.Item>
|
9d18f86b
Shinner
回退台数交互
|
246
|
|
eb77f47f
Shinner
增加表单交互
|
247
|
<Form.Item
|
9d18f86b
Shinner
回退台数交互
|
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
|
name="fuelVehicleTaskCount"
label="传统燃油车任务台数:"
required
dependencies={["taskCount", "newEnergyTaskCount"]}
rules={[
({ getFieldValue }) => ({
validator(_, value) {
const taskCount = getFieldValue("taskCount");
const newEnergyTaskCount =
getFieldValue("newEnergyTaskCount");
if (value >= 0 && newEnergyTaskCount + value === taskCount) {
return Promise.resolve();
}
return Promise.reject(
new Error(
"规则:新能源车任务台数 + 传统燃油车任务台数 = 零售任务台数"
)
);
},
}),
]}
|
eb77f47f
Shinner
增加表单交互
|
269
|
>
|
9d18f86b
Shinner
回退台数交互
|
270
271
272
273
274
275
|
<InputNumber
formatter={(value) => `${value}台`}
parser={(value: any) => value.replace("台", "")}
min={0}
max={MAX_NUM}
style={{ width: "100%" }}
|
9d18f86b
Shinner
回退台数交互
|
276
277
|
precision={0}
/>
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
278
|
</Form.Item>
|
eb77f47f
Shinner
增加表单交互
|
279
280
|
<Form.Item
name="vehicleGrossProfitTask"
|
7c25275f
Shinner
[车辆毛利任务]修改为[单车毛利任务]
|
281
|
label="单车毛利任务:"
|
eb77f47f
Shinner
增加表单交互
|
282
283
|
required
>
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
284
|
<InputNumber
|
22729ea6
Shinner
修复编辑顾问任务分配
|
285
286
|
formatter={(value) => `${value}元`}
parser={(value: any) => value.replace("元", "")}
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
287
|
min={0}
|
1c9bc538
Shinner
修复问题
|
288
|
max={MAX_NUM}
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
289
|
style={{ width: "100%" }}
|
b04b25da
Shinner
车辆毛利任务小数点两位
|
290
|
precision={2}
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
291
292
|
/>
</Form.Item>
|
eb77f47f
Shinner
增加表单交互
|
293
294
295
296
297
|
<Form.Item
name="testDriveTaskCount"
label="首客试驾成交任务台数:"
required
>
|
1aa6dd0a
Shinner
调试零售任务分配接口
|
298
299
300
301
|
<InputNumber
formatter={(value) => `${value}台`}
parser={(value: any) => value.replace("台", "")}
min={0}
|
1c9bc538
Shinner
修复问题
|
302
|
max={MAX_NUM}
|
1aa6dd0a
Shinner
调试零售任务分配接口
|
303
|
style={{ width: "100%" }}
|
1c9bc538
Shinner
修复问题
|
304
|
precision={0}
|
1aa6dd0a
Shinner
调试零售任务分配接口
|
305
306
|
/>
</Form.Item>
|
eb77f47f
Shinner
增加表单交互
|
307
|
<Form.Item name="tackCarTaskCount" label="攻坚车任务台数:" required>
|
1aa6dd0a
Shinner
调试零售任务分配接口
|
308
309
310
311
|
<InputNumber
formatter={(value) => `${value}台`}
parser={(value: any) => value.replace("台", "")}
min={0}
|
1c9bc538
Shinner
修复问题
|
312
|
max={MAX_NUM}
|
1aa6dd0a
Shinner
调试零售任务分配接口
|
313
|
style={{ width: "100%" }}
|
1c9bc538
Shinner
修复问题
|
314
|
precision={0}
|
1aa6dd0a
Shinner
调试零售任务分配接口
|
315
316
|
/>
</Form.Item>
|
eb77f47f
Shinner
增加表单交互
|
317
|
<Form.Item name="seriesTaskCount" label="车系任务台数:" required>
|
4ddb4140
Shinner
调试零售任务分配接口
|
318
319
320
321
|
<InputNumber
formatter={(value) => `${value}台`}
parser={(value: any) => value.replace("台", "")}
min={0}
|
1c9bc538
Shinner
修复问题
|
322
|
max={MAX_NUM}
|
4ddb4140
Shinner
调试零售任务分配接口
|
323
|
style={{ width: "100%" }}
|
1c9bc538
Shinner
修复问题
|
324
|
precision={0}
|
aeeb3492
Shinner
增加预览任务功能
|
325
|
disabled
|
4ddb4140
Shinner
调试零售任务分配接口
|
326
327
|
/>
</Form.Item>
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
328
329
330
331
332
333
334
335
336
337
|
</Form>
</div>
<Divider />
<div style={{ width: 880, margin: "0 auto" }}>
<Row
align="middle"
justify="space-between"
style={{ marginBottom: 20 }}
>
<h2 className={styles.carTask}>车系任务</h2>
|
3b0d1ee6
Shinner
增加零售任务分配菜单静态页面
|
338
339
340
341
342
343
344
345
346
347
348
|
{!isReadOnly && (
<Button
icon={<PlusOutlined />}
type="primary"
onClick={() => {
setSeriesVisible(true);
}}
>
添加车系
</Button>
)}
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
349
|
</Row>
|
a1e7edf3
Shinner
调试零售任务分配接口
|
350
|
<Form form={seriesForm} component={false}>
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
351
352
|
<Table
scroll={{ y: 400 }}
|
a1e7edf3
Shinner
调试零售任务分配接口
|
353
|
rowKey="seriesId"
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
354
355
356
|
rowClassName={() => "editable-cell"}
pagination={false}
components={components}
|
a1e7edf3
Shinner
调试零售任务分配接口
|
357
|
dataSource={[...shopTaskItem?.seriesTaskList!]}
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
358
|
>
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
359
|
<Column
|
3b0d1ee6
Shinner
增加零售任务分配菜单静态页面
|
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
|
title="车系"
dataIndex="seriesName"
render={(value, record: API.SeriesTaskItem) => {
return (
<Row align="middle" justify="start">
<span>{value}</span>
{record.newEnergy && (
<Tag
style={{ marginBottom: 5, marginLeft: 7 }}
color="green"
>
新能源
</Tag>
)}
</Row>
);
}}
/>
<Column
title="零售任务(台)"
|
a1e7edf3
Shinner
调试零售任务分配接口
|
380
381
|
dataIndex="taskCount"
onCell={(record: API.SeriesTaskItem) => ({
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
382
383
|
record,
inputType: "number",
|
a1e7edf3
Shinner
调试零售任务分配接口
|
384
|
dataIndex: "taskCount",
|
3b0d1ee6
Shinner
增加零售任务分配菜单静态页面
|
385
|
title: "零售任务(台)",
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
386
387
388
|
editing: isEditing(record),
})}
/>
|
3b0d1ee6
Shinner
增加零售任务分配菜单静态页面
|
389
390
391
392
|
{!isReadOnly && (
<Column
width={120}
title="操作"
|
a1e7edf3
Shinner
调试零售任务分配接口
|
393
|
render={(text, record: API.SeriesTaskItem) => {
|
3b0d1ee6
Shinner
增加零售任务分配菜单静态页面
|
394
395
396
397
398
|
const editable = isEditing(record);
return (
<div>
{editable ? (
<span>
|
a1e7edf3
Shinner
调试零售任务分配接口
|
399
400
401
|
<a onClick={() => setSeriesRow(record.seriesId)}>
确认
</a>
|
3b0d1ee6
Shinner
增加零售任务分配菜单静态页面
|
402
403
404
405
406
407
408
409
410
|
<Divider type="vertical" />
<a
style={{ color: "#999" }}
onClick={() => setEditingKey(-1)}
>
取消
</a>
</span>
) : (
|
1c9bc538
Shinner
修复问题
|
411
|
<span>
|
a1e7edf3
Shinner
调试零售任务分配接口
|
412
|
<a onClick={() => editSeriesRow(record)}>编辑</a>
|
1c9bc538
Shinner
修复问题
|
413
414
415
|
<Divider type="vertical" />
<a
style={{ color: "#999" }}
|
263b8790
Shinner
优化分配任务前端数据更新逻辑
|
416
|
onClick={() => deleteShopSeriesRow(record.seriesId)}
|
1c9bc538
Shinner
修复问题
|
417
418
419
420
|
>
删除
</a>
</span>
|
3b0d1ee6
Shinner
增加零售任务分配菜单静态页面
|
421
422
423
424
425
426
|
)}
</div>
);
}}
/>
)}
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
427
428
429
|
</Table>
</Form>
</div>
|
1aa6dd0a
Shinner
调试零售任务分配接口
|
430
431
432
433
434
435
436
437
438
439
440
441
|
<Row align="middle" justify="center" style={{ marginTop: 50 }}>
<Button onClick={handleGoBack}>返回列表</Button>
{!isReadOnly && (
<Button
type="primary"
style={{ marginLeft: 10 }}
loading={saveShopSaleTaskHook.loading}
onClick={handleSaveTask}
>
保存草稿
</Button>
)}
|
d8aedefd
Shinner
单个门店支持分配到门店和顾问
|
442
443
444
445
446
447
448
449
450
|
{!isReadOnly && (
<Button
type="primary"
style={{ marginLeft: 10 }}
onClick={autoAssignOneShop}
>
分配到门店和顾问
</Button>
)}
|
1aa6dd0a
Shinner
调试零售任务分配接口
|
451
|
</Row>
|
3b0d1ee6
Shinner
增加零售任务分配菜单静态页面
|
452
453
|
<SeriesModal
visible={seriesVisible}
|
1c9bc538
Shinner
修复问题
|
454
|
selectedIds={selectedIds}
|
3b0d1ee6
Shinner
增加零售任务分配菜单静态页面
|
455
456
457
458
459
|
onOk={handleSelectSeries}
onCancel={() => {
setSeriesVisible(false);
}}
/>
|
4c5bad19
Shinner
预览任务按钮显示与是否审批无关;调整样式
|
460
|
</>
|
32942bc1
Shinner
增加零售任务分配菜单静态页面
|
461
|
);
|
11ea8143
Shinner
调试零售任务分配接口
|
462
|
}
|