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,6 +109,25 @@ export function submitSaleTask(params: { id: number }): PromiseResp<boolean> {
109 return request.post(`${ORDER3_HOST}/erp/sales/task/submit`, params); 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 export interface BrandItem { 131 export interface BrandItem {
113 id: number; 132 id: number;
114 initial: string; 133 initial: string;
@@ -188,7 +207,9 @@ export interface PreviewTaskRes { @@ -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 return request.get(`${ORDER3_HOST}/erp/sales/task/approve/info`, { 213 return request.get(`${ORDER3_HOST}/erp/sales/task/approve/info`, {
193 params, 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 \ No newline at end of file 5 \ No newline at end of file
src/pages/order3/SaleTask/index.tsx
@@ -15,12 +15,14 @@ import { history } from &quot;umi&quot;; @@ -15,12 +15,14 @@ import { history } from &quot;umi&quot;;
15 import moment, { Moment } from "moment"; 15 import moment, { Moment } from "moment";
16 import useInitial from "@/hooks/useInitail"; 16 import useInitial from "@/hooks/useInitail";
17 import { Provider, useStore } from "./store"; 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 import EntryTaskPreview from "./components/EntryTaskPreview"; 19 import EntryTaskPreview from "./components/EntryTaskPreview";
20 import { OrderTaskApprovalType } from "./entity"; 20 import { OrderTaskApprovalType } from "./entity";
21 import AdviserTaskPreview from "./components/AdviserTaskPreview"; 21 import AdviserTaskPreview from "./components/AdviserTaskPreview";
22 import SeriesTaskPreview from "./components/SeriesTaskPreview"; 22 import SeriesTaskPreview from "./components/SeriesTaskPreview";
23 import ApproveModal from "@/pages/order3/Common/ApproveModal"; 23 import ApproveModal from "@/pages/order3/Common/ApproveModal";
  24 +import SaleTaskAutoAssign from "./components/SaleTaskAutoAssign";
  25 +import SaleTaskBatchSet from "./components/SaleTaskBatchSet";
24 26
25 const { Column } = Table; 27 const { Column } = Table;
26 28
@@ -42,6 +44,9 @@ function SaleTaskList() { @@ -42,6 +44,9 @@ function SaleTaskList() {
42 const [stpVisible, setStpVisible] = useState(false); 44 const [stpVisible, setStpVisible] = useState(false);
43 const [seriesTaskParams, setSeriesTaskParams] = useState({}); 45 const [seriesTaskParams, setSeriesTaskParams] = useState({});
44 46
  47 + const [autoVisible, setAutoVisible] = useState(false);
  48 + const [batchVisible, setBatchVisible] = useState(false);
  49 +
45 const { data, loading, setParams } = useInitial( 50 const { data, loading, setParams } = useInitial(
46 API.getSaleTaskApi, 51 API.getSaleTaskApi,
47 {} as API.GetSaleTaskApiRes, 52 {} as API.GetSaleTaskApiRes,
@@ -71,6 +76,19 @@ function SaleTaskList() { @@ -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 const viewProcess = () => { 93 const viewProcess = () => {
76 setApprove({ 94 setApprove({
@@ -128,26 +146,122 @@ function SaleTaskList() { @@ -128,26 +146,122 @@ function SaleTaskList() {
128 setEtpVisible(true); 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 return ( 225 return (
132 <PageHeaderWrapper title="零售任务分配"> 226 <PageHeaderWrapper title="零售任务分配">
133 <Card> 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 </Row> 265 </Row>
152 <Table 266 <Table
153 rowKey="id" 267 rowKey="id"
@@ -168,34 +282,34 @@ function SaleTaskList() { @@ -168,34 +282,34 @@ function SaleTaskList() {
168 fontWeight: 500, 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 {data.totalTaskCount} 287 {data.totalTaskCount}
176 </Table.Summary.Cell> 288 </Table.Summary.Cell>
177 - <Table.Summary.Cell align="left" index={3}> 289 + <Table.Summary.Cell index={3}>
178 {data.newEnergyTaskCount} 290 {data.newEnergyTaskCount}
179 </Table.Summary.Cell> 291 </Table.Summary.Cell>
180 - <Table.Summary.Cell align="left" index={4}> 292 + <Table.Summary.Cell index={4}>
181 {data.fuelVehicleTaskCount} 293 {data.fuelVehicleTaskCount}
182 </Table.Summary.Cell> 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 {data.vehicleGrossProfitTask} 297 {data.vehicleGrossProfitTask}
185 </Table.Summary.Cell> 298 </Table.Summary.Cell>
186 - <Table.Summary.Cell index={6}> 299 + <Table.Summary.Cell index={7}>
187 {data.clueDealTaskCount} 300 {data.clueDealTaskCount}
188 </Table.Summary.Cell> 301 </Table.Summary.Cell>
189 - <Table.Summary.Cell index={7}> 302 + <Table.Summary.Cell index={8}>
190 {data.testDriveTaskCount} 303 {data.testDriveTaskCount}
191 </Table.Summary.Cell> 304 </Table.Summary.Cell>
192 - <Table.Summary.Cell index={8}> 305 + <Table.Summary.Cell index={9}>
193 {data.tackCarTaskCount} 306 {data.tackCarTaskCount}
194 </Table.Summary.Cell> 307 </Table.Summary.Cell>
195 - <Table.Summary.Cell index={9}> 308 + <Table.Summary.Cell index={10}>
196 {data.seriesTaskCount} 309 {data.seriesTaskCount}
197 </Table.Summary.Cell> 310 </Table.Summary.Cell>
198 - <Table.Summary.Cell index={10} /> 311 + <Table.Summary.Cell index={11} />
  312 + <Table.Summary.Cell index={12} />
199 </Table.Summary.Row> 313 </Table.Summary.Row>
200 </Table.Summary> 314 </Table.Summary>
201 ); 315 );
@@ -205,7 +319,16 @@ function SaleTaskList() { @@ -205,7 +319,16 @@ function SaleTaskList() {
205 <Column title="零售任务(台)" dataIndex="taskCount" /> 319 <Column title="零售任务(台)" dataIndex="taskCount" />
206 <Column title="新能源车任务(台)" dataIndex="newEnergyTaskCount" /> 320 <Column title="新能源车任务(台)" dataIndex="newEnergyTaskCount" />
207 <Column title="传统燃油车任务(台)" dataIndex="fuelVehicleTaskCount" /> 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 <Column title="线索到店零售台数(台)" dataIndex="clueDealTaskCount" /> 332 <Column title="线索到店零售台数(台)" dataIndex="clueDealTaskCount" />
210 <Column 333 <Column
211 title="首客试驾成交任务数(台)" 334 title="首客试驾成交任务数(台)"
@@ -214,6 +337,20 @@ function SaleTaskList() { @@ -214,6 +337,20 @@ function SaleTaskList() {
214 <Column title="攻坚车任务数(台)" dataIndex="tackCarTaskCount" /> 337 <Column title="攻坚车任务数(台)" dataIndex="tackCarTaskCount" />
215 <Column title="车系任务数(台)" dataIndex="seriesTaskCount" /> 338 <Column title="车系任务数(台)" dataIndex="seriesTaskCount" />
216 <Column 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 title="操作" 354 title="操作"
218 render={(text: string, record: API.ShopTaskItem) => { 355 render={(text: string, record: API.ShopTaskItem) => {
219 return ( 356 return (
@@ -291,62 +428,8 @@ function SaleTaskList() { @@ -291,62 +428,8 @@ function SaleTaskList() {
291 </Row> 428 </Row>
292 <EntryTaskPreview 429 <EntryTaskPreview
293 params={previewTaskParams} 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 </Modal> 434 </Modal>
352 <Modal 435 <Modal
@@ -359,14 +442,7 @@ function SaleTaskList() { @@ -359,14 +442,7 @@ function SaleTaskList() {
359 > 442 >
360 <AdviserTaskPreview 443 <AdviserTaskPreview
361 params={adviserTaskParams} 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 </Modal> 447 </Modal>
372 <Modal 448 <Modal
@@ -379,6 +455,36 @@ function SaleTaskList() { @@ -379,6 +455,36 @@ function SaleTaskList() {
379 > 455 >
380 <SeriesTaskPreview params={seriesTaskParams} /> 456 <SeriesTaskPreview params={seriesTaskParams} />
381 </Modal> 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 <ApprovalProgressModal 488 <ApprovalProgressModal
383 visible={approve.visible} 489 visible={approve.visible}
384 orderNo={approve.orderNo} 490 orderNo={approve.orderNo}
src/pages/order3/SaleTask/subpages/TaskEdit/index.tsx
@@ -20,8 +20,9 @@ function TaskEdit() { @@ -20,8 +20,9 @@ function TaskEdit() {
20 const readOnly = querys?.readOnly === "1"; 20 const readOnly = querys?.readOnly === "1";
21 const shopId = querys?.shopId; 21 const shopId = querys?.shopId;
22 const taskDate = querys?.taskDate; 22 const taskDate = querys?.taskDate;
  23 + const queryTab = querys?.currTab;
23 const { shopTaskItem, setShopTaskItem, setIsReadOnly } = useStore(); 24 const { shopTaskItem, setShopTaskItem, setIsReadOnly } = useStore();
24 - const [currStep, setCurrStep] = useState("1"); 25 + const [currTab, setCurrTab] = useState(queryTab ?? "1");
25 const [shopTaskForm] = Form.useForm(); 26 const [shopTaskForm] = Form.useForm();
26 27
27 // 获取门店零售任务详情 28 // 获取门店零售任务详情
@@ -46,8 +47,8 @@ function TaskEdit() { @@ -46,8 +47,8 @@ function TaskEdit() {
46 title={<span>当前选择门店:{shopTaskItem?.shopName}</span>} 47 title={<span>当前选择门店:{shopTaskItem?.shopName}</span>}
47 > 48 >
48 <Tabs 49 <Tabs
49 - defaultActiveKey={currStep}  
50 - onChange={(activeKey) => setCurrStep(activeKey)} 50 + defaultActiveKey={currTab}
  51 + onChange={(activeKey) => setCurrTab(activeKey)}
51 items={[ 52 items={[
52 { 53 {
53 label: `门店任务分配${readOnly ? "详情" : ""}`, 54 label: `门店任务分配${readOnly ? "详情" : ""}`,