Commit 9b132f20162a7ba66a095272c2a4943b99f145a8
Merge branch 'master' into d-cas-maintain-config
Showing
46 changed files
with
2038 additions
and
399 deletions
config/routers/order3.ts
... | ... | @@ -335,4 +335,14 @@ export default [ |
335 | 335 | path: '/order3/promotionSettings/directCarPromotion', |
336 | 336 | component: './order3/DirectCarPromotion', |
337 | 337 | }, |
338 | + { | |
339 | + // 市占率数据导入 | |
340 | + path: '/order3/weeklydataupload', | |
341 | + component: './order3/WeeklydataUpload', | |
342 | + }, | |
343 | + { | |
344 | + // 车系映射配置 | |
345 | + path: '/order3/seriesmapping', | |
346 | + component: './order3/SeriesMapping', | |
347 | + }, | |
338 | 348 | ]; | ... | ... |
src/common/api.ts
... | ... | @@ -213,6 +213,16 @@ export function queryShopBizType(): http.PromiseResp<CommonApi.ShopRpTypeVO[]> { |
213 | 213 | return request.get(`${OOP_HOST}/select/shopBizType`); |
214 | 214 | } |
215 | 215 | |
216 | +export interface GetReimburseRpTypesReq { | |
217 | + businessTypes?: string | |
218 | +} | |
219 | +/** | |
220 | + * 报销款项列表 | |
221 | + */ | |
222 | +export function getReimburseRpTypes(params: GetReimburseRpTypesReq): http.PromiseResp<CommonApi.RPTypeVO[]> { | |
223 | + return request.get(`${FINANCE2_HOST}/common/reimburseRpTypes`, { params }); | |
224 | +} | |
225 | + | |
216 | 226 | /** |
217 | 227 | * 批量获取角色所在角色组信息 |
218 | 228 | * @param params 角色编码,多个角色英文逗号分割 | ... | ... |
src/pages/approval/ApprovalSetting/subpages/components/DefaultFlowNewOrEdit.tsx
... | ... | @@ -85,7 +85,8 @@ export default function DefaultSettingNewOrEdit(props: Props) { |
85 | 85 | // idOrCode to idOrCode__bizType |
86 | 86 | newCondVals.forEach((n) => { |
87 | 87 | if (n.flowTriggerDto.type === TriggerType.门店) { |
88 | - const value = JSON.parse(n.value).map((i: FlowSetting.CondValItem) => ({ | |
88 | + // 注意 || 和 ?? 的区别 | |
89 | + const value = JSON.parse(n.value || '[]').map((i: FlowSetting.CondValItem) => ({ | |
89 | 90 | idOrCode: `${i.idOrCode}__${i.bizType}`, |
90 | 91 | name: i.name, |
91 | 92 | bizType: i.bizType, |
... | ... | @@ -120,7 +121,7 @@ export default function DefaultSettingNewOrEdit(props: Props) { |
120 | 121 | const bizTypeSet = new Set<number>(); |
121 | 122 | shopCondVals.forEach((s) => { |
122 | 123 | try { |
123 | - const options = JSON.parse(s.value); | |
124 | + const options = JSON.parse(s.value || '[]'); | |
124 | 125 | options.forEach((o: FlowSetting.CondValItem) => { |
125 | 126 | bizTypeSet.add(o.bizType!); |
126 | 127 | }); |
... | ... | @@ -135,7 +136,7 @@ export default function DefaultSettingNewOrEdit(props: Props) { |
135 | 136 | const bizTypeSet = new Set<number>(); |
136 | 137 | shopCondVals.forEach((s) => { |
137 | 138 | try { |
138 | - const options = JSON.parse(s.value); | |
139 | + const options = JSON.parse(s.value || '[]'); | |
139 | 140 | options.forEach((o: FlowSetting.CondValItem) => { |
140 | 141 | bizTypeSet.add(o.bizType!); |
141 | 142 | }); |
... | ... | @@ -162,7 +163,7 @@ export default function DefaultSettingNewOrEdit(props: Props) { |
162 | 163 | // idOrCode__bizType to idOrCode |
163 | 164 | conditionVals.forEach((n) => { |
164 | 165 | if (n.flowTriggerDto.type === TriggerType.门店) { |
165 | - const value = JSON.parse(n.value).map((i: FlowSetting.CondValItem) => ({ | |
166 | + const value = JSON.parse(n.value || '[]').map((i: FlowSetting.CondValItem) => ({ | |
166 | 167 | idOrCode: i.idOrCode.split('__')[0]!, |
167 | 168 | name: i.name, |
168 | 169 | bizType: i.bizType, |
... | ... | @@ -347,7 +348,7 @@ export default function DefaultSettingNewOrEdit(props: Props) { |
347 | 348 | conditionVals.forEach((c) => { |
348 | 349 | const { flowTriggerDto: fd, value: v } = c; |
349 | 350 | const { type: t } = fd ?? {}; // 触发条件信息 |
350 | - const oData = JSON.parse(v || '{}'); | |
351 | + const oData = JSON.parse(v || '[]'); | |
351 | 352 | if (t === TriggerType.报销类型) { |
352 | 353 | rpTypes = oData.length > 0 ? oData.map((i: ApprovalSetting.CondValItem) => i.idOrCode) : []; |
353 | 354 | } else { | ... | ... |
src/pages/approval/FlowSetting/subpages/ConditionSetting/components/CustomFlowNewOrEdit.tsx
... | ... | @@ -102,7 +102,8 @@ export default function CustomFlowNewOrEdit(props: Props) { |
102 | 102 | // idOrCode to idOrCode__bizType |
103 | 103 | newCondVals.forEach((n) => { |
104 | 104 | if (n.flowTriggerDto.type === TriggerType.门店) { |
105 | - const value = JSON.parse(n.value).map((i: FlowSetting.CondValItem) => ({ | |
105 | + // 注意 || 和 ?? 的区别 | |
106 | + const value = JSON.parse(n.value || '[]').map((i: FlowSetting.CondValItem) => ({ | |
106 | 107 | idOrCode: `${i.idOrCode}__${i.bizType}`, |
107 | 108 | name: i.name, |
108 | 109 | bizType: i.bizType, |
... | ... | @@ -138,7 +139,7 @@ export default function CustomFlowNewOrEdit(props: Props) { |
138 | 139 | const bizTypeSet = new Set<number>(); |
139 | 140 | shopCondVals.forEach((s) => { |
140 | 141 | try { |
141 | - const options = JSON.parse(s.value); | |
142 | + const options = JSON.parse(s.value || '[]'); | |
142 | 143 | options.forEach((o: FlowSetting.CondValItem) => { |
143 | 144 | bizTypeSet.add(o.bizType!); |
144 | 145 | }); |
... | ... | @@ -153,7 +154,7 @@ export default function CustomFlowNewOrEdit(props: Props) { |
153 | 154 | const bizTypeSet = new Set<number>(); |
154 | 155 | shopCondVals.forEach((s) => { |
155 | 156 | try { |
156 | - const options = JSON.parse(s.value); | |
157 | + const options = JSON.parse(s.value || '[]'); | |
157 | 158 | options.forEach((o: FlowSetting.CondValItem) => { |
158 | 159 | bizTypeSet.add(o.bizType!); |
159 | 160 | }); |
... | ... | @@ -181,7 +182,7 @@ export default function CustomFlowNewOrEdit(props: Props) { |
181 | 182 | // idOrCode__bizType to idOrCode |
182 | 183 | conditionVals.forEach((n) => { |
183 | 184 | if (n.flowTriggerDto.type === TriggerType.门店) { |
184 | - const value = JSON.parse(n.value).map((i: FlowSetting.CondValItem) => ({ | |
185 | + const value = JSON.parse(n.value || '[]').map((i: FlowSetting.CondValItem) => ({ | |
185 | 186 | idOrCode: i.idOrCode.split('__')[0]!, |
186 | 187 | name: i.name, |
187 | 188 | bizType: i.bizType, |
... | ... | @@ -360,7 +361,7 @@ export default function CustomFlowNewOrEdit(props: Props) { |
360 | 361 | conditionVals.forEach((c) => { |
361 | 362 | const { flowTriggerDto: fd, value: v } = c; |
362 | 363 | const { type: t } = fd ?? {}; // 触发条件信息 |
363 | - const oData = JSON.parse(v || '{}'); | |
364 | + const oData = JSON.parse(v || '[]'); | |
364 | 365 | if (t === TriggerType.报销类型) { |
365 | 366 | rpTypes = oData.length > 0 ? oData.map((i: FlowSetting.CondValItem) => i.idOrCode) : []; |
366 | 367 | } else { | ... | ... |
src/pages/cas/ClaimConfirmation/components/DetailModal.tsx
1 | 1 | import React, { useEffect, useState } from 'react'; |
2 | 2 | import { Descriptions, Form, Input, message, Modal, Popconfirm, Select, Spin, Table } from 'antd'; |
3 | 3 | import moment from 'moment'; |
4 | +import {isEmpty} from "lodash"; | |
4 | 5 | import { ColumnsType } from 'antd/es/table'; |
5 | 6 | |
6 | 7 | import { formatPartCnt } from '../../utils'; |
... | ... | @@ -119,7 +120,7 @@ export default function DetailMOdal({ current, visible, setVisible, setLoading: |
119 | 120 | dataIndex: 'totalPrice', |
120 | 121 | title: '材料费', |
121 | 122 | align: 'center', |
122 | - render: (totalPrice: number) => rmb.p(totalPrice), | |
123 | + render: (totalPrice: number) => isNaN(totalPrice) ? '--' : rmb.p(totalPrice ?? 0), | |
123 | 124 | }, |
124 | 125 | { |
125 | 126 | dataIndex: 'partName', |
... | ... | @@ -357,7 +358,7 @@ export default function DetailMOdal({ current, visible, setVisible, setLoading: |
357 | 358 | {(detail && detail.consultantDesc) || '--'} |
358 | 359 | </DescriptionItem> |
359 | 360 | <DescriptionItem label="附件" span={3}> |
360 | - <ImageModal title="查看附件" fids={detail?.fids || []} /> | |
361 | + <ImageModal title="查看附件" fids={isEmpty(detail?.fids) ? [] : detail?.fids} /> | |
361 | 362 | </DescriptionItem> |
362 | 363 | </Descriptions> |
363 | 364 | ... | ... |
src/pages/cas/workOrder/PartLackHandle/api.ts
1 | 1 | import { http } from '@/typing/http'; |
2 | 2 | import request from '@/utils/request'; |
3 | 3 | import { CAS_HOST, PMS_HOST } from '@/utils/host'; |
4 | +import { AreaStockEnum, MethodEnum } from '@/pages/cas/workOrder/PartLackHandle/entity'; | |
4 | 5 | |
5 | 6 | type P<T> = http.PromiseResp<T>; |
6 | 7 | type Page<T> = http.PromisePageResp<T>; |
7 | 8 | |
8 | -interface ListParams { | |
9 | - groupId?: number; | |
10 | - shopId?: number; | |
11 | - userId?: number; | |
12 | - userName?: string; | |
13 | - pageSize?: number; | |
14 | - current?: number; | |
15 | - keywords?: string; | |
16 | -} | |
17 | - | |
18 | -export interface ListResult { | |
19 | - dataId: number; // 缺件单id | |
20 | - orderNo: number; // 工单号 | |
21 | - plateNo: number; // 车牌号 | |
22 | - ownerName: number; // 车主 | |
23 | - carName: number; // 车辆名称 | |
24 | - vin: number; // 车架号 | |
25 | - specCode: number; // 车型代码 | |
26 | - shopName: number; // 在修门店 | |
27 | - receiverName: number; // 服务顾问 | |
28 | - senderTime: number; // 进站时间 | |
29 | - serviceCatName: number; // 进站类型 | |
30 | -} | |
31 | - | |
32 | -export interface DetailResult { | |
33 | - lackListId: number; | |
34 | - quoteId: number; | |
35 | - ownerName: string; | |
36 | - phone: number; | |
37 | - brandId: number; | |
38 | - plateNo: string; | |
39 | - carName: string; | |
40 | - vin: string; | |
41 | - specCode: string; | |
42 | - senderTime: number; | |
43 | - consultant: string; | |
44 | - orderNo: string; | |
45 | - orderId: number; | |
46 | - shopId: number; | |
47 | - shopName: string; | |
48 | - groupId: number; | |
49 | - lackStatus: number; | |
50 | - items: Part[]; | |
51 | -} | |
52 | - | |
53 | -export interface TransferItem { | |
54 | - outStorageId: number; | |
55 | - outStorageName: string; | |
56 | - outShopId: number; | |
57 | - lackNum: number; | |
58 | -} | |
59 | - | |
60 | -export interface Part { | |
61 | - lackPartId: number; | |
62 | - itemId: number; | |
63 | - itemName: string; | |
64 | - quotePartId: number; | |
9 | +/** 缺件处理配件必备基础信息 */ | |
10 | +export interface LackPart { | |
65 | 11 | partId: number; |
66 | 12 | partCode: string; |
67 | 13 | partName: string; |
68 | 14 | lackNum: number; |
69 | - processingMethod?: number; // 处理方式 1: 区域库内调件 2: 厂家采购 3:外部采购 4:区域库外调件 5:计划员处理 | |
70 | - processingMethodName?: string; // 处理方式名称 | |
71 | - // processingMethod为1时,有以下字段 | |
72 | - shopId?: number; | |
73 | - outStorageId?: number; | |
74 | - outStorageName?: string; | |
75 | - outDividedBy?: number; | |
76 | - outDivision?: number; | |
77 | - inDividedBy?: number; | |
78 | - inDivision?: number; | |
15 | + methods?: Method[]; | |
16 | + oldPart?: LackPart; | |
79 | 17 | |
80 | - // todo confirm to del | |
81 | - expectedDate?: number; // 预计需要的入库天数 | |
82 | - transferItems?: TransferItem[]; // 顾问选择调件数据 | |
83 | - // @custom | |
84 | - oldPart?: Part; | |
85 | - methods?: MethodType[]; | |
86 | - // @custom 暂存区域库存信息:用于批量处理时展示 | |
87 | - isArea?: boolean; // 是否区域库内 | |
88 | - outStock?: number; // 区域库外库存 | |
18 | + [key: string]: any; | |
89 | 19 | } |
90 | 20 | |
91 | -export interface SavePart extends Part { | |
92 | - method?: number; | |
21 | +/** 缺件处理方式 */ | |
22 | +export interface Method { | |
23 | + method: MethodEnum; | |
24 | + num: number; | |
25 | + expectedDate?: number; | |
93 | 26 | shopId?: number; |
94 | 27 | outStorageId?: number; |
95 | 28 | outStorageName?: string; |
96 | 29 | outDividedBy?: number; |
97 | 30 | outDivision?: number; |
98 | - oldPartId?: number; | |
99 | - oldPartCode?: string; | |
100 | - oldPartName?: string; | |
31 | + inDividedBy?: number; | |
32 | + inDivision?: number; | |
101 | 33 | } |
102 | 34 | |
103 | 35 | export interface MethodType { |
... | ... | @@ -119,35 +51,17 @@ export interface MethodType { |
119 | 51 | num: number; |
120 | 52 | } |
121 | 53 | |
122 | -export interface SaveParams { | |
123 | - dataId: number; | |
124 | - userId?: number; | |
125 | - userName?: string; | |
126 | - groupId?: number; | |
127 | - purchase?: SavePart[]; | |
128 | - transfer?: SavePart[]; | |
129 | - book?: SavePart[]; | |
130 | -} | |
131 | - | |
132 | -// 列表 | |
133 | -export function listApi(params: ListParams): Page<ListResult> { | |
134 | - return request.get(`${CAS_HOST}/app/part/lack/list/planner`, { params }); | |
135 | -} | |
136 | - | |
137 | -// 详情 | |
138 | -export function detailApi(dataId: number): P<DetailResult> { | |
139 | - return request.get(`${CAS_HOST}/app/part/lack/list/detail/planner`, { params: { dataId } }); | |
140 | -} | |
141 | - | |
142 | -// 保存 | |
143 | -export function saveApi(params: SaveParams) { | |
144 | - return request.post(`${CAS_HOST}/app/part/lack/confirm/planner`, params); | |
54 | +export interface TransferItem { | |
55 | + outStorageId: number; | |
56 | + outStorageName: string; | |
57 | + outShopId: number; | |
58 | + lackNum: number; | |
145 | 59 | } |
146 | 60 | |
147 | 61 | export interface PartTransferParams { |
148 | 62 | bizShopId: number; //服务站 |
149 | 63 | partId?: number; //配件ID |
150 | - type: number; //类型 1 区域库内 2 区域库外 | |
64 | + type: AreaStockEnum; //类型 1 区域库内 2 区域库外 | |
151 | 65 | } |
152 | 66 | |
153 | 67 | /** | ... | ... |
src/pages/cas/workOrder/PartLackHandle/components/BatchHandler.tsx
1 | 1 | import React, { useEffect, useMemo, useState } from 'react'; |
2 | 2 | import { Form, InputNumber, Modal, Select, Table } from 'antd'; |
3 | 3 | |
4 | -import { BatchMethodData, MethodEnum } from '../entity'; | |
5 | -import type { MethodType, Part } from '../api'; | |
6 | -import { getPartsTransferStorageApi } from '../api'; | |
4 | +import { BatchMethodData, MethodEnum } from '@/pages/cas/workOrder/PartLackHandle/entity'; | |
5 | +import type { Method, LackPart } from '@/pages/cas/workOrder/PartLackHandle/api'; | |
6 | +import { getPartsTransferStorageApi } from '@/pages/cas/workOrder/PartLackHandle/api'; | |
7 | 7 | |
8 | 8 | import st from '@/pages/cas/style.less'; |
9 | 9 | import { ColumnsType } from 'antd/es/table'; |
... | ... | @@ -25,9 +25,9 @@ const formLayout = { |
25 | 25 | interface Props { |
26 | 26 | open: boolean; |
27 | 27 | shopId: number; |
28 | - parts: Part[]; | |
28 | + parts: LackPart[]; | |
29 | 29 | onCancel: () => void; |
30 | - onConfirm: (selectParts: Part[]) => void; | |
30 | + onConfirm: (selectParts: LackPart[]) => void; | |
31 | 31 | } |
32 | 32 | |
33 | 33 | /** |
... | ... | @@ -37,9 +37,9 @@ export default function BatchHandler({ open, shopId, parts = [], onCancel, onCon |
37 | 37 | const [form] = Form.useForm(); |
38 | 38 | const selectMethod = Form.useWatch('method', form); |
39 | 39 | |
40 | - const [selectParts, setSelectParts] = useState<Part[]>([]); | |
40 | + const [selectParts, setSelectParts] = useState<LackPart[]>([]); | |
41 | 41 | // const [retainParts, setRetainParts] = useState<Part[]>([]); |
42 | - const [filteredList, setFilteredList] = useState<Part[]>([]); | |
42 | + const [filteredList, setFilteredList] = useState<LackPart[]>([]); | |
43 | 43 | |
44 | 44 | const partIds = useMemo(() => parts.map((part) => part.partId), [parts]); |
45 | 45 | const isDayRequired = [MethodEnum.TRANSFER_OUTSIDE, MethodEnum.SUBSCRIBE].includes(Number(selectMethod)); |
... | ... | @@ -91,7 +91,7 @@ export default function BatchHandler({ open, shopId, parts = [], onCancel, onCon |
91 | 91 | |
92 | 92 | // const retainParts: Part[] = []; |
93 | 93 | // 需处理配件 |
94 | - const needHandleParts: Part[] = []; | |
94 | + const needHandleParts: LackPart[] = []; | |
95 | 95 | parts.forEach((part) => { |
96 | 96 | // @ts-ignore |
97 | 97 | if (!part.isArea && !part.methods) { |
... | ... | @@ -109,7 +109,7 @@ export default function BatchHandler({ open, shopId, parts = [], onCancel, onCon |
109 | 109 | } |
110 | 110 | }, [partsStocks]); |
111 | 111 | |
112 | - const columns: ColumnsType<Part> = [ | |
112 | + const columns: ColumnsType<LackPart> = [ | |
113 | 113 | { |
114 | 114 | title: '配件名称', |
115 | 115 | dataIndex: 'partName', |
... | ... | @@ -141,7 +141,7 @@ export default function BatchHandler({ open, shopId, parts = [], onCancel, onCon |
141 | 141 | |
142 | 142 | const handleSubmit = (values: any) => { |
143 | 143 | const finalParts = selectParts.map((part) => { |
144 | - const item: MethodType = { | |
144 | + const item: Method = { | |
145 | 145 | method: Number(values.method), |
146 | 146 | num: part.lackNum, |
147 | 147 | }; |
... | ... | @@ -203,7 +203,7 @@ export default function BatchHandler({ open, shopId, parts = [], onCancel, onCon |
203 | 203 | rowSelection={{ |
204 | 204 | type: 'checkbox', |
205 | 205 | selectedRowKeys: selectParts.map((si) => si.partId) || [], |
206 | - onChange: (selectedRowKeys, selectedRows: Part[]) => { | |
206 | + onChange: (selectedRowKeys, selectedRows: LackPart[]) => { | |
207 | 207 | setSelectParts(selectedRows); |
208 | 208 | }, |
209 | 209 | }} | ... | ... |
src/pages/cas/workOrder/PartLackHandle/components/EditMethod.tsx
... | ... | @@ -2,8 +2,8 @@ import React, { useEffect, useState } from 'react'; |
2 | 2 | import { Form, InputNumber, Modal, Select } from 'antd'; |
3 | 3 | import { isEmpty } from 'lodash'; |
4 | 4 | |
5 | -import { MethodData, MethodEnum } from '../entity'; | |
6 | -import type { MethodType, Stock, StorageResult } from '../api'; | |
5 | +import { MethodData, MethodEnum } from '@/pages/cas/workOrder/PartLackHandle/entity'; | |
6 | +import type { Method, Stock, StorageResult } from '@/pages/cas/workOrder/PartLackHandle/api'; | |
7 | 7 | |
8 | 8 | const FormItem = Form.Item; |
9 | 9 | const Option = Select.Option; |
... | ... | @@ -21,10 +21,10 @@ const formLayout = { |
21 | 21 | interface Props { |
22 | 22 | open: boolean; |
23 | 23 | lackNum: number; // 缺件数量 |
24 | - method: MethodType; // 处理方案 | |
24 | + method: Method; // 处理方案 | |
25 | 25 | warehouses: { inStorage: StorageResult; outStorage: StorageResult; inRatioThreshold: number }; // 库房信息 |
26 | 26 | onCancel: () => void; |
27 | - onConfirm: (method: MethodType) => void; | |
27 | + onConfirm: (method: Method) => void; | |
28 | 28 | } |
29 | 29 | |
30 | 30 | export default function EditMethod({ open, lackNum = 0, method, warehouses, onCancel, onConfirm }: Props) { |
... | ... | @@ -46,7 +46,7 @@ export default function EditMethod({ open, lackNum = 0, method, warehouses, onCa |
46 | 46 | setNeedNum(lackNum); |
47 | 47 | |
48 | 48 | /** |
49 | - * 添加时 | |
49 | + * 新增 | |
50 | 50 | * 默认选择条件:同时满足 |
51 | 51 | * 1.区域库内有库存,且大于等于缺件数量 |
52 | 52 | * 2.区域库内有库销比最高的仓库 |
... | ... | @@ -75,14 +75,21 @@ export default function EditMethod({ open, lackNum = 0, method, warehouses, onCa |
75 | 75 | } |
76 | 76 | } |
77 | 77 | |
78 | - // 编辑时 | |
78 | + // 编辑 | |
79 | 79 | if (!isEmpty(method)) { |
80 | + // 初始化表单信息 | |
80 | 81 | form.setFieldsValue({ |
81 | 82 | method: method.method ? Number(method.method) : undefined, |
82 | 83 | outStorageId: `${method.outStorageId || ''}`, |
83 | 84 | expectedDate: method.expectedDate || '', |
84 | 85 | num: method.num, |
85 | 86 | }); |
87 | + // 初始化选中仓库 | |
88 | + if (method.outStorageId) { | |
89 | + const stocks = Number(method.method) === MethodEnum.TRANSFER_INSIDE ? inStocks : outStocks; | |
90 | + const selectStock = stocks.filter((item) => item.storageId === Number(method.outStorageId))[0]; | |
91 | + setSelectStock({ ...selectStock }); | |
92 | + } | |
86 | 93 | } |
87 | 94 | } |
88 | 95 | }, [open, lackNum, method, inStocks]); |
... | ... | @@ -100,11 +107,11 @@ export default function EditMethod({ open, lackNum = 0, method, warehouses, onCa |
100 | 107 | const params = { ...values }; |
101 | 108 | // 区域库内/外调件,需要设置仓库信息 |
102 | 109 | if (isTransferInside || isTransferOutside) { |
103 | - const storageType = isTransferInside ? 'inStorage' : 'outStorage'; | |
110 | + const distStorage = warehouses[isTransferInside ? 'inStorage' : 'outStorage']; | |
104 | 111 | |
105 | - params.inDivision = warehouses[storageType].inDivision; | |
106 | - params.inDivisionBy = warehouses[storageType].inDividedBy; | |
107 | - params.shopId = warehouses[storageType].shopId; | |
112 | + params.inDivision = distStorage.inDivision; | |
113 | + params.inDivisionBy = distStorage.inDividedBy; | |
114 | + params.shopId = distStorage.shopId; | |
108 | 115 | |
109 | 116 | params.outDividedBy = selectStock.outDividedBy; |
110 | 117 | params.outDivision = selectStock.outDivision; | ... | ... |
src/pages/cas/workOrder/PartLackHandle/components/PartSelector.tsx
... | ... | @@ -5,8 +5,8 @@ import { CheckCircleOutlined } from '@ant-design/icons'; |
5 | 5 | import { debounce } from 'lodash'; |
6 | 6 | |
7 | 7 | import usePagination from '@/hooks/usePagination'; |
8 | -import type { WorkItemPart } from '../api'; | |
9 | -import { getWorkItemPartsApi } from '../api'; | |
8 | +import type { WorkItemPart } from '@/pages/cas/workOrder/PartLackHandle/api'; | |
9 | +import { getWorkItemPartsApi } from '@/pages/cas/workOrder/PartLackHandle/api'; | |
10 | 10 | |
11 | 11 | import st from '@/pages/cas/style.less'; |
12 | 12 | ... | ... |
src/pages/cas/workOrder/PartLackHandle/components/SingleHandler.tsx
... | ... | @@ -4,9 +4,9 @@ import { PlusOutlined } from '@ant-design/icons'; |
4 | 4 | |
5 | 5 | import useInitial from '@/hooks/useInitail'; |
6 | 6 | |
7 | -import { MethodNameEnum } from '../entity'; | |
8 | -import type { MethodType, Part, Stock, StorageResult } from '../api'; | |
9 | -import { getPartAreaTransferThresholdApi, getPartTransferStorageApi } from '../api'; | |
7 | +import { AreaStockEnum, MethodNameEnum } from '@/pages/cas/workOrder/PartLackHandle/entity'; | |
8 | +import type { LackPart, Method, Stock, StorageResult } from '@/pages/cas/workOrder/PartLackHandle/api'; | |
9 | +import { getPartAreaTransferThresholdApi, getPartTransferStorageApi } from '@/pages/cas/workOrder/PartLackHandle/api'; | |
10 | 10 | |
11 | 11 | import EditMethod from './EditMethod'; |
12 | 12 | |
... | ... | @@ -16,9 +16,9 @@ const Column = Table.Column; |
16 | 16 | interface Props { |
17 | 17 | open: boolean; |
18 | 18 | shopId: number; |
19 | - part: Part; | |
19 | + part: LackPart; | |
20 | 20 | onCancel: () => void; |
21 | - onConfirm: (newPart: Part) => void; | |
21 | + onConfirm: (newPart: LackPart) => void; | |
22 | 22 | } |
23 | 23 | |
24 | 24 | /** |
... | ... | @@ -27,6 +27,7 @@ interface Props { |
27 | 27 | export default function SingleHandler({ open, shopId, part, onCancel, onConfirm }: Props) { |
28 | 28 | const [delay, setDelay] = useState(true); |
29 | 29 | |
30 | + // 区域库内库存情况 | |
30 | 31 | const { |
31 | 32 | data: inStorage, |
32 | 33 | loading: inLoading, |
... | ... | @@ -37,10 +38,11 @@ export default function SingleHandler({ open, shopId, part, onCancel, onConfirm |
37 | 38 | { |
38 | 39 | partId: part.partId, |
39 | 40 | bizShopId: shopId, |
40 | - type: 1, | |
41 | + type: AreaStockEnum.INSIDE, | |
41 | 42 | }, |
42 | 43 | delay, |
43 | 44 | ); |
45 | + // 区域库外库存情况 | |
44 | 46 | const { |
45 | 47 | data: outStorage, |
46 | 48 | loading: outLoading, |
... | ... | @@ -51,15 +53,16 @@ export default function SingleHandler({ open, shopId, part, onCancel, onConfirm |
51 | 53 | { |
52 | 54 | partId: part.partId, |
53 | 55 | bizShopId: shopId, |
54 | - type: 2, | |
56 | + type: AreaStockEnum.OUTSIDE, | |
55 | 57 | }, |
56 | 58 | delay, |
57 | 59 | ); |
60 | + // 区域库内库销比调件阈值:区域库内有库存,且库销比大于该阈值,则必须选择区域库内调运 | |
58 | 61 | const { data: inRatioThreshold, setParams: setThresholdParams } = useInitial(getPartAreaTransferThresholdApi, 0, part.partId, delay); |
59 | 62 | |
60 | 63 | const [editOpen, setEditOpen] = useState(false); |
61 | 64 | const [currentIndex, setCurrentIndex] = useState(-1); |
62 | - const [currentMethod, setCurrentMethod] = useState({} as MethodType); | |
65 | + const [currentMethod, setCurrentMethod] = useState({} as Method); | |
63 | 66 | const [methods, setMethods] = useState(part.methods || []); |
64 | 67 | |
65 | 68 | const totalNum = useMemo(() => methods.map((m) => m.num || 0).reduce((prev, curr) => prev + curr, 0), [methods]); |
... | ... | @@ -101,17 +104,17 @@ export default function SingleHandler({ open, shopId, part, onCancel, onConfirm |
101 | 104 | |
102 | 105 | const handleAdd = () => { |
103 | 106 | setCurrentIndex(-1); |
104 | - setCurrentMethod({} as MethodType); | |
107 | + setCurrentMethod({} as Method); | |
105 | 108 | setEditOpen(true); |
106 | 109 | }; |
107 | 110 | |
108 | - const handleEdit = (method: MethodType, index: number) => { | |
111 | + const handleEdit = (method: Method, index: number) => { | |
109 | 112 | setCurrentIndex(index); |
110 | 113 | setCurrentMethod(method); |
111 | 114 | setEditOpen(true); |
112 | 115 | }; |
113 | 116 | |
114 | - const handleUpdate = (newMethod: MethodType) => { | |
117 | + const handleUpdate = (newMethod: Method) => { | |
115 | 118 | if (currentIndex === -1) { |
116 | 119 | methods.push(newMethod); // 新增 |
117 | 120 | } else { |
... | ... | @@ -119,7 +122,7 @@ export default function SingleHandler({ open, shopId, part, onCancel, onConfirm |
119 | 122 | } |
120 | 123 | setMethods([...methods]); |
121 | 124 | setCurrentIndex(-1); |
122 | - setCurrentMethod({} as MethodType); | |
125 | + setCurrentMethod({} as Method); | |
123 | 126 | setEditOpen(false); |
124 | 127 | }; |
125 | 128 | |
... | ... | @@ -172,7 +175,7 @@ export default function SingleHandler({ open, shopId, part, onCancel, onConfirm |
172 | 175 | <Column |
173 | 176 | title="处理方案" |
174 | 177 | dataIndex="index" |
175 | - render={(partId, record: MethodType) => ( | |
178 | + render={(partId, record: Method) => ( | |
176 | 179 | <div |
177 | 180 | style={{ |
178 | 181 | display: 'flex', |
... | ... | @@ -184,7 +187,7 @@ export default function SingleHandler({ open, shopId, part, onCancel, onConfirm |
184 | 187 | > |
185 | 188 | <div style={{ flex: 1.5 }}>调运方式:{MethodNameEnum[record.method]}</div> |
186 | 189 | {!!record.outStorageId ? <div style={{ flex: 1.5 }}>调出仓库:{record.outStorageName}</div> : <div style={{ flex: 1.5 }} />} |
187 | - {!!record.expectedDate ? <div style={{ flex: 1.2 }}>预计入库天数:{record.expectedDate}天</div> : <div style={{ flex: 1 }} />} | |
190 | + {!!record.expectedDate ? <div style={{ flex: 1.2 }}>预计入库天数:{record.expectedDate}天</div> : <div style={{ flex: 1.2 }} />} | |
188 | 191 | <div style={{ display: 'flex', flex: 1, justifyContent: 'center' }}>数量:{record.num}</div> |
189 | 192 | </div> |
190 | 193 | )} |
... | ... | @@ -194,7 +197,7 @@ export default function SingleHandler({ open, shopId, part, onCancel, onConfirm |
194 | 197 | width={180} |
195 | 198 | align="center" |
196 | 199 | dataIndex="lackNum" |
197 | - render={(val, record: MethodType, index) => ( | |
200 | + render={(val, record: Method, index) => ( | |
198 | 201 | <> |
199 | 202 | <Button type="link" onClick={() => handleEdit(record, index)}> |
200 | 203 | 编辑 | ... | ... |
src/pages/cas/workOrder/PartLackHandle/entity.ts
... | ... | @@ -10,6 +10,8 @@ export enum MethodEnum { |
10 | 10 | PURCHASE_BY_THIRD_PARTY = 3, |
11 | 11 | /** 区域库外调件 */ |
12 | 12 | TRANSFER_OUTSIDE = 4, |
13 | + /** 计划员处理 */ | |
14 | + PLANNER = 5, | |
13 | 15 | } |
14 | 16 | |
15 | 17 | export enum MethodNameEnum { |
... | ... | @@ -48,3 +50,10 @@ export const BatchMethodData = [ |
48 | 50 | value: MethodEnum.PURCHASE_BY_THIRD_PARTY, |
49 | 51 | }, |
50 | 52 | ]; |
53 | + | |
54 | +export enum AreaStockEnum { | |
55 | + /** 区域库内 */ | |
56 | + INSIDE = 1, | |
57 | + /** 区域库外 */ | |
58 | + OUTSIDE = 2, | |
59 | +} | ... | ... |
src/pages/cas/workOrder/PartLackHandle/index.tsx
1 | -import React, { useState } from 'react'; | |
1 | +import React from 'react'; | |
2 | 2 | import { PageHeaderWrapper } from '@ant-design/pro-layout'; |
3 | -import { Button, Card, Col, Input, Row, Table } from 'antd'; | |
4 | -import type { ColumnsType } from 'antd/lib/table'; | |
5 | -import { debounce } from 'lodash'; | |
6 | -import dayjs from 'dayjs'; | |
3 | +import { Card, Tabs } from 'antd'; | |
7 | 4 | |
8 | -import usePagination from '@/hooks/usePagination'; | |
9 | - | |
10 | -import { listApi, type ListResult } from './api'; | |
11 | - | |
12 | -import PartListModal from './components/PartListModal'; | |
13 | -import HandleModal from './components/HandleModal'; | |
14 | - | |
15 | -const Search = Input.Search; | |
5 | +import IndexOrder from './subpages/Order'; | |
6 | +import IndexBook from './subpages/Book'; | |
16 | 7 | |
17 | 8 | /** |
18 | - * 计划员:工单缺件处理 | |
9 | + * 计划员:工单、订件缺件处理 | |
19 | 10 | */ |
20 | 11 | export default function PartLackHandle() { |
21 | - const [dataId, setDataId] = useState(0); | |
22 | - const [openParts, setOpenParts] = useState(false); | |
23 | - const [openHandle, setOpenHandle] = useState(false); | |
24 | - | |
25 | - const { list, loading, setParams, setLoading, paginationConfig } = usePagination(listApi, {}); | |
26 | - | |
27 | - const handleSearch = debounce((keywords: string) => { | |
28 | - setParams({ keywords }, true); | |
29 | - }, 500); | |
30 | - | |
31 | - const showPartsModal = (dataId: number) => { | |
32 | - setDataId(dataId); | |
33 | - setOpenParts(true); | |
34 | - }; | |
35 | - | |
36 | - const showHandleModal = (dataId: number) => { | |
37 | - setDataId(dataId); | |
38 | - setOpenHandle(true); | |
39 | - }; | |
40 | - | |
41 | - const columns: ColumnsType<ListResult> = [ | |
42 | - { | |
43 | - title: '工单号', | |
44 | - dataIndex: 'orderNo', | |
45 | - fixed: 'left', | |
46 | - width: 100, | |
47 | - }, | |
48 | - { | |
49 | - title: '车牌号', | |
50 | - dataIndex: 'plateNo', | |
51 | - fixed: 'left', | |
52 | - width: 70, | |
53 | - }, | |
54 | - { | |
55 | - title: '车主', | |
56 | - dataIndex: 'ownerName', | |
57 | - width: 60, | |
58 | - }, | |
59 | - { | |
60 | - title: '车辆', | |
61 | - dataIndex: 'carName', | |
62 | - width: 150, | |
63 | - }, | |
12 | + const tabs = [ | |
64 | 13 | { |
65 | - title: 'VIN', | |
66 | - dataIndex: 'vin', | |
67 | - width: 120, | |
14 | + label: '工单缺件', | |
15 | + key: 'order', | |
16 | + children: <IndexOrder />, | |
68 | 17 | }, |
69 | 18 | { |
70 | - title: '车型代码', | |
71 | - dataIndex: 'specCode', | |
72 | - width: 140, | |
73 | - }, | |
74 | - { | |
75 | - title: '在修门店', | |
76 | - dataIndex: 'shopName', | |
77 | - width: 140, | |
78 | - }, | |
79 | - { | |
80 | - title: '服务顾问', | |
81 | - dataIndex: 'receiverName', | |
82 | - width: 60, | |
83 | - }, | |
84 | - { | |
85 | - title: '进站类型', | |
86 | - dataIndex: 'serviceCatName', | |
87 | - width: 70, | |
88 | - }, | |
89 | - { | |
90 | - title: '进站时间', | |
91 | - dataIndex: 'senderTime', | |
92 | - width: 70, | |
93 | - render: (senderTime: string) => dayjs(senderTime).format('YYYY-MM-DD HH:mm:ss'), | |
94 | - }, | |
95 | - { | |
96 | - title: '缺件清单', | |
97 | - dataIndex: 'dataId', | |
98 | - fixed: 'right', | |
99 | - width: 70, | |
100 | - align: 'center', | |
101 | - render: (dataId: number) => ( | |
102 | - <Button type="link" onClick={() => showPartsModal(dataId)}> | |
103 | - 查看 | |
104 | - </Button> | |
105 | - ), | |
106 | - }, | |
107 | - { | |
108 | - title: '操作', | |
109 | - dataIndex: 'dataId', | |
110 | - fixed: 'right', | |
111 | - width: 70, | |
112 | - align: 'center', | |
113 | - render: (dataId: number) => ( | |
114 | - <Button type="link" onClick={() => showHandleModal(dataId)}> | |
115 | - 处理 | |
116 | - </Button> | |
117 | - ), | |
19 | + label: '非工单缺件', | |
20 | + key: 'book', | |
21 | + children: <IndexBook />, | |
118 | 22 | }, |
119 | 23 | ]; |
120 | 24 | |
121 | 25 | return ( |
122 | - <PageHeaderWrapper title="工单缺件处理"> | |
26 | + <PageHeaderWrapper title="缺件处理"> | |
123 | 27 | <Card> |
124 | - <Row justify="space-between" style={{ marginBottom: 16 }}> | |
125 | - <Col> | |
126 | - <Search | |
127 | - style={{ width: 280 }} | |
128 | - placeholder="搜索工单号、车牌、VIN、车主" | |
129 | - allowClear | |
130 | - onChange={(e) => handleSearch(e.target.value)} | |
131 | - onSearch={handleSearch} | |
132 | - /> | |
133 | - </Col> | |
134 | - </Row> | |
135 | - | |
136 | - <Table dataSource={list} pagination={paginationConfig} rowKey="orderNo" loading={loading} columns={columns} bordered scroll={{ x: 1900 }} /> | |
28 | + <Tabs items={tabs} /> | |
137 | 29 | </Card> |
138 | - | |
139 | - <PartListModal | |
140 | - open={openParts} | |
141 | - dataId={dataId} | |
142 | - onCancel={() => { | |
143 | - setDataId(0); | |
144 | - setOpenParts(false); | |
145 | - }} | |
146 | - /> | |
147 | - | |
148 | - <HandleModal | |
149 | - open={openHandle} | |
150 | - dataId={dataId} | |
151 | - onCancel={() => { | |
152 | - setDataId(0); | |
153 | - setOpenHandle(false); | |
154 | - }} | |
155 | - onConfirm={() => { | |
156 | - setLoading(true); | |
157 | - setDataId(0); | |
158 | - setOpenHandle(false); | |
159 | - }} | |
160 | - /> | |
161 | 30 | </PageHeaderWrapper> |
162 | 31 | ); |
163 | 32 | } | ... | ... |
src/pages/cas/workOrder/PartLackHandle/subpages/Book/HandleModal.tsx
0 → 100644
1 | +import React, { useEffect, useState } from 'react'; | |
2 | +import { Button, Col, Descriptions, Divider, List, message, Modal, Row, Skeleton, Table } from 'antd'; | |
3 | +import type { ColumnsType } from 'antd/lib/table'; | |
4 | +import { ArrowUpOutlined, ExclamationCircleOutlined } from '@ant-design/icons'; | |
5 | +import moment from 'moment'; | |
6 | +import { cloneDeep, differenceBy, isEmpty } from 'lodash'; | |
7 | + | |
8 | +import useInitail from '@/hooks/useInitail'; | |
9 | + | |
10 | +import { MethodEnum, MethodNameEnum } from '@/pages/cas/workOrder/PartLackHandle/entity'; | |
11 | +import type { LackPart, Method, WorkItemPart } from '@/pages/cas/workOrder/PartLackHandle/api'; | |
12 | +import type { BookPart, DetailResult, SaveParams, Type, GetBearTypeInfoReq } from './api'; | |
13 | +import { detailApi, saveApi, getBearTypeInfo } from './api'; | |
14 | + | |
15 | +import SingleHandler from '@/pages/cas/workOrder/PartLackHandle/components/SingleHandler'; | |
16 | +import BatchHandler from '@/pages/cas/workOrder/PartLackHandle/components/BatchHandler'; | |
17 | +import PartSelector from '@/pages/cas/workOrder/PartLackHandle/components/PartSelector'; | |
18 | + | |
19 | +import st from '@/pages/cas/style.less'; | |
20 | + | |
21 | +const DescriptionItem = Descriptions.Item; | |
22 | + | |
23 | +interface Props { | |
24 | + open: boolean; | |
25 | + dataId: number; | |
26 | + onCancel: () => any; | |
27 | + onConfirm: () => any; | |
28 | +} | |
29 | + | |
30 | +export default function HandleModal({ open, dataId, onCancel, onConfirm }: Props) { | |
31 | + const [delay, setDelay] = useState(true); | |
32 | + const { data, loading, setParams } = useInitail(detailApi, {} as DetailResult, dataId, delay); | |
33 | + | |
34 | + const [parts, setParts] = useState<LackPart[]>([]); | |
35 | + const [batchParts, setBatchParts] = useState([] as LackPart[]); | |
36 | + const [currentIndex, setCurrentIndex] = useState(0); | |
37 | + const [currentRecord, setCurrentRecord] = useState({} as LackPart); | |
38 | + const [singleOpen, setSingleOpen] = useState(false); | |
39 | + const [batchOpen, setBatchOpen] = useState(false); | |
40 | + const [partSelectorOpen, setPartSelectorOpen] = useState(false); | |
41 | + const [submitting, setSubmitting] = useState(false); | |
42 | + | |
43 | + useEffect(() => { | |
44 | + if (open && dataId) { | |
45 | + setDelay(false); | |
46 | + setParams(dataId, true); | |
47 | + } | |
48 | + }, [open, dataId]); | |
49 | + | |
50 | + useEffect(() => { | |
51 | + if (data.parts) { | |
52 | + const initParts: LackPart[] = []; | |
53 | + data.parts.forEach((part) => { | |
54 | + // 顾问选择的区域库内调件,初始化为 method 信息,否则不添加 methods 字段,需要计划员新添加处理方式 | |
55 | + if (part.del || isEmpty(part.types)) { | |
56 | + return; | |
57 | + } | |
58 | + | |
59 | + // 提取基础数据,用于缺件处理 | |
60 | + const lackPart: LackPart = { | |
61 | + partId: part.partId, | |
62 | + partCode: part.partCode, | |
63 | + partName: part.partName, | |
64 | + lackNum: part.partCnt, | |
65 | + }; | |
66 | + | |
67 | + // 需计划员处理:不初始化 methods 字段,手动添加处理方式 | |
68 | + if (part.types.some((item) => item.type === MethodEnum.PLANNER)) { | |
69 | + initParts.push(lackPart); | |
70 | + return; | |
71 | + } | |
72 | + // 顾问已处理:初始化,计划员可修改 | |
73 | + lackPart.methods = part.types.map((item) => ({ | |
74 | + ...item, | |
75 | + method: item.type, | |
76 | + num: item.quantity, | |
77 | + })); | |
78 | + initParts.push(lackPart); | |
79 | + }); | |
80 | + setParts([...initParts]); | |
81 | + } | |
82 | + }, [data]); | |
83 | + | |
84 | + // 批量处理 | |
85 | + const showBatchHandleModal = () => { | |
86 | + // todo 区域库内有件的配件,不能批量处理,web是否继续保持该规则,需要时再次过滤 | |
87 | + const unhandledParts = parts.filter((part) => isEmpty(part.methods)); | |
88 | + setBatchParts(unhandledParts); | |
89 | + setBatchOpen(true); | |
90 | + }; | |
91 | + | |
92 | + // 批量更新处理完的配件 | |
93 | + | |
94 | + const handleBatchUpdate = (newBatchParts: LackPart[]) => { | |
95 | + const notBatchParts = differenceBy(parts, newBatchParts, 'partId'); | |
96 | + setParts([...notBatchParts, ...newBatchParts]); | |
97 | + setBatchOpen(false); | |
98 | + }; | |
99 | + // 单个编辑 | |
100 | + | |
101 | + const handlePartEdit = (record: LackPart, index: number) => { | |
102 | + setCurrentIndex(index); | |
103 | + setCurrentRecord(record); | |
104 | + setSingleOpen(true); | |
105 | + }; | |
106 | + // 单个更新 | |
107 | + | |
108 | + const handlePartUpdate = (newPart: LackPart, index: number) => { | |
109 | + parts[index] = newPart; | |
110 | + setParts([...parts]); | |
111 | + setSingleOpen(false); | |
112 | + }; | |
113 | + // 显示变更配件 | |
114 | + | |
115 | + const handlePartChange = (record: LackPart, index: number) => { | |
116 | + setCurrentIndex(index); | |
117 | + setCurrentRecord(record); | |
118 | + setPartSelectorOpen(true); | |
119 | + }; | |
120 | + | |
121 | + // 变更配件 | |
122 | + const handlePartReplace = (newPart: WorkItemPart, index: number) => { | |
123 | + const oldPart = cloneDeep(parts[index]); | |
124 | + // 使用新配件替换原配件 | |
125 | + parts[index] = { | |
126 | + // new part info | |
127 | + partId: newPart.partId, | |
128 | + partName: newPart.partName, | |
129 | + partCode: newPart.partCode, | |
130 | + // old part info | |
131 | + lackNum: oldPart.lackNum, | |
132 | + oldPart, // retain old part info for rollback | |
133 | + }; | |
134 | + setParts([...parts]); | |
135 | + setPartSelectorOpen(false); | |
136 | + }; | |
137 | + | |
138 | + const checkPartPrice = (newPart: WorkItemPart, index: number) => { | |
139 | + const params: GetBearTypeInfoReq = { | |
140 | + vin: data.vin, | |
141 | + shopId: data.shopId, | |
142 | + draftId: data.id, | |
143 | + parts: [{ partId: newPart.partId, partCnt: newPart.partCnt }], | |
144 | + } | |
145 | + getBearTypeInfo(params).then((res) => { | |
146 | + const partInfo = res.data?.parts[0]; | |
147 | + if (!partInfo?.bookPrice || partInfo?.bookPrice <= 0) { | |
148 | + Modal.confirm({ | |
149 | + title: '提示', | |
150 | + icon: <ExclamationCircleOutlined />, | |
151 | + content: '该配件没有售价,请先导入加权成本价或配置指定价格', | |
152 | + okText: '确认', | |
153 | + cancelText: '取消', | |
154 | + }); | |
155 | + } else { | |
156 | + // 执行替换配件 | |
157 | + handlePartReplace(newPart, index); | |
158 | + } | |
159 | + }); | |
160 | + }; | |
161 | + | |
162 | + // 撤销变更 | |
163 | + const handlePartRollback = (index: number) => { | |
164 | + const oldPart = cloneDeep(parts[index].oldPart); | |
165 | + parts.splice(index, 1, oldPart!); | |
166 | + setParts([...parts]); | |
167 | + }; | |
168 | + | |
169 | + function resetPageData() { | |
170 | + setParts([]); | |
171 | + setBatchParts([]); | |
172 | + } | |
173 | + | |
174 | + function assembleParts() { | |
175 | + // 配件对应处理方式数据 | |
176 | + const partMethodMap: { [key: string]: Type[] } = {}; | |
177 | + parts.forEach((part) => { | |
178 | + // 组装数据 | |
179 | + partMethodMap[part.partId] = | |
180 | + part.methods?.map((m) => { | |
181 | + const temp = { | |
182 | + ...m, | |
183 | + type: m.method, | |
184 | + quantity: m.num, | |
185 | + }; | |
186 | + // @ts-ignore | |
187 | + delete temp.method; | |
188 | + // @ts-ignore | |
189 | + delete temp.num; | |
190 | + return temp; | |
191 | + }) || []; | |
192 | + }); | |
193 | + | |
194 | + const finalParts: BookPart[] = []; | |
195 | + data.parts.forEach((part) => { | |
196 | + // 无需处理的数据,需要回传 | |
197 | + if (part.del || isEmpty(part.types)) { | |
198 | + finalParts.push(part); | |
199 | + return; | |
200 | + } | |
201 | + part.types = partMethodMap[part.partId]; | |
202 | + finalParts.push(part); | |
203 | + }); | |
204 | + return finalParts; | |
205 | + } | |
206 | + | |
207 | + function handleSubmit() { | |
208 | + if (parts.some((e) => !e.methods)) { | |
209 | + message.warn('请添加缺件处理方式'); | |
210 | + return; | |
211 | + } | |
212 | + | |
213 | + const params: SaveParams = { | |
214 | + type: 2, | |
215 | + parts: assembleParts(), | |
216 | + }; | |
217 | + setSubmitting(true); | |
218 | + saveApi(dataId, params) | |
219 | + .then(() => { | |
220 | + message.success('操作成功', 1, onConfirm); | |
221 | + resetPageData(); | |
222 | + }) | |
223 | + .catch((err) => { | |
224 | + Modal.confirm({ | |
225 | + title: '提示', | |
226 | + icon: <ExclamationCircleOutlined />, | |
227 | + content: err.message || '操作失败', | |
228 | + keyboard: false, | |
229 | + okText: '确认', | |
230 | + cancelText: '取消', | |
231 | + }); | |
232 | + }) | |
233 | + .finally(() => { | |
234 | + setSubmitting(false); | |
235 | + }); | |
236 | + } | |
237 | + | |
238 | + function renderCompareText(prevText: string, text: string) { | |
239 | + return ( | |
240 | + <div className={st.rowColumnLeft}> | |
241 | + <p className={st.colorDanger}>{text}</p> | |
242 | + <ArrowUpOutlined size={12} style={{ marginTop: '1em', marginBottom: '1em', paddingLeft: '1em' }} /> | |
243 | + <p>{prevText}</p> | |
244 | + </div> | |
245 | + ); | |
246 | + } | |
247 | + | |
248 | + const columns: ColumnsType<LackPart> = [ | |
249 | + { | |
250 | + title: '配件名称', | |
251 | + dataIndex: 'partName', | |
252 | + width: '30%', | |
253 | + render: (partName, record) => (record.oldPart ? renderCompareText(record.oldPart.partName, partName) : partName), | |
254 | + }, | |
255 | + { | |
256 | + title: '配件编码', | |
257 | + dataIndex: 'partCode', | |
258 | + width: '15%', | |
259 | + render: (partCode, record) => (record.oldPart ? renderCompareText(record.oldPart.partCode, partCode) : partCode), | |
260 | + }, | |
261 | + { | |
262 | + title: '数量', | |
263 | + dataIndex: 'lackNum', | |
264 | + width: '15%', | |
265 | + }, | |
266 | + { | |
267 | + title: '处理方案', | |
268 | + dataIndex: 'partId', | |
269 | + width: '20%', | |
270 | + render: (partId, record) => ( | |
271 | + <List | |
272 | + itemLayout="horizontal" | |
273 | + locale={{ emptyText: '暂无处理方案' }} | |
274 | + dataSource={record.methods || []} | |
275 | + renderItem={(item: Method) => ( | |
276 | + <List.Item> | |
277 | + <List.Item.Meta | |
278 | + title={MethodNameEnum[item.method]} | |
279 | + description={ | |
280 | + <> | |
281 | + {item.outStorageName && <p style={{ marginBottom: 0 }}>调出仓库:{item.outStorageName}</p>} | |
282 | + {item.expectedDate && <p style={{ marginBottom: 0 }}>预计入库天数:{item.expectedDate}</p>} | |
283 | + <p style={{ marginBottom: 0 }}> | |
284 | + 数量:<span style={{ color: '#FF921C' }}>{item.num}</span> | |
285 | + </p> | |
286 | + </> | |
287 | + } | |
288 | + /> | |
289 | + </List.Item> | |
290 | + )} | |
291 | + /> | |
292 | + ), | |
293 | + }, | |
294 | + { | |
295 | + title: '操作', | |
296 | + dataIndex: 'partId', | |
297 | + width: 200, | |
298 | + align: 'center', | |
299 | + render: (partId, record: LackPart, index) => ( | |
300 | + <> | |
301 | + {record.oldPart ? ( | |
302 | + <Button type="link" danger onClick={() => handlePartRollback(index)}> | |
303 | + 撤销变更 | |
304 | + </Button> | |
305 | + ) : ( | |
306 | + <Button type="link" onClick={() => handlePartChange(record, index)}> | |
307 | + 变更配件 | |
308 | + </Button> | |
309 | + )} | |
310 | + <Divider type="vertical" /> | |
311 | + {record.methods ? ( | |
312 | + <Button type="link" onClick={() => handlePartEdit(record, index)}> | |
313 | + 修改 | |
314 | + </Button> | |
315 | + ) : ( | |
316 | + <Button type="link" onClick={() => handlePartEdit(record, index)}> | |
317 | + 缺件处理 | |
318 | + </Button> | |
319 | + )} | |
320 | + </> | |
321 | + ), | |
322 | + }, | |
323 | + ]; | |
324 | + | |
325 | + return ( | |
326 | + <Modal | |
327 | + title="缺件处理" | |
328 | + open={open} | |
329 | + maskClosable={false} | |
330 | + width={1200} | |
331 | + confirmLoading={submitting} | |
332 | + okButtonProps={{ disabled: loading }} | |
333 | + cancelButtonProps={{ disabled: submitting }} | |
334 | + okText="提交" | |
335 | + onCancel={() => onCancel()} | |
336 | + onOk={handleSubmit} | |
337 | + > | |
338 | + <Skeleton loading={loading} active title={false} paragraph={{ rows: 3, width: '100%' }}> | |
339 | + <Descriptions> | |
340 | + <DescriptionItem label="车牌号">{data.plateNo}</DescriptionItem> | |
341 | + <DescriptionItem label="车主">{data.ownerName}</DescriptionItem> | |
342 | + <DescriptionItem label="车辆">{data.carName}</DescriptionItem> | |
343 | + <DescriptionItem label="VIN">{data.vin}</DescriptionItem> | |
344 | + <DescriptionItem label="车型代码">{data.specCode}</DescriptionItem> | |
345 | + <DescriptionItem label="服务顾问">{data.username}</DescriptionItem> | |
346 | + <DescriptionItem label="订件时间">{moment(data.createTime).format('YYYY-MM-DD HH:mm')}</DescriptionItem> | |
347 | + </Descriptions> | |
348 | + </Skeleton> | |
349 | + | |
350 | + <Divider /> | |
351 | + <Row justify="end" style={{ marginBottom: 20 }}> | |
352 | + <Col> | |
353 | + <Button type="primary" disabled={loading} onClick={showBatchHandleModal}> | |
354 | + 批量处理 | |
355 | + </Button> | |
356 | + </Col> | |
357 | + </Row> | |
358 | + | |
359 | + <Skeleton loading={loading} active title={false} paragraph={{ rows: 4, width: '100%' }}> | |
360 | + <Table loading={loading} dataSource={parts} pagination={false} rowKey="partId" columns={columns} scroll={{ y: 600 }} /> | |
361 | + </Skeleton> | |
362 | + | |
363 | + <SingleHandler | |
364 | + open={singleOpen} | |
365 | + shopId={data.shopId} | |
366 | + part={currentRecord} | |
367 | + onCancel={() => setSingleOpen(false)} | |
368 | + onConfirm={(newPart) => handlePartUpdate(newPart, currentIndex)} | |
369 | + /> | |
370 | + | |
371 | + <BatchHandler | |
372 | + open={batchOpen} | |
373 | + shopId={data.shopId} | |
374 | + parts={batchParts} | |
375 | + onCancel={() => { | |
376 | + setBatchOpen(false); | |
377 | + setBatchParts([]); | |
378 | + }} | |
379 | + onConfirm={handleBatchUpdate} | |
380 | + /> | |
381 | + | |
382 | + <PartSelector | |
383 | + open={partSelectorOpen} | |
384 | + base={{ shopId: data.shopId, vin: data.vin, specCode: data.specCode }} | |
385 | + selectIds={parts.map((item) => item.partId)} | |
386 | + onCancel={() => setPartSelectorOpen(false)} | |
387 | + onConfirm={(newPart) => checkPartPrice(newPart, currentIndex)} | |
388 | + /> | |
389 | + </Modal> | |
390 | + ); | |
391 | +} | ... | ... |
src/pages/cas/workOrder/PartLackHandle/subpages/Book/PartListModal.tsx
0 → 100644
1 | +import React from 'react'; | |
2 | +import { Modal, Table } from 'antd'; | |
3 | +import type { ColumnsType } from 'antd/lib/table'; | |
4 | +import { isEmpty } from 'lodash'; | |
5 | + | |
6 | +// import useInitail from '@/hooks/useInitail'; | |
7 | +import type { BookPart } from './api'; | |
8 | + | |
9 | +// import { detailApi } from './api'; | |
10 | + | |
11 | +interface Props { | |
12 | + open: boolean; | |
13 | + dataId: number; | |
14 | + data: BookPart[]; | |
15 | + onCancel: () => any; | |
16 | +} | |
17 | + | |
18 | +/** | |
19 | + * 配件清单 | |
20 | + * @desc 订件配件列表,包含所有配件,缺件清单及处理时,需要顾虑掉 del=true 或者 types=[] 的配件 | |
21 | + */ | |
22 | +export default function PartListModal({ open, data, onCancel }: Props) { | |
23 | + // const [delay, setDelay] = useState(true); | |
24 | + | |
25 | + // const { data, loading, setParams } = useInitail(detailApi, {} as DetailResult, dataId, delay); | |
26 | + const needHandleParts = | |
27 | + data.map((item) => { | |
28 | + if (item.del || isEmpty(item.types)) { | |
29 | + return; | |
30 | + } | |
31 | + return item; | |
32 | + }) || ([] as BookPart[]); | |
33 | + | |
34 | + // useEffect(() => { | |
35 | + // if (open && dataId) { | |
36 | + // setDelay(false); | |
37 | + // setParams(dataId, true); | |
38 | + // } | |
39 | + // }, [open]); | |
40 | + | |
41 | + const columns: ColumnsType<BookPart> = [ | |
42 | + { | |
43 | + title: '配件名称', | |
44 | + dataIndex: 'partName', | |
45 | + }, | |
46 | + { | |
47 | + title: '配件编码', | |
48 | + dataIndex: 'partCode', | |
49 | + }, | |
50 | + { | |
51 | + title: '数量', | |
52 | + dataIndex: 'partCnt', | |
53 | + }, | |
54 | + ]; | |
55 | + | |
56 | + return ( | |
57 | + <Modal title="配件清单" open={open} width={700} footer={null} onCancel={onCancel}> | |
58 | + <Table | |
59 | + // loading={loading} | |
60 | + dataSource={needHandleParts.filter((item) => item)} | |
61 | + pagination={{ pageSize: 10, showSizeChanger: false, showTotal: (total) => `共 ${total} 条` }} | |
62 | + rowKey="partId" | |
63 | + columns={columns} | |
64 | + /> | |
65 | + </Modal> | |
66 | + ); | |
67 | +} | ... | ... |
src/pages/cas/workOrder/PartLackHandle/subpages/Book/api.ts
0 → 100644
1 | +import { http } from '@/typing/http'; | |
2 | +import request from '@/utils/request'; | |
3 | +import { CAS_HOST } from '@/utils/host'; | |
4 | + | |
5 | +type P<T> = http.PromiseResp<T>; | |
6 | +type Page<T> = http.PromisePageResp<T>; | |
7 | + | |
8 | +interface ListParams { | |
9 | + groupId?: number; | |
10 | + shopId?: number; | |
11 | + userId?: number; | |
12 | + userName?: string; | |
13 | + pageSize?: number; | |
14 | + current?: number; | |
15 | + keywords?: string; | |
16 | +} | |
17 | + | |
18 | +export interface ListResult { | |
19 | + dataId: number; // 缺件单id | |
20 | + plateNo: number; // 车牌号 | |
21 | + ownerName: number; // 车主 | |
22 | + carName: number; // 车辆名称 | |
23 | + vin: number; // 车架号 | |
24 | + specCode: number; // 车型代码 | |
25 | + adviserName: number; // 服务顾问 | |
26 | + createTime: number; // 订件时间 | |
27 | + parts: BookPart[], // 配件:包含不缺件配件和已删除配件 | |
28 | +} | |
29 | + | |
30 | +export interface DetailResult { | |
31 | + id: number; // 订件草稿id | |
32 | + vin: string; // 车架号 | |
33 | + plateNo: string; // 车牌号 | |
34 | + carName: string; // 车辆名称 | |
35 | + ownerName: string; // 车主 | |
36 | + parts: BookPart[]; // 配件列表,只展示订件数量大于库存且del为false的配件 | |
37 | + totalAmount: number; // 填写的总金额 | |
38 | + createTime: number; // 订件时间 | |
39 | + status: number; // 状态 | |
40 | + expectAmount: number; // 预付订金合计 | |
41 | + customerId: number; | |
42 | + changeable: boolean; // 是否可以变更或退订 | |
43 | + shopName: string; // 门店名称 | |
44 | + username: string; // 服务顾问 | |
45 | + partBookId: number; // 订件id | |
46 | + statusName: string; // 状态名称 | |
47 | + specCode: string; // 配置代码 | |
48 | + orderId: number; // 工单id | |
49 | + orderNo: string; // 工单号 | |
50 | + shopId: number; // 门店id | |
51 | + adjustReason: string; // 调整原因 | |
52 | +} | |
53 | + | |
54 | +export interface Type { | |
55 | + type: number; | |
56 | + quantity: number; | |
57 | + expectedDate?: number; | |
58 | + shopId?: number; | |
59 | + outStorageId?: number; | |
60 | + outStorageName?: string; | |
61 | + outDividedBy?: number; | |
62 | + outDivision?: number; | |
63 | + inDividedBy?: number; | |
64 | + inDivision?: number; | |
65 | +} | |
66 | + | |
67 | +export interface BookPart { | |
68 | + partId: number; | |
69 | + partCode: string; | |
70 | + partName: string; | |
71 | + bearType: number; | |
72 | + partCnt: number; | |
73 | + stockCnt?: number; | |
74 | + retailPrice?: number; | |
75 | + bookPrice?: number; | |
76 | + types: Type[]; | |
77 | + planConfirmed?: boolean; | |
78 | + del?: boolean; | |
79 | + confirmCode?: string; | |
80 | + lockCnt?: number; | |
81 | +} | |
82 | + | |
83 | +// 列表-订件 | |
84 | +export function listApi(params: ListParams): Page<ListResult> { | |
85 | + return request.get(`${CAS_HOST}/erp/customer/book`, { params }); | |
86 | +} | |
87 | + | |
88 | +// 详情-订件 | |
89 | +export function detailApi(draftId: number): P<DetailResult> { | |
90 | + return request.get(`${CAS_HOST}/620/part/book/${draftId}`); | |
91 | +} | |
92 | + | |
93 | +// 保存-订件 | |
94 | +export interface SaveParams { | |
95 | + parts: BookPart[]; | |
96 | + type: 1 | 2; // 1: 驳回,2:确认 | |
97 | + planRemark?: string; | |
98 | +} | |
99 | + | |
100 | +// 订件缺件确认 | |
101 | +export function saveApi(draftId: number, params: SaveParams): P<any> { | |
102 | + return request.put(`${CAS_HOST}/620/part/book/process/${draftId}`, { ...params }); | |
103 | +} | |
104 | + | |
105 | +export interface GetBearTypeInfoItem { | |
106 | + partId: number; | |
107 | + partCnt: number; | |
108 | +} | |
109 | + | |
110 | +export interface GetBearTypeInfoReq { | |
111 | + vin?: string; | |
112 | + shopId: number; | |
113 | + draftId?: number; | |
114 | + parts: GetBearTypeInfoItem[]; | |
115 | +} | |
116 | + | |
117 | +export interface BearTypePartItem { | |
118 | + partId: number; | |
119 | + bearType: number; | |
120 | + retailPrice: number; // 售价 | |
121 | + bookPrice: number; // 订件价格 | |
122 | + partCnt: number; | |
123 | +} | |
124 | +export interface GetBearTypeInfoRes { | |
125 | + parts: BearTypePartItem[]; | |
126 | + expectAmount: number; | |
127 | + paid?: number; | |
128 | +} | |
129 | + | |
130 | +// 查询订件价格 | |
131 | +export function getBearTypeInfo(params: GetBearTypeInfoReq): P<GetBearTypeInfoRes> { | |
132 | + return request.post(`${CAS_HOST}/620/part/book/bear`, { ...params }); | |
133 | +} | ... | ... |
src/pages/cas/workOrder/PartLackHandle/subpages/Book/index.tsx
0 → 100644
1 | +import React, { useState } from 'react'; | |
2 | +import { Button, Col, Input, Row, Table } from 'antd'; | |
3 | +import type { ColumnsType } from 'antd/lib/table'; | |
4 | +import { debounce } from 'lodash'; | |
5 | +import dayjs from 'dayjs'; | |
6 | + | |
7 | +import usePagination from '@/hooks/usePagination'; | |
8 | + | |
9 | +import { listApi, type ListResult, type BookPart } from './api'; | |
10 | + | |
11 | +import PartListModal from './PartListModal'; | |
12 | +import HandleModal from './HandleModal'; | |
13 | + | |
14 | +const Search = Input.Search; | |
15 | + | |
16 | +/** | |
17 | + * 计划员:订件缺件处理 | |
18 | + */ | |
19 | +export default function PartLackHandle() { | |
20 | + const [dataId, setDataId] = useState(0); | |
21 | + const [openParts, setOpenParts] = useState(false); | |
22 | + const [openHandle, setOpenHandle] = useState(false); | |
23 | + // 缺件配件列表 | |
24 | + const [lackParts, setLackParts] = useState<BookPart[]>([]); | |
25 | + | |
26 | + const { list, loading, setParams, setLoading, paginationConfig } = usePagination(listApi, {}); | |
27 | + | |
28 | + const handleSearch = debounce((keywords: string) => { | |
29 | + setParams({ keywords }, true); | |
30 | + }, 500); | |
31 | + | |
32 | + const showPartsModal = (dataId: number) => { | |
33 | + setDataId(dataId); | |
34 | + setOpenParts(true); | |
35 | + }; | |
36 | + | |
37 | + const showHandleModal = (dataId: number) => { | |
38 | + setDataId(dataId); | |
39 | + setOpenHandle(true); | |
40 | + }; | |
41 | + | |
42 | + const columns: ColumnsType<ListResult> = [ | |
43 | + { | |
44 | + title: '车牌号', | |
45 | + dataIndex: 'plateNo', | |
46 | + fixed: 'left', | |
47 | + width: 70, | |
48 | + }, | |
49 | + { | |
50 | + title: '车主', | |
51 | + dataIndex: 'ownerName', | |
52 | + width: 60, | |
53 | + }, | |
54 | + { | |
55 | + title: '车辆', | |
56 | + dataIndex: 'carName', | |
57 | + width: 150, | |
58 | + }, | |
59 | + { | |
60 | + title: 'VIN', | |
61 | + dataIndex: 'vin', | |
62 | + width: 120, | |
63 | + }, | |
64 | + { | |
65 | + title: '车型代码', | |
66 | + dataIndex: 'specCode', | |
67 | + width: 140, | |
68 | + }, | |
69 | + { | |
70 | + title: '服务顾问', | |
71 | + dataIndex: 'adviserName', | |
72 | + width: 60, | |
73 | + }, | |
74 | + { | |
75 | + title: '订件时间', | |
76 | + dataIndex: 'createTime', | |
77 | + width: 70, | |
78 | + render: (val: number) => dayjs(val).format('YYYY-MM-DD HH:mm:ss'), | |
79 | + }, | |
80 | + { | |
81 | + title: '缺件清单', | |
82 | + dataIndex: 'dataId', | |
83 | + fixed: 'right', | |
84 | + width: 70, | |
85 | + align: 'center', | |
86 | + render: (dataId: number, record) => ( | |
87 | + <Button | |
88 | + type="link" | |
89 | + onClick={() => { | |
90 | + setLackParts(record.parts); | |
91 | + showPartsModal(dataId); | |
92 | + }} | |
93 | + > | |
94 | + 查看 | |
95 | + </Button> | |
96 | + ), | |
97 | + }, | |
98 | + { | |
99 | + title: '操作', | |
100 | + dataIndex: 'dataId', | |
101 | + fixed: 'right', | |
102 | + width: 70, | |
103 | + align: 'center', | |
104 | + render: (dataId: number) => ( | |
105 | + <Button type="link" onClick={() => showHandleModal(dataId)}> | |
106 | + 处理 | |
107 | + </Button> | |
108 | + ), | |
109 | + }, | |
110 | + ]; | |
111 | + | |
112 | + return ( | |
113 | + <div> | |
114 | + <Row justify="space-between" style={{ marginBottom: 16 }}> | |
115 | + <Col> | |
116 | + <Search | |
117 | + style={{ width: 280 }} | |
118 | + placeholder="搜索车牌、VIN、车主" | |
119 | + allowClear | |
120 | + onChange={(e) => handleSearch(e.target.value)} | |
121 | + onSearch={handleSearch} | |
122 | + /> | |
123 | + </Col> | |
124 | + </Row> | |
125 | + | |
126 | + <Table dataSource={list} pagination={paginationConfig} rowKey="orderNo" loading={loading} columns={columns} bordered scroll={{ x: 1900 }} /> | |
127 | + | |
128 | + <PartListModal | |
129 | + open={openParts} | |
130 | + dataId={dataId} | |
131 | + data={lackParts} | |
132 | + onCancel={() => { | |
133 | + setDataId(0); | |
134 | + setOpenParts(false); | |
135 | + setLackParts([]); | |
136 | + }} | |
137 | + /> | |
138 | + | |
139 | + <HandleModal | |
140 | + open={openHandle} | |
141 | + dataId={dataId} | |
142 | + onCancel={() => { | |
143 | + setDataId(0); | |
144 | + setOpenHandle(false); | |
145 | + }} | |
146 | + onConfirm={() => { | |
147 | + setLoading(true); | |
148 | + setDataId(0); | |
149 | + setOpenHandle(false); | |
150 | + }} | |
151 | + /> | |
152 | + </div> | |
153 | + ); | |
154 | +} | ... | ... |
src/pages/cas/workOrder/PartLackHandle/components/HandleModal.tsx renamed to src/pages/cas/workOrder/PartLackHandle/subpages/Order/HandleModal.tsx
... | ... | @@ -8,12 +8,13 @@ import { cloneDeep, differenceBy, isEmpty } from 'lodash'; |
8 | 8 | import useInitail from '@/hooks/useInitail'; |
9 | 9 | |
10 | 10 | import { MethodEnum, MethodNameEnum } from '@/pages/cas/workOrder/PartLackHandle/entity'; |
11 | -import type { DetailResult, MethodType, Part, SaveParams, WorkItemPart } from '../api'; | |
12 | -import { detailApi, saveApi, SavePart } from '../api'; | |
11 | +import type { WorkItemPart } from '@/pages/cas/workOrder/PartLackHandle/api'; | |
12 | +import type { DetailResult, MethodType, Part, SaveParams } from './api'; | |
13 | +import { detailApi, saveApi, SavePart } from './api'; | |
13 | 14 | |
14 | -import SingleHandler from './SingleHandler'; | |
15 | -import BatchHandler from './BatchHandler'; | |
16 | -import PartSelector from './PartSelector'; | |
15 | +import SingleHandler from '@/pages/cas/workOrder/PartLackHandle/components/SingleHandler'; | |
16 | +import BatchHandler from '@/pages/cas/workOrder/PartLackHandle/components/BatchHandler'; | |
17 | +import PartSelector from '@/pages/cas/workOrder/PartLackHandle/components/PartSelector'; | |
17 | 18 | |
18 | 19 | import st from '@/pages/cas/style.less'; |
19 | 20 | ... | ... |
src/pages/cas/workOrder/PartLackHandle/components/PartListModal.tsx renamed to src/pages/cas/workOrder/PartLackHandle/subpages/Order/PartListModal.tsx
... | ... | @@ -3,8 +3,8 @@ import { Modal, Table } from 'antd'; |
3 | 3 | import type { ColumnsType } from 'antd/lib/table'; |
4 | 4 | |
5 | 5 | import useInitail from '@/hooks/useInitail'; |
6 | -import type { DetailResult, Part } from '../api'; | |
7 | -import { detailApi } from '../api'; | |
6 | +import type { DetailResult, Part } from './api'; | |
7 | +import { detailApi } from './api'; | |
8 | 8 | |
9 | 9 | interface Props { |
10 | 10 | open: boolean; | ... | ... |
src/pages/cas/workOrder/PartLackHandle/subpages/Order/api.ts
0 → 100644
1 | +import { http } from '@/typing/http'; | |
2 | +import request from '@/utils/request'; | |
3 | +import { CAS_HOST } from '@/utils/host'; | |
4 | +import { TransferItem } from '@/pages/cas/workOrder/PartLackHandle/api'; | |
5 | + | |
6 | +type P<T> = http.PromiseResp<T>; | |
7 | +type Page<T> = http.PromisePageResp<T>; | |
8 | + | |
9 | +interface ListParams { | |
10 | + groupId?: number; | |
11 | + shopId?: number; | |
12 | + userId?: number; | |
13 | + userName?: string; | |
14 | + pageSize?: number; | |
15 | + current?: number; | |
16 | + keywords?: string; | |
17 | +} | |
18 | + | |
19 | +export interface ListResult { | |
20 | + dataId: number; // 缺件单id | |
21 | + orderNo: number; // 工单号 | |
22 | + plateNo: number; // 车牌号 | |
23 | + ownerName: number; // 车主 | |
24 | + carName: number; // 车辆名称 | |
25 | + vin: number; // 车架号 | |
26 | + specCode: number; // 车型代码 | |
27 | + shopName: number; // 在修门店 | |
28 | + receiverName: number; // 服务顾问 | |
29 | + senderTime: number; // 进站时间 | |
30 | + serviceCatName: number; // 进站类型 | |
31 | +} | |
32 | + | |
33 | +export interface DetailResult { | |
34 | + lackListId: number; | |
35 | + quoteId: number; | |
36 | + ownerName: string; | |
37 | + phone: number; | |
38 | + brandId: number; | |
39 | + plateNo: string; | |
40 | + carName: string; | |
41 | + vin: string; | |
42 | + specCode: string; | |
43 | + senderTime: number; | |
44 | + consultant: string; | |
45 | + orderNo: string; | |
46 | + orderId: number; | |
47 | + shopId: number; | |
48 | + shopName: string; | |
49 | + groupId: number; | |
50 | + lackStatus: number; | |
51 | + items: Part[]; | |
52 | +} | |
53 | + | |
54 | +export interface Part { | |
55 | + lackPartId: number; | |
56 | + itemId: number; | |
57 | + itemName: string; | |
58 | + quotePartId: number; | |
59 | + partId: number; | |
60 | + partCode: string; | |
61 | + partName: string; | |
62 | + lackNum: number; | |
63 | + processingMethod?: number; // 处理方式 1: 区域库内调件 2: 厂家采购 3:外部采购 4:区域库外调件 5:计划员处理 | |
64 | + processingMethodName?: string; // 处理方式名称 | |
65 | + // processingMethod为1时,有以下字段 | |
66 | + shopId?: number; | |
67 | + outStorageId?: number; | |
68 | + outStorageName?: string; | |
69 | + outDividedBy?: number; | |
70 | + outDivision?: number; | |
71 | + inDividedBy?: number; | |
72 | + inDivision?: number; | |
73 | + | |
74 | + // todo confirm to del | |
75 | + expectedDate?: number; // 预计需要的入库天数 | |
76 | + transferItems?: TransferItem[]; // 顾问选择调件数据 | |
77 | + // @custom | |
78 | + oldPart?: Part; | |
79 | + methods?: MethodType[]; | |
80 | + // @custom 暂存区域库存信息:用于批量处理时展示 | |
81 | + isArea?: boolean; // 是否区域库内 | |
82 | + outStock?: number; // 区域库外库存 | |
83 | +} | |
84 | + | |
85 | +export interface SavePart extends Part { | |
86 | + method?: number; | |
87 | + shopId?: number; | |
88 | + outStorageId?: number; | |
89 | + outStorageName?: string; | |
90 | + outDividedBy?: number; | |
91 | + outDivision?: number; | |
92 | + oldPartId?: number; | |
93 | + oldPartCode?: string; | |
94 | + oldPartName?: string; | |
95 | +} | |
96 | + | |
97 | +export interface MethodType { | |
98 | + method: number; | |
99 | + lackNum?: number; | |
100 | + expectedDate?: number; | |
101 | + partId?: number; | |
102 | + partCode?: string; | |
103 | + partName?: string; | |
104 | + itemId?: number; | |
105 | + shopId?: number; | |
106 | + outStorageId?: number; | |
107 | + outStorageName?: string; | |
108 | + outDividedBy?: number; | |
109 | + outDivision?: number; | |
110 | + inDividedBy?: number; | |
111 | + inDivision?: number; | |
112 | + // @custom | |
113 | + num: number; | |
114 | +} | |
115 | + | |
116 | +export interface SaveParams { | |
117 | + dataId: number; | |
118 | + userId?: number; | |
119 | + userName?: string; | |
120 | + groupId?: number; | |
121 | + purchase?: SavePart[]; | |
122 | + transfer?: SavePart[]; | |
123 | + book?: SavePart[]; | |
124 | +} | |
125 | + | |
126 | +// 列表 | |
127 | +export function listApi(params: ListParams): Page<ListResult> { | |
128 | + return request.get(`${CAS_HOST}/app/part/lack/list/planner`, { params }); | |
129 | +} | |
130 | + | |
131 | +// 详情 | |
132 | +export function detailApi(dataId: number): P<DetailResult> { | |
133 | + return request.get(`${CAS_HOST}/app/part/lack/list/detail/planner`, { params: { dataId } }); | |
134 | +} | |
135 | + | |
136 | +// 保存 | |
137 | +export function saveApi(params: SaveParams) { | |
138 | + return request.post(`${CAS_HOST}/app/part/lack/confirm/planner`, params); | |
139 | +} | ... | ... |
src/pages/cas/workOrder/PartLackHandle/subpages/Order/index.tsx
0 → 100644
1 | +import React, { useState } from 'react'; | |
2 | +import { Button, Col, Input, Row, Table } from 'antd'; | |
3 | +import type { ColumnsType } from 'antd/lib/table'; | |
4 | +import { debounce } from 'lodash'; | |
5 | +import dayjs from 'dayjs'; | |
6 | + | |
7 | +import usePagination from '@/hooks/usePagination'; | |
8 | + | |
9 | +import { listApi, type ListResult } from './api'; | |
10 | + | |
11 | +import PartListModal from './PartListModal'; | |
12 | +import HandleModal from './HandleModal'; | |
13 | + | |
14 | +const Search = Input.Search; | |
15 | + | |
16 | +/** | |
17 | + * 计划员:工单缺件处理 | |
18 | + */ | |
19 | +export default function PartLackHandle() { | |
20 | + const [dataId, setDataId] = useState(0); | |
21 | + const [openParts, setOpenParts] = useState(false); | |
22 | + const [openHandle, setOpenHandle] = useState(false); | |
23 | + | |
24 | + const { list, loading, setParams, setLoading, paginationConfig } = usePagination(listApi, {}); | |
25 | + | |
26 | + const handleSearch = debounce((keywords: string) => { | |
27 | + setParams({ keywords }, true); | |
28 | + }, 500); | |
29 | + | |
30 | + const showPartsModal = (dataId: number) => { | |
31 | + setDataId(dataId); | |
32 | + setOpenParts(true); | |
33 | + }; | |
34 | + | |
35 | + const showHandleModal = (dataId: number) => { | |
36 | + setDataId(dataId); | |
37 | + setOpenHandle(true); | |
38 | + }; | |
39 | + | |
40 | + const columns: ColumnsType<ListResult> = [ | |
41 | + { | |
42 | + title: '工单号', | |
43 | + dataIndex: 'orderNo', | |
44 | + fixed: 'left', | |
45 | + width: 100, | |
46 | + }, | |
47 | + { | |
48 | + title: '车牌号', | |
49 | + dataIndex: 'plateNo', | |
50 | + fixed: 'left', | |
51 | + width: 70, | |
52 | + }, | |
53 | + { | |
54 | + title: '车主', | |
55 | + dataIndex: 'ownerName', | |
56 | + width: 60, | |
57 | + }, | |
58 | + { | |
59 | + title: '车辆', | |
60 | + dataIndex: 'carName', | |
61 | + width: 150, | |
62 | + }, | |
63 | + { | |
64 | + title: 'VIN', | |
65 | + dataIndex: 'vin', | |
66 | + width: 120, | |
67 | + }, | |
68 | + { | |
69 | + title: '车型代码', | |
70 | + dataIndex: 'specCode', | |
71 | + width: 140, | |
72 | + }, | |
73 | + { | |
74 | + title: '在修门店', | |
75 | + dataIndex: 'shopName', | |
76 | + width: 140, | |
77 | + }, | |
78 | + { | |
79 | + title: '服务顾问', | |
80 | + dataIndex: 'receiverName', | |
81 | + width: 60, | |
82 | + }, | |
83 | + { | |
84 | + title: '进站类型', | |
85 | + dataIndex: 'serviceCatName', | |
86 | + width: 70, | |
87 | + }, | |
88 | + { | |
89 | + title: '进站时间', | |
90 | + dataIndex: 'senderTime', | |
91 | + width: 70, | |
92 | + render: (senderTime: string) => dayjs(senderTime).format('YYYY-MM-DD HH:mm:ss'), | |
93 | + }, | |
94 | + { | |
95 | + title: '缺件清单', | |
96 | + dataIndex: 'dataId', | |
97 | + fixed: 'right', | |
98 | + width: 70, | |
99 | + align: 'center', | |
100 | + render: (dataId: number) => ( | |
101 | + <Button type="link" onClick={() => showPartsModal(dataId)}> | |
102 | + 查看 | |
103 | + </Button> | |
104 | + ), | |
105 | + }, | |
106 | + { | |
107 | + title: '操作', | |
108 | + dataIndex: 'dataId', | |
109 | + fixed: 'right', | |
110 | + width: 70, | |
111 | + align: 'center', | |
112 | + render: (dataId: number) => ( | |
113 | + <Button type="link" onClick={() => showHandleModal(dataId)}> | |
114 | + 处理 | |
115 | + </Button> | |
116 | + ), | |
117 | + }, | |
118 | + ]; | |
119 | + | |
120 | + return ( | |
121 | + <div> | |
122 | + <Row justify="space-between" style={{ marginBottom: 16 }}> | |
123 | + <Col> | |
124 | + <Search | |
125 | + style={{ width: 280 }} | |
126 | + placeholder="搜索工单号、车牌、VIN、车主" | |
127 | + allowClear | |
128 | + onChange={(e) => handleSearch(e.target.value)} | |
129 | + onSearch={handleSearch} | |
130 | + /> | |
131 | + </Col> | |
132 | + </Row> | |
133 | + | |
134 | + <Table dataSource={list} pagination={paginationConfig} rowKey="orderNo" loading={loading} columns={columns} bordered scroll={{ x: 1900 }} /> | |
135 | + | |
136 | + <PartListModal | |
137 | + open={openParts} | |
138 | + dataId={dataId} | |
139 | + onCancel={() => { | |
140 | + setDataId(0); | |
141 | + setOpenParts(false); | |
142 | + }} | |
143 | + /> | |
144 | + | |
145 | + <HandleModal | |
146 | + open={openHandle} | |
147 | + dataId={dataId} | |
148 | + onCancel={() => { | |
149 | + setDataId(0); | |
150 | + setOpenHandle(false); | |
151 | + }} | |
152 | + onConfirm={() => { | |
153 | + setLoading(true); | |
154 | + setDataId(0); | |
155 | + setOpenHandle(false); | |
156 | + }} | |
157 | + /> | |
158 | + </div> | |
159 | + ); | |
160 | +} | ... | ... |
src/pages/coupon/CouponConfig/components/FullReduce.tsx
... | ... | @@ -155,7 +155,7 @@ export default function FullReduce({ info, readonly, form, getCouponType, confNo |
155 | 155 | )} |
156 | 156 | {/* 全部默认不叠加false,立减券允许修改类型 */} |
157 | 157 | <Form.Item label="可与其他同类型优惠券叠加使用" name="superimposed" > |
158 | - <Radio.Group disabled={readonly || !!confNo || info.discountsType != 1}> | |
158 | + <Radio.Group disabled={readonly || info.discountsType != 1}> | |
159 | 159 | <Radio key={1} value={true}>可叠加</Radio> |
160 | 160 | <Radio key={0} value={false}>不可叠加</Radio> |
161 | 161 | </Radio.Group> | ... | ... |
src/pages/mkt/ActivityCreate/ExternalPromotion/components/ActivityFlow/Coupons.tsx
... | ... | @@ -223,7 +223,7 @@ export default function Coupons({ awardWay, mulLottery, value, onChange, remove, |
223 | 223 | onClick={() => { |
224 | 224 | remove && remove(name); |
225 | 225 | }} |
226 | - // disabled={readOnly} | |
226 | + // disabled={readOnly} | |
227 | 227 | /> |
228 | 228 | )} |
229 | 229 | |
... | ... | @@ -251,7 +251,7 @@ export default function Coupons({ awardWay, mulLottery, value, onChange, remove, |
251 | 251 | setVisible(true); |
252 | 252 | setNoRewad(false); |
253 | 253 | }} |
254 | - // disabled={readOnly} | |
254 | + // disabled={readOnly} | |
255 | 255 | > |
256 | 256 | 新增 |
257 | 257 | </Button> |
... | ... | @@ -275,12 +275,12 @@ export default function Coupons({ awardWay, mulLottery, value, onChange, remove, |
275 | 275 | onClick={ |
276 | 276 | changeEnable |
277 | 277 | ? () => { |
278 | - // setVisible(true); | |
279 | - setNoRewad(false); | |
280 | - SetCurrentItem(record); | |
281 | - setItemIndex(index); | |
282 | - setVisible(true); | |
283 | - } | |
278 | + // setVisible(true); | |
279 | + setNoRewad(false); | |
280 | + SetCurrentItem(record); | |
281 | + setItemIndex(index); | |
282 | + setVisible(true); | |
283 | + } | |
284 | 284 | : undefined |
285 | 285 | } |
286 | 286 | > |
... | ... | @@ -325,7 +325,7 @@ export default function Coupons({ awardWay, mulLottery, value, onChange, remove, |
325 | 325 | {itemIndex + 1}.{item.aliasName} |
326 | 326 | </span> |
327 | 327 | </Button> |
328 | - {((item.aliasName && !readOnly) || changeEnable) && ( | |
328 | + {(item.aliasName && !readOnly) && ( | |
329 | 329 | <Popconfirm |
330 | 330 | title="删除将丢失优惠券信息,确定删除?" |
331 | 331 | okText="确定" |
... | ... | @@ -432,15 +432,15 @@ export default function Coupons({ awardWay, mulLottery, value, onChange, remove, |
432 | 432 | wrapperCol={{ span: 16 }} |
433 | 433 | onFinish={_onOk} |
434 | 434 | autoComplete="off" |
435 | - // initialValues={{ | |
436 | - // awardName: (awardWay === 2 && noReward) ? "谢谢惠顾" : "", | |
437 | - // }} | |
435 | + // initialValues={{ | |
436 | + // awardName: (awardWay === 2 && noReward) ? "谢谢惠顾" : "", | |
437 | + // }} | |
438 | 438 | > |
439 | 439 | <Form.Item |
440 | 440 | label="奖项名称:" |
441 | 441 | name="awardName" |
442 | 442 | rules={[{ required: true, message: '请输入奖项名称' }]} |
443 | - // initialValue={(awardWay === 2 && noReward) ? "谢谢惠顾" : ""} | |
443 | + // initialValue={(awardWay === 2 && noReward) ? "谢谢惠顾" : ""} | |
444 | 444 | > |
445 | 445 | <Input |
446 | 446 | // disabled={(awardWay === 2 && noReward) || !!currentItem.awardName} | ... | ... |
src/pages/mkt/ActivityCreate/ExternalPromotion/components/ActivityFlow/SignIn.tsx
... | ... | @@ -10,11 +10,11 @@ import moment from "moment"; |
10 | 10 | const { RangePicker } = DatePicker; |
11 | 11 | const { Option } = Select; |
12 | 12 | |
13 | -export default function index() { | |
13 | +export default function Index() { | |
14 | 14 | const { baseInfo, readOnly, getFlowConfig, externalInfo } = useStore(); |
15 | 15 | const { activityNo, changeEnable } = baseInfo; |
16 | 16 | const { flowDisable } = externalInfo; |
17 | - const { data, errMsg, loading, params, setParams } = useInitial(getSignInDetail, {}, {activityNo, change: changeEnable}); | |
17 | + const { data, errMsg, loading, params, setParams } = useInitial(getSignInDetail, {}, { activityNo, change: changeEnable }); | |
18 | 18 | const [form] = Form.useForm(); |
19 | 19 | const [saveLoading, setSaveLoading] = useState<boolean>(false); |
20 | 20 | ... | ... |
src/pages/mkt/ActivityCreate/ExternalPromotion/components/ActivityFlow/SignUp.tsx
1 | 1 | import React, { useState, useEffect } from 'react'; |
2 | -import { Button, Form, InputNumber, message, Space, Spin, Divider, Radio, Row, Alert } from 'antd'; | |
2 | +import { Button, Form, InputNumber, message, Space, Spin, Divider, Radio, Row } from 'antd'; | |
3 | 3 | import useInitial from '@/hooks/useInitail'; |
4 | 4 | import { PlusOutlined, MinusCircleOutlined } from '@ant-design/icons'; |
5 | 5 | import { saveSignUpApi, getSignUpDetail, saveChangeSignUpApi } from '../../api'; //保存报名有礼 |
... | ... | @@ -163,25 +163,6 @@ export default function Index() { |
163 | 163 | <Radio value={1}>按报名顺序不同赠送不同优惠券</Radio> |
164 | 164 | </Radio.Group> |
165 | 165 | </Form.Item> |
166 | - {changeEnable ? ( | |
167 | - <Alert | |
168 | - message="提示" | |
169 | - type="warning" | |
170 | - showIcon | |
171 | - closable | |
172 | - style={{ marginBottom: 10 }} | |
173 | - description={ | |
174 | - <div> | |
175 | - <p style={{ margin: 0, fontSize: 12, color: '#999' }}> | |
176 | - 1.优惠券编辑变更:范围只能扩大不能缩小,变更前所发优惠券与变更后所发优惠券的限制范围一致 | |
177 | - </p> | |
178 | - <p style={{ margin: 0, fontSize: 12, color: '#999' }}> | |
179 | - 2.优惠券删除-新增变更:不限制优惠券变更范围,变更前所发优惠券使用范围不变,变更后所发优惠券限制范围变更 | |
180 | - </p> | |
181 | - </div> | |
182 | - } | |
183 | - /> | |
184 | - ) : null} | |
185 | 166 | <Form.Item noStyle shouldUpdate={(prevValues, currentValues) => prevValues.ladderReward !== currentValues.ladderReward}> |
186 | 167 | {({ getFieldValue }) => { |
187 | 168 | return ( | ... | ... |
src/pages/mkt/ActivityCreate/ExternalPromotion/components/ActivityFlow/SignupGifts.tsx
... | ... | @@ -167,16 +167,18 @@ function SignupGifts({ value, onChange, disabled }: Props) { |
167 | 167 | > |
168 | 168 | 编辑 |
169 | 169 | </Button> |
170 | - <Popconfirm | |
171 | - title="删除将丢失优惠券信息,确定删除?" | |
172 | - okText="确定" | |
173 | - cancelText="取消" | |
174 | - onConfirm={() => deleteQestion(index)} | |
175 | - > | |
176 | - <Button type="link" danger> | |
177 | - 删除 | |
178 | - </Button> | |
179 | - </Popconfirm> | |
170 | + {!changeEnable && ( | |
171 | + <Popconfirm | |
172 | + title="删除将丢失优惠券信息,确定删除?" | |
173 | + okText="确定" | |
174 | + cancelText="取消" | |
175 | + onConfirm={() => deleteQestion(index)} | |
176 | + > | |
177 | + <Button type="link" danger> | |
178 | + 删除 | |
179 | + </Button> | |
180 | + </Popconfirm> | |
181 | + )} | |
180 | 182 | </Space> |
181 | 183 | ) |
182 | 184 | )} | ... | ... |
src/pages/order3/SeriesMapping/api.ts
0 → 100644
1 | +/* | |
2 | + * @Author: jiangwei jiangwei.feewee.cn | |
3 | + * @Date: 2024-03-27 17:40:09 | |
4 | + * @LastEditors: jiangwei jiangwei.feewee.cn | |
5 | + * @LastEditTime: 2024-04-18 17:52:00 | |
6 | + * @FilePath: /fw-cms/src/pages/order3/SeriesMapping/api.ts | |
7 | + * @Description: | |
8 | + * | |
9 | + * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved. | |
10 | + */ | |
11 | +import type { http } from '@/typing/http'; | |
12 | +import request from '@/utils/request'; | |
13 | +import { SDS_HOST } from '@/utils/host'; | |
14 | + | |
15 | +export interface series { | |
16 | + seriesId?: number | |
17 | + seriesName?: string | |
18 | + brandId?: number | |
19 | + brandName?: string | |
20 | +} | |
21 | +export interface saveparams { | |
22 | + importBrandName?: string | |
23 | + importSeriesName?: string | |
24 | + series?: series[] | |
25 | +} | |
26 | +/** 列表 */ | |
27 | +export function getList(params: any): http.PromisePageResp<saveparams> { | |
28 | + return request.get(`${SDS_HOST}/erp/series/mapping/get/mapping/list`, { params }); | |
29 | +} | |
30 | +/** 保存 */ | |
31 | +export function saveapi(params: saveparams) { | |
32 | + return request.post(`${SDS_HOST}/erp/series/mapping/save/mapping`, { ...params }); | |
33 | +} | |
34 | +/** 删除 */ | |
35 | +export function delapi(params: saveparams) { | |
36 | + return request.post(`${SDS_HOST}/erp/series/mapping/del/mapping`, { ...params }); | |
37 | +} | |
38 | + | |
39 | +export interface typedata { | |
40 | + value: string; | |
41 | + label: string; | |
42 | + children?: typedata[]; | |
43 | +} | |
44 | +// 车系 | |
45 | +export function getSeries(params: { brands?: string[]; vehicleCategory?: string[]; subdivideCategories?: string[] }): http.PromiseResp<typedata[]> { | |
46 | + return request.post(`${SDS_HOST}/erp/car/data/get/series/by/type`, params); | |
47 | +} | |
48 | +/** | |
49 | + * 类型10区域,20使用省份,30使用城市,40车型类别,50细分大类,60使用性质,70燃料种类,80国别大类,90国别,100排量,110动力类型,120所有权,130驱动形式150车系140品牌 | |
50 | +*/ | |
51 | +export function getTypedata(params: { type: number; queryAll?: boolean; parentTypes?: string[] }): http.PromiseResp<typedata[]> { | |
52 | + return request.post(`${SDS_HOST}/erp/type/settings/get/types`, params); | |
53 | +} | |
0 | 54 | \ No newline at end of file | ... | ... |
src/pages/order3/SeriesMapping/components/ChooseSeriesModal.tsx
0 → 100644
1 | +/* | |
2 | + * @Author: jiangwei jiangwei.feewee.cn | |
3 | + * @Date: 2024-04-18 17:12:08 | |
4 | + * @LastEditors: jiangwei jiangwei.feewee.cn | |
5 | + * @LastEditTime: 2024-04-18 18:25:13 | |
6 | + * @FilePath: /fw-cms/src/pages/order3/SeriesMapping/components/ChooseSeriesModal.tsx | |
7 | + * @Description: | |
8 | + * | |
9 | + * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved. | |
10 | + */ | |
11 | +import React, { useState, useEffect } from 'react'; | |
12 | +import { Table, Modal, Button, Input, Select } from 'antd'; | |
13 | +import usePagination from '@/hooks/usePagination'; | |
14 | +import useInitial from '@/hooks/useInitail'; | |
15 | +import { seriesListApi, getAllBrandApi } from '@/pages/oop/Series/api' | |
16 | + | |
17 | +interface Props { | |
18 | + visible: boolean, | |
19 | + onCancel: () => any, | |
20 | + onOk: (v: Series.seriesListItem[]) => any, | |
21 | +} | |
22 | +const Column = Table.Column; | |
23 | +export default function SeriesList(props: Props) { | |
24 | + const { visible, onCancel, onOk } = props | |
25 | + const { list, paginationConfig, loading, setParams } = usePagination(seriesListApi, { status: 1 }); | |
26 | + const { data: brands } = useInitial(getAllBrandApi, [], {}); | |
27 | + const [selectedSeries, setSelectedSeries] = useState<Series.seriesListItem[]>([]); | |
28 | + | |
29 | + useEffect(() => { | |
30 | + if (!visible) { | |
31 | + setSelectedSeries([]) | |
32 | + } | |
33 | + }, [visible]) | |
34 | + | |
35 | + const _onOk = () => { | |
36 | + onOk(selectedSeries); | |
37 | + onCancel(); | |
38 | + } | |
39 | + return ( | |
40 | + <Modal | |
41 | + title="选择映射车系" | |
42 | + maskClosable={false} | |
43 | + open={visible} | |
44 | + onCancel={onCancel} | |
45 | + width={800} | |
46 | + footer={[ | |
47 | + <Button onClick={onCancel} key={1} >取消</Button>, | |
48 | + <Button onClick={_onOk} key={2} type='primary' disabled={!selectedSeries.length}>确认</Button> | |
49 | + ]} | |
50 | + > | |
51 | + <div style={{ display: 'flex', justifyContent: "start" }}> | |
52 | + <Input | |
53 | + allowClear | |
54 | + style={{ width: 200, marginRight: 10, marginBottom: 10 }} | |
55 | + onChange={e => setParams({ name: e.target.value }, true)} | |
56 | + placeholder="车系名称" | |
57 | + /> | |
58 | + <Select | |
59 | + showSearch | |
60 | + optionFilterProp="children" | |
61 | + placeholder="选择品牌" | |
62 | + allowClear | |
63 | + onChange={val => { setParams({ brandId: val }, true) }} | |
64 | + style={{ width: 200, marginRight: 10, marginBottom: 10 }} | |
65 | + > | |
66 | + {brands.map((item: Series.BrandItem) => <Select.Option key={item.id} value={item.id!}>{item.name}</Select.Option>)} | |
67 | + </Select> | |
68 | + </div> | |
69 | + <Table | |
70 | + dataSource={list} | |
71 | + pagination={paginationConfig} | |
72 | + rowKey={record => Number(record.id)} | |
73 | + loading={loading} | |
74 | + size="small" | |
75 | + rowSelection={{ | |
76 | + type: "checkbox", | |
77 | + selectedRowKeys: selectedSeries.map(i => i.id), | |
78 | + onSelect: (row, _selected) => { | |
79 | + const index = selectedSeries.findIndex(_row => _row.id == row.id); | |
80 | + const newData = [...selectedSeries]; | |
81 | + if (_selected) { | |
82 | + newData.unshift(row); | |
83 | + } else if (index > -1) { | |
84 | + newData.splice(index, 1); | |
85 | + } | |
86 | + setSelectedSeries([...newData]); | |
87 | + }, | |
88 | + onSelectAll: (selected, selectedRows, changeRows) => { | |
89 | + const changedKeys = changeRows.map(row => row.id); | |
90 | + if (selected) { | |
91 | + // 全选 | |
92 | + const _arr = [...selectedSeries, ...changeRows] | |
93 | + setSelectedSeries(_arr); | |
94 | + } else { | |
95 | + // 取消全选 过滤当前页选中数据 | |
96 | + setSelectedSeries(selectedSeries.filter(row => !changedKeys.includes(row.id))) | |
97 | + } | |
98 | + }, | |
99 | + }} | |
100 | + > | |
101 | + <Column title="车系名称" dataIndex="name" /> | |
102 | + <Column title="品牌名称" dataIndex="brandName" /> | |
103 | + <Column title="厂商" dataIndex="factoryName" /> | |
104 | + </Table> | |
105 | + </Modal> | |
106 | + ); | |
107 | +} | ... | ... |
src/pages/order3/SeriesMapping/components/CreateModal.tsx
0 → 100644
1 | +import React, { useState, useEffect } from 'react'; | |
2 | +import { Button, Modal, message, Select,Table } from 'antd'; | |
3 | +import useInitial from '@/hooks/useInitail'; | |
4 | +import type { saveparams } from '../api'; | |
5 | +import { getTypedata, saveapi } from '../api'; | |
6 | +import ChooseSeriesModal from './ChooseSeriesModal'; | |
7 | + | |
8 | +const Column = Table.Column; | |
9 | +const Option = Select.Option; | |
10 | +interface Props { | |
11 | + onCancel: () => any; | |
12 | + visible: boolean; | |
13 | + onRefshing: () => any | |
14 | +} | |
15 | + | |
16 | +export default function UploadModal(props: Props) { | |
17 | + const { onCancel, visible, onRefshing } = props; | |
18 | + const { data: brands } = useInitial(getTypedata, [], {type: 140}); | |
19 | + const [param, setParam] = useState<saveparams>({}) | |
20 | + const [delay, setDelay] = useState(true); | |
21 | + const { data: series, setParams } = useInitial(getTypedata, [], { type: 150 }, delay); | |
22 | + const [loading, setLoading] = useState(false); | |
23 | + const [servisible, setServisible] = useState(false); | |
24 | + | |
25 | + useEffect(() => { | |
26 | + if (!visible) { | |
27 | + setParam({}); | |
28 | + } | |
29 | + }, [visible]); | |
30 | + | |
31 | + const onOk = () => { | |
32 | + if (!param.importBrandName) { | |
33 | + message.error('请选择导入品牌'); | |
34 | + return; | |
35 | + } | |
36 | + if (!param.importSeriesName) { | |
37 | + message.error('请选择导入车系'); | |
38 | + return; | |
39 | + } | |
40 | + if (!param.series?.length) { | |
41 | + message.error('请选择映射车系列表'); | |
42 | + return; | |
43 | + } | |
44 | + setLoading(true); | |
45 | + saveapi(param).then(() => { | |
46 | + setLoading(false); | |
47 | + onRefshing(); | |
48 | + onCancel(); | |
49 | + message.success('操作成功'); | |
50 | + }).catch(e => { | |
51 | + setLoading(false); | |
52 | + message.error(e.message); | |
53 | + }) | |
54 | + } | |
55 | + | |
56 | + return ( | |
57 | + <Modal | |
58 | + title={'新增车系映射'} | |
59 | + open={visible} | |
60 | + width={1000} | |
61 | + keyboard={false} | |
62 | + maskClosable={false} | |
63 | + onCancel={() => onCancel()} | |
64 | + footer={[ | |
65 | + <Button key="close" type="default" onClick={() => onCancel()} loading={loading}> | |
66 | + 关闭 | |
67 | + </Button>, | |
68 | + <Button key="ok" type="primary" onClick={() => onOk()} loading={loading}> | |
69 | + 确认 | |
70 | + </Button>, | |
71 | + ]} | |
72 | + > | |
73 | + <div style={{ display: 'flex', alignItems: 'center', marginBottom: 20 }}> | |
74 | + <div style={{ width: 100, textAlign: 'end' }}>导入品牌:</div> | |
75 | + <Select | |
76 | + value={param.importBrandName} | |
77 | + style={{ flex: 1 }} | |
78 | + placeholder="请选择导入品牌" | |
79 | + onChange={v => { | |
80 | + setParam({ ...param, importBrandName:v }); | |
81 | + setDelay(false); | |
82 | + setParams({ parentTypes: [v], type: 150 }, true) | |
83 | + }} | |
84 | + showSearch | |
85 | + optionFilterProp="children" | |
86 | + > | |
87 | + {brands?.map((it) => ( | |
88 | + <Option key={it.value} value={it.value}> | |
89 | + {it.value} | |
90 | + </Option> | |
91 | + ))} | |
92 | + </Select> | |
93 | + </div> | |
94 | + <div style={{ display: 'flex', alignItems: 'center' }}> | |
95 | + <div style={{ width: 100, textAlign: 'end' }}>导入车系:</div> | |
96 | + <Select | |
97 | + value={param.importSeriesName} | |
98 | + style={{ flex: 1 }} | |
99 | + placeholder="请选择导入车系" | |
100 | + onChange={v => { | |
101 | + setParam({ ...param, importSeriesName: v }); | |
102 | + }} | |
103 | + showSearch | |
104 | + optionFilterProp="children" | |
105 | + > | |
106 | + {series.map((it) => ( | |
107 | + <Option key={it.value} value={it.value}> | |
108 | + {it.value} | |
109 | + </Option> | |
110 | + ))} | |
111 | + </Select> | |
112 | + </div> | |
113 | + <div style={{ display: 'flex', marginTop: 20, marginBottom: 20, alignItems: 'start', width: '100%' }}> | |
114 | + <div style={{ width: 100, textAlign: 'end' }}>映射车系列表:</div> | |
115 | + <div style={{flex: 1}}> | |
116 | + <div style={{display: 'flex', justifyContent: 'end'}}> | |
117 | + <Button onClick={() => setServisible(true)} type='primary' style={{ marginBottom: 10 }}>添加映射车系</Button> | |
118 | + </div> | |
119 | + <Table dataSource={param.series} style={{flex: 1}} scroll={{y: 400}} pagination={false}> | |
120 | + <Column title="品牌名称" dataIndex="brandName" /> | |
121 | + <Column title="车系名称" dataIndex="seriesName" /> | |
122 | + </Table> | |
123 | + </div> | |
124 | + </div> | |
125 | + <ChooseSeriesModal | |
126 | + visible={servisible} | |
127 | + onCancel={() => setServisible(false)} | |
128 | + onOk={s => { | |
129 | + const _s = s.map(i => ({ ...i, seriesName: i.name, seriesId: i.id })) | |
130 | + setParam({ ...param, series: _s }) | |
131 | + }} | |
132 | + /> | |
133 | + </Modal> | |
134 | + ); | |
135 | +} | ... | ... |
src/pages/order3/SeriesMapping/components/MappingSeriesModal.tsx
0 → 100644
1 | +/* | |
2 | + * @Author: jiangwei jiangwei.feewee.cn | |
3 | + * @Date: 2024-04-18 16:46:23 | |
4 | + * @LastEditors: jiangwei jiangwei.feewee.cn | |
5 | + * @LastEditTime: 2024-04-19 09:16:21 | |
6 | + * @FilePath: /fw-cms/src/pages/order3/SeriesMapping/components/MappingSeriesModal.tsx | |
7 | + * @Description: | |
8 | + * | |
9 | + * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved. | |
10 | + */ | |
11 | +import React from 'react'; | |
12 | +import { Button, Modal, Table } from 'antd'; | |
13 | +import type { series } from '../api'; | |
14 | + | |
15 | +const Column = Table.Column; | |
16 | +interface Props { | |
17 | + onCancel: () => any; | |
18 | + visible: boolean; | |
19 | + data: series[] | |
20 | +} | |
21 | + | |
22 | +export default function UploadModal(props: Props) { | |
23 | + const { onCancel, visible, data } = props; | |
24 | + | |
25 | + return ( | |
26 | + <Modal | |
27 | + title={'车系映射列表'} | |
28 | + open={visible} | |
29 | + width={800} | |
30 | + keyboard={false} | |
31 | + maskClosable={false} | |
32 | + onCancel={() => onCancel()} | |
33 | + okButtonProps={{ hidden: true }} | |
34 | + footer={[ | |
35 | + <Button key="close" type="default" onClick={() => onCancel()}> | |
36 | + 关闭 | |
37 | + </Button> | |
38 | + ]} | |
39 | + > | |
40 | + <Table dataSource={data} pagination={false}> | |
41 | + <Column title="品牌名称" dataIndex="brandName" /> | |
42 | + <Column title="车系名称" dataIndex="seriesName" /> | |
43 | + </Table> | |
44 | + </Modal> | |
45 | + ); | |
46 | +} | ... | ... |
src/pages/order3/SeriesMapping/index.tsx
0 → 100644
1 | +/* | |
2 | + * @Author: jiangwei jiangwei.feewee.cn | |
3 | + * @Date: 2024-04-18 16:00:41 | |
4 | + * @LastEditors: jiangwei jiangwei.feewee.cn | |
5 | + * @LastEditTime: 2024-04-19 09:19:51 | |
6 | + * @FilePath: /fw-cms/src/pages/order3/SeriesMapping/index.tsx | |
7 | + * @Description: | |
8 | + * | |
9 | + * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved. | |
10 | + */ | |
11 | +import React, { useState } from 'react' | |
12 | +import { PageHeaderWrapper } from '@ant-design/pro-layout' | |
13 | +import { Button, Card, Table, Select, Popconfirm, message } from 'antd' | |
14 | +import CreateModal from './components/CreateModal'; | |
15 | +import MappingSeriesModal from './components/MappingSeriesModal'; | |
16 | +import usePagination from '@/hooks/usePagination'; | |
17 | +import useInitial from '@/hooks/useInitail'; | |
18 | +import type { saveparams, series } from './api'; | |
19 | +import { getList, getTypedata, delapi } from './api'; | |
20 | + | |
21 | +const { Column } = Table | |
22 | + | |
23 | +export default function Index() { | |
24 | + const [visible, setVisible] = useState < boolean > (false) | |
25 | + const { list, loading, setParams, paginationConfig } = usePagination(getList, {}) | |
26 | + const { data: brands } = useInitial(getTypedata, [], {type: 140}); | |
27 | + const [delay, setDelay] = useState(true); | |
28 | + const { data: series, setParams: seriesQuery, setData } = useInitial(getTypedata, [], { type: 150 }, delay); | |
29 | + const [mappseries, setMappingseries] = useState < { visible: boolean, data: series[] }>({visible: false, data: []}) | |
30 | + | |
31 | + const _del = (p: saveparams) => { | |
32 | + delapi(p).then(() => { | |
33 | + message.success('操作成功'); | |
34 | + setParams({}, true) | |
35 | + }).catch(e => message.error(e.message)) | |
36 | + } | |
37 | + return ( | |
38 | + <PageHeaderWrapper> | |
39 | + <Card> | |
40 | + <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 20 }}> | |
41 | + <div> | |
42 | + <Select | |
43 | + style={{ width: 200, marginRight: 20 }} | |
44 | + placeholder="导入品牌筛选" | |
45 | + onChange={v => { | |
46 | + setParams({ importBrandName: v }, true); | |
47 | + if (v) { | |
48 | + setDelay(false); | |
49 | + seriesQuery({ parentTypes: [v], type: 150 }, true) | |
50 | + } else { | |
51 | + setData([]); | |
52 | + } | |
53 | + }} | |
54 | + showSearch | |
55 | + allowClear | |
56 | + optionFilterProp="children" | |
57 | + > | |
58 | + {brands.map((it) => ( | |
59 | + <Select.Option key={it.value} value={it.value}> | |
60 | + {it.label} | |
61 | + </Select.Option> | |
62 | + ))} | |
63 | + </Select> | |
64 | + {!!series.length && | |
65 | + <Select | |
66 | + style={{ width: 200, marginRight: 20 }} | |
67 | + placeholder="导入车系筛选" | |
68 | + onChange={v => { | |
69 | + setParams({ importSeriesName: v }, true); | |
70 | + }} | |
71 | + showSearch | |
72 | + allowClear | |
73 | + optionFilterProp="children" | |
74 | + > | |
75 | + {series.map((it) => ( | |
76 | + <Select.Option key={it.value} value={it.value}> | |
77 | + {it.label} | |
78 | + </Select.Option> | |
79 | + ))} | |
80 | + </Select> | |
81 | + } | |
82 | + </div> | |
83 | + <div> | |
84 | + <Button type='primary' onClick={() => setVisible(true)}>新增</Button> | |
85 | + </div> | |
86 | + </div> | |
87 | + <Table | |
88 | + dataSource={list} | |
89 | + loading={loading} | |
90 | + pagination={paginationConfig} | |
91 | + rowKey={r => `${r.importBrandName}_${r.importSeriesName}`} | |
92 | + > | |
93 | + <Column title="导入品牌" dataIndex="importBrandName" /> | |
94 | + <Column title="导入车系" dataIndex="importSeriesName" /> | |
95 | + <Column title="映射车系列表" render={r => <a onClick={() => setMappingseries({visible: true, data: r.series})}>查看</a> } /> | |
96 | + <Column | |
97 | + title="操作" | |
98 | + render={r => ( | |
99 | + <Popconfirm title="确认删除?" onConfirm={() => _del(r)}> | |
100 | + <a style={{ color: 'red' }}>删除</a> | |
101 | + </Popconfirm> | |
102 | + )} | |
103 | + /> | |
104 | + </Table> | |
105 | + </Card> | |
106 | + <CreateModal visible={visible} onCancel={() => setVisible(false)} onRefshing={setParams} /> | |
107 | + <MappingSeriesModal visible={mappseries.visible} onCancel={() => setMappingseries({visible: false, data: []})} data={mappseries.data} /> | |
108 | + </PageHeaderWrapper> | |
109 | + ) | |
110 | +} | |
0 | 111 | \ No newline at end of file | ... | ... |
src/pages/order3/WeeklydataUpload/api.ts
0 → 100644
1 | +/* | |
2 | + * @Author: jiangwei jiangwei.feewee.cn | |
3 | + * @Date: 2024-03-27 17:40:09 | |
4 | + * @LastEditors: jiangwei jiangwei.feewee.cn | |
5 | + * @LastEditTime: 2024-04-12 18:30:51 | |
6 | + * @FilePath: /fw-cms/src/pages/order3/WeeklydataUpload/api.ts | |
7 | + * @Description: | |
8 | + * | |
9 | + * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved. | |
10 | + */ | |
11 | +import type { http } from '@/typing/http'; | |
12 | +import request from '@/utils/request'; | |
13 | +import { SDS_HOST } from '@/utils/host'; | |
14 | + | |
15 | +export interface List { | |
16 | + year?: number | |
17 | + week?: number | |
18 | + sourceFid?: string | |
19 | + successCnt?: number | |
20 | + failCnt?: number | |
21 | + failFid?: string | |
22 | + importUserName?: string | |
23 | + creatTime?: string | |
24 | + status?: number // 1处理中2已完成 | |
25 | +} | |
26 | +interface week { | |
27 | + id?: number, | |
28 | + createTime?: number, | |
29 | + updateTime?: number, | |
30 | + createBy?: number, | |
31 | + updateBy?: number, | |
32 | + year?: number, | |
33 | + week?: number, | |
34 | + yearWeek?: number, | |
35 | + startTime?: number, | |
36 | + endTime?: number | |
37 | +} | |
38 | + | |
39 | +interface weekdata { | |
40 | + currentWeek?: week | |
41 | + weekTimes?: week[] | |
42 | +} | |
43 | +interface saveparams { | |
44 | + year?: number | |
45 | + week?: number | |
46 | + sourceFid?: string | |
47 | +} | |
48 | +/** 列表 */ | |
49 | +export function getList(params: any): http.PromisePageResp<List> { | |
50 | + return request.get(`${SDS_HOST}/erp/car/sale/get/import/record/list`, { params }); | |
51 | +} | |
52 | +/** 上传 */ | |
53 | +export function upLoad(params: saveparams) { | |
54 | + return request.post(`${SDS_HOST}/erp/car/sale/import/data`, { ...params }); | |
55 | +} | |
56 | +// 年份数据列表 | |
57 | +export function getyeardata(): http.PromiseResp<number[]> { | |
58 | + return request.get(`${SDS_HOST}/erp/year/week/time/get/years`); | |
59 | +} | |
60 | +// 年份周度数据列表 | |
61 | +export function getweekdata(params: { year: number }): http.PromiseResp<weekdata> { | |
62 | + return request.get(`${SDS_HOST}/erp/year/week/time/get/year/weeks`, { params }); | |
63 | +} | |
0 | 64 | \ No newline at end of file | ... | ... |
src/pages/order3/WeeklydataUpload/components/UploadModal.tsx
0 → 100644
1 | +/* | |
2 | + * @Author: jiangwei jiangwei.feewee.cn | |
3 | + * @Date: 2024-04-16 17:51:11 | |
4 | + * @LastEditors: jiangwei jiangwei.feewee.cn | |
5 | + * @LastEditTime: 2024-04-16 19:29:30 | |
6 | + * @FilePath: /fw-cms/src/pages/order3/WeeklydataUpload/components/UploadModal.tsx | |
7 | + * @Description: | |
8 | + * | |
9 | + * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved. | |
10 | + */ | |
11 | +import React, { useState, useEffect } from 'react'; | |
12 | +import { UploadOutlined } from '@ant-design/icons'; | |
13 | +import FeeweeUploadAttachment from '@/components/FeeweeUploadAttachment'; | |
14 | +import { Button, Modal, message, Select } from 'antd'; | |
15 | +import useInitial from '@/hooks/useInitail'; | |
16 | +import moment from 'moment'; | |
17 | +import { getweekdata, getyeardata, upLoad } from '../api' | |
18 | + | |
19 | +const Option = Select.Option; | |
20 | +interface Props { | |
21 | + onCancel: () => any; | |
22 | + visible: boolean; | |
23 | + onRefshing: Function | |
24 | +} | |
25 | + | |
26 | +export default function UploadModal(props: Props) { | |
27 | + const { onCancel, visible, onRefshing } = props; | |
28 | + const { data: years } = useInitial(getyeardata, [], {}); | |
29 | + const { data: weeks, setParams } = useInitial(getweekdata, {}, { year: Number(moment().format('YYYY')) }); | |
30 | + const [year, setYear] = useState < number > (Number(moment().format('YYYY'))); | |
31 | + const [week, setWeek] = useState < number| undefined >(); | |
32 | + const [fids, setFids] = useState < any[] > ([]); | |
33 | + const [loading, setLoading] = useState(false); | |
34 | + | |
35 | + useEffect(() => { | |
36 | + if (!visible) { | |
37 | + setYear(Number(moment().format('YYYY'))); | |
38 | + setFids([]); | |
39 | + } | |
40 | + }, [visible]); | |
41 | + | |
42 | + useEffect(() => { | |
43 | + if (weeks.currentWeek?.week) { | |
44 | + setWeek(weeks.currentWeek?.week) | |
45 | + } | |
46 | + }, [weeks.currentWeek?.week]) | |
47 | + | |
48 | + const onOk = () => { | |
49 | + if (!fids) { | |
50 | + message.error('请先上传文件'); | |
51 | + return; | |
52 | + } | |
53 | + setLoading(true); | |
54 | + upLoad({ year, week, sourceFid: fids[0] }).then(() => { | |
55 | + setLoading(false); | |
56 | + onRefshing(); | |
57 | + onCancel(); | |
58 | + message.success('操作成功'); | |
59 | + }).catch(e => { | |
60 | + setLoading(false); | |
61 | + message.error(e.message); | |
62 | + }) | |
63 | + } | |
64 | + | |
65 | + return ( | |
66 | + <Modal | |
67 | + title={'市占率数据导入'} | |
68 | + open={visible} | |
69 | + width={800} | |
70 | + keyboard={false} | |
71 | + maskClosable={false} | |
72 | + onCancel={() => onCancel()} | |
73 | + footer={[ | |
74 | + <Button key="close" type="default" onClick={() => onCancel()} loading={loading}> | |
75 | + 关闭 | |
76 | + </Button>, | |
77 | + <Button key="ok" type="primary" onClick={() => onOk()} loading={loading}> | |
78 | + 确认导入 | |
79 | + </Button>, | |
80 | + ]} | |
81 | + > | |
82 | + <div style={{ display: 'flex', alignItems: 'center', marginBottom: 10 }}> | |
83 | + <span>导入年份:</span> | |
84 | + <Select | |
85 | + value={year} | |
86 | + style={{ width: 510 }} | |
87 | + placeholder="请选择导入年份" | |
88 | + onChange={v => { | |
89 | + setYear(v); | |
90 | + setParams({ year: v }, true) | |
91 | + }} | |
92 | + showSearch | |
93 | + optionFilterProp="children" | |
94 | + > | |
95 | + {years?.map((it) => ( | |
96 | + <Option key={it} value={it}> | |
97 | + {`${it}年`} | |
98 | + </Option> | |
99 | + ))} | |
100 | + </Select> | |
101 | + </div> | |
102 | + <div style={{ display: 'flex', alignItems: 'center' }}> | |
103 | + <span>导入周度:</span> | |
104 | + <Select | |
105 | + value={week} | |
106 | + style={{ width: 510 }} | |
107 | + placeholder="请选择导入周度" | |
108 | + onChange={setWeek} | |
109 | + showSearch | |
110 | + optionFilterProp="children" | |
111 | + > | |
112 | + {weeks.weekTimes?.map((it) => ( | |
113 | + <Option key={it.id} value={it.week}> | |
114 | + {`第${it.week}周(${moment(it.startTime).format('MM.DD')}-${moment(it.endTime).format('MM.DD')})`} | |
115 | + </Option> | |
116 | + ))} | |
117 | + </Select> | |
118 | + </div> | |
119 | + <div style={{ display: 'flex', alignItems: 'center', marginTop: 10, marginBottom: 20 }}> | |
120 | + <span>导入数据:</span> | |
121 | + <FeeweeUploadAttachment | |
122 | + fidList={fids} | |
123 | + onChange={(fil) => setFids(fil)} | |
124 | + > | |
125 | + {!fids.length && <Button icon={<UploadOutlined rev={undefined} />}>点击上传文件</Button>} | |
126 | + </FeeweeUploadAttachment> | |
127 | + </div> | |
128 | + <a href="https://gate.feewee.cn/file/show?fid=537083857248325" target="_blank" rel="noreferrer">下载导入模版</a> | |
129 | + </Modal> | |
130 | + ); | |
131 | +} | ... | ... |
src/pages/order3/WeeklydataUpload/index.tsx
0 → 100644
1 | +import React, { useState } from 'react' | |
2 | +import { PageHeaderWrapper } from '@ant-design/pro-layout' | |
3 | +import { Button, Card, Table, Tag, Divider, Select } from 'antd' | |
4 | +import UploadModal from './components/UploadModal'; | |
5 | +import usePagination from '@/hooks/usePagination'; | |
6 | +import useInitial from '@/hooks/useInitail'; | |
7 | +import { getList, getyeardata, getweekdata } from './api'; | |
8 | +import moment from 'moment'; | |
9 | + | |
10 | +const { Column } = Table | |
11 | + | |
12 | +export default function Index() { | |
13 | + const [visible, setVisible] = useState < boolean > (false) | |
14 | + const { list, loading, setParams, paginationConfig } = usePagination(getList, {}) | |
15 | + const { data: years } = useInitial(getyeardata, [], {}); | |
16 | + const { data: weeks, setParams: weekQuery } = useInitial(getweekdata, {}, { year: Number(moment().format('YYYY')) }); | |
17 | + return ( | |
18 | + <PageHeaderWrapper> | |
19 | + <Card> | |
20 | + <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 20 }}> | |
21 | + <div> | |
22 | + <Select | |
23 | + style={{ width: 200, marginRight: 20 }} | |
24 | + placeholder="导入年份筛选" | |
25 | + onChange={v => { | |
26 | + setParams({ year: v }, true) | |
27 | + weekQuery({ year: v }, true) | |
28 | + }} | |
29 | + showSearch | |
30 | + allowClear | |
31 | + optionFilterProp="children" | |
32 | + > | |
33 | + {years?.map((it) => ( | |
34 | + <Select.Option key={it} value={it}> | |
35 | + {`${it}年`} | |
36 | + </Select.Option> | |
37 | + ))} | |
38 | + </Select> | |
39 | + <Select | |
40 | + style={{ width: 200 }} | |
41 | + placeholder="导入周度筛选" | |
42 | + onChange={v => { | |
43 | + setParams({ week: v }, true) | |
44 | + }} | |
45 | + showSearch | |
46 | + allowClear | |
47 | + optionFilterProp="children" | |
48 | + > | |
49 | + {weeks.weekTimes?.map((it) => ( | |
50 | + <Select.Option key={it.id} value={it.week}> | |
51 | + {`第${it.week}周(${moment(it.startTime).format('MM.DD')}-${moment(it.endTime).format('MM.DD')})`} | |
52 | + </Select.Option> | |
53 | + ))} | |
54 | + </Select> | |
55 | + </div> | |
56 | + <div> | |
57 | + <Button type='primary' onClick={() => setVisible(true)}>新增导入</Button> | |
58 | + </div> | |
59 | + </div> | |
60 | + <Table | |
61 | + dataSource={list} | |
62 | + loading={loading} | |
63 | + pagination={paginationConfig} | |
64 | + rowKey={r => `${r.sourceFid}`} | |
65 | + > | |
66 | + <Column title="年份/周度" render={r => `${r.year}第${r.week}周(${moment(r.startTime).format('MM.DD')}-${moment(r.endTime).format('MM.DD')})`} /> | |
67 | + <Column title="导入时间" dataIndex="createTime" render={t => moment(t).format('YYYY.MM.DD HH:mm:ss')} /> | |
68 | + <Column title="导入人员" dataIndex="importUserName" /> | |
69 | + <Column title="导入数据" render={r => <span>{(r.successCnt || 0) + (r.failCnt || 0)}条</span>} /> | |
70 | + <Column title="成功" dataIndex="successCnt" render={t => <span>{t}条</span>} /> | |
71 | + <Column title="失败" dataIndex="failCnt" render={r => ( | |
72 | + r.failCnt ? | |
73 | + <> | |
74 | + <span>{r.failCnt}条</span> | |
75 | + <Divider type="vertical" /> | |
76 | + <a href={`https://gate.feewee.cn/file/show?fid=${r.failFid}`} target="_blank" rel="noreferrer">下载</a> | |
77 | + </> | |
78 | + : '--' | |
79 | + )} /> | |
80 | + <Column title="状态" dataIndex="status" render={t => <Tag color={t == 1 ? 'orange' : 'green'}>{t == 1 ? '处理中' : '已完成'}</Tag>} /> | |
81 | + </Table> | |
82 | + </Card> | |
83 | + <UploadModal visible={visible} onCancel={() => setVisible(false)} onRefshing={setParams} /> | |
84 | + </PageHeaderWrapper> | |
85 | + ) | |
86 | +} | |
0 | 87 | \ No newline at end of file | ... | ... |
src/pages/performance/DataImport/components/ExcelTable.tsx
... | ... | @@ -5,6 +5,7 @@ import { useRequest } from 'ahooks'; |
5 | 5 | import { ErrorType } from '../entity'; |
6 | 6 | |
7 | 7 | import moment from 'moment'; |
8 | + | |
8 | 9 | interface Props { |
9 | 10 | fid?: string; |
10 | 11 | show?: boolean; |
... | ... | @@ -19,7 +20,7 @@ export default function ExcelTable({ fid, show, indicator, setExcelvisible, refr |
19 | 20 | message.error(e.message); |
20 | 21 | }, |
21 | 22 | }); |
22 | - | |
23 | + | |
23 | 24 | useEffect(() => { |
24 | 25 | if (show) { |
25 | 26 | run(fid || '', indicator?.code || ''); |
... | ... | @@ -96,6 +97,7 @@ export default function ExcelTable({ fid, show, indicator, setExcelvisible, refr |
96 | 97 | <Modal |
97 | 98 | open={show} |
98 | 99 | destroyOnClose |
100 | + okButtonProps={{ disabled: (data?.successNum || 0) <= 0 }} | |
99 | 101 | onCancel={() => { |
100 | 102 | setExcelvisible?.(false); |
101 | 103 | }} | ... | ... |
src/pages/performance/DataImport/components/ImportList.tsx
... | ... | @@ -16,6 +16,7 @@ import type { ApprovalProgressModalRef } from '@/components/ApprovalProgressModa |
16 | 16 | import dowloader from '@/utils/downloader'; |
17 | 17 | import { IMGURL } from '@/utils'; |
18 | 18 | import ExcelTable from './ExcelTable'; |
19 | +import { ErrorType } from '../entity'; | |
19 | 20 | |
20 | 21 | type Props = { |
21 | 22 | indicator?: MDataImport.IndicatorList; |
... | ... | @@ -160,7 +161,23 @@ export default function TableList({ indicator }: Props) { |
160 | 161 | dataIndex: 'graderStaffName', |
161 | 162 | render: (name) => <span>{name || '--'}</span>, |
162 | 163 | }, |
164 | + { | |
165 | + title: '是否识别', | |
166 | + width: 100, | |
167 | + dataIndex: 'errorType', | |
168 | + align: 'center', | |
169 | + render: (_: any, record: any) => (record.errorType ? <div>未识别</div> : <div>已识别</div>), | |
170 | + }, | |
171 | + { | |
172 | + title: '未识别原因', | |
173 | + width: 150, | |
174 | + dataIndex: 'errorType', | |
175 | + align: 'center', | |
176 | + render: (_: any, record: any) => (record.errorType ? ErrorType[record.errorType] : '--'), | |
177 | + }, | |
163 | 178 | ]; |
179 | + | |
180 | + | |
164 | 181 | const columns: ColumnsType<MDataImport.DetailedList> = [ |
165 | 182 | { |
166 | 183 | title: '导入时间', |
... | ... | @@ -311,6 +328,10 @@ export default function TableList({ indicator }: Props) { |
311 | 328 | onClick={() => { |
312 | 329 | DownloadApi(indicator?.code) |
313 | 330 | .then((res) => { |
331 | + if(!res){ | |
332 | + message.error('模版不存在!') | |
333 | + return | |
334 | + } | |
314 | 335 | dowloader.downloadFile({ fileUrl: IMGURL.showImage(res) }); |
315 | 336 | }) |
316 | 337 | .catch((e) => { | ... | ... |
src/pages/performance/KpiSetting/components/EditModal.tsx
... | ... | @@ -44,8 +44,9 @@ export default function EditModal({ onClose, setItem, item, roleList }: Props) { |
44 | 44 | useEffect(() => { |
45 | 45 | if (visible && currentItem) { |
46 | 46 | const result = transformFormData(currentItem, roleList, list); |
47 | + console.log(currentItem,'323') | |
47 | 48 | console.log({...result},'1111dwewwwwwew') |
48 | - form.setFieldsValue({ ...result }); | |
49 | + form.setFieldsValue({ ...result}); | |
49 | 50 | } |
50 | 51 | }, [visible]); |
51 | 52 | function handleSave(values: any) { |
... | ... | @@ -230,6 +231,18 @@ export default function EditModal({ onClose, setItem, item, roleList }: Props) { |
230 | 231 | ) : null; |
231 | 232 | }} |
232 | 233 | </Form.Item> |
234 | + <Form.Item name="businessOriginName" label="原始指标名称" rules={[{ required: true, message: '请输入原始指标名称' }]}> | |
235 | + <Input placeholder="请输入指标名称" /> | |
236 | + </Form.Item> | |
237 | + <Form.Item name="businessOriginUnit" label="原始指标单位" rules={[{ required: true }]}> | |
238 | + <Select disabled={isOriginIndicatorCode} placeholder="请选择原始指标单位"> | |
239 | + {UnitType.map((item) => ( | |
240 | + <Option value={item.value} key={item.value}> | |
241 | + {item.label} | |
242 | + </Option> | |
243 | + ))} | |
244 | + </Select> | |
245 | + </Form.Item> | |
233 | 246 | </Form> |
234 | 247 | </Modal> |
235 | 248 | ); | ... | ... |
src/pages/performance/KpiSetting/interface.d.ts
src/pages/stock/RepertoryFw/comps/QueryForm.tsx
... | ... | @@ -7,6 +7,7 @@ import { ShippingStatus, TransportedStatus, lockedStatus, CashCarTypeStatus, Occ |
7 | 7 | import type { StorageSelect, StorageParams } from '@/pages/stock/Components/api'; |
8 | 8 | import { getStorageListApi } from '@/pages/stock/Components/api'; |
9 | 9 | import useInitial from '@/hooks/useInitail'; |
10 | +import { getCompanyList } from '@/pages/stock/TicketImport/api'; | |
10 | 11 | |
11 | 12 | const { Option } = Select; |
12 | 13 | |
... | ... | @@ -30,6 +31,12 @@ export default function QueryForm({ onChange, delearData, setSearchParams, inner |
30 | 31 | setParams, |
31 | 32 | params: storageParams, |
32 | 33 | } = useInitial<StorageSelect[], StorageParams>(getStorageListApi, [], {} as StorageParams, delay); |
34 | + /**融资银行 */ | |
35 | + const { data: financeList, errMsg: financeMessage } = useInitial<TicketImport.CompanyListVO[], any>( | |
36 | + getCompanyList, | |
37 | + [], | |
38 | + { types: 50, compCategory: 1 }, | |
39 | + ); | |
33 | 40 | const [carArray, setCarArray] = useState<number[]>([]); |
34 | 41 | const [searchValue, setSearchValue] = useState<serchParams>({}); |
35 | 42 | |
... | ... | @@ -124,37 +131,34 @@ export default function QueryForm({ onChange, delearData, setSearchParams, inner |
124 | 131 | value={innerParams.financeType} |
125 | 132 | > |
126 | 133 | <Option value="1" key="1"> |
127 | - 兵财 | |
134 | + 承兑汇票 | |
128 | 135 | </Option> |
129 | 136 | <Option value="2" key="2"> |
130 | - 光大 | |
137 | + 贷款 | |
131 | 138 | </Option> |
132 | 139 | <Option value="3" key="3"> |
133 | 140 | 现金 |
134 | 141 | </Option> |
135 | 142 | <Option value="4" key="4"> |
136 | - 现金(折让) | |
143 | + 折让 | |
137 | 144 | </Option> |
138 | 145 | <Option value="5" key="5"> |
139 | - 中信 | |
146 | + 厂家直营 | |
140 | 147 | </Option> |
141 | 148 | </Select> |
142 | 149 | <Select |
143 | - placeholder="请选择车辆类型" | |
144 | - onChange={(value) => onChange({ vehicleType: value })} | |
150 | + placeholder="请选择融资银行" | |
151 | + onChange={(value) => onChange({ compId: value })} | |
145 | 152 | style={{ width: 180 }} |
153 | + notFoundContent={financeMessage} | |
146 | 154 | allowClear |
147 | - value={innerParams.vehicleType} | |
155 | + value={innerParams.compId} | |
148 | 156 | > |
149 | - <Option value="1" key="1"> | |
150 | - 承兑汇票 | |
151 | - </Option> | |
152 | - <Option value="2" key="2"> | |
153 | - 现金车 | |
154 | - </Option> | |
155 | - <Option value="3" key="3"> | |
156 | - 贷款车 | |
157 | - </Option> | |
157 | + {financeList.map((i) => ( | |
158 | + <Option value={i.id} key={i.id}> | |
159 | + {i.shortName} | |
160 | + </Option> | |
161 | + ))} | |
158 | 162 | </Select> |
159 | 163 | <Select |
160 | 164 | placeholder="特价车" | ... | ... |
src/pages/stock/RepertoryFw/entity.ts
... | ... | @@ -23,10 +23,11 @@ export enum stockEnum { |
23 | 23 | } |
24 | 24 | |
25 | 25 | export const FinanceType = { |
26 | - 1: '兵财', | |
27 | - 2: '光大', | |
26 | + 1: '承兑汇票', | |
27 | + 2: '贷款', | |
28 | 28 | 3: '现金', |
29 | - 4: '现金(折让)', | |
29 | + 4: '折让', | |
30 | + 5: '厂家直营' | |
30 | 31 | }; |
31 | 32 | |
32 | 33 | export const LockedStatus = { |
... | ... | @@ -80,7 +81,7 @@ export const CashCarTypeStatus = [ |
80 | 81 | { value: 2, label: '现金启票' }, |
81 | 82 | ]; |
82 | 83 | |
83 | -export const CashCarType: { [key: number]: string } = { | |
84 | +export const CashCarType: Record<number, string> = { | |
84 | 85 | 1: '现金买断', |
85 | 86 | 2: '现金启票', |
86 | 87 | }; |
... | ... | @@ -92,7 +93,7 @@ export const OccupyTypeStatus = [ |
92 | 93 | { value: 3, label: '定金锁车占用' }, |
93 | 94 | ]; |
94 | 95 | |
95 | -export const OccupyType: { [key: number]: string } = { | |
96 | +export const OccupyType: Record<number, string> = { | |
96 | 97 | 1: '全款锁车占用', |
97 | 98 | 2: '首付款锁车占用', |
98 | 99 | 3: '定金锁车占用', | ... | ... |
src/pages/stock/RepertoryFw/index.tsx
... | ... | @@ -66,7 +66,7 @@ export default function Repertory() { |
66 | 66 | bordered |
67 | 67 | rowKey="vin" |
68 | 68 | size="small" |
69 | - scroll={{ x: 3000, y: 900 }} | |
69 | + scroll={{ x: 3200, y: 900 }} | |
70 | 70 | dataSource={list} |
71 | 71 | className={st.table} |
72 | 72 | > |
... | ... | @@ -97,7 +97,6 @@ export default function Repertory() { |
97 | 97 | }} |
98 | 98 | /> |
99 | 99 | <Column title="库房" dataIndex="storageName" width={130} /> |
100 | - <Column title="车辆类型" dataIndex="vehicleType" render={(text) => TypeEnum[text] || ''} width="6%" /> | |
101 | 100 | <Column title="是否上传押品" dataIndex="collateralTag" render={(text) => <span>{text ? '是' : '否'}</span>} width="6%" /> |
102 | 101 | <Column title="定制车标记" dataIndex="customTag" render={(text) => <span>{text ? '是' : '否'}</span>} width="6%" /> |
103 | 102 | <Column title="定制客户" dataIndex="memberName" render={(text) => <span>{text || '--'}</span>} width="6%" /> |
... | ... | @@ -117,7 +116,10 @@ export default function Repertory() { |
117 | 116 | </div> |
118 | 117 | )} |
119 | 118 | /> |
119 | + <Column title="资金类型" dataIndex="financeType" render={(text) => FinanceType[text] || ''} width="6%" /> | |
120 | + <Column title="融资银行" dataIndex="compName" width="7%" align="center" /> | |
120 | 121 | <Column title="押品合同开始时间" dataIndex="invoiceTime" render={(text) => text && moment(text).format('YYYY-MM-DD')} width="6%" /> |
122 | + <Column title="押品合同到期日期" dataIndex="invoiceExpireTime" render={(text) => text && moment(text).format('YYYY-MM-DD')} width="6%" /> | |
121 | 123 | <Column title="导入系统时间" dataIndex="createTime" render={(text) => text && moment(text).format('YYYY-MM-DD')} width="6%" /> |
122 | 124 | <Column title="启票时间" dataIndex="ticketTime" render={(text) => (text && moment(text).format('YYYY-MM-DD')) || '--'} width="6%" /> |
123 | 125 | <Column title="启票价格" dataIndex="invoicePrice" width="5%" /> |
... | ... | @@ -222,7 +224,6 @@ export default function Repertory() { |
222 | 224 | sorter={(a: Repertory.RepertoryItem, b: Repertory.RepertoryItem) => (a.dealerRetailPrice || 0) - (b.dealerRetailPrice || 0)} |
223 | 225 | width="6%" |
224 | 226 | /> |
225 | - <Column title="融资方式" dataIndex="financeType" render={(text) => FinanceType[text] || ''} width="6%" /> | |
226 | 227 | <Column |
227 | 228 | width="8%" |
228 | 229 | title="操作" | ... | ... |
src/pages/stock/RepertoryFw/interface.d.ts
... | ... | @@ -7,6 +7,7 @@ declare namespace Repertory { |
7 | 7 | vehicleType?: number; //车辆类型 1融资车2现金车 |
8 | 8 | financeType?: number; //资金类型 1兵财2光大3现金4现金(折让) |
9 | 9 | invoiceTime?: number; //开票日期 |
10 | + compId?: number; // 融资银行 | |
10 | 11 | brandId?: number; //品牌id |
11 | 12 | seriesId?: number; //车系id |
12 | 13 | specId?: number; //车型id | ... | ... |
src/pages/stock/TicketImport/components/ComfirmOrder.tsx
... | ... | @@ -132,7 +132,6 @@ export default function ComfirmModal() { |
132 | 132 | dataSource={data} |
133 | 133 | > |
134 | 134 | <Column title="订单类型" dataIndex="orderType" render={(text) => <span>{orderType[text]}</span>} /> |
135 | - <Column title="车辆类型" dataIndex="vehicleType" render={(text) => <span>{vehicleType[text]}</span>} /> | |
136 | 135 | <Column |
137 | 136 | title="资金类型" |
138 | 137 | dataIndex="financeType" | ... | ... |
src/pages/stock/TicketImport/components/TicketDetail.tsx
... | ... | @@ -30,8 +30,8 @@ export default function TicketDetail() { |
30 | 30 | <Column title="VIN" dataIndex="vin" align="center" /> |
31 | 31 | <Column title="发动机号" dataIndex="engineNo" /> |
32 | 32 | <Column title="订单类型" dataIndex="orderType" align="center" render={(text) => <span>{orderType[text]}</span>} /> |
33 | - <Column title="车辆类型" dataIndex="vehicleType" align="center" render={(text) => <span>{vehicleType[text]}</span>} /> | |
34 | 33 | <Column title="资金类型" dataIndex="financeType" align="center" render={(text) => <span>{financeType[text]}</span>} /> |
34 | + <Column title="融资银行" dataIndex="compName" align="center" /> | |
35 | 35 | <Column title="票号" dataIndex="invoiceNo" align="center" /> |
36 | 36 | <Column title="启票日期" dataIndex="invoiceTime" align="center" render={(text: number) => <span>{text && moment(text).format('YYYY-MM-DD') || '-'}</span>} /> |
37 | 37 | <Column title="品牌" dataIndex="brandName" align="center" /> | ... | ... |
src/pages/stock/TicketImport/entity.ts
... | ... | @@ -37,11 +37,12 @@ export const vehicleType = { |
37 | 37 | 4: '厂家直营车', |
38 | 38 | }; |
39 | 39 | |
40 | -export const financeType = { | |
41 | - 1: '兵财', | |
42 | - 2: '光大', | |
40 | +export const financeType: Record<number, string> = { | |
41 | + 1: '承兑汇票', | |
42 | + 2: '贷款', | |
43 | 43 | 3: '现金', |
44 | - 4: '现金(折让)', | |
44 | + 4: '折让', | |
45 | + 5: '厂家直营' | |
45 | 46 | }; |
46 | 47 | |
47 | 48 | export const BankListEnum = { | ... | ... |
src/pages/stock/TicketImport/store.ts
1 | 1 | import { useState, useEffect } from 'react'; |
2 | 2 | import { message } from 'antd'; |
3 | -import useInitail from "@/hooks/useInitail"; | |
3 | +import useInitail from '@/hooks/useInitail'; | |
4 | 4 | import { getBrandFilterApi, getDealerApi } from '@/common/api'; |
5 | 5 | import { getCompanyList, getTicketBrand } from './api'; |
6 | 6 | |
7 | 7 | export interface BreadcrumbItem { |
8 | - key?: string | |
9 | - name?: string | |
8 | + key?: string; | |
9 | + name?: string; | |
10 | 10 | } |
11 | 11 | |
12 | 12 | export default function useStore() { |
... | ... | @@ -14,14 +14,22 @@ export default function useStore() { |
14 | 14 | const { data: dealerList } = useInitail<CommonApi.OptionVO[], {}>(getDealerApi, [], {}); |
15 | 15 | const [brandId, setBrandId] = useState<any>(); |
16 | 16 | const [delay, setDelay] = useState<any>(true); |
17 | - const { data: factoryList, setParams: setFactoryParams, errMsg: factoryMessage } = useInitail<TicketImport.CompanyListVO[], any>(getCompanyList, [], { types: 10, compCategory: 1 }, delay); | |
17 | + const { | |
18 | + data: factoryList, | |
19 | + setParams: setFactoryParams, | |
20 | + errMsg: factoryMessage, | |
21 | + } = useInitail<TicketImport.CompanyListVO[], any>(getCompanyList, [], { types: 10, compCategory: 1 }, delay); | |
18 | 22 | /**融资银行 */ |
19 | - const { data: financeList, setParams: setFinanceParams, errMsg: financeMessage } = useInitail<TicketImport.CompanyListVO[], any>(getCompanyList, [], { types: 50, compCategory: 1 }, delay); | |
23 | + const { | |
24 | + data: financeList, | |
25 | + setParams: setFinanceParams, | |
26 | + errMsg: financeMessage, | |
27 | + } = useInitail<TicketImport.CompanyListVO[], any>(getCompanyList, [], { types: 50, compCategory: 1 }, delay); | |
20 | 28 | const [currentItem, setCurrentItem] = useState<TicketImport.QueryParams>({}); |
21 | 29 | // 面包屑列表 |
22 | - const [breadcrumbs, setBreadcrumbs] = useState<BreadcrumbItem[]>([{ name: "列表", key: "list" }]); | |
30 | + const [breadcrumbs, setBreadcrumbs] = useState<BreadcrumbItem[]>([{ name: '列表', key: 'list' }]); | |
23 | 31 | // 当前面包屑 |
24 | - const [currentBreadcrumb, setCurrentBreadcrumb] = useState<BreadcrumbItem>({ name: "列表", key: "list" }); | |
32 | + const [currentBreadcrumb, setCurrentBreadcrumb] = useState<BreadcrumbItem>({ name: '列表', key: 'list' }); | |
25 | 33 | const [ticketBatchId, setTicketBatchId] = useState<number>(); |
26 | 34 | // 保存上传押品后,服务器返回的数据 |
27 | 35 | const [CollateralItem, setCollateralItem] = useState<TicketImport.CollateralItem[]>([]); |
... | ... | @@ -45,14 +53,14 @@ export default function useStore() { |
45 | 53 | |
46 | 54 | useEffect(() => { |
47 | 55 | if (brandId) { |
48 | - setFactoryParams({ types: 10, compCategory: 1, brandId: typeof brandId === "object" ? brandId.value : brandId }, true); | |
49 | - setFinanceParams({ types: 50, compCategory: 1, brandId: typeof brandId === "object" ? brandId.value : brandId }, true); | |
56 | + setFactoryParams({ types: 10, compCategory: 1, brandId: typeof brandId === 'object' ? brandId.value : brandId }, true); | |
57 | + setFinanceParams({ types: 50, compCategory: 1, brandId: typeof brandId === 'object' ? brandId.value : brandId }, true); | |
50 | 58 | setDelay(false); |
51 | 59 | } |
52 | 60 | }, [brandId]); |
53 | 61 | |
54 | 62 | return { |
55 | - brandList: brandList.map(brand => ({ brandId: brand.id, brandName: brand.name })), | |
63 | + brandList: brandList.map((brand) => ({ brandId: brand.id, brandName: brand.name })), | |
56 | 64 | dealerList, |
57 | 65 | factoryList, |
58 | 66 | financeList, |
... | ... | @@ -81,6 +89,6 @@ export default function useStore() { |
81 | 89 | collateralVisible, |
82 | 90 | setCollateralVisible, |
83 | 91 | uploadCollateralModal, |
84 | - setUploadCollateralModal | |
92 | + setUploadCollateralModal, | |
85 | 93 | }; |
86 | -} | |
87 | 94 | \ No newline at end of file |
95 | +} | ... | ... |
src/utils/host.ts
1 | 1 | /* |
2 | 2 | * @Author: wangqiang@feewee.cn |
3 | 3 | * @Date: 2022-02-17 10:32:44 |
4 | - * @LastEditors: wangqiang@feewee.cn | |
5 | - * @LastEditTime: 2023-02-14 14:30:06 | |
4 | + * @LastEditors: jiangwei jiangwei.feewee.cn | |
5 | + * @LastEditTime: 2024-04-12 16:52:47 | |
6 | 6 | */ |
7 | 7 | export const HOST = '/admin'; |
8 | 8 | export const VWMS_HOST = '/vwms'; |
... | ... | @@ -88,6 +88,8 @@ export const DALARAN = '/dalaran'; |
88 | 88 | export const AMS_HOST = '/ams'; |
89 | 89 | // 云设备 |
90 | 90 | export const MMD_HOST = '/mmd'; |
91 | +// | |
92 | +export const SDS_HOST = '/sds'; | |
91 | 93 | |
92 | 94 | const host = { |
93 | 95 | admin: '/admin', | ... | ... |