Commit 310ddc9831d82f0af90bdc5234ea763393f847bb

Authored by 莫红玲
1 parent 68f1de8a

新增车辆授权选择组件

src/components/CarTableTreeAuth/SelectSpec.tsx 0 → 100644
  1 +import React, { useEffect, useState } from "react";
  2 +import {
  3 + Table,
  4 + Select,
  5 +} from "antd";
  6 +import {
  7 + CarOptionVo,
  8 +} from "@/pages/stock/Components/api";
  9 +import { ColumnsType } from 'antd/lib/table';
  10 +
  11 +interface Props {
  12 + onChange?: (pa: any) => void;
  13 + value?: any[];
  14 + disabled?: boolean;
  15 + level?: number; //1品牌,2车系,3车型
  16 + specList?: CarOptionVo[]
  17 +}
  18 +
  19 +interface Item {
  20 + label: string;
  21 + value: number;
  22 + key?: number;
  23 +}
  24 +const { Column } = Table;
  25 +const { Option } = Select;
  26 +
  27 +const columns: ColumnsType<CarOptionVo> = [
  28 + {
  29 + title: '车型',
  30 + dataIndex: 'name',
  31 + },
  32 + {
  33 + title: '配置代码',
  34 + dataIndex: 'specConfigCodeList',
  35 + render: (t) => t.map((i: string, key: number) => (<div key={i}>{key + 1}.{i}</div>))
  36 + },
  37 +];
  38 +export default function index({ onChange: onSelected, value, disabled, specList = [] }: Props) {
  39 + const rowSelection = {
  40 + onChange: (selectedRowKeys: React.Key[], selectedRows: CarOptionVo[]) => {
  41 + onSelected && onSelected(selectedRows);
  42 + },
  43 + };
  44 +
  45 + return (
  46 + <>
  47 + <Table
  48 + rowSelection={{
  49 + type: "checkbox",
  50 + selectedRowKeys: value && value.map(item => item.id),
  51 + ...rowSelection,
  52 + }}
  53 + pagination={false}
  54 + // loading={}
  55 + rowKey="id"
  56 + size="small"
  57 + scroll={{ y: 500 }}
  58 + columns={columns}
  59 + dataSource={specList}
  60 + />
  61 + </>
  62 + );
  63 +}
... ...
src/components/CarTableTreeAuth/entity.ts 0 → 100644
  1 +export interface CarAuthList {
  2 + authType: number;
  3 + brandId: number;
  4 + brandName: number;
  5 + children?: Array<SeriesAuth>
  6 +}
  7 +
  8 +interface SeriesAuth {
  9 + authType: number;
  10 + seriesId: number;
  11 + seriesName: string;
  12 + children?: Array<SpecAuth>
  13 +}
  14 +interface SpecAuth {
  15 + authType: number;
  16 + specId: number;
  17 + specName: string;
  18 +}
0 19 \ No newline at end of file
... ...
src/components/CarTableTreeAuth/index.tsx 0 → 100644
  1 +import React, { useEffect, useState } from "react";
  2 +import {
  3 + Button,
  4 + Card,
  5 + Table,
  6 + Modal,
  7 + Form,
  8 + Select,
  9 + Space,
  10 + Spin,
  11 + message,
  12 +} from "antd";
  13 +import {
  14 + CarOptionVo,
  15 + getOnsaleSeriesApi,
  16 + getOnsaleSpecApi,
  17 +} from "@/pages/stock/Components/api";
  18 +import { PlusOutlined } from '@ant-design/icons';
  19 +import { ColumnsType } from 'antd/lib/table';
  20 +import SelectSpec from './SelectSpec';
  21 +import { CarAuthList } from './entity';
  22 +import { getBrandFilterApi } from '@/common/api';
  23 +
  24 +interface Props {
  25 + onChange?: (pa: any) => void;
  26 + value?: CarAuthList[];
  27 + disabled?: boolean;
  28 + brandList?: CommonApi.OptionVO[];
  29 + /**品牌是否多选,默认true */
  30 + brandMultiple?: boolean;
  31 +}
  32 +
  33 +interface Item {
  34 + label: string;
  35 + value: number;
  36 + key?: number;
  37 +}
  38 +const { Column } = Table;
  39 +const { Option } = Select;
  40 +
  41 +export default function index({ onChange, value, disabled, brandMultiple = true, brandList }: Props) {
  42 + const [form] = Form.useForm();
  43 + // 控制Modal是否可见
  44 + const [visible, setVisible] = useState<boolean>(false);
  45 + // 控制是否可见车型下拉框
  46 + const [level, setLevel] = useState<number>(1);
  47 + //存储表格当前车系
  48 + const [currentItem, setCurrentItem] = useState<any>();
  49 + const [brandData, setBrandData] = useState<CommonApi.OptionVO[]>([]);
  50 + //存储Modal中可选的车系
  51 + const [series, setSeries] = useState<any>([]);
  52 + //存储接口返回的车型
  53 + const [specList, setSpecList] = useState<any>([]);
  54 + //存储Modal选择的品牌和车系作为表格的数据源
  55 + const [savaData, setSavadata] = useState<any>([]);
  56 + // 存储已经选中的车系
  57 + const [selectedSeries, setSelectedSeries] = useState<any[]>([]);
  58 + const [fetchLoading, setFetchLoading] = useState(false);
  59 +
  60 + useEffect(() => {
  61 + if (value && value.length) {
  62 + setSelectedSeries([...value]);
  63 + setSavadata([...value]);
  64 + }
  65 + }, [value]);
  66 +
  67 + useEffect(() => {
  68 + if (brandList && Array.isArray(brandList)) {
  69 + setBrandData(brandList || []);
  70 + }
  71 + }, [brandList]);
  72 +
  73 + function getBrands() {
  74 + if (brandData.length) {
  75 + return;
  76 + }
  77 + setFetchLoading(true);
  78 + getBrandFilterApi().then(res => {
  79 + setBrandData(res.data || []);
  80 + setFetchLoading(false);
  81 + }).catch(err => {
  82 + message.error(err.message);
  83 + setFetchLoading(false);
  84 + });
  85 + }
  86 +
  87 + const _onOk = () => {
  88 + form
  89 + .validateFields()
  90 + .then((fileds) => {
  91 + if (level === 2) {
  92 + const { series } = fileds;
  93 + const _series = series.map((item: Item) => ({
  94 + seriesId: item.value,
  95 + seriesName: item.label,
  96 + authType: 1,
  97 + }));
  98 +
  99 + const currentSeries = (savaData.filter((i: any) => i.brandId === currentItem.brandId)[0] || {}).children || [];
  100 + /**判断已有数据保留 */
  101 + if (currentSeries.length) {
  102 + const selectedIds = currentSeries.map(i => i.seriesId);
  103 + let newAuthSeries: any[] = [];
  104 + _series.forEach((item: any) => {
  105 + if (selectedIds.includes(item.seriesId)) {
  106 + newAuthSeries = newAuthSeries.concat(currentSeries.filter((list: any) => list.seriesId === item.seriesId));
  107 + } else {
  108 + newAuthSeries.push(item);
  109 + }
  110 + });
  111 + currentItem.children = newAuthSeries;
  112 + } else {
  113 + currentItem.children = _series;
  114 + }
  115 +
  116 + const tempData = savaData.map((item: any) => (item.brandId === currentItem.brandId ? { ...currentItem, authType: series.length ? 2 : 1 } : { ...item, authType: 1 }));
  117 + setSavadata([...tempData]);
  118 + onChange && onChange(tempData);
  119 + setVisible(false);
  120 + return;
  121 + }
  122 + if (level === 3) {
  123 + const { spec } = fileds;
  124 + const _spec = spec.map((item: any) => ({
  125 + specId: item.id,
  126 + specName: item.name,
  127 + }));
  128 + currentItem.children = _spec;
  129 + currentItem.authType = 2;
  130 + const tempData = savaData.map((item: any) => {
  131 + if (item.children) {
  132 + const newChildren = item.children.map((i: any) => (i.seriesId === currentItem.seriesId ? { ...currentItem, authType: spec.length ? 2 : 1 } : i));
  133 + item.children = newChildren;
  134 + }
  135 + return { ...item, authType: 1 };
  136 + });
  137 + setSavadata([...tempData]);
  138 + onChange && onChange(tempData);
  139 + setVisible(false);
  140 + return;
  141 + }
  142 + const { brand } = fileds;
  143 + const tempArray = (brandMultiple ? brand : [brand]).map((item: any) => ({
  144 + brandName: item.label,
  145 + brandId: item.value,
  146 + authType: 1, //1全部2部分
  147 + }));
  148 + const selectedBrands: number[] = savaData.map((i: any) => i.brandId);
  149 + let newAuthCar: any[] = [];
  150 + tempArray.forEach((item: any) => {
  151 + if (selectedBrands.includes(item.brandId)) {
  152 + newAuthCar = newAuthCar.concat(savaData.filter(list => list.brandId === item.brandId));
  153 + } else {
  154 + newAuthCar.push(item);
  155 + }
  156 + });
  157 + setSavadata(newAuthCar);
  158 + onChange && onChange(newAuthCar);
  159 + setVisible(false);
  160 + })
  161 + .catch((err) => console.log(err.message));
  162 + };
  163 +
  164 + // 选择部分车辆表格==》删除车系
  165 + const onDelete = (record: any) => {
  166 + const _savaData = savaData.filter(
  167 + (item: any) => item.seriesId != record.seriesId
  168 + );
  169 + const _selectedSeries = selectedSeries.filter(
  170 + (item) => item.seriesId != record.seriesId
  171 + );
  172 + setSavadata([..._savaData]);
  173 + onChange && onChange(_savaData);
  174 + setSelectedSeries([..._selectedSeries]);
  175 + };
  176 +
  177 + // 选择部分车辆表格==》编辑选择部分车系、车型
  178 + const onSelectSpec = async (record: any) => {
  179 + setCurrentItem(record);
  180 + setVisible(true);
  181 + if (record.brandId) {
  182 + setLevel(2);
  183 + setFetchLoading(true);
  184 + try {
  185 + const { data } = await getOnsaleSeriesApi(record.brandId);
  186 + const selectedSeries = savaData.filter((brand: any) => brand.brandId === record.brandId)[0].children;
  187 + selectedSeries && form.setFieldValue("series", selectedSeries.map(i => ({ value: i.seriesId, label: i.seriesName })));
  188 + setSeries(data);
  189 + setFetchLoading(false);
  190 + } catch (err: any) {
  191 + message.error(err.message);
  192 + setFetchLoading(false);
  193 + }
  194 + }
  195 + if (record.seriesId) {
  196 + setLevel(3);
  197 + setFetchLoading(true);
  198 + try {
  199 + const { data } = await getOnsaleSpecApi(record.seriesId);
  200 + record.children && form.setFieldValue("spec", record.children.map(i => ({ id: i.specId, name: i.specName })));
  201 + setSpecList(data);
  202 + setFetchLoading(false);
  203 + } catch (err: any) {
  204 + message.error(err.message);
  205 + setFetchLoading(false);
  206 + }
  207 + }
  208 + };
  209 +
  210 + return (
  211 + <>
  212 + <Card>
  213 + {!disabled && (
  214 + <div style={{ display: "flex", justifyContent: "flex-end" }}>
  215 + <Button
  216 + type="link"
  217 + disabled={disabled}
  218 + icon={<PlusOutlined />}
  219 + onClick={() => {
  220 + getBrands();
  221 + setVisible(true);
  222 + setLevel(1);
  223 + savaData.length && form.setFieldValue("brand", savaData.map((i: any) => ({ value: i.brandId, label: i.brandName })));
  224 + // form.resetFields();
  225 + }}
  226 + >
  227 + 新增
  228 + </Button>
  229 + </div>
  230 + )}
  231 +
  232 + <Table
  233 + dataSource={value}
  234 + rowKey={(record) => String(record.brandId || record.seriesId || record.specId)}
  235 + >
  236 + <Column
  237 + title="品牌"
  238 + dataIndex="brandName"
  239 + key="brandId"
  240 + />
  241 + <Column
  242 + title="车系"
  243 + dataIndex="seriesName"
  244 + key="seriesId"
  245 + render={(text, record: any) => {
  246 + return (text || record.specName || (record.children && record.children.length !== 0) ? (
  247 + <span>
  248 + {text}
  249 + </span>
  250 + ) : (
  251 + <span style={{ color: "#999" }}>全部车系</span>
  252 + ));
  253 + }}
  254 + />
  255 + <Column
  256 + title="车型"
  257 + dataIndex="specName"
  258 + key="specId"
  259 + render={(text, record: any) => {
  260 + return (text || (record.children && record.children.length !== 0) ? (
  261 + <span>
  262 + {text}
  263 + </span>
  264 + ) : (
  265 + <span style={{ color: "#999" }}>全部车型</span>
  266 + ));
  267 + }}
  268 + />
  269 + {!disabled && (
  270 + <Column
  271 + title="操作"
  272 + render={(_, record: any, index) => {
  273 + return (
  274 + <Space>
  275 + <Button
  276 + type={record.brandId ? "primary" : "link"}
  277 + style={{ padding: 2 }}
  278 + onClick={() => onSelectSpec(record)}
  279 + disabled={disabled}
  280 + >
  281 + {record.brandId ? "编辑车系" : (record.seriesId ? "编辑车型" : "")}
  282 + </Button>
  283 + {/* <Popconfirm
  284 + title="确定删除?"
  285 + okText="确定"
  286 + style={{ padding: 0 }}
  287 + cancelText="取消"
  288 + onConfirm={() => onDelete(record)}
  289 + >
  290 + <Button type="link" danger disabled={disabled}>
  291 + 删除
  292 + </Button>
  293 + </Popconfirm> */}
  294 + </Space>
  295 + );
  296 + }}
  297 + />
  298 + )}
  299 + </Table>
  300 + </Card>
  301 +
  302 + {/* 选择品牌和车系 */}
  303 + <Modal
  304 + title="选择车辆信息"
  305 + visible={visible}
  306 + onOk={() => form.submit()}
  307 + onCancel={() => {
  308 + setVisible(false);
  309 + }}
  310 + maskClosable={false}
  311 + afterClose={() => {
  312 + form.resetFields();
  313 + setCurrentItem({});
  314 + }}
  315 + >
  316 + <Spin spinning={fetchLoading}>
  317 + <Form onFinish={_onOk} form={form}>
  318 + {level === 1 ? (
  319 + <Form.Item
  320 + label="品牌"
  321 + name="brand"
  322 + >
  323 + <Select
  324 + labelInValue
  325 + mode={brandMultiple ? "multiple" : undefined}
  326 + placeholder="选择品牌"
  327 + >
  328 + {brandData.map((item) => (
  329 + <Option value={item.id} key={item.id}>
  330 + {item.name}
  331 + </Option>
  332 + ))}
  333 + </Select>
  334 + </Form.Item>
  335 + ) : null}
  336 +
  337 + {/* 车系 */}
  338 + {level === 2 && (
  339 + <Form.Item
  340 + label="车系"
  341 + name="series"
  342 + // rules={[{ required: true, message: "请选择车系" }]}
  343 + >
  344 + <Select labelInValue mode="multiple" placeholder="选择车系" allowClear>
  345 + {series.map((item: any) => (
  346 + <Option value={item.id} key={item.id}>
  347 + {item.name}
  348 + </Option>
  349 + ))}
  350 + </Select>
  351 + </Form.Item>
  352 + )}
  353 + {level === 3 ? (
  354 + <Form.Item
  355 + label=""
  356 + name="spec"
  357 + >
  358 + {/* <Select labelInValue mode="multiple" placeholder="选择车型" allowClear>
  359 + {specList.map((item: any) => (
  360 + <Option value={item.id} key={item.id}>
  361 + {item.name}
  362 + </Option>
  363 + ))}
  364 + </Select> */}
  365 + <SelectSpec specList={specList} />
  366 + </Form.Item>
  367 + ) : null}
  368 + </Form>
  369 + </Spin>
  370 + </Modal>
  371 + </>
  372 + );
  373 +}
... ...