From bdad4eb5d7ff3f9455e5ed25e8a4802cbfe07e80 Mon Sep 17 00:00:00 2001 From: Shinner Date: Mon, 22 May 2023 18:06:06 +0800 Subject: [PATCH] 调试自动分配接口 --- src/pages/order3/SaleTask/api.ts | 23 ++++++++++++++++++++++- src/pages/order3/SaleTask/components/SaleTaskAutoAssign.tsx | 274 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/pages/order3/SaleTask/components/SaleTaskBatchSet.tsx | 235 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/pages/order3/SaleTask/components/index.less | 4 ++++ src/pages/order3/SaleTask/index.tsx | 296 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------------------------------------------------------------------------- src/pages/order3/SaleTask/subpages/TaskEdit/index.tsx | 7 ++++--- 6 files changed, 740 insertions(+), 99 deletions(-) create mode 100644 src/pages/order3/SaleTask/components/SaleTaskAutoAssign.tsx create mode 100644 src/pages/order3/SaleTask/components/SaleTaskBatchSet.tsx create mode 100644 src/pages/order3/SaleTask/components/index.less diff --git a/src/pages/order3/SaleTask/api.ts b/src/pages/order3/SaleTask/api.ts index 6585a71..6c3b985 100644 --- a/src/pages/order3/SaleTask/api.ts +++ b/src/pages/order3/SaleTask/api.ts @@ -109,6 +109,25 @@ export function submitSaleTask(params: { id: number }): PromiseResp { return request.post(`${ORDER3_HOST}/erp/sales/task/submit`, params); } +export interface AutoAssignItem { + shopId: number; + taskCount: number; + newEnergyTaskCount: number; + fuelVehicleTaskCount: number; + tackCarTaskCount: number; +} + +export interface AutoAssignSaleTaskReq { + id: number; + assignTask: boolean; + shopTaskList: AutoAssignItem[]; +} + +/** 自动分配零售任务 */ +export function autoAssignSaleTask(params: AutoAssignSaleTaskReq): PromiseResp { + return request.post(`${ORDER3_HOST}/erp/sales/task/auto/assign`, params); +} + export interface BrandItem { id: number; initial: string; @@ -188,7 +207,9 @@ export interface PreviewTaskRes { } /** 预览任务 */ -export function previewTask(params: PreviewTaskReq): PromiseResp { +export function previewTask( + params: PreviewTaskReq +): PromiseResp { return request.get(`${ORDER3_HOST}/erp/sales/task/approve/info`, { params, }); diff --git a/src/pages/order3/SaleTask/components/SaleTaskAutoAssign.tsx b/src/pages/order3/SaleTask/components/SaleTaskAutoAssign.tsx new file mode 100644 index 0000000..72b27cc --- /dev/null +++ b/src/pages/order3/SaleTask/components/SaleTaskAutoAssign.tsx @@ -0,0 +1,274 @@ +import React, { useContext, useEffect, useRef, useState } from "react"; +import { + Table, + Form, + InputRef, + Input, + Row, + Button, + message, + Modal, + InputNumber, +} from "antd"; +import type { FormInstance } from "antd/es/form"; +import * as API from "../api"; +import styles from "./index.less"; +import { MAX_NUM } from "../entity"; + +type EditableTableProps = Parameters[0]; +type ColumnTypes = Exclude; +interface Item { + id: string; + shopName: string; + taskCount: number; + newEnergyTaskCount: number; + fuelVehicleTaskCount: number; + tackCarTaskCount: number; +} +interface EditableRowProps { + index: number; +} +interface EditableCellProps { + title: React.ReactNode; + editable: boolean; + children: React.ReactNode; + dataIndex: keyof Item; + record: Item; + handleSave: (record: Item) => void; +} + +const defaultColumns: (ColumnTypes[number] & { + editable?: boolean; + dataIndex: string; +})[] = [ + { + title: "门店", + dataIndex: "shopName", + editable: false, + }, + { + title: "零售任务(台)", + dataIndex: "taskCount", + editable: true, + }, + { + title: "新能源车任务(台)", + dataIndex: "newEnergyTaskCount", + editable: true, + }, + { + title: "传统燃油车任务(台)", + dataIndex: "fuelVehicleTaskCount", + editable: false, + }, + { + title: "攻坚车任务数(台)", + dataIndex: "tackCarTaskCount", + editable: true, + }, +]; + +interface SaleTaskAutoAssignProps { + id: number; + value?: API.ShopTaskItem[]; + onCancel: () => void; +} + +export default function SaleTaskAutoAssign({ + id, + value, + onCancel, +}: SaleTaskAutoAssignProps) { + const EditableContext = React.createContext | null>(null); + const [dataSource, setDataSource] = useState([]); + + useEffect(() => { + setDataSource(value ? [...value] : []); + }, [value]); + + const EditableRow: React.FC = ({ index, ...props }) => { + const [form] = Form.useForm(); + return ( +
+ + + +
+ ); + }; + + const EditableCell: React.FC = ({ + title, + editable, + children, + dataIndex, + record, + handleSave, + ...restProps + }) => { + const [editing, setEditing] = useState(false); + const inputRef = useRef(null); + const form = useContext(EditableContext)!; + + useEffect(() => { + if (editing) { + inputRef.current!.focus(); + } + }, [editing]); + + const toggleEdit = () => { + setEditing(!editing); + form.setFieldsValue({ [dataIndex]: record[dataIndex] }); + }; + + const save = async () => { + try { + const values = await form.validateFields(); + toggleEdit(); + handleSave({ ...record, ...values }); + } catch (errInfo) { + console.log("Save failed:", errInfo); + } + }; + + let childNode = children; + + if (editable) { + childNode = editing ? ( + + + + ) : ( +
+ {children} +
+ ); + } + + return {childNode}; + }; + + const handleSave = (row: API.ShopTaskItem) => { + const newData = [...dataSource]; + const index = newData.findIndex((item) => row.id === item.id); + const item = newData[index]; + if (row.taskCount !== 0 && row.newEnergyTaskCount > row.taskCount) { + message.warn("新能源车任务台数不得超过零售任务台数"); + return; + } + const newRow = { + ...item, + ...row, + fuelVehicleTaskCount: row.taskCount - row.newEnergyTaskCount, + }; + if (row.taskCount === 0) { + newRow.taskCount = 0; + newRow.newEnergyTaskCount = 0; + newRow.fuelVehicleTaskCount = 0; + } + newData.splice(index, 1, newRow); + console.log("handleSave newData", newData); + setDataSource(newData); + }; + + const autoAssignSaleTask = (isAssignToAdviser: boolean) => { + Modal.confirm({ + title: isAssignToAdviser + ? "确认分配到门店和顾问吗?" + : "确认分配到门店吗?", + zIndex: 1002, + onOk: async () => { + const hide = message.loading("分配中,请稍候", 0); + API.autoAssignSaleTask({ + id, + shopTaskList: dataSource.map((item) => ({ + shopId: item.shopId, + taskCount: item.taskCount, + newEnergyTaskCount: item.newEnergyTaskCount, + fuelVehicleTaskCount: item.fuelVehicleTaskCount, + tackCarTaskCount: item.tackCarTaskCount, + })), + assignTask: isAssignToAdviser, + }) + .then((res) => { + message.success("分配成功"); + }) + .catch((error: any) => { + message.error(error.message ?? "请求失败"); + }) + .finally(() => { + hide(); + }); + }, + }); + }; + + const components = { + body: { + row: EditableRow, + cell: EditableCell, + }, + }; + + const columns = defaultColumns.map((col) => { + if (!col.editable) { + return col; + } + return { + ...col, + onCell: (record: API.ShopTaskItem) => ({ + record, + editable: col.editable, + dataIndex: col.dataIndex, + title: col.title, + handleSave, + }), + }; + }); + + return ( + <> + "editable-row"} + bordered + rowKey="id" + dataSource={dataSource} + columns={columns as ColumnTypes} + /> + + + + + + + ); +} diff --git a/src/pages/order3/SaleTask/components/SaleTaskBatchSet.tsx b/src/pages/order3/SaleTask/components/SaleTaskBatchSet.tsx new file mode 100644 index 0000000..90e73a0 --- /dev/null +++ b/src/pages/order3/SaleTask/components/SaleTaskBatchSet.tsx @@ -0,0 +1,235 @@ +import { PlusOutlined } from "@ant-design/icons"; +import { Button, Card, Col, Form, InputNumber, Row, Select } from "antd"; +import styles from "./index.less"; +import React from "react"; +import { MAX_NUM } from "../entity"; + +export default function SaleTaskBatchSet() { + const [form] = Form.useForm(); + + const assignToShop = async () => { + await form.validateFields(); + const values = form.getFieldsValue(); + console.log(values); + }; + + const assignToBoth = async () => { + await form.validateFields(); + const values = form.getFieldsValue(); + console.log(values); + }; + + return ( + + + {(fields, { add, remove }) => ( + + +

单车毛利任务

+ +
+ {fields.map(({ key, name, ...restField }) => ( + +
+ + `${value}元`} + parser={(value: any) => value.replace("元", "")} + min={0} + max={MAX_NUM} + style={{ width: "100%" }} + precision={2} + placeholder="请填写单车毛利任务" + /> + + + + + + + + + + + + ))} + + )} + + + {(fields, { add, remove }) => ( + + +

攻坚车任务

+ +
+ {fields.map(({ key, name, ...restField }) => ( + +
+ + `${value}台`} + parser={(value: any) => value.replace("台", "")} + min={0} + max={MAX_NUM} + style={{ width: "100%" }} + precision={0} + placeholder="请填写攻坚车任务" + /> + + + + +
- - 合计 - - + 合计 + {data.totalTaskCount} - + {data.newEnergyTaskCount} - + {data.fuelVehicleTaskCount} - + + {data.vehicleGrossProfitTask} - + {data.clueDealTaskCount} - + {data.testDriveTaskCount} - + {data.tackCarTaskCount} - + {data.seriesTaskCount} - + + ); @@ -205,7 +319,16 @@ function SaleTaskList() { - + + { + return (record.taskCount * record.vehicleGrossProfitTask).toFixed( + 2 + ); + }} + /> { + return ( + { + goToAdviserPage(record); + }} + > + 查看 + + ); + }} + /> + { return ( @@ -291,62 +428,8 @@ function SaleTaskList() { { - const params: any = { - id: data.id, - taskId: record.id, - orderTaskApprovalType: OrderTaskApprovalType.门店维度, // 只有门店有查看销顾任务 - }; - switch (type) { - case OrderTaskApprovalType.门店维度: - params.shopId = record.dataId; - break; - case OrderTaskApprovalType.销售顾问维度: - params.staffId = record.dataId; - break; - case OrderTaskApprovalType.新车一级管理维度: - params.firstManageId = record.dataId; - break; - case OrderTaskApprovalType.新车二级管理维度: - params.secondManageId = record.dataId; - break; - case OrderTaskApprovalType.新车三级管理维度: - params.thirdManageId = record.dataId; - break; - default: - break; - } - setAdviserTaskParams(params); - setAtpVisible(true); - }} - showSeriesModal={(record, type) => { - const params: any = { - id: data.id, - taskId: record.id, - orderTaskApprovalType: OrderTaskApprovalType.车系, - }; - switch (type) { - case OrderTaskApprovalType.门店维度: - params.shopId = record.dataId; - break; - case OrderTaskApprovalType.销售顾问维度: - params.staffId = record.dataId; - break; - case OrderTaskApprovalType.新车一级管理维度: - params.firstManageId = record.dataId; - break; - case OrderTaskApprovalType.新车二级管理维度: - params.secondManageId = record.dataId; - break; - case OrderTaskApprovalType.新车三级管理维度: - params.thirdManageId = record.dataId; - break; - default: - break; - } - setSeriesTaskParams(params); - setStpVisible(true); - }} + showAdviserModal={showAdviserModal} + showSeriesModal={showSeriesModal} /> { - const params = { ...adviserTaskParams } as any; - params.taskId = record.id; - params.orderTaskApprovalType = OrderTaskApprovalType.车系; - params.staffId = record.dataId; - setSeriesTaskParams(params); - setStpVisible(true); - }} + showSeriesModal={showSeriesModalByAdviser} /> + { + setAutoVisible(false); + setParams({}, true); + }} + destroyOnClose + footer={null} + > + { + setAutoVisible(false); + setParams({}, true); + }} + /> + + setBatchVisible(false)} + destroyOnClose + footer={null} + > + + 当前选择门店:{shopTaskItem?.shopName}} > setCurrStep(activeKey)} + defaultActiveKey={currTab} + onChange={(activeKey) => setCurrTab(activeKey)} items={[ { label: `门店任务分配${readOnly ? "详情" : ""}`, -- libgit2 0.22.2