Commit e1dc8b1c3c4a00d4c68e71d471a7a4c5060c8e51

Authored by jiangwei
2 parents 3e90932f e888945d

Merge remote-tracking branch 'origin/master' into cas

Showing 42 changed files with 1492 additions and 223 deletions
config/routers/identify.ts
  1 +/*
  2 + * @Author: wangqiang@feewee.cn
  3 + * @Date: 2022-04-13 09:39:04
  4 + * @LastEditors: wangqiang@feewee.cn
  5 + * @LastEditTime: 2023-02-10 16:21:06
  6 + */
1 7 export default [
2 8 /**
3 9 * 认证系统
... ... @@ -18,4 +24,8 @@ export default [
18 24 path: "/identify/carRecord", //车辆纪录详情
19 25 component: "./identify/CarRecord",
20 26 },
  27 + {
  28 + path: "/identify/audit", // 认证审核
  29 + component: "./identify/IdentifyAudit",
  30 + },
21 31 ];
22 32 \ No newline at end of file
... ...
config/routers/pms.ts
... ... @@ -80,6 +80,10 @@ export default [
80 80 component: './pms/partPlan/CustBuyPlan'
81 81 },
82 82 {
  83 + path: '/pms/partPlan/custBuyPlanProcess', // 客户订件计划进度
  84 + component: './pms/partPlan/CustBuyPlanProcess'
  85 + },
  86 + {
83 87 path: '/pms/partPlan/appointPart', // 指定配件
84 88 component: './pms/partPlan/AppointPart'
85 89 },
... ...
src/components/FeeweeUploadAttachment/index.tsx
1 1 /*
2 2 * @Date: 2021-01-05 14:24:23
3 3 * @LastEditors: wangqiang@feewee.cn
4   - * @LastEditTime: 2022-12-21 09:42:29
  4 + * @LastEditTime: 2023-02-11 16:54:22
5 5 */
6 6 import React, { useEffect, useRef, useState } from "react";
7 7 import { message, Popover, Spin, Upload } from "antd";
... ... @@ -74,7 +74,7 @@ export default function FeeweeUploadAttachment({
74 74 useEffect(() => {
75 75 if (fidList?.length) {
76 76 setLoading(true);
77   - const hide = message.loading("", 0);
  77 + // const hide = message.loading("", 0);
78 78 getFileListDetailApi(fidList)
79 79 .then((res) => {
80 80 setFileList(
... ... @@ -91,7 +91,7 @@ export default function FeeweeUploadAttachment({
91 91 })
92 92 .catch((error: any) => {})
93 93 .finally(() => {
94   - hide();
  94 + // hide();
95 95 setLoading(false);
96 96 });
97 97 }
... ...
src/pages/backlog/TaskConfig/api.ts
1 1 /*
2 2 * @Date: 2021-12-29 15:35:12
3 3 * @LastEditors: wangqiang@feewee.cn
4   - * @LastEditTime: 2022-01-05 17:53:12
  4 + * @LastEditTime: 2023-02-15 17:19:33
5 5 */
6 6 import request from "@/utils/request";
7 7 import { common } from "@/typing/common";
... ... @@ -51,7 +51,8 @@ export interface ListVO {
51 51 customTempPath?: string; // 自定义模板路径
52 52 closeStand?: boolean; // 是否关单站岗
53 53 /** 工作类型 */
54   - workType?:number;
  54 + workType?: number;
  55 + ignoreCount?: boolean; // 忽略未完成待办统计
55 56 }
56 57  
57 58 export function getConfigListApi(params: ListParams): http.PromisePageResp<ListVO> {
... ...
src/pages/backlog/TaskConfig/components/CreateModal.tsx
... ... @@ -50,9 +50,10 @@ export default function CreateModal({
50 50 ...item,
51 51 funcPage: item.funcPage,
52 52 itemName: item.itemName,
53   - dock: item.dock,
54   - exShow: item.exShow,
55   - assess: item.assess,
  53 + dock: checkNull(item.dock) ? true : item.dock,
  54 + exShow: checkNull(item.exShow) ? false : item.exShow,
  55 + assess: checkNull(item.assess) ? true : item.assess,
  56 + ignoreCount: checkNull(item.ignoreCount) ? false : item.ignoreCount,
56 57 itemType: item.itemType || TodoTypeEnum["业务性"],
57 58 listPage: item.listPage,
58 59 detailPage: item.detailPage,
... ... @@ -79,9 +80,6 @@ export default function CreateModal({
79 80 pageParam[obj.key.trim()] = (obj.value || "").trim();
80 81 }
81 82 });
82   - const dock = feildValue.dock;
83   - const assess = feildValue.assess;
84   - const exShow = feildValue.exShow;
85 83 const params = {
86 84 ...feildValue,
87 85 itemName: (feildValue.itemName || "").trim(),
... ... @@ -89,10 +87,6 @@ export default function CreateModal({
89 87 funcPage: (feildValue.funcPage || "").trim(),
90 88 detailPage: (feildValue.detailPage || "").trim(),
91 89 pageParam: JSON.stringify(pageParam),
92   - dock: JSON.parse(dock),
93   - assess: JSON.parse(assess),
94   - exShow: JSON.parse(exShow),
95   - itemCode: item.itemCode,
96 90 id: item.id,
97 91 applySysId: feildValue.applySysId,
98 92 };
... ... @@ -122,8 +116,8 @@ export default function CreateModal({
122 116 <Form
123 117 form={form}
124 118 onFinish={handleSave}
125   - wrapperCol={{ span: 18 }}
126   - labelCol={{ span: 6 }}
  119 + // wrapperCol={{ span: 18 }}
  120 + // labelCol={{ span: 6 }}
127 121 >
128 122 <Form.Item
129 123 label="待办名称"
... ... @@ -152,11 +146,32 @@ export default function CreateModal({
152 146 <Radio value={false}>否</Radio>
153 147 </Radio.Group>
154 148 </Form.Item>
155   - {/* 是否显示切换入口 */}
  149 + <Form.Item noStyle shouldUpdate={(prev, cur) => prev.dock !== cur.dock}>
  150 + {({ getFieldValue }) => {
  151 + const dock = getFieldValue("dock") || false;
  152 + if (dock) {
  153 + return (
  154 + // 是否显示切换入口
  155 + <Form.Item
  156 + label="显示切换入口"
  157 + name="exShow"
  158 + rules={[
  159 + { required: true, message: "请选择是否显示切换入口" },
  160 + ]}
  161 + >
  162 + <Radio.Group>
  163 + <Radio value>是</Radio>
  164 + <Radio value={false}>否</Radio>
  165 + </Radio.Group>
  166 + </Form.Item>
  167 + );
  168 + } else return null;
  169 + }}
  170 + </Form.Item>
156 171 <Form.Item
157   - label="显示切换入口"
158   - name="exShow"
159   - rules={[{ required: true, message: "请选择是否显示切换入口" }]}
  172 + label="待办时效考核"
  173 + name="assess"
  174 + rules={[{ required: true, message: "请选择是否对接待办时效考核" }]}
160 175 >
161 176 <Radio.Group>
162 177 <Radio value>是</Radio>
... ... @@ -164,9 +179,9 @@ export default function CreateModal({
164 179 </Radio.Group>
165 180 </Form.Item>
166 181 <Form.Item
167   - label="待办时效考核"
168   - name="assess"
169   - rules={[{ required: true, message: "请选择是否对接待办时效考核" }]}
  182 + label="忽略未完成待办统计"
  183 + name="ignoreCount"
  184 + rules={[{ required: true, message: "请选择是否忽略未完成待办统计" }]}
170 185 >
171 186 <Radio.Group>
172 187 <Radio value>是</Radio>
... ... @@ -189,9 +204,7 @@ export default function CreateModal({
189 204  
190 205 <Form.Item
191 206 noStyle
192   - shouldUpdate={(pre, cur) =>
193   - pre.dock !== cur.dock || pre.itemType !== cur.itemType
194   - }
  207 + shouldUpdate={(pre, cur) => pre.dock !== cur.dock || pre.itemType !== cur.itemType}
195 208 >
196 209 {({ getFieldValue }) => {
197 210 const dock = getFieldValue("dock");
... ... @@ -218,11 +231,9 @@ export default function CreateModal({
218 231  
219 232 <Form.Item
220 233 noStyle
221   - shouldUpdate={(pre, cur) =>
222   - pre.customTemp !== cur.customTemp ||
  234 + shouldUpdate={(pre, cur) => pre.customTemp !== cur.customTemp ||
223 235 pre.dock !== cur.dock ||
224   - pre.itemType !== cur.itemType
225   - }
  236 + pre.itemType !== cur.itemType}
226 237 >
227 238 {({ getFieldValue }) => {
228 239 const dock = getFieldValue("dock");
... ... @@ -255,11 +266,9 @@ export default function CreateModal({
255 266  
256 267 <Form.Item
257 268 noStyle
258   - shouldUpdate={(pre, cur) =>
259   - pre.dock !== cur.dock ||
  269 + shouldUpdate={(pre, cur) => pre.dock !== cur.dock ||
260 270 pre.itemType !== cur.itemType ||
261   - pre.customTemp !== cur.customTemp
262   - }
  271 + pre.customTemp !== cur.customTemp}
263 272 >
264 273 {({ getFieldValue }) => {
265 274 const dock = getFieldValue("dock");
... ... @@ -337,9 +346,7 @@ export default function CreateModal({
337 346  
338 347 <Form.Item
339 348 noStyle
340   - shouldUpdate={(pre, cur) =>
341   - pre.itemType !== cur.itemType || pre.customTemp !== cur.customTemp
342   - }
  349 + shouldUpdate={(pre, cur) => pre.itemType !== cur.itemType || pre.customTemp !== cur.customTemp}
343 350 >
344 351 {({ getFieldValue }) => {
345 352 const itemType = getFieldValue("itemType");
... ...
src/pages/capital/ReceiveRules/api.ts
1 1 import request from '@/utils/request';
2 2 import { AMS_HOST } from '@/utils/host';
3 3 import { http } from '@/typing/http';
  4 +import { Params } from '@/typing/common';
4 5  
5 6 export function getGoodsAuthApi(): http.PromiseResp<OdSetting.Setting[]> {
6 7 return request.get(`${AMS_HOST}/erp/standard/get/auth`);
... ... @@ -22,14 +23,27 @@ export function deleteShopAuth(authId: number) {
22 23 /**逐条保存资产授权 */
23 24 export function addSingleAuth(params: OdSetting.GoodsAuthList) {
24 25 return request.post(`${AMS_HOST}/erp/standard/auth/save`, params);
25   -}
  26 +}
  27 +/**逐条保存资产授权校验 */
  28 +export function addSingleAuthCheck(params: OdSetting.GoodsAuthList): http.PromisePageResp<OdSetting.AuthCheckResult> {
  29 + return request.post(`${AMS_HOST}/erp/standard/auth/save/check`, params);
  30 +}
26 31  
27 32 /**按物品纬度授权 */
28 33 export function saveGoodsDimension(param: OdSetting.saveGoodsParams) {
29 34 return request.post(`${AMS_HOST}/erp/standard/asset/auth/batch/save`, param);
30 35 }
  36 +/**按物品纬度授权校验 */
  37 +export function saveGoodsDimensionCheck(param: OdSetting.saveGoodsParams): http.PromisePageResp<OdSetting.AuthCheckResult> {
  38 + return request.post(`${AMS_HOST}/erp/standard/asset/auth/batch/check`, param);
  39 +}
31 40  
32 41 /**按岗位纬度授权 */
33 42 export function savePostDimension(param: OdSetting.savePostParams) {
34 43 return request.post(`${AMS_HOST}/erp/standard/post/auth/save`, param);
  44 +}
  45 +
  46 +/**按岗位纬度授权校验 */
  47 +export function savePostDimensionCheck(param: OdSetting.saveGoodsParams | Params): http.PromisePageResp<OdSetting.AuthCheckResult> {
  48 + return request.post(`${AMS_HOST}/erp/standard/post/auth/check`, param);
35 49 }
36 50 \ No newline at end of file
... ...
src/pages/capital/ReceiveRules/component/AddStandard.tsx
... ... @@ -28,7 +28,7 @@ export default function AddStandard({ value = {}, onChange, disabled }: Props) {
28 28 disabled
29 29 placeholder="选择物品名称"
30 30 addonAfter={
31   - <Button type='link' onClick={() => setVisible(true)}>选择</Button>
  31 + <Button type="link" onClick={() => setVisible(true)}>选择</Button>
32 32 }
33 33 />
34 34 {!disabled && visible && (
... ...
src/pages/capital/ReceiveRules/component/AuthCheckResult.tsx 0 → 100644
  1 +import React, { useState } from 'react';
  2 +import { Card, Table } from 'antd';
  3 +import Column from 'antd/lib/table/Column';
  4 +import RenderGoodsSpec from '@/pages/capital/components/RenderGoodsSpec';
  5 +import { AssetTypeEnum, PeriodTypeEnum } from '@/pages/capital/entity';
  6 +
  7 +interface Props {
  8 + data: any
  9 +}
  10 +export default function AuthCheckResult({ data }: Props) {
  11 + return (
  12 + <Table
  13 + dataSource={data.data}
  14 + style={{ marginTop: 20 }}
  15 + // loading={loading}
  16 + // pagination={paginationConfig}
  17 + scroll={{ y: "65vh" }}
  18 + rowKey="id"
  19 + size="small"
  20 + >
  21 + <Column title="物品名称" dataIndex="name" />
  22 + <Column title="物品编码" dataIndex="code" />
  23 + <Column
  24 + title="型号规格"
  25 + dataIndex="spec"
  26 + width="16%"
  27 + ellipsis
  28 + render={(text, record) => <RenderGoodsSpec specList={text && JSON.parse(text)} />}
  29 + />
  30 + <Column
  31 + title="物品类型"
  32 + dataIndex="type"
  33 + render={(value) => (
  34 + <span>{AssetTypeEnum[value]}</span>
  35 + )}
  36 + />
  37 + <Column title="门店" dataIndex="shopName" />
  38 + <Column title="岗位" dataIndex="postName" />
  39 + <Column title="最大领用数量" dataIndex="maxNum" />
  40 + <Column
  41 + title="领用周期"
  42 + dataIndex="period"
  43 + render={(text, record: OdSetting.GoodsAuthList) => <span>{text ? `${text}${record.periodType && PeriodTypeEnum[record.periodType]}` : '--'}</span>}
  44 + />
  45 + </Table>
  46 + );
  47 +}
... ...
src/pages/capital/ReceiveRules/interface.d.ts
... ... @@ -54,4 +54,17 @@ declare namespace OdSetting {
54 54 shopId?: number;
55 55 shopName?: string;
56 56 }
  57 +
  58 + interface AuthCheckResult {
  59 + standardId: number;
  60 + name: string;
  61 + type: number;
  62 + code: string;
  63 + spec: string;
  64 + shopName: string;
  65 + postName: string;
  66 + maxNum: number;
  67 + periodType: number;
  68 + period: number;
  69 + }
57 70 }
58 71 \ No newline at end of file
... ...
src/pages/capital/ReceiveRules/subPages/GoodsDimension/components/PageAuthEdit/index.tsx
1 1 import React, { useState } from 'react';
2 2 import { PageHeaderWrapper } from '@ant-design/pro-layout';
3   -import { Card, Table, Popconfirm, Input, Button, message, Divider, Row } from 'antd';
4   -import { PlusOutlined } from '@ant-design/icons';
  3 +import { Card, Table, Popconfirm, Modal, Button, message, Divider, Row } from 'antd';
  4 +import { PlusOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
5 5 import Column from 'antd/lib/table/Column';
6 6 import AddModal from '@/pages/capital/ReceiveRules/component/AddAuthItems';
7 7 import RenderGoodsSpec from '@/pages/capital/components/RenderGoodsSpec';
8   -import { getGoodsAuthDetail, deleteShopAuth, addSingleAuth } from '@/pages/capital/ReceiveRules/api';
  8 +import { getGoodsAuthDetail, deleteShopAuth, addSingleAuthCheck, addSingleAuth } from '@/pages/capital/ReceiveRules/api';
9 9 import usePagination from '@/hooks/usePagination';
10 10 import { PeriodTypeEnum } from '@/pages/capital/entity';
11 11 import ShopSelectNew from '@/components/ShopSelectNew';
12 12 import PostSelectNew from '@/components/PostSelectNew';
13 13 import { Value } from '@/components/ShopSelectNew/api';
  14 +import AuthCheckResult from '@/pages/capital/ReceiveRules/component/AuthCheckResult';
14 15  
15 16 interface Props {
16 17 match?: any
... ... @@ -53,6 +54,26 @@ export default function SpecConfig(props: Props) {
53 54 ...val,
54 55 standardId: id,
55 56 };
  57 + addSingleAuthCheck({ ...params, pageSize: 1000 }).then(res => {
  58 + if (res.data && res.data.total) {
  59 + Modal.confirm({
  60 + title: '已有授权信息,继续提交将覆盖以下授权',
  61 + icon: <ExclamationCircleOutlined />,
  62 + width: 700,
  63 + content: <AuthCheckResult data={res.data} />,
  64 + okText: '提交',
  65 + cancelText: '取消',
  66 + onOk: () => onSubmit(params)
  67 + });
  68 + } else {
  69 + onSubmit(params);
  70 + }
  71 + }).catch(e => {
  72 + message.error(e.message);
  73 + });
  74 + }
  75 +
  76 + function onSubmit(params: any) {
56 77 addSingleAuth(params).then(res => {
57 78 message.success('保存成功');
58 79 setLoading(true);
... ...
src/pages/capital/ReceiveRules/subPages/GoodsDimension/components/RenderSelectGoos.tsx
... ... @@ -9,8 +9,13 @@ interface GoodsProps {
9 9 onChange?: Function;
10 10 value?: any;
11 11 }
12   -function RenderSelectGoos({ onChange, value=[] }: GoodsProps) {
  12 +function RenderSelectGoos({ onChange, value = [] }: GoodsProps) {
13 13 const [goodsModal, setGoodsModal] = useState({ visible: false });
  14 + function deleteItem(code: string) {
  15 + const newData = value.filter((i: any) => i.code !== code);
  16 + onChange && onChange(newData);
  17 + }
  18 +
14 19 return (
15 20 <Card>
16 21 <Row justify="end" style={{ marginBottom: 10 }}>
... ... @@ -32,8 +37,8 @@ function RenderSelectGoos({ onChange, value=[] }: GoodsProps) {
32 37 render={(value, record) => {
33 38 return (
34 39 <>
35   - <Popconfirm title="确认取消?" onConfirm={() => { }}>
36   - <Button type="link" onClick={() => edit(value)}>
  40 + <Popconfirm title="确认删除?" onConfirm={() => deleteItem(value.code)}>
  41 + <Button type="link">
37 42 删除
38 43 </Button>
39 44 </Popconfirm>
... ...
src/pages/capital/ReceiveRules/subPages/GoodsDimension/index.tsx
1 1 import React, { useState } from 'react';
2   -import { Form, message, Card, Button, Row, Col, Input } from 'antd';
  2 +import { Form, message, Card, Button, Row, Col, Input, Modal } from 'antd';
3 3 import { PageHeaderWrapper } from '@ant-design/pro-layout';
4 4 import * as api from '../../api';
5 5 import AuthTableList from './components/AuthTableList';
6 6 import { history } from 'umi';
7 7 import RenderSelectGoos from './components/RenderSelectGoos';
8   -
  8 +import { ExclamationCircleOutlined } from '@ant-design/icons';
  9 +import AuthCheckResult from '@/pages/capital/ReceiveRules/component/AuthCheckResult';
  10 +// import modal from 'antd/lib/modal';
  11 +// const { confirm } = Modal;
9 12 const formItemLayout =
10 13 {
11 14 labelCol: { span: 4 },
... ... @@ -31,6 +34,30 @@ export default function Index(props: Props) {
31 34 })),
32 35 };
33 36 setConfirmloading(true);
  37 + api.saveGoodsDimensionCheck({ ...params, pageSize: 1000 }).then(res => {
  38 + if (res.data && res.data?.total) {
  39 + Modal.confirm({
  40 + title: '已有授权信息,继续提交将覆盖以下授权',
  41 + icon: <ExclamationCircleOutlined />,
  42 + width: 700,
  43 + content: <AuthCheckResult data={res.data} />,
  44 + okText: '确认',
  45 + cancelText: '取消',
  46 + onOk: () => onSubmit(params),
  47 + });
  48 + } else {
  49 + // message.success('保存成功');
  50 + // history.goBack();
  51 + onSubmit(params);
  52 + }
  53 + }).catch(e => {
  54 + message.error(e.message);
  55 + }).finally(() => {
  56 + setConfirmloading(false);
  57 + });
  58 + }
  59 +
  60 + function onSubmit(params: any) {
34 61 api.saveGoodsDimension(params).then(res => {
35 62 message.success('保存成功');
36 63 history.goBack();
... ...
src/pages/capital/ReceiveRules/subPages/PostDimension/index.tsx
1 1 import React, { useState } from 'react';
2   -import { Form, Select, message, Card, Row, Col, Button } from 'antd';
  2 +import { Form, Select, message, Card, Row, Col, Button, Modal } from 'antd';
3 3 import { PageHeaderWrapper } from '@ant-design/pro-layout';
4 4 import * as api from '../../api';
5 5 import AuthTableList from './AuthTableList';
6 6 import PostSelectNew from '@/components/PostSelectNew';
  7 +import { ExclamationCircleOutlined } from '@ant-design/icons';
  8 +import AuthCheckResult from '@/pages/capital/ReceiveRules/component/AuthCheckResult';
  9 +import modal from 'antd/lib/modal';
7 10  
8 11 interface Props {
9 12 visible: boolean;
... ... @@ -22,7 +25,6 @@ export default function EditModal(props: Props) {
22 25 };
23 26  
24 27 function saveCh(feildValue: any) {
25   - setConfirmloading(true);
26 28 const params = {
27 29 postId: feildValue.postId.value,
28 30 postName: feildValue.postId.label,
... ... @@ -35,12 +37,36 @@ export default function EditModal(props: Props) {
35 37 }
36 38 }))
37 39 };
  40 + setConfirmloading(true);
  41 + api.savePostDimensionCheck({...params, pageSize: 1000}).then(res => {
  42 + if (res.data && res.data.total) {
  43 + Modal.confirm({
  44 + title: '已有授权信息,继续提交将覆盖以下授权',
  45 + icon: <ExclamationCircleOutlined />,
  46 + width: 700,
  47 + content: <AuthCheckResult data={res.data} />,
  48 + okText: '提交',
  49 + cancelText: '取消',
  50 + onOk: () => handSubmit(params),
  51 + onCancel: () => setConfirmloading(false),
  52 + });
  53 + } else {
  54 + handSubmit(params);
  55 + }
  56 + }).catch(e => {
  57 + message.error(e.message);
  58 + setConfirmloading(false);
  59 + });
  60 + }
  61 +
  62 + function handSubmit(params: any) {
38 63 api.savePostDimension(params).then(res => {
39 64 message.success('保存成功');
40 65 setConfirmloading(false);
41 66 history.back();
42 67 }).catch(e => {
43 68 message.error(e.message);
  69 + }).finally(() => {
44 70 setConfirmloading(false);
45 71 });
46 72 }
... ...
src/pages/capital/ReceiveRules/subPages/ShopsDimension/index.tsx
1 1 import React, { useState } from 'react';
2 2 import { PageHeaderWrapper } from '@ant-design/pro-layout';
3   -import { Card, Table, Popconfirm, Button, message, Divider, Row, Tag } from 'antd';
  3 +import { Card, Table, Popconfirm, Button, message, Divider, Row, Modal, Tag } from 'antd';
4 4 import * as api from '../../api';
5   -import { PlusOutlined } from '@ant-design/icons';
  5 +import { PlusOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
6 6 import Column from 'antd/lib/table/Column';
7 7 import AddModal from '@/pages/capital/ReceiveRules/component/AddAuthItems';
8 8 import Filter from './components/Filter';
9 9 import RenderGoodsSpec from '@/pages/capital/components/RenderGoodsSpec';
10 10 import usePagination from '@/hooks/usePagination';
11 11 import { AssetTypeEnum, PeriodTypeEnum } from '@/pages/capital/entity';
  12 +import AuthCheckResult from '@/pages/capital/ReceiveRules/component/AuthCheckResult';
12 13  
13 14 export default function SpecConfig() {
14 15 const { list, loading, setLoading, setParams, paginationConfig } = usePagination(api.getShopPostAuthApi, {});
... ... @@ -42,15 +43,36 @@ export default function SpecConfig() {
42 43 ...val,
43 44 standardId: val.standardId.id
44 45 };
  46 + api.addSingleAuthCheck({ ...params, pageSize: 1000 }).then(res => {
  47 + if (res.data && res.data.total) {
  48 + Modal.confirm({
  49 + title: '已有授权信息,继续提交将覆盖以下授权',
  50 + icon: <ExclamationCircleOutlined />,
  51 + width: 700,
  52 + content: <AuthCheckResult data={res.data} />,
  53 + okText: '提交',
  54 + cancelText: '取消',
  55 + onOk: () => onSubmit(params)
  56 + });
  57 + } else {
  58 + onSubmit(params);
  59 + }
  60 + }).catch(e => {
  61 + message.error(e.message);
  62 + });
  63 + }
  64 +
  65 + function onSubmit(params: any) {
45 66 api.addSingleAuth(params).then(res => {
46 67 message.success('保存成功');
47 68 setLoading(true);
48 69 setModalPa({ visible: false, rowValue: undefined });
49 70 }).catch(e => {
50 71 message.error(e.message);
  72 + }).finally(() => {
  73 + // setConfirmloading(false);
51 74 });
52 75 }
53   -
54 76 return (
55 77 <PageHeaderWrapper
56 78 title="门店维度授权"
... ...
src/pages/ehr/Authentication/Manage/components/Filter.tsx
... ... @@ -2,12 +2,32 @@
2 2 * @Author: wangqiang@feewee.cn
3 3 * @Date: 2022-11-24 20:18:39
4 4 * @LastEditors: wangqiang@feewee.cn
5   - * @LastEditTime: 2022-11-26 17:12:55
  5 + * @LastEditTime: 2023-02-14 09:25:39
6 6 */
7   -import { Row } from "antd";
  7 +import FeeweeFilterOption from "@/pages/notice/components/FeeweeFilterOption";
  8 +import { Input, Row } from "antd";
  9 +import { debounce } from "lodash";
8 10 import React from "react";
9 11 import { useStore } from "../index";
10 12  
11 13 export default function AuthenticationManageFilter() {
12   - return <Row style={{ display: "flex", flexDirection: "column" }} />;
  14 + const { pagination } = useStore();
  15 +
  16 + const searchName = debounce(
  17 + (name: string) => pagination.setParams({ name, current: 1 }, true),
  18 + 500
  19 + );
  20 +
  21 + return (
  22 + <Row>
  23 + <FeeweeFilterOption title="人员名称">
  24 + <Input
  25 + allowClear
  26 + placeholder="请输入人员名称"
  27 + onChange={(e) => searchName(e.target.value)}
  28 + style={{ minWidth: 260, marginBottom: 10 }}
  29 + />
  30 + </FeeweeFilterOption>
  31 + </Row>
  32 + );
13 33 }
... ...
src/pages/identify/CarRecord/index.tsx
1 1 import React, { useState } from "react";
2   -import { Card, Table, Button, Modal, Input, Badge, Popconfirm, Row, Col, Image, message } from "antd";
  2 +import {
  3 + Card,
  4 + Table,
  5 + Button,
  6 + Modal,
  7 + Input,
  8 + Badge,
  9 + Popconfirm,
  10 + Row,
  11 + Col,
  12 + Image,
  13 + message,
  14 + Select,
  15 +} from "antd";
3 16 import { PageHeaderWrapper } from "@ant-design/pro-layout";
4 17 import usePagination from "@/hooks/usePagination";
5 18 import { debounce } from "lodash";
... ... @@ -7,20 +20,28 @@ import { CarRecordListApi, removeApi } from &quot;./api&quot;;
7 20 import ProDescriptions from "@ant-design/pro-descriptions";
8 21 import { CopyOutlined } from "@ant-design/icons";
9 22 import moment from "moment";
10   -import { BadgeIcon, StatusEnum } from "@/pages/identify/entity";
  23 +import {
  24 + BadgeIcon,
  25 + StatusEnum,
  26 + useIdentifyInfoListHook,
  27 +} from "@/pages/identify/entity";
11 28 import { placeholderImage } from "@/utils";
12 29 import copy from "copy-to-clipboard";
  30 +import FeeweeFilterOption from "@/pages/notice/components/FeeweeFilterOption";
13 31  
14 32 const Column = Table.Column;
15 33 const Search = Input.Search;
16 34 export default function EmployeeRecord() {
17   - const { list, loading, paginationConfig, setParams, setLoading } = usePagination<EmployeeRecord.ListVO>(CarRecordListApi, {}, {});
  35 + const { list, loading, paginationConfig, setParams, setLoading } =
  36 + usePagination<EmployeeRecord.ListVO>(CarRecordListApi, {}, {});
18 37 const [currentFile, setCurrentFile] = useState<string[]>([]);
19 38 const [filesView, setFilesView] = useState<boolean>(false);
20 39  
21 40 const [extraData, setExtraData] = useState<string>();
22 41 const [extraDataVisible, setExtraDataVisible] = useState<boolean>(false);
23 42  
  43 + const { Databases } = useIdentifyInfoListHook();
  44 +
24 45 //按手机号搜索
25 46 const searchVin = debounce((val: string) => {
26 47 setParams({ vin: val.trim(), current: 1 }, true);
... ... @@ -28,8 +49,8 @@ export default function EmployeeRecord() {
28 49  
29 50 //按认证码搜索;
30 51 const searchCode = debounce((val: string) => {
31   - setParams({ identifyCode: val.trim(), current: 1 }, true);
32   - }, 500);
  52 + setParams({ identifyCode: val, current: 1 }, true);
  53 + }, 0);
33 54  
34 55 return (
35 56 <PageHeaderWrapper title="车辆认证记录">
... ... @@ -44,23 +65,51 @@ export default function EmployeeRecord() {
44 65 }}
45 66 >
46 67 <div style={{ display: "flex" }}>
47   - <Search
48   - allowClear
49   - placeholder="vin码"
50   - onChange={(e) => searchVin(e.target.value)}
51   - style={{ maxWidth: 260, marginRight: 15 }}
52   - />
53   - <Search
54   - allowClear
55   - placeholder="认证码"
56   - onChange={(e) => searchCode(e.target.value)}
57   - style={{ maxWidth: 260, marginRight: 15 }}
58   - />
  68 + <FeeweeFilterOption title="vin码">
  69 + <Search
  70 + allowClear
  71 + placeholder="vin码"
  72 + onChange={(e) => searchVin(e.target.value)}
  73 + style={{ maxWidth: 260, marginRight: 15 }}
  74 + />
  75 + </FeeweeFilterOption>
  76 + <div style={{ width: 10 }} />
  77 + <FeeweeFilterOption title="资料项">
  78 + <Select
  79 + allowClear
  80 + placeholder="请选择资料项"
  81 + showSearch
  82 + optionFilterProp="children"
  83 + onChange={(identifyCode: string) => searchCode(identifyCode)}
  84 + style={{
  85 + minWidth: 260,
  86 + marginRight: 10,
  87 + marginBottom: 10,
  88 + }}
  89 + getPopupContainer={(triggerNode) => triggerNode.parentNode}
  90 + >
  91 + {Databases.map((data) => (
  92 + <Select.Option key={data.code} value={data.code}>
  93 + {data.name}
  94 + </Select.Option>
  95 + ))}
  96 + </Select>
  97 + </FeeweeFilterOption>
59 98 </div>
60 99 </div>
61   - <Table dataSource={list} pagination={paginationConfig} rowKey="id" loading={loading}>
  100 + <Table
  101 + dataSource={list}
  102 + pagination={paginationConfig}
  103 + rowKey="id"
  104 + loading={loading}
  105 + >
62 106 <Column title="资料代码" dataIndex="identifyCode" align="center" />
63   - <Column title="资料名称" dataIndex="identifyName" align="center" render={(text) => text || "-"} />
  107 + <Column
  108 + title="资料名称"
  109 + dataIndex="identifyName"
  110 + align="center"
  111 + render={(text) => text || "-"}
  112 + />
64 113 <Column title="vin码" dataIndex="vin" align="center" />
65 114 <Column
66 115 title="生效时间"
... ... @@ -112,7 +161,12 @@ export default function EmployeeRecord() {
112 161 align="center"
113 162 render={(status) => {
114 163 if (typeof status === "number") {
115   - return <Badge status={BadgeIcon[status + 1]} text={StatusEnum[status]} />;
  164 + return (
  165 + <Badge
  166 + status={BadgeIcon[status + 1]}
  167 + text={StatusEnum[status]}
  168 + />
  169 + );
116 170 }
117 171 return "-";
118 172 }}
... ... @@ -131,7 +185,7 @@ export default function EmployeeRecord() {
131 185 title="是否删除此项?"
132 186 onConfirm={() => {
133 187 removeApi(record.id!);
134   - setLoading(true)
  188 + setLoading(true);
135 189 }}
136 190 okText="确定"
137 191 cancelText="取消"
... ... @@ -194,9 +248,15 @@ export default function EmployeeRecord() {
194 248 <ProDescriptions
195 249 title="额外数据:"
196 250 tooltip="点击旁边复制按钮可复制数据到剪切板"
197   - extra={<CopyOutlined onClick={() => extraData && copy(extraData) && message.success("复制成功")} />}
  251 + extra={
  252 + <CopyOutlined
  253 + onClick={() => extraData && copy(extraData) && message.success("复制成功")}
  254 + />
  255 + }
198 256 >
199   - <ProDescriptions.Item valueType="jsonCode">{extraData}</ProDescriptions.Item>
  257 + <ProDescriptions.Item valueType="jsonCode">
  258 + {extraData}
  259 + </ProDescriptions.Item>
200 260 </ProDescriptions>
201 261 </Modal>
202 262 </PageHeaderWrapper>
... ...
src/pages/identify/EmployeeRecord/index.tsx
1 1 import React, { useState } from "react";
2   -import { Card, Table, Button, Modal, Input, Badge, Popconfirm, Row, Col, Image, message } from "antd";
  2 +import {
  3 + Card,
  4 + Table,
  5 + Button,
  6 + Modal,
  7 + Input,
  8 + Badge,
  9 + Popconfirm,
  10 + Row,
  11 + Col,
  12 + Image,
  13 + message,
  14 + Select,
  15 +} from "antd";
3 16 import { PageHeaderWrapper } from "@ant-design/pro-layout";
4 17 import usePagination from "@/hooks/usePagination";
5 18 import { debounce } from "lodash";
6 19 import { EmployeeRecordListApi, removeApi } from "./api";
7   -import ProDescriptions from '@ant-design/pro-descriptions';
  20 +import ProDescriptions from "@ant-design/pro-descriptions";
8 21 import { CopyOutlined } from "@ant-design/icons";
9   -import moment from 'moment';
10   -import { BadgeIcon, StatusEnum } from "@/pages/identify/entity";
11   -import { placeholderImage } from '@/utils';
12   -import copy from 'copy-to-clipboard';
  22 +import moment from "moment";
  23 +import { BadgeIcon, StatusEnum, useIdentifyInfoListHook } from "@/pages/identify/entity";
  24 +import { placeholderImage } from "@/utils";
  25 +import copy from "copy-to-clipboard";
  26 +import FeeweeFilterOption from "@/pages/notice/components/FeeweeFilterOption";
13 27  
14 28 const Column = Table.Column;
15 29 const Search = Input.Search;
16 30 export default function EmployeeRecord() {
17   - const { list, loading, paginationConfig, setParams, setLoading } = usePagination<EmployeeRecord.ListVO>(
18   - EmployeeRecordListApi,
19   - {},
20   - {}
21   - );
  31 + const { list, loading, paginationConfig, setParams, setLoading } =
  32 + usePagination<EmployeeRecord.ListVO>(EmployeeRecordListApi, {}, {});
22 33 const [currentFile, setCurrentFile] = useState<string[]>([]);
23 34 const [filesView, setFilesView] = useState<boolean>(false);
24 35  
25   - const [extraData, setExtraData] = useState<string>();
26   - const [extraDataVisible, setExtraDataVisible] = useState<boolean>(false);
  36 + const [extraData, setExtraData] = useState<string>();
  37 + const [extraDataVisible, setExtraDataVisible] = useState<boolean>(false);
  38 +
  39 + const { Databases } = useIdentifyInfoListHook();
27 40  
28 41 //按手机号搜索
29 42 const searchPhone = debounce((val: string) => {
... ... @@ -37,8 +50,8 @@ export default function EmployeeRecord() {
37 50  
38 51 //按认证码搜索;
39 52 const searchCode = debounce((val: string) => {
40   - setParams({ identifyCode: val.trim(), current: 1 }, true);
41   - }, 500);
  53 + setParams({ identifyCode: val, current: 1 }, true);
  54 + }, 0);
42 55  
43 56 return (
44 57 <PageHeaderWrapper title="员工认证记录">
... ... @@ -53,29 +66,60 @@ export default function EmployeeRecord() {
53 66 }}
54 67 >
55 68 <div style={{ display: "flex" }}>
56   - <Search
57   - allowClear
58   - placeholder="手机号"
59   - onChange={(e) => searchPhone(e.target.value)}
60   - style={{ maxWidth: 260, marginRight: 15 }}
61   - />
62   - <Search
63   - allowClear
64   - placeholder="员工id"
65   - onChange={(e) => searchStaffId(e.target.value)}
66   - style={{ maxWidth: 260, marginRight: 15 }}
67   - />
68   - <Search
69   - allowClear
70   - placeholder="认证码"
71   - onChange={(e) => searchCode(e.target.value)}
72   - style={{ maxWidth: 260, marginRight: 15 }}
73   - />
  69 + <FeeweeFilterOption title="手机号">
  70 + <Search
  71 + allowClear
  72 + placeholder="手机号"
  73 + onChange={(e) => searchPhone(e.target.value)}
  74 + style={{ maxWidth: 260, marginRight: 15 }}
  75 + />
  76 + </FeeweeFilterOption>
  77 + <div style={{ width: 10 }} />
  78 + <FeeweeFilterOption title="员工ID">
  79 + <Search
  80 + allowClear
  81 + placeholder="会员ID"
  82 + onChange={(e) => searchStaffId(e.target.value)}
  83 + style={{ maxWidth: 260, marginRight: 15 }}
  84 + />
  85 + </FeeweeFilterOption>
  86 + <div style={{ width: 10 }} />
  87 + <FeeweeFilterOption title="资料项">
  88 + <Select
  89 + allowClear
  90 + placeholder="请选择资料项"
  91 + showSearch
  92 + optionFilterProp="children"
  93 + onChange={(identifyCode: string) => searchCode(identifyCode)}
  94 + style={{
  95 + minWidth: 260,
  96 + marginRight: 10,
  97 + marginBottom: 10,
  98 + }}
  99 + getPopupContainer={(triggerNode) => triggerNode.parentNode}
  100 + >
  101 + {Databases.map((data) => (
  102 + <Select.Option key={data.code} value={data.code}>
  103 + {data.name}
  104 + </Select.Option>
  105 + ))}
  106 + </Select>
  107 + </FeeweeFilterOption>
74 108 </div>
75 109 </div>
76   - <Table dataSource={list} pagination={paginationConfig} rowKey="id" loading={loading}>
  110 + <Table
  111 + dataSource={list}
  112 + pagination={paginationConfig}
  113 + rowKey="id"
  114 + loading={loading}
  115 + >
77 116 <Column title="资料代码" dataIndex="identifyCode" align="center" />
78   - <Column title="资料名称" dataIndex="identifyName" align="center" render={(text) => text || "-"} />
  117 + <Column
  118 + title="资料名称"
  119 + dataIndex="identifyName"
  120 + align="center"
  121 + render={(text) => text || "-"}
  122 + />
79 123 <Column title="员工编号" dataIndex="staffId" align="center" />
80 124 <Column title="员工名称" dataIndex="staffName" align="center" />
81 125 <Column
... ... @@ -128,7 +172,12 @@ export default function EmployeeRecord() {
128 172 align="center"
129 173 render={(status) => {
130 174 if (typeof status === "number") {
131   - return <Badge status={BadgeIcon[status + 1]} text={StatusEnum[status]} />;
  175 + return (
  176 + <Badge
  177 + status={BadgeIcon[status + 1]}
  178 + text={StatusEnum[status]}
  179 + />
  180 + );
132 181 }
133 182 return "-";
134 183 }}
... ... @@ -210,9 +259,15 @@ export default function EmployeeRecord() {
210 259 <ProDescriptions
211 260 title="额外数据:"
212 261 tooltip="点击旁边复制按钮可复制数据到剪切板"
213   - extra={<CopyOutlined onClick={() => extraData && copy(extraData) && message.success("复制成功")} />}
  262 + extra={
  263 + <CopyOutlined
  264 + onClick={() => extraData && copy(extraData) && message.success("复制成功")}
  265 + />
  266 + }
214 267 >
215   - <ProDescriptions.Item valueType="jsonCode">{extraData}</ProDescriptions.Item>
  268 + <ProDescriptions.Item valueType="jsonCode">
  269 + {extraData}
  270 + </ProDescriptions.Item>
216 271 </ProDescriptions>
217 272 </Modal>
218 273 </PageHeaderWrapper>
... ...
src/pages/identify/IdentifyAudit/api.ts 0 → 100644
  1 +/*
  2 + * @Author: wangqiang@feewee.cn
  3 + * @Date: 2023-02-10 16:04:36
  4 + * @LastEditors: wangqiang@feewee.cn
  5 + * @LastEditTime: 2023-02-11 10:21:47
  6 + */
  7 +import request from "@/utils/request";
  8 +import { IDENTIFY_HOST } from "@/utils/host";
  9 +import { http } from "@/typing/http";
  10 +
  11 +/**
  12 + * @description: 获取认证审核列表
  13 + * @param {IdentifyAudit.QueryParams} params
  14 + * @return {http.PromisePageResp<IdentifyAudit.List>}
  15 + */
  16 +export function getIdentifyAuditListApi(
  17 + params: IdentifyAudit.QueryParams
  18 +): http.PromisePageResp<IdentifyAudit.List> {
  19 + return request.get(`${IDENTIFY_HOST}/audit/page/list`, { params });
  20 +}
  21 +
  22 +/**
  23 + * @description: 认证审核
  24 + * @param {IdentifyAudit.SaveData} params
  25 + * @return {http.PromiseResp<string>}
  26 + */
  27 +export function submitIdentifyAuditApi(
  28 + params: IdentifyAudit.SaveData
  29 +): http.PromiseResp<string> {
  30 + return request.post(`${IDENTIFY_HOST}/audit/apply`, params);
  31 +}
  32 +
  33 +/**
  34 + * @description: 根据资料项码获取资料项额外参数配置列表
  35 + * @param {string} identifyCode
  36 + * @return {http.PromiseRespA<IdentifyAudit.ExpandItem>}
  37 + */
  38 +export function getIdentifyItemExpandInfoListApi(
  39 + identifyCode?: string
  40 +): http.PromiseRespA<IdentifyAudit.ExpandItem> {
  41 + return request.get(`${IDENTIFY_HOST}/identify/expand/list`, {
  42 + params: { identifyCode },
  43 + });
  44 +}
  45 +
  46 +/**
  47 + * @description: 获取额外参数类型枚举对象
  48 + * @return {http.PromiseResp<IdentifyAudit.ExpandTypeItem>}
  49 + */
  50 +export function getExpandTypesApi(): http.PromiseResp<IdentifyAudit.ExpandTypeItem> {
  51 + return request.get(`${IDENTIFY_HOST}/identify/expand/types`);
  52 +}
... ...
src/pages/identify/IdentifyAudit/components/List.tsx 0 → 100644
  1 +import React from "react";
  2 +import { Button, message, Modal, Table } from "antd";
  3 +import { useStore } from "../index";
  4 +import moment from "moment";
  5 +import ProDescriptions from "@ant-design/pro-descriptions";
  6 +import { CopyOutlined } from "@ant-design/icons";
  7 +import copy from "copy-to-clipboard";
  8 +import DetailItem from '@/pages/ehr/Authentication/Settings/components/DetailItem';
  9 +import FeeweeUploadAttachment from '@/components/FeeweeUploadAttachment';
  10 +
  11 +export default function IdentifyAuditList() {
  12 + const {
  13 + pagination,
  14 + Type,
  15 + extraDataModal,
  16 + setExtraDataModal,
  17 + setCurrent,
  18 + setOpen,
  19 + } = useStore();
  20 + return (
  21 + <>
  22 + <Table
  23 + dataSource={pagination.list}
  24 + loading={pagination.loading}
  25 + pagination={pagination.paginationConfig}
  26 + rowKey="id"
  27 + >
  28 + <Table.Column title="资料编码" dataIndex="identifyCode" align="left" />
  29 + <Table.Column title="资料名称" dataIndex="identifyName" align="left" />
  30 + {pagination.innerParams.type === Type.会员认证 ? (
  31 + <Table.Column title="会员号" dataIndex="memberId" align="left" />
  32 + ) : null}
  33 + {pagination.innerParams.type === Type.员工认证 ? (
  34 + <Table.Column title="员工ID" dataIndex="staffId" align="left" />
  35 + ) : null}
  36 + {pagination.innerParams.type === Type.车辆认证 ? (
  37 + <Table.Column title="VIN" dataIndex="vin" align="left" />
  38 + ) : null}
  39 + <Table.Column
  40 + title="额外资料"
  41 + dataIndex="extraData"
  42 + align="left"
  43 + render={(extraData: string, record: IdentifyAudit.List) => (
  44 + <Button
  45 + type="link"
  46 + onClick={() => {
  47 + setExtraDataModal({
  48 + visible: true,
  49 + data: extraData,
  50 + fids: record.fids,
  51 + });
  52 + }}
  53 + >
  54 + 查看
  55 + </Button>
  56 + )}
  57 + />
  58 + <Table.Column
  59 + title="操作"
  60 + align="left"
  61 + render={(record: IdentifyAudit.List) => (
  62 + <a
  63 + onClick={() => {
  64 + setCurrent(record);
  65 + setOpen(true);
  66 + }}
  67 + >
  68 + 审核
  69 + </a>
  70 + )}
  71 + />
  72 + </Table>
  73 + <Modal
  74 + title="额外数据"
  75 + visible={extraDataModal.visible}
  76 + footer={null}
  77 + destroyOnClose
  78 + onCancel={() => {
  79 + setExtraDataModal({ visible: false });
  80 + }}
  81 + width={450}
  82 + keyboard
  83 + >
  84 + <ProDescriptions
  85 + title="额外数据:"
  86 + tooltip="点击旁边复制按钮可复制数据到剪切板"
  87 + extra={
  88 + <CopyOutlined
  89 + onClick={() => extraDataModal.data &&
  90 + copy(extraDataModal.data) &&
  91 + message.success("复制成功")}
  92 + />
  93 + }
  94 + >
  95 + <ProDescriptions.Item valueType="jsonCode">
  96 + {extraDataModal.data}
  97 + </ProDescriptions.Item>
  98 + </ProDescriptions>
  99 + <DetailItem
  100 + title="附件"
  101 + desp={
  102 + <div style={{ flex: 1, width: "85%" }}>
  103 + <FeeweeUploadAttachment
  104 + fidList={extraDataModal?.fids?.split(",")}
  105 + disabled
  106 + style={{ flex: 1 }}
  107 + />
  108 + </div>
  109 + }
  110 + />
  111 + </Modal>
  112 + </>
  113 + );
  114 +}
... ...
src/pages/identify/IdentifyAudit/components/Modal.tsx 0 → 100644
  1 +/*
  2 + * @Author: wangqiang@feewee.cn
  3 + * @Date: 2023-02-10 17:52:44
  4 + * @LastEditors: wangqiang@feewee.cn
  5 + * @LastEditTime: 2023-02-11 16:46:04
  6 + */
  7 +import {
  8 + Button,
  9 + DatePicker,
  10 + Divider,
  11 + Form,
  12 + Input,
  13 + message,
  14 + Modal,
  15 + Spin,
  16 +} from "antd";
  17 +import React, { useEffect, useState } from "react";
  18 +import { useStore } from "../index";
  19 +import ProDescriptions from "@ant-design/pro-descriptions";
  20 +import {
  21 + getIdentifyItemExpandInfoListApi,
  22 + submitIdentifyAuditApi,
  23 +} from "@/pages/identify/IdentifyAudit/api";
  24 +import moment from "moment";
  25 +import FeeweeUploadAttachment from "@/components/FeeweeUploadAttachment";
  26 +import DetailItem from "@/pages/ehr/Authentication/Settings/components/DetailItem";
  27 +
  28 +const REMARK_KEY = "fw_other_remark";
  29 +
  30 +export default function IdentifyAuditModal() {
  31 + const { open, setOpen, current, setCurrent, Types, pagination, Type } =
  32 + useStore();
  33 + const [editData, setEditData] = useState<IdentifyAudit.ExpandItem[]>([]);
  34 + const [form] = Form.useForm();
  35 + const [loading, setLoading] = useState(false);
  36 +
  37 + useEffect(() => {
  38 + if (open) {
  39 + if (current?.identifyCode && current?.extraData) {
  40 + setLoading(true);
  41 + getIdentifyItemExpandInfoListApi(current.identifyCode)
  42 + .then((res) => {
  43 + const expandListData = res.data || [];
  44 + const _editData: IdentifyAudit.ExpandItem[] = [];
  45 + const extraData: { [key: string]: string } = JSON.parse(
  46 + current.extraData!
  47 + );
  48 + const keys = Object.keys(extraData);
  49 + const fields = {};
  50 + for (let key of keys) {
  51 + const item = expandListData.find((i) => i.name === key);
  52 + _editData.push({
  53 + name: key,
  54 + data: extraData[key],
  55 + ...(item || {}),
  56 + });
  57 + const value =
  58 + item?.type && Types[item.type] === "Date"
  59 + ? moment(extraData[key])
  60 + : extraData[key];
  61 + fields[key] = value;
  62 + }
  63 +
  64 + form.setFieldsValue(fields);
  65 + setEditData(_editData);
  66 + setLoading(false);
  67 + })
  68 + .catch((error) => {
  69 + console.error(error.message);
  70 + message.error("初始化认证审核表单失败");
  71 + setEditData([]);
  72 + setLoading(false);
  73 + });
  74 + }
  75 + }
  76 + }, [open, current]);
  77 +
  78 + const cancel = () => {
  79 + setCurrent(undefined);
  80 + setOpen(false);
  81 + };
  82 +
  83 + const submit = (pass: boolean) => {
  84 + form.validateFields().then((val) => {
  85 + const remark = val[REMARK_KEY];
  86 + delete val[REMARK_KEY];
  87 + for (let key of Object.keys(val)) {
  88 + if (typeof val[key] === "object") {
  89 + val[key] = moment(val[key]).format("YYYY-MM-DD HH:mm:ss");
  90 + }
  91 + }
  92 + const auditData = JSON.stringify(val);
  93 + setLoading(true);
  94 + submitIdentifyAuditApi({ id: current?.id, pass, auditData, remark })
  95 + .then((res) => {
  96 + message.success(res.result);
  97 + setLoading(false);
  98 + cancel();
  99 + pagination.setLoading(true);
  100 + })
  101 + .catch((error) => {
  102 + setLoading(false);
  103 + message.error(error.message || "保存认证审核失败");
  104 + });
  105 + });
  106 + };
  107 +
  108 + return (
  109 + <Modal
  110 + title="认证审核"
  111 + open={open}
  112 + onCancel={cancel}
  113 + footer={[
  114 + <Button loading={loading} onClick={cancel}>
  115 + 取消
  116 + </Button>,
  117 + <Button
  118 + loading={loading}
  119 + type="primary"
  120 + danger
  121 + onClick={() => submit(false)}
  122 + >
  123 + 拒绝
  124 + </Button>,
  125 + <Button loading={loading} type="primary" onClick={() => submit(true)}>
  126 + 通过
  127 + </Button>,
  128 + ]}
  129 + width="50%"
  130 + maskClosable={false}
  131 + afterClose={() => {
  132 + form.resetFields();
  133 + }}
  134 + >
  135 + <ProDescriptions column={2}>
  136 + <ProDescriptions.Item label="资料编码">
  137 + {current?.identifyCode || "-"}
  138 + </ProDescriptions.Item>
  139 + <ProDescriptions.Item label="资料名称">
  140 + {current?.identifyName || "-"}
  141 + </ProDescriptions.Item>
  142 + {pagination.innerParams?.type === Type.会员认证 ? (
  143 + <ProDescriptions.Item label="会员ID">
  144 + {current?.memberId || "-"}
  145 + </ProDescriptions.Item>
  146 + ) : null}
  147 + {pagination.innerParams?.type === Type.员工认证 ? (
  148 + <ProDescriptions.Item label="员工ID">
  149 + {current?.staffId || "-"}
  150 + </ProDescriptions.Item>
  151 + ) : null}
  152 + {pagination.innerParams?.type === Type.车辆认证 ? (
  153 + <ProDescriptions.Item label="VIN">
  154 + {current?.vin || "-"}
  155 + </ProDescriptions.Item>
  156 + ) : null}
  157 + <ProDescriptions.Item label="审核原因">
  158 + <span style={{ color: "red" }}>{current?.verify || "-"}</span>
  159 + </ProDescriptions.Item>
  160 + </ProDescriptions>
  161 +
  162 + <DetailItem
  163 + title="附件"
  164 + desp={
  165 + <div style={{ flex: 1, width: "85%" }}>
  166 + <FeeweeUploadAttachment
  167 + fidList={current?.fids?.split(",")}
  168 + disabled
  169 + style={{ flex: 1 }}
  170 + />
  171 + </div>
  172 + }
  173 + />
  174 + <Divider orientation="left">可编辑审核数据如下</Divider>
  175 + <Spin spinning={loading}>
  176 + <Form form={form}>
  177 + {editData.map((data) => (
  178 + <Form.Item
  179 + name={data.name}
  180 + label={data.label || data.name}
  181 + rules={[
  182 + { required: !!data.label, message: `${data.label}不能为空` },
  183 + ]}
  184 + >
  185 + {data.type && Types[data.type] === "Date" ? (
  186 + // @ts-ignore
  187 + <DatePicker
  188 + style={{ width: "100%" }}
  189 + allowClear
  190 + format="YYYY-MM-DD HH:mm:ss"
  191 + placeholder={`请选择${data.label || data.name}`}
  192 + />
  193 + ) : (
  194 + <Input
  195 + allowClear
  196 + placeholder={`请输入${data.label || data.name}`}
  197 + />
  198 + )}
  199 + </Form.Item>
  200 + ))}
  201 + <Divider />
  202 + <Form.Item name={REMARK_KEY} label="备注信息">
  203 + <Input.TextArea
  204 + allowClear
  205 + autoSize={{ minRows: 2 }}
  206 + placeholder="请输入备注信息"
  207 + />
  208 + </Form.Item>
  209 + </Form>
  210 + </Spin>
  211 + </Modal>
  212 + );
  213 +}
... ...
src/pages/identify/IdentifyAudit/index.tsx 0 → 100644
  1 +/*
  2 + * @Author: wangqiang@feewee.cn
  3 + * @Date: 2023-02-10 16:04:31
  4 + * @LastEditors: wangqiang@feewee.cn
  5 + * @LastEditTime: 2023-02-11 16:34:35
  6 + */
  7 +import React from "react";
  8 +import { Card, ConfigProvider, Input, Radio, Row, Select } from "antd";
  9 +import zhCN from "antd/lib/locale-provider/zh_CN";
  10 +import { PageHeaderWrapper } from "@ant-design/pro-layout";
  11 +import { createStore } from "@/hooks/moz";
  12 +import store from "./store";
  13 +import List from "./components/List";
  14 +import Modal from "./components/Modal";
  15 +import FeeweeFilterOption from "@/pages/notice/components/FeeweeFilterOption";
  16 +import { debounce } from "lodash";
  17 +
  18 +export const { Provider, useStore } = createStore(store);
  19 +
  20 +function IdentifyAudit() {
  21 + const { pagination, Type, Databases } = useStore();
  22 +
  23 + const search = debounce(
  24 + (params: IdentifyAudit.QueryParams) => pagination.setParams({ ...params, current: 1 }, true),
  25 + 500
  26 + );
  27 +
  28 + return (
  29 + <PageHeaderWrapper title="认证审核">
  30 + <ConfigProvider locale={zhCN}>
  31 + <Card bordered={false}>
  32 + <Row align="bottom">
  33 + <Radio.Group
  34 + value={pagination.innerParams.type}
  35 + buttonStyle="solid"
  36 + style={{ marginRight: 10, marginBottom: 10 }}
  37 + onChange={(e) => pagination.setParams({ type: e.target.value, current: 1 }, true)}
  38 + >
  39 + <Radio.Button value={Type.会员认证}>会员认证</Radio.Button>
  40 + <Radio.Button value={Type.员工认证}>员工认证</Radio.Button>
  41 + <Radio.Button value={Type.车辆认证}>车辆认证</Radio.Button>
  42 + </Radio.Group>
  43 + <FeeweeFilterOption title="资料项">
  44 + <Select
  45 + allowClear
  46 + placeholder="请选择资料项"
  47 + showSearch
  48 + optionFilterProp="children"
  49 + onChange={(identifyCode: string) => pagination.setParams({ identifyCode, current: 1 }, true)}
  50 + style={{
  51 + minWidth: 260,
  52 + marginRight: 10,
  53 + marginBottom: 10,
  54 + }}
  55 + getPopupContainer={(triggerNode) => triggerNode.parentNode}
  56 + >
  57 + {Databases.map((data) => (
  58 + <Select.Option key={data.code} value={data.code}>
  59 + {data.name}
  60 + </Select.Option>
  61 + ))}
  62 + </Select>
  63 + </FeeweeFilterOption>
  64 + {pagination.innerParams.type === Type.会员认证 ? (
  65 + <>
  66 + <FeeweeFilterOption title="会员ID">
  67 + <Input
  68 + allowClear
  69 + placeholder="请输入会员ID"
  70 + style={{ minWidth: 260, marginBottom: 10, marginRight: 10 }}
  71 + onChange={(e) => search({ memberId: e.target.value })}
  72 + />
  73 + </FeeweeFilterOption>
  74 + <div style={{ width: 10 }} />
  75 + </>
  76 + ) : null}
  77 + {pagination.innerParams.type === Type.员工认证 ? (
  78 + <>
  79 + <FeeweeFilterOption title="员工ID">
  80 + <Input
  81 + allowClear
  82 + placeholder="请输入员工ID"
  83 + style={{ minWidth: 260, marginBottom: 10, marginRight: 10 }}
  84 + onChange={(e) => search({ staffId: e.target.value })}
  85 + />
  86 + </FeeweeFilterOption>
  87 + <div style={{ width: 10 }} />
  88 + </>
  89 + ) : null}
  90 + {pagination.innerParams.type === Type.车辆认证 ? (
  91 + <FeeweeFilterOption title="车辆VIN">
  92 + <Input
  93 + allowClear
  94 + placeholder="请输入车辆VIN"
  95 + style={{ minWidth: 260, marginBottom: 10, marginRight: 10 }}
  96 + onChange={(e) => search({ vin: e.target.value })}
  97 + />
  98 + </FeeweeFilterOption>
  99 + ) : null}
  100 + </Row>
  101 + <List />
  102 + <Modal />
  103 + </Card>
  104 + </ConfigProvider>
  105 + </PageHeaderWrapper>
  106 + );
  107 +}
  108 +
  109 +export default () => (
  110 + // @ts-ignore
  111 + <Provider>
  112 + <IdentifyAudit />
  113 + </Provider>
  114 +);
... ...
src/pages/identify/IdentifyAudit/interface.d.ts 0 → 100644
  1 +declare namespace IdentifyAudit {
  2 + interface QueryParams {
  3 + type?: number; // 类型 1会员 2员工 3车辆
  4 + memberId?: string; // 会员ID
  5 + staffId?: string; // 员工ID
  6 + vin?: string; // vin
  7 + identifyCode?: string; // 认证编码
  8 + }
  9 +
  10 + interface List {
  11 + id?: number;
  12 + identifyCode?: string; // 标识码
  13 + identifyName?: string; // 资料名称
  14 + type?: number; // 审核类型 1会员 2员工 3车辆
  15 + memberId?: number;
  16 + memberName?: string;
  17 + staffId?: number;
  18 + staffName?: string;
  19 + vin?: string;
  20 + effectiveDate?: number; // 生效时间
  21 + expireDate?: number; // 过期时间
  22 + extraId?: number; // 审核额外数据id
  23 + extraData?: string; // 审核数据(Json字符串)
  24 + fids?: string; // 审核附件
  25 + verify?: string; // 校验备注
  26 + status?: number; // 状态 1 待审核 2通过 3拒绝
  27 + remark?: string; // 备注
  28 + createTime?: number; //创建时间
  29 + }
  30 +
  31 + interface SaveData {
  32 + id?: number; // 审核ID
  33 + pass?: boolean; // 是否通过
  34 + auditData?: string; // 审核后数据(Json字符串)
  35 + remark?: string; // 备注
  36 + }
  37 +
  38 + interface ExpandItem {
  39 + id?: string;
  40 + label?: string; // 拓展标签
  41 + name?: string; // 拓展名
  42 + type?: number; // 拓展类型
  43 + data?: string; // 可编辑数据,非接口返回字段
  44 + }
  45 +
  46 + interface ExpandTypeItem {
  47 + [key: number]: string;
  48 + }
  49 +}
... ...
src/pages/identify/IdentifyAudit/store.ts 0 → 100644
  1 +/*
  2 + * @Author: wangqiang@feewee.cn
  3 + * @Date: 2023-02-10 16:04:41
  4 + * @LastEditors: wangqiang@feewee.cn
  5 + * @LastEditTime: 2023-02-11 15:29:42
  6 + */
  7 +import usePagination from "@/hooks/usePagination";
  8 +import { useIdentifyInfoListHook } from "@/pages/identify/entity";
  9 +import {
  10 + getIdentifyAuditListApi,
  11 + getExpandTypesApi,
  12 +} from "@/pages/identify/IdentifyAudit/api";
  13 +import { message } from "antd";
  14 +import { useEffect, useState } from "react";
  15 +
  16 +export default function useStore() {
  17 + const pagination = usePagination(getIdentifyAuditListApi, { type: 1 });
  18 + const { Databases } = useIdentifyInfoListHook();
  19 + const [Types, setTypes] = useState<IdentifyAudit.ExpandTypeItem>({});
  20 + const [current, setCurrent] = useState<IdentifyAudit.List>();
  21 + const [open, setOpen] = useState(false);
  22 + const [extraDataModal, setExtraDataModal] = useState<{
  23 + visible: boolean;
  24 + data?: string;
  25 + fids?: string;
  26 + }>({ visible: false });
  27 +
  28 + enum Type {
  29 + "会员认证" = 1,
  30 + "员工认证",
  31 + "车辆认证",
  32 + }
  33 +
  34 + useEffect(() => {
  35 + initTypes();
  36 + }, []);
  37 +
  38 + function initTypes() {
  39 + getExpandTypesApi()
  40 + .then((res) => {
  41 + setTypes(res.data || {});
  42 + })
  43 + .catch((error) => {
  44 + message.error(error.message || "查询扩展参数枚举失败");
  45 + setTypes({});
  46 + });
  47 + }
  48 +
  49 + return {
  50 + pagination,
  51 + Databases,
  52 + Types,
  53 + current,
  54 + setCurrent,
  55 + open,
  56 + setOpen,
  57 + extraDataModal,
  58 + setExtraDataModal,
  59 + Type,
  60 + };
  61 +}
... ...
src/pages/identify/MemberRecord/index.tsx
1 1 import React, { useState } from "react";
2   -import { Card, Table, Button, Image, Modal, Input, Row, Col, Badge, message, Popconfirm } from "antd";
  2 +import {
  3 + Card,
  4 + Table,
  5 + Button,
  6 + Image,
  7 + Modal,
  8 + Input,
  9 + Row,
  10 + Col,
  11 + Badge,
  12 + message,
  13 + Popconfirm,
  14 + Select,
  15 +} from "antd";
3 16 import { PageHeaderWrapper } from "@ant-design/pro-layout";
4 17 import ProDescriptions from "@ant-design/pro-descriptions";
5 18 import usePagination from "@/hooks/usePagination";
... ... @@ -9,22 +22,25 @@ import { placeholderImage } from &quot;@/utils&quot;;
9 22 import moment from "moment";
10 23 import copy from "copy-to-clipboard";
11 24 import { CopyOutlined } from "@ant-design/icons";
12   -import { BadgeIcon, StatusEnum } from "@/pages/identify/entity";
  25 +import {
  26 + BadgeIcon,
  27 + StatusEnum,
  28 + useIdentifyInfoListHook,
  29 +} from "@/pages/identify/entity";
  30 +import FeeweeFilterOption from "@/pages/notice/components/FeeweeFilterOption";
13 31  
14 32 const Column = Table.Column;
15 33 const Search = Input.Search;
16 34  
17 35 export default function MemberRecord() {
18   - const { list, loading, paginationConfig, setParams, setLoading } = usePagination<MemberRecord.ListVO>(
19   - MemberRecordListApi,
20   - {},
21   - {}
22   - );
  36 + const { list, loading, paginationConfig, setParams, setLoading } =
  37 + usePagination<MemberRecord.ListVO>(MemberRecordListApi, {}, {});
23 38 const [currentFile, setCurrentFile] = useState<string[]>([]);
24 39 const [filesView, setFilesView] = useState<boolean>(false);
25 40  
26 41 const [extraData, setExtraData] = useState<string>();
27 42 const [extraDataVisible, setExtraDataVisible] = useState<boolean>(false);
  43 + const { Databases } = useIdentifyInfoListHook();
28 44  
29 45 //按手机号搜索
30 46 const searchPhone = debounce((val: string) => {
... ... @@ -38,19 +54,19 @@ export default function MemberRecord() {
38 54  
39 55 //按认证码搜索;
40 56 const searchCode = debounce((val: string) => {
41   - setParams({ identifyCode: val.trim(), current: 1 }, true);
42   - }, 500);
  57 + setParams({ identifyCode: val, current: 1 }, true);
  58 + }, 0);
43 59  
44 60 // 删除认证记录
45 61 const removeMemberReord = debounce((val: number) => {
46 62 removeMemberRecordApi(val)
47   - .then(res => {
48   - message.success(res.result);
49   - setLoading(true);
50   - })
51   - .catch(e => {
52   - message.error(e.message);
53   - });
  63 + .then((res) => {
  64 + message.success(res.result);
  65 + setLoading(true);
  66 + })
  67 + .catch((e) => {
  68 + message.error(e.message);
  69 + });
54 70 }, 500);
55 71  
56 72 return (
... ... @@ -66,31 +82,62 @@ export default function MemberRecord() {
66 82 }}
67 83 >
68 84 <div style={{ display: "flex" }}>
69   - <Search
70   - allowClear
71   - placeholder="手机号"
72   - onChange={(e) => searchPhone(e.target.value)}
73   - style={{ maxWidth: 260, marginRight: 15 }}
74   - />
75   - <Search
76   - allowClear
77   - placeholder="会员ID"
78   - onChange={(e) => searchMemberId(e.target.value)}
79   - style={{ maxWidth: 260, marginRight: 15 }}
80   - />
81   - <Search
82   - allowClear
83   - placeholder="认证码"
84   - onChange={(e) => searchCode(e.target.value)}
85   - style={{ maxWidth: 260, marginRight: 15 }}
86   - />
  85 + <FeeweeFilterOption title="手机号">
  86 + <Search
  87 + allowClear
  88 + placeholder="手机号"
  89 + onChange={(e) => searchPhone(e.target.value)}
  90 + style={{ maxWidth: 260, marginRight: 15 }}
  91 + />
  92 + </FeeweeFilterOption>
  93 + <div style={{ width: 10 }} />
  94 + <FeeweeFilterOption title="会员ID">
  95 + <Search
  96 + allowClear
  97 + placeholder="会员ID"
  98 + onChange={(e) => searchMemberId(e.target.value)}
  99 + style={{ maxWidth: 260, marginRight: 15 }}
  100 + />
  101 + </FeeweeFilterOption>
  102 + <div style={{ width: 10 }} />
  103 + <FeeweeFilterOption title="资料项">
  104 + <Select
  105 + allowClear
  106 + placeholder="请选择资料项"
  107 + showSearch
  108 + optionFilterProp="children"
  109 + onChange={(identifyCode: string) => searchCode(identifyCode)}
  110 + style={{
  111 + minWidth: 260,
  112 + marginRight: 10,
  113 + marginBottom: 10,
  114 + }}
  115 + getPopupContainer={(triggerNode) => triggerNode.parentNode}
  116 + >
  117 + {Databases.map((data) => (
  118 + <Select.Option key={data.code} value={data.code}>
  119 + {data.name}
  120 + </Select.Option>
  121 + ))}
  122 + </Select>
  123 + </FeeweeFilterOption>
87 124 </div>
88 125 </div>
89   - <Table dataSource={list} pagination={paginationConfig} rowKey="id" loading={loading}>
  126 + <Table
  127 + dataSource={list}
  128 + pagination={paginationConfig}
  129 + rowKey="id"
  130 + loading={loading}
  131 + >
90 132 <Column title="资料代码" dataIndex="identifyCode" align="center" />
91   - <Column title="资料名称" dataIndex="identifyName" align="center" render={(text) => text || "-"} />
  133 + <Column
  134 + title="资料名称"
  135 + dataIndex="identifyName"
  136 + align="center"
  137 + render={(text) => text || "-"}
  138 + />
92 139 <Column title="会员号" dataIndex="memberId" align="center" />
93   - <Column title="会员称" dataIndex="memberName" align="center" />
  140 + <Column title="会员称" dataIndex="memberName" align="center" />
94 141 <Column
95 142 title="生效时间"
96 143 dataIndex="effectiveDate"
... ... @@ -141,7 +188,12 @@ export default function MemberRecord() {
141 188 align="center"
142 189 render={(status) => {
143 190 if (typeof status === "number") {
144   - return <Badge status={BadgeIcon[status + 1]} text={StatusEnum[status]} />;
  191 + return (
  192 + <Badge
  193 + status={BadgeIcon[status + 1]}
  194 + text={StatusEnum[status]}
  195 + />
  196 + );
145 197 }
146 198 return "-";
147 199 }}
... ... @@ -220,9 +272,15 @@ export default function MemberRecord() {
220 272 <ProDescriptions
221 273 title="额外数据:"
222 274 tooltip="点击旁边复制按钮可复制数据到剪切板"
223   - extra={<CopyOutlined onClick={() => extraData && copy(extraData) && message.success("复制成功")} />}
  275 + extra={
  276 + <CopyOutlined
  277 + onClick={() => extraData && copy(extraData) && message.success("复制成功")}
  278 + />
  279 + }
224 280 >
225   - <ProDescriptions.Item valueType="jsonCode">{extraData}</ProDescriptions.Item>
  281 + <ProDescriptions.Item valueType="jsonCode">
  282 + {extraData}
  283 + </ProDescriptions.Item>
226 284 </ProDescriptions>
227 285 </Modal>
228 286 </PageHeaderWrapper>
... ...
src/pages/identify/databaseConfig/components/List.tsx
... ... @@ -42,7 +42,7 @@ export default function List() {
42 42 <Column title="资料名称" dataIndex="name" align="center" />
43 43 <Column
44 44 title="适用范围"
45   - width="25%"
  45 + width="15%"
46 46 dataIndex="applySysList"
47 47 ellipsis
48 48 align="center"
... ... @@ -67,7 +67,7 @@ export default function List() {
67 67 align="center"
68 68 render={(classifyType: number) => classifies[classifyType] || ''}
69 69 />
70   - <Column title="上传是否压缩" dataIndex="compress" align="center" render={(value) => (value ? "是" : "否")} />
  70 + <Column title="是否压缩" dataIndex="compress" align="center" render={(value) => (value ? "是" : "否")} />
71 71 <Column
72 72 title="示例资料"
73 73 dataIndex="exampleUri"
... ... @@ -97,6 +97,7 @@ export default function List() {
97 97 <Column
98 98 title="操作"
99 99 align="center"
  100 + width="10%"
100 101 render={(text, record: Database.ListVO) => (
101 102 <>
102 103 <Button
... ...
src/pages/identify/entity.ts
1   -import { PresetStatusColorType } from 'antd/lib/_util/colors';
  1 +import { PresetStatusColorType } from "antd/lib/_util/colors";
  2 +import { useEffect, useState } from "react";
  3 +import { DatabaseListApi } from "@/pages/identify/databaseConfig/api";
  4 +import { message } from "antd";
2 5  
3   -export const BadgeIcon: PresetStatusColorType[] = ["error", "success", "processing"];
  6 +export const BadgeIcon: PresetStatusColorType[] = [
  7 + "error",
  8 + "success",
  9 + "processing",
  10 +];
4 11  
5 12 export enum StatusEnum {
6 13 "已过期" = -1,
7 14 "待生效",
8 15 "已生效",
9   -}
10 16 \ No newline at end of file
  17 +}
  18 +
  19 +export function useIdentifyInfoListHook() {
  20 + const [Databases, setDatabases] = useState<
  21 + { code?: string; name?: string }[]
  22 + >([]);
  23 + const [loading, setLoading] = useState(false);
  24 +
  25 + useEffect(() => {
  26 + initDatabases();
  27 + }, []);
  28 +
  29 + function initDatabases() {
  30 + setLoading(true);
  31 + DatabaseListApi({ pageSize: 1000, current: 1 })
  32 + .then((res) => {
  33 + setDatabases(
  34 + (res.data?.data || []).map((item) => ({
  35 + code: item.identifyCode,
  36 + name: item.name,
  37 + }))
  38 + );
  39 + setLoading(false);
  40 + })
  41 + .catch((error) => {
  42 + message.error(error.message || "查询资料列表失败");
  43 + setDatabases([]);
  44 + setLoading(false);
  45 + });
  46 + }
  47 +
  48 + return { Databases, loading };
  49 +}
... ...
src/pages/performance/CompensateGroupConfig/EditComfirm/components/IndivatorsTable.tsx
... ... @@ -126,8 +126,9 @@ const IndivatorsTable = ({ value, onChange, postId, shopIds }: Props) =&gt; {
126 126 {
127 127 title: "考核目标设置",
128 128 render: (value: any, record: Item) => {
129   - if (record.commissionParams && record.commissionParams.length > 0) {
130   - const newValue = record.commissionParams.filter((item: any) => item.targetValue);
  129 + const targets: any = [];
  130 + if (record.targets && record.targets.length > 0) {
  131 + const newValue = record.targets.filter((item: any) => item.targetValue);
131 132 if (newValue.length === 1) {
132 133 return newValue[0].targetType === 2
133 134 ? `${newValue[0].targetValue}%`
... ... @@ -143,8 +144,17 @@ const IndivatorsTable = ({ value, onChange, postId, shopIds }: Props) =&gt; {
143 144 } else {
144 145 return "--";
145 146 }
146   - } else if (record.ladderParams && record.ladderParams.length > 0) {
147   - const newValue = record.ladderParams.filter((item: any) => item.targetValue);
  147 + } else {
  148 + if (record.conds && record.conds.length > 0) {
  149 + record.conds.forEach((i) => targets.push(i));
  150 + }
  151 + if (record.commissionParams && record.commissionParams.length > 0) {
  152 + record.commissionParams.forEach((i) => targets.push(i));
  153 + }
  154 + if (record.ladderParams && record.ladderParams.length > 0) {
  155 + record.ladderParams.forEach((i) => targets.push(i));
  156 + }
  157 + const newValue = targets.filter((item: any) => item.targetValue);
148 158 if (newValue.length === 1) {
149 159 return newValue[0].targetType === 2
150 160 ? `${newValue[0].targetValue}%`
... ... @@ -160,8 +170,6 @@ const IndivatorsTable = ({ value, onChange, postId, shopIds }: Props) =&gt; {
160 170 } else {
161 171 return "--";
162 172 }
163   - } else {
164   - return "--";
165 173 }
166 174 },
167 175 },
... ...
src/pages/performance/KpiGroupSetting/EditComfirm/components/IndivatorsTable.tsx
... ... @@ -117,19 +117,21 @@ const IndivatorsTable = ({ value, onChange, personModal }: Props) =&gt; {
117 117 },
118 118 {
119 119 title: "得分设置",
120   - render: (_: any, record: Item) => (record.indicatorLadders && record.indicatorLadders.length > 0 ? (
121   - <Button type="link" onClick={() => onLookLadders(record)}>
122   - 查看
123   - </Button>
  120 + render: (_: any, record: Item) =>
  121 + record.indicatorLadders && record.indicatorLadders.length > 0 ? (
  122 + <Button type="link" onClick={() => onLookLadders(record)}>
  123 + 查看
  124 + </Button>
124 125 ) : (
125 126 "--"
126   - )),
  127 + ),
127 128 },
128 129 {
129 130 title: "考核目标设置",
130 131 render: (value: any, record: Item) => {
131   - if (record.commissionParams && record.commissionParams.length > 0) {
132   - const newValue = record.commissionParams.filter((item: any) => item.targetValue);
  132 + const targets: any = [];
  133 + if (record.targets && record.targets.length > 0) {
  134 + const newValue = record.targets.filter((item: any) => item.targetValue);
133 135 if (newValue.length === 1) {
134 136 return newValue[0].targetType === 2
135 137 ? `${newValue[0].targetValue}%`
... ... @@ -145,8 +147,17 @@ const IndivatorsTable = ({ value, onChange, personModal }: Props) =&gt; {
145 147 } else {
146 148 return "--";
147 149 }
148   - } else if (record.ladderParams && record.ladderParams.length > 0) {
149   - const newValue = record.ladderParams.filter((item: any) => item.targetValue);
  150 + } else {
  151 + if (record.conds && record.conds.length > 0) {
  152 + record.conds.forEach((i) => targets.push(i));
  153 + }
  154 + if (record.commissionParams && record.commissionParams.length > 0) {
  155 + record.commissionParams.forEach((i) => targets.push(i));
  156 + }
  157 + if (record.ladderParams && record.ladderParams.length > 0) {
  158 + record.ladderParams.forEach((i) => targets.push(i));
  159 + }
  160 + const newValue = targets.filter((item: any) => item.targetValue);
150 161 if (newValue.length === 1) {
151 162 return newValue[0].targetType === 2
152 163 ? `${newValue[0].targetValue}%`
... ... @@ -162,10 +173,8 @@ const IndivatorsTable = ({ value, onChange, personModal }: Props) =&gt; {
162 173 } else {
163 174 return "--";
164 175 }
165   - } else {
166   - return "--";
167 176 }
168   - }
  177 + },
169 178 },
170 179 {
171 180 title: "操作",
... ...
src/pages/performance/KpiGroupSetting/interface.d.ts
... ... @@ -166,6 +166,7 @@ declare namespace KpiGroupSetteing {
166 166 }
167 167 // 配置阶梯项
168 168 interface Item {
  169 + targets: any[];
169 170 laddersType: number;
170 171 index: number;
171 172 itemId?: number;
... ...
src/pages/pms/partPlan/CustBuyPlan/api.ts
... ... @@ -4,6 +4,7 @@ import { PMS_HOST } from &#39;@/utils/host&#39;;
4 4  
5 5 export interface PlanParams {
6 6 brandId?: number, // 品牌ID
  7 + typeId?: string, // 品牌ID
7 8 parts?: PartItem[], // 供应商集合
8 9 }
9 10 export interface PartItem {
... ...
src/pages/pms/partPlan/CustBuyPlan/subpages/First/components/PartModal.tsx
... ... @@ -64,10 +64,9 @@ export default function DetailModal() {
64 64 <Table loading={loading} rowKey={(v: PartVO) => `${v.partId}`} scroll={{y: 500}} dataSource={data || []} pagination={false}>
65 65 <Column title="配件名称" dataIndex="partName" />
66 66 <Column title="配件编码" dataIndex="partCode" />
67   - <Column title="拆分件规格" dataIndex="splitUnit" render={t => t || '--'} />
68 67 <Column title="缺件数量" dataIndex="splitCnt" />
69   - <Column title="价格" dataIndex="price" />
70   - <Column title="总金额" dataIndex="amount" />
  68 + <Column title="价格(元)" dataIndex="price" />
  69 + <Column title="总金额(元)" dataIndex="amount" />
71 70 {fw && (
72 71 <Column
73 72 title="操作"
... ...
src/pages/pms/partPlan/CustBuyPlanProcess/api.ts 0 → 100644
  1 +import { http } from '@/typing/http';
  2 +import request from '@/utils/request';
  3 +import { PMS_HOST } from '@/utils/host';
  4 +
  5 +export interface ListVO {
  6 + partId?: number, // 配件id
  7 + partName?: string, // 配件名称
  8 + partCode?: string, // 配件编码
  9 + partCnt?: number, // 缺件数量
  10 + price?: number, // 价格
  11 + count?: number,
  12 + cnt?: number,
  13 + amount?: number, // 价格
  14 + supplierId?: number,
  15 + supplierName?: string,
  16 + storageId?: number
  17 + storageName?: string
  18 + shopId?: number
  19 + shopName?: string
  20 + waitListIds?: string
  21 + remark?: string
  22 + typeId?: string
  23 + userName?: string
  24 + status?:string
  25 + brandName?:number
  26 +}
  27 +
  28 +export interface Params{
  29 + current?:number
  30 + pageSize?:number
  31 + brandId?:number
  32 + status?:number
  33 + shopId?:number
  34 + keywords?:string
  35 +}
  36 +
  37 +export interface ProgressVO {
  38 + planId?: string, // 计划ID
  39 + planGroupId?: string, // 计划分组ID
  40 + progressVOS?: ProgressItemVO[], // 流程详情
  41 +}
  42 +export interface ProgressItemVO {
  43 + status?: string, // 状态
  44 + title?: string, // 标题
  45 + remarks?: string[], // 备注
  46 + hasDetail?: boolean, // 是否有明细
  47 +}
  48 +
  49 +export interface ProgressParams {
  50 + handleTypeId?: string, // 缺件处理类型id
  51 + handleType?: string, // 缺件处理类型 外采 调件 客户定件
  52 +}
  53 +// 列表查询
  54 +export function fetchPartList(params: Params): http.PromisePageResp<ListVO> {
  55 + return request.get(`${PMS_HOST}/erp/cus/buy/part/get/buy/part/page`, { params });
  56 +}
  57 +// 进度查询
  58 +export function fetchProgress(params?: ProgressParams): http.PromiseResp<ProgressItemVO[]> {
  59 + return request.get(`${PMS_HOST}/erp/cus/buy/part/get/pool/part/progress`, { params });
  60 +}
0 61 \ No newline at end of file
... ...
src/pages/pms/partPlan/CustBuyPlanProcess/components/ProcessModal.tsx 0 → 100644
  1 +import React from 'react';
  2 +import { Button, Modal, Timeline } from 'antd';
  3 +import { ProgressItemVO } from '../api';
  4 +import { RightOutlined } from '@ant-design/icons';
  5 +
  6 +interface Props {
  7 + visible?: boolean
  8 + onCancel: Function
  9 + processItem?: ProgressItemVO[]
  10 +}
  11 +const { Item } = Timeline;
  12 +export default function ProcessModal(props: Props) {
  13 + const { visible, onCancel, processItem } = props;
  14 + return (
  15 + <Modal
  16 + visible={visible}
  17 + title="申请进度"
  18 + onCancel={() => onCancel()}
  19 + maskClosable={false}
  20 + footer={[
  21 + <Button key="ok" onClick={() => onCancel()}>取消</Button>
  22 + ]}
  23 + >
  24 + <Timeline>
  25 + {processItem?.map((i, index) => (
  26 + <Item key={index}>
  27 + <h3>
  28 + {i.title}<RightOutlined />
  29 + <span style={{ marginLeft: 5, color: (i.status == "已完成" || i.status == "通过") ? "#0000FF" : "red", fontSize: 14 }}>
  30 + {i.status}
  31 + </span>
  32 + </h3>
  33 + {i.remarks?.map(it => <div style={{ marginTop: 8 }}>{it}</div>)}
  34 + </Item>
  35 + ))}
  36 + </Timeline>
  37 + </Modal>
  38 + );
  39 +}
0 40 \ No newline at end of file
... ...
src/pages/pms/partPlan/CustBuyPlanProcess/index.tsx 0 → 100644
  1 +import { Table, Select, Input, Card, message, Spin } from 'antd';
  2 +import React, { useState } from 'react';
  3 +import { fetchPartList, ListVO, fetchProgress, ProgressItemVO } from './api';
  4 +import { getShopApi } from '@/pages/pms/storage/partShop/api';
  5 +import useInitial from "@/hooks/useInitail";
  6 +import usePagination from '@/hooks/usePagination';
  7 +import { PageHeaderWrapper } from '@ant-design/pro-layout';
  8 +import * as API from '@/common/api';
  9 +import ProcessModal from './components/ProcessModal';
  10 +
  11 +const { Column } = Table;
  12 +const Option = Select.Option;
  13 +const Search = Input.Search;
  14 +
  15 +export default function Index() {
  16 + const { list, setParams, paginationConfig, loading } = usePagination<ListVO>(fetchPartList, [], {});
  17 + const { data: shops } = useInitial<PmsStoragePartShop.Option[], {}>(getShopApi, [], {});
  18 + const { data: brands } = useInitial(API.getBrandFilterApi, [], {});
  19 + const [currentInfo, setCurrentInfo] = useState<{visible?: boolean, item?: ProgressItemVO[], loading?:boolean}>({visible: false, item: [], loading: false});
  20 +
  21 + const process = (id?: string) => {
  22 + setCurrentInfo({loading: true});
  23 + fetchProgress({handleTypeId: id, handleType: "客户订件"}).then(res => {
  24 + setCurrentInfo({ visible: true, item: res.data, loading: false });
  25 + }).catch(e => {
  26 + message.error(e.message);
  27 + setCurrentInfo({ loading: false });
  28 + });
  29 + };
  30 +
  31 + return (
  32 + <PageHeaderWrapper title="客户订件计划进度">
  33 + <Card>
  34 + <Spin spinning={currentInfo.loading}>
  35 + <div style={{ display: 'flex', alignItems: 'center', marginBottom: 20 }}>
  36 + <Search
  37 + allowClear
  38 + placeholder="配件名称/编码搜索"
  39 + style={{ width: 200, marginRight: 10 }}
  40 + onChange={e => setParams({keywords: e.target.value}, true)}
  41 + />
  42 + <Select
  43 + allowClear
  44 + placeholder="选择品牌"
  45 + style={{ width: 200, marginRight: 10 }}
  46 + onChange={v => setParams({ brandId: v }, true)}
  47 + showSearch
  48 + optionFilterProp="children"
  49 + >
  50 + {brands.map(item => <Option key={item.id} value={item.id}>{item.name}</Option>)}
  51 + </Select>
  52 + <Select
  53 + allowClear
  54 + placeholder="选择门店"
  55 + style={{ width: 200, marginRight: 10 }}
  56 + onChange={v => setParams({shopId: v }, true)}
  57 + showSearch
  58 + optionFilterProp="children"
  59 + >
  60 + {shops.map((item: PmsStoragePartShop.Option) => <Option key={item.id} value={item.id || ""}>{item.name || ""}</Option>)}
  61 + </Select>
  62 + <Select
  63 + allowClear
  64 + placeholder="状态筛选"
  65 + style={{ width: 200 }}
  66 + onChange={v => setParams({status: v }, true)}
  67 + showSearch
  68 + optionFilterProp="children"
  69 + >
  70 + <Option value={0} key="1">未确认</Option>
  71 + <Option value={1} key="2">未添加</Option>
  72 + <Option value={2} key="3">已添加</Option>
  73 + <Option value={3} key="4">已完成</Option>
  74 + </Select>
  75 + </div>
  76 + <Table
  77 + rowKey={(v: ListVO) => `${v.waitListIds}`}
  78 + dataSource={list}
  79 + pagination={paginationConfig}
  80 + loading={loading}
  81 + scroll={{x: 1200}}
  82 + >
  83 + <Column title="配件编码" dataIndex="partCode" fixed="left" />
  84 + <Column title="配件名称" dataIndex="partName" />
  85 + <Column title="采购数量" dataIndex="cnt" />
  86 + <Column title="采购单价" dataIndex="price" />
  87 + <Column title="车牌号" dataIndex="plateNo" />
  88 + <Column title="时间" dataIndex="planTime" />
  89 + <Column title="VIN" dataIndex="typeId" />
  90 + <Column title="工单号" dataIndex="remark" />
  91 + <Column title="品牌" dataIndex="brandName" />
  92 + <Column title="门店名称" dataIndex="shopName" />
  93 + <Column title="状态" dataIndex="status" />
  94 +
  95 + {/* <Column title="接车服务顾问" dataIndex="userName" /> */}
  96 + {/* <Column title="库房名称" dataIndex="storageName" /> */}
  97 + {/* <Column title="订件数量" dataIndex="splitCnt" /> */}
  98 +
  99 + <Column
  100 + title="进度"
  101 + fixed="right"
  102 + width={100}
  103 + render={(t, _: ListVO) => (
  104 + <a onClick={() => process(_.waitListIds)}>查看</a>
  105 + )}
  106 + />
  107 + </Table>
  108 + <ProcessModal visible={currentInfo.visible} processItem={currentInfo.item} onCancel={() => setCurrentInfo({visible: false, item: [], loading: false})} />
  109 + </Spin>
  110 + </Card>
  111 + </PageHeaderWrapper>
  112 + );
  113 +}
... ...
src/pages/pms/purchase/PurchaseRecord/api.ts
... ... @@ -165,6 +165,15 @@ interface poolPart{
165 165 cnt?:number //配件数量
166 166 details?:partItem[]
167 167 }
  168 +export interface RelationList{
  169 + billAmountRatio?:number //发票比例
  170 + accountCheckPeriod?:number //对账周期
  171 + settleMethodList?: settleMethodList[]
  172 +}
  173 +interface settleMethodList{
  174 + value:number
  175 + name:string
  176 +}
168 177 /** 申请记录*/
169 178 export function getPurchaseRecord(params:Params):http.PromisePageResp<PageV0> {
170 179 return request.get(`${PMS_HOST}/erp/part/purchase/apply/record`, {params});
... ... @@ -178,7 +187,7 @@ export function purchaseApply(params: ApplyParams) {
178 187 return request.post(`${PMS_HOST}/erp/part/purchase/apply`, {...params});
179 188 }
180 189 /** 获取支付方式列表*/
181   -export function getrelationlist(params: relationParams):http.PromisePageResp<string> {
  190 +export function getrelationlist(params: relationParams): http.PromiseResp<RelationList[]> {
182 191 return request.get(`${FINANCE2_HOST}/trade/company//relation/listRelationByTradeCompany`, {params});
183 192 }
184 193 /** 查看流程进度*/
... ...
src/pages/pms/purchase/PurchaseRecord/comonents/AddPurchaseModal.tsx
... ... @@ -177,23 +177,24 @@ export default function PartStorageModal({ onCancel, visible, itemData, setItemD
177 177 placeholder="请选择供应商"
178 178 showSearch
179 179 optionFilterProp="children"
  180 + options={suppliers.filter((item, index, self) => {
  181 + return self.findIndex(el => el.supplierId == item.supplierId) === index;
  182 + }).map((item) => ({ value: item.supplierId, label: item.supplierName }))}
180 183 onChange={v => {
181 184 setPartParams({stId: storageid, spId: v});
182 185 setListRelation([]);
183 186 form.setFieldsValue({settlementMethod: undefined, proportion: undefined});
184 187 setSettlementMethod(undefined);
185 188 getrelationlist({tradeCompanyId: v, compCategory: 1, dealerId: storages.find(i => i.id == storageid)?.dealerId}).then(res => {
186   - if (res.success) {
187   - form.setFieldsValue({proportion: res.data && res.data[0].billAmountRatio, accountCheckPeriod: res.data && res.data[0].accountCheckPeriod});
188   - setListRelation(res.data && res.data[0].settleMethodList);
  189 + if (res.data?.length) {
  190 + form.setFieldsValue({ proportion: res.data[0].billAmountRatio, accountCheckPeriod: res.data && res.data[0].accountCheckPeriod});
  191 + setListRelation(res.data && res.data[0].settleMethodList);
  192 + } else {
  193 + message.error(`请财务先配置${suppliers.find(i => i.supplierId == form.getFieldValue('supplierId'))?.supplierName}的结算方式`);
189 194 }
190 195 }).catch(e => message.error(e.message));
191 196 }}
192   - >
193   - {suppliers.map((item) => (
194   - <Option value={item.supplierId} key={item.supplierId}>{item.supplierName}</Option>
195   - ))}
196   - </Select>
  197 + />
197 198 </Item>
198 199 <Item label="结算方式" name="settlementMethod" required rules={[{ required: true, message: '请选择结算方式' }]}>
199 200 <Select
... ... @@ -205,11 +206,11 @@ export default function PartStorageModal({ onCancel, visible, itemData, setItemD
205 206 onChange={setSettlementMethod}
206 207 onFocus={() => {
207 208 if (!form.getFieldValue("supplierId")) {
208   - message.warn("请先选择供应商");
  209 + message.error("请先选择供应商");
209 210 return;
210 211 }
211 212 if (!listRelation?.length) {
212   - message.warn(`请财务先配置${suppliers.find(i => i.supplierId == form.getFieldValue('supplierId'))?.supplierName}的结算方式`);
  213 + message.error(`请财务先配置${suppliers.find(i => i.supplierId == form.getFieldValue('supplierId'))?.supplierName}的结算方式`);
213 214 }
214 215 }}
215 216 >
... ...
src/pages/pms/purchase/PurchaseRecord/comonents/ProcessModal.tsx
... ... @@ -23,15 +23,13 @@ export default function ProcessModal(props: Props) {
23 23 >
24 24 <Timeline>
25 25 {processItem?.map((i, index) => (
26   - <Item key={i.status}>
27   - {/* <div onClick={() => seeDetail(item)}> */}
  26 + <Item key={index}>
28 27 <h3>
29 28 {i.title}<RightOutlined />
30 29 <span style={{marginLeft: 5, color: (i.status == "已完成" || i.status == "通过") ? "#0000FF" : "red", fontSize: 14}}>{i.status}</span>
31 30 {i.hasDetail && <span style={{marginLeft: 5, color: "#0000FF", fontSize: 10, cursor: 'pointer'}}>查看详情</span>}
32 31 </h3>
33 32 {i.remarks?.map(it => <div style={{marginTop: 8}}>{it}</div>)}
34   - {/* </div> */}
35 33 </Item>
36 34 ))}
37 35 </Timeline>
... ...
src/pages/pms/storage/partShop/components/Filter.tsx
... ... @@ -17,10 +17,8 @@ export default function Filter() {
17 17 }, 500);
18 18  
19 19 const isStock = (v:any) => {
20   - console.log(v);
21 20 if (v == undefined) {
22 21 setParams({current: 1, pageSize: 10, haveStock: undefined }, true);
23   - console.log('111');
24 22 return;
25 23 }
26 24 const param = Boolean(v);
... ... @@ -33,6 +31,13 @@ export default function Filter() {
33 31  
34 32 return (
35 33 <div>
  34 + <Search
  35 + style={{ width: 200, marginRight: 10 }}
  36 + allowClear
  37 + placeholder="配件编码|名称"
  38 + onSearch={v => handleChangeKeywords(v)}
  39 + onChange={e => handleChangeKeywords(e.target.value)}
  40 + />
36 41 <PmsSelect
37 42 style={{ width: 180, marginRight: 10}}
38 43 allowClear
... ... @@ -68,14 +73,6 @@ export default function Filter() {
68 73 placeholder="请选择配件类型"
69 74 options={partTypeData.map((item: any) => ({value: item.value, label: item.label}))}
70 75 />
71   - <Search
72   - style={{ width: 200, marginRight: 10 }}
73   - allowClear
74   - placeholder="配件编码|名称"
75   - onSearch={v => handleChangeKeywords(v)}
76   - onChange={e => handleChangeKeywords(e.target.value)}
77   - />
78   - {/* {!fw && ( */}
79 76 <PmsSelect
80 77 allowClear
81 78 placeholder="有无库存筛选"
... ... @@ -96,7 +93,6 @@ export default function Filter() {
96 93 {value: 21, label: "锁定库存降序"},
97 94 ]}
98 95 />
99   - {/* )} */}
100 96 </div>
101 97 );
102 98 }
... ...
src/pages/pms/storage/partShop/components/LoackStockModal.tsx
1   -/* eslint-disable prefer-promise-reject-errors */
2 1 import React, { useEffect } from 'react';
3 2 import { Modal, Button, Form, InputNumber, message, Input } from 'antd';
4 3 import { useStore } from '../index';
... ... @@ -20,19 +19,19 @@ export default function ReleaseModal(props: Props) {
20 19  
21 20 useEffect(() => {
22 21 if (!visable) {
23   - form.resetFields(['partCnt']);
  22 + form.resetFields();
24 23 return;
25 24 }
26 25 form.setFieldsValue({ actualStock: row.lockCnt });
27 26 }, [visable]);
28 27  
29 28 const handleSubmit = () => {
30   - setConfirmLoading(true);
31 29 form.validateFields().then(values => {
32 30 const params = {
33 31 ...row,
34 32 ...values
35 33 };
  34 + setConfirmLoading(true);
36 35 unLock(params).then(() => {
37 36 message.success('操作成功');
38 37 onCancel();
... ... @@ -79,7 +78,7 @@ export default function ReleaseModal(props: Props) {
79 78 validator: (rule, value) => {
80 79 if (row.lockCnt) {
81 80 if (value > row.lockCnt) {
82   - return Promise.reject('释放数量不能大于锁定数量');
  81 + return Promise.reject(new Error('释放数量不能大于锁定数量'));
83 82 } else {
84 83 return Promise.resolve();
85 84 }
... ...
src/pages/pms/storage/partShop/components/LockDetailModal.tsx
... ... @@ -37,7 +37,7 @@ export default function Index({ item = {}, visible, onCancel }: Props) {
37 37 return (
38 38 <Modal
39 39 title="锁定明细"
40   - width={1000}
  40 + width={1200}
41 41 visible={visible}
42 42 maskClosable={false}
43 43 onCancel={onCancel}
... ... @@ -46,7 +46,7 @@ export default function Index({ item = {}, visible, onCancel }: Props) {
46 46 ]}
47 47 >
48 48 <Table loading={loading} rowKey={(v: PmsStoragePartShop.LockDetailVO) => `${v.orderNo}`} scroll={{ y: 500 }} dataSource={data || []} pagination={false}>
49   - <Column title="锁库类型" dataIndex="type" />
  49 + <Column title="锁库类型" render={r => (r.orderNo.slice(0, 1) == "D" ? "装潢订单锁定" : r.type)} />
50 50 <Column title="单号" dataIndex="orderNo" />
51 51 <Column
52 52 title="详情"
... ... @@ -56,17 +56,18 @@ export default function Index({ item = {}, visible, onCancel }: Props) {
56 56 const obj = JSON.parse(t || '{}');
57 57 return (
58 58 <div>
59   - <div>{`锁库类型: ${it.type || '--'}`}</div>
  59 + <div>{`锁库类型: ${it.orderNo?.slice(0, 1) == "D" ? "装潢订单锁定" : it.type || '--'}`}</div>
60 60 <div>{`锁定库存数: ${it.lockCnt || 0}件`}</div>
61 61 <div>{`锁库天数: ${(it.days || 0).toFixed(0)}天`}</div>
62   - {!!obj.receiverName && <div>{`${typeReceiverObj[it.type || '']}顾问: ${obj.receiverName}`}</div>}
63   - {!!obj.senderName && !!typeSenderObj[it.type || ''] && <div>{`${typeSenderObj[it.type || '']}${obj.senderName}`}</div>}
  62 + {it.orderNo?.slice(0, 1) == "D" ? <div>推荐人: {obj.receiverName}</div> : !!obj.receiverName && <div>{`${typeReceiverObj[it.type || '']}顾问: ${obj.receiverName}`}</div>}
  63 + {it.orderNo?.slice(0, 1) == "D" ? <div>推荐人门店: {obj.shopName}</div> : !!obj.senderName && !!typeSenderObj[it.type || ''] && <div>{`${typeSenderObj[it.type || '']}${obj.senderName}`}</div>}
64 64 {!!obj.ownerName && <div>{`车主: ${obj.ownerName}`}</div>}
65   - {!!obj.senderTime && <div>{`进站时间: ${moment(obj.senderTime).format('YYYY-MM-DD HH:mm')}`}</div>}
  65 + {!!obj.senderTime && <div>{`${it.orderNo?.slice(0, 1) == "D" ? "下单时间" : "进站时间"}: ${moment(obj.senderTime).format('YYYY-MM-DD HH:mm')}`}</div>}
66 66 {!!obj.plateNo && <div>{`车牌号: ${obj.plateNo}`}</div>}
67 67 {!!obj.serviceCatName && <div>{`进站类型: ${obj.serviceCatName}`}</div>}
68 68 {!!obj.carName && <div>{`车辆: ${obj.carName}`}</div>}
69 69 {!!obj.vin && <div>{`车架号: ${obj.vin}`}</div>}
  70 + {it.orderNo?.slice(0, 1) == "D" && !!obj.specCode && <div>{`配置代码: ${obj.specCode}`}</div>}
70 71 {!!obj.inStorageName && <div>{`调入库房: ${obj.inStorageName}`}</div>}
71 72 {!!obj.inShopName && <div>{`调入门店: ${obj.inShopName}`}</div>}
72 73 {!!obj.outStorageName && <div>{`调出库房: ${obj.outStorageName}`}</div>}
... ... @@ -77,6 +78,7 @@ export default function Index({ item = {}, visible, onCancel }: Props) {
77 78 );
78 79 }}
79 80 />
  81 + <Column title="锁库时间" dataIndex="lockDate" />
80 82 <Column title="锁定库存数" dataIndex="lockCnt" />
81 83 <Column title="锁库天数" dataIndex="days" render={(t: number) => (t || 0).toFixed(0)} />
82 84 {fw && <Column title="操作" render={(record) => <a onClick={() => unLock(record)}>释放库存</a>} />}
... ...
src/pages/pms/storage/partShop/interface.d.ts
... ... @@ -50,11 +50,12 @@ declare namespace PmsStoragePartShop {
50 50 * 锁件明细
51 51 */
52 52 export interface LockDetailVO {
53   - type?: number, // 锁库类型
54   - orderNo?: number, // 单号
55   - text?: number, // 详情
  53 + type?: string, // 锁库类型
  54 + orderNo?: string, // 单号
  55 + text?: string, // 详情
56 56 lockCnt?: number, // 锁定库存数
57 57 days?: number, // 锁库天数
  58 + lockDate?:string
58 59 }
59 60  
60 61 /**
... ...
src/pages/pms/transfer/transferManage/comonents/TransferGroupProcessModal.tsx
... ... @@ -43,8 +43,8 @@ export default function Index(props:Props) {
43 43 </span>
44 44 </div>
45 45 <Timeline>
46   - {i.groupProcess?.map(item => (
47   - <Item key={item.title}>
  46 + {i.groupProcess?.map((item, index) => (
  47 + <Item key={index}>
48 48 <h3>
49 49 {item.title}<RightOutlined />
50 50 <span style={{marginLeft: 5, fontSize: 14, color: (item.status == "已完成" || item.status == "通过") ? "#0000FF" : "red"}}>{item.status}</span>
... ...