Commit e7258cdf9037cffd24b1cd165f21e63d3f9c5e03
1 parent
96ee8bdc
🐹 feat(*): 会滚后的代码恢复
Showing
10 changed files
with
837 additions
and
512 deletions
src/pages/Pay/MerchantList/api.ts
... | ... | @@ -7,45 +7,56 @@ interface mchQuery { |
7 | 7 | groupId?: number; |
8 | 8 | status?: number; |
9 | 9 | } |
10 | -export async function queryMchList(params: mchQuery, p2: CommonApi.OptionVO[]): http.PromiseResp<IMerchant.MerchantList[]> { | |
11 | - const resp = await request.get<IMerchant.MerchantList[]>(`${PAYMENT}/mch/data/open/list`, { params: { ...params } }); | |
12 | - const mList = resp.data || []; | |
13 | - if ((p2?.length || 0) <= 0) { | |
14 | - resp.data = []; | |
15 | - return resp; | |
16 | - } | |
17 | - resp.data = dataTransfer(p2, mList); | |
18 | - return resp; | |
19 | -} | |
20 | 10 | |
21 | -function dataTransfer(dealerList: CommonApi.OptionVO[], merchantList: IMerchant.MerchantList[]): IMerchant.MerchantList[] { | |
22 | - const dealerMap: Record<string, IMerchant.MerchantList[]> = groupBy<IMerchant.MerchantList>(merchantList, 'dealerId'); | |
11 | +function dataTransfer(dealerList: CommonApi.OptionVO[], merchantList: IMerchant.OpenMerchantData[]): IMerchant.OpenMerchantData[] { | |
12 | + const dealerMap: Record<string, IMerchant.OpenMerchantData[]> = groupBy<IMerchant.OpenMerchantData>(merchantList, 'dealerId'); | |
23 | 13 | return dealerList.map((item) => { |
24 | 14 | const dealerId = item.id; |
25 | - const re: IMerchant.MerchantList = { dealerId, dealerName: item.name }; | |
15 | + const re: IMerchant.OpenMerchantData = { dealerId, dealerName: item.name }; | |
26 | 16 | if (dealerId) { |
27 | 17 | const merchant = dealerMap[dealerId]?.[0]; |
28 | - re.id = merchant?.id; | |
29 | 18 | re.groupId = merchant?.groupId; |
30 | - re.status = merchant?.status; | |
31 | - re.remark = merchant?.remark; | |
32 | - re.mchBriefName = merchant?.mchBriefName; | |
33 | - re.spMchId = merchant?.spMchId; | |
34 | - re.subMchId = merchant?.subMchId; | |
19 | + re.openNum = merchant?.openNum; | |
20 | + re.total = merchant?.total; | |
21 | + re.itemList = merchant?.itemList || []; | |
35 | 22 | } |
36 | 23 | return re; |
37 | 24 | }); |
38 | 25 | } |
26 | +/** 查询商家商户号开通总览 */ | |
27 | +export async function queryMchList(params: mchQuery, p2: CommonApi.OptionVO[]): http.PromiseResp<IMerchant.OpenMerchantData[]> { | |
28 | + const resp = await request.get<IMerchant.OpenMerchantData[]>(`${PAYMENT}/mch/data/base/list`, { params: { ...params } }); | |
29 | + const mList = resp.data || []; | |
30 | + if ((p2?.length || 0) <= 0) { | |
31 | + resp.data = []; | |
32 | + return resp; | |
33 | + } | |
34 | + resp.data = dataTransfer(p2, mList); | |
35 | + return resp; | |
36 | +} | |
39 | 37 | |
40 | -export async function queryMchDetail(dealerId: number): Promise<IMerchant.MerchantDetail> { | |
41 | - const res = await request.get<IMerchant.MerchantDetail>(`${PAYMENT}/mch/data/view/detail`, { params: { dealerId } }); | |
38 | +/** 查询商家商户基础资料情况 */ | |
39 | +export async function queryMchBaseData(dealerId: number): Promise<IMerchant.BaseMerchantData> { | |
40 | + const res = await request.get<IMerchant.BaseMerchantData>(`${PAYMENT}/mch/data/view/detail`, { params: { dealerId } }); | |
42 | 41 | return res.data || {}; |
43 | 42 | } |
44 | 43 | |
45 | -export function saveMchDetail(params: IMerchant.MerchantDetail) { | |
44 | +/** 保存商家商户基础资料 */ | |
45 | +export function saveMchBaseDetail(params: IMerchant.BaseMerchantData) { | |
46 | 46 | return request.post(`${PAYMENT}/mch/data/save`, params); |
47 | 47 | } |
48 | 48 | |
49 | +/** 保存子商户 */ | |
50 | +export function saveMchDetail(params: IMerchant.MerchantDetail) { | |
51 | + return request.post(`${PAYMENT}/mch/data/item/save`, params); | |
52 | +} | |
53 | + | |
54 | +/** 删除子商户 */ | |
55 | +export function delMchDetail(id?: number) { | |
56 | + return request.get(`${PAYMENT}/mch/data/item/delete`, { params: { id } }); | |
57 | +} | |
58 | + | |
59 | +/** 查询授权书模板 */ | |
49 | 60 | export function queryTemplate() { |
50 | - return request.get<string>(`${PAYMENT}/mch/data/auth/temp`); | |
61 | + return request.get<string>(`${PAYMENT}/mch/data/item/auth/temp`); | |
51 | 62 | } | ... | ... |
src/pages/Pay/MerchantList/components/BaseEditModal.tsx
0 → 100644
1 | +import { PlusOutlined } from '@ant-design/icons'; | |
2 | +import type { UploadProps } from 'antd'; | |
3 | +import { Modal, Form, Upload, Input, message, Skeleton } from 'antd'; | |
4 | +import React, { useEffect } from 'react'; | |
5 | +import { useRequest } from 'ahooks'; | |
6 | +import { queryMchBaseData, saveMchBaseDetail } from '../api'; | |
7 | + | |
8 | +interface BaseMerchantFormData { | |
9 | + dealerName?: string; | |
10 | + /** 公司营业执照 */ | |
11 | + subjectFid?: IMerchant.FileInfo[]; | |
12 | + /** 法人身份证照片(正面) */ | |
13 | + legalCertFront?: IMerchant.FileInfo[]; | |
14 | + /** 法人身份证照片(反面) */ | |
15 | + legalCertBack?: IMerchant.FileInfo[]; | |
16 | +} | |
17 | + | |
18 | +interface ModalProps { | |
19 | + visible?: boolean; | |
20 | + dealerId?: number; | |
21 | + dealerName?: string; | |
22 | + onCancel?: () => void; | |
23 | + onRefresh?: () => void; | |
24 | +} | |
25 | +export default function EditModal({ visible, dealerId = -1, dealerName, onCancel, onRefresh }: ModalProps) { | |
26 | + const [form] = Form.useForm(); | |
27 | + | |
28 | + const { data, run, loading } = useRequest(queryMchBaseData, { | |
29 | + manual: true, | |
30 | + onSuccess: (detail, _params) => loadFromState(detail), | |
31 | + onError: (e, _params) => { | |
32 | + message.error(e.message); | |
33 | + }, | |
34 | + }); | |
35 | + | |
36 | + const { run: save, loading: confirmLoading } = useRequest(saveMchBaseDetail, { | |
37 | + manual: true, | |
38 | + onSuccess: (_, _params) => { | |
39 | + message.success('保存成功'); | |
40 | + onCancel?.(); | |
41 | + onRefresh?.(); | |
42 | + }, | |
43 | + onError: (e, _) => { | |
44 | + message.error(e.message); | |
45 | + }, | |
46 | + }); | |
47 | + | |
48 | + const uploadProps: UploadProps = { | |
49 | + action: 'api2/file/upload', | |
50 | + accept: 'image/*', | |
51 | + maxCount: 1, | |
52 | + listType: 'picture-card', | |
53 | + beforeUpload(file) { | |
54 | + const isLt2M = file.size / 1024 / 1024 < 2; | |
55 | + if (!isLt2M) { | |
56 | + message.error('图片大小不能超过 2MB!'); | |
57 | + return Upload.LIST_IGNORE; | |
58 | + } | |
59 | + return true; | |
60 | + }, | |
61 | + }; | |
62 | + | |
63 | + useEffect(() => { | |
64 | + if (visible) { | |
65 | + run(dealerId); | |
66 | + } | |
67 | + }, [visible]); | |
68 | + | |
69 | + function loadFromState(detail: IMerchant.BaseMerchantData) { | |
70 | + const commomFileProps: IMerchant.FileInfo = { | |
71 | + lastModified: Date.now(), | |
72 | + lastModifiedDate: new Date(), | |
73 | + name: '', | |
74 | + percent: 100, | |
75 | + status: 'done', | |
76 | + response: { data: '' }, | |
77 | + uid: '-1', | |
78 | + thumbUrl: '', | |
79 | + url: '', | |
80 | + }; | |
81 | + const fromState: BaseMerchantFormData = {}; | |
82 | + fromState.dealerName = detail?.dealerName ?? dealerName; | |
83 | + if (detail?.subjectFid) { | |
84 | + fromState.subjectFid = [ | |
85 | + { | |
86 | + ...commomFileProps, | |
87 | + response: { data: detail?.subjectFid }, | |
88 | + uid: detail.subjectFid ?? Date.now().toString(), | |
89 | + thumbUrl: `api/file/show?fid=${detail?.subjectFid}`, | |
90 | + url: `api/file/show?fid=${detail?.subjectFid}`, | |
91 | + }, | |
92 | + ]; | |
93 | + } | |
94 | + const certFidArr = detail?.legalCertFids?.split(','); | |
95 | + if (certFidArr?.[0]) { | |
96 | + fromState.legalCertFront = [ | |
97 | + { | |
98 | + ...commomFileProps, | |
99 | + response: { data: certFidArr?.[0] }, | |
100 | + uid: certFidArr?.[0] ?? Date.now().toString(), | |
101 | + thumbUrl: `api/file/show?fid=${certFidArr?.[0]}`, | |
102 | + url: `api/file/show?fid=${certFidArr?.[0]}`, | |
103 | + }, | |
104 | + ]; | |
105 | + } | |
106 | + if (certFidArr?.[1]) { | |
107 | + fromState.legalCertBack = [ | |
108 | + { | |
109 | + ...commomFileProps, | |
110 | + response: { data: certFidArr?.[1] }, | |
111 | + uid: certFidArr?.[1] ?? Date.now().toString(), | |
112 | + thumbUrl: `api/file/show?fid=${certFidArr?.[1]}`, | |
113 | + url: `api/file/show?fid=${certFidArr?.[1]}`, | |
114 | + }, | |
115 | + ]; | |
116 | + } | |
117 | + form.setFieldsValue(fromState); | |
118 | + } | |
119 | + | |
120 | + const normFile = (e: any) => { | |
121 | + if (Array.isArray(e)) { | |
122 | + return e; | |
123 | + } | |
124 | + return e?.fileList; | |
125 | + }; | |
126 | + | |
127 | + function handleSave(feildValue: BaseMerchantFormData) { | |
128 | + let saveData: IMerchant.BaseMerchantData = { dealerId, dealerName }; | |
129 | + if (data?.id) { | |
130 | + saveData = { ...data }; | |
131 | + } | |
132 | + saveData.subjectFid = feildValue.subjectFid?.[0]?.response?.data ?? ''; | |
133 | + saveData.legalCertFids = `${feildValue.legalCertFront?.[0]?.response?.data ?? ''},${feildValue.legalCertBack?.[0]?.response?.data ?? ''}`; | |
134 | + save(saveData); | |
135 | + } | |
136 | + | |
137 | + return ( | |
138 | + <Modal | |
139 | + title="资料维护" | |
140 | + width="65%" | |
141 | + open={visible} | |
142 | + onCancel={onCancel} | |
143 | + onOk={form.submit} | |
144 | + afterClose={() => form.resetFields()} | |
145 | + confirmLoading={confirmLoading} | |
146 | + > | |
147 | + <Skeleton loading={loading} active={loading} paragraph={{ rows: 16 }}> | |
148 | + <Form form={form} onFinish={handleSave} labelWrap labelCol={{ span: 6 }}> | |
149 | + <Form.Item label="商家" name="dealerName"> | |
150 | + <Input disabled style={{ maxWidth: 350 }} /> | |
151 | + </Form.Item> | |
152 | + | |
153 | + <Form.Item noStyle shouldUpdate={(prevValues, curValues) => prevValues.subjectFid != curValues.subjectFid}> | |
154 | + {({ getFieldValue }) => { | |
155 | + const subjectFidLength = getFieldValue('subjectFid')?.length ?? 0; | |
156 | + return ( | |
157 | + <Form.Item | |
158 | + label="公司营业执照" | |
159 | + name="subjectFid" | |
160 | + valuePropName="fileList" | |
161 | + getValueFromEvent={normFile} | |
162 | + rules={[{ required: true, message: '营业执照照片不能为空' }]} | |
163 | + extra={<p style={{ margin: 0, fontSize: 12 }}>营业执照正面清晰完整照片且不超过2M大小的JPG、BMP、PNG照片</p>} | |
164 | + > | |
165 | + <Upload {...uploadProps}> | |
166 | + {subjectFidLength >= 1 ? null : ( | |
167 | + <button style={{ border: 0, background: 'none' }} type="button"> | |
168 | + <PlusOutlined rev="" /> | |
169 | + <div style={{ marginTop: 8 }}>上传</div> | |
170 | + </button> | |
171 | + )} | |
172 | + </Upload> | |
173 | + </Form.Item> | |
174 | + ); | |
175 | + }} | |
176 | + </Form.Item> | |
177 | + <Form.Item noStyle shouldUpdate={(prevValues, curValues) => prevValues.legalCertFront != curValues.legalCertFront}> | |
178 | + {({ getFieldValue }) => { | |
179 | + const fileLength = getFieldValue('legalCertFront')?.length ?? 0; | |
180 | + return ( | |
181 | + <Form.Item | |
182 | + label="法人身份证人像面照片" | |
183 | + name="legalCertFront" | |
184 | + valuePropName="fileList" | |
185 | + getValueFromEvent={normFile} | |
186 | + rules={[{ required: true, message: '身份证照片不能为空' }]} | |
187 | + extra={<p style={{ margin: 0, fontSize: 12 }}>身份证人像面清晰完整照片且不超过2M大小的JPG、BMP、PNG格式照片</p>} | |
188 | + > | |
189 | + <Upload {...uploadProps}> | |
190 | + {fileLength >= 1 ? null : ( | |
191 | + <button style={{ border: 0, background: 'none' }} type="button"> | |
192 | + <PlusOutlined rev="" /> | |
193 | + <div style={{ marginTop: 8 }}>上传</div> | |
194 | + </button> | |
195 | + )} | |
196 | + </Upload> | |
197 | + </Form.Item> | |
198 | + ); | |
199 | + }} | |
200 | + </Form.Item> | |
201 | + <Form.Item noStyle shouldUpdate={(prevValues, curValues) => prevValues.legalCertBack != curValues.legalCertBack}> | |
202 | + {({ getFieldValue }) => { | |
203 | + const legalCertBackLength = getFieldValue('legalCertBack')?.length ?? 0; | |
204 | + return ( | |
205 | + <Form.Item | |
206 | + label="法人身份证国徽面照片" | |
207 | + name="legalCertBack" | |
208 | + valuePropName="fileList" | |
209 | + getValueFromEvent={normFile} | |
210 | + rules={[{ required: true, message: '身份证照片不能为空' }]} | |
211 | + extra={<p style={{ margin: 0, fontSize: 12 }}>身份证国徽面清晰完整照片且不超过2M大小的JPG、BMP、PNG格式照片</p>} | |
212 | + > | |
213 | + <Upload {...uploadProps}> | |
214 | + {legalCertBackLength >= 1 ? null : ( | |
215 | + <button style={{ border: 0, background: 'none' }} type="button"> | |
216 | + <PlusOutlined rev="" /> | |
217 | + <div style={{ marginTop: 8 }}>上传</div> | |
218 | + </button> | |
219 | + )} | |
220 | + </Upload> | |
221 | + </Form.Item> | |
222 | + ); | |
223 | + }} | |
224 | + </Form.Item> | |
225 | + </Form> | |
226 | + </Skeleton> | |
227 | + </Modal> | |
228 | + ); | |
229 | +} | ... | ... |
src/pages/Pay/MerchantList/components/EditModal.tsx
1 | 1 | import { PlusOutlined } from '@ant-design/icons'; |
2 | 2 | import type { UploadProps } from 'antd'; |
3 | -import { Modal, Form, Upload, Input, Checkbox, message, Skeleton } from 'antd'; | |
3 | +import { Modal, Form, Upload, Input, Checkbox, message } from 'antd'; | |
4 | 4 | import React, { useEffect } from 'react'; |
5 | 5 | import { useRequest, useSafeState } from 'ahooks'; |
6 | -import { queryMchDetail, saveMchDetail, queryTemplate } from '../api'; | |
6 | +import { saveMchDetail, queryTemplate } from '../api'; | |
7 | 7 | import { MerchantStatus } from '../entity'; |
8 | 8 | |
9 | 9 | interface ModalProps { |
10 | 10 | visible?: boolean; |
11 | - record?: IMerchant.MerchantList; | |
11 | + record?: IMerchant.MerchantDetail; | |
12 | 12 | onCancel?: () => void; |
13 | 13 | onRefresh?: () => void; |
14 | 14 | } |
15 | 15 | export default function EditModal({ visible, record, onCancel, onRefresh }: ModalProps) { |
16 | 16 | const [form] = Form.useForm(); |
17 | 17 | const [template, setTemplate] = useSafeState<string>(); |
18 | - const { data, run, loading } = useRequest(queryMchDetail, { | |
19 | - manual: true, | |
20 | - onSuccess: (detail, _params) => loadFromState(detail), | |
21 | - onError: (e, _params) => { | |
22 | - message.error(e.message); | |
23 | - }, | |
24 | - }); | |
25 | 18 | |
26 | 19 | const { run: save, loading: confirmLoading } = useRequest(saveMchDetail, { |
27 | 20 | manual: true, |
... | ... | @@ -55,11 +48,11 @@ export default function EditModal({ visible, record, onCancel, onRefresh }: Moda |
55 | 48 | queryTemplate().then((res) => { |
56 | 49 | setTemplate(res.data ?? ''); |
57 | 50 | }); |
51 | + | |
58 | 52 | if (record?.status && record?.dealerId) { |
59 | - run(record.dealerId); | |
53 | + loadFromState(record); | |
60 | 54 | } else { |
61 | 55 | const fromState: IMerchant.MerchantFromState = {}; |
62 | - fromState.dealerName = record?.dealerName; | |
63 | 56 | fromState.mangerSameLegal = true; |
64 | 57 | form.setFieldsValue(fromState); |
65 | 58 | } |
... | ... | @@ -79,41 +72,6 @@ export default function EditModal({ visible, record, onCancel, onRefresh }: Moda |
79 | 72 | url: '', |
80 | 73 | }; |
81 | 74 | const fromState: IMerchant.MerchantFromState = {}; |
82 | - fromState.dealerName = detail?.dealerName; | |
83 | - if (detail?.subjectFid) { | |
84 | - fromState.subjectFid = [ | |
85 | - { | |
86 | - ...commomFileProps, | |
87 | - response: { data: detail?.subjectFid }, | |
88 | - uid: detail.subjectFid ?? Date.now().toString(), | |
89 | - thumbUrl: `api/file/show?fid=${detail?.subjectFid}`, | |
90 | - url: `api/file/show?fid=${detail?.subjectFid}`, | |
91 | - }, | |
92 | - ]; | |
93 | - } | |
94 | - const certFidArr = detail?.legalCertFids?.split(','); | |
95 | - if (certFidArr?.[0]) { | |
96 | - fromState.legalCertFront = [ | |
97 | - { | |
98 | - ...commomFileProps, | |
99 | - response: { data: certFidArr?.[0] }, | |
100 | - uid: certFidArr?.[0] ?? Date.now().toString(), | |
101 | - thumbUrl: `api/file/show?fid=${certFidArr?.[0]}`, | |
102 | - url: `api/file/show?fid=${certFidArr?.[0]}`, | |
103 | - }, | |
104 | - ]; | |
105 | - } | |
106 | - if (certFidArr?.[1]) { | |
107 | - fromState.legalCertBack = [ | |
108 | - { | |
109 | - ...commomFileProps, | |
110 | - response: { data: certFidArr?.[1] }, | |
111 | - uid: certFidArr?.[1] ?? Date.now().toString(), | |
112 | - thumbUrl: `api/file/show?fid=${certFidArr?.[1]}`, | |
113 | - url: `api/file/show?fid=${certFidArr?.[1]}`, | |
114 | - }, | |
115 | - ]; | |
116 | - } | |
117 | 75 | fromState.publicBankNo = detail?.publicBankNo; |
118 | 76 | fromState.publicBankName = detail?.publicBankName; |
119 | 77 | fromState.publicBankOrg = detail?.publicBankOrg; |
... | ... | @@ -163,12 +121,10 @@ export default function EditModal({ visible, record, onCancel, onRefresh }: Moda |
163 | 121 | }; |
164 | 122 | |
165 | 123 | function handleSave(feildValue: IMerchant.MerchantFromState) { |
166 | - let saveData: IMerchant.MerchantDetail = { dealerId: record?.dealerId, dealerName: record?.dealerName }; | |
124 | + let saveData: IMerchant.MerchantDetail = { dealerId: record?.dealerId }; | |
167 | 125 | if (record?.id) { |
168 | - saveData = { ...data }; | |
126 | + saveData = { ...record }; | |
169 | 127 | } |
170 | - saveData.subjectFid = feildValue.subjectFid?.[0]?.response?.data ?? ''; | |
171 | - saveData.legalCertFids = `${feildValue.legalCertFront?.[0]?.response?.data ?? ''},${feildValue.legalCertBack?.[0]?.response?.data ?? ''}`; | |
172 | 128 | saveData.publicBankNo = feildValue?.publicBankNo; |
173 | 129 | saveData.publicBankName = feildValue?.publicBankName; |
174 | 130 | saveData.publicBankOrg = feildValue?.publicBankOrg; |
... | ... | @@ -194,225 +150,146 @@ export default function EditModal({ visible, record, onCancel, onRefresh }: Moda |
194 | 150 | afterClose={() => form.resetFields()} |
195 | 151 | confirmLoading={confirmLoading} |
196 | 152 | > |
197 | - <Skeleton loading={loading} active={loading} paragraph={{ rows: 16 }}> | |
198 | - <Form form={form} onFinish={handleSave} labelWrap labelCol={{ span: 6 }} disabled={MerchantStatus['已开通'] == record?.status}> | |
199 | - <Form.Item label="商家" name="dealerName"> | |
200 | - <Input disabled style={{ maxWidth: 350 }} /> | |
201 | - </Form.Item> | |
202 | - | |
203 | - <Form.Item noStyle shouldUpdate={(prevValues, curValues) => prevValues.subjectFid != curValues.subjectFid}> | |
204 | - {({ getFieldValue }) => { | |
205 | - const subjectFidLength = getFieldValue('subjectFid')?.length ?? 0; | |
206 | - return ( | |
207 | - <Form.Item | |
208 | - label="公司营业执照" | |
209 | - name="subjectFid" | |
210 | - valuePropName="fileList" | |
211 | - getValueFromEvent={normFile} | |
212 | - rules={[{ required: true, message: '营业执照照片不能为空' }]} | |
213 | - extra={<p style={{ margin: 0, fontSize: 12 }}>营业执照正面清晰完整照片且不超过2M大小的JPG、BMP、PNG照片</p>} | |
214 | - > | |
215 | - <Upload {...uploadProps}> | |
216 | - {subjectFidLength >= 1 ? null : ( | |
217 | - <button style={{ border: 0, background: 'none' }} type="button"> | |
218 | - <PlusOutlined rev="" /> | |
219 | - <div style={{ marginTop: 8 }}>上传</div> | |
220 | - </button> | |
221 | - )} | |
222 | - </Upload> | |
223 | - </Form.Item> | |
224 | - ); | |
225 | - }} | |
226 | - </Form.Item> | |
227 | - <Form.Item noStyle shouldUpdate={(prevValues, curValues) => prevValues.legalCertFront != curValues.legalCertFront}> | |
228 | - {({ getFieldValue }) => { | |
229 | - const fileLength = getFieldValue('legalCertFront')?.length ?? 0; | |
230 | - return ( | |
231 | - <Form.Item | |
232 | - label="法人身份证人像面照片" | |
233 | - name="legalCertFront" | |
234 | - valuePropName="fileList" | |
235 | - getValueFromEvent={normFile} | |
236 | - rules={[{ required: true, message: '身份证照片不能为空' }]} | |
237 | - extra={<p style={{ margin: 0, fontSize: 12 }}>身份证人像面清晰完整照片且不超过2M大小的JPG、BMP、PNG格式照片</p>} | |
238 | - > | |
239 | - <Upload {...uploadProps}> | |
240 | - {fileLength >= 1 ? null : ( | |
241 | - <button style={{ border: 0, background: 'none' }} type="button"> | |
242 | - <PlusOutlined rev="" /> | |
243 | - <div style={{ marginTop: 8 }}>上传</div> | |
244 | - </button> | |
245 | - )} | |
246 | - </Upload> | |
153 | + <Form form={form} onFinish={handleSave} labelWrap labelCol={{ span: 6 }} disabled={MerchantStatus['已开通'] == record?.status}> | |
154 | + <Form.Item label="对公账户" name="publicBankNo" rules={[{ required: true, message: '对公账户不能为空' }]}> | |
155 | + <Input placeholder="请输入" type="number" style={{ maxWidth: 350 }} /> | |
156 | + </Form.Item> | |
157 | + <Form.Item label="对公账户开户银行" name="publicBankName" rules={[{ required: true, message: '对公账户开户银行不能为空' }]}> | |
158 | + <Input placeholder="请输入" style={{ maxWidth: 350 }} /> | |
159 | + </Form.Item> | |
160 | + <Form.Item | |
161 | + label="对公账户开户支行" | |
162 | + name="publicBankOrg" | |
163 | + rules={[{ required: true, message: '对公账户开户支行不能为空' }]} | |
164 | + extra={<p style={{ margin: 0, marginTop: 10, fontSize: 12 }}>开户支行全称(省份-城市-支行)</p>} | |
165 | + > | |
166 | + <Input placeholder="请输入开户支行(省份-城市-支行)" style={{ maxWidth: 350 }} /> | |
167 | + </Form.Item> | |
168 | + <Form.Item | |
169 | + label="商户简称" | |
170 | + name="mchBriefName" | |
171 | + rules={[{ required: true, min: 2, max: 30, message: '请输入商户简称' }]} | |
172 | + extra={ | |
173 | + <> | |
174 | + <p style={{ margin: 0, marginTop: 10, fontSize: 12 }}>1、在支付完成页向买家展示,需与微信经营类目相关。</p> | |
175 | + <p style={{ margin: 0, fontSize: 12 }}>2、简称要求(2-30字):</p> | |
176 | + <p style={{ margin: 0, fontSize: 12 }}> | |
177 | + ① 不支持单纯以人名来命名,若为个体户经营,可用“个体户+经营者名称”或“经营者名称+业务”命名,如“个体户张三”或“张三餐饮店”; | |
178 | + </p> | |
179 | + <p style={{ margin: 0, fontSize: 12 }}>② 不支持无实际意义的文案,如“XX特约商户”、“800”、“XX客服电话XXX”;</p> | |
180 | + </> | |
181 | + } | |
182 | + > | |
183 | + <Input placeholder="请输入" maxLength={30} style={{ maxWidth: 350 }} /> | |
184 | + </Form.Item> | |
185 | + <Form.Item | |
186 | + label="客服电话" | |
187 | + name="mchServicePhone" | |
188 | + rules={[{ required: true, type: 'string', pattern: /^\d*$/, message: '请输入正确的电话号码' }]} | |
189 | + extra={<p style={{ margin: 0, marginTop: 10, fontSize: 12 }}>请输入正确的客服电话以便微信回电核实信息。</p>} | |
190 | + > | |
191 | + <Input placeholder="请输入" maxLength={32} style={{ maxWidth: 350 }} /> | |
192 | + </Form.Item> | |
193 | + <Form.Item label="管理者是否法人" name="mangerSameLegal" valuePropName="checked"> | |
194 | + <Checkbox>是</Checkbox> | |
195 | + </Form.Item> | |
196 | + <Form.Item noStyle shouldUpdate={(prevValues, curValues) => prevValues.mangerSameLegal != curValues.mangerSameLegal}> | |
197 | + {({ getFieldValue }) => { | |
198 | + const _mangerSameLegal = getFieldValue('mangerSameLegal'); | |
199 | + return !_mangerSameLegal ? ( | |
200 | + <> | |
201 | + <Form.Item noStyle shouldUpdate={(prevValues, curValues) => prevValues.mangerCertFront != curValues.mangerCertFront}> | |
202 | + {({ getFieldValue }) => { | |
203 | + const fileLength = getFieldValue('mangerCertFront')?.length ?? 0; | |
204 | + return ( | |
205 | + <Form.Item | |
206 | + label="管理者身份证人像面照片" | |
207 | + name="mangerCertFront" | |
208 | + valuePropName="fileList" | |
209 | + getValueFromEvent={normFile} | |
210 | + rules={[{ required: true, message: '身份证照片不能为空' }]} | |
211 | + extra={<p style={{ margin: 0, fontSize: 12 }}>身份证人像面清晰完整照片且不超过2M大小的JPG、BMP、PNG格式照片</p>} | |
212 | + > | |
213 | + <Upload {...uploadProps}> | |
214 | + {fileLength >= 1 ? null : ( | |
215 | + <button style={{ border: 0, background: 'none' }} type="button"> | |
216 | + <PlusOutlined rev="" /> | |
217 | + <div style={{ marginTop: 8 }}>上传</div> | |
218 | + </button> | |
219 | + )} | |
220 | + </Upload> | |
221 | + </Form.Item> | |
222 | + ); | |
223 | + }} | |
247 | 224 | </Form.Item> |
248 | - ); | |
249 | - }} | |
250 | - </Form.Item> | |
251 | - <Form.Item noStyle shouldUpdate={(prevValues, curValues) => prevValues.legalCertBack != curValues.legalCertBack}> | |
252 | - {({ getFieldValue }) => { | |
253 | - const legalCertBackLength = getFieldValue('legalCertBack')?.length ?? 0; | |
254 | - return ( | |
255 | - <Form.Item | |
256 | - label="法人身份证国徽面照片" | |
257 | - name="legalCertBack" | |
258 | - valuePropName="fileList" | |
259 | - getValueFromEvent={normFile} | |
260 | - rules={[{ required: true, message: '身份证照片不能为空' }]} | |
261 | - extra={<p style={{ margin: 0, fontSize: 12 }}>身份证国徽面清晰完整照片且不超过2M大小的JPG、BMP、PNG格式照片</p>} | |
262 | - > | |
263 | - <Upload {...uploadProps}> | |
264 | - {legalCertBackLength >= 1 ? null : ( | |
265 | - <button style={{ border: 0, background: 'none' }} type="button"> | |
266 | - <PlusOutlined rev="" /> | |
267 | - <div style={{ marginTop: 8 }}>上传</div> | |
268 | - </button> | |
269 | - )} | |
270 | - </Upload> | |
225 | + <Form.Item noStyle shouldUpdate={(prevValues, curValues) => prevValues.mangerCertBack != curValues.mangerCertBack}> | |
226 | + {({ getFieldValue }) => { | |
227 | + const fileLength = getFieldValue('mangerCertBack')?.length ?? 0; | |
228 | + return ( | |
229 | + <Form.Item | |
230 | + label="管理者身份证国徽面照片" | |
231 | + name="mangerCertBack" | |
232 | + valuePropName="fileList" | |
233 | + getValueFromEvent={normFile} | |
234 | + rules={[{ required: true, message: '身份证照片不能为空' }]} | |
235 | + extra={<p style={{ margin: 0, fontSize: 12 }}>身份证国徽份证人像面清晰完整照片且不超过2M大小的JPG、BMP、PNG格式照片</p>} | |
236 | + > | |
237 | + <Upload {...uploadProps}> | |
238 | + {fileLength >= 1 ? null : ( | |
239 | + <button style={{ border: 0, background: 'none' }} type="button"> | |
240 | + <PlusOutlined rev="" /> | |
241 | + <div style={{ marginTop: 8 }}>上传</div> | |
242 | + </button> | |
243 | + )} | |
244 | + </Upload> | |
245 | + </Form.Item> | |
246 | + ); | |
247 | + }} | |
271 | 248 | </Form.Item> |
272 | - ); | |
273 | - }} | |
274 | - </Form.Item> | |
275 | 249 | |
276 | - <Form.Item label="对公账户" name="publicBankNo" rules={[{ required: true, message: '对公账户不能为空' }]}> | |
277 | - <Input placeholder="请输入" type="number" style={{ maxWidth: 350 }} /> | |
278 | - </Form.Item> | |
279 | - <Form.Item label="对公账户开户银行" name="publicBankName" rules={[{ required: true, message: '对公账户开户银行不能为空' }]}> | |
280 | - <Input placeholder="请输入" style={{ maxWidth: 350 }} /> | |
281 | - </Form.Item> | |
282 | - <Form.Item | |
283 | - label="对公账户开户支行" | |
284 | - name="publicBankOrg" | |
285 | - rules={[{ required: true, message: '对公账户开户支行不能为空' }]} | |
286 | - extra={<p style={{ margin: 0, marginTop: 10, fontSize: 12 }}>开户支行全称(省份-城市-支行)</p>} | |
287 | - > | |
288 | - <Input placeholder="请输入开户支行(省份-城市-支行)" style={{ maxWidth: 350 }} /> | |
289 | - </Form.Item> | |
290 | - <Form.Item | |
291 | - label="商户简称" | |
292 | - name="mchBriefName" | |
293 | - rules={[{ required: true, min: 2, max: 30, message: '请输入商户简称' }]} | |
294 | - extra={ | |
295 | - <> | |
296 | - <p style={{ margin: 0, marginTop: 10, fontSize: 12 }}>1、在支付完成页向买家展示,需与微信经营类目相关。</p> | |
297 | - <p style={{ margin: 0, fontSize: 12 }}>2、简称要求(2-30字):</p> | |
298 | - <p style={{ margin: 0, fontSize: 12 }}> | |
299 | - ① 不支持单纯以人名来命名,若为个体户经营,可用“个体户+经营者名称”或“经营者名称+业务”命名,如“个体户张三”或“张三餐饮店”; | |
300 | - </p> | |
301 | - <p style={{ margin: 0, fontSize: 12 }}>② 不支持无实际意义的文案,如“XX特约商户”、“800”、“XX客服电话XXX”;</p> | |
250 | + <Form.Item noStyle shouldUpdate={(prevValues, curValues) => prevValues.mangerAuthFile != curValues.mangerAuthFile}> | |
251 | + {({ getFieldValue }) => { | |
252 | + const fileLength = getFieldValue('mangerAuthFile')?.length ?? 0; | |
253 | + return ( | |
254 | + <Form.Item | |
255 | + label="管理者业务办理授权书" | |
256 | + name="mangerAuthFile" | |
257 | + valuePropName="fileList" | |
258 | + getValueFromEvent={normFile} | |
259 | + rules={[{ required: true, message: '授权书不能为空' }]} | |
260 | + extra={ | |
261 | + <a href={`api/file/show?fid=${template}`} rel="noreferrer" target="_blank"> | |
262 | + 下载授权书模板 | |
263 | + </a> | |
264 | + } | |
265 | + > | |
266 | + <Upload {...uploadProps}> | |
267 | + {fileLength >= 1 ? null : ( | |
268 | + <button style={{ border: 0, background: 'none' }} type="button"> | |
269 | + <PlusOutlined rev="" /> | |
270 | + <div style={{ marginTop: 8 }}>上传</div> | |
271 | + </button> | |
272 | + )} | |
273 | + </Upload> | |
274 | + </Form.Item> | |
275 | + ); | |
276 | + }} | |
277 | + </Form.Item> | |
302 | 278 | </> |
303 | - } | |
304 | - > | |
305 | - <Input placeholder="请输入" maxLength={30} style={{ maxWidth: 350 }} /> | |
306 | - </Form.Item> | |
307 | - <Form.Item | |
308 | - label="客服电话" | |
309 | - name="mchServicePhone" | |
310 | - rules={[{ required: true, type: 'string', pattern: /^\d*$/, message: '请输入正确的电话号码' }]} | |
311 | - extra={<p style={{ margin: 0, marginTop: 10, fontSize: 12 }}>请输入正确的客服电话以便微信回电核实信息。</p>} | |
312 | - > | |
313 | - <Input placeholder="请输入" maxLength={32} style={{ maxWidth: 350 }} /> | |
314 | - </Form.Item> | |
315 | - <Form.Item label="管理者是否法人" name="mangerSameLegal" valuePropName="checked"> | |
316 | - <Checkbox>是</Checkbox> | |
317 | - </Form.Item> | |
318 | - <Form.Item noStyle shouldUpdate={(prevValues, curValues) => prevValues.mangerSameLegal != curValues.mangerSameLegal}> | |
319 | - {({ getFieldValue }) => { | |
320 | - const _mangerSameLegal = getFieldValue('mangerSameLegal'); | |
321 | - return !_mangerSameLegal ? ( | |
322 | - <> | |
323 | - <Form.Item noStyle shouldUpdate={(prevValues, curValues) => prevValues.mangerCertFront != curValues.mangerCertFront}> | |
324 | - {({ getFieldValue }) => { | |
325 | - const fileLength = getFieldValue('mangerCertFront')?.length ?? 0; | |
326 | - return ( | |
327 | - <Form.Item | |
328 | - label="管理者身份证人像面照片" | |
329 | - name="mangerCertFront" | |
330 | - valuePropName="fileList" | |
331 | - getValueFromEvent={normFile} | |
332 | - rules={[{ required: true, message: '身份证照片不能为空' }]} | |
333 | - extra={<p style={{ margin: 0, fontSize: 12 }}>身份证人像面清晰完整照片且不超过2M大小的JPG、BMP、PNG格式照片</p>} | |
334 | - > | |
335 | - <Upload {...uploadProps}> | |
336 | - {fileLength >= 1 ? null : ( | |
337 | - <button style={{ border: 0, background: 'none' }} type="button"> | |
338 | - <PlusOutlined rev="" /> | |
339 | - <div style={{ marginTop: 8 }}>上传</div> | |
340 | - </button> | |
341 | - )} | |
342 | - </Upload> | |
343 | - </Form.Item> | |
344 | - ); | |
345 | - }} | |
346 | - </Form.Item> | |
347 | - <Form.Item noStyle shouldUpdate={(prevValues, curValues) => prevValues.mangerCertBack != curValues.mangerCertBack}> | |
348 | - {({ getFieldValue }) => { | |
349 | - const fileLength = getFieldValue('mangerCertBack')?.length ?? 0; | |
350 | - return ( | |
351 | - <Form.Item | |
352 | - label="管理者身份证国徽面照片" | |
353 | - name="mangerCertBack" | |
354 | - valuePropName="fileList" | |
355 | - getValueFromEvent={normFile} | |
356 | - rules={[{ required: true, message: '身份证照片不能为空' }]} | |
357 | - extra={<p style={{ margin: 0, fontSize: 12 }}>身份证国徽份证人像面清晰完整照片且不超过2M大小的JPG、BMP、PNG格式照片</p>} | |
358 | - > | |
359 | - <Upload {...uploadProps}> | |
360 | - {fileLength >= 1 ? null : ( | |
361 | - <button style={{ border: 0, background: 'none' }} type="button"> | |
362 | - <PlusOutlined rev="" /> | |
363 | - <div style={{ marginTop: 8 }}>上传</div> | |
364 | - </button> | |
365 | - )} | |
366 | - </Upload> | |
367 | - </Form.Item> | |
368 | - ); | |
369 | - }} | |
370 | - </Form.Item> | |
371 | - | |
372 | - <Form.Item noStyle shouldUpdate={(prevValues, curValues) => prevValues.mangerAuthFile != curValues.mangerAuthFile}> | |
373 | - {({ getFieldValue }) => { | |
374 | - const fileLength = getFieldValue('mangerAuthFile')?.length ?? 0; | |
375 | - return ( | |
376 | - <Form.Item | |
377 | - label="管理者业务办理授权书" | |
378 | - name="mangerAuthFile" | |
379 | - valuePropName="fileList" | |
380 | - getValueFromEvent={normFile} | |
381 | - rules={[{ required: true, message: '授权书不能为空' }]} | |
382 | - extra={ | |
383 | - <a href={`api/file/show?fid=${template}`} rel="noreferrer" target="_blank"> | |
384 | - 下载授权书模板 | |
385 | - </a> | |
386 | - } | |
387 | - > | |
388 | - <Upload {...uploadProps}> | |
389 | - {fileLength >= 1 ? null : ( | |
390 | - <button style={{ border: 0, background: 'none' }} type="button"> | |
391 | - <PlusOutlined rev="" /> | |
392 | - <div style={{ marginTop: 8 }}>上传</div> | |
393 | - </button> | |
394 | - )} | |
395 | - </Upload> | |
396 | - </Form.Item> | |
397 | - ); | |
398 | - }} | |
399 | - </Form.Item> | |
400 | - </> | |
401 | - ) : null; | |
402 | - }} | |
403 | - </Form.Item> | |
404 | - <Form.Item | |
405 | - label="管理者电话" | |
406 | - name="mangerPhone" | |
407 | - rules={[{ required: true, type: 'string', pattern: /^\d*$/, message: '请输入正确的电话号码' }]} | |
408 | - > | |
409 | - <Input placeholder="请输入" maxLength={32} style={{ maxWidth: 350 }} /> | |
410 | - </Form.Item> | |
411 | - <Form.Item label="管理者邮箱" name="mangerEmail" required rules={[{ required: true, type: 'email', message: '请输入正确的邮箱' }]}> | |
412 | - <Input placeholder="请输入" type="email" maxLength={128} style={{ maxWidth: 350 }} /> | |
413 | - </Form.Item> | |
414 | - </Form> | |
415 | - </Skeleton> | |
279 | + ) : null; | |
280 | + }} | |
281 | + </Form.Item> | |
282 | + <Form.Item | |
283 | + label="管理者电话" | |
284 | + name="mangerPhone" | |
285 | + rules={[{ required: true, type: 'string', pattern: /^\d*$/, message: '请输入正确的电话号码' }]} | |
286 | + > | |
287 | + <Input placeholder="请输入" maxLength={32} style={{ maxWidth: 350 }} /> | |
288 | + </Form.Item> | |
289 | + <Form.Item label="管理者邮箱" name="mangerEmail" required rules={[{ required: true, type: 'email', message: '请输入正确的邮箱' }]}> | |
290 | + <Input placeholder="请输入" type="email" maxLength={128} style={{ maxWidth: 350 }} /> | |
291 | + </Form.Item> | |
292 | + </Form> | |
416 | 293 | </Modal> |
417 | 294 | ); |
418 | 295 | } | ... | ... |
src/pages/Pay/MerchantList/components/List.tsx
1 | -import { Badge, Table } from 'antd'; | |
1 | +import type { TableColumnsType } from 'antd'; | |
2 | +import { Badge, Divider, Popconfirm, Table, message } from 'antd'; | |
2 | 3 | import type { ColumnsType } from 'antd/lib/table'; |
3 | 4 | import React, { useMemo } from 'react'; |
4 | -import { MerchantStatus } from '../entity'; | |
5 | 5 | import EditModal from './EditModal'; |
6 | +import BaseEditModal from './BaseEditModal'; | |
6 | 7 | import { useSafeState } from 'ahooks'; |
8 | +import { MerchantStatus } from '../entity'; | |
9 | +import { delMchDetail } from '../api'; | |
7 | 10 | |
8 | 11 | interface Props { |
9 | 12 | loading?: boolean; |
10 | - dataSource?: IMerchant.MerchantList[]; | |
13 | + dataSource?: IMerchant.OpenMerchantData[]; | |
11 | 14 | searchText?: string; |
12 | 15 | onRefresh?: () => void; |
13 | 16 | } |
14 | 17 | |
15 | 18 | export default function Index({ loading, dataSource = [], searchText, onRefresh }: Props) { |
16 | 19 | const [visible, setVisible] = useSafeState<boolean>(); |
17 | - const [itemRow, setItemRow] = useSafeState<IMerchant.MerchantList>(); | |
20 | + const [itemRow, setItemRow] = useSafeState<IMerchant.OpenMerchantData>(); | |
21 | + const [baseVisible, setBaseVisible] = useSafeState<boolean>(); | |
22 | + const [dealerInfo, setDealerInfo] = useSafeState<IMerchant.OpenMerchantData>(); | |
23 | + | |
24 | + const badgeArr: ('error' | 'default' | 'success')[] = useMemo(() => ['error', 'default', 'success'], []); | |
18 | 25 | |
19 | 26 | const list = useMemo(() => { |
20 | 27 | if (searchText) { |
... | ... | @@ -22,55 +29,94 @@ export default function Index({ loading, dataSource = [], searchText, onRefresh |
22 | 29 | } |
23 | 30 | return dataSource; |
24 | 31 | }, [searchText, dataSource]); |
25 | - const badgeArr: ('error' | 'default' | 'success')[] = useMemo(() => ['error', 'default', 'success'], []); | |
32 | + | |
26 | 33 | //@ts-ignore |
27 | - const columns: ColumnsType<IMerchant.MerchantList> = useMemo( | |
34 | + const columns: ColumnsType<IMerchant.OpenMerchantData> = useMemo( | |
28 | 35 | () => [ |
29 | 36 | { |
30 | - title: '编号', | |
37 | + title: '商家编号', | |
31 | 38 | dataIndex: 'dealerId', |
32 | 39 | key: 'dealerId', |
33 | - width: 62, | |
34 | 40 | }, |
35 | 41 | { |
36 | 42 | title: '商家名称', |
37 | 43 | dataIndex: 'dealerName', |
38 | 44 | key: 'dealerName', |
39 | - width: '35%', | |
40 | 45 | }, |
41 | 46 | { |
42 | - title: '开通状态', | |
43 | - dataIndex: 'status', | |
44 | - key: 'status', | |
45 | - filters: [ | |
46 | - { | |
47 | - text: '草稿', | |
48 | - value: 1, | |
49 | - }, | |
50 | - { | |
51 | - text: '已开通', | |
52 | - value: 2, | |
53 | - }, | |
54 | - ], | |
55 | - onFilter: (value: number, record) => record.status == value, | |
56 | - render: (text, _record) => { | |
57 | - return text ? <Badge status={badgeArr[Number(text)]} text={MerchantStatus[text]} /> : '-'; | |
58 | - }, | |
47 | + title: '已开通数量', | |
48 | + dataIndex: 'openNum', | |
49 | + key: 'openNum', | |
50 | + render: (text, _record) => text ?? '-', | |
59 | 51 | }, |
60 | 52 | { |
53 | + title: '商户总数', | |
54 | + dataIndex: 'total', | |
55 | + key: 'total', | |
56 | + render: (text, _record) => text ?? '-', | |
57 | + }, | |
58 | + { | |
59 | + title: '商家资料', | |
60 | + dataIndex: '', | |
61 | + key: 'action', | |
62 | + render: (_, record) => ( | |
63 | + <> | |
64 | + <a | |
65 | + onClick={() => { | |
66 | + setDealerInfo(record); | |
67 | + setBaseVisible(true); | |
68 | + }} | |
69 | + > | |
70 | + 资料维护 | |
71 | + </a> | |
72 | + {(record?.total ?? -1) >= 0 && <Divider type="vertical" />} | |
73 | + {(record?.total ?? -1) >= 0 && <a onClick={() => showMerchModal({ dealerId: record.dealerId })}>新增子商户</a>} | |
74 | + </> | |
75 | + ), | |
76 | + }, | |
77 | + ], | |
78 | + [], | |
79 | + ); | |
80 | + | |
81 | + function deleteData(id?: number) { | |
82 | + delMchDetail(id) | |
83 | + .then(() => onRefresh?.()) | |
84 | + .catch((e) => message.error(e.message)); | |
85 | + } | |
86 | + | |
87 | + const expandedRowRender = (merchan: IMerchant.OpenMerchantData, _index: number, _indent: number, _expanded: boolean) => { | |
88 | + const c_columns: TableColumnsType<IMerchant.MerchantDetail> = [ | |
89 | + // { | |
90 | + // title: '编号', | |
91 | + // dataIndex: 'id', | |
92 | + // key: 'id', | |
93 | + // width: 50 | |
94 | + // }, | |
95 | + { | |
61 | 96 | title: '平台商户号', |
62 | 97 | dataIndex: 'spMchId', |
63 | 98 | key: 'spMchId', |
99 | + width: 120 | |
100 | + }, | |
101 | + { | |
102 | + title: '子商户号', | |
103 | + dataIndex: 'subMchId', | |
104 | + key: 'subMchId', | |
105 | + width: 120 | |
64 | 106 | }, |
65 | 107 | { |
66 | - title: '子商户简称', | |
108 | + title: '商户简称', | |
67 | 109 | dataIndex: 'mchBriefName', |
68 | 110 | key: 'mchBriefName', |
69 | 111 | }, |
70 | 112 | { |
71 | - title: '子商户号', | |
72 | - dataIndex: 'subMchId', | |
73 | - key: 'subMchId', | |
113 | + title: '状态', | |
114 | + dataIndex: 'status', | |
115 | + key: 'status', | |
116 | + render: (text, _record) => { | |
117 | + return text ? <Badge status={badgeArr[Number(text)]} text={MerchantStatus[text]} /> : '-'; | |
118 | + }, | |
119 | + width: 120 | |
74 | 120 | }, |
75 | 121 | { |
76 | 122 | title: '备注', |
... | ... | @@ -81,34 +127,57 @@ export default function Index({ loading, dataSource = [], searchText, onRefresh |
81 | 127 | title: '操作', |
82 | 128 | dataIndex: '', |
83 | 129 | key: 'action', |
84 | - render: (_, record) => ( | |
130 | + render: (_text, record) => ( | |
85 | 131 | <> |
86 | - {!record?.status && <a onClick={() => showModal(record)}>新增</a>} | |
87 | 132 | {record?.status == MerchantStatus['已开通'] && ( |
88 | - <a style={{ color: 'hsl(102, 53%, 61%)' }} onClick={() => showModal(record)}> | |
133 | + <a style={{ color: 'hsl(102, 53%, 61%)' }} onClick={() => showMerchModal(record)}> | |
89 | 134 | 查看 |
90 | 135 | </a> |
91 | 136 | )} |
92 | 137 | {record?.status == MerchantStatus['草稿'] && ( |
93 | - <a style={{ color: 'rgb(45, 183, 245)' }} onClick={() => showModal(record)}> | |
94 | - 编辑 | |
95 | - </a> | |
138 | + <> | |
139 | + <a style={{ color: 'rgb(45, 183, 245)' }} onClick={() => showMerchModal(record)}> | |
140 | + 编辑 | |
141 | + </a> | |
142 | + <Divider type="vertical" /> | |
143 | + <Popconfirm title="是否删除此项?" onConfirm={() => deleteData(record.id)} okText="确定" cancelText="取消"> | |
144 | + <a style={{ color: 'red' }}>删除</a> | |
145 | + </Popconfirm> | |
146 | + </> | |
96 | 147 | )} |
97 | 148 | </> |
98 | 149 | ), |
99 | 150 | }, |
100 | - ], | |
101 | - [], | |
102 | - ); | |
151 | + ]; | |
152 | + | |
153 | + return <Table rowKey="id" size="small" columns={c_columns} dataSource={merchan?.itemList || []} pagination={false} />; | |
154 | + }; | |
103 | 155 | |
104 | - function showModal(row: IMerchant.MerchantList) { | |
156 | + function showMerchModal(row: IMerchant.MerchantDetail) { | |
105 | 157 | setItemRow(row); |
106 | 158 | setVisible(true); |
107 | 159 | } |
108 | 160 | |
109 | 161 | return ( |
110 | 162 | <> |
111 | - <Table rowKey="dealerId" columns={columns} scroll={{ x: 'max-content' }} bordered loading={loading} dataSource={list} /> | |
163 | + <Table | |
164 | + rowKey="dealerId" | |
165 | + expandable={{ | |
166 | + expandedRowRender, | |
167 | + rowExpandable: (record) => (record?.total ?? 0) > 0, | |
168 | + }} | |
169 | + columns={columns} | |
170 | + bordered | |
171 | + loading={loading} | |
172 | + dataSource={list} | |
173 | + /> | |
174 | + <BaseEditModal | |
175 | + visible={baseVisible} | |
176 | + onCancel={() => setBaseVisible(false)} | |
177 | + onRefresh={onRefresh} | |
178 | + dealerName={dealerInfo?.dealerName} | |
179 | + dealerId={dealerInfo?.dealerId} | |
180 | + /> | |
112 | 181 | <EditModal visible={visible} onCancel={() => setVisible(false)} record={itemRow} onRefresh={onRefresh} /> |
113 | 182 | </> |
114 | 183 | ); | ... | ... |
src/pages/Pay/MerchantList/interface.d.ts
1 | 1 | declare namespace IMerchant { |
2 | - interface MerchantList { | |
3 | - id?: number; | |
2 | + interface OpenMerchantData { | |
4 | 3 | /** 集团id */ |
5 | 4 | groupId?: number; |
6 | 5 | /** 商家id */ |
7 | 6 | dealerId?: number; |
8 | 7 | /** 商家名称 */ |
9 | 8 | dealerName?: string; |
10 | - /** 资料状态 1草稿 2开通 @link MerchantStatus */ | |
11 | - status?: number; | |
12 | - /** 备注 */ | |
13 | - remark?: string; | |
14 | - /** 商户简称 */ | |
15 | - mchBriefName?: string; | |
16 | - /** 开通平台商户id */ | |
17 | - spMchId?: string; | |
18 | - /** 开通子商户id */ | |
19 | - subMchId?: string; | |
9 | + /** 开通数量 */ | |
10 | + openNum?: number; | |
11 | + /** 总商户数 */ | |
12 | + total?: number; | |
13 | + /** 商户信息 */ | |
14 | + itemList?: MerchantDetail[]; | |
20 | 15 | } |
21 | - | |
22 | - interface MerchantDetail { | |
16 | + interface BaseMerchantData { | |
23 | 17 | id?: number; |
24 | 18 | /** 集团id */ |
25 | 19 | groupId?: number; |
... | ... | @@ -31,6 +25,16 @@ declare namespace IMerchant { |
31 | 25 | subjectFid?: string; |
32 | 26 | /** 法人身份证照片(正反面) */ |
33 | 27 | legalCertFids?: string; |
28 | + } | |
29 | + | |
30 | + interface MerchantDetail { | |
31 | + id?: number; | |
32 | + /** 集团id */ | |
33 | + groupId?: number; | |
34 | + /** 商家id */ | |
35 | + dealerId?: number; | |
36 | + /** 商家名称 */ | |
37 | + dealerName?: string; | |
34 | 38 | /** 对公账户 */ |
35 | 39 | publicBankNo?: string; |
36 | 40 | /** 对公账户开户行 */ |
... | ... | @@ -60,16 +64,9 @@ declare namespace IMerchant { |
60 | 64 | /** 开通子商户id */ |
61 | 65 | subMchId?: string; |
62 | 66 | } |
63 | - | |
64 | 67 | interface MerchantFromState { |
65 | 68 | /** 商家名称 */ |
66 | 69 | dealerName?: string; |
67 | - /** 公司营业执照 */ | |
68 | - subjectFid?: FileInfo[]; | |
69 | - /** 法人身份证照片(正面) */ | |
70 | - legalCertFront?: FileInfo[]; | |
71 | - /** 法人身份证照片(反面) */ | |
72 | - legalCertBack?: FileInfo[]; | |
73 | 70 | /** 对公账户 */ |
74 | 71 | publicBankNo?: string; |
75 | 72 | /** 对公账户开户行 */ | ... | ... |
src/pages/Pay/OpenMerchantList/api.ts
1 | 1 | import request from '@/utils/request'; |
2 | 2 | import { PAYMENT } from '@/utils/host'; |
3 | 3 | |
4 | + | |
5 | +/** 查询商家的商户列表 */ | |
6 | +export async function queryMchListData(groupId?: number, dealerId?: number): Promise<IMerchant.MerchantDetail[]> { | |
7 | + const res = await request.get<IMerchant.MerchantDetail[]>(`${PAYMENT}/mch/data/item/list`, { params: { dealerId, groupId } }); | |
8 | + return res.data || []; | |
9 | +} | |
10 | + | |
4 | 11 | export interface Params { |
5 | 12 | id?: number; |
6 | 13 | open?: boolean; |
... | ... | @@ -10,7 +17,7 @@ export interface Params { |
10 | 17 | } |
11 | 18 | |
12 | 19 | export function openMch(params: Params) { |
13 | - return request.post(`${PAYMENT}/mch/data/open`, params); | |
20 | + return request.post(`${PAYMENT}/mch/data/item/open`, params); | |
14 | 21 | } |
15 | 22 | |
16 | 23 | interface MchPlfVO { | ... | ... |
src/pages/Pay/OpenMerchantList/components/BasePreViewModal.tsx
0 → 100644
1 | +import { PlusOutlined } from '@ant-design/icons'; | |
2 | +import type { UploadProps } from 'antd'; | |
3 | +import { Modal, Form, Upload, Input, message, Skeleton } from 'antd'; | |
4 | +import React, { useEffect } from 'react'; | |
5 | +import { useRequest } from 'ahooks'; | |
6 | +import { queryMchBaseData } from '@/pages/Pay/MerchantList/api'; | |
7 | + | |
8 | +interface BaseMerchantFormData { | |
9 | + dealerName?: string; | |
10 | + /** 公司营业执照 */ | |
11 | + subjectFid?: IMerchant.FileInfo[]; | |
12 | + /** 法人身份证照片(正面) */ | |
13 | + legalCertFront?: IMerchant.FileInfo[]; | |
14 | + /** 法人身份证照片(反面) */ | |
15 | + legalCertBack?: IMerchant.FileInfo[]; | |
16 | +} | |
17 | + | |
18 | +interface ModalProps { | |
19 | + visible?: boolean; | |
20 | + dealerId?: number; | |
21 | + dealerName?: string; | |
22 | + onCancel?: () => void; | |
23 | +} | |
24 | +export default function EditModal({ visible, dealerId = -1, dealerName, onCancel }: ModalProps) { | |
25 | + const [form] = Form.useForm(); | |
26 | + | |
27 | + const { run, loading } = useRequest(queryMchBaseData, { | |
28 | + manual: true, | |
29 | + onSuccess: (detail, _params) => loadFromState(detail), | |
30 | + onError: (e, _params) => { | |
31 | + message.error(e.message); | |
32 | + }, | |
33 | + }); | |
34 | + | |
35 | + const uploadProps: UploadProps = { | |
36 | + action: 'api2/file/upload', | |
37 | + accept: 'image/*', | |
38 | + maxCount: 1, | |
39 | + listType: 'picture-card', | |
40 | + beforeUpload(file) { | |
41 | + const isLt2M = file.size / 1024 / 1024 < 2; | |
42 | + if (!isLt2M) { | |
43 | + message.error('图片大小不能超过 2MB!'); | |
44 | + return Upload.LIST_IGNORE; | |
45 | + } | |
46 | + return true; | |
47 | + }, | |
48 | + }; | |
49 | + | |
50 | + useEffect(() => { | |
51 | + if (visible) { | |
52 | + run(dealerId); | |
53 | + } | |
54 | + }, [visible]); | |
55 | + | |
56 | + function loadFromState(detail: IMerchant.BaseMerchantData) { | |
57 | + const commomFileProps: IMerchant.FileInfo = { | |
58 | + lastModified: Date.now(), | |
59 | + lastModifiedDate: new Date(), | |
60 | + name: '', | |
61 | + percent: 100, | |
62 | + status: 'done', | |
63 | + response: { data: '' }, | |
64 | + uid: '-1', | |
65 | + thumbUrl: '', | |
66 | + url: '', | |
67 | + }; | |
68 | + const fromState: BaseMerchantFormData = {}; | |
69 | + fromState.dealerName = detail?.dealerName ?? dealerName; | |
70 | + if (detail?.subjectFid) { | |
71 | + fromState.subjectFid = [ | |
72 | + { | |
73 | + ...commomFileProps, | |
74 | + response: { data: detail?.subjectFid }, | |
75 | + uid: detail.subjectFid ?? Date.now().toString(), | |
76 | + thumbUrl: `api/file/show?fid=${detail?.subjectFid}`, | |
77 | + url: `api/file/show?fid=${detail?.subjectFid}`, | |
78 | + }, | |
79 | + ]; | |
80 | + } | |
81 | + const certFidArr = detail?.legalCertFids?.split(','); | |
82 | + if (certFidArr?.[0]) { | |
83 | + fromState.legalCertFront = [ | |
84 | + { | |
85 | + ...commomFileProps, | |
86 | + response: { data: certFidArr?.[0] }, | |
87 | + uid: certFidArr?.[0] ?? Date.now().toString(), | |
88 | + thumbUrl: `api/file/show?fid=${certFidArr?.[0]}`, | |
89 | + url: `api/file/show?fid=${certFidArr?.[0]}`, | |
90 | + }, | |
91 | + ]; | |
92 | + } | |
93 | + if (certFidArr?.[1]) { | |
94 | + fromState.legalCertBack = [ | |
95 | + { | |
96 | + ...commomFileProps, | |
97 | + response: { data: certFidArr?.[1] }, | |
98 | + uid: certFidArr?.[1] ?? Date.now().toString(), | |
99 | + thumbUrl: `api/file/show?fid=${certFidArr?.[1]}`, | |
100 | + url: `api/file/show?fid=${certFidArr?.[1]}`, | |
101 | + }, | |
102 | + ]; | |
103 | + } | |
104 | + form.setFieldsValue(fromState); | |
105 | + } | |
106 | + | |
107 | + const normFile = (e: any) => { | |
108 | + if (Array.isArray(e)) { | |
109 | + return e; | |
110 | + } | |
111 | + return e?.fileList; | |
112 | + }; | |
113 | + | |
114 | + return ( | |
115 | + <Modal title="资料维护" width="65%" open={visible} onCancel={onCancel} onOk={onCancel} afterClose={() => form.resetFields()}> | |
116 | + <Skeleton loading={loading} active={loading} paragraph={{ rows: 16 }}> | |
117 | + <Form form={form} labelWrap labelCol={{ span: 6 }} disabled={true}> | |
118 | + <Form.Item label="商家" name="dealerName"> | |
119 | + <Input disabled style={{ maxWidth: 350 }} /> | |
120 | + </Form.Item> | |
121 | + | |
122 | + <Form.Item noStyle shouldUpdate={(prevValues, curValues) => prevValues.subjectFid != curValues.subjectFid}> | |
123 | + {({ getFieldValue }) => { | |
124 | + const subjectFidLength = getFieldValue('subjectFid')?.length ?? 0; | |
125 | + return ( | |
126 | + <Form.Item | |
127 | + label="公司营业执照" | |
128 | + name="subjectFid" | |
129 | + valuePropName="fileList" | |
130 | + getValueFromEvent={normFile} | |
131 | + rules={[{ required: true, message: '营业执照照片不能为空' }]} | |
132 | + extra={<p style={{ margin: 0, fontSize: 12 }}>营业执照正面清晰完整照片且不超过2M大小的JPG、BMP、PNG照片</p>} | |
133 | + > | |
134 | + <Upload {...uploadProps}> | |
135 | + {subjectFidLength >= 1 ? null : ( | |
136 | + <button style={{ border: 0, background: 'none' }} type="button"> | |
137 | + <PlusOutlined rev="" /> | |
138 | + <div style={{ marginTop: 8 }}>上传</div> | |
139 | + </button> | |
140 | + )} | |
141 | + </Upload> | |
142 | + </Form.Item> | |
143 | + ); | |
144 | + }} | |
145 | + </Form.Item> | |
146 | + <Form.Item noStyle shouldUpdate={(prevValues, curValues) => prevValues.legalCertFront != curValues.legalCertFront}> | |
147 | + {({ getFieldValue }) => { | |
148 | + const fileLength = getFieldValue('legalCertFront')?.length ?? 0; | |
149 | + return ( | |
150 | + <Form.Item | |
151 | + label="法人身份证人像面照片" | |
152 | + name="legalCertFront" | |
153 | + valuePropName="fileList" | |
154 | + getValueFromEvent={normFile} | |
155 | + rules={[{ required: true, message: '身份证照片不能为空' }]} | |
156 | + extra={<p style={{ margin: 0, fontSize: 12 }}>身份证人像面清晰完整照片且不超过2M大小的JPG、BMP、PNG格式照片</p>} | |
157 | + > | |
158 | + <Upload {...uploadProps}> | |
159 | + {fileLength >= 1 ? null : ( | |
160 | + <button style={{ border: 0, background: 'none' }} type="button"> | |
161 | + <PlusOutlined rev="" /> | |
162 | + <div style={{ marginTop: 8 }}>上传</div> | |
163 | + </button> | |
164 | + )} | |
165 | + </Upload> | |
166 | + </Form.Item> | |
167 | + ); | |
168 | + }} | |
169 | + </Form.Item> | |
170 | + <Form.Item noStyle shouldUpdate={(prevValues, curValues) => prevValues.legalCertBack != curValues.legalCertBack}> | |
171 | + {({ getFieldValue }) => { | |
172 | + const legalCertBackLength = getFieldValue('legalCertBack')?.length ?? 0; | |
173 | + return ( | |
174 | + <Form.Item | |
175 | + label="法人身份证国徽面照片" | |
176 | + name="legalCertBack" | |
177 | + valuePropName="fileList" | |
178 | + getValueFromEvent={normFile} | |
179 | + rules={[{ required: true, message: '身份证照片不能为空' }]} | |
180 | + extra={<p style={{ margin: 0, fontSize: 12 }}>身份证国徽面清晰完整照片且不超过2M大小的JPG、BMP、PNG格式照片</p>} | |
181 | + > | |
182 | + <Upload {...uploadProps}> | |
183 | + {legalCertBackLength >= 1 ? null : ( | |
184 | + <button style={{ border: 0, background: 'none' }} type="button"> | |
185 | + <PlusOutlined rev="" /> | |
186 | + <div style={{ marginTop: 8 }}>上传</div> | |
187 | + </button> | |
188 | + )} | |
189 | + </Upload> | |
190 | + </Form.Item> | |
191 | + ); | |
192 | + }} | |
193 | + </Form.Item> | |
194 | + </Form> | |
195 | + </Skeleton> | |
196 | + </Modal> | |
197 | + ); | |
198 | +} | ... | ... |
src/pages/Pay/OpenMerchantList/components/List.tsx
1 | +import type { TableColumnsType } from 'antd'; | |
1 | 2 | import { Badge, Table } from 'antd'; |
2 | 3 | import type { ColumnsType } from 'antd/lib/table'; |
3 | 4 | import React, { useMemo } from 'react'; |
4 | 5 | import { MerchantStatus } from '@/pages/Pay/MerchantList/entity'; |
5 | 6 | import PreViewModal from './PreViewModal'; |
7 | +import BasePreViewModal from './BasePreViewModal'; | |
6 | 8 | import { useSafeState } from 'ahooks'; |
7 | 9 | import OpenModal from './OpenModal'; |
8 | 10 | |
9 | 11 | interface Props { |
10 | 12 | loading?: boolean; |
11 | - dataSource?: IMerchant.MerchantList[]; | |
13 | + dataSource?: IMerchant.OpenMerchantData[]; | |
12 | 14 | searchText?: string; |
13 | 15 | onRefresh?: () => void; |
14 | 16 | } |
... | ... | @@ -16,7 +18,10 @@ interface Props { |
16 | 18 | export default function Index({ loading, dataSource = [], searchText, onRefresh }: Props) { |
17 | 19 | const [visible, setVisible] = useSafeState<boolean>(); |
18 | 20 | const [visibleOpen, setVisibleOpen] = useSafeState<boolean>(); |
19 | - const [itemRow, setItemRow] = useSafeState<IMerchant.MerchantList>(); | |
21 | + const [itemRow, setItemRow] = useSafeState<IMerchant.OpenMerchantData>(); | |
22 | + | |
23 | + const [baseVisible, setBaseVisible] = useSafeState<boolean>(); | |
24 | + const [dealerInfo, setDealerInfo] = useSafeState<IMerchant.OpenMerchantData>(); | |
20 | 25 | |
21 | 26 | const list = useMemo(() => { |
22 | 27 | if (searchText) { |
... | ... | @@ -25,54 +30,85 @@ export default function Index({ loading, dataSource = [], searchText, onRefresh |
25 | 30 | return dataSource; |
26 | 31 | }, [searchText, dataSource]); |
27 | 32 | const badgeArr: ('error' | 'default' | 'success')[] = useMemo(() => ['error', 'default', 'success'], []); |
28 | - //@ts-ignore | |
29 | - const columns: ColumnsType<IMerchant.MerchantList> = useMemo( | |
33 | + | |
34 | + const columns: ColumnsType<IMerchant.OpenMerchantData> = useMemo( | |
30 | 35 | () => [ |
31 | 36 | { |
32 | - title: '编号', | |
37 | + title: '商家编号', | |
33 | 38 | dataIndex: 'dealerId', |
34 | 39 | key: 'dealerId', |
35 | - width: 62, | |
36 | 40 | }, |
37 | 41 | { |
38 | 42 | title: '商家名称', |
39 | 43 | dataIndex: 'dealerName', |
40 | 44 | key: 'dealerName', |
41 | - width: '35%', | |
42 | 45 | }, |
43 | 46 | { |
44 | - title: '开通状态', | |
45 | - dataIndex: 'status', | |
46 | - key: 'status', | |
47 | - filters: [ | |
48 | - { | |
49 | - text: '草稿', | |
50 | - value: 1, | |
51 | - }, | |
52 | - { | |
53 | - text: '已开通', | |
54 | - value: 2, | |
55 | - }, | |
56 | - ], | |
57 | - onFilter: (value: number, record) => record.status == value, | |
58 | - render: (text, _record) => { | |
59 | - return text ? <Badge status={badgeArr[Number(text)]} text={MerchantStatus[text]} /> : '-'; | |
60 | - }, | |
47 | + title: '已开通数量', | |
48 | + dataIndex: 'openNum', | |
49 | + key: 'openNum', | |
50 | + render: (text, _record) => text ?? '-', | |
51 | + }, | |
52 | + { | |
53 | + title: '商户总数', | |
54 | + dataIndex: 'total', | |
55 | + key: 'total', | |
56 | + render: (text, _record) => text ?? '-', | |
57 | + }, | |
58 | + { | |
59 | + title: '商家资料', | |
60 | + dataIndex: '', | |
61 | + key: 'action', | |
62 | + render: (_, record) => ( | |
63 | + <> | |
64 | + <a | |
65 | + onClick={() => { | |
66 | + setDealerInfo(record); | |
67 | + setBaseVisible(true); | |
68 | + }} | |
69 | + > | |
70 | + 查看资料 | |
71 | + </a> | |
72 | + </> | |
73 | + ), | |
61 | 74 | }, |
75 | + ], | |
76 | + [], | |
77 | + ); | |
78 | + | |
79 | + const expandedRowRender = (merchan: IMerchant.OpenMerchantData, _index: number, _indent: number, _expanded: boolean) => { | |
80 | + const c_columns: TableColumnsType<IMerchant.MerchantDetail> = [ | |
81 | + // { | |
82 | + // title: '编号', | |
83 | + // dataIndex: 'id', | |
84 | + // key: 'id', | |
85 | + // width: 50, | |
86 | + // }, | |
62 | 87 | { |
63 | 88 | title: '平台商户号', |
64 | 89 | dataIndex: 'spMchId', |
65 | 90 | key: 'spMchId', |
91 | + width: 120, | |
66 | 92 | }, |
67 | 93 | { |
68 | - title: '子商户简称', | |
94 | + title: '子商户号', | |
95 | + dataIndex: 'subMchId', | |
96 | + key: 'subMchId', | |
97 | + width: 120, | |
98 | + }, | |
99 | + { | |
100 | + title: '商户简称', | |
69 | 101 | dataIndex: 'mchBriefName', |
70 | 102 | key: 'mchBriefName', |
71 | 103 | }, |
72 | 104 | { |
73 | - title: '子商户号', | |
74 | - dataIndex: 'subMchId', | |
75 | - key: 'subMchId', | |
105 | + title: '状态', | |
106 | + dataIndex: 'status', | |
107 | + key: 'status', | |
108 | + render: (text, _record) => { | |
109 | + return text ? <Badge status={badgeArr[Number(text)]} text={MerchantStatus[text]} /> : '-'; | |
110 | + }, | |
111 | + width: 120, | |
76 | 112 | }, |
77 | 113 | { |
78 | 114 | title: '备注', |
... | ... | @@ -83,7 +119,7 @@ export default function Index({ loading, dataSource = [], searchText, onRefresh |
83 | 119 | title: '操作', |
84 | 120 | dataIndex: '', |
85 | 121 | key: 'action', |
86 | - render: (_, record) => ( | |
122 | + render: (_text, record) => ( | |
87 | 123 | <> |
88 | 124 | {(record?.status == MerchantStatus['已开通'] || record?.status == MerchantStatus['草稿']) && ( |
89 | 125 | <a |
... | ... | @@ -99,7 +135,7 @@ export default function Index({ loading, dataSource = [], searchText, onRefresh |
99 | 135 | <a |
100 | 136 | style={{ color: 'rgb(45, 183, 245)', marginLeft: 15 }} |
101 | 137 | onClick={() => { |
102 | - setItemRow(record); | |
138 | + setItemRow({ ...record, dealerName: merchan?.dealerName }); | |
103 | 139 | setVisibleOpen(true); |
104 | 140 | }} |
105 | 141 | > |
... | ... | @@ -109,13 +145,30 @@ export default function Index({ loading, dataSource = [], searchText, onRefresh |
109 | 145 | </> |
110 | 146 | ), |
111 | 147 | }, |
112 | - ], | |
113 | - [], | |
114 | - ); | |
148 | + ]; | |
149 | + | |
150 | + return <Table rowKey="id" size="small" columns={c_columns} dataSource={merchan?.itemList || []} pagination={false} />; | |
151 | + }; | |
115 | 152 | |
116 | 153 | return ( |
117 | 154 | <> |
118 | - <Table rowKey="dealerId" columns={columns} scroll={{ x: 'max-content' }} bordered loading={loading} dataSource={list} /> | |
155 | + <Table | |
156 | + rowKey="dealerId" | |
157 | + expandable={{ | |
158 | + expandedRowRender, | |
159 | + rowExpandable: (record) => (record?.total ?? 0) > 0, | |
160 | + }} | |
161 | + columns={columns} | |
162 | + bordered | |
163 | + loading={loading} | |
164 | + dataSource={list} | |
165 | + /> | |
166 | + <BasePreViewModal | |
167 | + visible={baseVisible} | |
168 | + onCancel={() => setBaseVisible(false)} | |
169 | + dealerName={dealerInfo?.dealerName} | |
170 | + dealerId={dealerInfo?.dealerId} | |
171 | + /> | |
119 | 172 | <PreViewModal visible={visible} onCancel={() => setVisible(false)} record={itemRow} /> |
120 | 173 | <OpenModal |
121 | 174 | visible={visibleOpen} | ... | ... |
src/pages/Pay/OpenMerchantList/components/OpenModal.tsx
... | ... | @@ -6,7 +6,7 @@ import { openMch, openMchPlf } from '../api'; |
6 | 6 | |
7 | 7 | interface ModalProps { |
8 | 8 | visible?: boolean; |
9 | - record?: IMerchant.MerchantList; | |
9 | + record?: IMerchant.MerchantDetail; | |
10 | 10 | onCancel?: () => void; |
11 | 11 | onRefresh?: () => void; |
12 | 12 | } |
... | ... | @@ -30,8 +30,8 @@ export default function OpenModal({ visible, record, onCancel, onRefresh }: Moda |
30 | 30 | }); |
31 | 31 | |
32 | 32 | useEffect(() => { |
33 | - if (visible && record?.dealerName) { | |
34 | - form.setFieldsValue({ dealerName: record?.dealerName }); | |
33 | + if (visible) { | |
34 | + form.setFieldsValue({ dealerName: record?.dealerName, mchBriefName: record?.mchBriefName }); | |
35 | 35 | } |
36 | 36 | }, [visible]); |
37 | 37 | |
... | ... | @@ -42,7 +42,7 @@ export default function OpenModal({ visible, record, onCancel, onRefresh }: Moda |
42 | 42 | } |
43 | 43 | saveData.open = !!feildValue?.open; |
44 | 44 | saveData.remark = feildValue?.remark; |
45 | - saveData.spMchId = feildValue?.spMchId; | |
45 | + saveData.spMchId = feildValue?.spMchId?.trim?.(); | |
46 | 46 | saveData.subMchId = feildValue?.subMchId?.trim?.(); |
47 | 47 | run(saveData); |
48 | 48 | } |
... | ... | @@ -61,6 +61,9 @@ export default function OpenModal({ visible, record, onCancel, onRefresh }: Moda |
61 | 61 | <Form.Item label="商家" name="dealerName"> |
62 | 62 | <Input disabled style={{ maxWidth: 350 }} /> |
63 | 63 | </Form.Item> |
64 | + <Form.Item label="商户简称" name="mchBriefName"> | |
65 | + <Input disabled style={{ maxWidth: 350 }} /> | |
66 | + </Form.Item> | |
64 | 67 | <Form.Item name="open" label="是否开户" valuePropName="checked"> |
65 | 68 | <Switch /> |
66 | 69 | </Form.Item> | ... | ... |
src/pages/Pay/OpenMerchantList/components/PreViewModal.tsx
1 | 1 | import { PlusOutlined } from '@ant-design/icons'; |
2 | 2 | import type { UploadProps } from 'antd'; |
3 | -import { Modal, Form, Upload, Input, Checkbox, message, Skeleton } from 'antd'; | |
3 | +import { Modal, Form, Upload, Input, Checkbox, message } from 'antd'; | |
4 | 4 | import React, { useEffect } from 'react'; |
5 | -import { useRequest } from 'ahooks'; | |
6 | -import { queryMchDetail } from '@/pages/Pay/MerchantList/api'; | |
7 | 5 | |
8 | 6 | interface ModalProps { |
9 | 7 | visible?: boolean; |
10 | - record?: IMerchant.MerchantList; | |
8 | + record?: IMerchant.MerchantDetail; | |
11 | 9 | onCancel?: () => void; |
12 | 10 | onRefresh?: () => void; |
13 | 11 | } |
14 | 12 | export default function PreViewModal({ visible, record, onCancel }: ModalProps) { |
15 | 13 | const [form] = Form.useForm(); |
16 | - const { run, loading } = useRequest(queryMchDetail, { | |
17 | - manual: true, | |
18 | - onSuccess: (detail, _params) => loadFromState(detail), | |
19 | - onError: (e, _params) => { | |
20 | - message.error(e.message); | |
21 | - }, | |
22 | - }); | |
23 | 14 | |
24 | 15 | const uploadProps: UploadProps = { |
25 | 16 | action: 'api2/file/upload', |
... | ... | @@ -39,7 +30,7 @@ export default function PreViewModal({ visible, record, onCancel }: ModalProps) |
39 | 30 | useEffect(() => { |
40 | 31 | if (visible) { |
41 | 32 | if (record?.status && record?.dealerId) { |
42 | - run(record.dealerId); | |
33 | + loadFromState(record); | |
43 | 34 | } else { |
44 | 35 | const fromState: IMerchant.MerchantFromState = {}; |
45 | 36 | fromState.dealerName = record?.dealerName; |
... | ... | @@ -63,40 +54,6 @@ export default function PreViewModal({ visible, record, onCancel }: ModalProps) |
63 | 54 | }; |
64 | 55 | const fromState: IMerchant.MerchantFromState = {}; |
65 | 56 | fromState.dealerName = detail?.dealerName; |
66 | - if (detail?.subjectFid) { | |
67 | - fromState.subjectFid = [ | |
68 | - { | |
69 | - ...commomFileProps, | |
70 | - response: { data: detail?.subjectFid }, | |
71 | - uid: detail.subjectFid ?? Date.now().toString(), | |
72 | - thumbUrl: `api/file/show?fid=${detail?.subjectFid}`, | |
73 | - url: `api/file/show?fid=${detail?.subjectFid}`, | |
74 | - }, | |
75 | - ]; | |
76 | - } | |
77 | - const certFidArr = detail?.legalCertFids?.split(','); | |
78 | - if (certFidArr?.[0]) { | |
79 | - fromState.legalCertFront = [ | |
80 | - { | |
81 | - ...commomFileProps, | |
82 | - response: { data: certFidArr?.[0] }, | |
83 | - uid: certFidArr?.[0] ?? Date.now().toString(), | |
84 | - thumbUrl: `api/file/show?fid=${certFidArr?.[0]}`, | |
85 | - url: `api/file/show?fid=${certFidArr?.[0]}`, | |
86 | - }, | |
87 | - ]; | |
88 | - } | |
89 | - if (certFidArr?.[1]) { | |
90 | - fromState.legalCertBack = [ | |
91 | - { | |
92 | - ...commomFileProps, | |
93 | - response: { data: certFidArr?.[1] }, | |
94 | - uid: certFidArr?.[1] ?? Date.now().toString(), | |
95 | - thumbUrl: `api/file/show?fid=${certFidArr?.[1]}`, | |
96 | - url: `api/file/show?fid=${certFidArr?.[1]}`, | |
97 | - }, | |
98 | - ]; | |
99 | - } | |
100 | 57 | fromState.publicBankNo = detail?.publicBankNo; |
101 | 58 | fromState.publicBankName = detail?.publicBankName; |
102 | 59 | fromState.publicBankOrg = detail?.publicBankOrg; |
... | ... | @@ -147,82 +104,7 @@ export default function PreViewModal({ visible, record, onCancel }: ModalProps) |
147 | 104 | |
148 | 105 | return ( |
149 | 106 | <Modal title={'查看'} width="65%" open={visible} onCancel={onCancel} onOk={form.submit} afterClose={() => form.resetFields()}> |
150 | - <Skeleton loading={loading} active={loading} paragraph={{ rows: 16 }}> | |
151 | 107 | <Form form={form} onFinish={() => onCancel?.()} labelWrap labelCol={{ span: 6 }} disabled> |
152 | - <Form.Item label="商家" name="dealerName"> | |
153 | - <Input disabled style={{ maxWidth: 350 }} /> | |
154 | - </Form.Item> | |
155 | - | |
156 | - <Form.Item noStyle shouldUpdate={(prevValues, curValues) => prevValues.subjectFid != curValues.subjectFid}> | |
157 | - {({ getFieldValue }) => { | |
158 | - const subjectFidLength = getFieldValue('subjectFid')?.length ?? 0; | |
159 | - return ( | |
160 | - <Form.Item | |
161 | - label="公司营业执照" | |
162 | - name="subjectFid" | |
163 | - valuePropName="fileList" | |
164 | - getValueFromEvent={normFile} | |
165 | - rules={[{ required: true, message: '营业执照照片不能为空' }]} | |
166 | - > | |
167 | - <Upload {...uploadProps}> | |
168 | - {subjectFidLength >= 1 ? null : ( | |
169 | - <button style={{ border: 0, background: 'none' }} type="button"> | |
170 | - <PlusOutlined rev="" /> | |
171 | - <div style={{ marginTop: 8 }}>上传</div> | |
172 | - </button> | |
173 | - )} | |
174 | - </Upload> | |
175 | - </Form.Item> | |
176 | - ); | |
177 | - }} | |
178 | - </Form.Item> | |
179 | - <Form.Item noStyle shouldUpdate={(prevValues, curValues) => prevValues.legalCertFront != curValues.legalCertFront}> | |
180 | - {({ getFieldValue }) => { | |
181 | - const fileLength = getFieldValue('legalCertFront')?.length ?? 0; | |
182 | - return ( | |
183 | - <Form.Item | |
184 | - label="法人身份证人像面照片" | |
185 | - name="legalCertFront" | |
186 | - valuePropName="fileList" | |
187 | - getValueFromEvent={normFile} | |
188 | - rules={[{ required: true, message: '身份证照片不能为空' }]} | |
189 | - > | |
190 | - <Upload {...uploadProps}> | |
191 | - {fileLength >= 1 ? null : ( | |
192 | - <button style={{ border: 0, background: 'none' }} type="button"> | |
193 | - <PlusOutlined rev="" /> | |
194 | - <div style={{ marginTop: 8 }}>上传</div> | |
195 | - </button> | |
196 | - )} | |
197 | - </Upload> | |
198 | - </Form.Item> | |
199 | - ); | |
200 | - }} | |
201 | - </Form.Item> | |
202 | - <Form.Item noStyle shouldUpdate={(prevValues, curValues) => prevValues.legalCertBack != curValues.legalCertBack}> | |
203 | - {({ getFieldValue }) => { | |
204 | - const legalCertBackLength = getFieldValue('legalCertBack')?.length ?? 0; | |
205 | - return ( | |
206 | - <Form.Item | |
207 | - label="法人身份证国徽面照片" | |
208 | - name="legalCertBack" | |
209 | - valuePropName="fileList" | |
210 | - getValueFromEvent={normFile} | |
211 | - rules={[{ required: true, message: '身份证照片不能为空' }]} | |
212 | - > | |
213 | - <Upload {...uploadProps}> | |
214 | - {legalCertBackLength >= 1 ? null : ( | |
215 | - <button style={{ border: 0, background: 'none' }} type="button"> | |
216 | - <PlusOutlined rev="" /> | |
217 | - <div style={{ marginTop: 8 }}>上传</div> | |
218 | - </button> | |
219 | - )} | |
220 | - </Upload> | |
221 | - </Form.Item> | |
222 | - ); | |
223 | - }} | |
224 | - </Form.Item> | |
225 | - | |
226 | 108 | <Form.Item label="对公账户" name="publicBankNo" rules={[{ required: true, message: '对公账户不能为空' }]}> |
227 | 109 | <Input placeholder="请输入" type="number" style={{ maxWidth: 350 }} /> |
228 | 110 | </Form.Item> |
... | ... | @@ -335,7 +217,6 @@ export default function PreViewModal({ visible, record, onCancel }: ModalProps) |
335 | 217 | <Input placeholder="请输入" type="email" maxLength={128} style={{ maxWidth: 350 }} /> |
336 | 218 | </Form.Item> |
337 | 219 | </Form> |
338 | - </Skeleton> | |
339 | 220 | </Modal> |
340 | 221 | ); |
341 | 222 | } | ... | ... |