Commit 50e3edecb63b50bae4cb7b61af06f0bea964a166

Authored by jiangwei
1 parent 8ad24e53

feat: 车系映射配置

config/routers/order3.ts
... ... @@ -325,4 +325,9 @@ export default [
325 325 path: '/order3/weeklydataupload',
326 326 component: './order3/WeeklydataUpload',
327 327 },
  328 + {
  329 + // 车系映射配置
  330 + path: '/order3/seriesmapping',
  331 + component: './order3/SeriesMapping',
  332 + },
328 333 ];
... ...
src/pages/order3/SeriesMapping/api.ts 0 → 100644
  1 +/*
  2 + * @Author: jiangwei jiangwei.feewee.cn
  3 + * @Date: 2024-03-27 17:40:09
  4 + * @LastEditors: jiangwei jiangwei.feewee.cn
  5 + * @LastEditTime: 2024-04-18 17:52:00
  6 + * @FilePath: /fw-cms/src/pages/order3/SeriesMapping/api.ts
  7 + * @Description:
  8 + *
  9 + * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved.
  10 + */
  11 +import type { http } from '@/typing/http';
  12 +import request from '@/utils/request';
  13 +import { SDS_HOST } from '@/utils/host';
  14 +
  15 +export interface series {
  16 + seriesId?: number
  17 + seriesName?: string
  18 + brandId?: number
  19 + brandName?: string
  20 +}
  21 +export interface saveparams {
  22 + importBrandName?: string
  23 + importSeriesName?: string
  24 + series?: series[]
  25 +}
  26 +/** 列表 */
  27 +export function getList(params: any): http.PromisePageResp<saveparams> {
  28 + return request.get(`${SDS_HOST}/erp/series/mapping/get/mapping/list`, { params });
  29 +}
  30 +/** 保存 */
  31 +export function saveapi(params: saveparams) {
  32 + return request.post(`${SDS_HOST}/erp/series/mapping/save/mapping`, { ...params });
  33 +}
  34 +/** 删除 */
  35 +export function delapi(params: saveparams) {
  36 + return request.post(`${SDS_HOST}/erp/series/mapping/del/mapping`, { ...params });
  37 +}
  38 +
  39 +export interface typedata {
  40 + value: string;
  41 + label: string;
  42 + children?: typedata[];
  43 +}
  44 +// 车系
  45 +export function getSeries(params: { brands?: string[]; vehicleCategory?: string[]; subdivideCategories?: string[] }): http.PromiseResp<typedata[]> {
  46 + return request.post(`${SDS_HOST}/erp/car/data/get/series/by/type`, params);
  47 +}
  48 +/**
  49 + * 类型10区域,20使用省份,30使用城市,40车型类别,50细分大类,60使用性质,70燃料种类,80国别大类,90国别,100排量,110动力类型,120所有权,130驱动形式150车系140品牌
  50 +*/
  51 +export function getTypedata(params: { type: number; queryAll?: boolean; parentTypes?: string[] }): http.PromiseResp<typedata[]> {
  52 + return request.post(`${SDS_HOST}/erp/type/settings/get/types`, params);
  53 +}
0 54 \ No newline at end of file
... ...
src/pages/order3/SeriesMapping/components/ChooseSeriesModal.tsx 0 → 100644
  1 +/*
  2 + * @Author: jiangwei jiangwei.feewee.cn
  3 + * @Date: 2024-04-18 17:12:08
  4 + * @LastEditors: jiangwei jiangwei.feewee.cn
  5 + * @LastEditTime: 2024-04-18 18:25:13
  6 + * @FilePath: /fw-cms/src/pages/order3/SeriesMapping/components/ChooseSeriesModal.tsx
  7 + * @Description:
  8 + *
  9 + * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved.
  10 + */
  11 +import React, { useState, useEffect } from 'react';
  12 +import { Table, Modal, Button, Input, Select } from 'antd';
  13 +import usePagination from '@/hooks/usePagination';
  14 +import useInitial from '@/hooks/useInitail';
  15 +import { seriesListApi, getAllBrandApi } from '@/pages/oop/Series/api'
  16 +
  17 +interface Props {
  18 + visible: boolean,
  19 + onCancel: () => any,
  20 + onOk: (v: Series.seriesListItem[]) => any,
  21 +}
  22 +const Column = Table.Column;
  23 +export default function SeriesList(props: Props) {
  24 + const { visible, onCancel, onOk } = props
  25 + const { list, paginationConfig, loading, setParams } = usePagination(seriesListApi, { status: 1 });
  26 + const { data: brands } = useInitial(getAllBrandApi, [], {});
  27 + const [selectedSeries, setSelectedSeries] = useState<Series.seriesListItem[]>([]);
  28 +
  29 + useEffect(() => {
  30 + if (!visible) {
  31 + setSelectedSeries([])
  32 + }
  33 + }, [visible])
  34 +
  35 + const _onOk = () => {
  36 + onOk(selectedSeries);
  37 + onCancel();
  38 + }
  39 + return (
  40 + <Modal
  41 + title="选择映射车系"
  42 + maskClosable={false}
  43 + open={visible}
  44 + onCancel={onCancel}
  45 + width={800}
  46 + footer={[
  47 + <Button onClick={onCancel} key={1} >取消</Button>,
  48 + <Button onClick={_onOk} key={2} type='primary' disabled={!selectedSeries.length}>确认</Button>
  49 + ]}
  50 + >
  51 + <div style={{ display: 'flex', justifyContent: "start" }}>
  52 + <Input
  53 + allowClear
  54 + style={{ width: 200, marginRight: 10, marginBottom: 10 }}
  55 + onChange={e => setParams({ name: e.target.value }, true)}
  56 + placeholder="车系名称"
  57 + />
  58 + <Select
  59 + showSearch
  60 + optionFilterProp="children"
  61 + placeholder="选择品牌"
  62 + allowClear
  63 + onChange={val => { setParams({ brandId: val }, true) }}
  64 + style={{ width: 200, marginRight: 10, marginBottom: 10 }}
  65 + >
  66 + {brands.map((item: Series.BrandItem) => <Select.Option key={item.id} value={item.id!}>{item.name}</Select.Option>)}
  67 + </Select>
  68 + </div>
  69 + <Table
  70 + dataSource={list}
  71 + pagination={paginationConfig}
  72 + rowKey={record => Number(record.id)}
  73 + loading={loading}
  74 + size="small"
  75 + rowSelection={{
  76 + type: "checkbox",
  77 + selectedRowKeys: selectedSeries.map(i => i.id),
  78 + onSelect: (row, _selected) => {
  79 + const index = selectedSeries.findIndex(_row => _row.id == row.id);
  80 + const newData = [...selectedSeries];
  81 + if (_selected) {
  82 + newData.unshift(row);
  83 + } else if (index > -1) {
  84 + newData.splice(index, 1);
  85 + }
  86 + setSelectedSeries([...newData]);
  87 + },
  88 + onSelectAll: (selected, selectedRows, changeRows) => {
  89 + const changedKeys = changeRows.map(row => row.id);
  90 + if (selected) {
  91 + // 全选
  92 + const _arr = [...selectedSeries, ...changeRows]
  93 + setSelectedSeries(_arr);
  94 + } else {
  95 + // 取消全选 过滤当前页选中数据
  96 + setSelectedSeries(selectedSeries.filter(row => !changedKeys.includes(row.id)))
  97 + }
  98 + },
  99 + }}
  100 + >
  101 + <Column title="车系名称" dataIndex="name" />
  102 + <Column title="品牌名称" dataIndex="brandName" />
  103 + <Column title="厂商" dataIndex="factoryName" />
  104 + </Table>
  105 + </Modal>
  106 + );
  107 +}
... ...
src/pages/order3/SeriesMapping/components/CreateModal.tsx 0 → 100644
  1 +import React, { useState, useEffect } from 'react';
  2 +import { Button, Modal, message, Select,Table } from 'antd';
  3 +import useInitial from '@/hooks/useInitail';
  4 +import type { saveparams } from '../api';
  5 +import { getTypedata, saveapi } from '../api';
  6 +import ChooseSeriesModal from './ChooseSeriesModal';
  7 +
  8 +const Column = Table.Column;
  9 +const Option = Select.Option;
  10 +interface Props {
  11 + onCancel: () => any;
  12 + visible: boolean;
  13 + onRefshing: () => any
  14 +}
  15 +
  16 +export default function UploadModal(props: Props) {
  17 + const { onCancel, visible, onRefshing } = props;
  18 + const { data: brands } = useInitial(getTypedata, [], {type: 140});
  19 + const [param, setParam] = useState<saveparams>({})
  20 + const [delay, setDelay] = useState(true);
  21 + const { data: series, setParams } = useInitial(getTypedata, [], { type: 150 }, delay);
  22 + const [loading, setLoading] = useState(false);
  23 + const [servisible, setServisible] = useState(false);
  24 +
  25 + useEffect(() => {
  26 + if (!visible) {
  27 + setParam({});
  28 + }
  29 + }, [visible]);
  30 +
  31 + const onOk = () => {
  32 + if (!param.importBrandName) {
  33 + message.error('请选择导入品牌');
  34 + return;
  35 + }
  36 + if (!param.importSeriesName) {
  37 + message.error('请选择导入车系');
  38 + return;
  39 + }
  40 + if (!param.series?.length) {
  41 + message.error('请选择映射车系列表');
  42 + return;
  43 + }
  44 + setLoading(true);
  45 + saveapi(param).then(() => {
  46 + setLoading(false);
  47 + onRefshing();
  48 + onCancel();
  49 + message.success('操作成功');
  50 + }).catch(e => {
  51 + setLoading(false);
  52 + message.error(e.message);
  53 + })
  54 + }
  55 +
  56 + return (
  57 + <Modal
  58 + title={'新增车系映射'}
  59 + open={visible}
  60 + width={1000}
  61 + keyboard={false}
  62 + maskClosable={false}
  63 + onCancel={() => onCancel()}
  64 + footer={[
  65 + <Button key="close" type="default" onClick={() => onCancel()} loading={loading}>
  66 + 关闭
  67 + </Button>,
  68 + <Button key="ok" type="primary" onClick={() => onOk()} loading={loading}>
  69 + 确认
  70 + </Button>,
  71 + ]}
  72 + >
  73 + <div style={{ display: 'flex', alignItems: 'center', marginBottom: 20 }}>
  74 + <div style={{ width: 100, textAlign: 'end' }}>导入品牌:</div>
  75 + <Select
  76 + value={param.importBrandName}
  77 + style={{ flex: 1 }}
  78 + placeholder="请选择导入品牌"
  79 + onChange={v => {
  80 + setParam({ ...param, importBrandName:v });
  81 + setDelay(false);
  82 + setParams({ parentTypes: [v], type: 150 }, true)
  83 + }}
  84 + showSearch
  85 + optionFilterProp="children"
  86 + >
  87 + {brands?.map((it) => (
  88 + <Option key={it.value} value={it.value}>
  89 + {it.value}
  90 + </Option>
  91 + ))}
  92 + </Select>
  93 + </div>
  94 + <div style={{ display: 'flex', alignItems: 'center' }}>
  95 + <div style={{ width: 100, textAlign: 'end' }}>导入车系:</div>
  96 + <Select
  97 + value={param.importSeriesName}
  98 + style={{ flex: 1 }}
  99 + placeholder="请选择导入车系"
  100 + onChange={v => {
  101 + setParam({ ...param, importSeriesName: v });
  102 + }}
  103 + showSearch
  104 + optionFilterProp="children"
  105 + >
  106 + {series.map((it) => (
  107 + <Option key={it.value} value={it.value}>
  108 + {it.value}
  109 + </Option>
  110 + ))}
  111 + </Select>
  112 + </div>
  113 + <div style={{ display: 'flex', marginTop: 20, marginBottom: 20, alignItems: 'start', width: '100%' }}>
  114 + <div style={{ width: 100, textAlign: 'end' }}>映射车系列表:</div>
  115 + <div style={{flex: 1}}>
  116 + <div style={{display: 'flex', justifyContent: 'end'}}>
  117 + <Button onClick={() => setServisible(true)} type='primary' style={{ marginBottom: 10 }}>添加映射车系</Button>
  118 + </div>
  119 + <Table dataSource={param.series} style={{flex: 1}} scroll={{y: 400}} pagination={false}>
  120 + <Column title="品牌名称" dataIndex="brandName" />
  121 + <Column title="车系名称" dataIndex="seriesName" />
  122 + </Table>
  123 + </div>
  124 + </div>
  125 + <ChooseSeriesModal
  126 + visible={servisible}
  127 + onCancel={() => setServisible(false)}
  128 + onOk={s => {
  129 + const _s = s.map(i => ({ ...i, seriesName: i.name, seriesId: i.id }))
  130 + setParam({ ...param, series: _s })
  131 + }}
  132 + />
  133 + </Modal>
  134 + );
  135 +}
... ...
src/pages/order3/SeriesMapping/components/MappingSeriesModal.tsx 0 → 100644
  1 +/*
  2 + * @Author: jiangwei jiangwei.feewee.cn
  3 + * @Date: 2024-04-18 16:46:23
  4 + * @LastEditors: jiangwei jiangwei.feewee.cn
  5 + * @LastEditTime: 2024-04-18 17:54:50
  6 + * @FilePath: /fw-cms/src/pages/order3/SeriesMapping/components/MappingSeriesModal.tsx
  7 + * @Description:
  8 + *
  9 + * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved.
  10 + */
  11 +import React from 'react';
  12 +import { Button, Modal, Table } from 'antd';
  13 +import type { series } from '../api';
  14 +
  15 +const Column = Table.Column;
  16 +interface Props {
  17 + onCancel: () => any;
  18 + visible: boolean;
  19 + data: series[]
  20 +}
  21 +
  22 +export default function UploadModal(props: Props) {
  23 + const { onCancel, visible, data } = props;
  24 + console.log(data, 'data')
  25 + return (
  26 + <Modal
  27 + title={'车系映射列表'}
  28 + open={visible}
  29 + width={800}
  30 + keyboard={false}
  31 + maskClosable={false}
  32 + onCancel={() => onCancel()}
  33 + okButtonProps={{ hidden: true }}
  34 + footer={[
  35 + <Button key="close" type="default" onClick={() => onCancel()}>
  36 + 关闭
  37 + </Button>
  38 + ]}
  39 + >
  40 + <Table dataSource={data} pagination={false}>
  41 + <Column title="品牌名称" dataIndex="brandName" />
  42 + <Column title="车系名称" dataIndex="seriesName" />
  43 + </Table>
  44 + </Modal>
  45 + );
  46 +}
... ...
src/pages/order3/SeriesMapping/index.tsx 0 → 100644
  1 +/*
  2 + * @Author: jiangwei jiangwei.feewee.cn
  3 + * @Date: 2024-04-18 16:00:41
  4 + * @LastEditors: jiangwei jiangwei.feewee.cn
  5 + * @LastEditTime: 2024-04-18 19:02:06
  6 + * @FilePath: /fw-cms/src/pages/order3/SeriesMapping/index.tsx
  7 + * @Description:
  8 + *
  9 + * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved.
  10 + */
  11 +import React, { useState } from 'react'
  12 +import { PageHeaderWrapper } from '@ant-design/pro-layout'
  13 +import { Button, Card, Table, Select, Popconfirm, message } from 'antd'
  14 +import CreateModal from './components/CreateModal';
  15 +import MappingSeriesModal from './components/MappingSeriesModal';
  16 +import usePagination from '@/hooks/usePagination';
  17 +import useInitial from '@/hooks/useInitail';
  18 +import type { saveparams, series } from './api';
  19 +import { getList, getTypedata, delapi } from './api';
  20 +
  21 +const { Column } = Table
  22 +
  23 +export default function Index() {
  24 + const [visible, setVisible] = useState < boolean > (false)
  25 + const { list, loading, setParams, paginationConfig } = usePagination(getList, {})
  26 + const { data: brands } = useInitial(getTypedata, [], {type: 140});
  27 + const [delay, setDelay] = useState(true);
  28 + const { data: series, setParams: seriesQuery } = useInitial(getTypedata, [], { type: 150 }, delay);
  29 + const [mappseries, setMappingseries] = useState < { visible: boolean, data: series[] }>({visible: false, data: []})
  30 +
  31 + const _del = (p: saveparams) => {
  32 + delapi(p).then(() => {
  33 + message.success('操作成功');
  34 + setParams({}, true)
  35 + }).catch(e => message.error(e.message))
  36 + }
  37 + return (
  38 + <PageHeaderWrapper>
  39 + <Card>
  40 + <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 20 }}>
  41 + <div>
  42 + <Select
  43 + style={{ width: 200, marginRight: 20 }}
  44 + placeholder="导入品牌筛选"
  45 + onChange={v => {
  46 + setParams({ importBrandName: v }, true);
  47 + setDelay(false);
  48 + seriesQuery({ parentTypes: [v], type: 150 }, true)
  49 + }}
  50 + showSearch
  51 + allowClear
  52 + optionFilterProp="children"
  53 + >
  54 + {brands.map((it) => (
  55 + <Select.Option key={it.value} value={it.value}>
  56 + {it.label}
  57 + </Select.Option>
  58 + ))}
  59 + </Select>
  60 + {!!series.length &&
  61 + <Select
  62 + style={{ width: 200, marginRight: 20 }}
  63 + placeholder="导入车系筛选"
  64 + onChange={v => {
  65 + setParams({ importSeriesName: v }, true);
  66 + }}
  67 + showSearch
  68 + allowClear
  69 + optionFilterProp="children"
  70 + >
  71 + {series.map((it) => (
  72 + <Select.Option key={it.value} value={it.value}>
  73 + {it.label}
  74 + </Select.Option>
  75 + ))}
  76 + </Select>
  77 + }
  78 + </div>
  79 + <div>
  80 + <Button type='primary' onClick={() => setVisible(true)}>新增</Button>
  81 + </div>
  82 + </div>
  83 + <Table
  84 + dataSource={list}
  85 + loading={loading}
  86 + pagination={paginationConfig}
  87 + rowKey={r => `${r.importBrandName}_${r.importSeriesName}`}
  88 + >
  89 + <Column title="导入品牌" dataIndex="importBrandName" />
  90 + <Column title="导入车系" dataIndex="importSeriesName" />
  91 + <Column title="映射车系列表" render={r => <a onClick={() => setMappingseries({visible: true, data: r.series})}>查看</a> } />
  92 + <Column
  93 + title="操作"
  94 + render={r => (
  95 + <Popconfirm title="确认删除?" onConfirm={() => _del(r)}>
  96 + <a style={{ color: 'red' }}>删除</a>
  97 + </Popconfirm>
  98 + )}
  99 + />
  100 + </Table>
  101 + </Card>
  102 + <CreateModal visible={visible} onCancel={() => setVisible(false)} onRefshing={setParams} />
  103 + <MappingSeriesModal visible={mappseries.visible} onCancel={() => setMappingseries({visible: false, data: []})} data={mappseries.data} />
  104 + </PageHeaderWrapper>
  105 + )
  106 +}
0 107 \ No newline at end of file
... ...
src/pages/order3/WeeklydataUpload/components/UploadModal.tsx
  1 +/*
  2 + * @Author: jiangwei jiangwei.feewee.cn
  3 + * @Date: 2024-04-16 17:51:11
  4 + * @LastEditors: jiangwei jiangwei.feewee.cn
  5 + * @LastEditTime: 2024-04-16 19:29:30
  6 + * @FilePath: /fw-cms/src/pages/order3/WeeklydataUpload/components/UploadModal.tsx
  7 + * @Description:
  8 + *
  9 + * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved.
  10 + */
1 11 import React, { useState, useEffect } from 'react';
2 12 import { UploadOutlined } from '@ant-design/icons';
3 13 import FeeweeUploadAttachment from '@/components/FeeweeUploadAttachment';
... ... @@ -10,15 +20,17 @@ const Option = Select.Option;
10 20 interface Props {
11 21 onCancel: () => any;
12 22 visible: boolean;
  23 + onRefshing: Function
13 24 }
14 25  
15 26 export default function UploadModal(props: Props) {
16   - const { onCancel, visible } = props;
  27 + const { onCancel, visible, onRefshing } = props;
17 28 const { data: years } = useInitial(getyeardata, [], {});
18 29 const { data: weeks, setParams } = useInitial(getweekdata, {}, { year: Number(moment().format('YYYY')) });
19 30 const [year, setYear] = useState < number > (Number(moment().format('YYYY')));
20 31 const [week, setWeek] = useState < number| undefined >();
21   - const [fids, setFids] = useState < any[] > ([])
  32 + const [fids, setFids] = useState < any[] > ([]);
  33 + const [loading, setLoading] = useState(false);
22 34  
23 35 useEffect(() => {
24 36 if (!visible) {
... ... @@ -38,9 +50,16 @@ export default function UploadModal(props: Props) {
38 50 message.error('请先上传文件');
39 51 return;
40 52 }
  53 + setLoading(true);
41 54 upLoad({ year, week, sourceFid: fids[0] }).then(() => {
  55 + setLoading(false);
  56 + onRefshing();
  57 + onCancel();
42 58 message.success('操作成功');
43   - }).catch(e => message.error(e.message))
  59 + }).catch(e => {
  60 + setLoading(false);
  61 + message.error(e.message);
  62 + })
44 63 }
45 64  
46 65 return (
... ... @@ -52,10 +71,10 @@ export default function UploadModal(props: Props) {
52 71 maskClosable={false}
53 72 onCancel={() => onCancel()}
54 73 footer={[
55   - <Button key="close" type="default" onClick={() => onCancel()}>
  74 + <Button key="close" type="default" onClick={() => onCancel()} loading={loading}>
56 75 关闭
57 76 </Button>,
58   - <Button key="ok" type="primary" onClick={() => onOk()}>
  77 + <Button key="ok" type="primary" onClick={() => onOk()} loading={loading}>
59 78 确认导入
60 79 </Button>,
61 80 ]}
... ...
src/pages/order3/WeeklydataUpload/index.tsx
... ... @@ -80,7 +80,7 @@ export default function Index() {
80 80 <Column title="状态" dataIndex="status" render={t => <Tag color={t == 1 ? 'orange' : 'green'}>{t == 1 ? '处理中' : '已完成'}</Tag>} />
81 81 </Table>
82 82 </Card>
83   - <UploadModal visible={visible} onCancel={() => setVisible(false)} />
  83 + <UploadModal visible={visible} onCancel={() => setVisible(false)} onRefshing={setParams} />
84 84 </PageHeaderWrapper>
85 85 )
86 86 }
87 87 \ No newline at end of file
... ...