Commit 96ee8bdc83a843965ad19a8cf50913f5268e65ec

Authored by 莫红玲
2 parents 2f5b8f85 e13b609e

Merge branch 'Shinner-carinsur-LoanClientRequires' into 'master'

Browse Code » feat(carinsur): 新增贷款期客户保险配置功能



See merge request !703
config/routers/angel.ts
... ... @@ -10,8 +10,8 @@ export default [
10 10 component: './carinsur/PurchaseConfig',
11 11 },
12 12 {
13   - path: '/angel/loan/client/config', //贷款客户保险要求配置
14   - component: './carinsur/LoanClientConfig',
  13 + path: '/angel/loanClientRequires', // 贷款期客户保险配置
  14 + component: './carinsur/LoanClientRequires',
15 15 },
16 16  
17 17 {
... ...
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 LoanType {
  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: LoanType;
  22 + newVci: LoanType;
  23 + newTai: LoanType;
  24 + reNewTci: LoanType;
  25 + reNewVci: LoanType;
  26 + reNewTai: LoanType;
  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}/loancusinsureq/page`, { params });
  40 +}
  41 +
  42 +/**
  43 + * 新增/编辑
  44 + */
  45 +export function addLCR(data?: Item): http.PromiseResp<void> {
  46 + return request.post(`${ANGEL_Host}/loancusinsureq/add`, data);
  47 +}
  48 +
  49 +/**
  50 + * 删除
  51 + */
  52 +export function delLCR(id: number): http.PromisePageResp<void> {
  53 + return request.post(`${ANGEL_Host}/loancusinsureq/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 +import BrandSeriesFormItem from '../BrandSeriesFormItem';
  6 +import ShopSelectorByAll from '../ShopSelectorByAll';
  7 +import LoanTypeFormItem from '../LoanTypeFormItem';
  8 +import type { LabeledValue } from 'antd/lib/select';
  9 +
  10 +interface Props {
  11 + visible: boolean;
  12 + row?: API.Item;
  13 + onCancel: () => void;
  14 + onRefresh: () => void;
  15 +}
  16 +
  17 +function AddModal({ visible, row, onCancel, onRefresh }: Props) {
  18 + const { id } = row ?? {};
  19 + const [form] = Form.useForm();
  20 +
  21 + const saveHook = useRequest(API.addLCR, {
  22 + manual: true,
  23 + throwOnError: true,
  24 + });
  25 +
  26 + useEffect(() => {
  27 + if (visible) {
  28 + if (row) {
  29 + form.setFieldsValue({
  30 + ...row,
  31 + useShopIds: row.useShopIds.map((i) => ({ label: i.shopName, value: i.shopId })),
  32 + });
  33 + } else {
  34 + form.setFieldsValue({
  35 + allBrandSeries: true,
  36 + });
  37 + }
  38 + } else {
  39 + form.resetFields();
  40 + }
  41 + }, [visible, row]);
  42 +
  43 + const handleSave = (feildValue: any) => {
  44 + saveHook
  45 + .run({
  46 + ...feildValue,
  47 + useShopIds: feildValue.useShopIds.map((i: LabeledValue) => ({ shopId: i.value, shopName: i.label })),
  48 + brandSeries: feildValue.allBrandSeries ? [] : feildValue.brandSeries,
  49 + })
  50 + .then(() => {
  51 + message.success('操作成功');
  52 + onCancel();
  53 + onRefresh();
  54 + })
  55 + .catch((e) => {
  56 + message.error(e.message);
  57 + });
  58 + };
  59 +
  60 + return (
  61 + <Modal title={`${id ? '编辑' : '新增'}`} open={visible} confirmLoading={saveHook.loading} onCancel={onCancel} onOk={form.submit} width={1000}>
  62 + <Form form={form} onFinish={handleSave} labelCol={{ span: 4 }} wrapperCol={{ span: 18 }}>
  63 + <Form.Item name="id" hidden />
  64 + <Form.Item label="适用品牌车系" name="allBrandSeries" rules={[{ required: true, message: '请选择' }]}>
  65 + <Radio.Group>
  66 + <Radio value={true}>全部品牌全部车系</Radio>
  67 + <Radio value={false}>部分品牌部分车系</Radio>
  68 + </Radio.Group>
  69 + </Form.Item>
  70 + <Form.Item
  71 + noStyle
  72 + shouldUpdate={(prev, curr) => {
  73 + // 切换全部|部分时交互未清空部分品牌部分车系数据
  74 + return prev.allBrandSeries !== curr.allBrandSeries;
  75 + }}
  76 + >
  77 + {({ getFieldValue }) => {
  78 + const allBrandSeries = getFieldValue('allBrandSeries');
  79 + if (allBrandSeries) {
  80 + return null;
  81 + }
  82 + return (
  83 + <Form.Item label="部分品牌部分车系" name="brandSeries" rules={[{ required: true, message: '请选择' }]}>
  84 + <BrandSeriesFormItem />
  85 + </Form.Item>
  86 + );
  87 + }}
  88 + </Form.Item>
  89 + <Form.Item label="适用门店" name="useShopIds" rules={[{ required: true, message: '请选择' }]}>
  90 + <ShopSelectorByAll />
  91 + </Form.Item>
  92 + <LoanTypeFormItem form={form} key="newTci" name="newTci" label="新保交强险" />
  93 + <LoanTypeFormItem form={form} key="newVci" name="newVci" label="新保商业险" />
  94 + <LoanTypeFormItem form={form} key="newTai" name="newTai" label="新保驾意险" />
  95 + <LoanTypeFormItem form={form} key="reNewTci" name="reNewTci" label="续保交强险" />
  96 + <LoanTypeFormItem form={form} key="reNewVci" name="reNewVci" label="续保商业险" />
  97 + <LoanTypeFormItem form={form} key="reNewTai" name="reNewTai" label="续保驾意险" />
  98 + </Form>
  99 + </Modal>
  100 + );
  101 +}
  102 +
  103 +export default memo(AddModal);
... ...
src/pages/carinsur/LoanClientRequires/components/BrandSeriesAddModal.tsx 0 → 100644
  1 +import React, { useEffect } from 'react';
  2 +import { Modal, Form, Select } from 'antd';
  3 +import type { brandSeriesItem } from '../api';
  4 +import type { LabeledValue } from 'antd/lib/select';
  5 +import SeriesSelectorByAll from './SeriesSelectorByAll';
  6 +import _ from 'lodash';
  7 +
  8 +interface Props {
  9 + brands?: CommonApi.OptionVO[];
  10 + visible: boolean;
  11 + value?: brandSeriesItem;
  12 + onCancel: () => void;
  13 + onChange: (data: brandSeriesItem) => void;
  14 +}
  15 +const FormItem = Form.Item;
  16 +
  17 +export default function Index({ brands, visible, value, onCancel, onChange }: Props) {
  18 + const [form] = Form.useForm();
  19 +
  20 + useEffect(() => {
  21 + if (visible && value) {
  22 + const { id, name, series } = value;
  23 + form.setFieldsValue({
  24 + brand: { label: name, value: id },
  25 + series: series.map((i) => ({ label: i.name, value: i.id })),
  26 + });
  27 + } else {
  28 + form.resetFields();
  29 + }
  30 + }, [visible]);
  31 +
  32 + const closeModal = () => {
  33 + onCancel();
  34 + form.resetFields();
  35 + };
  36 +
  37 + function handleSave(feildValue: any) {
  38 + const { brand, series } = feildValue;
  39 + onChange &&
  40 + onChange({
  41 + id: brand.value,
  42 + name: brand.label,
  43 + series: series.map((i: LabeledValue) => ({ id: i.value, name: i.label })),
  44 + });
  45 + closeModal();
  46 + }
  47 +
  48 + return (
  49 + <Modal title={`${value ? '编辑' : '新增'}品牌车系`} style={{ width: 600 }} open={visible} onCancel={closeModal} onOk={form.submit}>
  50 + <Form form={form} labelCol={{ span: '6' }} onFinish={handleSave}>
  51 + <FormItem label="品牌" name="brand" rules={[{ required: true, message: '请选择品牌' }]}>
  52 + <Select
  53 + disabled={!!value} // 编辑时不可编辑品牌
  54 + placeholder="请选择"
  55 + options={brands}
  56 + fieldNames={{ label: 'name', value: 'id' }}
  57 + showSearch
  58 + labelInValue
  59 + optionFilterProp="children"
  60 + />
  61 + </FormItem>
  62 + <Form.Item
  63 + noStyle
  64 + shouldUpdate={(prev, curr) => {
  65 + if (!_.isEqual(prev.brand, curr.brand)) {
  66 + if (value) {
  67 + form.setFieldValue('series', value.id === curr.brand.value ? value.series.map((i) => ({ label: i.name, value: i.id })) : []);
  68 + } else {
  69 + form.setFieldValue('series', []);
  70 + }
  71 + }
  72 + return !_.isEqual(prev.brand, curr.brand);
  73 + }}
  74 + >
  75 + {({ getFieldValue }) => {
  76 + const brandId = (getFieldValue('brand') ?? {}).value;
  77 + return (
  78 + <FormItem label="车系" name="series" rules={[{ required: true, message: '请选择车系' }]}>
  79 + <SeriesSelectorByAll brandId={brandId} disabled={!brandId} disabledTip="请先选择品牌" />
  80 + </FormItem>
  81 + );
  82 + }}
  83 + </Form.Item>
  84 + </Form>
  85 + </Modal>
  86 + );
  87 +}
... ...
src/pages/carinsur/LoanClientRequires/components/BrandSeriesFormItem.tsx 0 → 100644
  1 +import React, { useEffect, useMemo, useState } from 'react';
  2 +import { Table, Divider, Popconfirm, Button, Row } from 'antd';
  3 +import { PlusOutlined } from '@ant-design/icons';
  4 +import BrandSeriesAddModal from './BrandSeriesAddModal';
  5 +import type { brandSeriesItem } from '../api';
  6 +import TextWithMore from '@/components/TextWithMore';
  7 +import useInitial from '@/hooks/useInitail';
  8 +import { getBrandFilterApi } from '@/common/api';
  9 +
  10 +const { Column } = Table;
  11 +
  12 +interface Props {
  13 + readOnly?: boolean;
  14 + value?: brandSeriesItem[];
  15 + onChange?: (data: brandSeriesItem[]) => void;
  16 +}
  17 +
  18 +export default function Index({ readOnly = false, value = [], onChange }: Props) {
  19 + const [delay, setDelay] = useState(true);
  20 + const { data: brands, setParams } = useInitial(getBrandFilterApi, [], {}, delay);
  21 +
  22 + useEffect(() => {
  23 + if (!readOnly) {
  24 + setDelay(false);
  25 + setParams(undefined, true);
  26 + }
  27 + }, []);
  28 +
  29 + const theRestBrands = useMemo(() => {
  30 + const selectedBrands = value.map((i) => i.id);
  31 + return brands.filter((b) => !selectedBrands.includes(b.id!));
  32 + }, [value, brands]);
  33 +
  34 + // 新增 | 编辑
  35 + const [addModal, setAddModal] = useState<{
  36 + visible: boolean;
  37 + row?: brandSeriesItem;
  38 + }>({
  39 + visible: false,
  40 + });
  41 +
  42 + const handleEdit = (row: brandSeriesItem) => {
  43 + setAddModal({
  44 + visible: true,
  45 + row,
  46 + });
  47 + };
  48 +
  49 + const handleDelete = (row: brandSeriesItem) => {
  50 + const newVal = [...value];
  51 + const currIdx = newVal.findIndex((i) => i.id === row.id);
  52 + newVal.splice(currIdx, 1);
  53 + onChange && onChange(newVal);
  54 + };
  55 +
  56 + const handleUpdate = (res: brandSeriesItem) => {
  57 + const newVal = [...value];
  58 + const currIdx = newVal.findIndex((i) => i.id === res.id); // 品牌 id
  59 + if (currIdx > -1) {
  60 + newVal[currIdx] = res;
  61 + } else {
  62 + newVal.push(res);
  63 + }
  64 + onChange && onChange(newVal);
  65 + };
  66 +
  67 + return (
  68 + <>
  69 + {!readOnly && (
  70 + <Row align="middle" justify="end" style={{ marginBottom: 20 }}>
  71 + <Button
  72 + type="primary"
  73 + icon={<PlusOutlined />}
  74 + onClick={() => {
  75 + setAddModal({
  76 + visible: true,
  77 + });
  78 + }}
  79 + >
  80 + 新增
  81 + </Button>
  82 + </Row>
  83 + )}
  84 + <Table dataSource={value} rowKey="id" size="small">
  85 + <Column title="品牌" dataIndex="name" width={200} render={(t) => t || '-'} />
  86 + <Column title="车系" dataIndex="series" width={200} render={(t) => <TextWithMore title="车系" dataIndex="name" list={t} />} />
  87 + {!readOnly && (
  88 + <Column
  89 + title="操作"
  90 + width={100}
  91 + dataIndex="unit"
  92 + render={(text, row: brandSeriesItem) => (
  93 + <span>
  94 + <a
  95 + onClick={() => {
  96 + handleEdit(row);
  97 + }}
  98 + >
  99 + 编辑
  100 + </a>
  101 + <Divider type="vertical" />
  102 + <Popconfirm title="是否删除?" onConfirm={() => handleDelete(row)} okText="确定" cancelText="取消">
  103 + <a
  104 + onClick={(e) => {
  105 + e.preventDefault();
  106 + }}
  107 + style={{ color: 'red' }}
  108 + >
  109 + 删除
  110 + </a>
  111 + </Popconfirm>
  112 + </span>
  113 + )}
  114 + />
  115 + )}
  116 + </Table>
  117 + <BrandSeriesAddModal
  118 + brands={theRestBrands}
  119 + visible={addModal.visible}
  120 + value={addModal.row}
  121 + onCancel={() => setAddModal({ visible: false })}
  122 + onChange={handleUpdate}
  123 + />
  124 + </>
  125 + );
  126 +}
... ...
src/pages/carinsur/LoanClientRequires/components/BrandSeriesModal.tsx 0 → 100644
  1 +import React from 'react';
  2 +import { Modal } from 'antd';
  3 +import BrandSeriesFormItem from './BrandSeriesFormItem';
  4 +import type { brandSeriesItem } from '../api';
  5 +
  6 +interface Props {
  7 + brandSeriesModal: { visible: boolean; brandSeries?: brandSeriesItem[] };
  8 + onCancel: () => void;
  9 +}
  10 +
  11 +export default function Index({ brandSeriesModal, onCancel }: Props) {
  12 + const { visible, brandSeries = [] } = brandSeriesModal;
  13 + return (
  14 + <Modal title="部分品牌部分车系" open={visible} onCancel={() => onCancel()} footer={null} width={600}>
  15 + <BrandSeriesFormItem value={brandSeries} readOnly />
  16 + </Modal>
  17 + );
  18 +}
... ...
src/pages/carinsur/LoanClientRequires/components/Filter/index.tsx 0 → 100644
  1 +import React from 'react';
  2 +import { Row, Select } from 'antd';
  3 +import _ from 'lodash';
  4 +import type { PageParams } from '../../api';
  5 +import { getBrandFilterApi, getSaleSeries, getShopApi } from '@/common/api';
  6 +import useInitial from '@/hooks/useInitail';
  7 +
  8 +interface Props {
  9 + innerParams?: any;
  10 + setParams: (params: PageParams, refreshing: boolean) => void;
  11 +}
  12 +
  13 +function Filter({ innerParams, setParams }: Props) {
  14 + const { data: brands } = useInitial(getBrandFilterApi, [], {});
  15 + const { data: series } = useInitial(getSaleSeries, [], {});
  16 + const { data: shops } = useInitial<CommonApi.OptionVO[], undefined>(getShopApi, [], undefined);
  17 +
  18 + const onChange = _.debounce((newParams) => {
  19 + setParams({ ...innerParams, ...newParams }, true);
  20 + }, 600);
  21 +
  22 + return (
  23 + <Row style={{ display: 'flex', flex: 1 }}>
  24 + <Select
  25 + style={{ width: 200 }}
  26 + showSearch
  27 + allowClear
  28 + // optionFilterProp="children"
  29 + placeholder="筛选品牌"
  30 + options={brands}
  31 + fieldNames={{ label: 'name', value: 'id' }}
  32 + onChange={(value) => {
  33 + onChange({ brandId: value });
  34 + }}
  35 + />
  36 + <Select
  37 + style={{ width: 200, marginLeft: 20 }}
  38 + showSearch
  39 + allowClear
  40 + // optionFilterProp="children"
  41 + placeholder="筛选车系"
  42 + options={series}
  43 + fieldNames={{ label: 'name', value: 'id' }}
  44 + onChange={(value) => {
  45 + onChange({ seriesId: value });
  46 + }}
  47 + />
  48 + <Select
  49 + style={{ width: 200, marginLeft: 20 }}
  50 + showSearch
  51 + allowClear
  52 + // optionFilterProp="children"
  53 + placeholder="筛选门店"
  54 + options={shops}
  55 + fieldNames={{ label: 'name', value: 'id' }}
  56 + onChange={(value) => {
  57 + onChange({ shopId: value });
  58 + }}
  59 + />
  60 + </Row>
  61 + );
  62 +}
  63 +
  64 +export default Filter;
... ...
src/pages/carinsur/LoanClientRequires/components/LoanTypeFormItem.tsx 0 → 100644
  1 +import { Form, InputNumber, Radio } from 'antd';
  2 +import React from 'react';
  3 +import { LoanTypeEnum } from '../../entity';
  4 +
  5 +interface Props {
  6 + form: any;
  7 + name: string;
  8 + label: string;
  9 +}
  10 +
  11 +export default function Index({ form, name, label }: Props) {
  12 + return (
  13 + <Form.Item label={label} name={[name, 'type']} rules={[{ required: true, message: '请选择' }]}>
  14 + <Radio.Group>
  15 + <Radio value={LoanTypeEnum.购买即可}>购买即可</Radio>
  16 + <Radio value={LoanTypeEnum.购保要求金额}>
  17 + <div style={{ display: 'flex', alignItems: 'center', flexDirection: 'row' }}>
  18 + <span>购保要求金额</span>
  19 + <Form.Item
  20 + noStyle
  21 + shouldUpdate={(prev, curr) => {
  22 + if (prev[name] && curr[name] && prev[name].type !== curr[name].type && curr[name].type !== LoanTypeEnum.购保要求金额) {
  23 + form.setFieldValue([name, 'amount'], undefined);
  24 + }
  25 + return prev[name] !== curr[name];
  26 + }}
  27 + >
  28 + {({ getFieldValue }) => {
  29 + const type = (getFieldValue(name) ?? {}).type;
  30 + if (type !== LoanTypeEnum.购保要求金额) return null;
  31 + return (
  32 + <Form.Item
  33 + style={{ marginBottom: 0, marginLeft: 10 }}
  34 + name={[name, 'amount']}
  35 + required
  36 + rules={[{ required: true, message: '请填写金额' }]}
  37 + >
  38 + <InputNumber addonBefore="≥" addonAfter="元" style={{ minWidth: 120 }} min={0.01} precision={2} placeholder="请填写金额" />
  39 + </Form.Item>
  40 + );
  41 + }}
  42 + </Form.Item>
  43 + </div>
  44 + </Radio>
  45 + <Radio value={LoanTypeEnum.无要求}>无要求</Radio>
  46 + </Radio.Group>
  47 + </Form.Item>
  48 + );
  49 +}
... ...
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 [allList, setAllList] = useState<any[]>([]);
  28 + const { data: list, setParams, loading } = useInitial<CommonApi.OptionVO[], number>(getSeriesApi, [], brandId, delay);
  29 +
  30 + useEffect(() => {
  31 + if (brandId) {
  32 + setParams(brandId, true);
  33 + setDelay(false);
  34 + }
  35 + }, [brandId]);
  36 +
  37 + useEffect(() => {
  38 + if (list && list.length > 0) {
  39 + // @ts-ignore
  40 + const newPostList = [{ id: -1, name: '全部车系' }].concat(list); // 前端手动在列表头部增加一个 {id: -1, name: '全部车系'} 的选项
  41 + setAllList(newPostList);
  42 + } else {
  43 + setAllList([]);
  44 + }
  45 + }, [list]);
  46 +
  47 + return (
  48 + <Spin spinning={loading && !disabled}>
  49 + <Select
  50 + labelInValue
  51 + value={value}
  52 + mode="multiple"
  53 + onChange={(value) => {
  54 + if (value && value.findIndex((i) => i.value === -1) > -1) {
  55 + onChange && onChange([{ key: '-1', label: '全部车系', value: -1 }]);
  56 + } else {
  57 + onChange && onChange(value);
  58 + }
  59 + }}
  60 + style={style || { flex: 1 }}
  61 + allowClear
  62 + placeholder={disabled ? disabledTip : defaultTip}
  63 + showSearch
  64 + optionFilterProp="children"
  65 + disabled={disabled}
  66 + // getPopupContainer={(triggerNode) => triggerNode.parentNode}
  67 + >
  68 + {allList.map((brand) => (
  69 + <Select.Option key={brand.id} value={brand.id!} disabled={value.findIndex((i) => i.value === -1) > -1 && brand.id !== -1}>
  70 + {brand.name}
  71 + </Select.Option>
  72 + ))}
  73 + </Select>
  74 + </Spin>
  75 + );
  76 +}
... ...
src/pages/carinsur/LoanClientRequires/components/ShopSelectorByAll.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 { getShopApi } 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 [allList, setAllList] = useState<any[]>([]);
  19 + const { data: list, setParams, loading } = useInitial<CommonApi.OptionVO[], undefined>(getShopApi, [], 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 + setAllList(newPostList);
  26 + } else {
  27 + setAllList([]);
  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 + {allList.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/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 +import { LoanTypeEnum } from '../entity';
  13 +import BrandSeriesModal from './components/BrandSeriesModal';
  14 +
  15 +const { Column } = Table;
  16 +
  17 +export default function Index() {
  18 + // 新增 | 编辑
  19 + const [addModal, setAddModal] = useState<{
  20 + visible: boolean;
  21 + row?: API.Item;
  22 + }>({
  23 + visible: false,
  24 + });
  25 + // 查看部分品牌车系
  26 + const [brandSeriesModal, setBrandSeriesModal] = useState<{
  27 + visible: boolean;
  28 + brandSeries?: API.brandSeriesItem[];
  29 + }>({
  30 + visible: false,
  31 + brandSeries: [],
  32 + });
  33 +
  34 + const { list, paginationConfig, loading, innerParams, setParams } = usePagination<API.Item>(API.getLCRPage);
  35 +
  36 + const handleDelete = (row: API.Item) => {
  37 + const { id } = row;
  38 + API.delLCR(id!)
  39 + .then((res) => {
  40 + message.success(res.result);
  41 + setParams({ ...innerParams }, true);
  42 + })
  43 + .catch((e) => {
  44 + message.error(e.message);
  45 + });
  46 + };
  47 +
  48 + const handleEdit = (row: API.Item) => {
  49 + setAddModal({
  50 + visible: true,
  51 + row,
  52 + });
  53 + };
  54 +
  55 + const renderLoanTypeEle = (value: API.LoanType) => {
  56 + return value ? (value.type !== LoanTypeEnum.购保要求金额 ? LoanTypeEnum[value.type] : `保费 ≥ ${value.amount}元`) : '--';
  57 + };
  58 +
  59 + return (
  60 + <PageHeaderWrapper title="贷款期客户保险要求">
  61 + <ConfigProvider locale={zhCN}>
  62 + <Card>
  63 + <Row align="middle" justify="space-between" style={{ marginBottom: 20 }}>
  64 + <Filter innerParams={innerParams} setParams={setParams} />
  65 + <Button
  66 + type="primary"
  67 + icon={<PlusOutlined />}
  68 + onClick={() => {
  69 + setAddModal({
  70 + visible: true,
  71 + });
  72 + }}
  73 + >
  74 + 新增
  75 + </Button>
  76 + </Row>
  77 + <Table
  78 + loading={loading}
  79 + dataSource={list}
  80 + pagination={paginationConfig}
  81 + scroll={{ y: 800 }}
  82 + rowKey="id"
  83 + onChange={(_pagination) => setParams({ ..._pagination }, true)}
  84 + >
  85 + <Column
  86 + title="适用品牌车系"
  87 + dataIndex="allBrandSeries"
  88 + render={(value, row: API.Item) =>
  89 + value ? (
  90 + '全部品牌全部车系'
  91 + ) : (
  92 + <a
  93 + onClick={(e) => {
  94 + e.preventDefault();
  95 + setBrandSeriesModal({ visible: true, brandSeries: row.brandSeries });
  96 + }}
  97 + >
  98 + 查看
  99 + </a>
  100 + )
  101 + }
  102 + />
  103 + <Column title="适用门店" dataIndex="useShopIds" render={(value) => <TextWithMore title="适用门店" dataIndex="shopName" list={value} />} />
  104 + <Column title="新保交强险" dataIndex="newTci" render={renderLoanTypeEle} />
  105 + <Column title="新保商业险" dataIndex="newVci" render={renderLoanTypeEle} />
  106 + <Column title="新保驾意险" dataIndex="newTai" render={renderLoanTypeEle} />
  107 + <Column title="续保交强险" dataIndex="reNewTci" render={renderLoanTypeEle} />
  108 + <Column title="续保商业险" dataIndex="reNewVci" render={renderLoanTypeEle} />
  109 + <Column title="续保驾意险" dataIndex="reNewTai" render={renderLoanTypeEle} />
  110 + <Column
  111 + title="操作"
  112 + dataIndex="btns"
  113 + render={(text, row: API.Item) => (
  114 + <span>
  115 + <a
  116 + onClick={(e) => {
  117 + e.preventDefault();
  118 + handleEdit(row);
  119 + }}
  120 + >
  121 + 编辑
  122 + </a>
  123 + <Divider type="vertical" />
  124 + <Popconfirm title="是否删除?" onConfirm={() => handleDelete(row)}>
  125 + <a
  126 + onClick={(e) => {
  127 + e.preventDefault();
  128 + }}
  129 + style={{ color: 'red' }}
  130 + >
  131 + 删除
  132 + </a>
  133 + </Popconfirm>
  134 + </span>
  135 + )}
  136 + />
  137 + </Table>
  138 + </Card>
  139 + <AddModal
  140 + visible={addModal.visible}
  141 + row={addModal.row}
  142 + onCancel={() => {
  143 + setAddModal({ visible: false });
  144 + }}
  145 + onRefresh={() => setParams({ ...innerParams }, true)}
  146 + />
  147 + <BrandSeriesModal
  148 + brandSeriesModal={brandSeriesModal}
  149 + onCancel={() => {
  150 + setBrandSeriesModal({ visible: false });
  151 + }}
  152 + />
  153 + </ConfigProvider>
  154 + </PageHeaderWrapper>
  155 + );
  156 +}
... ...
src/pages/carinsur/entity.ts 0 → 100644
  1 +export interface ShopOption {
  2 + shopId: number;
  3 + shopName: string;
  4 +}
  5 +export interface IdNameOption {
  6 + id: number;
  7 + name: string;
  8 +}
  9 +export enum LoanTypeEnum {
  10 + '购买即可' = 1,
  11 + '购保要求金额',
  12 + '无要求',
  13 +}
0 14 \ No newline at end of file
... ...