Commit bc9db829e40de19f6ee76d2e9590ab4039648bc2

Authored by 舒述军
1 parent dd3e22ff

新增置换补贴

src/pages/order3/CarPurchaseSubsidy/ReplacementSubsidy/subpages/AddConfig/index.tsx
1 import React, { useEffect, useState } from 'react'; 1 import React, { useEffect, useState } from 'react';
2 -import { Table, Modal, Button, Form, Space, DatePicker, Tree, Input, message, Card, Row, Col} from 'antd';  
3 -import CarSelect from '@/pages/order3/Common/CarSelect/index'; 2 +import { Table, Button, Form, Space, DatePicker, Tree, Input, message, Card, Row, Col, Radio, Select, InputNumber} from 'antd';
4 import {saveReplacementApi, ApplyData} from '@/pages/order3/CarPurchaseSubsidy/ReplacementSubsidy/api'; 3 import {saveReplacementApi, ApplyData} from '@/pages/order3/CarPurchaseSubsidy/ReplacementSubsidy/api';
5 import { getAllBrandApi, getSeriesApi } from "@/common/api"; 4 import { getAllBrandApi, getSeriesApi } from "@/common/api";
6 import useInitial from '@/hooks/useInitail'; 5 import useInitial from '@/hooks/useInitail';
7 import NewDataModal from '@/pages/order3/Common/NewDataModal/index'; 6 import NewDataModal from '@/pages/order3/Common/NewDataModal/index';
8 import moment from 'moment'; 7 import moment from 'moment';
9 import { PageHeaderWrapper } from '@ant-design/pro-layout'; 8 import { PageHeaderWrapper } from '@ant-design/pro-layout';
  9 +import CarTableTreeAuth from '@/components/CarTableTreeAuth';
  10 +import { PlusSquareOutlined } from '@ant-design/icons';
  11 +import { CarAuthList } from '@/components/CarTableTreeAuth/entity';
  12 +import { getShopApi, ShopVo, RequestShopParams } from '@/pages/order3/Common/api';
10 import { isNil } from 'lodash'; 13 import { isNil } from 'lodash';
11 14
12 interface DataNode { 15 interface DataNode {
@@ -15,22 +18,21 @@ interface DataNode { @@ -15,22 +18,21 @@ interface DataNode {
15 isLeaf?: boolean; 18 isLeaf?: boolean;
16 children?: DataNode[]; 19 children?: DataNode[];
17 } 20 }
  21 +const Requirements = [{value: true, label: '必买'}, {value: false, label: '非必买'}];
18 22
19 export default function ApplyModal() { 23 export default function ApplyModal() {
20 const [form] = Form.useForm(); 24 const [form] = Form.useForm();
21 const [loading, setLoading] = useState<boolean>(false); 25 const [loading, setLoading] = useState<boolean>(false);
22 - const [showTree, setShowTree] = useState<any[]>([]);  
23 const {data} = useInitial(getAllBrandApi, [], {}); 26 const {data} = useInitial(getAllBrandApi, [], {});
24 - const [subinfo, setSubinfo] = useState<number[]>([]);  
25 - const [afterCar, setAfterCar] = useState<number[]>([]);  
26 - const [hidden, setHidden] = useState<boolean>(true);  
27 const [treeData, setTreeData] = useState<any>([]); 27 const [treeData, setTreeData] = useState<any>([]);
28 const [checked, setChecked] = useState<any[]>([]); 28 const [checked, setChecked] = useState<any[]>([]);
29 - const [specKey, setSpecKey] = useState<any[]>([]);  
30 - const [brand, setBrand] = useState<any>();  
31 const [beforeData, setBeforeData] = useState<ApplyData[]>([]); // 前置资料 29 const [beforeData, setBeforeData] = useState<ApplyData[]>([]); // 前置资料
32 const [afterData, setAfterData] = useState<ApplyData[]>([]); // 后置资料 30 const [afterData, setAfterData] = useState<ApplyData[]>([]); // 后置资料
33 const [afterDay, setAfterDay] = useState<number>(); // 后置资料上传天数 31 const [afterDay, setAfterDay] = useState<number>(); // 后置资料上传天数
  32 + const [shopList, setShopList] = useState<ShopVo[]>([]);
  33 + const [shopLoading, setShopLoading] = useState<boolean>(false);
  34 + const [carSelectData, setCarSelectData] = useState<CarAuthList[]>([]);
  35 + const [insure, setInsure] = useState<any>([{mustBuyTci: undefined, mustBuyVci: undefined, vciBuyAmount: undefined, id: 1}]);
34 36
35 useEffect(() => { 37 useEffect(() => {
36 if (data.length) { 38 if (data.length) {
@@ -49,18 +51,6 @@ export default function ApplyModal() { @@ -49,18 +51,6 @@ export default function ApplyModal() {
49 } 51 }
50 }, [checked.length]); 52 }, [checked.length]);
51 53
52 - useEffect(() => {  
53 - brand && setChecked([brand]);  
54 - }, [brand]);  
55 -  
56 - useEffect(() => {  
57 - if (subinfo.length>0) {  
58 - form.setFieldsValue({subsidyDataList: subinfo});  
59 - } else {  
60 - form.setFieldsValue({subsidyDataList: undefined});  
61 - }  
62 - }, [subinfo.length]);  
63 -  
64 const onCheck = (value:any) => { 54 const onCheck = (value:any) => {
65 setChecked(value); 55 setChecked(value);
66 }; 56 };
@@ -116,11 +106,7 @@ function updateTreeData(list: DataNode[], key: React.Key, children: DataNode[]): @@ -116,11 +106,7 @@ function updateTreeData(list: DataNode[], key: React.Key, children: DataNode[]):
116 setTreeData((origin:any) => updateTreeData(origin, key, _childrenNode)); 106 setTreeData((origin:any) => updateTreeData(origin, key, _childrenNode));
117 }; 107 };
118 const handleCancel = () => { 108 const handleCancel = () => {
119 - setSpecKey([]);  
120 - setSubinfo([]);  
121 - setAfterCar([]);  
122 setChecked([]); 109 setChecked([]);
123 - setHidden(true);  
124 setChecked([]); 110 setChecked([]);
125 }; 111 };
126 const onFinsh = async () => { 112 const onFinsh = async () => {
@@ -137,6 +123,9 @@ function updateTreeData(list: DataNode[], key: React.Key, children: DataNode[]): @@ -137,6 +123,9 @@ function updateTreeData(list: DataNode[], key: React.Key, children: DataNode[]):
137 applyShops: param.applyShops.map((item:any) => { return {shopId: item.value, shopName: item.label}; }), // 门店列表 123 applyShops: param.applyShops.map((item:any) => { return {shopId: item.value, shopName: item.label}; }), // 门店列表
138 subsidyDataUploadApply: beforeData.map((v:any) => { return {applyUpload: 1, dataType: v.dataType, dataName: v.dataName}; }), // 申请时上传资料 124 subsidyDataUploadApply: beforeData.map((v:any) => { return {applyUpload: 1, dataType: v.dataType, dataName: v.dataName}; }), // 申请时上传资料
139 subsidyType: 2, 125 subsidyType: 2,
  126 + applyCarList: handleCarData(param.optionalAuth),
  127 + containOrder: param.containOrder,
  128 + insuranceRequire: param.insuranceRequire
140 }; 129 };
141 if (checked.length === 0) { 130 if (checked.length === 0) {
142 message.error("请选择本品牌范围!"); 131 message.error("请选择本品牌范围!");
@@ -144,44 +133,35 @@ function updateTreeData(list: DataNode[], key: React.Key, children: DataNode[]): @@ -144,44 +133,35 @@ function updateTreeData(list: DataNode[], key: React.Key, children: DataNode[]):
144 } else if (!isNil(afterDay) && afterData.length === 0) { 133 } else if (!isNil(afterDay) && afterData.length === 0) {
145 message.error("请勾选交车后N天内上传的资料!"); 134 message.error("请勾选交车后N天内上传的资料!");
146 return; 135 return;
147 - } else if (param.applyCarType === 2 && param.applySeriesList.length === 0) { // 部分车系  
148 - message.error("请选择适用车辆!"); 136 + } else if (param.insuranceRequire && isNil(insure[0].mustBuyTci)) {
  137 + message.error("请选择是否购买交强险!");
  138 + return;
  139 + } else if (param.insuranceRequire && isNil(insure[0].mustBuyVci)) {
  140 + message.error("请选择商是否购买商业险购!");
149 return; 141 return;
150 - } else if (param.applyCarType === 3 && showTree.length === 0) { // 部分车型  
151 - message.error("请选择适用车辆!"); 142 + } else if (param.insuranceRequire && isNil(insure[0].vciBuyAmount)) {
  143 + message.error("请选择输入商业险金额!");
152 return; 144 return;
153 } 145 }
154 if (!isNil(afterDay)) { 146 if (!isNil(afterDay)) {
155 _param.deliveryAfterDays = afterDay; 147 _param.deliveryAfterDays = afterDay;
156 _param.subsidyDataUploadNDay = afterData.map((item: any) => { return {applyUpload: 0, dataType: item.dataType, dataName: item.dateName}; }); 148 _param.subsidyDataUploadNDay = afterData.map((item: any) => { return {applyUpload: 0, dataType: item.dataType, dataName: item.dateName}; });
157 } 149 }
  150 + if (param.insuranceRequire) {
  151 + _param.mustBuyTci = insure[0].mustBuyTci;
  152 + _param.mustBuyVci = insure[0].mustBuyVci;
  153 + _param.vciBuyAmount = insure[0].vciBuyAmount;
  154 + }
158 if (param.applyCarType === 2) { 155 if (param.applyCarType === 2) {
159 _param.applySpecList = param.applySeriesList.map((item:any) => { return {seriesId: item.value, seriesName: item.label}; }); 156 _param.applySpecList = param.applySeriesList.map((item:any) => { return {seriesId: item.value, seriesName: item.label}; });
160 } 157 }
161 - if (param.applyCarType === 3) {  
162 - const _showTree = JSON.parse(JSON.stringify(showTree));  
163 - _param.applySpecList = _showTree.map((item:any) => {  
164 - const _data = item.children.map((v:any) => {  
165 - return {  
166 - seriesId: item.key,  
167 - seriesName: item.title,  
168 - specId: v.key,  
169 - specName: v.title  
170 - };  
171 - });  
172 - return [..._data];  
173 - }).flat();  
174 - }  
175 const sameBrandRange = brandList(checked); 158 const sameBrandRange = brandList(checked);
176 _param.sameBrandRange = sameBrandRange; 159 _param.sameBrandRange = sameBrandRange;
177 setLoading(true); 160 setLoading(true);
178 saveReplacementApi(_param) 161 saveReplacementApi(_param)
179 .then(res => { 162 .then(res => {
180 message.success(res.result); 163 message.success(res.result);
181 - setSubinfo([]);  
182 - setAfterCar([]);  
183 setLoading(false); 164 setLoading(false);
184 - setSpecKey([]);  
185 }) 165 })
186 .catch(e => { 166 .catch(e => {
187 message.error(e.message); 167 message.error(e.message);
@@ -189,10 +169,95 @@ function updateTreeData(list: DataNode[], key: React.Key, children: DataNode[]): @@ -189,10 +169,95 @@ function updateTreeData(list: DataNode[], key: React.Key, children: DataNode[]):
189 }); 169 });
190 }; 170 };
191 171
192 - function onClose() {  
193 - form.resetFields();  
194 - setBrand(undefined);  
195 - setChecked([]); 172 + /**
  173 + * 选择车辆范围回调
  174 + * @param value 车辆树形结构
  175 + */
  176 + function handleChange(value: CarAuthList[] = []) {
  177 + const brandIds: number[] = [];
  178 + const seriesIds: number[] = [];
  179 + const specIds: number[] = [];
  180 + value.forEach(v => {
  181 + if (v.children) {
  182 + v.children.forEach(k => {
  183 + if (k.children) {
  184 + const spec = k.children.map(q => q.specId);
  185 + specIds.push(...spec);
  186 + } else {
  187 + seriesIds.push(k.seriesId);
  188 + }
  189 + });
  190 + } else {
  191 + brandIds.push(v.brandId);
  192 + }
  193 + });
  194 + const parmas = {
  195 + brandIds,
  196 + seriesIds,
  197 + specIds
  198 + };
  199 + setCarSelectData(value || []);
  200 + getShopScope(parmas);
  201 + console.log(value);
  202 + }
  203 +
  204 + /**
  205 + * 获取所选车辆的授权门店范围
  206 + * @param params
  207 + */
  208 + function getShopScope(params: RequestShopParams) {
  209 + setShopLoading(true);
  210 + getShopApi(params)
  211 + .then(res => {
  212 + setShopLoading(false);
  213 + setShopList(res.data || []);
  214 + }).catch(e => {
  215 + setShopLoading(false);
  216 + setShopList([]);
  217 + message.error(e.message);
  218 + });
  219 + }
  220 +
  221 + function handleInsureChange(name: string, value?: number) {
  222 + setInsure([{...insure[0], [name]: value}]);
  223 + }
  224 +
  225 + function resetInsure() {
  226 + setInsure([{mustBuyTci: undefined, mustBuyVci: undefined, vciBuyAmount: undefined, id: 1}]);
  227 + }
  228 +
  229 + /**
  230 + * 将树形车辆结构转换成扁平结构
  231 + * applyCarType为最细化层级的类型
  232 + * @param value
  233 + * @returns
  234 + */
  235 + function handleCarData(value: CarAuthList[]) {
  236 + const result: any = [];
  237 + let applyCarType = 1;
  238 + value.forEach(v => {
  239 + if (v.children) {
  240 + v.children.forEach(k => {
  241 + if (k.children) {
  242 + k.children.forEach(r => {
  243 + const item = {brandId: v.brandId, brandName: v.brandName, seriesId: k.seriesId, seriesName: k.seriesName, specId: r.specId, specName: r.specName};
  244 + result.push(item);
  245 + applyCarType = Math.max(applyCarType, 3);
  246 + });
  247 + } else {
  248 + const item = {brandId: v.brandId, brandName: v.brandName, seriesId: k.seriesId, seriesName: k.seriesName};
  249 + result.push(item);
  250 + applyCarType = Math.max(applyCarType, 2);
  251 + }
  252 + });
  253 + } else {
  254 + const item = { brandId: v.brandId, brandName: v.brandName, applyCarType: v.authType};
  255 + result.push(item);
  256 + applyCarType = Math.max(applyCarType, 1);
  257 + }
  258 + });
  259 + const _result = result.map((v: any) => ({...v, applyCarType}));
  260 + return _result;
196 } 261 }
197 262
198 return ( 263 return (
@@ -203,7 +268,22 @@ function updateTreeData(list: DataNode[], key: React.Key, children: DataNode[]): @@ -203,7 +268,22 @@ function updateTreeData(list: DataNode[], key: React.Key, children: DataNode[]):
203 <Form 268 <Form
204 form={form} 269 form={form}
205 > 270 >
206 - {/* <CarSelect specKey={specKey} setSpecKey={setSpecKey} modalVis={visible} setFieldsValue={form.setFieldsValue} showTree={showTree} setShowTree={setShowTree} setBrand={setBrand} /> */} 271 + <Form.Item
  272 + name="optionalAuth"
  273 + label="授权车辆范围"
  274 + rules={[{ required: true, message: "选择车辆" }]}
  275 + tooltip={<span style={{ color: '#ccc', fontSize: 12 }}>*点击图标<PlusSquareOutlined />展开授权详情</span>}
  276 + >
  277 + <CarTableTreeAuth value={carSelectData} onChange={handleChange} brandMultiple={false} />
  278 + </Form.Item>
  279 + <Form.Item
  280 + label="适用门店"
  281 + name="applyShops"
  282 + labelAlign="left"
  283 + rules={[{ required: true, message: "请选择适用门店" }]}
  284 + >
  285 + <Select mode="multiple" allowClear filterOption optionFilterProp="children" labelInValue placeholder="请选择" options={shopList.map(v => ({label: v.shopName, value: v.shopId}))} loading={shopLoading} />
  286 + </Form.Item>
207 <Form.Item name="time" label="有效时间" rules={[{ type: 'array' as const, required: true, message: '请选择有效时间!' }]}> 287 <Form.Item name="time" label="有效时间" rules={[{ type: 'array' as const, required: true, message: '请选择有效时间!' }]}>
208 <DatePicker.RangePicker showTime style={{width: "100%"}} /> 288 <DatePicker.RangePicker showTime style={{width: "100%"}} />
209 </Form.Item> 289 </Form.Item>
@@ -226,6 +306,47 @@ function updateTreeData(list: DataNode[], key: React.Key, children: DataNode[]): @@ -226,6 +306,47 @@ function updateTreeData(list: DataNode[], key: React.Key, children: DataNode[]):
226 <Form.Item name="extraAmount" label="4S店老客户升级置换额外享受补贴" rules={[{required: true, pattern: /^(\d+|\d+\.\d{1,2})$/, message: "请输入正确的补贴值!"}]}> 306 <Form.Item name="extraAmount" label="4S店老客户升级置换额外享受补贴" rules={[{required: true, pattern: /^(\d+|\d+\.\d{1,2})$/, message: "请输入正确的补贴值!"}]}>
227 <Input /> 307 <Input />
228 </Form.Item> 308 </Form.Item>
  309 + <Form.Item labelAlign="left" label="保险要求" name="insuranceRequire" rules={[{required: true, message: "请选择保险要求!"}]}>
  310 + <Radio.Group onChange={resetInsure}>
  311 + <Radio value={false}>无要求</Radio>
  312 + <Radio value>有要求</Radio>
  313 + </Radio.Group>
  314 + </Form.Item>
  315 + <Form.Item
  316 + noStyle
  317 + shouldUpdate={(prevValues, curValues) => prevValues.insuranceRequire !== curValues.insuranceRequire}
  318 + >
  319 + {({ getFieldValue }) => {
  320 + const bool = getFieldValue('insuranceRequire');
  321 + return bool ? (
  322 + <Card>
  323 + <Table pagination={false} dataSource={insure} rowKey="id">
  324 + <Table.Column
  325 + title="交强险"
  326 + dataIndex="mustBuyTci"
  327 + render={(_text, record) => <Select value={_text} onChange={(e) => handleInsureChange("mustBuyTci", e)} placeholder="请选择" options={Requirements} />}
  328 + />
  329 + <Table.Column
  330 + title="商业险"
  331 + dataIndex="mustBuyVci"
  332 + render={(_text, record) => <Select value={_text} onChange={e => handleInsureChange("mustBuyVci", e)} placeholder="请选择" options={Requirements} />}
  333 + />
  334 + <Table.Column
  335 + title="商业险金额(≥元)"
  336 + dataIndex="vciBuyAmount"
  337 + render={(_text, record) => <InputNumber value={_text} onChange={e => handleInsureChange("vciBuyAmount", e)} controls={false} min={0} precision={2} placeholder="请输入金额" />}
  338 + />
  339 + </Table>
  340 + </Card>
  341 + ) : null;
  342 + }}
  343 + </Form.Item>
  344 + <Form.Item labelAlign="left" label="政策适用范围" name="containOrder" rules={[{required: true, message: "请选择政策适用范围!"}]}>
  345 + <Radio.Group>
  346 + <Radio value>是</Radio>
  347 + <Radio value={false}>否</Radio>
  348 + </Radio.Group>
  349 + </Form.Item>
229 <Form.Item 350 <Form.Item
230 labelAlign="left" 351 labelAlign="left"
231 label="置换补贴资料" 352 label="置换补贴资料"