Commit e1dc8b1c3c4a00d4c68e71d471a7a4c5060c8e51
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 "./api"; |
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 "@/utils"; |
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) => { |
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) => { |
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) => { |
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) => { |
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) => { |
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) => { |
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
src/pages/pms/partPlan/CustBuyPlan/api.ts
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> | ... | ... |