Commit cfb1af9195d2e9dc61b47441ac063a906d71f9ae
Merge remote-tracking branch 'origin/master' into bug_fix
Showing
15 changed files
with
888 additions
and
38 deletions
config/routers/performance.ts
... | ... | @@ -99,6 +99,11 @@ export default [ |
99 | 99 | path: '/morax/evaDataImport', |
100 | 100 | component: './performance/EvaDataImport', |
101 | 101 | }, |
102 | + /** 数据导入 */ | |
103 | + { | |
104 | + path: '/morax/DataImport', | |
105 | + component: './performance/DataImport', | |
106 | + }, | |
102 | 107 | /** 考评数据导入==> 查看数据清单 */ |
103 | 108 | { |
104 | 109 | path: '/morax/evaDataImport/edit/:id?/:dimensionType?', | ... | ... |
src/components/ApprovalProgress/index.tsx
... | ... | @@ -43,41 +43,6 @@ export default function ApprovalProgress({ orderNo }: Props) { |
43 | 43 | setProgress({ |
44 | 44 | loading: false, |
45 | 45 | data: res.data || [], |
46 | - // data: [ | |
47 | - // { | |
48 | - // // 审批中倒计时 | |
49 | - // approveTime: 1709741004000, | |
50 | - // approverName: 'Shinner', | |
51 | - // approverId: 2144, | |
52 | - // status: 1, | |
53 | - // opinion: '测试理由', | |
54 | - // efficientTime: 1709781004000, | |
55 | - // createTime: 1709721004000, | |
56 | - // roleNames: ['销售一级管理', '销售二级管理', '销售三级管理'], | |
57 | - // }, | |
58 | - // { | |
59 | - // // 审批中超时 | |
60 | - // approveTime: 1799722004000, | |
61 | - // approverName: 'Shinner', | |
62 | - // approverId: 2145, | |
63 | - // status: 1, | |
64 | - // opinion: '测试理由', | |
65 | - // efficientTime: 1709721004000, | |
66 | - // createTime: 1709721004000, | |
67 | - // roleNames: ['销售一级管理', '销售二级管理', '销售三级管理'], | |
68 | - // }, | |
69 | - // { | |
70 | - // // 审批结束超时 | |
71 | - // approveTime: 1799722004000, | |
72 | - // approverName: 'Shinner', | |
73 | - // approverId: 2146, | |
74 | - // status: 2, | |
75 | - // opinion: '测试理由', | |
76 | - // efficientTime: 1709781004000, | |
77 | - // createTime: 1709721004000, | |
78 | - // roleNames: ['销售一级管理', '销售二级管理', '销售三级管理'], | |
79 | - // }, | |
80 | - // ], | |
81 | 46 | }); |
82 | 47 | }) |
83 | 48 | .catch((error) => { | ... | ... |
src/pages/performance/DataImport/api.ts
0 → 100644
1 | +import request from '@/utils/request'; | |
2 | +import { MORAX_HOST } from '@/utils/host'; | |
3 | +import type { Page } from '@/typing/common'; | |
4 | +import type { Data } from 'ahooks/lib/useAntdTable/types'; | |
5 | + | |
6 | +/** | |
7 | + * 展厅美化导入记录分页查询 | |
8 | + * http://testgate.feewee.cn/morax/erp/eval-indicator-import/showroom-page | |
9 | + */ | |
10 | +export async function DataImportAPi(params: MDataImport.DataImportListParams) { | |
11 | + const res = await request.get<Page<MDataImport.DataImportList>>(`${MORAX_HOST}/erp/eval-indicator-import/showroom-page`, { | |
12 | + params, | |
13 | + }); | |
14 | + const data = res?.data || { total: 0, list: [], data: [] }; | |
15 | + if (data) { | |
16 | + const d = data.data || []; | |
17 | + data.data = d; | |
18 | + data.list = d; | |
19 | + } | |
20 | + return data as Data; | |
21 | +} | |
22 | + | |
23 | +/** | |
24 | + * 数据导入指标列表 | |
25 | + * http://testgate.feewee.cn/morax/erp/eval-indicator-import/indicators | |
26 | + */ | |
27 | +export async function IndicatorListApi() { | |
28 | + const res = await request.get<MDataImport.IndicatorList[]>(`${MORAX_HOST}/erp/eval-indicator-import/indicators`); | |
29 | + return res.data ?? []; | |
30 | +} | |
31 | + | |
32 | +/** | |
33 | + * 展厅美化导入清单查询 | |
34 | + * http://testgate.feewee.cn/morax/erp/eval-indicator-import/showroom-detail | |
35 | + */ | |
36 | + | |
37 | +export async function DetailedListAPi(params: MDataImport.DataImportListParams) { | |
38 | + const res = await request.get<Page<MDataImport.DetailedList>>(`${MORAX_HOST}/erp/eval-indicator-import/showroom-detail`, { | |
39 | + params, | |
40 | + }); | |
41 | + const data = res?.data || { total: 0, list: [], data: [] }; | |
42 | + if (data) { | |
43 | + const d = data.data || []; | |
44 | + data.data = d; | |
45 | + data.list = d; | |
46 | + } | |
47 | + return data as Data; | |
48 | +} | |
49 | +/** | |
50 | + * 展厅美化导入记录详情查询 | |
51 | + * http://testgate.feewee.cn/morax/erp/eval-indicator-import/showroom-import-detail | |
52 | + */ | |
53 | + | |
54 | +export async function ImportListDetailApi(id?: number) { | |
55 | + const res = await request.get<MDataImport.DataImportList>(`${MORAX_HOST}/erp/eval-indicator-import/showroom-import-detail`, { params: { id } }); | |
56 | + return res.data ?? {}; | |
57 | +} | |
58 | + | |
59 | +/** | |
60 | + * 上传展厅美化数据 | |
61 | + * http://testgate.feewee.cn/morax/erp/eval-indicator-import/analysis/showroom-shop | |
62 | + */ | |
63 | + | |
64 | +export async function UploadImportApi(fid?: string, indicatorCode?: string) { | |
65 | + const res = await request.get<MDataImport.DataImportList>(`${MORAX_HOST}/erp/eval-indicator-import/analysis/showroom-shop`, { | |
66 | + params: { fid, indicatorCode }, | |
67 | + }); | |
68 | + return res.data ?? {}; | |
69 | +} | |
70 | + | |
71 | +/** | |
72 | + * 下载展厅美化数据 | |
73 | + * http://testgate.feewee.cn/morax/erp/eval-indicator-import/template-file | |
74 | + */ | |
75 | + | |
76 | +export async function DownloadApi( indicatorCode?: string) { | |
77 | + const res = await request.get<any>(`${MORAX_HOST}/erp/eval-indicator-import/template-file`, { | |
78 | + params: { indicatorCode }, | |
79 | + }); | |
80 | + return res.data ?? {}; | |
81 | +} | |
82 | + | |
83 | +/** | |
84 | + * 删除导入审批 | |
85 | + * http://testgate.feewee.cn/morax/erp/eval-indicator/del-import | |
86 | + */ | |
87 | +export function deleteApi(params: { id: number }) { | |
88 | + return request.get(`${MORAX_HOST}/erp/eval-indicator/del-import`, { params }); | |
89 | +} | |
90 | +/** | |
91 | + * 撤销审批 | |
92 | + * http://testgate.feewee.cn/morax/erp/eval-indicator/cancel | |
93 | + */ | |
94 | +export function revokeApi(params: { id: number }) { | |
95 | + return request.get(`${MORAX_HOST}/erp/eval-indicator/cancel`, { params }); | |
96 | +} | |
97 | + | |
98 | +/** | |
99 | + * 保存展厅美化数据 | |
100 | + * http://testgate.feewee.cn/morax/erp/eval-indicator-import/save-showroom-import | |
101 | + */ | |
102 | +export function SaveDataApi(params: { key: string }) { | |
103 | + return request.get(`${MORAX_HOST}/erp/eval-indicator-import/save-showroom-import`, { params }); | |
104 | +} | |
0 | 105 | \ No newline at end of file | ... | ... |
src/pages/performance/DataImport/components/DetailList.tsx
0 → 100644
1 | +import React, { useEffect, useState } from 'react'; | |
2 | +import { Table, message, DatePicker, Select } from 'antd'; | |
3 | +import type { ColumnsType } from 'antd/es/table'; | |
4 | +import type { DatePickerProps } from 'antd'; | |
5 | +import { DetailedListAPi } from '../api'; | |
6 | +import { useAntdTable } from 'ahooks'; | |
7 | +import moment from 'moment'; | |
8 | +import useInitial from '@/hooks/useInitail'; | |
9 | +import { getShopApi } from '@/common/api'; | |
10 | + | |
11 | +type Props = { | |
12 | + indicator?: MDataImport.IndicatorList; | |
13 | + onChange?: (value?: any) => void; | |
14 | +}; | |
15 | +interface DataType { | |
16 | + key: string; | |
17 | + name: string; | |
18 | +} | |
19 | +export default function TableList({ indicator }: Props) { | |
20 | + const [monthly, setMonthly] = useState<number>(); | |
21 | + const [shopId, setShopId] = useState<number>(); | |
22 | + const { data } = useInitial(getShopApi, [], {}); | |
23 | + const pickMonth: DatePickerProps['onChange'] = (date, _dateString) => { | |
24 | + setMonthly(date?.valueOf() ?? 0); | |
25 | + }; | |
26 | + function shopChange(value: any) { | |
27 | + setShopId(value); | |
28 | + } | |
29 | + //@ts-ignore | |
30 | + const { tableProps, run } = useAntdTable<any, MDataImport.DataImportListParams[]>(DetailedListAPi, { | |
31 | + manual: true, | |
32 | + defaultParams: [ | |
33 | + { | |
34 | + pageSize: 10, | |
35 | + current: 1, | |
36 | + shopId: undefined, | |
37 | + monthly: Date.now(), | |
38 | + indicatorCode: indicator?.code || '', | |
39 | + }, | |
40 | + ], | |
41 | + onError: (e, _) => { | |
42 | + message.error(e.message); | |
43 | + }, | |
44 | + }); | |
45 | + const columns: ColumnsType<DataType> = [ | |
46 | + { | |
47 | + title: '月度', | |
48 | + dataIndex: 'dataDate', | |
49 | + align:'center', | |
50 | + width: 200, | |
51 | + key: 'dataDate', | |
52 | + render: (time: number) => (time ? moment(time).format('YYYY-MM') : '--'), | |
53 | + }, | |
54 | + { | |
55 | + title: '门店', | |
56 | + dataIndex: 'shopName', | |
57 | + width: 300, | |
58 | + align:'center', | |
59 | + key: 'shopName', | |
60 | + render: (name) => <span>{name || '--'}</span>, | |
61 | + }, | |
62 | + { | |
63 | + title: '打分', | |
64 | + dataIndex: 'score', | |
65 | + width: 100, | |
66 | + align:'center', | |
67 | + key: 'score', | |
68 | + render: (name) => <span>{name || '--'}</span>, | |
69 | + }, | |
70 | + { | |
71 | + title: '总分', | |
72 | + key: 'totalScore', | |
73 | + width: 100, | |
74 | + align:'center', | |
75 | + dataIndex: 'totalScore', | |
76 | + render: (name) => <span>{name || '--'}</span>, | |
77 | + }, | |
78 | + { | |
79 | + title: '打分人员', | |
80 | + key: 'graderStaffName', | |
81 | + width: 200, | |
82 | + align:'center', | |
83 | + dataIndex: 'graderStaffName', | |
84 | + render: (name) => <span>{name || '--'}</span>, | |
85 | + }, | |
86 | + ]; | |
87 | + useEffect(() => { | |
88 | + if(indicator?.code){ | |
89 | + run({ | |
90 | + pageSize: 10, | |
91 | + current: 1, | |
92 | + monthly: monthly || Date.now(), | |
93 | + indicatorCode: indicator?.code || '', | |
94 | + shopId: shopId || undefined, | |
95 | + }); | |
96 | + } | |
97 | + }, [indicator?.code, monthly, shopId]); | |
98 | + return ( | |
99 | + <> | |
100 | + <div style={{ display: 'flex' }}> | |
101 | + <DatePicker value={monthly?moment(monthly):undefined} onChange={pickMonth} picker="month" style={{ marginRight: 20 }} /> | |
102 | + <Select allowClear style={{ width: 200, marginRight: 20 }} placeholder="请选择门店" onChange={shopChange}> | |
103 | + {(data || []).map((shop) => ( | |
104 | + <Select.Option value={shop.id} key={shop.id}> | |
105 | + {shop.name} | |
106 | + </Select.Option> | |
107 | + ))} | |
108 | + </Select> | |
109 | + </div> | |
110 | + <Table columns={columns} {...tableProps} rowKey="id" style={{ marginTop: 20 }} /> | |
111 | + </> | |
112 | + ); | |
113 | +} | ... | ... |
src/pages/performance/DataImport/components/ExcelTable.tsx
0 → 100644
1 | +import React, { useEffect, useState } from 'react'; | |
2 | +import { Table, message, Modal } from 'antd'; | |
3 | +import { UploadImportApi, SaveDataApi } from '../api'; | |
4 | +import { useRequest } from 'ahooks'; | |
5 | +import { ErrorType } from '../entity'; | |
6 | + | |
7 | +import moment from 'moment'; | |
8 | +interface Props { | |
9 | + fid?: string; | |
10 | + show?: boolean; | |
11 | + indicator?: MDataImport.IndicatorList; | |
12 | + setExcelvisible?: (bool: boolean) => void; | |
13 | + refresh?: () => void; | |
14 | +} | |
15 | +export default function ExcelTable({ fid, show, indicator, setExcelvisible, refresh }: Props) { | |
16 | + const { data, run, loading } = useRequest<MDataImport.DataImportList, string[]>(UploadImportApi, { | |
17 | + manual: true, | |
18 | + onError: (e, _) => { | |
19 | + message.error(e.message); | |
20 | + }, | |
21 | + }); | |
22 | + | |
23 | + useEffect(() => { | |
24 | + if (show) { | |
25 | + run(fid || '', indicator?.code || ''); | |
26 | + } | |
27 | + }, [show, fid, indicator]); | |
28 | + const savesubmit = () => { | |
29 | + SaveDataApi({ key: data?.key || '' }) | |
30 | + .then(() => { | |
31 | + message.success('操作成功'); | |
32 | + setExcelvisible?.(false); | |
33 | + refresh?.(); | |
34 | + }) | |
35 | + .catch((error) => { | |
36 | + message.error(error.message); | |
37 | + setExcelvisible?.(false); | |
38 | + }); | |
39 | + }; | |
40 | + const tableItem: any = [ | |
41 | + { | |
42 | + title: '月度', | |
43 | + align: 'center', | |
44 | + width: 100, | |
45 | + dataIndex: 'dataDate', | |
46 | + key: 'dataDate', | |
47 | + render: (time: number) => (time ? moment(time).format('YYYY-MM') : '--'), | |
48 | + }, | |
49 | + { | |
50 | + title: '门店', | |
51 | + dataIndex: 'shopName', | |
52 | + align: 'center', | |
53 | + key: 'shopName', | |
54 | + render: (name: any) => <span>{name || '--'}</span>, | |
55 | + }, | |
56 | + { | |
57 | + title: '打分', | |
58 | + width: 100, | |
59 | + dataIndex: 'score', | |
60 | + align: 'center', | |
61 | + key: 'score', | |
62 | + render: (name: any) => <span>{name || '--'}</span>, | |
63 | + }, | |
64 | + { | |
65 | + title: '总分', | |
66 | + width: 100, | |
67 | + dataIndex: 'totalScore', | |
68 | + align: 'center', | |
69 | + key: 'totalScore', | |
70 | + render: (name: any) => <span>{name || '--'}</span>, | |
71 | + }, | |
72 | + { | |
73 | + title: '打分人员', | |
74 | + width: 100, | |
75 | + dataIndex: 'graderStaffName', | |
76 | + align: 'center', | |
77 | + key: 'graderStaffName', | |
78 | + render: (name: any) => <span>{name || '--'}</span>, | |
79 | + }, | |
80 | + { | |
81 | + title: '是否识别', | |
82 | + width: 100, | |
83 | + dataIndex: 'errorType', | |
84 | + align: 'center', | |
85 | + render: (_: any, record: any) => (record.errorType ? <div>未识别</div> : <div>已识别</div>), | |
86 | + }, | |
87 | + { | |
88 | + title: '未识别原因', | |
89 | + width: 150, | |
90 | + dataIndex: 'errorType', | |
91 | + align: 'center', | |
92 | + render: (_: any, record: any) => (record.errorType ? ErrorType[record.errorType] : '--'), | |
93 | + }, | |
94 | + ]; | |
95 | + return ( | |
96 | + <Modal | |
97 | + open={show} | |
98 | + destroyOnClose | |
99 | + onCancel={() => { | |
100 | + setExcelvisible?.(false); | |
101 | + }} | |
102 | + width="70%" | |
103 | + keyboard | |
104 | + onOk={savesubmit} | |
105 | + > | |
106 | + <Table loading={loading} dataSource={data?.details} columns={tableItem} pagination={{ pageSizeOptions: [10, 20, 50] }} /> | |
107 | + <div> | |
108 | + 成功条数: <span style={{ color: '#20c688' }}>{data?.successNum}</span> 条 | |
109 | + </div> | |
110 | + <div> | |
111 | + 失败条数: <span style={{ color: '#f4333c' }}>{data?.errorNum}</span> 条 | |
112 | + </div> | |
113 | + </Modal> | |
114 | + ); | |
115 | +} | ... | ... |
src/pages/performance/DataImport/components/ImportList.tsx
0 → 100644
1 | +import React, { useEffect, useState, useRef } from 'react'; | |
2 | +import { Table, Button, Tag, message, DatePicker, Select, Modal, Upload, Space, Divider, Popconfirm, Typography } from 'antd'; | |
3 | +import type { UploadProps } from 'antd'; | |
4 | +import type { ColumnsType } from 'antd/es/table'; | |
5 | +import { DataImportAPi, ImportListDetailApi, DownloadApi, deleteApi, revokeApi } from '../api'; | |
6 | +import { useAntdTable } from 'ahooks'; | |
7 | +import moment from 'moment'; | |
8 | +import type { DatePickerProps } from 'antd'; | |
9 | +import useInitial from '@/hooks/useInitail'; | |
10 | +import { getShopApi } from '@/common/api'; | |
11 | +import { SelectStatus } from '../entity'; | |
12 | +import { DownloadOutlined, PlusOutlined } from '@ant-design/icons'; | |
13 | +import { useRequest } from 'ahooks'; | |
14 | +import ApprovalProgressModal from '@/components/ApprovalProgressModal'; | |
15 | +import type { ApprovalProgressModalRef } from '@/components/ApprovalProgressModal'; | |
16 | +import dowloader from '@/utils/downloader'; | |
17 | +import { IMGURL } from '@/utils'; | |
18 | +import ExcelTable from './ExcelTable'; | |
19 | + | |
20 | +type Props = { | |
21 | + indicator?: MDataImport.IndicatorList; | |
22 | +}; | |
23 | +interface DataType { | |
24 | + key: string; | |
25 | + name: string; | |
26 | +} | |
27 | +export default function TableList({ indicator }: Props) { | |
28 | + const [monthly, setMonthly] = useState<number>(); | |
29 | + const [shopId, setShopId] = useState<number>(); | |
30 | + const [status, setStatus] = useState<number>(); | |
31 | + const [fid, setFid] = useState<string>(''); | |
32 | + const [dataVisible, setDataVisible] = useState<boolean>(false); | |
33 | + const [excelvisible, setExcelvisible] = useState<boolean>(false); | |
34 | + const tagColorArr = ['', 'warning', 'processing', 'error', 'success', 'warning']; | |
35 | + | |
36 | + const approvalProgressRef = useRef<ApprovalProgressModalRef | null>(null); | |
37 | + | |
38 | + const upload: UploadProps = { | |
39 | + name: 'file', | |
40 | + action: '/api2/file/upload', | |
41 | + accept: '.xlsx,.xls', | |
42 | + maxCount: 1, | |
43 | + showUploadList: false, | |
44 | + onChange(info) { | |
45 | + if (info.file.status !== 'uploading') { | |
46 | + } | |
47 | + if (info.file.status === 'done') { | |
48 | + setFid(info.file.response.data); | |
49 | + setExcelvisible(true); | |
50 | + } else if (info.file.status === 'error') { | |
51 | + message.error(`${info.file.name} 上传失败`); | |
52 | + } | |
53 | + }, | |
54 | + }; | |
55 | + const viewProcess = (record: MDataImport.DetailedList) => { | |
56 | + approvalProgressRef.current?.setApprovalProgressModalInfo({ | |
57 | + visible: true, | |
58 | + orderNo: record?.approvalNo, | |
59 | + }); | |
60 | + }; | |
61 | + const pickMonth: DatePickerProps['onChange'] = (date, _dateString) => { | |
62 | + setMonthly(date?.valueOf() ?? 0); | |
63 | + }; | |
64 | + function shopChange(value: any) { | |
65 | + setShopId(value); | |
66 | + } | |
67 | + function statusChange(value: any) { | |
68 | + setStatus(value); | |
69 | + } | |
70 | + const { data } = useInitial(getShopApi, [], {}); | |
71 | + //@ts-ignore | |
72 | + const { tableProps, run, refresh } = useAntdTable<any, MDataImport.DataImportListParams[]>(DataImportAPi, { | |
73 | + manual: true, | |
74 | + defaultParams: [ | |
75 | + { | |
76 | + pageSize: 10, | |
77 | + current: 1, | |
78 | + monthly: Date.now(), | |
79 | + indicatorCode: indicator?.code || '', | |
80 | + }, | |
81 | + ], | |
82 | + | |
83 | + onError: (e, _) => { | |
84 | + message.error(e.message); | |
85 | + }, | |
86 | + }); | |
87 | + const { | |
88 | + run: running, | |
89 | + mutate, | |
90 | + loading, | |
91 | + data: list, | |
92 | + } = useRequest<MDataImport.DataImportList, (number | undefined)[]>(ImportListDetailApi, { | |
93 | + manual: true, | |
94 | + onError: (e, _) => { | |
95 | + message.error(e.message); | |
96 | + }, | |
97 | + }); | |
98 | + const deleteData = async (id: number) => { | |
99 | + const param = { id }; | |
100 | + try { | |
101 | + const { success } = await deleteApi(param); | |
102 | + if (success) { | |
103 | + message.success('删除成功'); | |
104 | + refresh(); | |
105 | + } | |
106 | + } catch (error: any) { | |
107 | + message.error(error.message); | |
108 | + } | |
109 | + }; | |
110 | + const revoke = async (id: number) => { | |
111 | + const param = { id }; | |
112 | + try { | |
113 | + const { success } = await revokeApi(param); | |
114 | + if (success) { | |
115 | + message.success('删除成功'); | |
116 | + refresh(); | |
117 | + } | |
118 | + } catch (error: any) { | |
119 | + message.error(error.message); | |
120 | + } | |
121 | + }; | |
122 | + const detailColumns: ColumnsType<DataType> = [ | |
123 | + { | |
124 | + title: '月度', | |
125 | + align: 'center', | |
126 | + dataIndex: 'dataDate', | |
127 | + width: 200, | |
128 | + key: 'dataDate', | |
129 | + render: (time: number) => (time ? moment(time).format('YYYY-MM') : '--'), | |
130 | + }, | |
131 | + { | |
132 | + title: '门店', | |
133 | + align: 'center', | |
134 | + dataIndex: 'shopName', | |
135 | + width: 300, | |
136 | + key: 'shopName', | |
137 | + render: (name) => <span>{name || '--'}</span>, | |
138 | + }, | |
139 | + { | |
140 | + title: '打分', | |
141 | + align: 'center', | |
142 | + dataIndex: 'score', | |
143 | + width: 100, | |
144 | + key: 'score', | |
145 | + render: (name) => <span>{name || '--'}</span>, | |
146 | + }, | |
147 | + { | |
148 | + title: '总分', | |
149 | + align: 'center', | |
150 | + key: 'totalScore', | |
151 | + width: 100, | |
152 | + dataIndex: 'totalScore', | |
153 | + render: (name) => <span>{name || '--'}</span>, | |
154 | + }, | |
155 | + { | |
156 | + title: '打分人员', | |
157 | + align: 'center', | |
158 | + key: 'graderStaffName', | |
159 | + width: 200, | |
160 | + dataIndex: 'graderStaffName', | |
161 | + render: (name) => <span>{name || '--'}</span>, | |
162 | + }, | |
163 | + ]; | |
164 | + const columns: ColumnsType<MDataImport.DetailedList> = [ | |
165 | + { | |
166 | + title: '导入时间', | |
167 | + align: 'center', | |
168 | + width: 300, | |
169 | + dataIndex: 'createTime', | |
170 | + key: 'createTime', | |
171 | + render: (time: number) => (time ? moment(time).format('YYYY-MM-DD hh:mm:ss') : '--'), | |
172 | + }, | |
173 | + { | |
174 | + title: '导入人员', | |
175 | + align: 'center', | |
176 | + width: 300, | |
177 | + dataIndex: 'importUserName', | |
178 | + key: 'importUserName', | |
179 | + render: (name) => <span>{name || '--'}</span>, | |
180 | + }, | |
181 | + | |
182 | + { | |
183 | + title: '导入数据', | |
184 | + align: 'center', | |
185 | + width: 100, | |
186 | + key: 'num', | |
187 | + dataIndex: 'num', | |
188 | + render: (name) => <span>{name + '条' || '--'}</span>, | |
189 | + }, | |
190 | + { | |
191 | + title: '成功', | |
192 | + align: 'center', | |
193 | + width: 100, | |
194 | + key: 'successNum', | |
195 | + dataIndex: 'successNum', | |
196 | + render: (name) => <span>{name + '条' || '--'}</span>, | |
197 | + }, | |
198 | + { | |
199 | + title: '失败', | |
200 | + align: 'center', | |
201 | + width: 100, | |
202 | + key: 'errorNum', | |
203 | + dataIndex: 'errorNum', | |
204 | + render: (name) => <span>{name + '条' || '--'}</span>, | |
205 | + }, | |
206 | + { | |
207 | + title: '数据清单', | |
208 | + align: 'center', | |
209 | + width: 200, | |
210 | + key: 'importUserId', | |
211 | + render: (value, record: MDataImport.DetailedList) => { | |
212 | + return ( | |
213 | + <Button | |
214 | + type="link" | |
215 | + onClick={() => { | |
216 | + { | |
217 | + setDataVisible(true); | |
218 | + running(record?.id); | |
219 | + } | |
220 | + }} | |
221 | + > | |
222 | + 查看 | |
223 | + </Button> | |
224 | + ); | |
225 | + }, | |
226 | + }, | |
227 | + { | |
228 | + title: '状态', | |
229 | + width: 100, | |
230 | + align: 'center', | |
231 | + key: 'status', | |
232 | + dataIndex: 'status', | |
233 | + render: (text: number) => <Tag color={tagColorArr[text]}>{text ? SelectStatus[text] : '--'}</Tag>, | |
234 | + }, | |
235 | + { | |
236 | + title: '操作', | |
237 | + align: 'center', | |
238 | + width: 300, | |
239 | + key: 'tags', | |
240 | + render: (_: any, record: MDataImport.DetailedList) => { | |
241 | + return ( | |
242 | + <Space split={<Divider type="vertical" />}> | |
243 | + {(record.status == 1 || record.status == 3 || record.status == 5) && ( | |
244 | + <Popconfirm title="确定删除,提交后不可更改?" onConfirm={() => deleteData(record?.id || 0)} okText="确定" cancelText="取消"> | |
245 | + <Typography.Link>删除</Typography.Link> | |
246 | + </Popconfirm> | |
247 | + )} | |
248 | + {(record.status == 2 || record.status == 3) && ( | |
249 | + <> | |
250 | + {record.status == 2 && ( | |
251 | + <Popconfirm title="确定撤销,提交后不可更改?" onConfirm={() => revoke(record?.id || 0)} okText="确定" cancelText="取消"> | |
252 | + <Typography.Link>撤销</Typography.Link> | |
253 | + </Popconfirm> | |
254 | + )} | |
255 | + <Typography.Link | |
256 | + onClick={() => { | |
257 | + viewProcess(record); | |
258 | + }} | |
259 | + > | |
260 | + 流程进度 | |
261 | + </Typography.Link> | |
262 | + </> | |
263 | + )} | |
264 | + {record.status == 4 && <div>--</div>} | |
265 | + </Space> | |
266 | + ); | |
267 | + }, | |
268 | + }, | |
269 | + ]; | |
270 | + | |
271 | + useEffect(() => { | |
272 | + if (indicator?.code) { | |
273 | + run({ | |
274 | + pageSize: 10, | |
275 | + current: 1, | |
276 | + monthly: monthly || Date.now(), | |
277 | + indicatorCode: indicator?.code || '', | |
278 | + shopId: shopId || undefined, | |
279 | + status: status || undefined, | |
280 | + }); | |
281 | + } | |
282 | + }, [indicator?.code, monthly, shopId, status]); | |
283 | + return ( | |
284 | + <> | |
285 | + <div style={{ display: 'flex' }}> | |
286 | + <DatePicker value={monthly ? moment(monthly) : undefined} onChange={pickMonth} picker="month" style={{ marginRight: 20 }} /> | |
287 | + <Select allowClear style={{ width: 245, marginRight: 20 }} placeholder="请选择门店" onChange={shopChange}> | |
288 | + {(data || []).map((shop) => ( | |
289 | + <Select.Option value={shop.id} key={shop.id}> | |
290 | + {shop.name} | |
291 | + </Select.Option> | |
292 | + ))} | |
293 | + </Select> | |
294 | + <Select allowClear style={{ width: 120 }} placeholder="状态筛选" onChange={statusChange}> | |
295 | + {[2, 3, 4, 5].map((text: number) => ( | |
296 | + <Select.Option value={text} key={text}> | |
297 | + {SelectStatus[text]} | |
298 | + </Select.Option> | |
299 | + ))} | |
300 | + </Select> | |
301 | + <div style={{ marginLeft: 'auto' }}> | |
302 | + <Button | |
303 | + icon={<DownloadOutlined rev="" />} | |
304 | + type="primary" | |
305 | + onClick={() => { | |
306 | + DownloadApi(indicator?.code) | |
307 | + .then((res) => { | |
308 | + dowloader.downloadFile({ fileUrl: IMGURL.showImage(res) }); | |
309 | + }) | |
310 | + .catch((e) => { | |
311 | + message.error(e.message); | |
312 | + }); | |
313 | + }} | |
314 | + > | |
315 | + 下载模版 | |
316 | + </Button> | |
317 | + <Upload {...upload}> | |
318 | + <Button style={{ marginLeft: 10 }} icon={<PlusOutlined rev="" />} type="primary"> | |
319 | + 导入 | |
320 | + </Button> | |
321 | + </Upload> | |
322 | + </div> | |
323 | + </div> | |
324 | + | |
325 | + <Table rowKey="id" columns={columns} {...tableProps} style={{ marginTop: 20 }} /> | |
326 | + <Modal | |
327 | + title="数据清单" | |
328 | + open={dataVisible} | |
329 | + footer={null} | |
330 | + destroyOnClose | |
331 | + onCancel={() => { | |
332 | + setDataVisible(false); | |
333 | + mutate(undefined); | |
334 | + }} | |
335 | + width="70%" | |
336 | + keyboard | |
337 | + > | |
338 | + <Table | |
339 | + rowKey="id" | |
340 | + loading={loading} | |
341 | + dataSource={list?.details ?? []} | |
342 | + columns={detailColumns} | |
343 | + pagination={{ pageSizeOptions: [10, 20, 50] }} | |
344 | + /> | |
345 | + </Modal> | |
346 | + <ExcelTable refresh={refresh} setExcelvisible={setExcelvisible} show={excelvisible} fid={fid} indicator={indicator} /> | |
347 | + <ApprovalProgressModal ref={approvalProgressRef} /> | |
348 | + </> | |
349 | + ); | |
350 | +} | ... | ... |
src/pages/performance/DataImport/components/exhibitionHallFour.tsx
0 → 100644
1 | +import React, { useState } from 'react'; | |
2 | +import { Radio, Empty } from 'antd'; | |
3 | +import ImportList from './ImportList'; | |
4 | +import DetailList from './DetailList'; | |
5 | + | |
6 | +type Props = { | |
7 | + indicator?: MDataImport.IndicatorList; | |
8 | + onChange?: (value?: any) => void; | |
9 | +}; | |
10 | + | |
11 | +export default function ExhibitionHallFour({ indicator }: Props) { | |
12 | + const [tableType, setTableType] = useState<number>(0); | |
13 | + | |
14 | + return ( | |
15 | + <div style={{ flex: 1, overflowX: 'hidden', marginLeft: 20 }}> | |
16 | + {indicator?.code ? ( | |
17 | + <div> | |
18 | + <div style={{ fontSize: 18, fontWeight: 'bold' }}>{`指标:${indicator?.name ?? '-'}`}</div> | |
19 | + <Radio.Group defaultValue="a" buttonStyle="solid" style={{ marginTop: 15, marginBottom: 20 }}> | |
20 | + <Radio.Button | |
21 | + value="a" | |
22 | + style={{ marginRight: 10 }} | |
23 | + onClick={() => { | |
24 | + setTableType(0); | |
25 | + }} | |
26 | + > | |
27 | + 导入记录 | |
28 | + </Radio.Button> | |
29 | + | |
30 | + <Radio.Button | |
31 | + value="b" | |
32 | + onClick={() => { | |
33 | + setTableType(1); | |
34 | + }} | |
35 | + > | |
36 | + 数据清单 | |
37 | + </Radio.Button> | |
38 | + </Radio.Group> | |
39 | + {tableType === 0 ? <ImportList indicator={indicator} /> : <DetailList indicator={indicator} />} | |
40 | + </div> | |
41 | + ) : ( | |
42 | + <div style={{ marginTop: '25%', display: 'flex', justifyContent: 'center' }}> | |
43 | + <Empty description={'请选择指标'} /> | |
44 | + </div> | |
45 | + )} | |
46 | + </div> | |
47 | + ); | |
48 | +} | ... | ... |
src/pages/performance/DataImport/components/truckloadBank.tsx
0 → 100644
1 | +import React from 'react'; | |
2 | +import { Table, message } from 'antd'; | |
3 | +import { IndicatorListApi } from '../api'; | |
4 | +import { useRequest } from 'ahooks'; | |
5 | + | |
6 | +type Props = { | |
7 | + value?: MDataImport.IndicatorList; | |
8 | + onChange?: (value?: any) => void; | |
9 | +}; | |
10 | +export default function TruckloadBank({ value, onChange }: Props) { | |
11 | + const Column = Table.Column; | |
12 | + const { data } = useRequest<MDataImport.IndicatorList[], never[]>(IndicatorListApi, { | |
13 | + onSuccess: (data, _params) => { | |
14 | + onChange?.(data?.[0]); | |
15 | + }, | |
16 | + onError: (e, _) => { | |
17 | + message.error(e.message); | |
18 | + }, | |
19 | + }); | |
20 | + | |
21 | + return ( | |
22 | + <div style={{ width: 200 }}> | |
23 | + <Table | |
24 | + rowKey="code" | |
25 | + pagination={false} | |
26 | + rowSelection={{ | |
27 | + type: 'radio', | |
28 | + selectedRowKeys: value?.code ? [value.code] : [], | |
29 | + onSelect: (record) => onChange?.(record), | |
30 | + }} | |
31 | + dataSource={data || []} | |
32 | + > | |
33 | + <Column title="指标" dataIndex="name" align="center" render={(text) => text ?? '-'} fixed /> | |
34 | + </Table> | |
35 | + </div> | |
36 | + ); | |
37 | +} | ... | ... |
src/pages/performance/DataImport/entity.ts
0 → 100644
src/pages/performance/DataImport/index.css
0 → 100644
src/pages/performance/DataImport/index.tsx
0 → 100644
1 | +import React, { useState } from 'react'; | |
2 | +import { PageHeaderWrapper } from '@ant-design/pro-layout'; | |
3 | +import { Card } from 'antd'; | |
4 | +import TruckloadBank from './components/truckloadBank'; | |
5 | +import ExhibitionHallFour from './components/exhibitionHallFour'; | |
6 | + | |
7 | +export default () => { | |
8 | + const [indicator, setIndicator] = useState<MDataImport.IndicatorList>(); | |
9 | + const onChange = (value?: MDataImport.IndicatorList) => { | |
10 | + setIndicator(value); | |
11 | + }; | |
12 | + return ( | |
13 | + <PageHeaderWrapper title="自定义数据导入"> | |
14 | + <Card> | |
15 | + <div style={{ display: 'flex' }}> | |
16 | + <TruckloadBank value={indicator} onChange={onChange} /> | |
17 | + <ExhibitionHallFour indicator={indicator} onChange={onChange} /> | |
18 | + </div> | |
19 | + </Card> | |
20 | + </PageHeaderWrapper> | |
21 | + ); | |
22 | +}; | ... | ... |
src/pages/performance/DataImport/interface.d.ts
0 → 100644
1 | +declare namespace MDataImport { | |
2 | + /** | |
3 | + * 展厅美化导入记录分页查询参数 | |
4 | + */ | |
5 | + interface DataImportListParams { | |
6 | + current: number; | |
7 | + pageSize: number; | |
8 | + indicatorCode?: string; | |
9 | + shopId?: number; | |
10 | + monthly?: number; | |
11 | + sorter?: any; | |
12 | + filter?: any; | |
13 | + extra?: any; | |
14 | + [key: string]: any; | |
15 | + } | |
16 | + | |
17 | + /** | |
18 | + * 展厅美化导入记录分页查询数据 | |
19 | + */ | |
20 | + interface DataImportList { | |
21 | + id?: number; | |
22 | + importUserId?: number; | |
23 | + importUserName?: string; | |
24 | + shopId?: number; | |
25 | + shopName?: string; | |
26 | + dimensionType?: string; | |
27 | + indicatorCode?: string; | |
28 | + indicatorName?: string; | |
29 | + valueType?: number; | |
30 | + dataDate?: string; | |
31 | + num?: number; | |
32 | + successNum?: number; | |
33 | + errorNum?: number; | |
34 | + groupId?: number; | |
35 | + createTime?: string; | |
36 | + key?: string; | |
37 | + status?: string; | |
38 | + approvalNo?: string; | |
39 | + dataTimeType?: string; | |
40 | + details?: []; | |
41 | + } | |
42 | + /** | |
43 | + * 数据导入指标列表数据 | |
44 | + */ | |
45 | + interface IndicatorList { | |
46 | + id?: number; | |
47 | + code?: string; | |
48 | + name?: 'melda.sanford'; | |
49 | + } | |
50 | + /** | |
51 | + * 数据清单列表数据 | |
52 | + */ | |
53 | + interface DetailedList { | |
54 | + id?: number; | |
55 | + recordId?: number; | |
56 | + indicatorName?: string; | |
57 | + indicatorCode?: string; | |
58 | + shopId?: number; | |
59 | + shopName?: string; | |
60 | + score?: number; | |
61 | + totalScore?: number; | |
62 | + graderStaffName?: string; | |
63 | + graderStaffId?: number; | |
64 | + stageStartDataDate?: string; | |
65 | + stageEndDataDate?: string; | |
66 | + dataDate?: string; | |
67 | + errorType?: string; | |
68 | + valid?: boolean; | |
69 | + yn?: boolean; | |
70 | + approvalNo?: string; | |
71 | + status: number; | |
72 | + } | |
73 | +} | ... | ... |
src/pages/performance/EvaDataImport/index.tsx
... | ... | @@ -51,7 +51,7 @@ export default () => { |
51 | 51 | } |
52 | 52 | const uploadPerson: UploadProps = { |
53 | 53 | name: 'file', |
54 | - action: '/api/morax/erp/eval-indicator/analysis-staff', | |
54 | + action: '/api/morax/erp/eval-indicator/analysis-staff', | |
55 | 55 | maxCount: 1, |
56 | 56 | showUploadList: false, |
57 | 57 | // 设置headers里的token |
... | ... | @@ -62,6 +62,7 @@ export default () => { |
62 | 62 | } |
63 | 63 | if (info.file.status === 'done') { |
64 | 64 | setFileData(info.file.response.data); |
65 | + | |
65 | 66 | setVisible(true); |
66 | 67 | } else if (info.file.status === 'error') { |
67 | 68 | message.error(`${info.file.name} 上传失败`); | ... | ... |
src/pages/performance/KpiGroupSetting/EditComfirm/components/IndivatorsTable.tsx
... | ... | @@ -199,7 +199,7 @@ const IndivatorsTable = ({ value, onChange, personModal }: Props) => { |
199 | 199 | return _columns; |
200 | 200 | }; |
201 | 201 | const onChangePag = (page: number, pageSize: number) => { |
202 | - console.log(page, pageSize, value); | |
202 | + console.log(page, pageSize, value,'0000000'); | |
203 | 203 | setPage(page - 1); |
204 | 204 | }; |
205 | 205 | return ( | ... | ... |
src/pages/performance/KpiSetting/components/EditModal.tsx
... | ... | @@ -210,7 +210,7 @@ export default function EditModal({ onClose, setItem, item, roleList }: Props) { |
210 | 210 | > |
211 | 211 | {({ getFieldValue }) => { |
212 | 212 | return getFieldValue('roleType') === 3 ? ( |
213 | - <Form.Item name="roles" label="适用角色" rules={[{ required: true }]}> | |
213 | + <Form.Item name="roles" label="适用角色1" rules={[{ required: true }]}> | |
214 | 214 | <Select |
215 | 215 | placeholder="请选择角色" |
216 | 216 | showSearch | ... | ... |