Commit c52b00d615d692c69a4c1de3eb63dfb022546136
1 parent
99114ea0
Merge branch 'cas' of gitlab.feewee.cn:FEV2/fw-cms into cas
Showing
101 changed files
with
2396 additions
and
785 deletions
Too many changes to show.
To preserve performance only 88 of 101 files are displayed.
.gitignore
build/admin.tar.gz deleted
No preview for this file type
package.json
... | ... | @@ -5,7 +5,7 @@ |
5 | 5 | "description": "霏微汽车云平台", |
6 | 6 | "scripts": { |
7 | 7 | "analyze": "cross-env ANALYZE=1 umi build", |
8 | - "build:prod": "cross-env REACT_APP_ENV=prod umi build && npm run package", | |
8 | + "build:prod": "cross-env REACT_APP_ENV=prod umi build", | |
9 | 9 | "build:unset": "cross-env REACT_APP_ENV=dev umi build", |
10 | 10 | "lint": "npm run lint:js && npm run lint:style && npm run lint:prettier", |
11 | 11 | "lint-staged": "lint-staged", |
... | ... | @@ -62,11 +62,12 @@ |
62 | 62 | "lrz": "^4.9.40", |
63 | 63 | "mobx": "5.15.4", |
64 | 64 | "mobx-react-lite": "1.5.2", |
65 | - "moment": "2.24.0", | |
65 | + "moment": "^2.24.0", | |
66 | 66 | "omit.js": "^1.0.2", |
67 | 67 | "path-to-regexp": "^3.0.0", |
68 | 68 | "qrcode.react": "^1.0.0", |
69 | 69 | "qs": "^6.7.0", |
70 | + "react-amap": "^1.2.8", | |
70 | 71 | "react-beautiful-dnd": "^13.1.0", |
71 | 72 | "react-bmap": "^1.0.130", |
72 | 73 | "react-copy-to-clipboard": "^5.0.1", |
... | ... | @@ -80,10 +81,8 @@ |
80 | 81 | "use-merge-value": "^1.0.1", |
81 | 82 | "webpack-theme-color-replacer": "^1.3.11" |
82 | 83 | }, |
83 | - "resolutions": { | |
84 | - "moment": "2.24.0" | |
85 | - }, | |
86 | 84 | "devDependencies": { |
85 | + "@amap/amap-jsapi-loader": "^1.0.1", | |
87 | 86 | "@ant-design/pro-cli": "^2.1.5", |
88 | 87 | "@ant-design/pro-form": "^1.49.0", |
89 | 88 | "@ant-design/pro-table": "^2.57.2", | ... | ... |
src/common/api.ts
1 | 1 | /* |
2 | 2 | * @Date: 2021-07-31 09:42:25 |
3 | 3 | * @LastEditors: wangqiang@feewee.cn |
4 | - * @LastEditTime: 2022-06-29 10:59:21 | |
4 | + * @LastEditTime: 2022-11-02 14:47:26 | |
5 | 5 | */ |
6 | 6 | import request from "@/utils/request"; |
7 | 7 | import { http } from "@/typing/http"; |
8 | -import { HOST, EHR_HOST } from "@/utils/host"; | |
8 | +import { HOST, EHR_HOST, FINANCE2_HOST } from "@/utils/host"; | |
9 | 9 | |
10 | 10 | type PrResArr<T> = http.PromiseResp<T[]>; |
11 | 11 | |
... | ... | @@ -137,4 +137,15 @@ export function authShopRoleListApi(params: { |
137 | 137 | */ |
138 | 138 | export function getInsurOderApi(fid: string): http.PromiseResp<CommonApi.InsurOrderItem> { |
139 | 139 | return request.post(`/ocr/app/ocr/insuranceorder`, { fid }, { contentType: 'form-data' }); |
140 | +} | |
141 | + | |
142 | +/** | |
143 | + * @description: 获取往来单位列表 | |
144 | + * @param {CommonApi.ConmanyQueryParams} parmas | |
145 | + * @return {http.PromiseRespA<CommonApi.companyVO>} | |
146 | + */ | |
147 | +export function getUnitCompanyListApi( | |
148 | + params: CommonApi.ConmanyQueryParams | |
149 | +): http.PromiseRespA<CommonApi.companyVO> { | |
150 | + return request.get(`${FINANCE2_HOST}/common/trade/company/list`, { params }); | |
140 | 151 | } |
141 | 152 | \ No newline at end of file | ... | ... |
src/common/interface.d.ts
... | ... | @@ -124,17 +124,30 @@ declare namespace CommonApi { |
124 | 124 | userName: string; |
125 | 125 | mobile: string; |
126 | 126 | } |
127 | + | |
128 | + interface ConmanyQueryParams { | |
129 | + dealerId?: string; // 商家id列表,逗号分割 | |
130 | + brandId?: number; // 品牌ID | |
131 | + compCategory?: number; // 单位类别(See: 往来单位类别) | |
132 | + excludeIds?: string; // 要排除的往来单位id列表,逗号分割 | |
133 | + types?: string; // 单位类型(See: 单位(业务)类型枚举往来单位类型列表,逗号分割 | |
134 | + keywords?: string; // | |
135 | + groupId?: number; | |
136 | + shopIds?: string; // 门店ID列表,逗号分割 | |
137 | + } | |
138 | + | |
127 | 139 | interface companyVO { |
128 | - id: number; // id | |
129 | - type?: number; | |
130 | - no?: string; | |
131 | - name?: string; | |
132 | - shortName?: string; | |
133 | - compCategory?: string; | |
134 | - creditCode?: string; | |
135 | - compAddress?: string; | |
136 | - concatPhone?: string; | |
137 | - concatName?: string; | |
140 | + id: number; // 单位id | |
141 | + compCategory?: string; // 单位类别(See: 往来单位类别) | |
142 | + type?: number[]; // 往来单位类型 | |
143 | + compTypeName?: string; // 往来单位类型名称 | |
144 | + no?: string; // 单位编号 | |
145 | + name?: string; // 单位名称 | |
146 | + creditCode?: string; // 社会信用代码 | |
147 | + shortName?: string; // 单位简称 | |
148 | + compAddress?: string; // 单位地址 | |
149 | + concatPhone?: string; // 单位联系人电话 | |
150 | + concatName?: string; // 联系人名称 | |
138 | 151 | } |
139 | 152 | |
140 | 153 | export interface InsurOrderItem { | ... | ... |
src/components/MemberSelect/index.tsx
1 | 1 | /* |
2 | 2 | * @Date: 2021-03-06 16:59:54 |
3 | 3 | * @LastEditors: wangqiang@feewee.cn |
4 | - * @LastEditTime: 2022-08-25 14:40:39 | |
4 | + * @LastEditTime: 2022-11-05 15:19:03 | |
5 | 5 | */ |
6 | 6 | import React, { useEffect, useMemo, useRef, useState } from "react"; |
7 | 7 | import { Checkbox, Radio, Row, TreeSelect } from "antd"; |
... | ... | @@ -21,7 +21,7 @@ const divId = `TreeSelect_Staff_Div_${Date.now()}`; // 生成岗位div唯一key |
21 | 21 | |
22 | 22 | interface Props { |
23 | 23 | value?: (LabelValueType | number)[]; // 人员id 列表 |
24 | - onChange?: Function; | |
24 | + onChange?: (value: (LabelValueType | number)[]) => void; | |
25 | 25 | multiple?: boolean; |
26 | 26 | labelInValue?: boolean; |
27 | 27 | initType?: 1 | 2; |
... | ... | @@ -207,42 +207,6 @@ export default function MemberSelect({ |
207 | 207 | } else return []; |
208 | 208 | }, [type, postShopStaffInitail.data, shopPostStaffInitail.data]); |
209 | 209 | |
210 | - const staffIdList = useMemo(() => { | |
211 | - if (type === 1) { | |
212 | - return postShopStaffInitail.data.reduce( | |
213 | - (array, cur) => array.concat( | |
214 | - (cur.children || []).reduce( | |
215 | - (array, cur) => array.concat( | |
216 | - (cur.children || []).reduce( | |
217 | - (array, cur) => array.concat(cur.id), | |
218 | - [] as (number | undefined)[] | |
219 | - ) | |
220 | - ), | |
221 | - [] as (number | undefined)[] | |
222 | - ) | |
223 | - ), | |
224 | - [] as (number | undefined)[] | |
225 | - ); | |
226 | - } | |
227 | - if (type === 2) { | |
228 | - return shopPostStaffInitail.data.reduce( | |
229 | - (array, cur) => array.concat( | |
230 | - (cur.children || []).reduce( | |
231 | - (array, cur) => array.concat( | |
232 | - (cur.children || []).reduce( | |
233 | - (array, cur) => array.concat(cur.id), | |
234 | - [] as (number | undefined)[] | |
235 | - ) | |
236 | - ), | |
237 | - [] as (number | undefined)[] | |
238 | - ) | |
239 | - ), | |
240 | - [] as (number | undefined)[] | |
241 | - ); | |
242 | - } | |
243 | - return []; | |
244 | - }, [type, postShopStaffInitail.data, shopPostStaffInitail.data]); | |
245 | - | |
246 | 210 | useEffect(() => { |
247 | 211 | if (type === 1) { |
248 | 212 | postShopStaffInitail.setParams({ excludeProbation }, true); |
... | ... | @@ -252,22 +216,29 @@ export default function MemberSelect({ |
252 | 216 | }, [excludeProbation, type]); |
253 | 217 | |
254 | 218 | useEffect(() => { |
255 | - const _value = labelInValue | |
256 | - ? // @ts-ignore | |
257 | - value.filter((v) => staffIdList.includes(v.value)) | |
258 | - : // @ts-ignore | |
259 | - value.filter((v) => staffIdList.includes(v)); | |
260 | - if (multiple) { | |
261 | - setCheckInfo({ | |
262 | - indeterminate: | |
263 | - _value && | |
264 | - _value.length > 0 && | |
265 | - _value.length !== allValues.current.length, | |
266 | - checkAll: _value && _value.length === allValues.current.length, | |
267 | - }); | |
219 | + if (allValues.current.length) { | |
220 | + const v = value || []; | |
221 | + const _value = labelInValue | |
222 | + ? // @ts-ignore | |
223 | + allValues.current | |
224 | + .filter( | |
225 | + (val) => !!v.find((_) => (_ as LabelValueType).value === val.value) | |
226 | + ) | |
227 | + .map((val: any) => ({ ...val, label: val.staffName })) | |
228 | + : v; | |
229 | + console.log(value, _value, allValues.current); | |
230 | + if (multiple) { | |
231 | + setCheckInfo({ | |
232 | + indeterminate: | |
233 | + _value && | |
234 | + _value.length > 0 && | |
235 | + _value.length !== allValues.current.length, | |
236 | + checkAll: _value && _value.length === allValues.current.length, | |
237 | + }); | |
238 | + } | |
239 | + onChange && onChange(_value); | |
268 | 240 | } |
269 | - onChange && onChange(_value); | |
270 | - }, [staffIdList]); | |
241 | + }, [allValues.current]); | |
271 | 242 | |
272 | 243 | const _onChange: ( |
273 | 244 | _value: LabelValueType[], |
... | ... | @@ -293,7 +264,7 @@ export default function MemberSelect({ |
293 | 264 | })); |
294 | 265 | onChange && onChange(_val); |
295 | 266 | } else { |
296 | - onChange && onChange(ids); | |
267 | + onChange && onChange(ids as (LabelValueType | number)[]); | |
297 | 268 | } |
298 | 269 | } else { |
299 | 270 | let _val: any = _value; |
... | ... | @@ -308,7 +279,7 @@ export default function MemberSelect({ |
308 | 279 | _val = (_value && _value.value) || undefined; |
309 | 280 | } |
310 | 281 | // @ts-ignore |
311 | - onChange && onChange(_val); | |
282 | + onChange && onChange([_val]); | |
312 | 283 | } |
313 | 284 | }; |
314 | 285 | |
... | ... | @@ -325,7 +296,10 @@ export default function MemberSelect({ |
325 | 296 | // @ts-ignore |
326 | 297 | label: staff.staffName, |
327 | 298 | })) |
328 | - : allValues.current.map((_v) => _v.value) | |
299 | + : (allValues.current.map((_v) => _v.value) as ( | |
300 | + | LabelValueType | |
301 | + | number | |
302 | + )[]) | |
329 | 303 | : [] |
330 | 304 | ); |
331 | 305 | }; |
... | ... | @@ -388,6 +362,7 @@ export default function MemberSelect({ |
388 | 362 | // multiple={multiple} |
389 | 363 | treeCheckable={multiple} |
390 | 364 | // showCheckedStrategy={multiple ? TreeSelect.SHOW_PARENT : TreeSelect.SHOW_CHILD} |
365 | + loading={postShopStaffInitail.loading || shopPostStaffInitail.loading} | |
391 | 366 | allowClear |
392 | 367 | labelInValue |
393 | 368 | placeholder="请选择人员或输入关键字筛选" | ... | ... |
src/components/PositionSelector/AMapLoader.tsx
0 → 100644
1 | +import React, { useEffect, useLayoutEffect, useRef, useState } from "react"; | |
2 | +import AMapLoader from "@amap/amap-jsapi-loader"; | |
3 | +import styles from "./MapModal.less"; | |
4 | +import { Col, Divider, Input, message, Modal, Row } from 'antd'; | |
5 | + | |
6 | +interface Props { | |
7 | + info: any, | |
8 | + visible: boolean, | |
9 | + cancel: () => void, | |
10 | + ok: (value: any) => void, | |
11 | +} | |
12 | +function App(props: Props) { | |
13 | + const { info, visible, cancel, ok } = props; | |
14 | + const map = useRef<any>(null); | |
15 | + const marker = useRef<any>(null); | |
16 | + const [currentPoint, setCurrentPoint] = useState({...info}); | |
17 | + | |
18 | + useLayoutEffect(() => { | |
19 | + mapinit(); | |
20 | + return () => { | |
21 | + map?.current?.destroy(); | |
22 | + marker.current=null; | |
23 | + }; | |
24 | + }, []); | |
25 | + | |
26 | + function mapinit() { | |
27 | + if (map.current) { | |
28 | + return; | |
29 | + } | |
30 | + AMapLoader.load({ | |
31 | + key: "438e704a19d6259e1dce9ada54c02b21", // 申请好的Web端开发者Key,首次调用 load 时必填 | |
32 | + version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15 | |
33 | + plugins: ["AMap.Geolocation", "AMap.AutoComplete", "AMap.PlaceSearch", "AMap.Geocoder"], // 需要使用的的插件列表,如比例尺'AMap.Scale'等 | |
34 | + }) | |
35 | + .then((AMap) => { | |
36 | + const {lng, lat }=currentPoint.point || {}; | |
37 | + map.current = new AMap.Map("container", { | |
38 | + viewMode: "3D", //是否为3D地图模式 | |
39 | + zoom: 14, //初始化地图级别 | |
40 | + center: lng? [lng, lat] : [116.4035, 39.928216], //初始化地图中心点位置 | |
41 | + }); | |
42 | + marker.current = new AMap.Marker({ | |
43 | + position: lng && lat? new AMap.LngLat(lng, lat): null, | |
44 | + draggable: true, | |
45 | + }); | |
46 | + map?.current?.add(marker.current); | |
47 | + marker.current.on("dragend", (result: any) => { | |
48 | + const { lnglat } = result; | |
49 | + map.current.panTo(lnglat); //地图中心移动 | |
50 | + getLocation(lnglat); | |
51 | + }); | |
52 | + // 地图图块加载完成后触发 | |
53 | + geo(AMap); | |
54 | + search(AMap); | |
55 | + }) | |
56 | + .catch((e) => { | |
57 | + console.log(e); | |
58 | + }); | |
59 | + } | |
60 | + | |
61 | + const search = (AMap: any) => { | |
62 | + const auto = new AMap.AutoComplete({ | |
63 | + input: "tipinput", | |
64 | + map: map.current | |
65 | + }); | |
66 | + const placeSearch = new AMap.PlaceSearch({ }); //构造地点查询类 | |
67 | + auto.on("select", select);//注册监听,当选中某条记录时会触发 | |
68 | + auto.on("error", (e: any) => { message.info(e); });//注册监听,当选中某条记录时会触发 | |
69 | + // auto.on("choose", select);//注册监听,当选中某条记录时会触发 | |
70 | + function select(e: any) { | |
71 | + const info= { point: e.poi.location, address: e.poi.name }; | |
72 | + info.point && getLocation(info.point, info.address); | |
73 | + placeSearch.setCity(e.poi.adcode); | |
74 | + placeSearch.search(e.poi.name, (status: any, result: any) => { | |
75 | + if (!info.point && result) { | |
76 | + const pois=result.poiList.pois.length? result.poiList.pois[0] : {}; | |
77 | + info.point=pois.location; | |
78 | + info.address=pois.name; | |
79 | + getLocation(info.point, info.address); | |
80 | + } | |
81 | + }); //关键字查询查询 | |
82 | + } | |
83 | + }; | |
84 | + | |
85 | + const geo = (AMap: any) => { | |
86 | + const geolocation = new AMap.Geolocation({ | |
87 | + // 是否使用高精度定位,默认:true | |
88 | + enableHighAccuracy: true, | |
89 | + // 设置定位超时时间,默认:无穷大 | |
90 | + timeout: 20000, | |
91 | + // 定位按钮的停靠位置的偏移量 | |
92 | + offset: [10, 20], | |
93 | + // 定位成功后调整地图视野范围使定位位置及精度范围视野内可见,默认:false | |
94 | + zoomToAccuracy: true, | |
95 | + // 定位按钮的排放位置, RB表示右下 | |
96 | + position: "RB", | |
97 | + }); | |
98 | + map.current?.addControl(geolocation); | |
99 | + map.current.on('click', (ev: any) => { | |
100 | + // 触发事件的地理坐标,AMap.LngLat 类型 | |
101 | + const lnglat = ev.lnglat; | |
102 | + getLocation(lnglat); | |
103 | + }); | |
104 | + | |
105 | + geolocation.getCurrentPosition((status: any, result: any) => { | |
106 | + if (status == "complete") { | |
107 | + if (result?.position) { | |
108 | + map?.current?.setZoom(16); | |
109 | + map?.current?.setCenter(result.position); | |
110 | + getLocation(result.position); | |
111 | + } | |
112 | + } else { | |
113 | + console.log("定位失败:", result); | |
114 | + } | |
115 | + }); | |
116 | + }; | |
117 | + | |
118 | +const getLocation = (point: any, address?: string) => { | |
119 | + marker.current.setPosition(point); | |
120 | + map.current.panTo(point); | |
121 | + if (address) { | |
122 | + setCurrentPoint({ address, point }); | |
123 | + return; | |
124 | + } | |
125 | + const geocoder = new window.AMap.Geocoder({ | |
126 | + // city: "010", //城市设为北京,默认:“全国” | |
127 | + radius: 1000 //范围,默认:500 | |
128 | + }); | |
129 | + const lnglat = [point.lng, point.lat]; | |
130 | + geocoder.getAddress(lnglat, (status: string, result: any) => { | |
131 | + if (status === 'complete' && result.regeocode) { | |
132 | + const address = result.regeocode.formattedAddress; | |
133 | + setCurrentPoint({ | |
134 | + address, | |
135 | + point | |
136 | + }); | |
137 | + } else { | |
138 | + message.info('根据经纬度查询地址失败'); | |
139 | + } | |
140 | + }); | |
141 | + }; | |
142 | + | |
143 | + function onOk() { | |
144 | + const params ={ | |
145 | + address: currentPoint.address, | |
146 | + point: {lat: currentPoint.point.lat, lng: currentPoint.point.lng} | |
147 | + }; | |
148 | + ok && ok(params); | |
149 | + } | |
150 | + | |
151 | +const PositionTxt = () => { | |
152 | + const { address, point } = currentPoint; | |
153 | + | |
154 | + if (!address && !point) { | |
155 | + return <div>定位中...</div>; | |
156 | + } | |
157 | + return ( | |
158 | + <div | |
159 | + style={{ | |
160 | + marginLeft: 16, | |
161 | + lineHeight: "35px", | |
162 | + color: "deepskyblue", | |
163 | + }} | |
164 | + > | |
165 | + <p> | |
166 | + 当前地址:{address} | 当前经纬度:{point ? point.lat : ""},{point ? point.lng : ""} | |
167 | + </p> | |
168 | + </div> | |
169 | + ); | |
170 | +}; | |
171 | + | |
172 | + return ( | |
173 | + <Modal title="选点" visible={visible} onCancel={cancel} onOk={onOk} width="80%" style={{ top: 20 }}> | |
174 | + <Row> | |
175 | + <Col span={8}> | |
176 | + <Input | |
177 | + placeholder="输入位置" | |
178 | + id="tipinput" | |
179 | + allowClear | |
180 | + // value={positionValue} | |
181 | + /> | |
182 | + <div id="searchResultPanel" className={styles.searchResult} /> | |
183 | + </Col> | |
184 | + <Col span={16}> | |
185 | + <PositionTxt /> | |
186 | + </Col> | |
187 | + </Row> | |
188 | + <Divider style={{margin: 0}} /> | |
189 | + <div id="container" className={styles.map} /> | |
190 | + </Modal> | |
191 | + ); | |
192 | +} | |
193 | + | |
194 | +export default App; | ... | ... |
src/components/PositionSelector/MapModal.less
1 | -.searchResult{ | |
2 | - border:1px solid #C0C0C0;width:150px;height:auto; display:none; | |
1 | +.searchResult { | |
2 | + border: 1px solid #C0C0C0; | |
3 | + width: 150px; | |
4 | + height: auto; | |
5 | + display: none; | |
3 | 6 | } |
7 | + | |
4 | 8 | :global(.tangram-suggestion-main) { |
5 | 9 | z-index: 10000; |
6 | 10 | } |
7 | 11 | |
8 | -:global{ | |
9 | - .tangram-suggestion-main{ | |
12 | +:global { | |
13 | + .tangram-suggestion-main { | |
10 | 14 | z-index: 10000; |
11 | 15 | } |
12 | 16 | } |
13 | 17 | |
18 | +.map { | |
19 | + height: 600px; | |
20 | +} | |
14 | 21 | \ No newline at end of file | ... | ... |
src/components/PositionSelector/index.tsx
src/pages/attendance/BlackList/components/Modal.tsx
... | ... | @@ -21,7 +21,7 @@ function CreateModal(props: Props) { |
21 | 21 | useEffect(() => { |
22 | 22 | if (current.id) { |
23 | 23 | form.setFieldsValue({ |
24 | - userName: { label: current.userName, value: current.userId }, | |
24 | + userName: current.userName && current.userId ? [{ label: current.userName, value: current.userId }] : undefined, | |
25 | 25 | startDate: moment(current.startDate), |
26 | 26 | endDate: moment(current.endDate), |
27 | 27 | }); |
... | ... | @@ -33,8 +33,8 @@ function CreateModal(props: Props) { |
33 | 33 | function submit(item: any) { |
34 | 34 | const params = { |
35 | 35 | id: current.id, |
36 | - userId: item.userName.value, | |
37 | - userName: item.userName.label, | |
36 | + userId: (item.userName || [])[0]?.value, | |
37 | + userName: (item.userName || [])[0]?.label, | |
38 | 38 | startDate: item.startDate.valueOf(), |
39 | 39 | endDate: item.endDate.valueOf() |
40 | 40 | }; | ... | ... |
src/pages/cas/ClaimCheck/subpages/ClaimCheckDetail.tsx
... | ... | @@ -85,7 +85,7 @@ export default function ClaimCheckDetail(props: Props) { |
85 | 85 | label: k.shopName, |
86 | 86 | }; |
87 | 87 | }); |
88 | - const _month = newAarray[0].month.map((k: any) => { | |
88 | + const _month = newAarray.length > 0 && newAarray[0].month.map((k: any) => { | |
89 | 89 | return { |
90 | 90 | value: k, |
91 | 91 | label: moment(k).format("YYYY年MM月"), |
... | ... | @@ -137,12 +137,14 @@ export default function ClaimCheckDetail(props: Props) { |
137 | 137 | label: k.shopName, |
138 | 138 | }; |
139 | 139 | }); |
140 | - const _month = newAarray[0].month.map((k:any) => { | |
141 | - return { | |
142 | - value: k, | |
143 | - label: moment(k).format('YYYY年MM月'), | |
144 | - }; | |
145 | - }); | |
140 | + const _month = | |
141 | + newAarray.length > 0 && | |
142 | + newAarray[0].month.map((k: any) => { | |
143 | + return { | |
144 | + value: k, | |
145 | + label: moment(k).format("YYYY年MM月"), | |
146 | + }; | |
147 | + }); | |
146 | 148 | return { |
147 | 149 | ...e, |
148 | 150 | apportion: newAarray, | ... | ... |
src/pages/cas/ClaimCheck/subpages/components/UploadExcel.tsx
src/pages/cas/MaintenanceCard/Upsert/EngineOilSelector/index.tsx
... | ... | @@ -19,7 +19,7 @@ export interface Props { |
19 | 19 | |
20 | 20 | function EngineOilSelector(props: Props) { |
21 | 21 | const { value = [], onChange, disabled, hasRecommendSwitch, priceType, brandId, oringPriceType } = props; |
22 | - console.log('vvv', value) | |
22 | + console.log('vvv', value); | |
23 | 23 | const [visible, setVisible] = useState<boolean>(false); |
24 | 24 | const [oilData, setOilData] = useState<any>({ visible: false, data: {} }); |
25 | 25 | const [current, setCurrent] = useState({} as Maintain.oilGroup); |
... | ... | @@ -43,11 +43,19 @@ function EngineOilSelector(props: Props) { |
43 | 43 | setEditingKey(''); |
44 | 44 | } |
45 | 45 | |
46 | - async function save(key: React.Key) { | |
46 | + async function save(record: any) { | |
47 | 47 | try { |
48 | 48 | const row = (await form.validateFields()) as OilItem; |
49 | 49 | const newData = [...value]; |
50 | - const index = newData.findIndex(item => key === item.oilBrandId); | |
50 | + const _items = value; | |
51 | + const index = _items.findIndex( | |
52 | + (e) => e.oilBrandId === record.oilBrandId && | |
53 | + e.motorOilType === record.motorOilType && | |
54 | + e.oilLevel === record.oilLevel && | |
55 | + e.oilModel === record.oilModel && | |
56 | + e.oilViscosity === record.oilViscosity | |
57 | + ); | |
58 | + // const index = newData.findIndex((item) => key === item.oilBrandId); | |
51 | 59 | if (index > -1) { |
52 | 60 | const item = newData[index]; |
53 | 61 | newData.splice(index, 1, { |
... | ... | @@ -58,9 +66,9 @@ function EngineOilSelector(props: Props) { |
58 | 66 | newData.push(row); |
59 | 67 | } |
60 | 68 | onChange && onChange(newData); |
61 | - setEditingKey(''); | |
69 | + setEditingKey(""); | |
62 | 70 | } catch (errInfo) { |
63 | - console.log('Validate Failed:', errInfo); | |
71 | + console.log("Validate Failed:", errInfo); | |
64 | 72 | } |
65 | 73 | } |
66 | 74 | |
... | ... | @@ -198,7 +206,7 @@ function EngineOilSelector(props: Props) { |
198 | 206 | <Button |
199 | 207 | size="small" |
200 | 208 | type="link" |
201 | - onClick={() => save(record.oilBrandId)} | |
209 | + onClick={() => save(record)} | |
202 | 210 | style={{ marginRight: 8 }} |
203 | 211 | > |
204 | 212 | 保存 | ... | ... |
src/pages/cas/afterSaleConfiguration/jobManagement/components/CreateModal.tsx
... | ... | @@ -4,8 +4,9 @@ import { Input, Select, InputNumber, message, Modal, Form, Spin, Radio } from 'a |
4 | 4 | import * as api from '../api'; |
5 | 5 | import CarModal from './CarModal'; |
6 | 6 | import List from './List'; |
7 | -import { getSeriesApi } from "@/common/api"; | |
7 | +import { getSeriesApi, getBrandFilterApi } from "@/common/api"; | |
8 | 8 | import useInitial from "@/hooks/useInitail"; |
9 | +import { workTypeEnum } from '@/pages/cas/afterSaleConfiguration/jobManagement/entity'; | |
9 | 10 | |
10 | 11 | const FormItem = Form.Item; |
11 | 12 | const { Option } = Select; |
... | ... | @@ -28,12 +29,17 @@ interface Props { |
28 | 29 | } |
29 | 30 | export default function SaveModal(props: Props) { |
30 | 31 | const [form] = Form.useForm(); |
31 | - const { onCancel, item, brandId, fetchList, brandName } = props; | |
32 | - const { data: specs } = useInitial(getSeriesApi, [], brandId); // 车系数据 | |
32 | + const { onCancel, item, fetchList, brandName } = props; | |
33 | + const [delay, setDelay] = useState(true) | |
34 | + const [brandId, setBrandId] = useState<any>() | |
35 | + | |
36 | + const { data: specs, setParams, setData } = useInitial(getSeriesApi, [], brandId, delay); // 车系数据 | |
37 | + const {data: brand} = useInitial(getBrandFilterApi, [], {}) // 品牌数据 | |
33 | 38 | const [confirmLoading, setConfirmLoading] = useState<boolean>(false); |
34 | 39 | const [loading, setLoading] = useState(false); |
35 | 40 | const [groupSpec, setGroupSpec] = useState<WorkProject.SpecCode[]>([]); |
36 | 41 | const [current, setCurrent] = useState<any>(); |
42 | + const [workType, setWorkType] = useState<any>(); | |
37 | 43 | |
38 | 44 | const [objVisible, setObjVisible] = useState({seriesVisible: true, carVisible: true}); |
39 | 45 | const [list, setList] = useState<any[]>([]); // 不分整车型号 |
... | ... | @@ -56,6 +62,16 @@ export default function SaveModal(props: Props) { |
56 | 62 | } |
57 | 63 | }, []); |
58 | 64 | |
65 | + const selectSpec = (v: number) => { | |
66 | + if (v) { | |
67 | + setBrandId(v); | |
68 | + setDelay(false); | |
69 | + setParams(v, true); | |
70 | + } else { | |
71 | + setData([]) | |
72 | + } | |
73 | + } | |
74 | + | |
59 | 75 | function _fetchDetail() { |
60 | 76 | setLoading(true); |
61 | 77 | api |
... | ... | @@ -70,6 +86,8 @@ export default function SaveModal(props: Props) { |
70 | 86 | }); |
71 | 87 | const _list = (data && data.specCodes) || []; |
72 | 88 | setList([..._list]); |
89 | + setWorkType(data?.workType); | |
90 | + setBrandId(data?.brandId); | |
73 | 91 | setObjVisible({ |
74 | 92 | seriesVisible: !(data && data.seriesId), |
75 | 93 | carVisible: !(data && data.specCodes), |
... | ... | @@ -83,19 +101,6 @@ export default function SaveModal(props: Props) { |
83 | 101 | }); |
84 | 102 | } |
85 | 103 | |
86 | - /**车辆分组代码查询 */ | |
87 | - // function fetchGroupList() { | |
88 | - // api | |
89 | - // .getGroupSpec(brandId) | |
90 | - // .then((res) => { | |
91 | - // const { data } = res; | |
92 | - // setGroupSpec(data || []); | |
93 | - // }) | |
94 | - // .catch((e) => { | |
95 | - // message.error(e.message); | |
96 | - // }); | |
97 | - // } | |
98 | - | |
99 | 104 | function save(fieldsValue: any) { |
100 | 105 | setConfirmLoading(true); |
101 | 106 | const datas = { |
... | ... | @@ -131,35 +136,6 @@ export default function SaveModal(props: Props) { |
131 | 136 | ); |
132 | 137 | } |
133 | 138 | |
134 | - //根据 车型代码查范围 | |
135 | - // const onSelectCode = (e: any) => { | |
136 | - // const _data = groupSpec.filter((v: any) => v.code === e); | |
137 | - // api | |
138 | - // .getGroupSpecSelectCar(e) | |
139 | - // .then((res) => setScope({ | |
140 | - // hidden: true, | |
141 | - // data: { | |
142 | - // codename: _data.length > 0 ? _data[0].name : e, | |
143 | - // codelength: res.data?.length, | |
144 | - // codedata: res.data || [], | |
145 | - // }, | |
146 | - // }) | |
147 | - // ) | |
148 | - // .catch((err) => message.error(err.message)); | |
149 | - // }; | |
150 | - | |
151 | - // const onChangeFile = (changedFields:FieldData[], allFields:FieldData[]) => { | |
152 | - // const list = allFields.filter((e: FieldData) => e.name[0] == "specGroupCode"); | |
153 | - // if (list[0].value) { | |
154 | - // cons | |
155 | - // api | |
156 | - // .getGroupSpecSelectCar(list[0].value) | |
157 | - // .then((res) => console.log(res)) | |
158 | - // .catch((err) => message.error(err.message)); | |
159 | - // //setScope(true); | |
160 | - // } | |
161 | - // }; | |
162 | - | |
163 | 139 | return ( |
164 | 140 | <Modal |
165 | 141 | title={!item.id ? "新增" : "编辑"} |
... | ... | @@ -189,6 +165,7 @@ export default function SaveModal(props: Props) { |
189 | 165 | placeholder="请选择" |
190 | 166 | // disabled={!!item.id} |
191 | 167 | maxTagTextLength={20} |
168 | + onSelect={(v: any) => setWorkType(v)} | |
192 | 169 | > |
193 | 170 | <Option value={1} key={1}> |
194 | 171 | 机修 |
... | ... | @@ -229,13 +206,33 @@ export default function SaveModal(props: Props) { |
229 | 206 | > |
230 | 207 | <Input placeholder="请输入作业名称" allowClear /> |
231 | 208 | </FormItem> |
232 | - {item.id ? ( | |
209 | + {item.id || | |
210 | + workType == workTypeEnum["机修"] || | |
211 | + workType == workTypeEnum["电器"] || | |
212 | + workType == workTypeEnum["厂家喷漆"] ? ( | |
233 | 213 | <FormItem label="作业代码" name="itemCode"> |
234 | - <Input placeholder="请输入作业代码" allowClear disabled /> | |
214 | + <Input | |
215 | + placeholder="请输入作业代码" | |
216 | + allowClear | |
217 | + disabled={ | |
218 | + !( | |
219 | + workType == workTypeEnum["机修"] || | |
220 | + workType == workTypeEnum["电器"] || | |
221 | + workType == workTypeEnum["厂家喷漆"] | |
222 | + ) | |
223 | + } | |
224 | + /> | |
235 | 225 | </FormItem> |
236 | 226 | ) : null} |
237 | 227 | <FormItem label="品牌" name="brandName"> |
238 | - <Input style={{ width: "60%" }} disabled /> | |
228 | + {/* <Input style={{ width: "60%" }} disabled /> */} | |
229 | + <Select disabled={!!item.id} onChange={selectSpec} allowClear> | |
230 | + {brand.map(e => ( | |
231 | + <Option value={e.id} key={e.id}> | |
232 | + {e.name} | |
233 | + </Option> | |
234 | + ))} | |
235 | + </Select> | |
239 | 236 | </FormItem> |
240 | 237 | <FormItem label="车系" name="series"> |
241 | 238 | <Radio.Group | ... | ... |
src/pages/cas/afterSaleConfiguration/jobManagement/entity.ts
src/pages/cas/afterSaleConfiguration/jobManagement/index.tsx
... | ... | @@ -55,10 +55,10 @@ export default function FactoryList() { |
55 | 55 | } |
56 | 56 | |
57 | 57 | function handleMenuClick(e: any) { |
58 | - const brandName = | |
59 | - e.item.props.children[1].props.props.children[1].props.children; | |
60 | - setBrandName(brandName || ''); | |
61 | - setBrandItem(e.key); | |
58 | + // const brandName = | |
59 | + // e.item.props.children[1].props.props.children[1].props.children; | |
60 | + // setBrandName(brandName || ''); | |
61 | + // setBrandItem(e.key); | |
62 | 62 | setItem({}); |
63 | 63 | setVisibleEdit(true); |
64 | 64 | } |
... | ... | @@ -71,7 +71,7 @@ export default function FactoryList() { |
71 | 71 | onFilter={(value) => setParams({ ...value, current: 1 }, true)} |
72 | 72 | brandList={brand} |
73 | 73 | /> |
74 | - <Dropdown | |
74 | + {/* <Dropdown | |
75 | 75 | overlay={ |
76 | 76 | <Menu onClick={handleMenuClick}> |
77 | 77 | {brand.map((item: WorkProject.optionItem) => ( |
... | ... | @@ -83,7 +83,14 @@ export default function FactoryList() { |
83 | 83 | <Button className={indexS.add} type="primary"> |
84 | 84 | 新增 <DownOutlined /> |
85 | 85 | </Button> |
86 | - </Dropdown> | |
86 | + </Dropdown> */} | |
87 | + <Button | |
88 | + className={indexS.add} | |
89 | + type="primary" | |
90 | + onClick={handleMenuClick} | |
91 | + > | |
92 | + 新增 | |
93 | + </Button> | |
87 | 94 | </div> |
88 | 95 | <Table |
89 | 96 | pagination={paginationConfig} |
... | ... | @@ -95,7 +102,12 @@ export default function FactoryList() { |
95 | 102 | <Column title="作业项代码" dataIndex="itemCode" align="center" /> |
96 | 103 | {/* <Column title="分组代码" dataIndex="specGroupCode" align="center" /> */} |
97 | 104 | <Column title="作业项名称" dataIndex="itemName" align="center" /> |
98 | - <Column title="品牌" dataIndex="brandName" align="center" /> | |
105 | + <Column | |
106 | + title="品牌" | |
107 | + dataIndex="brandName" | |
108 | + align="center" | |
109 | + render={(text) => <span>{text || "--"}</span>} | |
110 | + /> | |
99 | 111 | <Column |
100 | 112 | title="车系" |
101 | 113 | dataIndex="seriesName" |
... | ... | @@ -111,7 +123,9 @@ export default function FactoryList() { |
111 | 123 | type="link" |
112 | 124 | onClick={() => { |
113 | 125 | setSpecVisible(true); |
114 | - const _list = (record.specCodes || []).map((e: any) => ({specCode: e})); | |
126 | + const _list = (record.specCodes || []).map((e: any) => ({ | |
127 | + specCode: e, | |
128 | + })); | |
115 | 129 | setSpecList([..._list]); |
116 | 130 | }} |
117 | 131 | disabled={!(text && text.length > 0)} | ... | ... |
src/pages/cas/workOrder/base/api.ts
... | ... | @@ -6,10 +6,10 @@ type P<T> = http.PromiseResp<T>; |
6 | 6 | //type Page<T> = http.PromisePageResp<T>; |
7 | 7 | |
8 | 8 | export interface Item { |
9 | - id?: number, // 配置id | |
10 | - code?: string //配置项编码 | |
11 | - name?: string //配置项名称 | |
12 | - value?: string //配置项值 | |
9 | + id: number, // 配置id | |
10 | + code: string //配置项编码 | |
11 | + name: string //配置项名称 | |
12 | + value: string //配置项值 | |
13 | 13 | } |
14 | 14 | |
15 | 15 | /**详情*/ | ... | ... |
src/pages/cas/workOrder/base/index.tsx
... | ... | @@ -11,6 +11,7 @@ import { |
11 | 11 | Popconfirm, |
12 | 12 | Row, |
13 | 13 | Select, |
14 | + Col, | |
14 | 15 | } from "antd"; |
15 | 16 | |
16 | 17 | const FormItem = Form.Item; |
... | ... | @@ -21,38 +22,24 @@ const Basic = () => { |
21 | 22 | const { data } = useInitial(API.fetchDetail, [], ""); |
22 | 23 | const [reset, setReset] = useState<boolean>(false); |
23 | 24 | |
24 | - const timeData = Array.from({ length: 28 }, (_, i) => 1 + i); | |
25 | + const timeData = Array.from({ length: 28 }, (_, i) => 1 + i); | |
25 | 26 | |
26 | 27 | useEffect(() => { |
27 | 28 | if (data) { |
28 | - form.setFieldsValue({ | |
29 | - morningShiftPercent: | |
30 | - data.filter((e) => e.code == "part_book_amount").length > 0 | |
31 | - ? data.filter((e) => e.code == "part_book_amount")[0].value | |
32 | - : "", | |
33 | - time: | |
34 | - data.filter((e) => e.code == "claim_review_day").length > 0 | |
35 | - ? { | |
36 | - value: data.filter((e) => e.code == "claim_review_day")[0].value, | |
37 | - lavbel: data.filter((e) => e.code == "claim_review_day")[0].value, | |
38 | - } | |
39 | - : "", | |
40 | - }); | |
29 | + data.map(e => form.setFieldsValue({[e.code]: e.value})); | |
41 | 30 | setReset(false); |
42 | 31 | } |
43 | 32 | }, [data, reset]); |
44 | 33 | |
45 | 34 | function handleOk(feildValue: any) { |
46 | 35 | const list = data.map(e => { |
47 | - if (e.code == "part_book_amount") { | |
48 | - e.value = feildValue.morningShiftPercent; | |
49 | - } | |
50 | - if (e.code == "claim_review_day") { | |
51 | - e.value = feildValue.time.value; | |
36 | + if (feildValue[e.code]) { | |
37 | + e.value = feildValue[e.code] | |
52 | 38 | } |
53 | 39 | return e |
54 | 40 | }) |
55 | 41 | setEdit(false); |
42 | + console.log('first', list) | |
56 | 43 | API.saveApi(list) |
57 | 44 | .then((res) => { |
58 | 45 | setEdit(false); |
... | ... | @@ -81,83 +68,105 @@ const Basic = () => { |
81 | 68 | onFinish={handleOk} |
82 | 69 | onValuesChange={(changeValue, values) => {}} |
83 | 70 | > |
84 | - <div | |
85 | - style={{ display: "flex", flexDirection: "row", flexWrap: "wrap" }} | |
86 | - > | |
87 | - <h2 style={{ width: "100%" }}>常规设置</h2> | |
71 | + <h2 style={{ width: "100%" }}>常规设置</h2> | |
72 | + <Row> | |
88 | 73 | <FormItem |
89 | - label="客户订件金额要求" | |
90 | - name="morningShiftPercent" | |
91 | - rules={[{ required: true, message: "请输入客户订件金额要求" }]} | |
92 | - style={{ width: 500 }} | |
74 | + label="每月索赔复核待办起始日" | |
75 | + name="claim_review_day" | |
76 | + rules={[ | |
77 | + { required: true, message: "请输入每月索赔复核待办起始日" }, | |
78 | + ]} | |
93 | 79 | > |
94 | 80 | <InputNumber |
95 | 81 | disabled={!edit} |
96 | 82 | min={0} |
97 | - formatter={(value) => `${value}%`} | |
98 | - parser={(value: any) => value.replace("%", "")} | |
99 | - style={{ width: 200 }} | |
83 | + max={31} | |
84 | + style={{ width: "200px" }} | |
100 | 85 | /> |
101 | 86 | </FormItem> |
102 | - <FormItem | |
103 | - label="每月索赔复核待办起始日" | |
104 | - name="time" | |
105 | - rules={[ | |
106 | - { | |
107 | - type: "object" as const, | |
108 | - required: true, | |
109 | - message: "请选择每月索赔复核待办起始日", | |
110 | - }, | |
111 | - ]} | |
112 | - style={{ width: 500 }} | |
113 | - > | |
114 | - <Select placeholder="请选择" labelInValue disabled={!edit}> | |
115 | - {timeData.map((d) => ( | |
116 | - <Select.Option key={d} value={d}> | |
117 | - {d} | |
118 | - </Select.Option> | |
119 | - ))} | |
120 | - </Select> | |
121 | - </FormItem> | |
122 | - {/* <h2 style={{ width: "100%" }}>洗车设置</h2> | |
123 | - <FormItem | |
124 | - label="洗车列表" | |
125 | - rules={[ | |
126 | - { | |
127 | - required: true, | |
128 | - min: 1, | |
129 | - message: "洗车列表不能为空", | |
130 | - type: "array", | |
131 | - }, | |
132 | - ]} | |
133 | - shouldUpdate | |
134 | - name="partList" | |
135 | - > | |
136 | - <WashList edit={edit} /> | |
137 | - </FormItem> */} | |
138 | - <Row style={{ width: "100%" }} justify="center"> | |
139 | - {!edit ? ( | |
140 | - <Button type="primary" onClick={handleEdit}> | |
141 | - 编辑 | |
87 | + </Row> | |
88 | + <Row> | |
89 | + <Col span={8}> | |
90 | + <FormItem | |
91 | + label="三包订件金额比例" | |
92 | + name="part_book_claim_amount_rate" | |
93 | + rules={[{ required: true, message: "请输入三包订件金额比例" }]} | |
94 | + > | |
95 | + <InputNumber | |
96 | + disabled={!edit} | |
97 | + min={0} | |
98 | + formatter={(value) => `${value}%`} | |
99 | + parser={(value: any) => value.replace("%", "")} | |
100 | + style={{ width: "200px" }} | |
101 | + /> | |
102 | + </FormItem> | |
103 | + </Col> | |
104 | + <Col span={8} offset={4}> | |
105 | + <FormItem | |
106 | + label="三包订件封顶金额" | |
107 | + name="part_book_claim_amount_max" | |
108 | + rules={[{ required: true, message: "请输入三包订件封顶比例" }]} | |
109 | + > | |
110 | + <InputNumber | |
111 | + disabled={!edit} | |
112 | + min={0} | |
113 | + style={{ width: "200px" }} | |
114 | + /> | |
115 | + </FormItem> | |
116 | + </Col> | |
117 | + </Row> | |
118 | + <Row> | |
119 | + <Col span={8}> | |
120 | + <FormItem | |
121 | + label="自费订件金额比例" | |
122 | + name="part_book_amount_rate" | |
123 | + rules={[{ required: true, message: "请输入自费订件金额比例" }]} | |
124 | + > | |
125 | + <InputNumber | |
126 | + disabled={!edit} | |
127 | + min={0} | |
128 | + formatter={(value) => `${value}%`} | |
129 | + parser={(value: any) => value.replace("%", "")} | |
130 | + style={{ width: "200px" }} | |
131 | + /> | |
132 | + </FormItem> | |
133 | + </Col> | |
134 | + <Col span={8} offset={4}> | |
135 | + <FormItem | |
136 | + label="自费订件封顶金额" | |
137 | + name="part_book_amount_max" | |
138 | + rules={[{ required: true, message: "请输入自费订件封顶金额" }]} | |
139 | + > | |
140 | + <InputNumber | |
141 | + disabled={!edit} | |
142 | + min={0} | |
143 | + style={{ width: "200px" }} | |
144 | + /> | |
145 | + </FormItem> | |
146 | + </Col> | |
147 | + </Row> | |
148 | + <Row style={{ width: "100%" }} justify="center"> | |
149 | + {!edit ? ( | |
150 | + <Button type="primary" onClick={handleEdit}> | |
151 | + 编辑 | |
152 | + </Button> | |
153 | + ) : ( | |
154 | + <div> | |
155 | + <Button type="primary" onClick={form.submit}> | |
156 | + 确定 | |
142 | 157 | </Button> |
143 | - ) : ( | |
144 | - <div> | |
145 | - <Button type="primary" onClick={form.submit}> | |
146 | - 确定 | |
147 | - </Button> | |
148 | - <Popconfirm | |
149 | - title="确定取消?取消将重置数据" | |
150 | - onConfirm={() => { | |
151 | - setReset(true); | |
152 | - setEdit(false); | |
153 | - }} | |
154 | - > | |
155 | - <Button style={{ marginLeft: 60 }}>取消</Button> | |
156 | - </Popconfirm> | |
157 | - </div> | |
158 | - )} | |
159 | - </Row> | |
160 | - </div> | |
158 | + <Popconfirm | |
159 | + title="确定取消?取消将重置数据" | |
160 | + onConfirm={() => { | |
161 | + setReset(true); | |
162 | + setEdit(false); | |
163 | + }} | |
164 | + > | |
165 | + <Button style={{ marginLeft: 60 }}>取消</Button> | |
166 | + </Popconfirm> | |
167 | + </div> | |
168 | + )} | |
169 | + </Row> | |
161 | 170 | </Form> |
162 | 171 | </Card> |
163 | 172 | </PageHeaderWrapper> | ... | ... |
src/pages/crm_new/ClueStoreSetting/components/EditModal.tsx
... | ... | @@ -79,6 +79,14 @@ export default function Index() { |
79 | 79 | }); |
80 | 80 | } |
81 | 81 | |
82 | + /** 计算直接集客厂家下发转化占比 */ | |
83 | + function handleSetFactoryClueConvertRate(value: number = 0) { | |
84 | + const count = currency(100).subtract(value).value; | |
85 | + form.setFieldsValue({ | |
86 | + factoryClueConvertRate: count | |
87 | + }); | |
88 | + } | |
89 | + | |
82 | 90 | function handleResetValue() { |
83 | 91 | form.setFieldsValue({shopList: [], exclusiveClueConvertRate: undefined, factoryClueConvertRate: undefined}); |
84 | 92 | } |
... | ... | @@ -123,6 +131,7 @@ export default function Index() { |
123 | 131 | formatter={value => `${value}%`} |
124 | 132 | precision={2} |
125 | 133 | parser={value => value?.replace('%', '')} |
134 | + onChange={(e) => handleSetFactoryClueConvertRate(e)} | |
126 | 135 | /> |
127 | 136 | </Form.Item> |
128 | 137 | |
... | ... | @@ -139,6 +148,7 @@ export default function Index() { |
139 | 148 | formatter={value => `${value}%`} |
140 | 149 | precision={2} |
141 | 150 | parser={value => value?.replace('%', '')} |
151 | + disabled | |
142 | 152 | /> |
143 | 153 | </Form.Item> |
144 | 154 | ... | ... |
src/pages/crm_new/TargetAndProportion/api.ts
... | ... | @@ -18,6 +18,11 @@ export interface SaveParams { |
18 | 18 | gatherLiveAimDirect?: number // 直播/短视频直接集客目标占比 |
19 | 19 | potentialAim?: number // 潜客转化率 |
20 | 20 | potentialAimExclusive?: number // 集客转潜客占比 |
21 | + directAimRate?: number // 计算线索目标综合达成率 | |
22 | + exclusiveAimRate?: number //计算专属线索目标达成率 | |
23 | + gatherAimManufacturer?: number // 集客目标 厂家下发占比 | |
24 | + gatherAimDirect?: number // 直接集客目标 | |
25 | + potentialAimToShop?: number // 潜客目标 自然到店占比 | |
21 | 26 | } |
22 | 27 | |
23 | 28 | export interface ShopList { | ... | ... |
src/pages/crm_new/TargetAndProportion/components/TargetModal.tsx
... | ... | @@ -51,27 +51,67 @@ export default function Index() { |
51 | 51 | |
52 | 52 | <> |
53 | 53 | <p className={styles.title}>潜客</p> |
54 | - <p className={styles.lineSpace}>月潜客目标中:<span className={styles.textTitle}>集客转潜客占比</span><span className={styles.text}>{renderData(data.data?.potentialAimExclusive)}</span></p> | |
55 | - <p className={styles.lineSpace}>计算月潜客目标:<span className={styles.textTitle}>潜客转化率</span><span className={styles.text}>{renderData(data.data?.potentialAim)}</span></p> | |
56 | - <p className={styles.lineSpace}>计算线索到店目标:<span className={styles.textTitle}>线索到店成交潜客转化率</span><span className={styles.text}>{renderData(data.data?.clueDealAim)}</span></p> | |
54 | + <p className={styles.lineSpace}>月潜客目标中: | |
55 | + <span className={styles.textTitle}>集客转潜客目标占比</span><span className={styles.text}>{renderData(data.data?.potentialAimExclusive)}</span> | |
56 | + <span className={styles.textTitle}>自然到店目标占比</span><span className={styles.text}>{renderData(data.data?.potentialAimToShop)}</span> | |
57 | + </p> | |
58 | + <p className={styles.lineSpace}>计算月潜客目标: | |
59 | + <span className={styles.textTitle}>潜客转化率</span><span className={styles.text}>{renderData(data.data?.potentialAim)}</span> | |
60 | + </p> | |
61 | + <p className={styles.lineSpace}>计算线索到店目标: | |
62 | + <span className={styles.textTitle}>线索到店率</span><span className={styles.text}>{renderData(data.data?.clueDealAim)}</span> | |
63 | + </p> | |
57 | 64 | </> |
58 | 65 | |
59 | 66 | <> |
60 | 67 | <p className={styles.title}>集客</p> |
61 | 68 | <p className={styles.lineSpace}>计算月集客目标:<span className={styles.textTitle}>集客转化率</span><span className={styles.text}>{renderData(data.data?.gatherAim)}</span></p> |
62 | - <p className={styles.lineSpace}>月集客目标中:<span className={styles.textTitle}>专属线索转集客占比</span><span className={styles.text}>{renderData(data.data?.gatherAimExclusive)}</span></p> | |
63 | - <p className={styles.text}>直接集客目标中:<span className={styles.textTitle}>直播/短视频直接集客目标占比</span><span className={styles.text}>{renderData(data.data?.gatherLiveAimDirect)}</span></p> | |
69 | + <p className={styles.lineSpace}>月集客目标: | |
70 | + <span className={styles.textTitle}>专属线索转集客占比</span><span className={styles.text}>{renderData(data.data?.gatherAimExclusive)}</span> | |
71 | + <span className={styles.textTitle}>直接集客目标占比</span><span className={styles.text}>{renderData(data.data?.gatherAimDirect)}</span> | |
72 | + </p> | |
73 | + <Row className={styles.wrap}> | |
74 | + <Col className={styles.wrapItem}><span className={styles.text}>直接集客目标中:</span></Col> | |
75 | + <Col className={styles.wrapItem}> | |
76 | + <p className={styles.lineSpace}> | |
77 | + <span className={styles.textTitle}>直播/短视频直接集客目标占比</span> | |
78 | + <span className={styles.text}>{renderData(data.data?.gatherLiveAimDirect)}</span>; | |
79 | + <span className={styles.textTitle}>定巡展车展目标占比</span> | |
80 | + <span className={styles.text}>{renderData(data.data?.clueAimVisit)}</span> | |
81 | + </p> | |
82 | + <p> | |
83 | + <span className={styles.textTitle}>厂家下发直接集客目标占比</span> | |
84 | + <span className={styles.text}>{renderData(data.data?.gatherAimManufacturer)}</span> | |
85 | + </p> | |
86 | + </Col> | |
87 | + </Row> | |
64 | 88 | </> |
65 | 89 | |
66 | 90 | <> |
67 | 91 | <p className={styles.title}>线索</p> |
68 | 92 | <p className={styles.text}>计算线索目标:<span className={styles.textTitle}>专属线索转化率</span><span className={styles.text}>{renderData(data.data?.clueAimExclusive)}</span></p> |
69 | 93 | <Row className={styles.wrap}> |
70 | - <Col className={styles.wrapItem}><span className={styles.text}>线索目标占比设置:</span></Col> | |
94 | + <Col className={styles.wrapItem}><span className={styles.text}>专属线索目标占比设置:</span></Col> | |
95 | + <Col className={styles.wrapItem}> | |
96 | + <p className={styles.lineSpace}> | |
97 | + <span className={styles.textTitle}>厂家下发线索目标占比</span> | |
98 | + <span className={styles.text}>{renderData(data.data?.clueAimManufacturer)};</span> | |
99 | + <span className={styles.textTitle}>经纪人推荐目标占比</span> | |
100 | + <span className={styles.text}>{renderData(data.data?.clueAimBroker)}</span> | |
101 | + </p> | |
102 | + <p> | |
103 | + <span className={styles.textTitle}>保有客推荐目标占比</span> | |
104 | + <span className={styles.text}>{renderData(data.data?.clueAimCas)};</span> | |
105 | + <span className={styles.textTitle}>员工推荐目标占比</span> | |
106 | + <span className={styles.text}>{renderData(data.data?.clueAimStaff)}</span> | |
107 | + </p> | |
108 | + </Col> | |
109 | + </Row> | |
110 | + <Row className={styles.wrap}> | |
111 | + <Col className={styles.wrapItem}><span className={styles.text}>计算线索目标综合达成率:</span></Col> | |
71 | 112 | <Col className={styles.wrapItem}> |
72 | - <p className={styles.lineSpace}><span className={styles.textTitle}>厂家下发线索目标占比</span><span className={styles.text}>{renderData(data.data?.clueAimManufacturer)}</span>;<span className={styles.textTitle}>经纪人推荐目标占比</span><span className={styles.text}>{renderData(data.data?.clueAimBroker)}</span></p> | |
73 | - <p><span className={styles.textTitle}>保有客推荐目标占比</span><span className={styles.text}>{renderData(data.data?.clueAimCas)}</span>;<span className={styles.textTitle}>员工推荐目标占比</span><span className={styles.text}>{renderData(data.data?.clueAimStaff)}</span></p> | |
74 | - <p><span className={styles.textTitle}>定巡展车展目标占比</span><span className={styles.text}>{renderData(data.data?.clueAimVisit)}</span></p> | |
113 | + <p className={styles.lineSpace}><span className={styles.textTitle}>直接集客目标达成率:权重</span><span className={styles.text}>{renderData(data.data?.directAimRate)}</span></p> | |
114 | + <p><span className={styles.textTitle}>专属线索目标达成率:权重</span><span className={styles.text}>{renderData(data.data?.exclusiveAimRate)}</span></p> | |
75 | 115 | </Col> |
76 | 116 | </Row> |
77 | 117 | </> | ... | ... |
src/pages/crm_new/TargetAndProportion/subpages/AddNewSetting/index.tsx
... | ... | @@ -21,7 +21,7 @@ export default function ApplyModal() { |
21 | 21 | const [loading, setLoading] = useState<boolean>(false); |
22 | 22 | const [disabledShopIds, setDisabledShopIds] = useState<number[]>([]); |
23 | 23 | const [pageLoading, setPageLoading] = useState<boolean>(false); |
24 | - const tip = "厂家下发线索目标占比+经纪人推荐目标占比+保有客推荐目标占比+员工推荐目标占比+定巡展车展目标占比之和需等于100"; | |
24 | + const tip = "厂家下发线索目标占比+经纪人推荐目标占比+保有客推荐目标占比+员工推荐目标占比之和需等于100!"; | |
25 | 25 | |
26 | 26 | useEffect(() => { |
27 | 27 | handleData(); |
... | ... | @@ -50,7 +50,7 @@ export default function ApplyModal() { |
50 | 50 | } |
51 | 51 | |
52 | 52 | function handleInitail(data: any = {}) { |
53 | - const {clueAimExclusive=0, clueAimManufacturer=0, clueAimBroker=0, clueAimCas=0, clueAimStaff=0, gatherAim=0, gatherAimExclusive=0, gatherLiveAimDirect=0, potentialAim=0, potentialAimExclusive=0, clueAimVisit=0, shopList, clueDealAim=0} = data; | |
53 | + const {clueAimExclusive=0, clueAimManufacturer=0, clueAimBroker=0, clueAimCas=0, clueAimStaff=0, gatherAim=0, gatherAimExclusive=0, gatherLiveAimDirect=0, potentialAim=0, potentialAimExclusive=0, clueAimVisit=0, shopList, clueDealAim=0, exclusiveAimRate = 0, directAimRate = 0, potentialAimToShop = 0, gatherAimDirect = 0, gatherAimManufacturer = 0} = data; | |
54 | 54 | form.setFieldsValue({ |
55 | 55 | clueAimExclusive: (clueAimExclusive*100).toFixed(2), |
56 | 56 | clueAimManufacturer: (clueAimManufacturer*100).toFixed(2), |
... | ... | @@ -64,6 +64,11 @@ export default function ApplyModal() { |
64 | 64 | potentialAim: (potentialAim*100).toFixed(2), |
65 | 65 | potentialAimExclusive: (potentialAimExclusive*100).toFixed(2), |
66 | 66 | clueDealAim: (clueDealAim*100).toFixed(2), |
67 | + exclusiveAimRate: (exclusiveAimRate*100).toFixed(2), | |
68 | + directAimRate: (directAimRate*100).toFixed(2), | |
69 | + gatherAimManufacturer: (gatherAimManufacturer*100).toFixed(2), | |
70 | + gatherAimDirect: (gatherAimDirect*100).toFixed(2), | |
71 | + potentialAimToShop: (potentialAimToShop*100).toFixed(2), | |
67 | 72 | shopList: shopList?.map((v:any) => ({label: v.shopName, value: v.shopId})) |
68 | 73 | }); |
69 | 74 | } |
... | ... | @@ -73,12 +78,36 @@ export default function ApplyModal() { |
73 | 78 | const count = currency(params.clueAimManufacturer) |
74 | 79 | .add(params.clueAimBroker) |
75 | 80 | .add(params.clueAimCas) |
76 | - .add(params.clueAimStaff) | |
77 | - .add(params.clueAimVisit).value; | |
78 | - if (count !=100) { | |
81 | + .add(params.clueAimStaff).value; | |
82 | + if (count != 100) { | |
79 | 83 | message.error(tip); |
80 | 84 | return; |
81 | 85 | } |
86 | + | |
87 | + const aimRate = currency(params.directAimRate).add(params.exclusiveAimRate).value; | |
88 | + if (aimRate != 100) { | |
89 | + message.error("直接集客目标达成率:权重+专属线索目标达成率:权重之和需等于100!"); | |
90 | + return; | |
91 | + } | |
92 | + | |
93 | + const potentialCount = currency(params.potentialAimExclusive).add(params.potentialAimToShop).value; | |
94 | + if (potentialCount != 100) { | |
95 | + message.error("集客转潜客目标占比+自然到店目标占比之和需等于100!"); | |
96 | + return; | |
97 | + } | |
98 | + | |
99 | + const gatherCount = currency(params.gatherAimExclusive).add(params.gatherAimDirect).value; | |
100 | + if (gatherCount != 100) { | |
101 | + message.error("专属线索转集客占比+直接集客目标占比之和需等于100!"); | |
102 | + return; | |
103 | + } | |
104 | + | |
105 | + const gatherAimCount = currency(params.gatherLiveAimDirect).add(params.clueAimVisit).add(params.gatherAimManufacturer).value; | |
106 | + if (gatherAimCount !=100) { | |
107 | + message.error("直播/短视频直接集客目标占比+定巡展车展目标占比+厂家下发直接集客目标占比之和需等于100!"); | |
108 | + return; | |
109 | + } | |
110 | + | |
82 | 111 | const shopList = params.shopList.map((v:any) => ({shopName: v.label, shopId: v.value})); |
83 | 112 | const _params: SaveParams = { |
84 | 113 | clueAimExclusive: +(params.clueAimExclusive / 100).toFixed(4), |
... | ... | @@ -93,8 +122,13 @@ export default function ApplyModal() { |
93 | 122 | potentialAim: +(params.potentialAim /100).toFixed(4), |
94 | 123 | potentialAimExclusive: +(params.potentialAimExclusive /100).toFixed(4), |
95 | 124 | clueDealAim: +(params.clueDealAim /100).toFixed(4), |
96 | - shopList, | |
97 | - id, | |
125 | + directAimRate: +(params.directAimRate /100).toFixed(4), | |
126 | + exclusiveAimRate: +(params.exclusiveAimRate / 100).toFixed(4), | |
127 | + gatherAimManufacturer: +(params.gatherAimManufacturer /100).toFixed(4), | |
128 | + gatherAimDirect: +(params.gatherAimDirect / 100).toFixed(4), | |
129 | + potentialAimToShop: +(params.potentialAimToShop / 100).toFixed(4), | |
130 | + shopList, | |
131 | + id, | |
98 | 132 | operationType |
99 | 133 | }; |
100 | 134 | setLoading(true); |
... | ... | @@ -114,6 +148,58 @@ export default function ApplyModal() { |
114 | 148 | history.goBack(); |
115 | 149 | } |
116 | 150 | |
151 | + /** 计算专属线索目标达成率:权重 */ | |
152 | + function handleSetExclusiveAimRate(value: number = 0) { | |
153 | + const count = currency(100).subtract(value).value; | |
154 | + form.setFieldsValue({ | |
155 | + exclusiveAimRate: count | |
156 | + }); | |
157 | + } | |
158 | + | |
159 | + /**计算员工推荐目标占比 */ | |
160 | + function handleClueAimStaff(value: number =0, value2: number = 0, value3: number = 0) { | |
161 | + if (currency(value).add(value2).add(value3).value >= 100) { | |
162 | + form.setFieldsValue({ | |
163 | + clueAimStaff: 0 | |
164 | + }); | |
165 | + return; | |
166 | + } | |
167 | + const count = currency(100).subtract(value).subtract(value2).subtract(value3).value; | |
168 | + form.setFieldsValue({ | |
169 | + clueAimStaff: count | |
170 | + }); | |
171 | + } | |
172 | + | |
173 | + /** 计算厂家下发直接集客目标占比 */ | |
174 | + function handleGatherAimManufacturer(value: number = 0, value1: number = 0) { | |
175 | + if (currency(value).add(value1).value >= 100) { | |
176 | + form.setFieldsValue({ | |
177 | + gatherAimManufacturer: 0 | |
178 | + }); | |
179 | + return; | |
180 | + } | |
181 | + const count = currency(100).subtract(value).subtract(value1).value; | |
182 | + form.setFieldsValue({ | |
183 | + gatherAimManufacturer: count | |
184 | + }); | |
185 | + } | |
186 | + | |
187 | + /*** 计算直接集客目标占比 */ | |
188 | + function handleGatherAimDirect(value: number = 0) { | |
189 | + const count = currency(100).subtract(value).value; | |
190 | + form.setFieldsValue({ | |
191 | + gatherAimDirect: count | |
192 | + }); | |
193 | + } | |
194 | + | |
195 | + /** 计算自然到店目标占比 */ | |
196 | + function handlePotentialAimToShop(value: number = 0) { | |
197 | + const count = currency(100).subtract(value).value; | |
198 | + form.setFieldsValue({ | |
199 | + potentialAimToShop: count | |
200 | + }); | |
201 | + } | |
202 | + | |
117 | 203 | return ( |
118 | 204 | <PageHeaderWrapper loading={pageLoading} title={TitleEnum[operationType]}> |
119 | 205 | <Card> |
... | ... | @@ -152,7 +238,20 @@ export default function ApplyModal() { |
152 | 238 | </Form.Item> */} |
153 | 239 | |
154 | 240 | <Divider orientation="left" orientationMargin="0">潜客</Divider> |
155 | - <Form.Item name="potentialAimExclusive" labelAlign="right" label="月潜客目标中:集客转潜客占比" rules={[{ required: true, message: "请输入大于0的数!" }]}> | |
241 | + | |
242 | + <Form.Item name="potentialAimExclusive" labelAlign="right" label="月潜客目标中:集客转潜客目标占比" rules={[{ required: true, message: "请输入大于0的数!" }]}> | |
243 | + <InputNumber | |
244 | + style={{width: '100%'}} | |
245 | + controls={false} | |
246 | + min={0.01} | |
247 | + max={100} | |
248 | + formatter={value => `${value}%`} | |
249 | + precision={2} | |
250 | + parser={value => value?.replace('%', '')} | |
251 | + onChange={(e) => handlePotentialAimToShop(e)} | |
252 | + /> | |
253 | + </Form.Item> | |
254 | + <Form.Item name="potentialAimToShop" labelAlign="right" label="自然到店目标占比" rules={[{ required: true, message: "请输入大于0的数!" }]}> | |
156 | 255 | <InputNumber |
157 | 256 | style={{width: '100%'}} |
158 | 257 | controls={false} |
... | ... | @@ -161,9 +260,16 @@ export default function ApplyModal() { |
161 | 260 | formatter={value => `${value}%`} |
162 | 261 | precision={2} |
163 | 262 | parser={value => value?.replace('%', '')} |
263 | + disabled | |
164 | 264 | /> |
165 | 265 | </Form.Item> |
166 | - <Form.Item name="potentialAim" labelAlign="right" label="计算月潜客目标:潜客转化率" rules={[{ required: true, message: "请输入大于0的数!" }]}> | |
266 | + | |
267 | + <Form.Item | |
268 | + name="potentialAim" | |
269 | + labelAlign="right" | |
270 | + label="计算月潜客目标:潜客转化率" | |
271 | + rules={[{ required: true, message: "请输入大于0的数!" }]} | |
272 | + > | |
167 | 273 | <InputNumber |
168 | 274 | style={{width: '100%'}} |
169 | 275 | controls={false} |
... | ... | @@ -175,7 +281,7 @@ export default function ApplyModal() { |
175 | 281 | /> |
176 | 282 | </Form.Item> |
177 | 283 | |
178 | - <Form.Item name="clueDealAim" labelAlign="right" label="计算线索到店目标:线索到店成交潜客转化率" rules={[{ required: true, message: "请输入大于0的数!" }]}> | |
284 | + <Form.Item name="clueDealAim" labelAlign="right" label="计算线索到店目标:线索到店率" rules={[{ required: true, message: "请输入大于0的数!" }]}> | |
179 | 285 | <InputNumber |
180 | 286 | style={{width: '100%'}} |
181 | 287 | controls={false} |
... | ... | @@ -199,6 +305,7 @@ export default function ApplyModal() { |
199 | 305 | parser={value => value?.replace('%', '')} |
200 | 306 | /> |
201 | 307 | </Form.Item> |
308 | + | |
202 | 309 | <Form.Item name="gatherAimExclusive" labelAlign="right" label="月集客目标中:专属线索转集客占比" rules={[{ required: true, message: "请输入大于0的数!" }]}> |
203 | 310 | <InputNumber |
204 | 311 | style={{width: '100%'}} |
... | ... | @@ -208,9 +315,10 @@ export default function ApplyModal() { |
208 | 315 | formatter={value => `${value}%`} |
209 | 316 | precision={2} |
210 | 317 | parser={value => value?.replace('%', '')} |
318 | + onChange={(e) => handleGatherAimDirect(e)} | |
211 | 319 | /> |
212 | 320 | </Form.Item> |
213 | - <Form.Item name="gatherLiveAimDirect" labelAlign="right" label="直接集客目标中:直播/短视频直接集客目标占比" rules={[{ required: true, message: "请输入大于0的数!" }]}> | |
321 | + <Form.Item name="gatherAimDirect" labelAlign="right" label="直接集客目标占比" rules={[{ required: true, message: "请输入大于0的数!" }]}> | |
214 | 322 | <InputNumber |
215 | 323 | style={{width: '100%'}} |
216 | 324 | controls={false} |
... | ... | @@ -219,12 +327,70 @@ export default function ApplyModal() { |
219 | 327 | formatter={value => `${value}%`} |
220 | 328 | precision={2} |
221 | 329 | parser={value => value?.replace('%', '')} |
330 | + disabled | |
331 | + /> | |
332 | + </Form.Item> | |
333 | + | |
334 | + <Form.Item | |
335 | + name="gatherLiveAimDirect" | |
336 | + labelAlign="right" | |
337 | + label="直接集客目标中:直播/短视频直接集客目标占比" | |
338 | + rules={[{ required: true, message: "请输入大于0的数!" }]} | |
339 | + > | |
340 | + <InputNumber | |
341 | + style={{width: '100%'}} | |
342 | + controls={false} | |
343 | + min={0.01} | |
344 | + max={100} | |
345 | + formatter={value => `${value}%`} | |
346 | + precision={2} | |
347 | + parser={value => value?.replace('%', '')} | |
348 | + onChange={(e) => handleGatherAimManufacturer(e, form.getFieldValue("clueAimVisit"))} | |
349 | + /> | |
350 | + </Form.Item> | |
351 | + <Form.Item | |
352 | + name="clueAimVisit" | |
353 | + label="定巡展车展目标占比" | |
354 | + labelAlign="right" | |
355 | + rules={[{ required: true, message: "请输入!" }]} | |
356 | + > | |
357 | + <InputNumber | |
358 | + style={{width: '100%'}} | |
359 | + controls={false} | |
360 | + min={0} | |
361 | + max={100} | |
362 | + formatter={value => `${value}%`} | |
363 | + precision={2} | |
364 | + parser={value => value?.replace('%', '')} | |
365 | + onChange={e => handleGatherAimManufacturer(e, form.getFieldValue("gatherLiveAimDirect"))} | |
366 | + /> | |
367 | + </Form.Item> | |
368 | + <Form.Item | |
369 | + name="gatherAimManufacturer" | |
370 | + label="厂家下发直接集客目标占比" | |
371 | + labelAlign="right" | |
372 | + rules={[{ required: true, message: "请输入!" }]} | |
373 | + > | |
374 | + <InputNumber | |
375 | + style={{width: '100%'}} | |
376 | + controls={false} | |
377 | + min={0} | |
378 | + max={100} | |
379 | + formatter={value => `${value}%`} | |
380 | + precision={2} | |
381 | + parser={value => value?.replace('%', '')} | |
382 | + disabled | |
222 | 383 | /> |
223 | 384 | </Form.Item> |
224 | 385 | |
225 | 386 | <Divider orientation="left" orientationMargin="0">线索</Divider> |
226 | 387 | |
227 | - <Form.Item name="clueAimExclusive" labelAlign="right" label="计算线索目标:专属线索转化率" rules={[{ required: true, message: "请输入!" }]}> | |
388 | + <Form.Item | |
389 | + name="clueAimExclusive" | |
390 | + labelAlign="right" | |
391 | + label="计算线索目标:专属线索转化率" | |
392 | + rules={[{ required: true, message: "请输入!" }]} | |
393 | + > | |
228 | 394 | <InputNumber |
229 | 395 | style={{width: '100%'}} |
230 | 396 | controls={false} |
... | ... | @@ -235,10 +401,11 @@ export default function ApplyModal() { |
235 | 401 | parser={value => value?.replace('%', '')} |
236 | 402 | /> |
237 | 403 | </Form.Item> |
404 | + | |
238 | 405 | <Form.Item |
239 | 406 | name="clueAimManufacturer" |
240 | 407 | labelAlign="right" |
241 | - label="线索目标占比设置:厂家下发线索目标占比" | |
408 | + label="专属线索目标占比设置:厂家下发线索目标占比" | |
242 | 409 | rules={[{ required: true, message: "请输入!" }]} |
243 | 410 | > |
244 | 411 | <InputNumber |
... | ... | @@ -249,6 +416,7 @@ export default function ApplyModal() { |
249 | 416 | formatter={value => `${value}%`} |
250 | 417 | precision={2} |
251 | 418 | parser={value => value?.replace('%', '')} |
419 | + onChange={(e) => handleClueAimStaff(e, form.getFieldValue("clueAimCas"), form.getFieldValue("clueAimBroker"))} | |
252 | 420 | /> |
253 | 421 | </Form.Item> |
254 | 422 | <Form.Item |
... | ... | @@ -265,6 +433,7 @@ export default function ApplyModal() { |
265 | 433 | formatter={value => `${value}%`} |
266 | 434 | precision={2} |
267 | 435 | parser={value => value?.replace('%', '')} |
436 | + onChange={(e) => handleClueAimStaff(e, form.getFieldValue("clueAimCas"), form.getFieldValue("clueAimManufacturer"))} | |
268 | 437 | /> |
269 | 438 | </Form.Item> |
270 | 439 | <Form.Item |
... | ... | @@ -281,6 +450,7 @@ export default function ApplyModal() { |
281 | 450 | formatter={value => `${value}%`} |
282 | 451 | precision={2} |
283 | 452 | parser={value => value?.replace('%', '')} |
453 | + onChange={e => handleClueAimStaff(e, form.getFieldValue("clueAimBroker"), form.getFieldValue("clueAimManufacturer"))} | |
284 | 454 | /> |
285 | 455 | </Form.Item> |
286 | 456 | <Form.Item |
... | ... | @@ -297,11 +467,31 @@ export default function ApplyModal() { |
297 | 467 | formatter={value => `${value}%`} |
298 | 468 | precision={2} |
299 | 469 | parser={value => value?.replace('%', '')} |
470 | + disabled | |
300 | 471 | /> |
301 | 472 | </Form.Item> |
473 | + | |
474 | + <p>计算线索目标综合达成率:</p> | |
302 | 475 | <Form.Item |
303 | - name="clueAimVisit" | |
304 | - label="定巡展车展目标占比" | |
476 | + name="directAimRate" | |
477 | + label="直接集客目标达成率:权重" | |
478 | + labelAlign="right" | |
479 | + rules={[{ required: true, message: "请输入!" }]} | |
480 | + > | |
481 | + <InputNumber | |
482 | + style={{width: '100%'}} | |
483 | + controls={false} | |
484 | + min={0} | |
485 | + max={100} | |
486 | + formatter={value => `${value}%`} | |
487 | + precision={2} | |
488 | + parser={value => value?.replace('%', '')} | |
489 | + onChange={(e) => handleSetExclusiveAimRate(e)} | |
490 | + /> | |
491 | + </Form.Item> | |
492 | + <Form.Item | |
493 | + name="exclusiveAimRate" | |
494 | + label="专属线索目标达成率:权重" | |
305 | 495 | labelAlign="right" |
306 | 496 | rules={[{ required: true, message: "请输入!" }]} |
307 | 497 | > |
... | ... | @@ -313,6 +503,7 @@ export default function ApplyModal() { |
313 | 503 | formatter={value => `${value}%`} |
314 | 504 | precision={2} |
315 | 505 | parser={value => value?.replace('%', '')} |
506 | + disabled | |
316 | 507 | /> |
317 | 508 | </Form.Item> |
318 | 509 | </Form> | ... | ... |
src/pages/dalaran/Account/api.ts
... | ... | @@ -145,7 +145,7 @@ export function authorizedReport(params: AccountReportDTO): http.PromiseResp<any |
145 | 145 | * @returns |
146 | 146 | */ |
147 | 147 | export function authorizedAccount(account: string, type: number): http.PromiseResp<string> { |
148 | - return request.get("http_dalaran/account/getCode", { params: { account, type } }); | |
148 | + return request.get("/http_dalaran/account/getCode", { params: { account, type } }); | |
149 | 149 | } |
150 | 150 | |
151 | 151 | export interface LoginParams { |
... | ... | @@ -162,7 +162,7 @@ export interface LoginParams { |
162 | 162 | * @returns |
163 | 163 | */ |
164 | 164 | export function loginAccount(params: LoginParams): http.PromiseResp<String> { |
165 | - return request.post("http_dalaran/account/login", { ...params }, { contentType: "form-urlencoded" }); | |
165 | + return request.post("/http_dalaran/account/login", { ...params }, { contentType: "form-urlencoded" }); | |
166 | 166 | } |
167 | 167 | |
168 | 168 | /** |
... | ... | @@ -172,5 +172,5 @@ export function loginAccount(params: LoginParams): http.PromiseResp<String> { |
172 | 172 | * @returns |
173 | 173 | */ |
174 | 174 | export function exitLogin(account?: string, type?: number): http.PromiseResp<boolean> { |
175 | - return request.put("http_dalaran/account/exit", { account, type }, { contentType: "form-urlencoded" }); | |
175 | + return request.put("/http_dalaran/account/exit", { account, type }, { contentType: "form-urlencoded" }); | |
176 | 176 | } | ... | ... |
src/pages/decoration/deco/DecorationPromotion/DecorateFullFree/components/AddBrand.tsx
1 | 1 | import React, { useEffect, useImperativeHandle, useRef, useState } from "react"; |
2 | -import { Tabs } from "antd"; | |
2 | +import { message, Tabs } from "antd"; | |
3 | 3 | import ShopDetail2 from "./ShopDetail2"; |
4 | 4 | import SearchModal from "./SearchModal"; |
5 | 5 | |
... | ... | @@ -56,6 +56,12 @@ function AddBrand(props: Props) { |
56 | 56 | }; |
57 | 57 | |
58 | 58 | const add = (value: any) => { |
59 | + const _value = panes.findIndex((e) => e.value.value == value.value); | |
60 | + if (_value > -1) { | |
61 | + message.error("该品牌已添加"); | |
62 | + return; | |
63 | + } | |
64 | + setVisible(false); | |
59 | 65 | let tabIndex = newTabIndex; |
60 | 66 | tabIndex++; |
61 | 67 | setNewTabIndex(tabIndex); | ... | ... |
src/pages/decoration/deco/DecorationPromotion/DecorateFullFree/components/AddSerie.tsx
1 | 1 | import React, { useEffect, useState } from "react"; |
2 | -import { Tabs } from "antd"; | |
2 | +import { message, Tabs } from "antd"; | |
3 | 3 | import ShopDetail2 from "./ShopDetail2"; |
4 | 4 | import SearchModal from "./SearchModal"; |
5 | 5 | |
... | ... | @@ -61,6 +61,12 @@ function AddBrand(props: Props) { |
61 | 61 | }; |
62 | 62 | |
63 | 63 | const add = (value: any) => { |
64 | + const _value = panes.findIndex((e) => e.value.seriesId == value.seriesId); | |
65 | + if (_value > -1) { | |
66 | + message.error("该车系已添加"); | |
67 | + return; | |
68 | + } | |
69 | + setVisible(false); | |
64 | 70 | let tabIndex = newTabIndex; |
65 | 71 | tabIndex++; |
66 | 72 | setNewTabIndex(tabIndex); | ... | ... |
src/pages/decoration/deco/DecorationPromotion/DecorateFullFree/components/AddSpec.tsx
1 | 1 | import React, { useEffect, useState } from "react"; |
2 | -import { Tabs } from "antd"; | |
2 | +import { message, Tabs } from "antd"; | |
3 | 3 | import ShopDetail2 from "./ShopDetail2"; |
4 | 4 | import SearchModal from "./SearchModal"; |
5 | 5 | |
... | ... | @@ -61,6 +61,12 @@ function AddBrand(props:Props) { |
61 | 61 | }; |
62 | 62 | |
63 | 63 | const add = (value: any) => { |
64 | + const _value = panes.findIndex((e) => e.value.specId == value.specId); | |
65 | + if (_value > -1) { | |
66 | + message.error("该车型已添加"); | |
67 | + return; | |
68 | + } | |
69 | + setVisible(false); | |
64 | 70 | let tabIndex = newTabIndex; |
65 | 71 | tabIndex++; |
66 | 72 | setNewTabIndex(tabIndex); | ... | ... |
src/pages/decoration/deco/DecorationPromotion/DecorateFullFree/components/Modal.tsx
... | ... | @@ -80,6 +80,9 @@ export default function AddModal(props: Props) { |
80 | 80 | } else { |
81 | 81 | setDiscountList([]); |
82 | 82 | setAllData([]); |
83 | + setBrandData([]); | |
84 | + setSerieseData([]); | |
85 | + setSpecData([]); | |
83 | 86 | setBrandItem({}); |
84 | 87 | setSeriesItem({}); |
85 | 88 | setSpecItem({}); |
... | ... | @@ -268,7 +271,7 @@ export default function AddModal(props: Props) { |
268 | 271 | <span>交</span> |
269 | 272 | <Form.Item |
270 | 273 | name="price" |
271 | - rules={[{ required: true }]} | |
274 | + rules={[{ required: true, message: "请输入" }]} | |
272 | 275 | style={{ display: "block", width: 150, marginInline: 5 }} |
273 | 276 | > |
274 | 277 | <InputNumber /> |
... | ... | @@ -285,7 +288,7 @@ export default function AddModal(props: Props) { |
285 | 288 | <span>抵</span> |
286 | 289 | <Form.Item |
287 | 290 | name="applyPrice" |
288 | - rules={[{ required: true }]} | |
291 | + rules={[{ required: true, message: "请输入" }]} | |
289 | 292 | style={{ |
290 | 293 | display: "block", |
291 | 294 | width: 150, | ... | ... |
src/pages/decoration/deco/DecorationPromotion/DecorateFullFree/components/SearchModal.tsx
... | ... | @@ -55,14 +55,14 @@ async function loadData(selectedOptions: any) { |
55 | 55 | const brand = seriesOptions.find((item: any) => item.value === brandId); |
56 | 56 | setBrandId(brand.value); |
57 | 57 | try { |
58 | - const res: any = await API.getSeriesApi(brandId); | |
58 | + const res: any = await API.getSaleSeries({brandId}); | |
59 | 59 | brand.loaded = true; |
60 | 60 | brand.children = res.data.map((series: any) => ({ |
61 | 61 | value: series.id, |
62 | 62 | title: series.name, |
63 | 63 | isLeaf: true, |
64 | 64 | })); |
65 | - } catch (e) { | |
65 | + } catch (e:any) { | |
66 | 66 | brand.loaded = false; |
67 | 67 | message.error(e.message); |
68 | 68 | } |
... | ... | @@ -98,7 +98,7 @@ async function loadData(selectedOptions: any) { |
98 | 98 | selectable: false, |
99 | 99 | })); |
100 | 100 | } |
101 | - } catch (e) { | |
101 | + } catch (e:any) { | |
102 | 102 | brand.loaded = false; |
103 | 103 | message.error(e.message); |
104 | 104 | } |
... | ... | @@ -106,7 +106,7 @@ async function loadData(selectedOptions: any) { |
106 | 106 | } |
107 | 107 | |
108 | 108 | const onOK = () => { |
109 | - setVisible(false); | |
109 | + // setVisible(false); | |
110 | 110 | if (type === 1) { |
111 | 111 | add(brandValue); |
112 | 112 | } else if (type === 2) { | ... | ... |
src/pages/decoration/parts/DecorationPromotion/DecorateFullFree/components/AddBrand.tsx
1 | 1 | import React, { useEffect, useImperativeHandle, useRef, useState } from "react"; |
2 | -import { Tabs } from "antd"; | |
2 | +import { Tabs, message } from "antd"; | |
3 | 3 | import ShopDetail2 from "./ShopDetail2"; |
4 | 4 | import SearchModal from "./SearchModal"; |
5 | 5 | |
... | ... | @@ -56,6 +56,12 @@ function AddBrand(props: Props) { |
56 | 56 | }; |
57 | 57 | |
58 | 58 | const add = (value: any) => { |
59 | + const _value = panes.findIndex(e => e.value.value == value.value) | |
60 | + if (_value > -1) { | |
61 | + message.error('该品牌已添加'); | |
62 | + return | |
63 | + } | |
64 | + setVisible(false); | |
59 | 65 | let tabIndex = newTabIndex; |
60 | 66 | tabIndex++; |
61 | 67 | setNewTabIndex(tabIndex); | ... | ... |
src/pages/decoration/parts/DecorationPromotion/DecorateFullFree/components/AddSerie.tsx
1 | 1 | import React, { useEffect, useState } from "react"; |
2 | -import { Tabs } from "antd"; | |
2 | +import { message, Tabs } from "antd"; | |
3 | 3 | import ShopDetail2 from "./ShopDetail2"; |
4 | 4 | import SearchModal from "./SearchModal"; |
5 | 5 | |
... | ... | @@ -61,6 +61,12 @@ function AddBrand(props: Props) { |
61 | 61 | }; |
62 | 62 | |
63 | 63 | const add = (value: any) => { |
64 | + const _value = panes.findIndex((e) => e.value.seriesId == value.seriesId); | |
65 | + if (_value > -1) { | |
66 | + message.error("该车系已添加"); | |
67 | + return; | |
68 | + } | |
69 | + setVisible(false); | |
64 | 70 | let tabIndex = newTabIndex; |
65 | 71 | tabIndex++; |
66 | 72 | setNewTabIndex(tabIndex); | ... | ... |
src/pages/decoration/parts/DecorationPromotion/DecorateFullFree/components/AddSpec.tsx
1 | 1 | import React, { useEffect, useState } from "react"; |
2 | -import { Tabs } from "antd"; | |
2 | +import { message, Tabs } from "antd"; | |
3 | 3 | import ShopDetail2 from "./ShopDetail2"; |
4 | 4 | import SearchModal from "./SearchModal"; |
5 | 5 | |
... | ... | @@ -61,6 +61,12 @@ function AddBrand(props:Props) { |
61 | 61 | }; |
62 | 62 | |
63 | 63 | const add = (value: any) => { |
64 | + const _value = panes.findIndex((e) => e.value.specId == value.specId); | |
65 | + if (_value > -1) { | |
66 | + message.error("该车型已添加"); | |
67 | + return; | |
68 | + } | |
69 | + setVisible(false); | |
64 | 70 | let tabIndex = newTabIndex; |
65 | 71 | tabIndex++; |
66 | 72 | setNewTabIndex(tabIndex); | ... | ... |
src/pages/decoration/parts/DecorationPromotion/DecorateFullFree/components/Modal.tsx
... | ... | @@ -80,6 +80,9 @@ export default function AddModal(props: Props) { |
80 | 80 | } else { |
81 | 81 | setDiscountList([]); |
82 | 82 | setAllData([]); |
83 | + setBrandData([]); | |
84 | + setSerieseData([]); | |
85 | + setSpecData([]); | |
83 | 86 | setBrandItem({}); |
84 | 87 | setSeriesItem({}); |
85 | 88 | setSpecItem({}); |
... | ... | @@ -268,7 +271,7 @@ export default function AddModal(props: Props) { |
268 | 271 | <span>交</span> |
269 | 272 | <Form.Item |
270 | 273 | name="price" |
271 | - rules={[{ required: true }]} | |
274 | + rules={[{ required: true, message: "请输入" }]} | |
272 | 275 | style={{ display: "block", width: 150, marginInline: 5 }} |
273 | 276 | > |
274 | 277 | <InputNumber /> |
... | ... | @@ -285,7 +288,7 @@ export default function AddModal(props: Props) { |
285 | 288 | <span>抵</span> |
286 | 289 | <Form.Item |
287 | 290 | name="applyPrice" |
288 | - rules={[{ required: true }]} | |
291 | + rules={[{ required: true, message: "请输入" }]} | |
289 | 292 | style={{ |
290 | 293 | display: "block", |
291 | 294 | width: 150, | ... | ... |
src/pages/decoration/parts/DecorationPromotion/DecorateFullFree/components/SearchModal.tsx
... | ... | @@ -62,7 +62,7 @@ async function loadData(selectedOptions: any) { |
62 | 62 | title: series.name, |
63 | 63 | isLeaf: true, |
64 | 64 | })); |
65 | - } catch (e) { | |
65 | + } catch (e:any) { | |
66 | 66 | brand.loaded = false; |
67 | 67 | message.error(e.message); |
68 | 68 | } |
... | ... | @@ -98,7 +98,7 @@ async function loadData(selectedOptions: any) { |
98 | 98 | selectable: false, |
99 | 99 | })); |
100 | 100 | } |
101 | - } catch (e) { | |
101 | + } catch (e:any) { | |
102 | 102 | brand.loaded = false; |
103 | 103 | message.error(e.message); |
104 | 104 | } |
... | ... | @@ -106,7 +106,7 @@ async function loadData(selectedOptions: any) { |
106 | 106 | } |
107 | 107 | |
108 | 108 | const onOK = () => { |
109 | - setVisible(false); | |
109 | + // setVisible(false); | |
110 | 110 | if (type === 1) { |
111 | 111 | add(brandValue); |
112 | 112 | } else if (type === 2) { | ... | ... |
src/pages/document.ejs
... | ... | @@ -9,11 +9,14 @@ |
9 | 9 | /> |
10 | 10 | <title>霏微汽车服务平台</title> |
11 | 11 | <script src="https://gw.alipayobjects.com/os/antv/pkg/_antv.data-set-0.9.6/dist/data-set.min.js"></script> |
12 | - <script type="text/javascript" src="//api.map.baidu.com/api?v=2.0&ak=1QGwev2yt8kSqNTDDU8gb34gUwRr29AU"></script> | |
13 | 12 | <!--加载鼠标绘制工具--> |
14 | - <script type="text/javascript" src="//api.map.baidu.com/library/DrawingManager/1.4/src/DrawingManager_min.js"></script> | |
15 | - <link rel="stylesheet" href="//api.map.baidu.com/library/DrawingManager/1.4/src/DrawingManager_min.css" /> | |
16 | 13 | <link rel="icon" href="/favicon.png" type="image/x-icon" /> |
14 | + <!-- 高德地图 --> | |
15 | + <script type="text/javascript"> | |
16 | + window._AMapSecurityConfig = { | |
17 | + securityJsCode: '235e8683072929e38b792ded30736d2d', | |
18 | + } | |
19 | + </script> | |
17 | 20 | </head> |
18 | 21 | <body> |
19 | 22 | <noscript>Sorry, we need js to run correctly!</noscript> | ... | ... |
src/pages/ehr/GroupMobileRecord/components/GroupMobileRecordModal.tsx
1 | 1 | /* |
2 | 2 | * @Date: 2021-01-05 14:24:23 |
3 | 3 | * @LastEditors: wangqiang@feewee.cn |
4 | - * @LastEditTime: 2022-07-14 16:30:12 | |
4 | + * @LastEditTime: 2022-11-02 15:17:36 | |
5 | 5 | */ |
6 | 6 | import React, { useEffect, useState } from "react"; |
7 | 7 | import { Form, Input, Modal, message, Select, Switch } from "antd"; |
... | ... | @@ -41,6 +41,27 @@ export default function GroupMobileRecordModal() { |
41 | 41 | currentItem.postList?.length |
42 | 42 | ) |
43 | 43 | ); |
44 | + | |
45 | + // 编辑归属门店时,需要动态查询对应的集团手机号往来单位 | |
46 | + if (currentItem.shopList?.length) { | |
47 | + setTempShopList( | |
48 | + currentItem.shopList.map((shop) => ({ | |
49 | + value: shop.shopId as number, | |
50 | + label: shop.shopName as string, | |
51 | + })) | |
52 | + ); | |
53 | + unitCompanyInitail.setParams( | |
54 | + { | |
55 | + shopIds: currentItem.shopList | |
56 | + ?.map((v) => v.shopId as number) | |
57 | + .join(","), | |
58 | + }, | |
59 | + true | |
60 | + ); | |
61 | + } else { | |
62 | + setTempShopList(undefined); | |
63 | + } | |
64 | + | |
44 | 65 | form.setFieldsValue({ |
45 | 66 | ...currentItem, |
46 | 67 | subject: |
... | ... | @@ -68,6 +89,7 @@ export default function GroupMobileRecordModal() { |
68 | 89 | : undefined, |
69 | 90 | }); |
70 | 91 | } else { |
92 | + setTempShopList(undefined); | |
71 | 93 | form.setFieldsValue({ |
72 | 94 | recording: false, |
73 | 95 | recordingTranslate: false, |
... | ... | @@ -99,9 +121,15 @@ export default function GroupMobileRecordModal() { |
99 | 121 | custodyShopName: val.custodyShop?.label, |
100 | 122 | subjectId: val.subject?.value, |
101 | 123 | subjectName: val.subject?.label, |
102 | - recording: elements.includes("mobile:special-function:edit") ? val.recording : currentItem?.recording, | |
103 | - recordingTranslate: elements.includes("mobile:special-function:edit") ? val.recordingTranslate: currentItem?.recordingTranslate, | |
104 | - businessCard: elements.includes("mobile:special-function:edit") ? val.businessCard : currentItem?.businessCard, | |
124 | + recording: elements.includes("mobile:special-function:edit") | |
125 | + ? val.recording | |
126 | + : currentItem?.recording, | |
127 | + recordingTranslate: elements.includes("mobile:special-function:edit") | |
128 | + ? val.recordingTranslate | |
129 | + : currentItem?.recordingTranslate, | |
130 | + businessCard: elements.includes("mobile:special-function:edit") | |
131 | + ? val.businessCard | |
132 | + : currentItem?.businessCard, | |
105 | 133 | }; |
106 | 134 | saveMobileApi(params) |
107 | 135 | .then((res) => { |
... | ... | @@ -133,6 +161,13 @@ export default function GroupMobileRecordModal() { |
133 | 161 | } else { |
134 | 162 | setTempShopList(undefined); |
135 | 163 | } |
164 | + // 编辑归属门店时,需要动态查询对应的集团手机号往来单位 | |
165 | + unitCompanyInitail.setParams( | |
166 | + { | |
167 | + shopIds: val?.map((v) => v.value as number).join(","), | |
168 | + }, | |
169 | + true | |
170 | + ); | |
136 | 171 | form.setFieldsValue({ custodyShop: undefined }); |
137 | 172 | return val; |
138 | 173 | }; |
... | ... | @@ -147,6 +182,19 @@ export default function GroupMobileRecordModal() { |
147 | 182 | return val; |
148 | 183 | }; |
149 | 184 | |
185 | + const custodyShopChange = (val: LabeledValue) => { | |
186 | + if (!tempShopList?.length && val) { | |
187 | + // 编辑归属门店时,需要动态查询对应的集团手机号往来单位 | |
188 | + unitCompanyInitail.setParams( | |
189 | + { | |
190 | + shopIds: val?.value as string, | |
191 | + }, | |
192 | + true | |
193 | + ); | |
194 | + } | |
195 | + return val; | |
196 | + }; | |
197 | + | |
150 | 198 | return ( |
151 | 199 | <Modal |
152 | 200 | title={`${currentItem ? "编辑" : "添加"}集团手机号备案`} |
... | ... | @@ -247,6 +295,7 @@ export default function GroupMobileRecordModal() { |
247 | 295 | name="custodyShop" |
248 | 296 | label="当前保管门店" |
249 | 297 | rules={[{ required: true, message: "请选择当前保管门店" }]} |
298 | + getValueFromEvent={custodyShopChange} | |
250 | 299 | > |
251 | 300 | <Select |
252 | 301 | allowClear |
... | ... | @@ -283,6 +332,7 @@ export default function GroupMobileRecordModal() { |
283 | 332 | showSearch |
284 | 333 | optionFilterProp="children" |
285 | 334 | getPopupContainer={(triggerNode) => triggerNode.parentNode} |
335 | + loading={unitCompanyInitail.loading} | |
286 | 336 | > |
287 | 337 | {unitCompanyInitail.data.map((company) => ( |
288 | 338 | <Select.Option key={company.id} value={company.id!}> | ... | ... |
src/pages/ehr/GroupMobileRecord/store.ts
1 | 1 | /* |
2 | 2 | * @Date: 2021-01-05 14:24:23 |
3 | 3 | * @LastEditors: wangqiang@feewee.cn |
4 | - * @LastEditTime: 2022-07-12 10:15:14 | |
4 | + * @LastEditTime: 2022-11-02 14:55:55 | |
5 | 5 | */ |
6 | 6 | import usePagination from "@/hooks/usePagination"; |
7 | 7 | import useInitail from "@/hooks/useInitail"; |
8 | 8 | import { useState } from "react"; |
9 | -import { getMobileListApi, getPostListApi, getUnitCompanyListApi } from "./api"; | |
9 | +import { getMobileListApi, getPostListApi } from "./api"; | |
10 | 10 | import { getShopListApi } from "@/pages/ehr/PostSetting/api"; |
11 | -import { getStaffApi } from "@/common/api"; | |
12 | -import useMenuElement from '@/hooks/useMenuElement'; | |
11 | +import { getStaffApi, getUnitCompanyListApi } from "@/common/api"; | |
12 | +import useMenuElement from "@/hooks/useMenuElement"; | |
13 | 13 | |
14 | 14 | export default function useStore() { |
15 | 15 | const { elements } = useMenuElement("groupMobileRecord"); |
... | ... | @@ -19,7 +19,9 @@ export default function useStore() { |
19 | 19 | const { data: shops } = useInitail(getShopListApi, [], {}); |
20 | 20 | const { list: posts } = usePagination(getPostListApi); |
21 | 21 | const staffPagination = usePagination<CommonApi.StaffListVO>(getStaffApi, {}); |
22 | - const unitCompanyInitail = useInitail(getUnitCompanyListApi, [], null); | |
22 | + const unitCompanyInitail = useInitail(getUnitCompanyListApi, [], { | |
23 | + types: '131', // 默认查询 集团手机号往来单位 | |
24 | + }); | |
23 | 25 | const [editSubject, setEditSubject] = useState(false); |
24 | 26 | |
25 | 27 | enum StatusText { | ... | ... |
src/pages/ehr/Insurance/WhiteListAffiliation/components/Modal.tsx
... | ... | @@ -2,7 +2,7 @@ |
2 | 2 | * @Author: wangqiang@feewee.cn |
3 | 3 | * @Date: 2022-04-29 15:12:07 |
4 | 4 | * @LastEditors: wangqiang@feewee.cn |
5 | - * @LastEditTime: 2022-05-12 17:29:30 | |
5 | + * @LastEditTime: 2022-11-05 15:13:40 | |
6 | 6 | */ |
7 | 7 | import React, { useEffect, useState } from "react"; |
8 | 8 | import { Form, Modal, message, Input, Radio, DatePicker, Select } from "antd"; |
... | ... | @@ -44,12 +44,12 @@ export default function WhiteListAffiliationModal() { |
44 | 44 | : undefined, |
45 | 45 | shop: |
46 | 46 | current.shopId && current.shopName |
47 | - ? { value: current.shopId, label: current.shopName } | |
47 | + ? [{ value: current.shopId, label: current.shopName }] | |
48 | 48 | : undefined, |
49 | 49 | flowStaff: current.flowStaff, |
50 | 50 | flowStaffInfo: |
51 | 51 | current.flowStaff && current.flowStaffName && current.flowStaffId |
52 | - ? { label: current.flowStaffName, value: current.flowStaffId } | |
52 | + ? [{ label: current.flowStaffName, value: current.flowStaffId }] | |
53 | 53 | : undefined, |
54 | 54 | }); |
55 | 55 | } |
... | ... | @@ -74,9 +74,13 @@ export default function WhiteListAffiliationModal() { |
74 | 74 | shopName: val.shop?.label, |
75 | 75 | flowStaff: val.flowStaff, |
76 | 76 | flowStaffId: |
77 | - val.flowStaff === false ? undefined : val.flowStaffInfo?.value, | |
77 | + val.flowStaff === false | |
78 | + ? undefined | |
79 | + : (val.flowStaffInfo || [])[0]?.value, | |
78 | 80 | flowStaffName: |
79 | - val.flowStaff === false ? undefined : val.flowStaffInfo?.label, | |
81 | + val.flowStaff === false | |
82 | + ? undefined | |
83 | + : (val.flowStaffInfo || [])[0]?.label, | |
80 | 84 | }; |
81 | 85 | saveWhiteListAffiliationApi(params) |
82 | 86 | .then((res) => { | ... | ... |
src/pages/ehr/StaffCardInfo/components/StaffCardInfoList.tsx
1 | 1 | /* |
2 | 2 | * @Date: 2021-07-13 14:26:59 |
3 | 3 | * @LastEditors: wangqiang@feewee.cn |
4 | - * @LastEditTime: 2022-08-23 16:08:01 | |
4 | + * @LastEditTime: 2022-11-03 15:49:00 | |
5 | 5 | */ |
6 | 6 | import React from "react"; |
7 | 7 | import { Popover, Row, Table } from "antd"; |
... | ... | @@ -50,13 +50,20 @@ export default function StaffCardInfoList() { |
50 | 50 | </span> |
51 | 51 | <br /> |
52 | 52 | <span> |
53 | - <span style={{ color: "#999" }}>门店:</span> | |
53 | + <span style={{ color: "#999" }}>在职门店:</span> | |
54 | 54 | <span style={{ color: "#333" }}> |
55 | 55 | {record.shopName || "--"} |
56 | 56 | </span> |
57 | 57 | </span> |
58 | 58 | <br /> |
59 | 59 | <span> |
60 | + <span style={{ color: "#999" }}>社保公积金门店:</span> | |
61 | + <span style={{ color: "#333" }}> | |
62 | + {record.fundShopName || "--"} | |
63 | + </span> | |
64 | + </span> | |
65 | + <br /> | |
66 | + <span> | |
60 | 67 | <span style={{ color: "#999" }}>手机号:</span> |
61 | 68 | <span style={{ color: "#333" }}>{record.mobile || "--"}</span> |
62 | 69 | </span> |
... | ... | @@ -90,17 +97,51 @@ export default function StaffCardInfoList() { |
90 | 97 | <span style={{ color: "#333" }}>{record.nation || "--"}</span> |
91 | 98 | </span> |
92 | 99 | </Row> |
100 | + <Row> | |
101 | + <span className="span_limit_1"> | |
102 | + <span style={{ color: "#999" }}>岗位:</span> | |
103 | + <span style={{ color: "#333" }}> | |
104 | + {record.postName || "--"} | |
105 | + </span> | |
106 | + </span> | |
107 | + <span className="span_limit_1"> | |
108 | + <span style={{ color: "#999" }}>在职门店:</span> | |
109 | + <span style={{ color: "#333" }}> | |
110 | + {record.shopName || "--"} | |
111 | + </span> | |
112 | + </span> | |
113 | + </Row> | |
114 | + <Row> | |
115 | + <span className="span_limit_1"> | |
116 | + <span style={{ color: "#999" }}>手机号:</span> | |
117 | + <span style={{ color: "#333" }}>{record.mobile || "--"}</span> | |
118 | + </span> | |
119 | + <span className="span_limit_1"> | |
120 | + <span style={{ color: "#999" }}>身份证号:</span> | |
121 | + <span style={{ color: "#333" }}> | |
122 | + {record.idNumber || "--"} | |
123 | + </span> | |
124 | + </span> | |
125 | + </Row> | |
126 | + <Row> | |
127 | + <span className="span_limit_1"> | |
128 | + <span style={{ color: "#999" }}>身份证地址:</span> | |
129 | + <span style={{ color: "#333" }}> | |
130 | + {record.idCardAddress || "--"} | |
131 | + </span> | |
132 | + </span> | |
133 | + <span className="span_limit_1"> | |
134 | + <span style={{ color: "#999" }}>现居地:</span> | |
135 | + <span style={{ color: "#333" }}> | |
136 | + {record.address || "--"} | |
137 | + </span> | |
138 | + </span> | |
139 | + </Row> | |
93 | 140 | <span className="span_limit_1"> |
94 | - <span style={{ color: "#999" }}>岗位:</span> | |
95 | - <span style={{ color: "#333" }}>{record.postName || "--"}</span> | |
96 | - </span> | |
97 | - <span className="span_limit_1"> | |
98 | - <span style={{ color: "#999" }}>门店:</span> | |
99 | - <span style={{ color: "#333" }}>{record.shopName || "--"}</span> | |
100 | - </span> | |
101 | - <span className="span_limit_1"> | |
102 | - <span style={{ color: "#999" }}>手机号:</span> | |
103 | - <span style={{ color: "#333" }}>{record.mobile || "--"}</span> | |
141 | + <span style={{ color: "#999" }}>社保公积金门店:</span> | |
142 | + <span style={{ color: "#333" }}> | |
143 | + {record.fundShopName || "--"} | |
144 | + </span> | |
104 | 145 | </span> |
105 | 146 | </span> |
106 | 147 | </Popover> | ... | ... |
src/pages/ehr/StaffCardInfo/interface.d.ts
1 | 1 | /* |
2 | 2 | * @Date: 2021-09-06 15:09:10 |
3 | 3 | * @LastEditors: wangqiang@feewee.cn |
4 | - * @LastEditTime: 2022-08-23 16:04:48 | |
4 | + * @LastEditTime: 2022-11-03 15:48:11 | |
5 | 5 | */ |
6 | 6 | declare namespace StaffCardInfo { |
7 | 7 | interface QueryParams { |
... | ... | @@ -24,5 +24,9 @@ declare namespace StaffCardInfo { |
24 | 24 | nation?: string; // 民族 |
25 | 25 | sexName?: string; // 性别字符串 男 女 |
26 | 26 | houseTypeName?: string; // 户口性质 |
27 | + idNumber?: string; // 身份证号 | |
28 | + idCardAddress?: string; // 身份证地址 | |
29 | + address?: string; // 现居地 | |
30 | + fundShopName?: string; // 社保公积金门店 | |
27 | 31 | } |
28 | 32 | } |
29 | 33 | \ No newline at end of file | ... | ... |
src/pages/ehr/SubsidyWhite/components/SubsidyWhiteModal.tsx
1 | 1 | /* |
2 | 2 | * @Date: 2021-07-13 14:26:59 |
3 | 3 | * @LastEditors: wangqiang@feewee.cn |
4 | - * @LastEditTime: 2022-05-26 14:33:13 | |
4 | + * @LastEditTime: 2022-11-05 15:20:33 | |
5 | 5 | */ |
6 | 6 | import React, { useEffect, useState } from "react"; |
7 | 7 | import { Form, Modal, message, Input } from "antd"; |
... | ... | @@ -22,7 +22,10 @@ export default function SubsidyWhiteModal() { |
22 | 22 | if (currentItem) { |
23 | 23 | form.setFieldsValue({ |
24 | 24 | ...currentItem, |
25 | - staff: { label: currentItem.staffName, value: currentItem.staffId }, | |
25 | + staff: | |
26 | + currentItem.staffId && currentItem.staffName | |
27 | + ? [{ label: currentItem.staffName, value: currentItem.staffId }] | |
28 | + : undefined, | |
26 | 29 | phoneSubsidy: currentItem.phoneSubsidy || 0, |
27 | 30 | mealSubsidy: currentItem.mealSubsidy || 0, |
28 | 31 | trafficSubsidy: currentItem.trafficSubsidy || 0, |
... | ... | @@ -46,8 +49,8 @@ export default function SubsidyWhiteModal() { |
46 | 49 | console.log("x", val); |
47 | 50 | const params: SubsidyWhite.List = { |
48 | 51 | ...val, |
49 | - staffId: val.staff?.value, | |
50 | - staffName: val.staff?.label, | |
52 | + staffId: (val.staff || [])[0]?.value, | |
53 | + staffName: (val.staff || [])[0]?.label, | |
51 | 54 | id: currentItem ? currentItem.id || undefined : undefined, |
52 | 55 | }; |
53 | 56 | saveSubsidyWhiteApi(params) | ... | ... |
src/pages/mkt/ActivityCreate/ExternalPromotion/components/Menu.tsx
src/pages/mkt/EvaluativeGifts/entity.ts
src/pages/oop/Dealer/Shop/index.tsx
... | ... | @@ -5,7 +5,7 @@ import * as IF from './interface.d'; |
5 | 5 | import styles from './index.less'; |
6 | 6 | import { common } from '@/typing/common'; |
7 | 7 | import { PageHeaderWrapper } from '@ant-design/pro-layout'; |
8 | -import { PlusOutlined } from '@ant-design/icons'; | |
8 | +import { PlusOutlined, DoubleLeftOutlined } from '@ant-design/icons'; | |
9 | 9 | import usePagination from '@/hooks/usePagination'; |
10 | 10 | import * as api from './api'; |
11 | 11 | import _ from 'lodash'; |
... | ... | @@ -63,6 +63,7 @@ export default function Shop(props: common.ConnectProps) { |
63 | 63 | flexDirection: "row", |
64 | 64 | justifyContent: "space-between", |
65 | 65 | alignItems: "center", |
66 | + marginBottom: 10 | |
66 | 67 | }} |
67 | 68 | > |
68 | 69 | <div className={styles.tableListForm}> |
... | ... | @@ -94,16 +95,25 @@ export default function Shop(props: common.ConnectProps) { |
94 | 95 | </Col> |
95 | 96 | </Row> |
96 | 97 | </div> |
97 | - <Button | |
98 | - icon={<PlusOutlined />} | |
99 | - type="primary" | |
100 | - onClick={() => { | |
101 | - setVisible(true); setRecord({}); | |
102 | - }} | |
103 | - style={{ marginBottom: 24 }} | |
104 | - > | |
105 | - 添加门店 | |
106 | - </Button> | |
98 | + <div> | |
99 | + <Button | |
100 | + type="dashed" | |
101 | + icon={<DoubleLeftOutlined />} | |
102 | + onClick={() => history.go(-1)} | |
103 | + style={{ marginRight: 15 }} | |
104 | + > | |
105 | + 返回 | |
106 | + </Button> | |
107 | + <Button | |
108 | + icon={<PlusOutlined />} | |
109 | + type="primary" | |
110 | + onClick={() => { | |
111 | + setVisible(true); setRecord({}); | |
112 | + }} | |
113 | + > | |
114 | + 添加门店 | |
115 | + </Button> | |
116 | + </div> | |
107 | 117 | </div> |
108 | 118 | |
109 | 119 | <Table |
... | ... | @@ -158,7 +168,7 @@ export default function Shop(props: common.ConnectProps) { |
158 | 168 | width={180} |
159 | 169 | title="操作" |
160 | 170 | render={(text: any, record: IF.shopItem) => ( |
161 | - <React.Fragment> | |
171 | + <> | |
162 | 172 | <a |
163 | 173 | href="#" |
164 | 174 | onClick={(e) => { |
... | ... | @@ -177,7 +187,7 @@ export default function Shop(props: common.ConnectProps) { |
177 | 187 | > |
178 | 188 | <a href="">{record.status === 1 ? "禁用" : "启用"}</a> |
179 | 189 | </Popconfirm> |
180 | - </React.Fragment> | |
190 | + </> | |
181 | 191 | )} |
182 | 192 | /> |
183 | 193 | </Table> | ... | ... |
src/pages/oop/Dealer/index.tsx
... | ... | @@ -20,7 +20,7 @@ const Option = Select.Option; |
20 | 20 | function Dealer(props: Props) { |
21 | 21 | // @ts-ignore |
22 | 22 | const { query } = props.location; |
23 | - const { setVisible, setParams, setGroupId, setGroupName } = useStore(); | |
23 | + const { setVisible, setParams, setGroupId, innerParams, setGroupName } = useStore(); | |
24 | 24 | const { groupId } = query; |
25 | 25 | const { groupName } = props.match.params; |
26 | 26 | useEffect(() => { |
... | ... | @@ -30,6 +30,7 @@ function Dealer(props: Props) { |
30 | 30 | |
31 | 31 | const _onChange = _.debounce((parma: any) => { |
32 | 32 | setParams({ ...parma, current: 1 }, true); |
33 | + sessionStorage.setItem('oop_groupDealer_searchParams', JSON.stringify(parma)); | |
33 | 34 | }, 500); |
34 | 35 | |
35 | 36 | return ( |
... | ... | @@ -58,6 +59,7 @@ function Dealer(props: Props) { |
58 | 59 | <Search |
59 | 60 | allowClear |
60 | 61 | enterButton |
62 | + defaultValue={innerParams.name} | |
61 | 63 | placeholder="请输入商家名称" |
62 | 64 | onChange={(e) => _onChange({ name: e.target.value })} |
63 | 65 | onSearch={(value) => _onChange({ name: value })} |
... | ... | @@ -68,7 +70,7 @@ function Dealer(props: Props) { |
68 | 70 | optionFilterProp="children" |
69 | 71 | onChange={(value) => _onChange({ status: value })} |
70 | 72 | placeholder="选择状态" |
71 | - style={{width: 230, marginLeft: 20 }} | |
73 | + style={{ width: 230, marginLeft: 20 }} | |
72 | 74 | defaultValue={1} |
73 | 75 | > |
74 | 76 | <Option key="1" value={1}> | ... | ... |
src/pages/oop/Dealer/store.ts
... | ... | @@ -11,7 +11,8 @@ export default function useStore() { |
11 | 11 | const [groupId, setGroupId] = useState<number>(); |
12 | 12 | const [groupName, setGroupName] = useState<string>(); |
13 | 13 | const [delay, setDelay] = useState<boolean>(true); |
14 | - const pagination = usePagination(api.queryDealer, { groupId }, { delay }); | |
14 | + let cashParams = JSON.parse(sessionStorage.getItem('oop_groupDealer_searchParams') || '{}'); | |
15 | + const pagination = usePagination(api.queryDealer, { groupId, ...cashParams }, { delay }); | |
15 | 16 | |
16 | 17 | useEffect(() => { |
17 | 18 | groupId && fetchBrands(); | ... | ... |
src/pages/oop/Group/store.ts
... | ... | @@ -11,9 +11,10 @@ export default function useStore() { |
11 | 11 | const [brands, setBrands] = useState<group.Brands[]>([]); |
12 | 12 | |
13 | 13 | useEffect(() => { |
14 | - fetchBrands() | |
14 | + fetchBrands(); | |
15 | + sessionStorage.removeItem('oop_groupDealer_searchParams'); | |
15 | 16 | }, []); |
16 | - | |
17 | + | |
17 | 18 | function fetchBrands() { |
18 | 19 | api.queryAllCarBrands().then(res => { |
19 | 20 | setBrands(res.data || []) |
... | ... | @@ -27,7 +28,7 @@ export default function useStore() { |
27 | 28 | setVisible, |
28 | 29 | confirmLoading, |
29 | 30 | setConfirmLoading, |
30 | - record, | |
31 | + record, | |
31 | 32 | SetRecord, |
32 | 33 | brands |
33 | 34 | } | ... | ... |
src/pages/oop/Series/api.ts
... | ... | @@ -37,3 +37,10 @@ export const getAllFactoryApi = (params: Series.factoryVar) => { |
37 | 37 | export const saveCarInfoApi = (params: Series.carInfo): any => { |
38 | 38 | return request.post(`/oop/spec/save`, { ...params }); |
39 | 39 | }; |
40 | + | |
41 | +/** | |
42 | + * @desc 修改车系状态禁用/启用 | |
43 | + */ | |
44 | +export const changeStatusApi = (params: Series.statusInfo): any => { | |
45 | + return request.post(`/oop/erp/series/change/status`, { ...params }); | |
46 | +}; | ... | ... |
src/pages/oop/Series/components/SeriesFilter.tsx
... | ... | @@ -7,7 +7,7 @@ import { Series } from '../interface'; |
7 | 7 | const { Option } = Select; |
8 | 8 | |
9 | 9 | export default function SeriesFilter() { |
10 | - const { setParams, brands, factorys, getFactories } = useStore(); | |
10 | + const { setParams, brands, factorys, getFactories, innerParams } = useStore(); | |
11 | 11 | const [brandId, setBrandId] = useState<number>(); |
12 | 12 | const [factoryId, setFactoryId] = useState<number>(); |
13 | 13 | |
... | ... | @@ -35,17 +35,26 @@ export default function SeriesFilter() { |
35 | 35 | > |
36 | 36 | {brands.map((item: Series.BrandItem) => <Option key={item.id} value={item.id!}>{item.name}</Option>)} |
37 | 37 | </Select> |
38 | - {brandId && <Select | |
39 | - showSearch | |
40 | - optionFilterProp="children" | |
41 | - placeholder="选择厂商" | |
42 | - allowClear | |
43 | - value={factoryId} | |
44 | - onChange={val => { setParams({ factoryId: val, current: 1 }, true); setFactoryId(val ? +val : undefined) }} | |
45 | - style={{ width: 200, marginRight: 10, marginBottom: 10 }} | |
38 | + {brandId && ( | |
39 | + <Select | |
40 | + showSearch | |
41 | + optionFilterProp="children" | |
42 | + placeholder="选择厂商" | |
43 | + allowClear | |
44 | + value={factoryId} | |
45 | + onChange={val => { setParams({ factoryId: val, current: 1 }, true); setFactoryId(val ? +val : undefined) }} | |
46 | + style={{ width: 200, marginRight: 10, marginBottom: 10 }} | |
47 | + > | |
48 | + {factorys.map((item: Series.FactoryItem) => <Option key={item.id} value={item.id!}>{item.name}</Option>)} | |
49 | + </Select> | |
50 | + )} | |
51 | + <Select | |
52 | + onChange={v => setParams({ status: v }, true)} | |
53 | + value={innerParams.status} | |
46 | 54 | > |
47 | - {factorys.map((item: Series.FactoryItem) => <Option key={item.id} value={item.id!}>{item.name}</Option>)} | |
48 | - </Select>} | |
55 | + <Option key={1} value={1}>启用</Option> | |
56 | + <Option key={0} value={0}>禁用</Option> | |
57 | + </Select> | |
49 | 58 | </div> |
50 | - ) | |
59 | + ); | |
51 | 60 | } |
52 | 61 | \ No newline at end of file | ... | ... |
src/pages/oop/Series/components/SeriesList.tsx
1 | -import React from 'react'; | |
2 | -import { Table, Divider } from 'antd'; | |
1 | +import React, { useState } from 'react'; | |
2 | +import { Table, Divider, Switch, message, Popconfirm } from 'antd'; | |
3 | 3 | import { history } from 'umi'; |
4 | 4 | import { useStore } from '../index'; |
5 | 5 | import defaultThum from '@/assets/defaultThum.png'; |
6 | 6 | import style from '../index.less'; |
7 | +import { changeStatusApi } from '../api'; | |
7 | 8 | import { Series } from '../interface'; |
8 | 9 | |
9 | 10 | export default function SeriesList() { |
10 | - const { list, paginationConfig, loading, setVisible, setCurrentItem } = useStore(); | |
11 | - | |
11 | + const { list, paginationConfig, loading, setLoading, setVisible, setCurrentItem } = useStore(); | |
12 | + const [switchLoading, setSwitchLoading]=useState(false); | |
13 | + function onChangeStatus(params: Series.statusInfo) { | |
14 | + setSwitchLoading(true); | |
15 | + changeStatusApi(params).then(res => { | |
16 | + message.success("操作成功"); | |
17 | + setSwitchLoading(false); | |
18 | + setLoading(true); | |
19 | + }).catch((e) => { | |
20 | + message.error(e.message); | |
21 | + setSwitchLoading(false); | |
22 | + }); | |
23 | + } | |
12 | 24 | let columns = [{ |
13 | 25 | title: '编号', |
14 | 26 | dataIndex: 'id', |
... | ... | @@ -31,14 +43,33 @@ export default function SeriesList() { |
31 | 43 | align: "center", |
32 | 44 | render: (val: string) => <img style={{ objectFit: 'cover', width: 60, height: 30 }} src={val ? val : defaultThum} alt="" /> |
33 | 45 | }, { |
46 | + title: '状态', | |
47 | + dataIndex: 'status', | |
48 | + align: "center", | |
49 | + render: (val: string, row: Series.seriesListItem) => ( | |
50 | + <Popconfirm | |
51 | + placement="top" | |
52 | + title={`确认${val ? "禁用" : "启用"}?`} | |
53 | + onConfirm={() => onChangeStatus({ seriesId: row.id, status: !val })} | |
54 | + onCancel={() => setSwitchLoading(false)} | |
55 | + > | |
56 | + <Switch | |
57 | + checkedChildren="启用" | |
58 | + unCheckedChildren="禁用" | |
59 | + defaultChecked={!!val} | |
60 | + loading={switchLoading} | |
61 | + /> | |
62 | + </Popconfirm> | |
63 | + ) | |
64 | + }, { | |
34 | 65 | title: '操作', |
35 | 66 | align: "center", |
36 | 67 | render: (row: Series.seriesListItem) => ( |
37 | - <React.Fragment> | |
68 | + <> | |
38 | 69 | <a onClick={(e) => { e.preventDefault(); setCurrentItem(row); setVisible(true); }}>编辑</a> |
39 | 70 | <Divider type="vertical" /> |
40 | - <a onClick={() => { history.push(`/oop/seriesDetail?id=${row.id}`) }}>详情</a> | |
41 | - </React.Fragment> | |
71 | + <a onClick={() => { history.push(`/oop/seriesDetail?id=${row.id}`); }}>详情</a> | |
72 | + </> | |
42 | 73 | ) |
43 | 74 | }]; |
44 | 75 | ... | ... |
src/pages/oop/Series/index.tsx
src/pages/oop/Series/interface.d.ts
... | ... | @@ -4,6 +4,7 @@ declare namespace Series { |
4 | 4 | interface seriesListParam { |
5 | 5 | name?: string, |
6 | 6 | brandId?: number, |
7 | + status?: number, | |
7 | 8 | factoryId?: number |
8 | 9 | } |
9 | 10 | |
... | ... | @@ -105,4 +106,8 @@ declare namespace Series { |
105 | 106 | srcSpecId: number, |
106 | 107 | specId: number |
107 | 108 | } |
109 | + interface statusInfo { | |
110 | + seriesId: number; //车系ID | |
111 | + status: boolean; | |
112 | + } | |
108 | 113 | } | ... | ... |
src/pages/oop/Series/store.ts
... | ... | @@ -5,7 +5,7 @@ import useInitial from '@/hooks/useInitail'; |
5 | 5 | import { Series } from './interface'; |
6 | 6 | |
7 | 7 | export default function useStore() { |
8 | - const pagination = usePagination(api.seriesListApi, {}); | |
8 | + const pagination = usePagination(api.seriesListApi, { status: 1 }); | |
9 | 9 | const [currentItem, setCurrentItem] = useState<Series.seriesListItem>(); |
10 | 10 | const [visible, setVisible] = useState(false); |
11 | 11 | const { data: brands } = useInitial(api.getAllBrandApi, [], {}); | ... | ... |
src/pages/performance/CompensateGroupConfig/EditComfirm/api.ts
... | ... | @@ -61,7 +61,7 @@ export function queryShopByPost(postId: number): http.PromiseResp<ShopList[]> { |
61 | 61 | } |
62 | 62 | |
63 | 63 | /** |
64 | - * 薪酬组配置指标选择器 | |
64 | + * 薪酬组配置指标选择器(按岗位、门店查询) | |
65 | 65 | * http://testgate.feewee.cn/morax/erp/salary/group/indicator/selector |
66 | 66 | * @param postId |
67 | 67 | * @returns |
... | ... | @@ -71,6 +71,13 @@ export function queryPostIndicatorApi(params?: IndicatorParams): http.PromiseRes |
71 | 71 | } |
72 | 72 | |
73 | 73 | /** |
74 | + * 薪酬组配置指标选择器(所有) | |
75 | + * /erp/salary/group/all-indicator | |
76 | + */ | |
77 | +export function queryIndicatorsApi(): http.PromiseResp<KpiGroupSetteing.IndicatorByPost[]> { | |
78 | + return request.get(`${MORAX_HOST}/erp/salary/group/all-indicator`); | |
79 | +} | |
80 | +/** | |
74 | 81 | * 绩效组保存 |
75 | 82 | * http://testgate.feewee.cn/morax/erp/salary/group/save |
76 | 83 | */ | ... | ... |
src/pages/performance/CompensateGroupConfig/EditComfirm/components/AddIndicatorsModal.tsx
... | ... | @@ -13,17 +13,16 @@ const Option = Select.Option; |
13 | 13 | interface Props { |
14 | 14 | visible: boolean; |
15 | 15 | onCancel: Function; |
16 | - postId?: number; | |
17 | - shopIds?: string; | |
18 | 16 | onOk: (vales: any) => void; |
19 | 17 | currentItem: CompensateConfig.Item; |
20 | 18 | indicatorsList?: any[]; |
19 | + allIndicatorsList?:any[]; | |
21 | 20 | } |
22 | 21 | |
23 | 22 | export default function CreateModal(props: Props) { |
24 | 23 | const [form] = Form.useForm(); |
25 | 24 | const { selectedSalaryIds, setSelectedSalaryIds } = useStore(); |
26 | - const { visible, onCancel, onOk, currentItem, indicatorsList = [] } = props; | |
25 | + const { visible, onCancel, onOk, currentItem, indicatorsList = [], allIndicatorsList=[] } = props; | |
27 | 26 | |
28 | 27 | // 存储选择计算方式 |
29 | 28 | const [calType, setCalType] = useState<number>(); |
... | ... | @@ -34,9 +33,12 @@ export default function CreateModal(props: Props) { |
34 | 33 | |
35 | 34 | useEffect(() => { |
36 | 35 | if (visible && currentItem.salaryProjectId) { |
37 | - // 将表格数据转换成表单数据 | |
36 | + | |
37 | + // console.log("currentItem", currentItem); | |
38 | + | |
38 | 39 | // 当前指标名称 |
39 | - const curIndicator = indicatorsList.find((item) => item.salaryCode === currentItem.salaryProjectCode); | |
40 | + // const curIndicator = indicatorsList.find((item) => item.salaryCode === currentItem.salaryProjectCode)||{}; | |
41 | + const curIndicator = allIndicatorsList.find((item) => item.salaryCode === currentItem.salaryProjectCode) || {}; | |
40 | 42 | setSelectedIndicator(curIndicator.optionalMethods || []); |
41 | 43 | const _res = transformFormData(currentItem); |
42 | 44 | //编辑时存储当前薪酬项目的计算方式 |
... | ... | @@ -78,7 +80,7 @@ export default function CreateModal(props: Props) { |
78 | 80 | }); |
79 | 81 | return detail; |
80 | 82 | } |
81 | - /** 接口返回数据转换成表单数据 */ | |
83 | + | |
82 | 84 | const transformFormData = (currentItem) => { |
83 | 85 | let _settings = currentItem.settings; |
84 | 86 | const salaryProjectName = { |
... | ... | @@ -112,32 +114,19 @@ export default function CreateModal(props: Props) { |
112 | 114 | |
113 | 115 | // 保存Modal |
114 | 116 | function handSubmit(fieldsValue: any) { |
115 | - if (fieldsValue.calMethod === 1) { | |
116 | - // const _result = verifySteps(fieldsValue.settings, fieldsValue.calMethod); | |
117 | - // if (!_result) { | |
118 | - // return; | |
119 | - // } | |
120 | - } | |
121 | - | |
122 | 117 | const pa = transformDTO(fieldsValue); |
123 | - | |
124 | 118 | // 校验标准分不能大于绩效分值 |
125 | 119 | const salaryProjectId = pa.salaryProjectId; |
126 | - // 编辑时,不需要push id | |
127 | 120 | if (!currentItem.salaryProjectId) { |
128 | - //新增 | |
129 | 121 | const tmpIds = [...selectedSalaryIds]; |
130 | 122 | tmpIds.push(salaryProjectId); |
131 | 123 | setSelectedSalaryIds([...tmpIds]); |
132 | 124 | } else { |
133 | - //编辑 | |
134 | 125 | pa.salaryProjectCode = currentItem.salaryProjectCode; |
135 | 126 | pa.salaryProjectId = currentItem.salaryProjectId; |
136 | 127 | pa.salaryProjectName = currentItem.salaryProjectName; |
137 | 128 | pa.id = currentItem.id; |
138 | 129 | } |
139 | - // console.log("新增保存参数:", pa); | |
140 | - // return; | |
141 | 130 | onOk(pa); |
142 | 131 | onCancel && onCancel(); |
143 | 132 | } |
... | ... | @@ -288,7 +277,6 @@ export default function CreateModal(props: Props) { |
288 | 277 | if (_salaryProjectName) { |
289 | 278 | _salaryCode = _salaryProjectName.value; |
290 | 279 | } |
291 | - console.log("_salaryCode", _salaryCode); | |
292 | 280 | if (caculateType === 1) { |
293 | 281 | //星级 |
294 | 282 | return ( | ... | ... |
src/pages/performance/CompensateGroupConfig/EditComfirm/components/IndivatorsTable.tsx
1 | 1 | import React, { useState, useEffect } from "react"; |
2 | 2 | import { Table, Typography, Button, message, Card, Divider, Space } from "antd"; |
3 | 3 | import AddIndicatorsModal from "./AddIndicatorsModal"; |
4 | -import { KpiGroupSetteing } from "@/pages/performance/KpiGroupSetting/interface"; | |
5 | -import LadderTable from "@/pages/performance/KpiGroupSetting/EditComfirm/components/LadderTable"; | |
6 | 4 | import { useStore } from "../index"; |
7 | 5 | import { CompensateConfig } from "@/pages/performance/CompensateGroupConfig/interface"; |
8 | 6 | import { OptionalMethod_Enum } from "../../entity"; |
9 | 7 | import useInitail from "@/hooks/useInitail"; |
10 | -import { queryPostIndicatorApi } from "../api"; | |
8 | +import { queryIndicatorsApi, queryPostIndicatorApi } from "../api"; | |
11 | 9 | |
12 | 10 | interface Props { |
13 | 11 | value?: any[]; |
... | ... | @@ -20,21 +18,15 @@ type Item = CompensateConfig.Item; |
20 | 18 | |
21 | 19 | const IndivatorsTable = ({ value, onChange, postId, shopIds }: Props) => { |
22 | 20 | const [delay, setDelay] = useState(true); |
23 | - const { selectedSalaryIds, setSelectedSalaryIds, readOnly } = useStore(); | |
21 | + const { selectedSalaryIds, readOnly } = useStore(); | |
24 | 22 | const [tableData, setTableData] = useState<Item[]>(value || []); |
25 | - // 添加指标Modal | |
26 | 23 | const [visible, setVisible] = useState(false); |
27 | - // 存储当前编辑数据 | |
28 | 24 | const [currentItem, setCurrentItem] = useState<Item>({}); |
29 | - // 查看得分阶梯 | |
30 | - const [ladderVisible, setladderVisible] = useState(false); | |
31 | - // 查看得分阶梯值 | |
32 | - const [ladderList, setladderList] = useState<KpiGroupSetteing.IndicatorLadders[]>([]); | |
33 | 25 | |
26 | + const { data: allIndicatorsList } = useInitail(queryIndicatorsApi, [], null); | |
34 | 27 | const { |
35 | 28 | data: indicatorsList, |
36 | 29 | setParams, |
37 | - loading, | |
38 | 30 | } = useInitail(queryPostIndicatorApi, [], { postId, shopIds }, delay); |
39 | 31 | |
40 | 32 | useEffect(() => { |
... | ... | @@ -68,7 +60,6 @@ const IndivatorsTable = ({ value, onChange, postId, shopIds }: Props) => { |
68 | 60 | |
69 | 61 | // 编辑 |
70 | 62 | const onEdit = (record: Item) => { |
71 | - console.log("编辑record:", record); | |
72 | 63 | setVisible(true); |
73 | 64 | setCurrentItem({ ...record }); |
74 | 65 | }; |
... | ... | @@ -134,16 +125,13 @@ const IndivatorsTable = ({ value, onChange, postId, shopIds }: Props) => { |
134 | 125 | visible={visible} |
135 | 126 | currentItem={currentItem} |
136 | 127 | onCancel={onCancel} |
137 | - postId={postId} | |
138 | - shopIds={shopIds} | |
139 | 128 | indicatorsList={indicatorsList} |
129 | + allIndicatorsList={allIndicatorsList} | |
140 | 130 | onOk={(values) => { |
141 | - // 新增 push | |
142 | 131 | if (!currentItem.salaryProjectId) { |
143 | 132 | tableData.push(values); |
144 | 133 | onChange && onChange(tableData); |
145 | 134 | } else { |
146 | - // 编辑替换 | |
147 | 135 | const res = tableData.map((item) => |
148 | 136 | item.salaryProjectId === currentItem.salaryProjectId ? { ...values } : item |
149 | 137 | ); | ... | ... |
src/pages/performance/CompensateGroupConfig/EditComfirm/index.tsx
1 | 1 | import React, { useEffect, useState } from "react"; |
2 | -import { Table, Card, Popconfirm, Row, Button, message, Result, Form, Select, Radio, Input } from "antd"; | |
3 | -import { FeeweeFileAccept, FeeweeFileChange, FeeweeFileInit } from "@/utils/getFidFile"; | |
4 | - | |
2 | +import { Card, Popconfirm, Row, Button, message, Result, Form, Select, Radio, Input } from "antd"; | |
3 | +import { FeeweeFileAccept, FeeweeFileChange } from "@/utils/getFidFile"; | |
5 | 4 | import { common } from "@/typing/common"; |
6 | -import { UploadOutlined, PlusOutlined } from "@ant-design/icons"; | |
7 | -import { getFidFile, IMGURL } from "@/utils"; | |
5 | +import { PlusOutlined } from "@ant-design/icons"; | |
6 | +import { IMGURL } from "@/utils"; | |
8 | 7 | import { PageHeaderWrapper } from "@ant-design/pro-layout"; |
9 | 8 | import { createStore } from "@/hooks/moz"; |
10 | -import { UploadChangeParam, UploadFile } from "antd/lib/upload/interface"; | |
11 | 9 | import { history } from "umi"; |
12 | 10 | import store from "./store"; |
13 | -import AddIndicatorsModal from "./components/AddIndicatorsModal"; | |
14 | 11 | import PersonModal from "../components/PersonModal"; |
15 | -import { LabelValueType } from "rc-tree-select/lib/interface"; | |
16 | 12 | import { KpiGroupSetteing } from "@/pages/performance/KpiGroupSetting/interface"; |
17 | -import useInitail from "@/hooks/useInitail"; | |
18 | 13 | import * as api from "./api"; |
19 | 14 | import { ShopList, saveKpiGroupConfig } from "./api"; |
20 | 15 | import IndivatorsTable from "./components/IndivatorsTable"; |
... | ... | @@ -22,23 +17,16 @@ import FeeweeUpload from "@/components/FeeweeUpload"; |
22 | 17 | import { transformDTO, transformFormData } from "../entity"; |
23 | 18 | import moment from "moment"; |
24 | 19 | |
25 | -// 星级数据: | |
26 | -type StartData = KpiGroupSetteing.StartData; | |
27 | 20 | export const { Provider, useStore } = createStore(store); |
28 | 21 | const { Option } = Select; |
29 | 22 | |
30 | 23 | interface Props extends common.ConnectProps {} |
31 | 24 | function Index(props: Props) { |
32 | 25 | const { postList, detailError, configId, setId, data, readOnly, setReadOnly, setSelectedSalaryIds } = useStore(); |
33 | - | |
34 | 26 | const [form] = Form.useForm(); |
35 | 27 | const { match } = props; |
36 | - | |
37 | 28 | const { id, read } = match.params; |
38 | 29 | |
39 | - useEffect(() => { | |
40 | - setReadOnly(read === undefined ? false : read !== "false"); | |
41 | - }, [read]); | |
42 | 30 | // 选择岗位id |
43 | 31 | const [postId, setPostId] = useState<number>(); |
44 | 32 | // 适用门店ids; |
... | ... | @@ -53,6 +41,11 @@ function Index(props: Props) { |
53 | 41 | shopIds: "", |
54 | 42 | }); |
55 | 43 | |
44 | + | |
45 | + useEffect(() => { | |
46 | + setReadOnly(read === undefined ? false : read !== "false"); | |
47 | + }, [read]); | |
48 | + | |
56 | 49 | useEffect(() => { |
57 | 50 | setId(id); |
58 | 51 | }, [id]); |
... | ... | @@ -60,12 +53,10 @@ function Index(props: Props) { |
60 | 53 | // 控制回显 |
61 | 54 | useEffect(() => { |
62 | 55 | if (configId && data) { |
63 | - // 将接口数据转成表单数据 | |
64 | 56 | const res = transformFormData(data); |
65 | 57 | form.setFieldsValue({ |
66 | 58 | ...res, |
67 | 59 | }); |
68 | - // 回显 | |
69 | 60 | if (data.shopIds?.length > 0) { |
70 | 61 | setPersonModal({ |
71 | 62 | postId: data.postId, |
... | ... | @@ -94,7 +85,6 @@ function Index(props: Props) { |
94 | 85 | const _shopIds: number[] = fieldsValue.shop.map((item) => item.value); |
95 | 86 | const res = transformDTO(fieldsValue); |
96 | 87 | const _shopNames = shopList.filter((item) => _shopIds.find((y) => y === item.shopId)).map((i) => i.shopName); |
97 | - | |
98 | 88 | const pa = { ...res, id: configId, shopNames: _shopNames }; |
99 | 89 | setSaveLoading(true); |
100 | 90 | saveKpiGroupConfig(pa) | ... | ... |
src/pages/performance/CompensateGroupConfig/EditComfirm/store.ts
... | ... | @@ -10,10 +10,8 @@ export default function useStore() { |
10 | 10 | const [delay, setDelay] = useState(true); |
11 | 11 | const { data, errMsg: detailError, setParams } = useInitail(api.queryDetailListApi, {}, {}, delay); |
12 | 12 | const [readOnly, setReadOnly] = useState(false); |
13 | - | |
14 | - // 保存已经配置过阶梯的指标的id | |
13 | + | |
15 | 14 | const [selectedSalaryIds, setSelectedSalaryIds] = useState<number[]>([]); |
16 | - // 保存已经配置过的车系id | |
17 | 15 | const [selectedSeriesIds, setSelectedSeriesIds] = useState<number[]>([]); |
18 | 16 | |
19 | 17 | useEffect(() => { | ... | ... |
src/pages/performance/CompensateGroupConfig/components/Filter.tsx
1 | -import React, { useState, useEffect, useCallback } from "react"; | |
2 | -import { Table, Row, Input, Select } from "antd"; | |
1 | +import React from "react"; | |
2 | +import { Row, Select } from "antd"; | |
3 | 3 | import _ from "lodash"; |
4 | 4 | import usePagination from "@/hooks/usePagination"; |
5 | -import { systemListApi } from "@/pages/admin/Privilege/api"; | |
6 | 5 | import { getAllPostListApi, authShopListApi } from "@/common/api"; |
7 | 6 | import useInitial from "@/hooks/useInitail"; |
8 | -import { StatusData } from '@/pages/performance/entity'; | |
7 | +import { StatusData } from "@/pages/performance/entity"; | |
9 | 8 | |
10 | 9 | const { Option } = Select; |
11 | 10 | interface Props { |
12 | 11 | setParams: any; |
13 | - innerParams:any; | |
12 | + innerParams: any; | |
14 | 13 | } |
15 | 14 | |
16 | 15 | export default function Filter({ setParams, innerParams }: Props) { |
17 | - const { list } = usePagination(getAllPostListApi, [], {}); | |
18 | - const { data } = useInitial(authShopListApi, [], {}); | |
19 | - | |
20 | - const seachOnchange = useCallback( | |
21 | - _.debounce((param) => { | |
22 | - setParams({ ...param }, true); | |
23 | - }, 800), | |
24 | - [setParams] | |
25 | - ); | |
16 | + const { list } = usePagination(getAllPostListApi, { pageSize: 999 }); | |
17 | + const { data } = useInitial(authShopListApi, [], ""); | |
26 | 18 | |
27 | 19 | return ( |
28 | 20 | <Row justify="start" style={{ marginBottom: 20 }}> |
... | ... | @@ -64,7 +56,6 @@ export default function Filter({ setParams, innerParams }: Props) { |
64 | 56 | style={{ width: 250, marginRight: 10, marginBottom: 10 }} |
65 | 57 | value={innerParams.status} |
66 | 58 | onChange={(value) => { |
67 | - console.log("选中状态", value); | |
68 | 59 | setParams({ status: value }, true); |
69 | 60 | }} |
70 | 61 | > | ... | ... |
src/pages/performance/CompensateGroupConfig/entity.ts
1 | 1 | import { KpiGroupSetteing } from "@/pages/performance/KpiGroupSetting/interface"; |
2 | -import office from "config/routers/office"; | |
3 | 2 | import _ from "lodash"; |
4 | 3 | |
5 | 4 | // roleType 适用角色类型; 1: 全部角色 2:全部管理角色 3: 自定义(See: 适用角色类型枚举) |
... | ... | @@ -137,12 +136,10 @@ const setMaxValue = (indicators: any[]) => { |
137 | 136 | const _length = item.settings.length; |
138 | 137 | if (_length > 0 && (item.calMethod === 6 || item.calMethod === 3)) { |
139 | 138 | item.settings[_length - 1].stairMax = 65536; |
140 | - // if (item.calMethod === 6 || item.calMethod === 3) { | |
141 | 139 | item.settings.forEach((i, idx) => { |
142 | 140 | item.settings[idx].stairKey = item.salaryProjectId; |
143 | 141 | item.settings[idx].stairKeyDesc = item.salaryProjectName; |
144 | 142 | }); |
145 | - // } | |
146 | 143 | } |
147 | 144 | } |
148 | 145 | }); | ... | ... |
src/pages/pms/comonents/PartModal.tsx
... | ... | @@ -33,7 +33,7 @@ export default function Index({ onCancel, visible, parts=[], onOk }: Props) { |
33 | 33 | } |
34 | 34 | |
35 | 35 | const handleChange = debounce((value) => { |
36 | - setPartList(partList.filter(it => { | |
36 | + setPartList(parts.filter(it => { | |
37 | 37 | return (it.partCode || '').includes(value) |
38 | 38 | || (it.partName || '').includes(value) |
39 | 39 | || (it.supplierName || '').includes(value); |
... | ... | @@ -74,9 +74,9 @@ export default function Index({ onCancel, visible, parts=[], onOk }: Props) { |
74 | 74 | pagination={false} |
75 | 75 | rowSelection={{ |
76 | 76 | type: "checkbox", |
77 | - selectedRowKeys: selectedParts.map(part => part.partCode || ''), | |
77 | + selectedRowKeys: selectedParts.map(part => `${part.partCode}-${part.storageId}`), | |
78 | 78 | onSelect: (row: PartVO, _selected: boolean) => { |
79 | - const index = selectedParts.findIndex(_row => _row.partCode == row.partCode); | |
79 | + const index = selectedParts.findIndex(_row => _row.partCode == row.partCode && _row.storageId == row.storageId); | |
80 | 80 | let newData = [...selectedParts]; |
81 | 81 | if (_selected) { |
82 | 82 | newData.unshift(row); |
... | ... | @@ -86,23 +86,25 @@ export default function Index({ onCancel, visible, parts=[], onOk }: Props) { |
86 | 86 | setSelectedParts([...newData]); |
87 | 87 | }, |
88 | 88 | onSelectAll: (selected, selectedRows, changeRows) => { |
89 | - const changedKeys = changeRows.map(row => row.partCode); | |
89 | + const changedKeys = changeRows.map(row => `${row.partCode}-${row.storageId}`); | |
90 | 90 | let newData = [...selectedParts]; |
91 | 91 | // 全选 |
92 | 92 | if (selected) { |
93 | 93 | // 过滤掉已选的 |
94 | - newData = selectedParts.concat(changeRows.filter(row => !selectedParts.some(item => item.partCode == row.partCode)),); | |
94 | + newData = selectedParts.concat(changeRows.filter(row => !selectedParts.some(item => item.partCode == row.partCode && item.storageId == row.storageId)),); | |
95 | 95 | } else { |
96 | 96 | // 全不选 - 去掉已选的 |
97 | - newData = selectedParts.filter(row => !changedKeys.includes(row.partCode)); | |
97 | + newData = selectedParts.filter(row => !changedKeys.includes(`${row.partCode}-${row.storageId}`)); | |
98 | 98 | } |
99 | 99 | setSelectedParts(newData); |
100 | 100 | }, |
101 | 101 | }} |
102 | - rowKey={(record) => `${record.partCode}`} | |
102 | + rowKey={(record) => `${record.partCode}-${record.storageId}`} | |
103 | 103 | > |
104 | 104 | <Column title="配件编码" dataIndex="partCode" /> |
105 | 105 | <Column title="配件名称" dataIndex="partName" /> |
106 | + <Column title="库房名称" dataIndex="storageName" /> | |
107 | + <Column title="门店名称" dataIndex="shopName" /> | |
106 | 108 | <Column title="配件数量" dataIndex="count" /> |
107 | 109 | <Column title="上次采购供应商" dataIndex="supplierName" /> |
108 | 110 | </Table> | ... | ... |
src/pages/pms/comonents/SupplierModal.tsx
... | ... | @@ -4,7 +4,7 @@ import Column from 'antd/lib/table/Column'; |
4 | 4 | import usePagination from '@/hooks/usePagination'; |
5 | 5 | import {getPageListApi, Item} from "@/pages/pms/partPlan/PlanSupplier/api"; |
6 | 6 | import PartModal from '@/pages/pms/comonents/PartModal'; |
7 | -import {groupBy} from '@/pages/pms/entity'; | |
7 | +import {groupBys} from '@/pages/pms/entity'; | |
8 | 8 | |
9 | 9 | const Option = Select.Option; |
10 | 10 | interface Props { |
... | ... | @@ -27,7 +27,7 @@ export default function Index({ onCancel, brandId, visible, parts = [], onOk, su |
27 | 27 | |
28 | 28 | useEffect(() => { |
29 | 29 | if (visible && parts.length) { |
30 | - const ps: any[] = groupBy(parts, 'partCode'); | |
30 | + const ps: any[] = groupBys(parts, 'partCode', 'storageId'); | |
31 | 31 | setPartData(ps.map(it => ({...it, list: []}))); |
32 | 32 | } |
33 | 33 | }, [visible, parts]); |
... | ... | @@ -96,7 +96,7 @@ export default function Index({ onCancel, brandId, visible, parts = [], onOk, su |
96 | 96 | dataSource={selectedParts} |
97 | 97 | pagination={false} |
98 | 98 | scroll={{y: 600}} |
99 | - rowKey="partCode" | |
99 | + rowKey={(t, _) => `${t.partCode}-${t.storageId}`} | |
100 | 100 | > |
101 | 101 | <Column title="配件编码" dataIndex="partCode" /> |
102 | 102 | <Column title="配件名称" dataIndex="partName" /> |
... | ... | @@ -107,7 +107,7 @@ export default function Index({ onCancel, brandId, visible, parts = [], onOk, su |
107 | 107 | <Column |
108 | 108 | title="操作" |
109 | 109 | render={(text, _item: any) => ( |
110 | - <a onClick={() => setSelectedParts(selectedParts.filter(i => i.partCode != _item.partCode))}> | |
110 | + <a onClick={() => setSelectedParts(selectedParts.filter(i => i.partCode != _item.partCode || i.storageId != _item.storageId))}> | |
111 | 111 | 删除 |
112 | 112 | </a> |
113 | 113 | )} |
... | ... | @@ -116,10 +116,10 @@ export default function Index({ onCancel, brandId, visible, parts = [], onOk, su |
116 | 116 | <PartModal |
117 | 117 | visible={visiblePart} |
118 | 118 | onCancel={() => setVisiblePart(false)} |
119 | - parts={partData.filter(it => !selectedParts.map(i => i.partCode).includes(it.partCode))} | |
119 | + parts={partData.filter(it => !selectedParts.map(i => `${i.partCode}-${i.storageId}`).includes(`${it.partCode}-${it.storageId}`))} | |
120 | 120 | onOk={(ps=[]) => { |
121 | - const ids = [...selectedParts, ...ps].map(it => it.partCode); | |
122 | - setSelectedParts(parts.filter(it => ids.includes(it.partCode))); | |
121 | + const ids = [...selectedParts, ...ps].map(it => `${it.partCode}-${it.storageId}`); | |
122 | + setSelectedParts(parts.filter(it => ids.includes(`${it.partCode}-${it.storageId}`))); | |
123 | 123 | }} |
124 | 124 | /> |
125 | 125 | </Modal> | ... | ... |
src/pages/pms/entity.ts
... | ... | @@ -70,6 +70,19 @@ export function groupBy(list: any[], key: string) { |
70 | 70 | return data; |
71 | 71 | } |
72 | 72 | |
73 | +export function groupBys(list: any[], key1: string, key2: string) { | |
74 | + const data: any[] = []; | |
75 | + for (let listEle of list) { | |
76 | + let item = data.find(i => i[key1] == listEle[key1] && i[key2] == listEle[key2]); | |
77 | + if (!item) { | |
78 | + item = deepClone({...listEle, list: []}); | |
79 | + data.push(item); | |
80 | + } | |
81 | + item.list.push(listEle); | |
82 | + } | |
83 | + return data; | |
84 | +} | |
85 | + | |
73 | 86 | export function numFormat(num: number = 0, unit?: string): string { |
74 | 87 | return (unit == '%' ? num * 100 : unit == '万元' ? num / 10000 : num).toFixed(2); |
75 | 88 | } | ... | ... |
src/pages/pms/partPlan/CustBuyPlan/useStore.ts
... | ... | @@ -39,7 +39,7 @@ export default function useStore() { |
39 | 39 | brandId, |
40 | 40 | suppliers: summarySupplier.map(i => ({ |
41 | 41 | supplierId: i.supplierId, |
42 | - parts: i.parts?.map(i => ({partId: i.partId, count: i.count, storageId: i.storageId})), | |
42 | + parts: i.parts?.map(i => ({partId: i.partId, count: i.count, storageId: i.storageId, waitListIds: i.waitListIds})), | |
43 | 43 | })) |
44 | 44 | }; |
45 | 45 | savePlanApi(pa).then(() => { | ... | ... |
src/pages/pms/partPlan/MinRatioPlan/api.ts
src/pages/pms/storage/partShop/api.ts
... | ... | @@ -42,3 +42,7 @@ export function getLockDetail(params?: PmsStoragePartShop.LockParams): http.Prom |
42 | 42 | export function getFlowDetail(params?: PmsStoragePartShop.FlowParams): http.PromisePageResp<PmsStoragePartShop.FlowVO> { |
43 | 43 | return request.get(`${PMS_HOST}/erp/part/shop/get/record`, { params }); |
44 | 44 | } |
45 | +// 释放库存 | |
46 | +export function unLock(params: PmsStoragePartShop.unLock): http.PromiseResp<string> { | |
47 | + return request.post(`${PMS_HOST}/erp/part/shop/cancel/lock`, { lockId: params.lockId, cancelCnt: params.cancelCnt }, { contentType: "form-urlencoded" }); | |
48 | +} | ... | ... |
src/pages/pms/storage/partShop/components/FlowDetailModal.tsx
1 | 1 | import React, { useEffect, useState } from 'react'; |
2 | 2 | import { Button, Modal, Table } from 'antd'; |
3 | 3 | import { getFlowDetail} from '@/pages/pms/storage/partShop/api'; |
4 | -import {typeReceiverObj, typeSenderObj} from '@/pages/pms/entity'; | |
5 | 4 | import moment from 'moment'; |
6 | 5 | import usePagination from '@/hooks/usePagination'; |
7 | 6 | |
... | ... | @@ -24,7 +23,7 @@ export default function Index({item = {}, visible, onCancel}: Props) { |
24 | 23 | } |
25 | 24 | }, [item, visible]); |
26 | 25 | |
27 | - console.log('item, ', item); | |
26 | + // console.log('item, ', item); | |
28 | 27 | |
29 | 28 | return ( |
30 | 29 | <Modal |
... | ... | @@ -70,8 +69,8 @@ export default function Index({item = {}, visible, onCancel}: Props) { |
70 | 69 | {!!obj.transferUserName && <div>{`调运人员: ${obj.transferUserName}`}</div>} |
71 | 70 | {!!obj.creatTime && <div>{`发起时间: ${moment(obj.creatTime).format('YYYY-MM-DD HH:mm')}`}</div>} |
72 | 71 | |
73 | - {!!obj.receiverName && <div>{`${typeReceiverObj[it.type || '']}顾问: ${obj.receiverName}`}</div>} | |
74 | - {!!obj.senderName && <div>{`${typeSenderObj[it.type || '']}: ${obj.senderName}`}</div>} | |
72 | + {!!obj.receiverName && <div>{`顾问: ${obj.receiverName}`}</div>} | |
73 | + {!!obj.senderName && <div>{`客户: ${obj.senderName}`}</div>} | |
75 | 74 | {!!obj.ownerName && <div>{`车主: ${obj.ownerName}`}</div>} |
76 | 75 | {!!obj.carName && <div>{`车辆: ${obj.carName}`}</div>} |
77 | 76 | {!!obj.vin && <div>{`车架号: ${obj.vin}`}</div>} | ... | ... |
src/pages/pms/storage/partShop/components/LoackStockModal.tsx
1 | +/* eslint-disable prefer-promise-reject-errors */ | |
1 | 2 | import React, { useEffect } from 'react'; |
2 | 3 | import { Modal, Button, Form, InputNumber, message } from 'antd'; |
3 | 4 | import { useStore } from '../index'; |
4 | -import { releaseApi } from '../api'; | |
5 | +import { unLock } from '../api'; | |
5 | 6 | import _ from 'lodash'; |
6 | 7 | |
7 | 8 | const { Item } = Form; |
8 | 9 | |
9 | -export default function ReleaseModal() { | |
10 | - const { releaseVisible, setReleaseVisible, setLoading, item = {}, setConfirmLoading, confirmLoading } = useStore(); | |
10 | +interface Props { | |
11 | + row: PmsStoragePartShop.unLock | |
12 | + visable: boolean | |
13 | + onCancel: () => any | |
14 | +} | |
15 | + | |
16 | +export default function ReleaseModal(props: Props) { | |
17 | + const { row, visable, onCancel } = props; | |
18 | + const { setLoading, item = {}, setConfirmLoading, confirmLoading } = useStore(); | |
11 | 19 | const [form] = Form.useForm(); |
12 | 20 | |
13 | 21 | useEffect(() => { |
14 | - if (!releaseVisible) { | |
22 | + if (!visable) { | |
15 | 23 | form.resetFields(['partCnt']); |
16 | 24 | return; |
17 | 25 | } |
18 | - form.setFieldsValue({actualStock: item.actualStock}); | |
19 | - }, [releaseVisible]); | |
26 | + form.setFieldsValue({ actualStock: row.lockCnt }); | |
27 | + }, [visable]); | |
20 | 28 | |
21 | 29 | const handleSubmit = () => { |
22 | 30 | setConfirmLoading(true); |
23 | 31 | form.validateFields().then(values => { |
24 | 32 | const params = { |
25 | - ...item, | |
33 | + ...row, | |
26 | 34 | ...values |
27 | 35 | }; |
28 | - releaseApi(params).then(() => { | |
36 | + unLock(params).then(() => { | |
29 | 37 | message.success('操作成功'); |
30 | - setReleaseVisible(false); | |
38 | + onCancel(); | |
31 | 39 | setLoading(true); |
32 | 40 | setConfirmLoading(false); |
33 | 41 | }).catch(e => { |
... | ... | @@ -40,11 +48,11 @@ export default function ReleaseModal() { |
40 | 48 | return ( |
41 | 49 | <Modal |
42 | 50 | title="释放初始锁定库存" |
43 | - visible={releaseVisible} | |
51 | + visible={visable} | |
44 | 52 | maskClosable={false} |
45 | - onCancel={() => setReleaseVisible(false)} | |
53 | + onCancel={onCancel} | |
46 | 54 | footer={[ |
47 | - <Button key="1" type="default" loading={confirmLoading} onClick={() => setReleaseVisible(false)}>取消</Button>, | |
55 | + <Button key="1" type="default" loading={confirmLoading} onClick={onCancel}>取消</Button>, | |
48 | 56 | <Button key="2" type="primary" loading={confirmLoading} onClick={_.throttle(handleSubmit, 3000)}>确定</Button> |
49 | 57 | ]} |
50 | 58 | > |
... | ... | @@ -62,7 +70,25 @@ export default function ReleaseModal() { |
62 | 70 | <Item label="初始锁定库存" name="actualStock"> |
63 | 71 | <InputNumber disabled style={{ width: "100%" }} /> |
64 | 72 | </Item> |
65 | - <Item label="释放数量" name="partCnt" rules={[{ required: true, message: "请输入释放数量" }]}> | |
73 | + <Item | |
74 | + label="释放数量" | |
75 | + name="cancelCnt" | |
76 | + rules={[ | |
77 | + { required: true, message: "请输入释放数量" }, | |
78 | + { | |
79 | + validator: (rule, value) => { | |
80 | + if (row.lockCnt) { | |
81 | + if (value > row.lockCnt) { | |
82 | + return Promise.reject('释放数量不能大于锁定数量'); | |
83 | + } else { | |
84 | + return Promise.resolve(); | |
85 | + } | |
86 | + } | |
87 | + return Promise.resolve(); | |
88 | + } | |
89 | + } | |
90 | + ]} | |
91 | + > | |
66 | 92 | <InputNumber style={{ width: "100%" }} min={1} max={item.actualStock} step={1} placeholder="请输入释放数量" /> |
67 | 93 | </Item> |
68 | 94 | </Form> | ... | ... |
src/pages/pms/storage/partShop/components/LockDetailModal.tsx
1 | 1 | import React, { useEffect, useState } from 'react'; |
2 | 2 | import { Button, Modal, Table } from 'antd'; |
3 | -import { getLockDetail} from '@/pages/pms/storage/partShop/api'; | |
3 | +import { getLockDetail } from '@/pages/pms/storage/partShop/api'; | |
4 | 4 | import useInitail from "@/hooks/useInitail"; |
5 | -import {typeReceiverObj, typeSenderObj} from '@/pages/pms/entity'; | |
5 | +import { typeReceiverObj, typeSenderObj } from '@/pages/pms/entity'; | |
6 | +import LoackStockModal from './LoackStockModal'; | |
6 | 7 | import moment from 'moment'; |
7 | 8 | |
8 | 9 | const { Column } = Table; |
... | ... | @@ -13,16 +14,23 @@ interface Props { |
13 | 14 | onCancel: () => any |
14 | 15 | } |
15 | 16 | |
16 | -export default function Index({item = {}, visible, onCancel}: Props) { | |
17 | +export default function Index({ item = {}, visible, onCancel }: Props) { | |
17 | 18 | const [delay, setDelay] = useState(true); |
18 | - const { data, loading, setParams} = useInitail<PmsStoragePartShop.LockDetailVO[], PmsStoragePartShop.LockParams>(getLockDetail, [], {}, delay); | |
19 | + const { data, loading, setParams } = useInitail<PmsStoragePartShop.LockDetailVO[], PmsStoragePartShop.LockParams>(getLockDetail, [], {}, delay); | |
20 | + const [visableLoackStockModal, setVisableLoackStockModal] = useState(false); | |
21 | + const [row, setRow] = useState<PmsStoragePartShop.unLock>({}); | |
19 | 22 | |
20 | 23 | useEffect(() => { |
21 | 24 | if (item.shopId && item.partId && visible) { |
22 | 25 | setDelay(false); |
23 | - setParams({shopId: item.shopId, partId: item.partId}, true); | |
26 | + setParams({ shopId: item.shopId, partId: item.partId }, true); | |
24 | 27 | } |
25 | - }, [item, visible]); | |
28 | + }, [item, visible, visableLoackStockModal]); | |
29 | + | |
30 | + const unLock = (record: any) => { | |
31 | + setVisableLoackStockModal(true); | |
32 | + setRow(record); | |
33 | + }; | |
26 | 34 | |
27 | 35 | return ( |
28 | 36 | <Modal |
... | ... | @@ -35,7 +43,7 @@ export default function Index({item = {}, visible, onCancel}: Props) { |
35 | 43 | <Button key="1" loading={loading} onClick={onCancel}>取消</Button>, |
36 | 44 | ]} |
37 | 45 | > |
38 | - <Table loading={loading} rowKey={(v: PmsStoragePartShop.LockDetailVO) => `${v.orderNo}`} scroll={{y: 500}} dataSource={data || []} pagination={false}> | |
46 | + <Table loading={loading} rowKey={(v: PmsStoragePartShop.LockDetailVO) => `${v.orderNo}`} scroll={{ y: 500 }} dataSource={data || []} pagination={false}> | |
39 | 47 | <Column title="锁库类型" dataIndex="type" /> |
40 | 48 | <Column title="单号" dataIndex="orderNo" /> |
41 | 49 | <Column |
... | ... | @@ -69,7 +77,9 @@ export default function Index({item = {}, visible, onCancel}: Props) { |
69 | 77 | /> |
70 | 78 | <Column title="锁定库存数" dataIndex="lockCnt" /> |
71 | 79 | <Column title="锁库天数" dataIndex="days" render={(t: number) => (t || 0).toFixed(0)} /> |
80 | + <Column title="操作" render={(record) => <a onClick={() => unLock(record)}>释放库存</a>} /> | |
72 | 81 | </Table> |
82 | + <LoackStockModal row={row} visable={visableLoackStockModal} onCancel={() => { setVisableLoackStockModal(false); }} /> | |
73 | 83 | </Modal> |
74 | 84 | ); |
75 | 85 | } | ... | ... |
src/pages/pms/storage/partShop/index.tsx
... | ... | @@ -23,7 +23,7 @@ function PartShop() { |
23 | 23 | <Card> |
24 | 24 | <div style={{ display: 'flex', flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 10 }}> |
25 | 25 | <Filter /> |
26 | - <div> | |
26 | + <div style={{ display: 'flex', flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}> | |
27 | 27 | <Button |
28 | 28 | type="primary" |
29 | 29 | icon={<VerticalAlignBottomOutlined />} | ... | ... |
src/pages/pms/storage/partShop/interface.d.ts
src/pages/promotion/proengineCreate/components/DealerSelector/api.ts
... | ... | @@ -8,7 +8,18 @@ export interface DealerItem { |
8 | 8 | dealerName: string |
9 | 9 | } |
10 | 10 | |
11 | + interface DealersShop { | |
12 | + value: number, //商家id | |
13 | + label: string, // 商家名称 | |
14 | + children: any[], | |
15 | + } | |
16 | + | |
11 | 17 | /** 根据品牌获取商家列表 */ |
12 | 18 | export function getDealerApi(brandId: number): http.PromiseResp<DealerItem[]> { |
13 | 19 | return request.get(`${OOP_HOST}/select/dealer/list`, { params: { brandId } }); |
14 | 20 | } |
21 | + | |
22 | +/** 根据当前登录人信息获取商家门店树 */ | |
23 | +export function getDealerTreeApi(params: {bizType: number}): http.PromiseRespA<DealersShop> { | |
24 | + return request.get(`${OOP_HOST}/select/dealers/shops`, {params}); | |
25 | +} | |
15 | 26 | \ No newline at end of file | ... | ... |
src/pages/promotion/proengineCreate/components/DealerSelector/index.tsx
1 | 1 | import React, { useEffect, useState, Ref, forwardRef } from 'react'; |
2 | -import { Radio, message, Select } from 'antd'; | |
3 | -import { DealerItem, getDealerApi } from './api'; | |
2 | +import { Radio, message, Select, TreeSelect } from 'antd'; | |
3 | +import type { DefaultOptionType } from 'antd/es/select'; | |
4 | +import { DealerItem, getDealerApi, getDealerTreeApi } from './api'; | |
5 | +import { getShopApi } from '@/common/api'; | |
6 | +import type { TreeSelectProps } from 'antd'; | |
4 | 7 | |
5 | 8 | const RadioGroup = Radio.Group; |
6 | 9 | const Option = Select.Option; |
... | ... | @@ -11,14 +14,16 @@ interface Value { |
11 | 14 | * 2. 部分商家 |
12 | 15 | */ |
13 | 16 | type: 1 | 2, |
14 | - selected: number[] | |
17 | + selected: string[] | |
15 | 18 | } |
16 | 19 | |
17 | 20 | export interface DealerSelectorProps { |
18 | 21 | brandId: number, |
19 | 22 | value?: Value, |
23 | + bizType?: number, | |
20 | 24 | onChange?: (value: Value) => any, |
21 | - disabled?: boolean | |
25 | + disabled?: boolean, | |
26 | + joinDealerIds?: string[], | |
22 | 27 | } |
23 | 28 | |
24 | 29 | const defaultValue: Value = { |
... | ... | @@ -27,37 +32,51 @@ const defaultValue: Value = { |
27 | 32 | }; |
28 | 33 | |
29 | 34 | function DealerSelector(props: DealerSelectorProps, ref?: Ref<any>) { |
30 | - const { brandId, value = defaultValue, onChange, disabled } = props; | |
35 | + const { brandId, value = defaultValue, bizType, joinDealerIds, onChange, disabled } = props; | |
31 | 36 | const { type = 1, selected = [] } = value; |
32 | - const [dealers, setDealers] = useState<DealerItem[]>([]); | |
33 | 37 | const [innerValue, setValue] = useState<Value>({ type, selected }); |
38 | + const [treeData, setTreeData] = useState<Omit<DefaultOptionType, 'label'>[]>([]); | |
34 | 39 | |
35 | 40 | useEffect(() => { |
36 | 41 | setValue({ ...value }); |
37 | 42 | }, [type]); |
38 | 43 | |
44 | + useEffect(() => { | |
45 | + | |
46 | + }); | |
47 | + | |
39 | 48 | function typeChange(e: any) { |
40 | 49 | const _new = { type: e.target.value, selected: [] }; |
41 | 50 | setValue(_new); |
42 | 51 | onChange && onChange(_new); |
43 | 52 | } |
44 | 53 | |
45 | - function dealerChange(value: any) { | |
54 | + function treeOnChange(value: string[]) { | |
46 | 55 | const _new = { ...innerValue, selected: value }; |
47 | 56 | setValue(_new); |
48 | 57 | onChange && onChange(_new); |
49 | 58 | } |
50 | 59 | |
51 | 60 | useEffect(() => { |
52 | - if (brandId) { | |
53 | - getDealerApi(brandId).then(res => { | |
61 | + if (bizType) { | |
62 | + getDealerTreeApi({bizType}).then(res => { | |
54 | 63 | const { data = [] } = res; |
55 | - setDealers(data); | |
64 | + const newItems = data.map(i => ({ | |
65 | + key: i.value, | |
66 | + value: i.value, | |
67 | + title: i.label, | |
68 | + children: i.children.map(chi => ({ | |
69 | + key: chi.value, | |
70 | + value: disabled ? chi.value : `${i.value}-${chi.value}`, | |
71 | + title: chi.label, | |
72 | + })) | |
73 | + })); | |
74 | + setTreeData(newItems); | |
56 | 75 | }).catch(e => { |
57 | 76 | message.error(e.message); |
58 | 77 | }); |
59 | 78 | } |
60 | - }, [brandId]); | |
79 | + }, [bizType]); | |
61 | 80 | |
62 | 81 | return ( |
63 | 82 | <div> |
... | ... | @@ -66,19 +85,20 @@ function DealerSelector(props: DealerSelectorProps, ref?: Ref<any>) { |
66 | 85 | <Radio value={2}>部分商家</Radio> |
67 | 86 | </RadioGroup> |
68 | 87 | {innerValue.type === 2 && ( |
69 | - <Select | |
70 | - optionFilterProp="children" | |
71 | - value={innerValue.selected} | |
88 | + <TreeSelect | |
89 | + showSearch | |
90 | + allowClear | |
72 | 91 | disabled={disabled} |
73 | - mode="multiple" | |
92 | + treeCheckable | |
93 | + placeholder="请选择商家/门店" | |
74 | 94 | style={{ width: '100%' }} |
75 | - placeholder="请选择参与商家" | |
76 | - onChange={dealerChange} | |
77 | - > | |
78 | - {dealers.map((dealer) => ( | |
79 | - <Option value={dealer.id} key={dealer.id}>{dealer.name}</Option> | |
80 | - ))} | |
81 | - </Select> | |
95 | + value={innerValue.selected} | |
96 | + treeExpandAction="click" | |
97 | + multiple | |
98 | + dropdownStyle={{ maxHeight: 400, overflow: 'auto' }} | |
99 | + onChange={treeOnChange} | |
100 | + treeData={treeData} | |
101 | + /> | |
82 | 102 | )} |
83 | 103 | </div> |
84 | 104 | ); | ... | ... |
src/pages/promotion/proengineCreate/components/entity.ts
src/pages/promotion/proengineCreate/components/index.tsx
... | ... | @@ -30,11 +30,12 @@ interface Props { |
30 | 30 | export default function Condition(props: Props) { |
31 | 31 | const { form, onBrandChange, disabled, style, formItemLayout = defaultLayout, value = {}, brandLabelInValue } = props; |
32 | 32 | const { getFieldDecorator, getFieldValue, setFieldsValue } = form; |
33 | - const { | |
33 | + const { | |
34 | 34 | brandId, |
35 | 35 | brandName, |
36 | 36 | joinDealerType, |
37 | 37 | joinDealerIds, |
38 | + joinShopIds, | |
38 | 39 | proItemType, |
39 | 40 | joinItemList, |
40 | 41 | excludeItemList, |
... | ... | @@ -51,7 +52,7 @@ export default function Condition(props: Props) { |
51 | 52 | function changeBrand(value: number | Brand) { |
52 | 53 | onBrandChange && onBrandChange(value); |
53 | 54 | /** 品牌改变: 商家需重新选择 */ |
54 | - getFieldValue("joinDealer") && setFieldsValue({ joinDealer: defaultDealerValue }); | |
55 | + // getFieldValue("joinDealer") && setFieldsValue({ joinDealer: defaultDealerValue }); | |
55 | 56 | /** 品牌改变: 车辆的车系需重新选择 */ |
56 | 57 | getFieldValue("joinItems") && setFieldsValue({ joinItems: undefined }); |
57 | 58 | } |
... | ... | @@ -69,11 +70,11 @@ export default function Condition(props: Props) { |
69 | 70 | {!!currentBrandId && ( |
70 | 71 | <FormItem label="参与商家" {...formItemLayout}> |
71 | 72 | {getFieldDecorator("joinDealer", { |
72 | - initialValue: value ? { type: joinDealerType || 1, selected: _.compact((joinDealerIds || '').split(",").map(item => Number(item))) } : defaultDealerValue, | |
73 | + initialValue: value ? { type: joinDealerType || 1, selected: _.compact((joinShopIds || '').split(",")) } : defaultDealerValue, | |
73 | 74 | rules: [{ required: true, message: "必填项" }, |
74 | 75 | { validator: checkJionDealer }] |
75 | 76 | })( |
76 | - <DealerSelector brandId={currentBrandId} disabled={disabled} /> | |
77 | + <DealerSelector joinDealerIds={joinDealerIds ? joinDealerIds.split(',') : []} brandId={currentBrandId} bizType={bizType} disabled={disabled} /> | |
77 | 78 | )} |
78 | 79 | </FormItem> |
79 | 80 | )} | ... | ... |
src/pages/promotion/proengineCreate/entity.ts
... | ... | @@ -47,6 +47,8 @@ export const base: BaseInfoDto = { |
47 | 47 | joinDealerType: 1, |
48 | 48 | /**参与商家们 */ |
49 | 49 | joinDealerIds: '', |
50 | + /**参与门店 */ | |
51 | + joinShopIds: '', | |
50 | 52 | /**参与用户类型 */ |
51 | 53 | applyType: 1, |
52 | 54 | /**参与用户条件 */ |
... | ... | @@ -192,8 +194,15 @@ export function stateTransforToStore(formState) { |
192 | 194 | store.applyValue = value.targetValue; |
193 | 195 | break; |
194 | 196 | case 'joinDealer': |
197 | + const dealersIds: string[] = []; | |
198 | + const shopIds: string[] = []; | |
199 | + value.selected.forEach((item:string) => { | |
200 | + dealersIds.push(item.split("-")[0]); | |
201 | + shopIds.push(item.split("-")[1]); | |
202 | + }); | |
195 | 203 | store.joinDealerType = value.type; |
196 | - store.joinDealerIds = value.selected.join(","); | |
204 | + store.joinDealerIds = [...new Set(dealersIds)].join(","); | |
205 | + store.joinShopIds = shopIds.join(","); | |
197 | 206 | break; |
198 | 207 | |
199 | 208 | case 'joinItems': | ... | ... |
src/pages/promotion/proengineCreate/index.tsx
... | ... | @@ -116,7 +116,8 @@ function ProengineCreate(props: Props) { |
116 | 116 | excludeItemList, |
117 | 117 | proItemType, |
118 | 118 | applyType, |
119 | - applyValue | |
119 | + applyValue, | |
120 | + joinShopIds | |
120 | 121 | } = _data; |
121 | 122 | setTargerSelectValue({ |
122 | 123 | brandId, |
... | ... | @@ -124,6 +125,7 @@ function ProengineCreate(props: Props) { |
124 | 125 | joinDealerType, |
125 | 126 | joinDealerIds, |
126 | 127 | joinItemList, |
128 | + joinShopIds, | |
127 | 129 | excludeItemList, |
128 | 130 | proItemType, |
129 | 131 | applyType, | ... | ... |
src/pages/promotion/proengineCreate/interface.d.ts
src/pages/stock/ExternalVehicle/api.ts
... | ... | @@ -31,8 +31,8 @@ export function getDetailListApi(params?: ExternalImport.QueryParams): http.Prom |
31 | 31 | } |
32 | 32 | |
33 | 33 | //外采供应商 |
34 | -export function getCompanyList(): http.PromiseRespA<ExternalImport.CompanyListVO> { | |
35 | - return request.get(`${FINANCE2_HOST}/common/trade/company/list`, { params: { types: 12, compCategory: 1 } }); | |
34 | +export function getCompanyList(params: {types: number}): http.PromiseRespA<ExternalImport.CompanyListVO> { | |
35 | + return request.get(`${FINANCE2_HOST}/common/trade/company/list`, { params: {...params, compCategory: 1} }); | |
36 | 36 | } |
37 | 37 | |
38 | 38 | /** | ... | ... |
src/pages/stock/ExternalVehicle/components/UploadExcel.tsx
... | ... | @@ -13,7 +13,7 @@ interface Props { |
13 | 13 | export default function UploadExcel(props: Props) { |
14 | 14 | const [form] = Form.useForm(); |
15 | 15 | const { onCancel, searchDealerId } = props; |
16 | - const { setBreadcrumbs, dealerList, brandList, visibleUpload, setVisibleUpload, factoryList, uploadModalValue, setuploadModalValue, | |
16 | + const { setBreadcrumbs, dealerList, brandList, visibleUpload, setVisibleUpload, factoryList, mainEngineList, uploadModalValue, setuploadModalValue, | |
17 | 17 | breadcrumbs, setTicketBatchId } = useStore(); |
18 | 18 | const [dealerId, setDealerId] = useState<any>(); |
19 | 19 | const [saveLoading, setSaveLoading] = useState(false); |
... | ... | @@ -74,6 +74,8 @@ export default function UploadExcel(props: Props) { |
74 | 74 | brandName: fieldsValue.brandId.label, |
75 | 75 | dealerId: fieldsValue.dealerId.value, |
76 | 76 | dealerName: fieldsValue.dealerId.label, |
77 | + factoryId: fieldsValue.factoryId.value, | |
78 | + factoryName: fieldsValue.factoryId.label, | |
77 | 79 | fid1: fieldsValue.fid1[0].response.data, |
78 | 80 | supplyId: fieldsValue.supplyId.value, |
79 | 81 | supplyName: fieldsValue.supplyId.label, |
... | ... | @@ -114,6 +116,7 @@ export default function UploadExcel(props: Props) { |
114 | 116 | placeholder="请选择商家" |
115 | 117 | notFoundContent="暂无数据" |
116 | 118 | showSearch |
119 | + optionFilterProp="children" | |
117 | 120 | style={{ width: 300 }} |
118 | 121 | value={dealerId} |
119 | 122 | onChange={(v: any) => { setDealerId(v); dealerId && form.setFieldsValue({ fid1: undefined, fid2: undefined }); }} |
... | ... | @@ -130,7 +133,6 @@ export default function UploadExcel(props: Props) { |
130 | 133 | labelInValue |
131 | 134 | placeholder="请选择品牌" |
132 | 135 | notFoundContent="暂无数据" |
133 | - showSearch | |
134 | 136 | style={{ width: 300 }} |
135 | 137 | > |
136 | 138 | { |
... | ... | @@ -154,6 +156,23 @@ export default function UploadExcel(props: Props) { |
154 | 156 | } |
155 | 157 | </Select> |
156 | 158 | </Form.Item> |
159 | + <Form.Item label="主机厂" name="factoryId" rules={[{ required: true, message: '请选择' }]}> | |
160 | + <Select | |
161 | + labelInValue | |
162 | + showSearch | |
163 | + allowClear | |
164 | + optionFilterProp="children" | |
165 | + placeholder="请选择" | |
166 | + notFoundContent="暂无数据" | |
167 | + style={{ minWidth: 300, maxWidth: 500 }} | |
168 | + > | |
169 | + { | |
170 | + mainEngineList && mainEngineList.map((item) => { | |
171 | + return <Option value={item.id || -1} key={item.id}>{item.name}</Option>; | |
172 | + }) | |
173 | + } | |
174 | + </Select> | |
175 | + </Form.Item> | |
157 | 176 | <div style={{ textAlign: 'center', fontSize: 12, marginBottom: 10 }}>上传excle数据文档:支持扩展名:.xls .xlsx</div> |
158 | 177 | <Form.Item |
159 | 178 | label="数据文档" | ... | ... |
src/pages/stock/ExternalVehicle/store.ts
... | ... | @@ -12,7 +12,9 @@ export interface BreadcrumbItem { |
12 | 12 | export default function useStore() { |
13 | 13 | const { data: brandList, errMsg: brandMessage } = useInitail<CommonApi.OptionVO[], CommonApi.BrandParm>(getBrandFilterApi, [], {}); |
14 | 14 | const { data: dealerList, errMsg: dealerMessage } = useInitail<CommonApi.OptionVO[], CommonApi.DealerParam>(getDealerApi, [], {}); |
15 | - const { data: factoryList, errMsg: factoryMessage } = useInitail<ExternalImport.CompanyListVO[], CommonApi.DealerParam>(getCompanyList, [], {}); | |
15 | + const { data: factoryList, errMsg: factoryMessage } = useInitail<ExternalImport.CompanyListVO[], { types: number }>(getCompanyList, [], { types: 12 }); | |
16 | + /**主机厂 */ | |
17 | + const { data: mainEngineList, errMsg: engineMessage } = useInitail<ExternalImport.CompanyListVO[], { types: number }>(getCompanyList, [], { types: 10 }); | |
16 | 18 | const [currentItem, setCurrentItem] = useState<ExternalImport.QueryParams>({}); |
17 | 19 | // 面包屑列表 |
18 | 20 | const [breadcrumbs, setBreadcrumbs] = useState<BreadcrumbItem[]>([{ name: '列表', key: 'list' }]); |
... | ... | @@ -34,6 +36,8 @@ export default function useStore() { |
34 | 36 | factoryList, |
35 | 37 | currentItem, |
36 | 38 | setCurrentItem, |
39 | + mainEngineList, | |
40 | + engineMessage, | |
37 | 41 | breadcrumbs, |
38 | 42 | setBreadcrumbs, |
39 | 43 | currentBreadcrumb, | ... | ... |
src/pages/stock/StoreHouse/AbnormalAuth/components/CreatelModal.tsx
... | ... | @@ -29,17 +29,18 @@ export default function CreateModal(props: Props) { |
29 | 29 | if (item.id || brandId) { |
30 | 30 | setStorageParams({ authId: item.id, brandId: item.id ? item.brandId : brandId }, true); |
31 | 31 | setDelay(false); |
32 | + setStorageList(item.storageList || []); | |
32 | 33 | } |
33 | 34 | }, [item.id, brandId]); |
34 | 35 | |
35 | 36 | function handSubmit(fieldsValue: any) { |
36 | 37 | const param = { |
37 | 38 | id: item.id, |
39 | + storageList, | |
38 | 40 | userId: fieldsValue.userId.value, |
39 | 41 | userName: fieldsValue.userId.label, |
40 | 42 | brandId: fieldsValue.brandId.value, |
41 | 43 | brandName: fieldsValue.brandId.label, |
42 | - storageList | |
43 | 44 | }; |
44 | 45 | setLoading(true); |
45 | 46 | saveApi(param).then(() => { | ... | ... |
src/pages/stock/TicketImport/api.ts
... | ... | @@ -52,8 +52,8 @@ export function getTicketBrand(): http.PromiseRespA<TicketImport.BrandListVO> { |
52 | 52 | } |
53 | 53 | |
54 | 54 | //启票模板校验 |
55 | -export function getTemplateCheck(params: { brandId: number, ticketTemplate: string }): http.PromiseResp<void> { | |
56 | - return request.post(`${FVM_HOST}/erp/ticket/template/valid`, params); | |
55 | +export function getTemplateCheck(params: { brandId: number, fid: string }): http.PromiseResp<void> { | |
56 | + return request.get(`${FVM_HOST}/erp/ticket/template/valid`, {params}); | |
57 | 57 | } |
58 | 58 | |
59 | 59 | /** | ... | ... |
src/pages/stock/TicketImport/components/TemplateCheck.tsx
1 | 1 | import React, { useState, useEffect } from 'react'; |
2 | 2 | import { Button, Modal, Upload, message, Select, Form } from 'antd'; |
3 | 3 | import { useStore } from '../index'; |
4 | -import { importCarApi } from '../api'; | |
4 | +import { getTemplateCheck, importCarApi } from '../api'; | |
5 | +import { UploadChangeParam } from 'antd/lib/upload'; | |
5 | 6 | import { UploadOutlined } from '@ant-design/icons'; |
6 | 7 | import axios from 'axios'; |
7 | 8 | |
... | ... | @@ -48,6 +49,9 @@ export default function TemplateCheck(props: Props) { |
48 | 49 | message.error("文件上传出错,请重新上传"); |
49 | 50 | return ''; |
50 | 51 | } |
52 | + if (e.file.status === "done") { | |
53 | + upload(e.file.response.data, brandId.value); | |
54 | + } | |
51 | 55 | // e.file.percent = 100; |
52 | 56 | // e.file.status = 'done'; |
53 | 57 | return e && e.fileList.slice(-1); |
... | ... | @@ -58,21 +62,17 @@ export default function TemplateCheck(props: Props) { |
58 | 62 | setBrandId(undefined); |
59 | 63 | } |
60 | 64 | |
61 | - function upload(e: any) { | |
62 | - const ps = new FormData(); | |
63 | - ps.append('ticketTemplate', e.file); | |
64 | - ps.append('brandId', brandId.value); | |
65 | + /**下载Excel文件 */ | |
66 | + function upload(fid: string, brandId: number) { | |
65 | 67 | axios({ |
66 | - method: 'post', | |
67 | - data: ps, | |
68 | + method: 'get', | |
69 | + params: { | |
70 | + fid, brandId | |
71 | + }, | |
68 | 72 | headers: { 'content-type': 'multipart/form-data', 'X-Requested-With': 'XMLHttpRequest' }, |
69 | 73 | url: '/fvm/erp/ticket/template/valid', |
70 | 74 | responseType: 'arraybuffer', |
71 | - onUploadProgress: (event: any) => { | |
72 | - e.onProgress && e.onProgress({ percent: event.loaded / event.total * 100 }, e.file); | |
73 | - } | |
74 | 75 | }).then(res => { |
75 | - e.onSuccess && e.onSuccess({ ...e.file, status: 'done' }, e.file); | |
76 | 76 | // 假设 data 是返回来的二进制数据 |
77 | 77 | const data = res.data; |
78 | 78 | const url = window.URL.createObjectURL(new Blob([data], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" })); |
... | ... | @@ -90,22 +90,9 @@ export default function TemplateCheck(props: Props) { |
90 | 90 | } |
91 | 91 | |
92 | 92 | const uploadProps = { |
93 | - // accept: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel', | |
94 | 93 | accept: '.xlsx,.xls', |
95 | - name: 'ticketTemplate', | |
96 | 94 | multiple: false, |
97 | - customRequest: upload, | |
98 | - data: { brandId: brandId && brandId.value }, | |
99 | - progress: { | |
100 | - strokeColor: { | |
101 | - '0%': '#108ee9', | |
102 | - '100%': '#87d068', | |
103 | - }, | |
104 | - strokeWidth: 3, | |
105 | - format: (percent: any) => `${parseFloat(percent.toFixed(2))}%`, | |
106 | - }, | |
107 | - // action: `/api/fvm/erp/ticket/template/valid`, | |
108 | - // onChange: (file: any) => handleChange(file), | |
95 | + action: `/api/file/upload`, | |
109 | 96 | beforeUpload: (info: any) => beforeUpload(info), |
110 | 97 | }; |
111 | 98 | ... | ... |
src/pages/vms/Fence/AMapCenter/index.tsx
0 → 100644
1 | +import React, { Component } from 'react'; | |
2 | +import { DeleteOutlined } from '@ant-design/icons'; | |
3 | +import { Map as AMap, MouseTool, Circle, CircleEditor, Polygon, PolyEditor } from 'react-amap'; | |
4 | +import { Button, Input, message } from 'antd'; | |
5 | +import { MapType } from './util'; | |
6 | +import './style.less'; | |
7 | + | |
8 | +// const style = require('./style.less'); | |
9 | +const styleOptions = { | |
10 | + strokeColor: '#4189FD', | |
11 | + fillColor: '#4189FD', | |
12 | + strokeWeight: 3, | |
13 | + strokeOpacity: 0.8, | |
14 | + fillOpacity: 0.5 | |
15 | +}; | |
16 | +interface Props { | |
17 | + overlays?: Array<MapIF.Overlays>; | |
18 | + drawingTypes?: Array<string>; | |
19 | + onDrawComplete?: Function; | |
20 | + onEditComplete?: Function; | |
21 | + clearDrawing?: boolean; | |
22 | + region?: string; | |
23 | +} | |
24 | + | |
25 | +interface State { | |
26 | + editing?: boolean; | |
27 | + fenceName?: string; | |
28 | + what?: string; | |
29 | + /**多边形回显 */ | |
30 | + PolygonPath: Array<{ longitude: number, latitude: number }>; | |
31 | + /**圆形回显 */ | |
32 | + CirclePath: MapIF.CirclePath; | |
33 | + mapCenter?: { longitude: number, latitude: number } | undefined; | |
34 | + editActive: boolean; | |
35 | +} | |
36 | + | |
37 | +class MapCenter extends Component<Props, Object> { | |
38 | + // class MapCenter extends Component { | |
39 | + state: State = { editing: false, editActive: false, fenceName: '', what: '', PolygonPath: [], CirclePath: {} }; | |
40 | + | |
41 | + // constructor() { | |
42 | + // super(); | |
43 | + // state: State = { editing: false, fenceName: '', what: '' }; | |
44 | + // } | |
45 | + | |
46 | + // 地图元素ID | |
47 | + MapKey = ''; | |
48 | + | |
49 | + // 地图实例 | |
50 | + MapInstance = null; | |
51 | + | |
52 | + // 绘图实例 | |
53 | + DrawingManager = null; | |
54 | + | |
55 | + // 绘制的覆盖物列表 | |
56 | + DrawOverlays = []; | |
57 | + // mapCenter: { longitude: number, latitude: number } | undefined = undefined; | |
58 | + | |
59 | + // 当前的编辑覆盖物 | |
60 | + CurrentOverlay = { type: '', overlay: null }; | |
61 | + | |
62 | + constructor() { | |
63 | + super(); | |
64 | + const self = this; | |
65 | + this.state = { | |
66 | + what: '点击上方按钮开始绘制' | |
67 | + }; | |
68 | + this.toolEvents = { | |
69 | + created: (tool) => { | |
70 | + self.tool = tool; | |
71 | + | |
72 | + let auto, placeSearch; | |
73 | + window.AMap.plugin('AMap.Autocomplete', () => { | |
74 | + auto = new window.AMap.Autocomplete({ | |
75 | + input: 'tipinput', | |
76 | + pageSize: 10, | |
77 | + pageIndex: 1, | |
78 | + // citylimit: true, // 仅搜索本城市的地名 | |
79 | + // city: '', // 限制为只能搜索当前地区的位置 不填全国搜索 | |
80 | + outPutDirAuto: true | |
81 | + }); | |
82 | + }); | |
83 | + | |
84 | + // 创建搜索实例 | |
85 | + window.AMap.plugin('AMap.PlaceSearch', () => { | |
86 | + placeSearch = new window.AMap.PlaceSearch({ | |
87 | + input: 'tipinput', | |
88 | + pageSize: 10, | |
89 | + pageIndex: 1, | |
90 | + // citylimit: true, // 仅搜索本城市的地名 | |
91 | + }); | |
92 | + }); | |
93 | + window.AMap.event.addListener(auto, "select", (e) => { | |
94 | + const info = e.poi.location; | |
95 | + if (info) { | |
96 | + this.setState({ mapCenter: { longitude: info.lng, latitude: info.lat } }); | |
97 | + } | |
98 | + placeSearch.setCity(e.poi.adcode); | |
99 | + placeSearch.search(e.poi.name, (status: any, result: any) => { | |
100 | + if (!info && result) { | |
101 | + const pois = result.poiList.pois.length ? result.poiList.pois[0] : {}; | |
102 | + const point = pois.location; | |
103 | + this.setState({ mapCenter: { longitude: point.lng, latitude: point.lat } }); | |
104 | + } | |
105 | + }); | |
106 | + }); | |
107 | + }, | |
108 | + draw({ obj }) { | |
109 | + self.drawWhat(obj); | |
110 | + } | |
111 | + }; | |
112 | + this.mapPlugins = ['ToolBar']; | |
113 | + } | |
114 | + | |
115 | + drawWhat(obj) { | |
116 | + if (this.state.editing) { | |
117 | + this.close(); | |
118 | + } | |
119 | + let text = ''; | |
120 | + switch (obj.CLASS_NAME) { | |
121 | + case 'AMap.Marker': | |
122 | + text = `你绘制了一个标记,坐标位置是 {${obj.getPosition()}}`; | |
123 | + this.handleOverlayComplete(MapType.POLYLINE, obj); | |
124 | + break; | |
125 | + case 'AMap.Polygon': | |
126 | + text = `你绘制了一个多边形,有${obj.getPath().length}个端点`; | |
127 | + this.handleOverlayComplete(MapType.POLYGON, obj); | |
128 | + break; | |
129 | + case 'AMap.Circle': | |
130 | + text = `你绘制了一个圆形,圆心位置为{${obj.getCenter()}}`; | |
131 | + this.handleOverlayComplete(MapType.CIRCLE, obj); | |
132 | + break; | |
133 | + default: | |
134 | + text = ''; | |
135 | + } | |
136 | + this.setState({ | |
137 | + what: text | |
138 | + }); | |
139 | + } | |
140 | + | |
141 | + drawCircle() { | |
142 | + if (this.tool) { | |
143 | + this.tool.circle(); | |
144 | + this.setState({ | |
145 | + what: '准备绘制圆形' | |
146 | + }); | |
147 | + } | |
148 | + } | |
149 | + drawRectangle() { | |
150 | + if (this.tool) { | |
151 | + this.tool.rectangle(); | |
152 | + this.setState({ | |
153 | + what: '准备绘制多边形(矩形)' | |
154 | + }); | |
155 | + } | |
156 | + } | |
157 | + | |
158 | + drawMarker() { | |
159 | + if (this.tool) { | |
160 | + this.tool.marker(); | |
161 | + this.setState({ | |
162 | + what: '准备绘制坐标点' | |
163 | + }); | |
164 | + } | |
165 | + } | |
166 | + | |
167 | + drawPolygon() { | |
168 | + if (this.tool) { | |
169 | + this.tool.polygon(); | |
170 | + this.setState({ | |
171 | + what: '准备绘制多边形' | |
172 | + }); | |
173 | + } | |
174 | + } | |
175 | + | |
176 | + close() { | |
177 | + if (this.tool) { | |
178 | + console.log('close'); | |
179 | + this.tool.close(true); | |
180 | + } | |
181 | + this.setState({ | |
182 | + what: '关闭了鼠标工具' | |
183 | + }); | |
184 | + } | |
185 | + | |
186 | + // componentWillMount() { | |
187 | + // this.MapKey = `MapCenter_${new Date().getTime()}`; | |
188 | + // } | |
189 | + | |
190 | + componentDidMount() { | |
191 | + this.handleOverlay(this.props.overlays); | |
192 | + } | |
193 | + | |
194 | + componentWillReceiveProps(nextProps: Props) { | |
195 | + const { clearDrawing, region } = this.props; | |
196 | + this.handleOverlay(nextProps.overlays); | |
197 | + if (nextProps.clearDrawing && nextProps.clearDrawing !== clearDrawing) { | |
198 | + // this.handleClearDraw(); | |
199 | + // this.handleClearShow(); | |
200 | + this.handleEditCancel(); | |
201 | + } | |
202 | + // if (nextProps.region && nextProps.region !== region) { | |
203 | + // this.handleShowRegion(nextProps.region); | |
204 | + // } | |
205 | + } | |
206 | + | |
207 | + /** | |
208 | + * 处理绘制完成 | |
209 | + */ | |
210 | + handleOverlayComplete = (type: string, overlay) => { | |
211 | + this.DrawOverlays.push(overlay); | |
212 | + if (type === MapType.CIRCLE) { | |
213 | + this.props.onDrawComplete && | |
214 | + this.props.onDrawComplete({ | |
215 | + edit: false, | |
216 | + type, | |
217 | + point: overlay.getCenter(), | |
218 | + radius: Math.round(overlay.getRadius()), | |
219 | + }); | |
220 | + } else { | |
221 | + this.props.onDrawComplete && | |
222 | + this.props.onDrawComplete({ edit: false, type, points: overlay.getPath() }); | |
223 | + } | |
224 | + }; | |
225 | + | |
226 | + /** | |
227 | + * 处理编辑完成 | |
228 | + */ | |
229 | + handleEditComplete = (e) => { | |
230 | + const overlay = e; | |
231 | + if (this.CurrentOverlay.type === MapType.CIRCLE) { | |
232 | + this.props.onEditComplete && | |
233 | + this.props.onEditComplete({ | |
234 | + edit: true, | |
235 | + type: this.CurrentOverlay.type, | |
236 | + point: overlay.getCenter(), | |
237 | + radius: Math.round(overlay.getRadius()), | |
238 | + }); | |
239 | + } else { | |
240 | + this.props.onEditComplete && | |
241 | + this.props.onEditComplete({ | |
242 | + edit: true, | |
243 | + type: this.CurrentOverlay.type, | |
244 | + points: overlay.getPath(), | |
245 | + }); | |
246 | + } | |
247 | + }; | |
248 | + | |
249 | + /** | |
250 | + * 取消编辑 | |
251 | + */ | |
252 | + handleEditCancel = () => { | |
253 | + this.setState({ editActive: false, editing: false, fenceName: '' }); | |
254 | + }; | |
255 | + | |
256 | + /** | |
257 | + * 获取当前定位 | |
258 | + */ | |
259 | + handleLodation = () => { | |
260 | + const point = new BMap.Point(104.074, 30.572); | |
261 | + this.MapInstance.centerAndZoom(point, 12); | |
262 | + const geolocation = new BMap.Geolocation(); | |
263 | + geolocation.getCurrentPosition(response => { | |
264 | + if (response.point && response.point.lat) { | |
265 | + this.MapInstance.panTo(response.point); | |
266 | + } | |
267 | + }); | |
268 | + }; | |
269 | + | |
270 | + /** | |
271 | + * 循环处理覆盖物 | |
272 | + */ | |
273 | + handleOverlay = overlays => { | |
274 | + if (overlays && overlays.length > 0) { | |
275 | + this.handleClearShow(); | |
276 | + for (let i = 0; i < overlays.length; i++) { | |
277 | + this.handleAddOverlay(overlays[i]); | |
278 | + } | |
279 | + } | |
280 | + }; | |
281 | + | |
282 | + /** | |
283 | + * 给地图上添加覆盖物 | |
284 | + */ | |
285 | + handleAddOverlay = (options: MapIF.Overlays) => { | |
286 | + const styleOptions = { | |
287 | + strokeColor: '#4189FD', | |
288 | + strokeWeight: 3, | |
289 | + strokeOpacity: 0.8, | |
290 | + }; | |
291 | + if (options.type === MapType.POINT) { | |
292 | + const temp = options.point; | |
293 | + const point = new BMap.Point(temp.lng, temp.lat); | |
294 | + const marker = new BMap.Marker(); | |
295 | + this.MapInstance.addOverlay(marker); | |
296 | + this.MapInstance.panTo([point]); | |
297 | + this.CurrentOverlay = { type: options.type, overlay: marker }; | |
298 | + } else if (options.type === MapType.POLYLINE) { | |
299 | + const points = []; | |
300 | + for (let i = 0; i < options.points.length; i++) { | |
301 | + const point = options.points[i]; | |
302 | + // points.push(new BMap.Point(point.lng, point.lat)); | |
303 | + points.push({ longitude: point.lng, latitude: point.lat }); | |
304 | + } | |
305 | + this.setState({ PolygonPath: points, mapCenter: points[0] }); | |
306 | + this.CurrentOverlay = { type: options.type, overlay: null }; | |
307 | + } else if (options.type === MapType.POLYGON) { | |
308 | + const points = []; | |
309 | + for (let i = 0; i < options.points.length; i++) { | |
310 | + const point = options.points[i]; | |
311 | + points.push({ longitude: point.lng, latitude: point.lat }); | |
312 | + } | |
313 | + this.setState({ PolygonPath: points, mapCenter: points[0] }); | |
314 | + this.CurrentOverlay = { type: options.type, overlay: null }; | |
315 | + } else if (options.type === MapType.DISTRICT) { | |
316 | + this.handleShowRegion(options.region); | |
317 | + } else if (options.type === MapType.CIRCLE) { | |
318 | + const point: any = options.point || {}; | |
319 | + const circlePoint = { longitude: point.lng, latitude: point.lat }; | |
320 | + this.setState({ CirclePath: { ...circlePoint, radius: options.radius! }, mapCenter: circlePoint }); | |
321 | + this.CurrentOverlay = { type: options.type, overlay: null }; | |
322 | + } | |
323 | + if (options.edit) { | |
324 | + this.setState({ editing: true, editActive: true, fenceName: options.name }); | |
325 | + } | |
326 | + }; | |
327 | + | |
328 | + editEvents = { | |
329 | + move: () => { console.log('circle move') }, | |
330 | + adjust: () => { | |
331 | + console.log('circle adjust'); | |
332 | + }, | |
333 | + end: (e) => { | |
334 | + if (this.state.editing) { | |
335 | + this.handleEditComplete(e.target); | |
336 | + } else { | |
337 | + this.handleClearShow(); | |
338 | + } | |
339 | + }, | |
340 | + created: (ins) => { console.log(ins) } | |
341 | + } | |
342 | + | |
343 | + toggleAdd = () => { | |
344 | + this.setState({ | |
345 | + editActive: false | |
346 | + }); | |
347 | + } | |
348 | + /** | |
349 | + * 地图显示区域 | |
350 | + */ | |
351 | + handleShowRegion = (region: string) => { | |
352 | + const bdary = new BMap.Boundary(); | |
353 | + const styleOptions = { | |
354 | + strokeColor: '#4189FD', | |
355 | + strokeWeight: 3, | |
356 | + strokeOpacity: 0.8, | |
357 | + }; | |
358 | + bdary.get(region, response => { | |
359 | + this.MapInstance.clearOverlays(); //清除地图覆盖物 | |
360 | + const count = response.boundaries.length; //行政区域的点有多少个 | |
361 | + if (count === 0) { | |
362 | + message.error('未能获取当前输入行政区域!'); | |
363 | + return; | |
364 | + } | |
365 | + let pointArray = []; | |
366 | + for (let i = 0; i < count; i++) { | |
367 | + const ply = new BMap.Polygon(response.boundaries[i], styleOptions); //建立多边形覆盖物 | |
368 | + this.MapInstance.addOverlay(ply); //添加覆盖物 | |
369 | + pointArray = pointArray.concat(ply.getPath()); | |
370 | + } | |
371 | + this.MapInstance.setViewport(pointArray); //调整视野 | |
372 | + }); | |
373 | + }; | |
374 | + | |
375 | + /** | |
376 | + * 清空绘制图 | |
377 | + */ | |
378 | + handleClearAll = () => { | |
379 | + this.handleClearShow(); | |
380 | + this.handleClearDraw(); | |
381 | + message.success('清空成功!'); | |
382 | + }; | |
383 | + | |
384 | + /** | |
385 | + * 清空绘制图层 | |
386 | + */ | |
387 | + handleClearDraw = () => { | |
388 | + this.close(); | |
389 | + this.DrawOverlays.length = 0; | |
390 | + }; | |
391 | + | |
392 | + /** | |
393 | + * 清空展示图层 | |
394 | + */ | |
395 | + handleClearShow = () => { | |
396 | + this.CurrentOverlay = { type: '', overlay: null }; | |
397 | + this.setState({ editing: false, editActive: false, CirclePath: {}, PolygonPath: [] }); | |
398 | + this.close(); | |
399 | + }; | |
400 | + | |
401 | + /** | |
402 | + * 关键字检索 | |
403 | + */ | |
404 | + handleKeyword = ({ name }) => { | |
405 | + const myKeys = [name]; | |
406 | + const local = new BMap.LocalSearch(this.MapInstance, { | |
407 | + renderOptions: { map: this.MapInstance, panel: 'searchPanel' }, | |
408 | + pageCapacity: 5, | |
409 | + }); | |
410 | + local.searchInBounds(myKeys, this.MapInstance.getBounds()); | |
411 | + }; | |
412 | + | |
413 | + render() { | |
414 | + const { editing, editActive, fenceName, CirclePath, PolygonPath, mapCenter } = this.state; | |
415 | + const { drawingTypes } = this.props; | |
416 | + | |
417 | + return ( | |
418 | + <div className="mapCenter"> | |
419 | + {/* <div id={this.MapKey} className='mapContainer' /> */} | |
420 | + <div style={{ height: 700 }}> | |
421 | + <AMap | |
422 | + zoom={16} | |
423 | + viewMode="3D" | |
424 | + amapkey="438e704a19d6259e1dce9ada54c02b21" | |
425 | + plugins={this.mapPlugins} | |
426 | + center={mapCenter} | |
427 | + > | |
428 | + {this.CurrentOverlay.type === "circle" && ( | |
429 | + <Circle style={styleOptions} bubble={false} radius={CirclePath.radius} center={{ longitude: CirclePath.longitude, latitude: CirclePath.latitude }}> | |
430 | + <CircleEditor events={this.editEvents} active={editActive} /> | |
431 | + </Circle> | |
432 | + )} | |
433 | + {this.CurrentOverlay.type === "polygon" && ( | |
434 | + <Polygon style={styleOptions} path={PolygonPath}> | |
435 | + <PolyEditor active={editActive} events={this.editEvents} /> | |
436 | + </Polygon> | |
437 | + )} | |
438 | + <MouseTool events={this.toolEvents} /> | |
439 | + </AMap> | |
440 | + </div> | |
441 | + <div className="layerStyle">{this.state.what}</div> | |
442 | + <Input className="input" placeholder="搜索位置" style={{ width: 200 }} allowClear id="tipinput" /> | |
443 | + {drawingTypes && ( | |
444 | + <div className="toolContainer"> | |
445 | + {drawingTypes.includes("polygon") && ( | |
446 | + <Button title="绘制多边形" onClick={() => this.drawPolygon()}>多边形</Button> | |
447 | + )} | |
448 | + {drawingTypes.includes("rectangle") && ( | |
449 | + <Button onClick={() => { this.drawRectangle(); }}>矩形</Button> | |
450 | + )} | |
451 | + {drawingTypes.includes("circle") && ( | |
452 | + <Button title="绘制圆形" onClick={() => this.drawCircle()}>圆形</Button> | |
453 | + )} | |
454 | + <Button title="清空绘图" onClick={() => (editing ? this.handleEditCancel() : this.handleClearAll())}>清空画图</Button> | |
455 | + </div> | |
456 | + )} | |
457 | + {editing && ( | |
458 | + <div className="btnContainer"> | |
459 | + <div className="title">{fenceName}</div> | |
460 | + <div className="btns"> | |
461 | + <Button className="cancel" onClick={this.handleEditCancel}> | |
462 | + 取消 | |
463 | + </Button> | |
464 | + <Button type="primary" onClick={this.toggleAdd}> | |
465 | + 完成 | |
466 | + </Button> | |
467 | + </div> | |
468 | + </div> | |
469 | + )} | |
470 | + {/* <div className={style.searchContainer}> | |
471 | + <FenceFilter searchKey="name" placeholder="关键字检索" onSearch={this.handleKeyword} /> | |
472 | + <div className={style.searchPanel} id="searchPanel" /> | |
473 | + </div> */} | |
474 | + </div> | |
475 | + ); | |
476 | + } | |
477 | +} | |
478 | + | |
479 | +export default MapCenter; | ... | ... |
src/pages/vms/Fence/AMapCenter/interface.d.ts
0 → 100644
1 | +declare namespace MapIF { | |
2 | + /** | |
3 | + * | |
4 | + */ | |
5 | + interface Overlays { | |
6 | + type?: 'point' | 'circle' | 'polyline' | 'polygon' | 'district'; | |
7 | + name?: string; | |
8 | + points?: Array<Point>; | |
9 | + point?: Point; | |
10 | + region?: string; | |
11 | + radius?: number; | |
12 | + edit?: boolean; | |
13 | + } | |
14 | + | |
15 | + /** | |
16 | + * 点 | |
17 | + */ | |
18 | + interface Point { | |
19 | + lat: number; | |
20 | + lng: number; | |
21 | + } | |
22 | + | |
23 | + interface CirclePath { | |
24 | + longitude: number; | |
25 | + latitude: number; | |
26 | + radius: number; | |
27 | + } | |
28 | + | |
29 | + /** | |
30 | + * 绘制返回结果 | |
31 | + */ | |
32 | + interface DrawResponse { | |
33 | + edit: boolean; | |
34 | + type?: 'circle' | 'polyline' | 'polygon'; | |
35 | + points?: Array<Point>; | |
36 | + point?: Point; | |
37 | + radius?: number; | |
38 | + } | |
39 | +} | ... | ... |
src/pages/vms/Fence/AMapCenter/style.less
0 → 100644
1 | +.mapCenter { | |
2 | + height: 100%; | |
3 | + position: relative; | |
4 | +} | |
5 | + | |
6 | +.mapContainer { | |
7 | + height: 100%; | |
8 | + min-height: 700px; | |
9 | + transition: all 0.5s ease-in-out; | |
10 | +} | |
11 | + | |
12 | +.toolContainer { | |
13 | + position: absolute; | |
14 | + right: 6px; | |
15 | + top: 15px; | |
16 | + z-index: 99; | |
17 | +} | |
18 | + | |
19 | +.input { | |
20 | + position: absolute; | |
21 | + left: 6px; | |
22 | + top: 8px; | |
23 | + z-index: 99; | |
24 | +} | |
25 | + | |
26 | +.toolBtn { | |
27 | + width: 64px; | |
28 | + height: 45px; | |
29 | + display: inline-block; | |
30 | + line-height: 43px; | |
31 | + text-align: center; | |
32 | + background-color: #fbf9f9; | |
33 | + border-radius: 5px; | |
34 | + font-weight: bold; | |
35 | + font-size: 28px; | |
36 | + color: #007aba; | |
37 | +} | |
38 | + | |
39 | +.btnContainer { | |
40 | + // position: absolute; | |
41 | + // left: 5px; | |
42 | + // top: 5px; | |
43 | + // padding: 10px; | |
44 | + // background-color: #fff; | |
45 | + // border: 1px solid #efefef; | |
46 | + // border-radius: 4px; | |
47 | + // z-index: 99; | |
48 | +} | |
49 | + | |
50 | +.layerStyle { | |
51 | + padding: 5px; | |
52 | + border: 1px solid #ddd; | |
53 | + border-radius: 4; | |
54 | + // position: absolute; | |
55 | + // top: 10; | |
56 | + // left: 10; | |
57 | +} | |
58 | + | |
59 | +.title { | |
60 | + font-size: 16px; | |
61 | + margin-bottom: 10px; | |
62 | + color: #333; | |
63 | +} | |
64 | + | |
65 | +.btns { | |
66 | + text-align: right; | |
67 | +} | |
68 | + | |
69 | +.cancel { | |
70 | + margin-right: 10px; | |
71 | +} | |
72 | + | |
73 | +.searchContainer { | |
74 | + position: absolute; | |
75 | + left: 0; | |
76 | + right: 0; | |
77 | + top: 15px; | |
78 | + z-index: 99; | |
79 | + width: 240px; | |
80 | + margin: auto; | |
81 | +} | |
82 | + | |
83 | +.searchPanel { | |
84 | + background-color: #fff; | |
85 | +} | |
0 | 86 | \ No newline at end of file | ... | ... |
src/pages/vms/Fence/AMapCenter/util.ts
0 → 100644
1 | +import { common } from '@/typing/common'; | |
2 | + | |
3 | +/** | |
4 | + * 转化字符串点集为数组 | |
5 | + */ | |
6 | +export function parseVertexes(vertexes: string): Array<MapIF.Point> { | |
7 | + const points: Array<MapIF.Point> = []; | |
8 | + if (~vertexes.indexOf(';')) { | |
9 | + const tempArray = vertexes.split(';'); | |
10 | + tempArray.map((item: string) => { | |
11 | + if (~item.indexOf(',')) { | |
12 | + const temp = item.split(','); | |
13 | + points.push({ lng: Number(temp[0]), lat: Number(temp[1]) }); | |
14 | + } | |
15 | + return item; | |
16 | + }); | |
17 | + } | |
18 | + return points; | |
19 | +} | |
20 | +/** | |
21 | + * 转化字符串点集为数组路径 | |
22 | + */ | |
23 | +export function parseVertexesPath(vertexes: string): Array<MapIF.Point> { | |
24 | + const points: Array<MapIF.Point> = []; | |
25 | + if (~vertexes.indexOf(';')) { | |
26 | + const tempArray = vertexes.split(';'); | |
27 | + tempArray.map((item: string) => { | |
28 | + if (~item.indexOf(',')) { | |
29 | + const temp = item.split(','); | |
30 | + points.push({ longitude: Number(temp[0]), latitude: Number(temp[1]) }); | |
31 | + } | |
32 | + return item; | |
33 | + }); | |
34 | + } | |
35 | + return points; | |
36 | +} | |
37 | + | |
38 | +/** | |
39 | + * 转化数组点集为字符串 | |
40 | + */ | |
41 | +export function stringifyVertexes(points: Array<MapIF.Point>): string { | |
42 | + return points.map(item => `${item.lng},${item.lat}`).join(';'); | |
43 | +} | |
44 | + | |
45 | +/** | |
46 | + * 地图覆盖物类型枚举 | |
47 | + */ | |
48 | +export const MapType: { | |
49 | + POINT: 'point'; | |
50 | + MARKER: 'marker'; | |
51 | + POLYLINE: 'polyline'; | |
52 | + POLYGON: 'polygon'; | |
53 | + CIRCLE: 'circle'; | |
54 | + RECT: 'rectangle'; | |
55 | + DISTRICT: 'district'; | |
56 | +} = { | |
57 | + POINT: 'point', | |
58 | + MARKER: 'marker', | |
59 | + POLYLINE: 'polyline', | |
60 | + POLYGON: 'polygon', | |
61 | + CIRCLE: 'circle', | |
62 | + RECT: 'rectangle', | |
63 | + DISTRICT: 'district', | |
64 | +}; | |
65 | + | |
66 | +/** | |
67 | + * 围栏类型枚举 | |
68 | + */ | |
69 | +export const FenceType: { | |
70 | + TESTDRIVE_PARK: 'testdrive_park'; | |
71 | + TESTDRIVE_WARN: 'testdrive_warn'; | |
72 | + TESTDRIVE_DISTRICT: 'testdrive_district'; | |
73 | + TESTDRIVE_GAS: 'testdrive_gas'; | |
74 | + RENTCAR_PARK: 'rentcar_park'; | |
75 | + RENTCAR_WARN: 'rentcar_warn'; | |
76 | + RENTCAR_DISTRICT: 'rentcar_district'; | |
77 | + RENTCAR_GAS: 'rentcar_gas'; | |
78 | + OFFICECAR_PARK: 'officecar_park'; | |
79 | + OFFICECAR_WARN: 'officecar_warn'; | |
80 | + OFFICECAR_DISTRICT: 'officecar_district'; | |
81 | +} = { | |
82 | + TESTDRIVE_PARK: 'testdrive_park', | |
83 | + TESTDRIVE_WARN: 'testdrive_warn', | |
84 | + TESTDRIVE_DISTRICT: 'testdrive_district', | |
85 | + TESTDRIVE_GAS: 'testdrive_gas', | |
86 | + RENTCAR_PARK: 'rentcar_park', | |
87 | + RENTCAR_WARN: 'rentcar_warn', | |
88 | + RENTCAR_DISTRICT: 'rentcar_district', | |
89 | + RENTCAR_GAS: 'rentcar_gas', | |
90 | + OFFICECAR_PARK: 'officecar_park', | |
91 | + OFFICECAR_WARN: 'officecar_warn', | |
92 | + OFFICECAR_DISTRICT: 'officecar_district', | |
93 | +}; | |
94 | + | |
95 | +/** | |
96 | + * 围栏类型映射 | |
97 | + */ | |
98 | +export const FenceMap: { | |
99 | + [key: string]: { | |
100 | + fenceType: number; // (围栏类型:1:报警围栏,2:停车围栏 3:加油区, 4.路线围栏, 5。行政区划围栏) | |
101 | + useType: number; // (车辆业务类型:1:试乘试驾,2:租赁,3:员工, 4:三方司机) | |
102 | + drawingTypes?: Array<string>; // 围栏绘制类型 (线、 面、 圆) | |
103 | + shapes?: Array<string>; // 围栏图形类型 (行政区会用到) | |
104 | + }; | |
105 | +} = { | |
106 | + [FenceType.TESTDRIVE_PARK]: { | |
107 | + fenceType: 2, | |
108 | + useType: 1, | |
109 | + drawingTypes: [MapType.POLYGON, MapType.CIRCLE], | |
110 | + shapes: [MapType.POLYGON, MapType.CIRCLE], | |
111 | + }, | |
112 | + [FenceType.TESTDRIVE_WARN]: { | |
113 | + fenceType: 1, | |
114 | + useType: 1, | |
115 | + drawingTypes: [MapType.POLYGON, MapType.CIRCLE], | |
116 | + shapes: [MapType.POLYGON, MapType.CIRCLE], | |
117 | + }, | |
118 | + [FenceType.TESTDRIVE_DISTRICT]: { | |
119 | + fenceType: 5, | |
120 | + useType: 1, | |
121 | + shapes: [MapType.DISTRICT], | |
122 | + }, | |
123 | + [FenceType.TESTDRIVE_GAS]: { | |
124 | + fenceType: 3, | |
125 | + useType: 1, | |
126 | + drawingTypes: [MapType.CIRCLE], | |
127 | + shapes: [MapType.CIRCLE], | |
128 | + }, | |
129 | + [FenceType.RENTCAR_PARK]: { | |
130 | + fenceType: 2, | |
131 | + useType: 2, | |
132 | + drawingTypes: [MapType.POLYGON, MapType.CIRCLE], | |
133 | + shapes: [MapType.POLYGON, MapType.CIRCLE], | |
134 | + }, | |
135 | + [FenceType.RENTCAR_WARN]: { | |
136 | + fenceType: 1, | |
137 | + useType: 2, | |
138 | + drawingTypes: [MapType.POLYGON, MapType.CIRCLE], | |
139 | + shapes: [MapType.POLYGON, MapType.CIRCLE], | |
140 | + }, | |
141 | + [FenceType.RENTCAR_DISTRICT]: { | |
142 | + fenceType: 5, | |
143 | + useType: 2, | |
144 | + shapes: [MapType.DISTRICT], | |
145 | + }, | |
146 | + [FenceType.RENTCAR_GAS]: { | |
147 | + fenceType: 3, | |
148 | + useType: 2, | |
149 | + drawingTypes: [MapType.CIRCLE], | |
150 | + shapes: [MapType.CIRCLE], | |
151 | + }, | |
152 | + [FenceType.OFFICECAR_PARK]: { | |
153 | + fenceType: 2, | |
154 | + useType: 5, | |
155 | + drawingTypes: [MapType.POLYGON, MapType.CIRCLE], | |
156 | + shapes: [MapType.POLYGON, MapType.CIRCLE], | |
157 | + }, | |
158 | + [FenceType.OFFICECAR_WARN]: { | |
159 | + fenceType: 1, | |
160 | + useType: 5, | |
161 | + drawingTypes: [MapType.POLYGON, MapType.CIRCLE], | |
162 | + shapes: [MapType.POLYGON, MapType.CIRCLE], | |
163 | + }, | |
164 | + [FenceType.OFFICECAR_DISTRICT]: { | |
165 | + fenceType: 5, | |
166 | + useType: 5, | |
167 | + shapes: [MapType.DISTRICT], | |
168 | + }, | |
169 | +}; | |
170 | + | |
171 | +/** | |
172 | + * Madel数据 | |
173 | + */ | |
174 | +export interface FenceState { | |
175 | + [FenceType.TESTDRIVE_PARK]: common.Page<Fence.FenceItem>; | |
176 | + [FenceType.TESTDRIVE_WARN]: common.Page<Fence.FenceItem>; | |
177 | + [FenceType.TESTDRIVE_DISTRICT]: common.Page<Fence.FenceItem>; | |
178 | + [FenceType.TESTDRIVE_GAS]: common.Page<Fence.FenceItem>; | |
179 | + [FenceType.RENTCAR_PARK]: common.Page<Fence.FenceItem>; | |
180 | + [FenceType.RENTCAR_WARN]: common.Page<Fence.FenceItem>; | |
181 | + [FenceType.RENTCAR_DISTRICT]: common.Page<Fence.FenceItem>; | |
182 | + [FenceType.RENTCAR_GAS]: common.Page<Fence.FenceItem>; | |
183 | + [FenceType.OFFICECAR_PARK]: common.Page<Fence.FenceItem>; | |
184 | + [FenceType.OFFICECAR_WARN]: common.Page<Fence.FenceItem>; | |
185 | + [FenceType.OFFICECAR_DISTRICT]: common.Page<Fence.FenceItem>; | |
186 | + VehicleParams: Fence.VehicleParams; | |
187 | + VehiclePage: common.Page<Fence.VehicleItem>; | |
188 | + MonVehicleList: Array<Fence.VehicleItem>; | |
189 | + DealerData: Array<Fence.DealerItem>; | |
190 | +} | ... | ... |
src/pages/vms/Fence/FenceManager/index.tsx
... | ... | @@ -2,7 +2,7 @@ import React, { Component } from 'react'; |
2 | 2 | import { connect } from 'umi'; |
3 | 3 | import { Modal } from 'antd'; |
4 | 4 | import { WrappedFormUtils } from 'antd/lib/form/Form'; |
5 | -import MapCenter from '@/pages/vms/Fence/MapCenter'; | |
5 | +import MapCenter from '@/pages/vms/Fence/AMapCenter'; | |
6 | 6 | import Filter from '../components/Filter'; |
7 | 7 | import FenceTable from '../components/FenceTable'; |
8 | 8 | import SelectTable from '../components/SelectTable'; |
... | ... | @@ -13,7 +13,7 @@ import { |
13 | 13 | MapType, |
14 | 14 | FenceMap, |
15 | 15 | FenceState, |
16 | -} from '@/pages/vms/Fence/MapCenter/util'; | |
16 | +} from '@/pages/vms/Fence/AMapCenter/util'; | |
17 | 17 | import { common } from '@/typing/common'; |
18 | 18 | import './style.less'; |
19 | 19 | |
... | ... | @@ -130,7 +130,7 @@ class FenceManager extends Component<Props, Object> { |
130 | 130 | radius: record.radius, |
131 | 131 | }); |
132 | 132 | } else if (record.shape === MapType.POLYLINE) { |
133 | - const points = parseVertexes(record.vertexes); | |
133 | + const points = parseVertexes(record.points); | |
134 | 134 | overlays.push({ |
135 | 135 | edit, |
136 | 136 | name: record.name, |
... | ... | @@ -138,7 +138,7 @@ class FenceManager extends Component<Props, Object> { |
138 | 138 | points, |
139 | 139 | }); |
140 | 140 | } else if (record.shape === MapType.POLYGON) { |
141 | - const points = parseVertexes(record.vertexes); | |
141 | + const points = parseVertexes(record.points); | |
142 | 142 | overlays.push({ |
143 | 143 | edit, |
144 | 144 | name: record.name, |
... | ... | @@ -238,16 +238,15 @@ class FenceManager extends Component<Props, Object> { |
238 | 238 | if (errors) return; |
239 | 239 | const { record } = this.state; |
240 | 240 | const params = { ...values }; |
241 | - if (values.shop && values.shop.key) { | |
242 | - params.shopId = values.shop.key; | |
243 | - params.shopName = values.shop.label; | |
241 | + if (values.shops) { | |
242 | + params.shops = values.shops.map(i => ({ shopId: i.value, shopName: i.label })); | |
244 | 243 | } |
245 | 244 | params.fenceType = this.params.fenceType; |
246 | 245 | params.useType = this.params.useType; |
247 | 246 | let actionType = ''; |
248 | 247 | if (this.drawData.type === MapType.POLYLINE) { |
249 | 248 | actionType = 'FenceModel/createPolyline'; |
250 | - params.vertexes = stringifyVertexes(this.drawData.points); | |
249 | + params.points = stringifyVertexes(this.drawData.points); | |
251 | 250 | } else if (this.drawData.type === MapType.CIRCLE) { |
252 | 251 | actionType = 'FenceModel/createCircle'; |
253 | 252 | params.lat = this.drawData.point.lat; |
... | ... | @@ -255,7 +254,7 @@ class FenceManager extends Component<Props, Object> { |
255 | 254 | params.radius = this.drawData.radius; |
256 | 255 | } else if (this.drawData.type === MapType.POLYGON) { |
257 | 256 | actionType = 'FenceModel/createPolygon'; |
258 | - params.vertexes = stringifyVertexes(this.drawData.points); | |
257 | + params.points = stringifyVertexes(this.drawData.points); | |
259 | 258 | } |
260 | 259 | if (record.id) { |
261 | 260 | params.id = record.id; | ... | ... |