SaleTaskAutoAssign.tsx 6.65 KB
import React, { useContext, useEffect, useRef, useState } from "react";
import {
  Table,
  Form,
  InputRef,
  Row,
  Button,
  message,
  Modal,
  InputNumber,
} from "antd";
import type { FormInstance } from "antd/es/form";
import * as API from "../api";
import "./index.less";
import { MAX_NUM } from "../entity";

type EditableTableProps = Parameters<typeof Table>[0];
type ColumnTypes = Exclude<EditableTableProps["columns"], undefined>;
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;
  onRefresh: () => void;
}

export default function SaleTaskAutoAssign(props: SaleTaskAutoAssignProps) {
  const EditableContext = React.createContext<FormInstance<any> | null>(null);
  const [dataSource, setDataSource] = useState<API.ShopTaskItem[]>([]);

  useEffect(() => {
    setDataSource(props.value ? [...props.value] : []);
  }, [props.value]);

  const EditableRow: React.FC<EditableRowProps> = ({ index, ...props }) => {
    const [form] = Form.useForm();
    return (
      <Form form={form} component={false}>
        <EditableContext.Provider value={form}>
          <tr {...props} />
        </EditableContext.Provider>
      </Form>
    );
  };

  const EditableCell: React.FC<EditableCellProps> = ({
    title,
    editable,
    children,
    dataIndex,
    record,
    handleSave,
    ...restProps
  }) => {
    const [editing, setEditing] = useState(false);
    const inputRef = useRef<InputRef>(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 ? (
        <Form.Item
          noStyle
          name={dataIndex}
          rules={[
            {
              required: true,
              message: `请输入${title}`,
            },
          ]}
        >
          <InputNumber
            ref={inputRef}
            min={0}
            max={MAX_NUM}
            style={{ width: "80px" }}
            onPressEnter={save}
            onBlur={save}
          />
        </Form.Item>
      ) : (
        <div className="editable-cell-value-wrap" onClick={toggleEdit}>
          {children}
        </div>
      );
    }

    return <td {...restProps}>{childNode}</td>;
  };

  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);
    setDataSource(newData);
  };

  const autoAssignSaleTask = (isAssignToAdviser: boolean) => {
    Modal.confirm({
      title: isAssignToAdviser ? (
        <span>
          确认分配到
          <span className="tip">全部门店和顾问</span>
          吗?
        </span>
      ) : (
        <span>
          确认分配到
          <span className="tip">全部门店</span>
          吗?
        </span>
      ),
      zIndex: 1002,
      onOk: async () => {
        const hide = message.loading("分配中,请稍候", 0);
        API.autoAssignSaleTask({
          id: props.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("分配成功");
            props.onRefresh();
          })
          .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 (
    <>
      <Table
        components={components}
        rowClassName={() => "editable-row"}
        bordered
        rowKey="id"
        dataSource={dataSource}
        columns={columns as ColumnTypes}
      />
      <Row align="middle" justify="center" style={{ marginTop: 20 }}>
        <Button onClick={props.onCancel}>取消</Button>
        <Button
          type="primary"
          style={{ marginLeft: 10 }}
          onClick={() => autoAssignSaleTask(false)}
        >
          分配到门店
        </Button>
        <Button
          type="primary"
          style={{ marginLeft: 10 }}
          onClick={() => autoAssignSaleTask(true)}
        >
          分配到门店和顾问
        </Button>
      </Row>
    </>
  );
}