Commit 8bd54c91b7a06b98e203e822c3059ffc5e9cf4ec
1 parent
6e8bd92c
feat(carinsur): 新增贷款期客户保险配置功能
Showing
7 changed files
with
443 additions
and
0 deletions
src/pages/carinsur/LoanClientRequires/api.ts
0 → 100644
1 | +import type { http } from '@/typing/http'; | |
2 | +import request from '@/utils/request'; | |
3 | +import type { IdNameOption, ShopOption } from '../entity'; | |
4 | +import { ANGEL_Host } from '@/utils/host'; | |
5 | +import type { Pagination } from '@/typing/common'; | |
6 | + | |
7 | +export interface InsuranceItem { | |
8 | + type: number; | |
9 | + amount: number; | |
10 | +} | |
11 | +export interface brandSeriesItem { | |
12 | + id: number; | |
13 | + name: string; | |
14 | + series: IdNameOption[]; | |
15 | +} | |
16 | +export interface Item { | |
17 | + id?: number; | |
18 | + allBrandSeries: boolean; | |
19 | + brandSeries: brandSeriesItem[]; | |
20 | + useShopIds: ShopOption[]; | |
21 | + newTci: InsuranceItem; | |
22 | + newVci: InsuranceItem; | |
23 | + newTai: InsuranceItem; | |
24 | + reNewTci: InsuranceItem; | |
25 | + reNewVci: InsuranceItem; | |
26 | + reNewTai: InsuranceItem; | |
27 | +} | |
28 | + | |
29 | +export interface PageParams extends Pagination { | |
30 | + shopId?: number; | |
31 | + brandId?: number; | |
32 | + seriesId?: number; | |
33 | +} | |
34 | + | |
35 | +/** | |
36 | + * 分页查询 | |
37 | + */ | |
38 | +export function getLCRPage(params?: PageParams): http.PromisePageResp<Item> { | |
39 | + return request.get(`${ANGEL_Host}/erp/express/logistics/article/page`, { params }); | |
40 | +} | |
41 | + | |
42 | +/** | |
43 | + * 新增/编辑 | |
44 | + */ | |
45 | +export function addLCR(params?: Item): http.PromiseResp<void> { | |
46 | + return request.post(`${ANGEL_Host}/erp/express/logistics/article/save`, { ...params }); | |
47 | +} | |
48 | + | |
49 | +/** | |
50 | + * 删除 | |
51 | + */ | |
52 | +export function delLCR(id: number): http.PromisePageResp<void> { | |
53 | + return request.post(`${ANGEL_Host}/erp/express/logistics/article/delete`, { id }); | |
54 | +} | ... | ... |
src/pages/carinsur/LoanClientRequires/components/AddModal/index.tsx
0 → 100644
1 | +import React, { useEffect, memo } from 'react'; | |
2 | +import { Modal, Form, message, Radio } from 'antd'; | |
3 | +import * as API from '../../api'; | |
4 | +import { useRequest } from 'umi'; | |
5 | + | |
6 | +interface Props { | |
7 | + visible: boolean; | |
8 | + row?: API.Item; | |
9 | + onCancel: () => void; | |
10 | + onRefresh: () => void; | |
11 | +} | |
12 | + | |
13 | +function AddModal({ visible, row, onCancel, onRefresh }: Props) { | |
14 | + const { id } = row ?? {}; | |
15 | + const [form] = Form.useForm(); | |
16 | + | |
17 | + const saveHook = useRequest(API.addLCR, { | |
18 | + manual: true, | |
19 | + formatResult: (res) => res, | |
20 | + }); | |
21 | + | |
22 | + useEffect(() => { | |
23 | + if (visible && row) { | |
24 | + form.setFieldsValue({ | |
25 | + ...row, | |
26 | + }); | |
27 | + } else { | |
28 | + form.resetFields(); | |
29 | + } | |
30 | + }, [visible, row]); | |
31 | + | |
32 | + const handleSave = (feildValue: any) => { | |
33 | + saveHook | |
34 | + .run({ | |
35 | + ...feildValue, | |
36 | + }) | |
37 | + .then((res) => { | |
38 | + message.success(res.result); | |
39 | + onCancel(); | |
40 | + onRefresh(); | |
41 | + }) | |
42 | + .catch((e) => { | |
43 | + message.error(e.message); | |
44 | + }); | |
45 | + }; | |
46 | + | |
47 | + return ( | |
48 | + <Modal title={`${id ? '编辑' : '新增'}`} open={visible} confirmLoading={saveHook.loading} onCancel={onCancel} onOk={form.submit} width="50%"> | |
49 | + <Form form={form} onFinish={handleSave} labelCol={{ span: 4 }} wrapperCol={{ span: 18 }}> | |
50 | + <Form.Item name="id" hidden /> | |
51 | + <Form.Item label="适用品牌车系" name="allBrandSeries" rules={[{ required: true, message: '请选择' }]}> | |
52 | + <Radio.Group> | |
53 | + <Radio value={true}>全部品牌全部车系</Radio> | |
54 | + <Radio value={false}>部分品牌部分车系</Radio> | |
55 | + </Radio.Group> | |
56 | + </Form.Item> | |
57 | + <Form.Item | |
58 | + noStyle | |
59 | + shouldUpdate={(prev, curr) => { | |
60 | + return prev.allBrandSeries !== curr.allBrandSeries; | |
61 | + }} | |
62 | + > | |
63 | + {({ getFieldValue }) => { | |
64 | + const allBrandSeries = getFieldValue('allBrandSeries'); | |
65 | + if (allBrandSeries) { | |
66 | + return null; | |
67 | + } | |
68 | + return null; // todo | |
69 | + }} | |
70 | + </Form.Item> | |
71 | + </Form> | |
72 | + </Modal> | |
73 | + ); | |
74 | +} | |
75 | + | |
76 | +export default memo(AddModal); | ... | ... |
src/pages/carinsur/LoanClientRequires/components/BrandSelectorByAll.tsx
0 → 100644
1 | +import React, { useEffect, useState } from 'react'; | |
2 | +import { Select, Spin } from 'antd'; | |
3 | +import type { LabelInValueType } from 'rc-select/lib/Select'; | |
4 | +import { getAllBrandApi } from '@/common/api'; | |
5 | +import useInitial from '@/hooks/useInitail'; | |
6 | + | |
7 | +interface Props { | |
8 | + value?: LabelInValueType[]; | |
9 | + onChange?: (value: LabelInValueType[]) => void; | |
10 | + disabled?: boolean; | |
11 | + disabledTip?: string; | |
12 | + defaultTip?: string; | |
13 | + style?: React.CSSProperties; | |
14 | +} | |
15 | + | |
16 | +export default function Index({ value = [], onChange, disabled = false, disabledTip = '请选择品牌', defaultTip = '请选择品牌', style }: Props) { | |
17 | + const [delay, setDelay] = useState(true); | |
18 | + const [brandList, setBrandList] = useState<any[]>([]); | |
19 | + const { data: list, setParams, loading } = useInitial<CommonApi.OptionVO[], undefined>(getAllBrandApi, [], undefined, delay); | |
20 | + | |
21 | + useEffect(() => { | |
22 | + if (list && list.length > 0) { | |
23 | + // @ts-ignore | |
24 | + const newPostList = [{ id: -1, name: '全部品牌' }].concat(list); // 前端手动在列表头部增加一个 {id: -1, name: '全部品牌'} 的选项 | |
25 | + setBrandList(newPostList); | |
26 | + } else { | |
27 | + setBrandList([]); | |
28 | + } | |
29 | + }, [list]); | |
30 | + | |
31 | + useEffect(() => { | |
32 | + setParams(undefined, true); | |
33 | + setDelay(false); | |
34 | + }, []); | |
35 | + | |
36 | + return ( | |
37 | + <Spin spinning={loading && !disabled}> | |
38 | + <Select | |
39 | + labelInValue | |
40 | + value={value} | |
41 | + mode="multiple" | |
42 | + onChange={(value) => { | |
43 | + if (value && value.findIndex((i) => i.value === -1) > -1) { | |
44 | + onChange && onChange([{ key: '-1', label: '全部品牌', value: -1 }]); | |
45 | + } else { | |
46 | + onChange && onChange(value); | |
47 | + } | |
48 | + }} | |
49 | + style={style || { flex: 1 }} | |
50 | + allowClear | |
51 | + placeholder={disabled ? disabledTip : defaultTip} | |
52 | + showSearch | |
53 | + optionFilterProp="children" | |
54 | + disabled={disabled} | |
55 | + // getPopupContainer={(triggerNode) => triggerNode.parentNode} | |
56 | + > | |
57 | + {brandList.map((brand) => ( | |
58 | + <Select.Option key={brand.id} value={brand.id!} disabled={value.findIndex((i) => i.value === -1) > -1 && brand.id !== -1}> | |
59 | + {brand.name} | |
60 | + </Select.Option> | |
61 | + ))} | |
62 | + </Select> | |
63 | + </Spin> | |
64 | + ); | |
65 | +} | ... | ... |
src/pages/carinsur/LoanClientRequires/components/Filter/index.tsx
0 → 100644
1 | +import React from 'react'; | |
2 | +import { Row } from 'antd'; | |
3 | +import _ from 'lodash'; | |
4 | +import type { PageParams } from '../../api'; | |
5 | + | |
6 | +interface Props { | |
7 | + innerParams?: any; | |
8 | + setParams: (params: PageParams, refreshing: boolean) => void; | |
9 | +} | |
10 | + | |
11 | +function Filter({ innerParams, setParams }: Props) { | |
12 | + const onChange = _.debounce((newParams) => { | |
13 | + setParams({ ...innerParams, ...newParams }, true); | |
14 | + }, 600); | |
15 | + | |
16 | + return ( | |
17 | + <Row style={{ display: 'flex', flex: 1 }}> | |
18 | + {/* <Select | |
19 | + showSearch | |
20 | + allowClear | |
21 | + optionFilterProp="children" | |
22 | + placeholder="筛选授权角色" | |
23 | + onChange={(value) => { | |
24 | + onChange({ roles: value }); | |
25 | + }} | |
26 | + > | |
27 | + {roleList.map((i) => ( | |
28 | + <Option value={i.roleCode} key={i.roleCode}> | |
29 | + {i.roleName} | |
30 | + </Option> | |
31 | + ))} | |
32 | + </Select> | |
33 | + <Select | |
34 | + showSearch | |
35 | + allowClear | |
36 | + optionFilterProp="children" | |
37 | + placeholder="筛选往来对象类型" | |
38 | + options={TradeTypeOptions} | |
39 | + onChange={(value) => { | |
40 | + onChange({ tradeObjType: value }); | |
41 | + }} | |
42 | + /> */} | |
43 | + </Row> | |
44 | + ); | |
45 | +} | |
46 | + | |
47 | +export default Filter; | ... | ... |
src/pages/carinsur/LoanClientRequires/components/SeriesSelectorByAll.tsx
0 → 100644
1 | +import React, { useEffect, useState } from 'react'; | |
2 | +import { Select, Spin } from 'antd'; | |
3 | +import type { LabelInValueType } from 'rc-select/lib/Select'; | |
4 | +import { getSeriesApi } from '@/common/api'; | |
5 | +import useInitial from '@/hooks/useInitail'; | |
6 | + | |
7 | +interface Props { | |
8 | + brandId: number; // 根据品牌 id 筛选车系 | |
9 | + value?: LabelInValueType[]; | |
10 | + onChange?: (value: LabelInValueType[]) => void; | |
11 | + disabled?: boolean; | |
12 | + disabledTip?: string; | |
13 | + defaultTip?: string; | |
14 | + style?: React.CSSProperties; | |
15 | +} | |
16 | + | |
17 | +export default function Index({ | |
18 | + brandId, | |
19 | + value = [], | |
20 | + onChange, | |
21 | + disabled = false, | |
22 | + disabledTip = '请选择车系', | |
23 | + defaultTip = '请选择车系', | |
24 | + style, | |
25 | +}: Props) { | |
26 | + const [delay, setDelay] = useState(true); | |
27 | + const [brandList, setBrandList] = useState<any[]>([]); | |
28 | + const { data: list, setParams, loading } = useInitial<CommonApi.OptionVO[], number>(getSeriesApi, [], brandId, delay); | |
29 | + | |
30 | + useEffect(() => { | |
31 | + if (list && list.length > 0) { | |
32 | + // @ts-ignore | |
33 | + const newPostList = [{ id: -1, name: '全部车系' }].concat(list); // 前端手动在列表头部增加一个 {id: -1, name: '全部车系'} 的选项 | |
34 | + setBrandList(newPostList); | |
35 | + } else { | |
36 | + setBrandList([]); | |
37 | + } | |
38 | + }, [list]); | |
39 | + | |
40 | + useEffect(() => { | |
41 | + setParams(brandId, true); | |
42 | + setDelay(false); | |
43 | + }, []); | |
44 | + | |
45 | + return ( | |
46 | + <Spin spinning={loading && !disabled}> | |
47 | + <Select | |
48 | + labelInValue | |
49 | + value={value} | |
50 | + mode="multiple" | |
51 | + onChange={(value) => { | |
52 | + if (value && value.findIndex((i) => i.value === -1) > -1) { | |
53 | + onChange && onChange([{ key: '-1', label: '全部车系', value: -1 }]); | |
54 | + } else { | |
55 | + onChange && onChange(value); | |
56 | + } | |
57 | + }} | |
58 | + style={style || { flex: 1 }} | |
59 | + allowClear | |
60 | + placeholder={disabled ? disabledTip : defaultTip} | |
61 | + showSearch | |
62 | + optionFilterProp="children" | |
63 | + disabled={disabled} | |
64 | + // getPopupContainer={(triggerNode) => triggerNode.parentNode} | |
65 | + > | |
66 | + {brandList.map((brand) => ( | |
67 | + <Select.Option key={brand.id} value={brand.id!} disabled={value.findIndex((i) => i.value === -1) > -1 && brand.id !== -1}> | |
68 | + {brand.name} | |
69 | + </Select.Option> | |
70 | + ))} | |
71 | + </Select> | |
72 | + </Spin> | |
73 | + ); | |
74 | +} | ... | ... |
src/pages/carinsur/LoanClientRequires/index.tsx
0 → 100644
1 | +import React, { useState } from 'react'; | |
2 | +import { Button, Card, ConfigProvider, Divider, message, Popconfirm, Row, Table } from 'antd'; | |
3 | +import { PageHeaderWrapper } from '@ant-design/pro-layout'; | |
4 | +import zhCN from 'antd/lib/locale-provider/zh_CN'; | |
5 | +import usePagination from '@/hooks/usePagination'; | |
6 | +import { PlusOutlined } from '@ant-design/icons'; | |
7 | +import AddModal from './components/AddModal'; | |
8 | +import Filter from './components/Filter'; | |
9 | +import * as API from './api'; | |
10 | +import _ from 'lodash'; | |
11 | +import TextWithMore from '@/components/TextWithMore'; | |
12 | + | |
13 | +const { Column } = Table; | |
14 | + | |
15 | +export default function Index() { | |
16 | + // 新增 | 编辑 | |
17 | + const [addModal, setAddModal] = useState<{ | |
18 | + visible: boolean; | |
19 | + row?: API.Item; | |
20 | + }>({ | |
21 | + visible: false, | |
22 | + }); | |
23 | + | |
24 | + const { list, paginationConfig, loading, innerParams, setParams } = usePagination<API.Item>(API.getLCRPage); | |
25 | + | |
26 | + const handleDelete = (row: API.Item) => { | |
27 | + const { id } = row; | |
28 | + API.delLCR(id!) | |
29 | + .then((res) => { | |
30 | + message.success(res.result); | |
31 | + setParams({ ...innerParams }, true); | |
32 | + }) | |
33 | + .catch((e) => { | |
34 | + message.error(e.message); | |
35 | + }); | |
36 | + }; | |
37 | + | |
38 | + const handleEdit = (row: API.Item) => { | |
39 | + setAddModal({ | |
40 | + visible: true, | |
41 | + row, | |
42 | + }); | |
43 | + }; | |
44 | + | |
45 | + return ( | |
46 | + <PageHeaderWrapper title="贷款期客户保险要求"> | |
47 | + <ConfigProvider locale={zhCN}> | |
48 | + <Card> | |
49 | + <Row align="middle" justify="space-between" style={{ marginBottom: 20 }}> | |
50 | + <Filter innerParams={innerParams} setParams={setParams} /> | |
51 | + <Button | |
52 | + type="primary" | |
53 | + icon={<PlusOutlined />} | |
54 | + onClick={() => { | |
55 | + setAddModal({ | |
56 | + visible: true, | |
57 | + }); | |
58 | + }} | |
59 | + > | |
60 | + 新增 | |
61 | + </Button> | |
62 | + </Row> | |
63 | + <Table | |
64 | + loading={loading} | |
65 | + dataSource={list} | |
66 | + pagination={paginationConfig} | |
67 | + scroll={{ y: 800 }} | |
68 | + rowKey="id" | |
69 | + onChange={(_pagination) => setParams({ ..._pagination }, true)} | |
70 | + > | |
71 | + <Column title="适用品牌车系" dataIndex="allBrandSeries" render={(value) => (value ? '全部品牌全部车系' : '查看 todo')} /> | |
72 | + <Column title="适用门店" dataIndex="useShopIds" render={(value) => <TextWithMore title="适用门店" dataIndex="shopName" list={value} />} /> | |
73 | + <Column title="新保交强险" dataIndex="newTci" /> | |
74 | + <Column title="新保商业险" dataIndex="newVci" /> | |
75 | + <Column title="新保驾意险" dataIndex="newTai" /> | |
76 | + <Column title="续保交强险" dataIndex="renewTci" /> | |
77 | + <Column title="续保商业险" dataIndex="renewVci" /> | |
78 | + <Column title="续保驾意险" dataIndex="renewTai" /> | |
79 | + <Column | |
80 | + title="操作" | |
81 | + dataIndex="btns" | |
82 | + render={(text, row: API.Item) => ( | |
83 | + <span> | |
84 | + <a | |
85 | + onClick={(e) => { | |
86 | + e.preventDefault(); | |
87 | + handleEdit(row); | |
88 | + }} | |
89 | + > | |
90 | + 编辑 | |
91 | + </a> | |
92 | + <Divider type="vertical" /> | |
93 | + <Popconfirm title="是否删除?" onConfirm={() => handleDelete(row)}> | |
94 | + <a | |
95 | + onClick={(e) => { | |
96 | + e.preventDefault(); | |
97 | + }} | |
98 | + style={{ color: 'red' }} | |
99 | + > | |
100 | + 删除 | |
101 | + </a> | |
102 | + </Popconfirm> | |
103 | + </span> | |
104 | + )} | |
105 | + /> | |
106 | + </Table> | |
107 | + </Card> | |
108 | + <AddModal | |
109 | + visible={addModal.visible} | |
110 | + row={addModal.row} | |
111 | + onCancel={() => { | |
112 | + setAddModal({ visible: false }); | |
113 | + }} | |
114 | + onRefresh={() => setParams({ ...innerParams }, true)} | |
115 | + /> | |
116 | + </ConfigProvider> | |
117 | + </PageHeaderWrapper> | |
118 | + ); | |
119 | +} | ... | ... |