Blame view

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