Commit bdad4eb5d7ff3f9455e5ed25e8a4802cbfe07e80

Authored by Shinner
1 parent 7c25275f

调试自动分配接口

src/pages/order3/SaleTask/api.ts
... ... @@ -109,6 +109,25 @@ export function submitSaleTask(params: { id: number }): PromiseResp<boolean> {
109 109 return request.post(`${ORDER3_HOST}/erp/sales/task/submit`, params);
110 110 }
111 111  
  112 +export interface AutoAssignItem {
  113 + shopId: number;
  114 + taskCount: number;
  115 + newEnergyTaskCount: number;
  116 + fuelVehicleTaskCount: number;
  117 + tackCarTaskCount: number;
  118 +}
  119 +
  120 +export interface AutoAssignSaleTaskReq {
  121 + id: number;
  122 + assignTask: boolean;
  123 + shopTaskList: AutoAssignItem[];
  124 +}
  125 +
  126 +/** 自动分配零售任务 */
  127 +export function autoAssignSaleTask(params: AutoAssignSaleTaskReq): PromiseResp<boolean> {
  128 + return request.post(`${ORDER3_HOST}/erp/sales/task/auto/assign`, params);
  129 +}
  130 +
112 131 export interface BrandItem {
113 132 id: number;
114 133 initial: string;
... ... @@ -188,7 +207,9 @@ export interface PreviewTaskRes {
188 207 }
189 208  
190 209 /** 预览任务 */
191   -export function previewTask(params: PreviewTaskReq): PromiseResp<PreviewTaskRes> {
  210 +export function previewTask(
  211 + params: PreviewTaskReq
  212 +): PromiseResp<PreviewTaskRes> {
192 213 return request.get(`${ORDER3_HOST}/erp/sales/task/approve/info`, {
193 214 params,
194 215 });
... ...
src/pages/order3/SaleTask/components/SaleTaskAutoAssign.tsx 0 → 100644
  1 +import React, { useContext, useEffect, useRef, useState } from "react";
  2 +import {
  3 + Table,
  4 + Form,
  5 + InputRef,
  6 + Input,
  7 + Row,
  8 + Button,
  9 + message,
  10 + Modal,
  11 + InputNumber,
  12 +} from "antd";
  13 +import type { FormInstance } from "antd/es/form";
  14 +import * as API from "../api";
  15 +import styles from "./index.less";
  16 +import { MAX_NUM } from "../entity";
  17 +
  18 +type EditableTableProps = Parameters<typeof Table>[0];
  19 +type ColumnTypes = Exclude<EditableTableProps["columns"], undefined>;
  20 +interface Item {
  21 + id: string;
  22 + shopName: string;
  23 + taskCount: number;
  24 + newEnergyTaskCount: number;
  25 + fuelVehicleTaskCount: number;
  26 + tackCarTaskCount: number;
  27 +}
  28 +interface EditableRowProps {
  29 + index: number;
  30 +}
  31 +interface EditableCellProps {
  32 + title: React.ReactNode;
  33 + editable: boolean;
  34 + children: React.ReactNode;
  35 + dataIndex: keyof Item;
  36 + record: Item;
  37 + handleSave: (record: Item) => void;
  38 +}
  39 +
  40 +const defaultColumns: (ColumnTypes[number] & {
  41 + editable?: boolean;
  42 + dataIndex: string;
  43 +})[] = [
  44 + {
  45 + title: "门店",
  46 + dataIndex: "shopName",
  47 + editable: false,
  48 + },
  49 + {
  50 + title: "零售任务(台)",
  51 + dataIndex: "taskCount",
  52 + editable: true,
  53 + },
  54 + {
  55 + title: "新能源车任务(台)",
  56 + dataIndex: "newEnergyTaskCount",
  57 + editable: true,
  58 + },
  59 + {
  60 + title: "传统燃油车任务(台)",
  61 + dataIndex: "fuelVehicleTaskCount",
  62 + editable: false,
  63 + },
  64 + {
  65 + title: "攻坚车任务数(台)",
  66 + dataIndex: "tackCarTaskCount",
  67 + editable: true,
  68 + },
  69 +];
  70 +
  71 +interface SaleTaskAutoAssignProps {
  72 + id: number;
  73 + value?: API.ShopTaskItem[];
  74 + onCancel: () => void;
  75 +}
  76 +
  77 +export default function SaleTaskAutoAssign({
  78 + id,
  79 + value,
  80 + onCancel,
  81 +}: SaleTaskAutoAssignProps) {
  82 + const EditableContext = React.createContext<FormInstance<any> | null>(null);
  83 + const [dataSource, setDataSource] = useState<API.ShopTaskItem[]>([]);
  84 +
  85 + useEffect(() => {
  86 + setDataSource(value ? [...value] : []);
  87 + }, [value]);
  88 +
  89 + const EditableRow: React.FC<EditableRowProps> = ({ index, ...props }) => {
  90 + const [form] = Form.useForm();
  91 + return (
  92 + <Form form={form} component={false}>
  93 + <EditableContext.Provider value={form}>
  94 + <tr {...props} />
  95 + </EditableContext.Provider>
  96 + </Form>
  97 + );
  98 + };
  99 +
  100 + const EditableCell: React.FC<EditableCellProps> = ({
  101 + title,
  102 + editable,
  103 + children,
  104 + dataIndex,
  105 + record,
  106 + handleSave,
  107 + ...restProps
  108 + }) => {
  109 + const [editing, setEditing] = useState(false);
  110 + const inputRef = useRef<InputRef>(null);
  111 + const form = useContext(EditableContext)!;
  112 +
  113 + useEffect(() => {
  114 + if (editing) {
  115 + inputRef.current!.focus();
  116 + }
  117 + }, [editing]);
  118 +
  119 + const toggleEdit = () => {
  120 + setEditing(!editing);
  121 + form.setFieldsValue({ [dataIndex]: record[dataIndex] });
  122 + };
  123 +
  124 + const save = async () => {
  125 + try {
  126 + const values = await form.validateFields();
  127 + toggleEdit();
  128 + handleSave({ ...record, ...values });
  129 + } catch (errInfo) {
  130 + console.log("Save failed:", errInfo);
  131 + }
  132 + };
  133 +
  134 + let childNode = children;
  135 +
  136 + if (editable) {
  137 + childNode = editing ? (
  138 + <Form.Item
  139 + noStyle
  140 + name={dataIndex}
  141 + rules={[
  142 + {
  143 + required: true,
  144 + message: `请输入${title}`,
  145 + },
  146 + ]}
  147 + >
  148 + <InputNumber
  149 + ref={inputRef}
  150 + min={0}
  151 + max={MAX_NUM}
  152 + style={{ width: "80px" }}
  153 + onPressEnter={save}
  154 + onBlur={save}
  155 + />
  156 + </Form.Item>
  157 + ) : (
  158 + <div className="editable-cell-value-wrap" onClick={toggleEdit}>
  159 + {children}
  160 + </div>
  161 + );
  162 + }
  163 +
  164 + return <td {...restProps}>{childNode}</td>;
  165 + };
  166 +
  167 + const handleSave = (row: API.ShopTaskItem) => {
  168 + const newData = [...dataSource];
  169 + const index = newData.findIndex((item) => row.id === item.id);
  170 + const item = newData[index];
  171 + if (row.taskCount !== 0 && row.newEnergyTaskCount > row.taskCount) {
  172 + message.warn("新能源车任务台数不得超过零售任务台数");
  173 + return;
  174 + }
  175 + const newRow = {
  176 + ...item,
  177 + ...row,
  178 + fuelVehicleTaskCount: row.taskCount - row.newEnergyTaskCount,
  179 + };
  180 + if (row.taskCount === 0) {
  181 + newRow.taskCount = 0;
  182 + newRow.newEnergyTaskCount = 0;
  183 + newRow.fuelVehicleTaskCount = 0;
  184 + }
  185 + newData.splice(index, 1, newRow);
  186 + console.log("handleSave newData", newData);
  187 + setDataSource(newData);
  188 + };
  189 +
  190 + const autoAssignSaleTask = (isAssignToAdviser: boolean) => {
  191 + Modal.confirm({
  192 + title: isAssignToAdviser
  193 + ? "确认分配到门店和顾问吗?"
  194 + : "确认分配到门店吗?",
  195 + zIndex: 1002,
  196 + onOk: async () => {
  197 + const hide = message.loading("分配中,请稍候", 0);
  198 + API.autoAssignSaleTask({
  199 + id,
  200 + shopTaskList: dataSource.map((item) => ({
  201 + shopId: item.shopId,
  202 + taskCount: item.taskCount,
  203 + newEnergyTaskCount: item.newEnergyTaskCount,
  204 + fuelVehicleTaskCount: item.fuelVehicleTaskCount,
  205 + tackCarTaskCount: item.tackCarTaskCount,
  206 + })),
  207 + assignTask: isAssignToAdviser,
  208 + })
  209 + .then((res) => {
  210 + message.success("分配成功");
  211 + })
  212 + .catch((error: any) => {
  213 + message.error(error.message ?? "请求失败");
  214 + })
  215 + .finally(() => {
  216 + hide();
  217 + });
  218 + },
  219 + });
  220 + };
  221 +
  222 + const components = {
  223 + body: {
  224 + row: EditableRow,
  225 + cell: EditableCell,
  226 + },
  227 + };
  228 +
  229 + const columns = defaultColumns.map((col) => {
  230 + if (!col.editable) {
  231 + return col;
  232 + }
  233 + return {
  234 + ...col,
  235 + onCell: (record: API.ShopTaskItem) => ({
  236 + record,
  237 + editable: col.editable,
  238 + dataIndex: col.dataIndex,
  239 + title: col.title,
  240 + handleSave,
  241 + }),
  242 + };
  243 + });
  244 +
  245 + return (
  246 + <>
  247 + <Table
  248 + components={components}
  249 + rowClassName={() => "editable-row"}
  250 + bordered
  251 + rowKey="id"
  252 + dataSource={dataSource}
  253 + columns={columns as ColumnTypes}
  254 + />
  255 + <Row align="middle" justify="center" style={{ marginTop: 20 }}>
  256 + <Button onClick={onCancel}>取消</Button>
  257 + <Button
  258 + type="primary"
  259 + style={{ marginLeft: 10 }}
  260 + onClick={() => autoAssignSaleTask(false)}
  261 + >
  262 + 分配到门店
  263 + </Button>
  264 + <Button
  265 + type="primary"
  266 + style={{ marginLeft: 10 }}
  267 + onClick={() => autoAssignSaleTask(true)}
  268 + >
  269 + 分配到门店和顾问
  270 + </Button>
  271 + </Row>
  272 + </>
  273 + );
  274 +}
... ...
src/pages/order3/SaleTask/components/SaleTaskBatchSet.tsx 0 → 100644
  1 +import { PlusOutlined } from "@ant-design/icons";
  2 +import { Button, Card, Col, Form, InputNumber, Row, Select } from "antd";
  3 +import styles from "./index.less";
  4 +import React from "react";
  5 +import { MAX_NUM } from "../entity";
  6 +
  7 +export default function SaleTaskBatchSet() {
  8 + const [form] = Form.useForm();
  9 +
  10 + const assignToShop = async () => {
  11 + await form.validateFields();
  12 + const values = form.getFieldsValue();
  13 + console.log(values);
  14 + };
  15 +
  16 + const assignToBoth = async () => {
  17 + await form.validateFields();
  18 + const values = form.getFieldsValue();
  19 + console.log(values);
  20 + };
  21 +
  22 + return (
  23 + <Form form={form} name="sale-task-batch-set-form" autoComplete="off">
  24 + <Form.List name="vehicleGrossProfitTask">
  25 + {(fields, { add, remove }) => (
  26 + <Card>
  27 + <Row
  28 + align="middle"
  29 + justify="space-between"
  30 + style={{ marginBottom: 15 }}
  31 + >
  32 + <h4 className={styles.title}>单车毛利任务</h4>
  33 + <Button type="link" onClick={() => add()} icon={<PlusOutlined />}>
  34 + 新增
  35 + </Button>
  36 + </Row>
  37 + {fields.map(({ key, name, ...restField }) => (
  38 + <Row gutter={16} key={key}>
  39 + <Col className="gutter-row" span={6}>
  40 + <Form.Item
  41 + {...restField}
  42 + name={[name, "vehicleGrossProfitTask"]}
  43 + rules={[{ required: true, message: "请填写单车毛利任务" }]}
  44 + >
  45 + <InputNumber
  46 + formatter={(value) => `${value}元`}
  47 + parser={(value: any) => value.replace("元", "")}
  48 + min={0}
  49 + max={MAX_NUM}
  50 + style={{ width: "100%" }}
  51 + precision={2}
  52 + placeholder="请填写单车毛利任务"
  53 + />
  54 + </Form.Item>
  55 + </Col>
  56 + <Col className="gutter-row" span={15}>
  57 + <Form.Item
  58 + {...restField}
  59 + name={[name, "shop"]}
  60 + rules={[{ required: true, message: "请选择适用门店" }]}
  61 + >
  62 + <Select
  63 + showSearch
  64 + allowClear
  65 + labelInValue
  66 + loading={false}
  67 + placeholder="请选择适用门店"
  68 + style={{ width: "100%" }}
  69 + fieldNames={{ value: "id", label: "name" }}
  70 + options={[]}
  71 + />
  72 + </Form.Item>
  73 + </Col>
  74 + <Col className="gutter-row" span={3}>
  75 + <Button
  76 + type="link"
  77 + style={{ color: "#999" }}
  78 + onClick={() => remove(name)}
  79 + >
  80 + 删除
  81 + </Button>
  82 + </Col>
  83 + </Row>
  84 + ))}
  85 + </Card>
  86 + )}
  87 + </Form.List>
  88 + <Form.List name="testDriveTaskCount">
  89 + {(fields, { add, remove }) => (
  90 + <Card style={{ marginTop: 20 }}>
  91 + <Row
  92 + align="middle"
  93 + justify="space-between"
  94 + style={{ marginBottom: 15 }}
  95 + >
  96 + <h4 className={styles.title}>首客试驾成交</h4>
  97 + <Button type="link" onClick={() => add()} icon={<PlusOutlined />}>
  98 + 新增
  99 + </Button>
  100 + </Row>
  101 + {fields.map(({ key, name, ...restField }) => (
  102 + <Row gutter={16} key={key}>
  103 + <Col className="gutter-row" span={6}>
  104 + <Form.Item
  105 + {...restField}
  106 + name={[name, "testDriveTaskCount"]}
  107 + rules={[{ required: true, message: "请填写首客试驾成交" }]}
  108 + >
  109 + <InputNumber
  110 + formatter={(value) => `${value}台`}
  111 + parser={(value: any) => value.replace("台", "")}
  112 + min={0}
  113 + max={MAX_NUM}
  114 + style={{ width: "100%" }}
  115 + precision={0}
  116 + placeholder="请填写首客试驾成交"
  117 + />
  118 + </Form.Item>
  119 + </Col>
  120 + <Col className="gutter-row" span={15}>
  121 + <Form.Item
  122 + {...restField}
  123 + name={[name, "shop"]}
  124 + rules={[{ required: true, message: "请选择适用门店" }]}
  125 + >
  126 + <Select
  127 + showSearch
  128 + allowClear
  129 + labelInValue
  130 + loading={false}
  131 + placeholder="请选择适用门店"
  132 + style={{ width: "100%" }}
  133 + fieldNames={{ value: "id", label: "name" }}
  134 + options={[]}
  135 + />
  136 + </Form.Item>
  137 + </Col>
  138 + <Col className="gutter-row" span={3}>
  139 + <Button
  140 + type="link"
  141 + style={{ color: "#999" }}
  142 + onClick={() => remove(name)}
  143 + >
  144 + 删除
  145 + </Button>
  146 + </Col>
  147 + </Row>
  148 + ))}
  149 + </Card>
  150 + )}
  151 + </Form.List>
  152 + <Form.List name="tackCarTaskCount">
  153 + {(fields, { add, remove }) => (
  154 + <Card style={{ marginTop: 20 }}>
  155 + <Row
  156 + align="middle"
  157 + justify="space-between"
  158 + style={{ marginBottom: 15 }}
  159 + >
  160 + <h4 className={styles.title}>攻坚车任务</h4>
  161 + <Button type="link" onClick={() => add()} icon={<PlusOutlined />}>
  162 + 新增
  163 + </Button>
  164 + </Row>
  165 + {fields.map(({ key, name, ...restField }) => (
  166 + <Row gutter={16} key={key}>
  167 + <Col className="gutter-row" span={6}>
  168 + <Form.Item
  169 + {...restField}
  170 + name={[name, "tackCarTaskCount"]}
  171 + rules={[{ required: true, message: "请填写攻坚车任务" }]}
  172 + >
  173 + <InputNumber
  174 + formatter={(value) => `${value}台`}
  175 + parser={(value: any) => value.replace("台", "")}
  176 + min={0}
  177 + max={MAX_NUM}
  178 + style={{ width: "100%" }}
  179 + precision={0}
  180 + placeholder="请填写攻坚车任务"
  181 + />
  182 + </Form.Item>
  183 + </Col>
  184 + <Col className="gutter-row" span={15}>
  185 + <Form.Item
  186 + {...restField}
  187 + name={[name, "shop"]}
  188 + rules={[{ required: true, message: "请选择适用门店" }]}
  189 + >
  190 + <Select
  191 + showSearch
  192 + allowClear
  193 + labelInValue
  194 + loading={false}
  195 + placeholder="请选择适用门店"
  196 + style={{ width: "100%" }}
  197 + fieldNames={{ value: "id", label: "name" }}
  198 + options={[]}
  199 + />
  200 + </Form.Item>
  201 + </Col>
  202 + <Col className="gutter-row" span={3}>
  203 + <Button
  204 + type="link"
  205 + style={{ color: "#999" }}
  206 + onClick={() => remove(name)}
  207 + >
  208 + 删除
  209 + </Button>
  210 + </Col>
  211 + </Row>
  212 + ))}
  213 + </Card>
  214 + )}
  215 + </Form.List>
  216 + <Row align="middle" justify="center" style={{ marginTop: 20 }}>
  217 + <Button onClick={() => {}}>取消</Button>
  218 + <Button
  219 + type="primary"
  220 + style={{ marginLeft: 10 }}
  221 + onClick={assignToShop}
  222 + >
  223 + 分配到门店
  224 + </Button>
  225 + <Button
  226 + type="primary"
  227 + style={{ marginLeft: 10 }}
  228 + onClick={assignToBoth}
  229 + >
  230 + 分配到门店和顾问
  231 + </Button>
  232 + </Row>
  233 + </Form>
  234 + );
  235 +}
... ...
src/pages/order3/SaleTask/components/index.less 0 → 100644
  1 +.editable-row:hover .editableCellValueWrap {
  2 + // box-shadow: 0 0 0 1px #d9d9d9;
  3 + background-color: #eee;
  4 +}
0 5 \ No newline at end of file
... ...
src/pages/order3/SaleTask/index.tsx
... ... @@ -15,12 +15,14 @@ import { history } from &quot;umi&quot;;
15 15 import moment, { Moment } from "moment";
16 16 import useInitial from "@/hooks/useInitail";
17 17 import { Provider, useStore } from "./store";
18   -import { default as ApprovalProgressModal } from "@/pages/stock/AdvanceProgress/components/ApproveModal";
  18 +import ApprovalProgressModal from "@/pages/stock/AdvanceProgress/components/ApproveModal";
19 19 import EntryTaskPreview from "./components/EntryTaskPreview";
20 20 import { OrderTaskApprovalType } from "./entity";
21 21 import AdviserTaskPreview from "./components/AdviserTaskPreview";
22 22 import SeriesTaskPreview from "./components/SeriesTaskPreview";
23 23 import ApproveModal from "@/pages/order3/Common/ApproveModal";
  24 +import SaleTaskAutoAssign from "./components/SaleTaskAutoAssign";
  25 +import SaleTaskBatchSet from "./components/SaleTaskBatchSet";
24 26  
25 27 const { Column } = Table;
26 28  
... ... @@ -42,6 +44,9 @@ function SaleTaskList() {
42 44 const [stpVisible, setStpVisible] = useState(false);
43 45 const [seriesTaskParams, setSeriesTaskParams] = useState({});
44 46  
  47 + const [autoVisible, setAutoVisible] = useState(false);
  48 + const [batchVisible, setBatchVisible] = useState(false);
  49 +
45 50 const { data, loading, setParams } = useInitial(
46 51 API.getSaleTaskApi,
47 52 {} as API.GetSaleTaskApiRes,
... ... @@ -71,6 +76,19 @@ function SaleTaskList() {
71 76 });
72 77 };
73 78  
  79 + // 查看销顾任务
  80 + const goToAdviserPage = (record: API.ShopTaskItem) => {
  81 + history.push({
  82 + pathname: "/order3/saleTask/edit",
  83 + query: {
  84 + readOnly: isReadOnly ? "1" : "0",
  85 + shopId: String(record.shopId),
  86 + taskDate: String(targetMonth.valueOf()),
  87 + currTab: "2",
  88 + },
  89 + });
  90 + };
  91 +
74 92 // 查看流程进度
75 93 const viewProcess = () => {
76 94 setApprove({
... ... @@ -128,26 +146,122 @@ function SaleTaskList() {
128 146 setEtpVisible(true);
129 147 };
130 148  
  149 + // 销顾任务
  150 + const showAdviserModal = (
  151 + record: API.TaskListItem,
  152 + type: OrderTaskApprovalType
  153 + ) => {
  154 + const params: any = {
  155 + id: data.id,
  156 + taskId: record.id,
  157 + orderTaskApprovalType: OrderTaskApprovalType.门店维度, // 只有门店有查看销顾任务
  158 + };
  159 + switch (type) {
  160 + case OrderTaskApprovalType.门店维度:
  161 + params.shopId = record.dataId;
  162 + break;
  163 + case OrderTaskApprovalType.销售顾问维度:
  164 + params.staffId = record.dataId;
  165 + break;
  166 + case OrderTaskApprovalType.新车一级管理维度:
  167 + params.firstManageId = record.dataId;
  168 + break;
  169 + case OrderTaskApprovalType.新车二级管理维度:
  170 + params.secondManageId = record.dataId;
  171 + break;
  172 + case OrderTaskApprovalType.新车三级管理维度:
  173 + params.thirdManageId = record.dataId;
  174 + break;
  175 + default:
  176 + break;
  177 + }
  178 + setAdviserTaskParams(params);
  179 + setAtpVisible(true);
  180 + };
  181 +
  182 + // 销顾任务--查看车系任务
  183 + const showSeriesModalByAdviser = (record: API.TaskListItem) => {
  184 + const params = { ...adviserTaskParams } as any;
  185 + params.taskId = record.id;
  186 + params.orderTaskApprovalType = OrderTaskApprovalType.车系;
  187 + params.staffId = record.dataId;
  188 + setSeriesTaskParams(params);
  189 + setStpVisible(true);
  190 + };
  191 +
  192 + // 车系任务
  193 + const showSeriesModal = (
  194 + record: API.TaskListItem,
  195 + type: OrderTaskApprovalType
  196 + ) => {
  197 + const params: any = {
  198 + id: data.id,
  199 + taskId: record.id,
  200 + orderTaskApprovalType: OrderTaskApprovalType.车系,
  201 + };
  202 + switch (type) {
  203 + case OrderTaskApprovalType.门店维度:
  204 + params.shopId = record.dataId;
  205 + break;
  206 + case OrderTaskApprovalType.销售顾问维度:
  207 + params.staffId = record.dataId;
  208 + break;
  209 + case OrderTaskApprovalType.新车一级管理维度:
  210 + params.firstManageId = record.dataId;
  211 + break;
  212 + case OrderTaskApprovalType.新车二级管理维度:
  213 + params.secondManageId = record.dataId;
  214 + break;
  215 + case OrderTaskApprovalType.新车三级管理维度:
  216 + params.thirdManageId = record.dataId;
  217 + break;
  218 + default:
  219 + break;
  220 + }
  221 + setSeriesTaskParams(params);
  222 + setStpVisible(true);
  223 + };
  224 +
131 225 return (
132 226 <PageHeaderWrapper title="零售任务分配">
133 227 <Card>
134   - <Row align="middle" justify="start" style={{ marginBottom: 20 }}>
135   - <DatePicker
136   - placeholder="月度"
137   - style={{ width: 260 }}
138   - picker="month"
139   - value={targetMonth}
140   - onChange={handleChangeMonth}
141   - allowClear={false}
142   - />
143   - <Input.Search
144   - allowClear
145   - placeholder="门店名称"
146   - style={{ width: 260, marginLeft: 15 }}
147   - onSearch={(v) => {
148   - setParams({ shopName: v }, true);
149   - }}
150   - />
  228 + <Row
  229 + align="middle"
  230 + justify="space-between"
  231 + style={{ marginBottom: 20 }}
  232 + >
  233 + <Row align="middle" justify="start" style={{ marginBottom: 20 }}>
  234 + <DatePicker
  235 + placeholder="月度"
  236 + style={{ width: 260 }}
  237 + picker="month"
  238 + value={targetMonth}
  239 + onChange={handleChangeMonth}
  240 + allowClear={false}
  241 + />
  242 + <Input.Search
  243 + allowClear
  244 + placeholder="门店名称"
  245 + style={{ width: 260, marginLeft: 15 }}
  246 + onSearch={(v) => {
  247 + setParams({ shopName: v }, true);
  248 + }}
  249 + />
  250 + </Row>
  251 + {!isReadOnly && (
  252 + <Row align="middle" justify="start" style={{ marginBottom: 20 }}>
  253 + <Button type="primary" onClick={() => setAutoVisible(true)}>
  254 + 零售任务快捷分配
  255 + </Button>
  256 + <Button
  257 + type="primary"
  258 + style={{ marginLeft: 10 }}
  259 + onClick={() => setBatchVisible(true)}
  260 + >
  261 + 批量设置
  262 + </Button>
  263 + </Row>
  264 + )}
151 265 </Row>
152 266 <Table
153 267 rowKey="id"
... ... @@ -168,34 +282,34 @@ function SaleTaskList() {
168 282 fontWeight: 500,
169 283 }}
170 284 >
171   - <Table.Summary.Cell align="left" index={1}>
172   - 合计
173   - </Table.Summary.Cell>
174   - <Table.Summary.Cell align="left" index={2}>
  285 + <Table.Summary.Cell index={1}>合计</Table.Summary.Cell>
  286 + <Table.Summary.Cell index={2}>
175 287 {data.totalTaskCount}
176 288 </Table.Summary.Cell>
177   - <Table.Summary.Cell align="left" index={3}>
  289 + <Table.Summary.Cell index={3}>
178 290 {data.newEnergyTaskCount}
179 291 </Table.Summary.Cell>
180   - <Table.Summary.Cell align="left" index={4}>
  292 + <Table.Summary.Cell index={4}>
181 293 {data.fuelVehicleTaskCount}
182 294 </Table.Summary.Cell>
183   - <Table.Summary.Cell align="left" index={5}>
  295 + <Table.Summary.Cell index={5} />
  296 + <Table.Summary.Cell index={6}>
184 297 {data.vehicleGrossProfitTask}
185 298 </Table.Summary.Cell>
186   - <Table.Summary.Cell index={6}>
  299 + <Table.Summary.Cell index={7}>
187 300 {data.clueDealTaskCount}
188 301 </Table.Summary.Cell>
189   - <Table.Summary.Cell index={7}>
  302 + <Table.Summary.Cell index={8}>
190 303 {data.testDriveTaskCount}
191 304 </Table.Summary.Cell>
192   - <Table.Summary.Cell index={8}>
  305 + <Table.Summary.Cell index={9}>
193 306 {data.tackCarTaskCount}
194 307 </Table.Summary.Cell>
195   - <Table.Summary.Cell index={9}>
  308 + <Table.Summary.Cell index={10}>
196 309 {data.seriesTaskCount}
197 310 </Table.Summary.Cell>
198   - <Table.Summary.Cell index={10} />
  311 + <Table.Summary.Cell index={11} />
  312 + <Table.Summary.Cell index={12} />
199 313 </Table.Summary.Row>
200 314 </Table.Summary>
201 315 );
... ... @@ -205,7 +319,16 @@ function SaleTaskList() {
205 319 <Column title="零售任务(台)" dataIndex="taskCount" />
206 320 <Column title="新能源车任务(台)" dataIndex="newEnergyTaskCount" />
207 321 <Column title="传统燃油车任务(台)" dataIndex="fuelVehicleTaskCount" />
208   - <Column title="车辆毛利任务(元)" dataIndex="vehicleGrossProfitTask" />
  322 + <Column title="单车毛利任务(元)" dataIndex="vehicleGrossProfitTask" />
  323 + <Column
  324 + title="合计(元)"
  325 + dataIndex="total"
  326 + render={(text: string, record: API.ShopTaskItem) => {
  327 + return (record.taskCount * record.vehicleGrossProfitTask).toFixed(
  328 + 2
  329 + );
  330 + }}
  331 + />
209 332 <Column title="线索到店零售台数(台)" dataIndex="clueDealTaskCount" />
210 333 <Column
211 334 title="首客试驾成交任务数(台)"
... ... @@ -214,6 +337,20 @@ function SaleTaskList() {
214 337 <Column title="攻坚车任务数(台)" dataIndex="tackCarTaskCount" />
215 338 <Column title="车系任务数(台)" dataIndex="seriesTaskCount" />
216 339 <Column
  340 + title="销顾任务"
  341 + render={(text: string, record: API.ShopTaskItem) => {
  342 + return (
  343 + <a
  344 + onClick={() => {
  345 + goToAdviserPage(record);
  346 + }}
  347 + >
  348 + 查看
  349 + </a>
  350 + );
  351 + }}
  352 + />
  353 + <Column
217 354 title="操作"
218 355 render={(text: string, record: API.ShopTaskItem) => {
219 356 return (
... ... @@ -291,62 +428,8 @@ function SaleTaskList() {
291 428 </Row>
292 429 <EntryTaskPreview
293 430 params={previewTaskParams}
294   - showAdviserModal={(record, type) => {
295   - const params: any = {
296   - id: data.id,
297   - taskId: record.id,
298   - orderTaskApprovalType: OrderTaskApprovalType.门店维度, // 只有门店有查看销顾任务
299   - };
300   - switch (type) {
301   - case OrderTaskApprovalType.门店维度:
302   - params.shopId = record.dataId;
303   - break;
304   - case OrderTaskApprovalType.销售顾问维度:
305   - params.staffId = record.dataId;
306   - break;
307   - case OrderTaskApprovalType.新车一级管理维度:
308   - params.firstManageId = record.dataId;
309   - break;
310   - case OrderTaskApprovalType.新车二级管理维度:
311   - params.secondManageId = record.dataId;
312   - break;
313   - case OrderTaskApprovalType.新车三级管理维度:
314   - params.thirdManageId = record.dataId;
315   - break;
316   - default:
317   - break;
318   - }
319   - setAdviserTaskParams(params);
320   - setAtpVisible(true);
321   - }}
322   - showSeriesModal={(record, type) => {
323   - const params: any = {
324   - id: data.id,
325   - taskId: record.id,
326   - orderTaskApprovalType: OrderTaskApprovalType.车系,
327   - };
328   - switch (type) {
329   - case OrderTaskApprovalType.门店维度:
330   - params.shopId = record.dataId;
331   - break;
332   - case OrderTaskApprovalType.销售顾问维度:
333   - params.staffId = record.dataId;
334   - break;
335   - case OrderTaskApprovalType.新车一级管理维度:
336   - params.firstManageId = record.dataId;
337   - break;
338   - case OrderTaskApprovalType.新车二级管理维度:
339   - params.secondManageId = record.dataId;
340   - break;
341   - case OrderTaskApprovalType.新车三级管理维度:
342   - params.thirdManageId = record.dataId;
343   - break;
344   - default:
345   - break;
346   - }
347   - setSeriesTaskParams(params);
348   - setStpVisible(true);
349   - }}
  431 + showAdviserModal={showAdviserModal}
  432 + showSeriesModal={showSeriesModal}
350 433 />
351 434 </Modal>
352 435 <Modal
... ... @@ -359,14 +442,7 @@ function SaleTaskList() {
359 442 >
360 443 <AdviserTaskPreview
361 444 params={adviserTaskParams}
362   - showSeriesModal={(record) => {
363   - const params = { ...adviserTaskParams } as any;
364   - params.taskId = record.id;
365   - params.orderTaskApprovalType = OrderTaskApprovalType.车系;
366   - params.staffId = record.dataId;
367   - setSeriesTaskParams(params);
368   - setStpVisible(true);
369   - }}
  445 + showSeriesModal={showSeriesModalByAdviser}
370 446 />
371 447 </Modal>
372 448 <Modal
... ... @@ -379,6 +455,36 @@ function SaleTaskList() {
379 455 >
380 456 <SeriesTaskPreview params={seriesTaskParams} />
381 457 </Modal>
  458 + <Modal
  459 + width={800}
  460 + title="零售任务快捷分配"
  461 + open={autoVisible}
  462 + onCancel={() => {
  463 + setAutoVisible(false);
  464 + setParams({}, true);
  465 + }}
  466 + destroyOnClose
  467 + footer={null}
  468 + >
  469 + <SaleTaskAutoAssign
  470 + id={data.id}
  471 + value={data.shopTaskList}
  472 + onCancel={() => {
  473 + setAutoVisible(false);
  474 + setParams({}, true);
  475 + }}
  476 + />
  477 + </Modal>
  478 + <Modal
  479 + width={800}
  480 + title="批量设置"
  481 + open={batchVisible}
  482 + onCancel={() => setBatchVisible(false)}
  483 + destroyOnClose
  484 + footer={null}
  485 + >
  486 + <SaleTaskBatchSet />
  487 + </Modal>
382 488 <ApprovalProgressModal
383 489 visible={approve.visible}
384 490 orderNo={approve.orderNo}
... ...
src/pages/order3/SaleTask/subpages/TaskEdit/index.tsx
... ... @@ -20,8 +20,9 @@ function TaskEdit() {
20 20 const readOnly = querys?.readOnly === "1";
21 21 const shopId = querys?.shopId;
22 22 const taskDate = querys?.taskDate;
  23 + const queryTab = querys?.currTab;
23 24 const { shopTaskItem, setShopTaskItem, setIsReadOnly } = useStore();
24   - const [currStep, setCurrStep] = useState("1");
  25 + const [currTab, setCurrTab] = useState(queryTab ?? "1");
25 26 const [shopTaskForm] = Form.useForm();
26 27  
27 28 // 获取门店零售任务详情
... ... @@ -46,8 +47,8 @@ function TaskEdit() {
46 47 title={<span>当前选择门店:{shopTaskItem?.shopName}</span>}
47 48 >
48 49 <Tabs
49   - defaultActiveKey={currStep}
50   - onChange={(activeKey) => setCurrStep(activeKey)}
  50 + defaultActiveKey={currTab}
  51 + onChange={(activeKey) => setCurrTab(activeKey)}
51 52 items={[
52 53 {
53 54 label: `门店任务分配${readOnly ? "详情" : ""}`,
... ...