Blame view

src/pages/order3/SaleTask/subpages/TaskEdit/components/ShopTask.tsx 13.7 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";
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
  }