Commit 6e9d80c33d300675b7b519d3f415b6ab88c1ce41
Merge branch 'master' into d-cas
Showing
37 changed files
with
1896 additions
and
1067 deletions
afterbuild.js
0 → 100644
1 | +const fs = require("fs"); | |
2 | + | |
3 | +const encoding = "UTF-8"; | |
4 | +/** | |
5 | + * 写入version信息方便判断版本 | |
6 | + */ | |
7 | +function sendfile() { | |
8 | + try { | |
9 | + const pathFolder = "./dist/version.text"; | |
10 | + deleteFolder(pathFolder); | |
11 | + fs.writeFileSync(pathFolder, new Date().getTime().toString(), { encoding }); | |
12 | + } catch (e) { | |
13 | + console.error("sourcemap文件写入失败", e); | |
14 | + } | |
15 | +} | |
16 | + | |
17 | +/**删除文件或文件夹 */ | |
18 | +function deleteFolder(path) { | |
19 | + let files = []; | |
20 | + if (fs.existsSync(path)) { | |
21 | + if (fs.statSync(path).isFile()) { | |
22 | + fs.unlinkSync(path); //删除文件 | |
23 | + } else { | |
24 | + files = fs.readdirSync(path); | |
25 | + files.forEach((file, index) => { | |
26 | + let curPath = path + "/" + file; | |
27 | + if (fs.statSync(curPath).isDirectory()) { | |
28 | + // recurse | |
29 | + deleteFolder(curPath); | |
30 | + } else { | |
31 | + // delete file | |
32 | + fs.unlinkSync(curPath); | |
33 | + } | |
34 | + }); | |
35 | + fs.rmdirSync(path); | |
36 | + } | |
37 | + } | |
38 | +} | |
39 | + | |
40 | +sendfile(); | ... | ... |
config/routers/pms.ts
... | ... | @@ -44,6 +44,10 @@ export default [ |
44 | 44 | component: './pms/storage/partShop' |
45 | 45 | }, |
46 | 46 | { |
47 | + path: '/pms/storage/fwStockPartShop', // 服务站配件(霏微(库存)) | |
48 | + component: './pms/storage/partShop' | |
49 | + }, | |
50 | + { | |
47 | 51 | path: '/pms/storage/areaStorage', // 区域库设置 |
48 | 52 | component: './pms/storage/areaStorageSetting' |
49 | 53 | }, | ... | ... |
package.json
... | ... | @@ -5,8 +5,8 @@ |
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", | |
9 | - "build:unset": "cross-env REACT_APP_ENV=dev umi build", | |
8 | + "build:prod": "cross-env REACT_APP_ENV=prod umi build && node afterbuild.js", | |
9 | + "build:unset": "cross-env REACT_APP_ENV=dev umi build && node afterbuild.js", | |
10 | 10 | "lint": "npm run lint:js && npm run lint:style && npm run lint:prettier", |
11 | 11 | "lint-staged": "lint-staged", |
12 | 12 | "lint-staged:js": "eslint --ext .js,.jsx,.ts,.tsx ", |
... | ... | @@ -14,16 +14,16 @@ |
14 | 14 | "lint:js": "eslint --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./", |
15 | 15 | "lint:prettier": "check-prettier lint", |
16 | 16 | "lint:style": "stylelint --fix \"src/**/*.less\" --syntax less", |
17 | + "package": "chmod +x ./build.sh && ./build.sh", | |
17 | 18 | "prettier": "prettier -c --write \"**/*\"", |
18 | 19 | "site": "cross-env npm run fetch:blocks && npm run build && npm run functions:build", |
19 | 20 | "start": "cross-env HOST=devlocal.feewee.cn umi dev", |
20 | 21 | "start:dev": "cross-env REACT_APP_ENV=dev MOCK=none UMI_UI=none HOST=devlocal.feewee.cn umi dev", |
21 | - "start:test": "cross-env REACT_APP_ENV=test MOCK=none UMI_UI=none HOST=testlocal.feewee.cn umi dev", | |
22 | 22 | "start:prod": "cross-env REACT_APP_ENV=prod MOCK=none UMI_UI=none HOST=local.feewee.cn umi dev", |
23 | + "start:test": "cross-env REACT_APP_ENV=test MOCK=none UMI_UI=none HOST=testlocal.feewee.cn umi dev", | |
23 | 24 | "test": "umi test", |
24 | 25 | "test:all": "node ./tests/run-tests.js", |
25 | - "test:component": "umi test ./src/components", | |
26 | - "package": "chmod +x ./build.sh && ./build.sh" | |
26 | + "test:component": "umi test ./src/components" | |
27 | 27 | }, |
28 | 28 | "husky": { |
29 | 29 | "hooks": {} | ... | ... |
src/components/GlobalFooter/index.tsx
1 | -import React from 'react'; | |
2 | -import { CopyrightOutlined } from '@ant-design/icons'; | |
3 | -import { Layout } from 'antd'; | |
4 | -import classNames from 'classnames'; | |
5 | -import styles from './index.less'; | |
1 | +import React, { useCallback, useEffect, useRef } from "react"; | |
2 | +import { CopyrightOutlined } from "@ant-design/icons"; | |
3 | +import { Button, Layout, Space, notification } from "antd"; | |
4 | +import classNames from "classnames"; | |
5 | +import styles from "./index.less"; | |
6 | +import { useIntl } from "umi"; | |
6 | 7 | |
7 | 8 | export interface IGlobalFooterProps { |
8 | 9 | links?: Array<{ |
... | ... | @@ -17,25 +18,74 @@ const { Footer } = Layout; |
17 | 18 | const COPYRIGHT = `${new Date().getFullYear()} 重庆霏微科技有限公司 渝ICP备17016156号-3`; |
18 | 19 | |
19 | 20 | const GlobalFooter = ({ links }: IGlobalFooterProps) => { |
21 | + const notifiShowRef = useRef<boolean>(false); | |
22 | + | |
23 | + const intl = useIntl(); | |
24 | + | |
25 | + useEffect(() => { | |
26 | + document.getElementById("fw_updater")?.addEventListener("click", showNotification); | |
27 | + return () => { | |
28 | + document.getElementById("fw_updater")?.removeEventListener("click", showNotification); | |
29 | + }; | |
30 | + }, []); | |
31 | + | |
32 | + const showNotification = useCallback(() => { | |
33 | + if (notifiShowRef?.current) { | |
34 | + return; | |
35 | + } | |
36 | + const key = `open${Date.now()}`; | |
37 | + const btn = ( | |
38 | + <Space> | |
39 | + <Button | |
40 | + size="small" | |
41 | + onClick={() => { | |
42 | + notification.close(key); | |
43 | + notifiShowRef.current = false; | |
44 | + }} | |
45 | + > | |
46 | + {intl.formatMessage({ id: "app.update.tip.close" })} | |
47 | + </Button> | |
48 | + <Button type="primary" size="small" onClick={() => window.location.reload()}> | |
49 | + {intl.formatMessage({ id: "app.update.tip.confirm" })} | |
50 | + </Button> | |
51 | + </Space> | |
52 | + ); | |
53 | + notification.open({ | |
54 | + message: intl.formatMessage({ id: "app.update.tip.title" }), | |
55 | + description: intl.formatMessage({ id: "app.update.tip.message" }), | |
56 | + btn, | |
57 | + placement: "bottomRight", | |
58 | + key, | |
59 | + duration: 0, | |
60 | + onClose: () => { | |
61 | + notifiShowRef.current = false; | |
62 | + }, | |
63 | + }); | |
64 | + notifiShowRef.current = true; | |
65 | + }, []); | |
66 | + | |
20 | 67 | const clsString = classNames(styles.globalFooter); |
21 | 68 | return ( |
22 | 69 | <Footer style={{ padding: 0 }}> |
23 | 70 | <div className={clsString}> |
24 | 71 | {links && ( |
25 | 72 | <div className={styles.links}> |
26 | - {links.map(link => ( | |
73 | + {links.map((link) => ( | |
27 | 74 | <a |
28 | 75 | key={link.key} |
29 | 76 | title={link.key} |
30 | - target={link.blankTarget ? '_blank' : '_self'} | |
77 | + target={link.blankTarget ? "_blank" : "_self"} | |
31 | 78 | href={link.href} |
79 | + rel="noreferrer" | |
32 | 80 | > |
33 | 81 | {link.title} |
34 | 82 | </a> |
35 | 83 | ))} |
36 | 84 | </div> |
37 | 85 | )} |
38 | - <div className={styles.copyright}>Copyright <CopyrightOutlined /> {COPYRIGHT}</div> | |
86 | + <div className={styles.copyright}> | |
87 | + Copyright <CopyrightOutlined /> {COPYRIGHT} | |
88 | + </div> | |
39 | 89 | </div> |
40 | 90 | </Footer> |
41 | 91 | ); | ... | ... |
src/global.tsx
src/locales/en-US.ts
... | ... | @@ -6,11 +6,16 @@ import settingDrawer from './en-US/settingDrawer'; |
6 | 6 | import settings from './en-US/settings'; |
7 | 7 | |
8 | 8 | export default { |
9 | - 'navBar.lang': 'Languages', | |
10 | - 'layout.user.link.help': 'Help', | |
11 | - 'layout.user.link.privacy': 'Privacy', | |
12 | - 'layout.user.link.terms': 'Terms', | |
13 | - 'app.preview.down.block': 'Download this page to your local project', | |
9 | + "navBar.lang": "Languages", | |
10 | + "layout.user.link.help": "Help", | |
11 | + "layout.user.link.privacy": "Privacy", | |
12 | + "layout.user.link.terms": "Terms", | |
13 | + "app.preview.down.block": "Download this page to your local project", | |
14 | + "app.update.tip.title": "Update Tips", | |
15 | + "app.update.tip.message": | |
16 | + "It is detected that the content of the website has been updated. Do you want to refresh the page to load the latest version?", | |
17 | + "app.update.tip.confirm": "Confirm", | |
18 | + "app.update.tip.close": "Close", | |
14 | 19 | ...globalHeader, |
15 | 20 | ...menu, |
16 | 21 | ...settingDrawer, | ... | ... |
src/locales/pt-BR.ts
... | ... | @@ -6,11 +6,16 @@ import settingDrawer from './pt-BR/settingDrawer'; |
6 | 6 | import settings from './pt-BR/settings'; |
7 | 7 | |
8 | 8 | export default { |
9 | - 'navBar.lang': 'Idiomas', | |
10 | - 'layout.user.link.help': 'ajuda', | |
11 | - 'layout.user.link.privacy': 'política de privacidade', | |
12 | - 'layout.user.link.terms': 'termos de serviços', | |
13 | - 'app.preview.down.block': 'Download this page to your local project', | |
9 | + "navBar.lang": "Idiomas", | |
10 | + "layout.user.link.help": "ajuda", | |
11 | + "layout.user.link.privacy": "política de privacidade", | |
12 | + "layout.user.link.terms": "termos de serviços", | |
13 | + "app.preview.down.block": "Download this page to your local project", | |
14 | + "app.update.tip.title": "Update Tips", | |
15 | + "app.update.tip.message": | |
16 | + "It is detected that the content of the website has been updated. Do you want to refresh the page to load the latest version?", | |
17 | + "app.update.tip.confirm": "Confirm", | |
18 | + "app.update.tip.close": "Close", | |
14 | 19 | ...globalHeader, |
15 | 20 | ...menu, |
16 | 21 | ...settingDrawer, | ... | ... |
src/locales/zh-CN.ts
... | ... | @@ -6,11 +6,15 @@ import settingDrawer from './zh-CN/settingDrawer'; |
6 | 6 | import settings from './zh-CN/settings'; |
7 | 7 | |
8 | 8 | export default { |
9 | - 'navBar.lang': '语言', | |
10 | - 'layout.user.link.help': '帮助', | |
11 | - 'layout.user.link.privacy': '隐私', | |
12 | - 'layout.user.link.terms': '条款', | |
13 | - 'app.preview.down.block': '下载此页面到本地项目', | |
9 | + "navBar.lang": "语言", | |
10 | + "layout.user.link.help": "帮助", | |
11 | + "layout.user.link.privacy": "隐私", | |
12 | + "layout.user.link.terms": "条款", | |
13 | + "app.preview.down.block": "下载此页面到本地项目", | |
14 | + "app.update.tip.title": "更新提示", | |
15 | + "app.update.tip.message": "检测到网站内容有更新,是否刷新页面加载最新版本?", | |
16 | + "app.update.tip.confirm": "确认", | |
17 | + "app.update.tip.close": "关闭", | |
14 | 18 | ...globalHeader, |
15 | 19 | ...menu, |
16 | 20 | ...settingDrawer, | ... | ... |
src/locales/zh-TW.ts
... | ... | @@ -6,11 +6,15 @@ import settingDrawer from './zh-TW/settingDrawer'; |
6 | 6 | import settings from './zh-TW/settings'; |
7 | 7 | |
8 | 8 | export default { |
9 | - 'navBar.lang': '語言', | |
10 | - 'layout.user.link.help': '幫助', | |
11 | - 'layout.user.link.privacy': '隱私', | |
12 | - 'layout.user.link.terms': '條款', | |
13 | - 'app.preview.down.block': '下載此頁面到本地項目', | |
9 | + "navBar.lang": "語言", | |
10 | + "layout.user.link.help": "幫助", | |
11 | + "layout.user.link.privacy": "隱私", | |
12 | + "layout.user.link.terms": "條款", | |
13 | + "app.preview.down.block": "下載此頁面到本地項目", | |
14 | + "app.update.tip.title": "更新提示", | |
15 | + "app.update.tip.message": "檢測到網站內容有更新,是否刷新頁面加載最新版本?", | |
16 | + "app.update.tip.confirm": "確認", | |
17 | + "app.update.tip.close": "關閉", | |
14 | 18 | ...globalHeader, |
15 | 19 | ...menu, |
16 | 20 | ...settingDrawer, | ... | ... |
src/pages/document.ejs
... | ... | @@ -3,19 +3,16 @@ |
3 | 3 | <head> |
4 | 4 | <meta charset="UTF-8" /> |
5 | 5 | <meta http-equiv="X-UA-Compatible" content="IE=edge" /> |
6 | - <meta | |
7 | - name="viewport" | |
8 | - content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" | |
9 | - /> | |
6 | + <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" /> | |
10 | 7 | <title>霏微汽车服务平台</title> |
11 | 8 | <script src="https://gw.alipayobjects.com/os/antv/pkg/_antv.data-set-0.9.6/dist/data-set.min.js"></script> |
12 | 9 | <!--加载鼠标绘制工具--> |
13 | 10 | <link rel="icon" href="/favicon.png" type="image/x-icon" /> |
14 | 11 | <!-- 高德地图 --> |
15 | 12 | <script type="text/javascript"> |
16 | - window._AMapSecurityConfig = { | |
17 | - securityJsCode: '235e8683072929e38b792ded30736d2d', | |
18 | - } | |
13 | + window._AMapSecurityConfig = { | |
14 | + securityJsCode: "235e8683072929e38b792ded30736d2d", | |
15 | + }; | |
19 | 16 | </script> |
20 | 17 | </head> |
21 | 18 | <body> |
... | ... | @@ -23,34 +20,34 @@ |
23 | 20 | <div id="root"> |
24 | 21 | <style> |
25 | 22 | .page-loading-warp { |
26 | - padding: 120px; | |
27 | 23 | display: flex; |
28 | - justify-content: center; | |
29 | 24 | align-items: center; |
25 | + justify-content: center; | |
26 | + padding: 120px; | |
30 | 27 | } |
31 | 28 | .ant-spin { |
29 | + position: absolute; | |
30 | + display: none; | |
32 | 31 | -webkit-box-sizing: border-box; |
33 | 32 | box-sizing: border-box; |
34 | 33 | margin: 0; |
35 | 34 | padding: 0; |
36 | 35 | color: rgba(0, 0, 0, 0.65); |
36 | + color: #1890ff; | |
37 | 37 | font-size: 14px; |
38 | 38 | font-variant: tabular-nums; |
39 | 39 | line-height: 1.5; |
40 | - list-style: none; | |
41 | - -webkit-font-feature-settings: 'tnum'; | |
42 | - font-feature-settings: 'tnum'; | |
43 | - position: absolute; | |
44 | - display: none; | |
45 | - color: #1890ff; | |
46 | 40 | text-align: center; |
47 | 41 | vertical-align: middle; |
42 | + list-style: none; | |
48 | 43 | opacity: 0; |
49 | 44 | -webkit-transition: -webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86); |
50 | 45 | transition: -webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86); |
51 | 46 | transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86); |
52 | 47 | transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86), |
53 | 48 | -webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86); |
49 | + -webkit-font-feature-settings: "tnum"; | |
50 | + font-feature-settings: "tnum"; | |
54 | 51 | } |
55 | 52 | |
56 | 53 | .ant-spin-spinning { |
... | ... | @@ -62,9 +59,9 @@ |
62 | 59 | .ant-spin-dot { |
63 | 60 | position: relative; |
64 | 61 | display: inline-block; |
65 | - font-size: 20px; | |
66 | 62 | width: 20px; |
67 | 63 | height: 20px; |
64 | + font-size: 20px; | |
68 | 65 | } |
69 | 66 | |
70 | 67 | .ant-spin-dot-item { |
... | ... | @@ -120,9 +117,9 @@ |
120 | 117 | } |
121 | 118 | |
122 | 119 | .ant-spin-lg .ant-spin-dot { |
123 | - font-size: 32px; | |
124 | 120 | width: 32px; |
125 | 121 | height: 32px; |
122 | + font-size: 32px; | |
126 | 123 | } |
127 | 124 | |
128 | 125 | .ant-spin-lg .ant-spin-dot i { |
... | ... | @@ -166,11 +163,12 @@ |
166 | 163 | <div class="page-loading-warp"> |
167 | 164 | <div class="ant-spin ant-spin-lg ant-spin-spinning"> |
168 | 165 | <span class="ant-spin-dot ant-spin-dot-spin" |
169 | - ><i class="ant-spin-dot-item"></i><i class="ant-spin-dot-item"></i | |
170 | - ><i class="ant-spin-dot-item"></i><i class="ant-spin-dot-item"></i | |
166 | + ><i class="ant-spin-dot-item"></i><i class="ant-spin-dot-item"></i><i class="ant-spin-dot-item"></i | |
167 | + ><i class="ant-spin-dot-item"></i | |
171 | 168 | ></span> |
172 | 169 | </div> |
173 | 170 | </div> |
174 | 171 | </div> |
172 | + <button id="fw_updater" style="display: none"></button> | |
175 | 173 | </body> |
176 | 174 | </html> | ... | ... |
src/pages/order3/SaleTask/api.ts
... | ... | @@ -25,6 +25,7 @@ export interface GetSaleTaskApiRes { |
25 | 25 | testDriveTaskCount: number; |
26 | 26 | seriesTaskCount: number; |
27 | 27 | vehicleGrossProfitTask: number; |
28 | + totalGrossProfitTask: number; | |
28 | 29 | } |
29 | 30 | |
30 | 31 | export interface SeriesTaskItem { |
... | ... | @@ -71,6 +72,8 @@ export interface ShopTaskItem { |
71 | 72 | seriesTaskCount: number; |
72 | 73 | vehicleGrossProfitTask: number; |
73 | 74 | taskId?: number; |
75 | + orderTaskApplyId?: number; | |
76 | + orderShopTaskId?: number; | |
74 | 77 | } |
75 | 78 | |
76 | 79 | /** 月度零售任务列表 */ |
... | ... | @@ -81,8 +84,8 @@ export function getSaleTaskApi( |
81 | 84 | } |
82 | 85 | |
83 | 86 | export interface GetShopSaleTaskReq { |
84 | - shopId: number; | |
85 | - taskDate: number; | |
87 | + shopId?: number; | |
88 | + taskDate?: number; | |
86 | 89 | } |
87 | 90 | |
88 | 91 | /** 门店零售任务详情 */ |
... | ... | @@ -109,6 +112,54 @@ export function submitSaleTask(params: { id: number }): PromiseResp<boolean> { |
109 | 112 | return request.post(`${ORDER3_HOST}/erp/sales/task/submit`, params); |
110 | 113 | } |
111 | 114 | |
115 | +export interface AutoAssignItem { | |
116 | + shopId: number; | |
117 | + taskCount: number; | |
118 | + newEnergyTaskCount: number; | |
119 | + fuelVehicleTaskCount: number; | |
120 | + tackCarTaskCount: number; | |
121 | +} | |
122 | + | |
123 | +export interface AutoAssignSaleTaskReq { | |
124 | + id: number; | |
125 | + assignTask: boolean; | |
126 | + shopTaskList: AutoAssignItem[]; | |
127 | +} | |
128 | + | |
129 | +/** 自动分配零售任务 */ | |
130 | +export function autoAssignSaleTask( | |
131 | + params: AutoAssignSaleTaskReq | |
132 | +): PromiseResp<boolean> { | |
133 | + return request.post(`${ORDER3_HOST}/erp/sales/task/auto/assign`, params); | |
134 | +} | |
135 | + | |
136 | +interface BatchSetSaleTaskItem { | |
137 | + shopIdList: number[]; | |
138 | + taskAims: number; | |
139 | +} | |
140 | + | |
141 | +export interface BatchSetSaleTaskReq { | |
142 | + grossProfitTaskList?: BatchSetSaleTaskItem[]; | |
143 | + tackCarTaskList?: BatchSetSaleTaskItem[]; | |
144 | + testDriveTaskList?: BatchSetSaleTaskItem[]; | |
145 | + assignTask: boolean; | |
146 | + orderTaskApplyId: number; | |
147 | +} | |
148 | + | |
149 | +/** 批量设置零售任务 */ | |
150 | +export function batchSetSaleTask( | |
151 | + params: BatchSetSaleTaskReq | |
152 | +): PromiseResp<boolean> { | |
153 | + return request.post(`${ORDER3_HOST}/erp/sales/task/batch/shop/set`, params); | |
154 | +} | |
155 | + | |
156 | +/** 自动分配单个门店的零售任务 */ | |
157 | +export function autoAssignOneShop( | |
158 | + params: ShopTaskItem | |
159 | +): PromiseResp<boolean> { | |
160 | + return request.post(`${ORDER3_HOST}/erp/sales/task/auto/assign/shop`, params); | |
161 | +} | |
162 | + | |
112 | 163 | export interface BrandItem { |
113 | 164 | id: number; |
114 | 165 | initial: string; |
... | ... | @@ -148,9 +199,10 @@ export interface PreviewTaskReq { |
148 | 199 | secondManageId?: number; |
149 | 200 | thirdManageId?: number; |
150 | 201 | taskId?: number; |
151 | - orderTaskApprovalType: number; | |
152 | - id: number; | |
202 | + orderTaskApprovalType?: number; | |
203 | + id?: number; | |
153 | 204 | token?: string; |
205 | + keywords?: string; | |
154 | 206 | } |
155 | 207 | |
156 | 208 | export interface TaskListItem { |
... | ... | @@ -188,7 +240,9 @@ export interface PreviewTaskRes { |
188 | 240 | } |
189 | 241 | |
190 | 242 | /** 预览任务 */ |
191 | -export function previewTask(params: PreviewTaskReq): PromiseResp<PreviewTaskRes> { | |
243 | +export function previewTask( | |
244 | + params: PreviewTaskReq | |
245 | +): PromiseResp<PreviewTaskRes> { | |
192 | 246 | return request.get(`${ORDER3_HOST}/erp/sales/task/approve/info`, { |
193 | 247 | params, |
194 | 248 | }); | ... | ... |
src/pages/order3/SaleTask/components/AdviserTaskPreview.tsx
... | ... | @@ -4,8 +4,7 @@ import { observer } from "mobx-react-lite"; |
4 | 4 | import * as API from "../api"; |
5 | 5 | import useInitial from "@/hooks/useInitail"; |
6 | 6 | import ModifiedTableCell from "./ModifiedTableCell"; |
7 | - | |
8 | -const { Column } = Table; | |
7 | +import { ColumnsType } from "antd/es/table"; | |
9 | 8 | |
10 | 9 | // 查看销顾任务弹框 |
11 | 10 | interface AdviserTaskPreviewProps { |
... | ... | @@ -31,73 +30,103 @@ const AdviserTaskPreview = ({ |
31 | 30 | showSeriesModal(record); |
32 | 31 | }; |
33 | 32 | |
33 | + const columns: ColumnsType<API.TaskListItem> = [ | |
34 | + { | |
35 | + title: "姓名", | |
36 | + width: 100, | |
37 | + dataIndex: "dataName", | |
38 | + filterSearch: true, | |
39 | + onFilter: ( | |
40 | + value: string | number | boolean, | |
41 | + record: API.TaskListItem | |
42 | + ) => { | |
43 | + return record.dataName.startsWith(value.toString()); | |
44 | + }, | |
45 | + }, | |
46 | + { | |
47 | + title: "零售任务(台)", | |
48 | + children: [ | |
49 | + { | |
50 | + title: "合计", | |
51 | + dataIndex: "taskCount", | |
52 | + key: "taskCount", | |
53 | + render: (text: string, record: API.TaskListItem) => { | |
54 | + return ModifiedTableCell(record, "taskCount"); | |
55 | + }, | |
56 | + }, | |
57 | + { | |
58 | + title: "新能源车", | |
59 | + dataIndex: "newEnergyTaskCount", | |
60 | + key: "newEnergyTaskCount", | |
61 | + render: (text: string, record: API.TaskListItem) => { | |
62 | + return ModifiedTableCell(record, "newEnergyTaskCount"); | |
63 | + }, | |
64 | + }, | |
65 | + { | |
66 | + title: "传统燃油车", | |
67 | + dataIndex: "fuelVehicleTaskCount", | |
68 | + key: "fuelVehicleTaskCount", | |
69 | + render: (text: string, record: API.TaskListItem) => { | |
70 | + return ModifiedTableCell(record, "fuelVehicleTaskCount"); | |
71 | + }, | |
72 | + }, | |
73 | + ], | |
74 | + }, | |
75 | + { | |
76 | + title: "单车毛利任务(元)", | |
77 | + dataIndex: "vehicleGrossProfitTask", | |
78 | + render: (text: string, record: API.TaskListItem) => { | |
79 | + if (record.dataId === -999) { | |
80 | + return <div style={{ textAlign: "center" }}>-</div>; | |
81 | + } | |
82 | + return ModifiedTableCell(record, "vehicleGrossProfitTask"); | |
83 | + }, | |
84 | + }, | |
85 | + { | |
86 | + title: "线索到店成交(台)", | |
87 | + width: 100, | |
88 | + dataIndex: "clueDealTaskCount", | |
89 | + render: (text: string, record: API.TaskListItem) => { | |
90 | + return ModifiedTableCell(record, "clueDealTaskCount"); | |
91 | + }, | |
92 | + }, | |
93 | + { | |
94 | + title: "首客试驾成交(台)", | |
95 | + width: 100, | |
96 | + dataIndex: "testDriveTaskCount", | |
97 | + render: (text: string, record: API.TaskListItem) => { | |
98 | + return ModifiedTableCell(record, "testDriveTaskCount"); | |
99 | + }, | |
100 | + }, | |
101 | + { | |
102 | + title: "攻坚车任务(台)", | |
103 | + width: 100, | |
104 | + dataIndex: "tackCarTaskCount", | |
105 | + render: (text: string, record: API.TaskListItem) => { | |
106 | + return ModifiedTableCell(record, "tackCarTaskCount"); | |
107 | + }, | |
108 | + }, | |
109 | + { | |
110 | + title: "车系任务(台)", | |
111 | + width: 100, | |
112 | + dataIndex: "seriesTaskCount", | |
113 | + render: (text: string, record: API.TaskListItem) => { | |
114 | + if (record.dataId === -999) return text; | |
115 | + return <a onClick={() => handlePreviewSeriesTask(record)}>{text}</a>; | |
116 | + }, | |
117 | + }, | |
118 | + ]; | |
119 | + | |
34 | 120 | return ( |
35 | 121 | <Table |
122 | + bordered | |
36 | 123 | rowKey="dataId" |
37 | 124 | loading={loading} |
125 | + columns={columns} | |
38 | 126 | dataSource={data.taskList} |
39 | 127 | pagination={false} |
40 | 128 | scroll={{ y: 450 }} |
41 | - > | |
42 | - <Column title="姓名" dataIndex="dataName" /> | |
43 | - <Column | |
44 | - title="零售任务(台)" | |
45 | - dataIndex="taskCount" | |
46 | - render={(text: string, record: API.TaskListItem) => { | |
47 | - return ModifiedTableCell(record, "taskCount"); | |
48 | - }} | |
49 | - /> | |
50 | - <Column | |
51 | - title="新能源车任务(台)" | |
52 | - dataIndex="newEnergyTaskCount" | |
53 | - render={(text: string, record: API.TaskListItem) => { | |
54 | - return ModifiedTableCell(record, "newEnergyTaskCount"); | |
55 | - }} | |
56 | - /> | |
57 | - <Column | |
58 | - title="传统燃油车任务(台)" | |
59 | - dataIndex="fuelVehicleTaskCount" | |
60 | - render={(text: string, record: API.TaskListItem) => { | |
61 | - return ModifiedTableCell(record, "fuelVehicleTaskCount"); | |
62 | - }} | |
63 | - /> | |
64 | - <Column | |
65 | - title="车辆毛利任务(元)" | |
66 | - dataIndex="vehicleGrossProfitTask" | |
67 | - render={(text: string, record: API.TaskListItem) => { | |
68 | - return ModifiedTableCell(record, "vehicleGrossProfitTask"); | |
69 | - }} | |
70 | - /> | |
71 | - <Column | |
72 | - title="线索到店零售台数(台)" | |
73 | - dataIndex="clueDealTaskCount" | |
74 | - render={(text: string, record: API.TaskListItem) => { | |
75 | - return ModifiedTableCell(record, "clueDealTaskCount"); | |
76 | - }} | |
77 | - /> | |
78 | - <Column | |
79 | - title="首客试驾成交任务数(台)" | |
80 | - dataIndex="testDriveTaskCount" | |
81 | - render={(text: string, record: API.TaskListItem) => { | |
82 | - return ModifiedTableCell(record, "testDriveTaskCount"); | |
83 | - }} | |
84 | - /> | |
85 | - <Column | |
86 | - title="攻坚车任务数(台)" | |
87 | - dataIndex="tackCarTaskCount" | |
88 | - render={(text: string, record: API.TaskListItem) => { | |
89 | - return ModifiedTableCell(record, "tackCarTaskCount"); | |
90 | - }} | |
91 | - /> | |
92 | - <Column | |
93 | - title="车系任务数(台)" | |
94 | - dataIndex="seriesTaskCount" | |
95 | - render={(text: string, record: API.TaskListItem) => { | |
96 | - if (record.dataId === -999) return text; | |
97 | - return <a onClick={() => handlePreviewSeriesTask(record)}>{text}</a>; | |
98 | - }} | |
99 | - /> | |
100 | - </Table> | |
129 | + /> | |
101 | 130 | ); |
102 | 131 | }; |
103 | 132 | ... | ... |
src/pages/order3/SaleTask/components/EntryTaskPreview.tsx
1 | 1 | import React, { useState } from "react"; |
2 | -import { Card, Radio, RadioChangeEvent, Row, Table } from "antd"; | |
2 | +import { | |
3 | + Card, | |
4 | + DatePicker, | |
5 | + Input, | |
6 | + Radio, | |
7 | + RadioChangeEvent, | |
8 | + Row, | |
9 | + Table, | |
10 | +} from "antd"; | |
3 | 11 | import { observer } from "mobx-react-lite"; |
4 | 12 | import * as API from "../api"; |
5 | 13 | import { OrderTaskApprovalType } from "../entity"; |
6 | 14 | import useInitial from "@/hooks/useInitail"; |
7 | 15 | import ModifiedTableCell from "./ModifiedTableCell"; |
16 | +import { ColumnsType } from "antd/es/table"; | |
17 | +import { Moment } from "moment"; | |
8 | 18 | |
9 | -const { Column } = Table; | |
10 | 19 | const RadioButton = Radio.Button; |
11 | 20 | const RadioGroup = Radio.Group; |
12 | 21 | |
13 | 22 | // 预览任务入口弹框 |
14 | 23 | interface EntryTaskPreviewProps { |
24 | + month: Moment; | |
15 | 25 | params: any; // API.PreviewTaskReq |
16 | 26 | showAdviserModal: ( |
17 | 27 | record: API.TaskListItem, |
... | ... | @@ -24,11 +34,13 @@ interface EntryTaskPreviewProps { |
24 | 34 | } |
25 | 35 | |
26 | 36 | const EntryTaskPreview = ({ |
37 | + month, | |
27 | 38 | params, |
28 | 39 | showAdviserModal, |
29 | 40 | showSeriesModal, |
30 | 41 | }: EntryTaskPreviewProps) => { |
31 | 42 | const [type, setType] = useState(OrderTaskApprovalType.门店维度); |
43 | + const [keywords, setKeywords] = useState(""); | |
32 | 44 | |
33 | 45 | const { data, loading, setParams } = useInitial< |
34 | 46 | API.PreviewTaskRes, |
... | ... | @@ -40,15 +52,13 @@ const EntryTaskPreview = ({ |
40 | 52 | if (value === 99) { |
41 | 53 | setType(OrderTaskApprovalType.新车一级管理维度); |
42 | 54 | setParams( |
43 | - // @ts-ignore | |
44 | 55 | { orderTaskApprovalType: OrderTaskApprovalType.新车一级管理维度 }, |
45 | 56 | true |
46 | 57 | ); |
47 | 58 | return; |
48 | 59 | } |
49 | 60 | setType(value); |
50 | - // @ts-ignore | |
51 | - setParams({ orderTaskApprovalType: value }, true); | |
61 | + setParams({ orderTaskApprovalType: value, keywords }, true); | |
52 | 62 | }; |
53 | 63 | |
54 | 64 | // 查看顾问任务 |
... | ... | @@ -67,130 +77,174 @@ const EntryTaskPreview = ({ |
67 | 77 | showSeriesModal(record, type); |
68 | 78 | }; |
69 | 79 | |
70 | - return ( | |
71 | - <Card | |
72 | - title={ | |
73 | - <Row align="middle" justify="start"> | |
74 | - <RadioGroup onChange={handleChangeType} value={type}> | |
75 | - <RadioButton value={OrderTaskApprovalType.门店维度}> | |
76 | - 门店 | |
77 | - </RadioButton> | |
78 | - <RadioButton value={OrderTaskApprovalType.销售顾问维度}> | |
79 | - 销顾 | |
80 | - </RadioButton> | |
81 | - <RadioButton value={99}>销售管理</RadioButton> | |
82 | - </RadioGroup> | |
83 | - {type !== OrderTaskApprovalType.门店维度 && | |
84 | - type !== OrderTaskApprovalType.销售顾问维度 && ( | |
85 | - <RadioGroup | |
86 | - onChange={handleChangeType} | |
87 | - value={type} | |
88 | - style={{ marginLeft: 20 }} | |
89 | - > | |
90 | - <RadioButton value={OrderTaskApprovalType.新车一级管理维度}> | |
91 | - 销售一级管理 | |
92 | - </RadioButton> | |
93 | - <RadioButton value={OrderTaskApprovalType.新车二级管理维度}> | |
94 | - 销售二级管理 | |
95 | - </RadioButton> | |
96 | - <RadioButton value={OrderTaskApprovalType.新车三级管理维度}> | |
97 | - 销售三级管理 | |
98 | - </RadioButton> | |
99 | - </RadioGroup> | |
100 | - )} | |
101 | - </Row> | |
102 | - } | |
103 | - > | |
104 | - <Table | |
105 | - rowKey="dataId" | |
106 | - loading={loading} | |
107 | - dataSource={data.taskList} | |
108 | - pagination={false} | |
109 | - scroll={{ y: 450 }} | |
110 | - > | |
111 | - <Column | |
112 | - title={type === OrderTaskApprovalType.门店维度 ? "门店" : "姓名"} | |
113 | - dataIndex="dataName" | |
114 | - filterSearch | |
115 | - onFilter={( | |
116 | - value: string | number | boolean, | |
117 | - record: API.TaskListItem | |
118 | - ) => { | |
119 | - return record.dataName.startsWith(value.toString()); | |
120 | - }} | |
121 | - /> | |
122 | - <Column | |
123 | - title="零售任务(台)" | |
124 | - dataIndex="taskCount" | |
125 | - render={(text: string, record: API.TaskListItem) => { | |
80 | + const columns: ColumnsType<API.TaskListItem> = [ | |
81 | + { | |
82 | + title: type === OrderTaskApprovalType.门店维度 ? "门店" : "姓名", | |
83 | + width: type === OrderTaskApprovalType.门店维度 ? 150 : 100, | |
84 | + dataIndex: "dataName", | |
85 | + filterSearch: true, | |
86 | + onFilter: ( | |
87 | + value: string | number | boolean, | |
88 | + record: API.TaskListItem | |
89 | + ) => { | |
90 | + return record.dataName.startsWith(value.toString()); | |
91 | + }, | |
92 | + }, | |
93 | + { | |
94 | + title: "零售任务(台)", | |
95 | + children: [ | |
96 | + { | |
97 | + title: "合计", | |
98 | + dataIndex: "taskCount", | |
99 | + key: "taskCount", | |
100 | + render: (text: string, record: API.TaskListItem) => { | |
126 | 101 | return ModifiedTableCell(record, "taskCount"); |
127 | - }} | |
128 | - /> | |
129 | - <Column | |
130 | - title="新能源车任务(台)" | |
131 | - dataIndex="newEnergyTaskCount" | |
132 | - render={(text: string, record: API.TaskListItem) => { | |
102 | + }, | |
103 | + }, | |
104 | + { | |
105 | + title: "新能源车", | |
106 | + dataIndex: "newEnergyTaskCount", | |
107 | + key: "newEnergyTaskCount", | |
108 | + render: (text: string, record: API.TaskListItem) => { | |
133 | 109 | return ModifiedTableCell(record, "newEnergyTaskCount"); |
134 | - }} | |
135 | - /> | |
136 | - <Column | |
137 | - title="传统燃油车任务(台)" | |
138 | - dataIndex="fuelVehicleTaskCount" | |
139 | - render={(text: string, record: API.TaskListItem) => { | |
110 | + }, | |
111 | + }, | |
112 | + { | |
113 | + title: "传统燃油车", | |
114 | + dataIndex: "fuelVehicleTaskCount", | |
115 | + key: "fuelVehicleTaskCount", | |
116 | + render: (text: string, record: API.TaskListItem) => { | |
140 | 117 | return ModifiedTableCell(record, "fuelVehicleTaskCount"); |
141 | - }} | |
142 | - /> | |
143 | - <Column | |
144 | - title="车辆毛利任务(元)" | |
145 | - dataIndex="vehicleGrossProfitTask" | |
146 | - render={(text: string, record: API.TaskListItem) => { | |
147 | - return ModifiedTableCell(record, "vehicleGrossProfitTask"); | |
148 | - }} | |
149 | - /> | |
150 | - <Column | |
151 | - title="线索到店零售台数(台)" | |
152 | - dataIndex="clueDealTaskCount" | |
153 | - render={(text: string, record: API.TaskListItem) => { | |
154 | - return ModifiedTableCell(record, "clueDealTaskCount"); | |
155 | - }} | |
156 | - /> | |
157 | - <Column | |
158 | - title="首客试驾成交任务数(台)" | |
159 | - dataIndex="testDriveTaskCount" | |
160 | - render={(text: string, record: API.TaskListItem) => { | |
161 | - return ModifiedTableCell(record, "testDriveTaskCount"); | |
162 | - }} | |
118 | + }, | |
119 | + }, | |
120 | + ], | |
121 | + }, | |
122 | + { | |
123 | + title: "单车毛利任务(元)", | |
124 | + dataIndex: "vehicleGrossProfitTask", | |
125 | + render: (text: string, record: API.TaskListItem) => { | |
126 | + if (record.dataId === -999) { | |
127 | + return <div style={{ textAlign: "center" }}>-</div>; | |
128 | + } | |
129 | + return ModifiedTableCell(record, "vehicleGrossProfitTask"); | |
130 | + }, | |
131 | + }, | |
132 | + { | |
133 | + title: "线索到店成交(台)", | |
134 | + width: 100, | |
135 | + dataIndex: "clueDealTaskCount", | |
136 | + render: (text: string, record: API.TaskListItem) => { | |
137 | + return ModifiedTableCell(record, "clueDealTaskCount"); | |
138 | + }, | |
139 | + }, | |
140 | + { | |
141 | + title: "首客试驾成交(台)", | |
142 | + width: 100, | |
143 | + dataIndex: "testDriveTaskCount", | |
144 | + render: (text: string, record: API.TaskListItem) => { | |
145 | + return ModifiedTableCell(record, "testDriveTaskCount"); | |
146 | + }, | |
147 | + }, | |
148 | + { | |
149 | + title: "攻坚车任务(台)", | |
150 | + width: 100, | |
151 | + dataIndex: "tackCarTaskCount", | |
152 | + render: (text: string, record: API.TaskListItem) => { | |
153 | + return ModifiedTableCell(record, "tackCarTaskCount"); | |
154 | + }, | |
155 | + }, | |
156 | + { | |
157 | + title: "车系任务(台)", | |
158 | + width: 100, | |
159 | + dataIndex: "seriesTaskCount", | |
160 | + render: (text: string, record: API.TaskListItem) => { | |
161 | + if (record.dataId === -999) return text; | |
162 | + return <a onClick={() => handlePreviewSeriesTask(record)}>{text}</a>; | |
163 | + }, | |
164 | + }, | |
165 | + ]; | |
166 | + | |
167 | + const extraColumns: ColumnsType<API.TaskListItem> = [ | |
168 | + { | |
169 | + title: "销顾任务", | |
170 | + render: (text: string, record: API.TaskListItem) => { | |
171 | + if (record.dataId === -999) { | |
172 | + return "-"; | |
173 | + } | |
174 | + return <a onClick={() => handlePreviewAdviserTask(record)}>查看</a>; | |
175 | + }, | |
176 | + }, | |
177 | + ]; | |
178 | + | |
179 | + return ( | |
180 | + <> | |
181 | + <Row align="middle" justify="start" style={{ marginBottom: 20 }}> | |
182 | + <DatePicker | |
183 | + style={{ width: 245 }} | |
184 | + picker="month" | |
185 | + value={month} | |
186 | + allowClear={false} | |
187 | + disabled | |
163 | 188 | /> |
164 | - <Column | |
165 | - title="攻坚车任务数(台)" | |
166 | - dataIndex="tackCarTaskCount" | |
167 | - render={(text: string, record: API.TaskListItem) => { | |
168 | - return ModifiedTableCell(record, "tackCarTaskCount"); | |
189 | + <Input.Search | |
190 | + allowClear | |
191 | + placeholder="搜索门店或顾问" | |
192 | + style={{ width: 263, marginLeft: 20 }} | |
193 | + value={keywords} | |
194 | + onChange={(e) => setKeywords(e.target.value)} | |
195 | + onSearch={(v) => { | |
196 | + setParams({ keywords: v }, true); | |
169 | 197 | }} |
170 | 198 | /> |
171 | - <Column | |
172 | - title="车系任务数(台)" | |
173 | - dataIndex="seriesTaskCount" | |
174 | - render={(text: string, record: API.TaskListItem) => { | |
175 | - if (record.dataId === -999) return text; | |
176 | - return ( | |
177 | - <a onClick={() => handlePreviewSeriesTask(record)}>{text}</a> | |
178 | - ); | |
179 | - }} | |
199 | + </Row> | |
200 | + <Card | |
201 | + title={ | |
202 | + <Row align="middle" justify="start"> | |
203 | + <RadioGroup onChange={handleChangeType} value={type}> | |
204 | + <RadioButton value={OrderTaskApprovalType.门店维度}> | |
205 | + 门店 | |
206 | + </RadioButton> | |
207 | + <RadioButton value={OrderTaskApprovalType.销售顾问维度}> | |
208 | + 销顾 | |
209 | + </RadioButton> | |
210 | + <RadioButton value={99}>销售管理层</RadioButton> | |
211 | + </RadioGroup> | |
212 | + {type !== OrderTaskApprovalType.门店维度 && | |
213 | + type !== OrderTaskApprovalType.销售顾问维度 && ( | |
214 | + <RadioGroup | |
215 | + onChange={handleChangeType} | |
216 | + value={type} | |
217 | + style={{ marginLeft: 20 }} | |
218 | + > | |
219 | + <RadioButton value={OrderTaskApprovalType.新车一级管理维度}> | |
220 | + 销售一级管理 | |
221 | + </RadioButton> | |
222 | + <RadioButton value={OrderTaskApprovalType.新车二级管理维度}> | |
223 | + 销售二级管理 | |
224 | + </RadioButton> | |
225 | + <RadioButton value={OrderTaskApprovalType.新车三级管理维度}> | |
226 | + 销售三级管理 | |
227 | + </RadioButton> | |
228 | + </RadioGroup> | |
229 | + )} | |
230 | + </Row> | |
231 | + } | |
232 | + > | |
233 | + <Table | |
234 | + bordered | |
235 | + rowKey="dataId" | |
236 | + columns={ | |
237 | + type === OrderTaskApprovalType.门店维度 | |
238 | + ? columns.concat(extraColumns) | |
239 | + : columns | |
240 | + } | |
241 | + loading={loading} | |
242 | + dataSource={data.taskList} | |
243 | + pagination={false} | |
244 | + scroll={{ y: 450 }} | |
180 | 245 | /> |
181 | - {type === OrderTaskApprovalType.门店维度 && ( | |
182 | - <Column | |
183 | - title="销顾" | |
184 | - render={(text: string, record: API.TaskListItem) => { | |
185 | - if (record.dataId === -999) return "-"; | |
186 | - return ( | |
187 | - <a onClick={() => handlePreviewAdviserTask(record)}>查看</a> | |
188 | - ); | |
189 | - }} | |
190 | - /> | |
191 | - )} | |
192 | - </Table> | |
193 | - </Card> | |
246 | + </Card> | |
247 | + </> | |
194 | 248 | ); |
195 | 249 | }; |
196 | 250 | ... | ... |
src/pages/order3/SaleTask/components/SaleTaskAutoAssign.tsx
0 → 100644
1 | +import React, { useContext, useEffect, useRef, useState } from "react"; | |
2 | +import { | |
3 | + Table, | |
4 | + Form, | |
5 | + InputRef, | |
6 | + Row, | |
7 | + Button, | |
8 | + message, | |
9 | + Modal, | |
10 | + InputNumber, | |
11 | +} from "antd"; | |
12 | +import type { FormInstance } from "antd/es/form"; | |
13 | +import * as API from "../api"; | |
14 | +import "./index.less"; | |
15 | +import { MAX_NUM } from "../entity"; | |
16 | + | |
17 | +type EditableTableProps = Parameters<typeof Table>[0]; | |
18 | +type ColumnTypes = Exclude<EditableTableProps["columns"], undefined>; | |
19 | +interface Item { | |
20 | + id: string; | |
21 | + shopName: string; | |
22 | + taskCount: number; | |
23 | + newEnergyTaskCount: number; | |
24 | + fuelVehicleTaskCount: number; | |
25 | + tackCarTaskCount: number; | |
26 | +} | |
27 | +interface EditableRowProps { | |
28 | + index: number; | |
29 | +} | |
30 | +interface EditableCellProps { | |
31 | + title: React.ReactNode; | |
32 | + editable: boolean; | |
33 | + children: React.ReactNode; | |
34 | + dataIndex: keyof Item; | |
35 | + record: Item; | |
36 | + handleSave: (record: Item) => void; | |
37 | +} | |
38 | + | |
39 | +const defaultColumns: (ColumnTypes[number] & { | |
40 | + editable?: boolean; | |
41 | + dataIndex: string; | |
42 | +})[] = [ | |
43 | + { | |
44 | + title: "门店", | |
45 | + dataIndex: "shopName", | |
46 | + editable: false, | |
47 | + }, | |
48 | + { | |
49 | + title: "零售任务(台)", | |
50 | + dataIndex: "taskCount", | |
51 | + editable: true, | |
52 | + }, | |
53 | + { | |
54 | + title: "新能源车任务(台)", | |
55 | + dataIndex: "newEnergyTaskCount", | |
56 | + editable: true, | |
57 | + }, | |
58 | + { | |
59 | + title: "传统燃油车任务(台)", | |
60 | + dataIndex: "fuelVehicleTaskCount", | |
61 | + editable: false, | |
62 | + }, | |
63 | + { | |
64 | + title: "攻坚车任务(台)", | |
65 | + dataIndex: "tackCarTaskCount", | |
66 | + editable: true, | |
67 | + }, | |
68 | +]; | |
69 | + | |
70 | +interface SaleTaskAutoAssignProps { | |
71 | + id: number; | |
72 | + value?: API.ShopTaskItem[]; | |
73 | + onCancel: () => void; | |
74 | + onRefresh: () => void; | |
75 | +} | |
76 | + | |
77 | +export default function SaleTaskAutoAssign(props: SaleTaskAutoAssignProps) { | |
78 | + const EditableContext = React.createContext<FormInstance<any> | null>(null); | |
79 | + const [dataSource, setDataSource] = useState<API.ShopTaskItem[]>([]); | |
80 | + | |
81 | + useEffect(() => { | |
82 | + setDataSource(props.value ? [...props.value] : []); | |
83 | + }, [props.value]); | |
84 | + | |
85 | + const EditableRow: React.FC<EditableRowProps> = ({ index, ...props }) => { | |
86 | + const [form] = Form.useForm(); | |
87 | + return ( | |
88 | + <Form form={form} component={false}> | |
89 | + <EditableContext.Provider value={form}> | |
90 | + <tr {...props} /> | |
91 | + </EditableContext.Provider> | |
92 | + </Form> | |
93 | + ); | |
94 | + }; | |
95 | + | |
96 | + const EditableCell: React.FC<EditableCellProps> = ({ | |
97 | + title, | |
98 | + editable, | |
99 | + children, | |
100 | + dataIndex, | |
101 | + record, | |
102 | + handleSave, | |
103 | + ...restProps | |
104 | + }) => { | |
105 | + const [editing, setEditing] = useState(false); | |
106 | + const inputRef = useRef<InputRef>(null); | |
107 | + const form = useContext(EditableContext)!; | |
108 | + | |
109 | + useEffect(() => { | |
110 | + if (editing) { | |
111 | + inputRef.current!.focus(); | |
112 | + } | |
113 | + }, [editing]); | |
114 | + | |
115 | + const toggleEdit = () => { | |
116 | + setEditing(!editing); | |
117 | + form.setFieldsValue({ [dataIndex]: record[dataIndex] }); | |
118 | + }; | |
119 | + | |
120 | + const save = async () => { | |
121 | + try { | |
122 | + const values = await form.validateFields(); | |
123 | + toggleEdit(); | |
124 | + handleSave({ ...record, ...values }); | |
125 | + } catch (errInfo) { | |
126 | + console.log("Save failed:", errInfo); | |
127 | + } | |
128 | + }; | |
129 | + | |
130 | + let childNode = children; | |
131 | + | |
132 | + if (editable) { | |
133 | + childNode = editing ? ( | |
134 | + <Form.Item | |
135 | + noStyle | |
136 | + name={dataIndex} | |
137 | + rules={[ | |
138 | + { | |
139 | + required: true, | |
140 | + message: `请输入${title}`, | |
141 | + }, | |
142 | + ]} | |
143 | + > | |
144 | + <InputNumber | |
145 | + ref={inputRef} | |
146 | + min={0} | |
147 | + max={MAX_NUM} | |
148 | + style={{ width: "80px" }} | |
149 | + onPressEnter={save} | |
150 | + onBlur={save} | |
151 | + /> | |
152 | + </Form.Item> | |
153 | + ) : ( | |
154 | + <div className="editable-cell-value-wrap" onClick={toggleEdit}> | |
155 | + {children} | |
156 | + </div> | |
157 | + ); | |
158 | + } | |
159 | + | |
160 | + return <td {...restProps}>{childNode}</td>; | |
161 | + }; | |
162 | + | |
163 | + const handleSave = (row: API.ShopTaskItem) => { | |
164 | + const newData = [...dataSource]; | |
165 | + const index = newData.findIndex((item) => row.id === item.id); | |
166 | + const item = newData[index]; | |
167 | + if (row.taskCount !== 0 && row.newEnergyTaskCount > row.taskCount) { | |
168 | + message.warn("新能源车任务台数不得超过零售任务台数"); | |
169 | + return; | |
170 | + } | |
171 | + const newRow = { | |
172 | + ...item, | |
173 | + ...row, | |
174 | + fuelVehicleTaskCount: row.taskCount - row.newEnergyTaskCount, | |
175 | + }; | |
176 | + if (row.taskCount === 0) { | |
177 | + newRow.taskCount = 0; | |
178 | + newRow.newEnergyTaskCount = 0; | |
179 | + newRow.fuelVehicleTaskCount = 0; | |
180 | + } | |
181 | + newData.splice(index, 1, newRow); | |
182 | + setDataSource(newData); | |
183 | + }; | |
184 | + | |
185 | + const autoAssignSaleTask = (isAssignToAdviser: boolean) => { | |
186 | + Modal.confirm({ | |
187 | + title: isAssignToAdviser ? ( | |
188 | + <span> | |
189 | + 确认分配到 | |
190 | + <span className="tip">全部门店和顾问</span> | |
191 | + 吗? | |
192 | + </span> | |
193 | + ) : ( | |
194 | + <span> | |
195 | + 确认分配到 | |
196 | + <span className="tip">全部门店</span> | |
197 | + 吗? | |
198 | + </span> | |
199 | + ), | |
200 | + zIndex: 1002, | |
201 | + onOk: async () => { | |
202 | + const hide = message.loading("分配中,请稍候", 0); | |
203 | + API.autoAssignSaleTask({ | |
204 | + id: props.id, | |
205 | + shopTaskList: dataSource.map((item) => ({ | |
206 | + shopId: item.shopId, | |
207 | + taskCount: item.taskCount, | |
208 | + newEnergyTaskCount: item.newEnergyTaskCount, | |
209 | + fuelVehicleTaskCount: item.fuelVehicleTaskCount, | |
210 | + tackCarTaskCount: item.tackCarTaskCount, | |
211 | + })), | |
212 | + assignTask: isAssignToAdviser, | |
213 | + }) | |
214 | + .then((res) => { | |
215 | + message.success("分配成功"); | |
216 | + props.onRefresh(); | |
217 | + }) | |
218 | + .catch((error: any) => { | |
219 | + message.error(error.message ?? "请求失败"); | |
220 | + }) | |
221 | + .finally(() => { | |
222 | + hide(); | |
223 | + }); | |
224 | + }, | |
225 | + }); | |
226 | + }; | |
227 | + | |
228 | + const components = { | |
229 | + body: { | |
230 | + row: EditableRow, | |
231 | + cell: EditableCell, | |
232 | + }, | |
233 | + }; | |
234 | + | |
235 | + const columns = defaultColumns.map((col) => { | |
236 | + if (!col.editable) { | |
237 | + return col; | |
238 | + } | |
239 | + return { | |
240 | + ...col, | |
241 | + onCell: (record: API.ShopTaskItem) => ({ | |
242 | + record, | |
243 | + editable: col.editable, | |
244 | + dataIndex: col.dataIndex, | |
245 | + title: col.title, | |
246 | + handleSave, | |
247 | + }), | |
248 | + }; | |
249 | + }); | |
250 | + | |
251 | + return ( | |
252 | + <> | |
253 | + <Table | |
254 | + components={components} | |
255 | + rowClassName={() => "editable-row"} | |
256 | + bordered | |
257 | + rowKey="id" | |
258 | + dataSource={dataSource} | |
259 | + columns={columns as ColumnTypes} | |
260 | + /> | |
261 | + <Row align="middle" justify="center" style={{ marginTop: 20 }}> | |
262 | + <Button onClick={props.onCancel}>取消</Button> | |
263 | + <Button | |
264 | + type="primary" | |
265 | + style={{ marginLeft: 10 }} | |
266 | + onClick={() => autoAssignSaleTask(false)} | |
267 | + > | |
268 | + 分配到门店 | |
269 | + </Button> | |
270 | + <Button | |
271 | + type="primary" | |
272 | + style={{ marginLeft: 10 }} | |
273 | + onClick={() => autoAssignSaleTask(true)} | |
274 | + > | |
275 | + 分配到门店和顾问 | |
276 | + </Button> | |
277 | + </Row> | |
278 | + </> | |
279 | + ); | |
280 | +} | ... | ... |
src/pages/order3/SaleTask/components/SaleTaskBatchSet.tsx
0 → 100644
1 | +import { PlusOutlined } from "@ant-design/icons"; | |
2 | +import { | |
3 | + Button, | |
4 | + Card, | |
5 | + Col, | |
6 | + Form, | |
7 | + InputNumber, | |
8 | + Modal, | |
9 | + Row, | |
10 | + message, | |
11 | +} from "antd"; | |
12 | +import "./index.less"; | |
13 | +import React, { useState } from "react"; | |
14 | +import { MAX_NUM } from "../entity"; | |
15 | +import * as API from "../api"; | |
16 | +import ShopSelectNew from "@/components/ShopSelectNew"; | |
17 | +import { isArray } from "lodash"; | |
18 | + | |
19 | +interface SaleTaskBatchSetProps { | |
20 | + id: number; | |
21 | + onCancel: () => void; | |
22 | + onRefresh: () => void; | |
23 | +} | |
24 | + | |
25 | +export default function SaleTaskBatchSet(props: SaleTaskBatchSetProps) { | |
26 | + const [form] = Form.useForm(); | |
27 | + // 过滤各项已经选择的门店 | |
28 | + // const [selectedShopIds, setSelectedShopIds] = useState({ | |
29 | + // grossProfit: [], | |
30 | + // tackCar: [], | |
31 | + // testDrive: [], | |
32 | + // }); | |
33 | + | |
34 | + const batchSetSaleTask = async (isAssignToAdviser: boolean) => { | |
35 | + await form.validateFields(); | |
36 | + const values = form.getFieldsValue(); | |
37 | + if ( | |
38 | + Object.values(values).every( | |
39 | + (item) => !item || (isArray(item) && item.length === 0) | |
40 | + ) | |
41 | + ) { | |
42 | + message.warn("请设置任务后再进行分配"); | |
43 | + return; | |
44 | + } | |
45 | + const newValues = {}; | |
46 | + Array.from(Object.keys(values)).forEach((valueKey: any) => { | |
47 | + if (values[valueKey]) { | |
48 | + newValues[valueKey] = values[valueKey].map((valueItem: any) => ({ | |
49 | + taskAims: valueItem.taskAims, | |
50 | + shopIdList: valueItem.shopIdList.map( | |
51 | + (shopItem: any) => shopItem.shopId | |
52 | + ), | |
53 | + })); | |
54 | + } | |
55 | + }); | |
56 | + Modal.confirm({ | |
57 | + title: isAssignToAdviser ? ( | |
58 | + <span> | |
59 | + 确认分配到 | |
60 | + <span className="tip">全部门店和顾问</span> | |
61 | + 吗? | |
62 | + </span> | |
63 | + ) : ( | |
64 | + <span> | |
65 | + 确认分配到 | |
66 | + <span className="tip">全部门店</span> | |
67 | + 吗? | |
68 | + </span> | |
69 | + ), | |
70 | + zIndex: 1002, | |
71 | + onOk: async () => { | |
72 | + const hide = message.loading("分配中,请稍候", 0); | |
73 | + API.batchSetSaleTask({ | |
74 | + assignTask: isAssignToAdviser, | |
75 | + orderTaskApplyId: props.id, | |
76 | + ...newValues, | |
77 | + }) | |
78 | + .then((res) => { | |
79 | + message.success("分配成功"); | |
80 | + props.onRefresh(); | |
81 | + }) | |
82 | + .catch((error: any) => { | |
83 | + message.error(error.message ?? "请求失败"); | |
84 | + }) | |
85 | + .finally(() => { | |
86 | + hide(); | |
87 | + }); | |
88 | + }, | |
89 | + }); | |
90 | + }; | |
91 | + | |
92 | + // const handleFormChange = (changedValues: any) => { | |
93 | + // const labelKey: any = Object.keys(changedValues)[0]; | |
94 | + // const list: any = Object.values(changedValues)[0]; | |
95 | + // console.log(list); | |
96 | + // if (!list[0]) return; | |
97 | + // if (Object.keys(list[0])[0] === "shopIdList") { | |
98 | + // const newSelectedIds = { ...selectedShopIds }; | |
99 | + // newSelectedIds[labelKey] = Object.values(list[0])[0]; | |
100 | + // setSelectedShopIds(newSelectedIds); | |
101 | + // } | |
102 | + // }; | |
103 | + | |
104 | + return ( | |
105 | + <Form | |
106 | + form={form} | |
107 | + name="sale-task-batch-set-form" | |
108 | + autoComplete="off" | |
109 | + // onValuesChange={handleFormChange} | |
110 | + > | |
111 | + <Form.List name="grossProfitTaskList"> | |
112 | + {(fields, { add, remove }) => ( | |
113 | + <Card> | |
114 | + <Row | |
115 | + align="middle" | |
116 | + justify="space-between" | |
117 | + style={{ marginBottom: 15 }} | |
118 | + > | |
119 | + <h4 className="title">单车毛利任务</h4> | |
120 | + <Button type="link" onClick={() => add()} icon={<PlusOutlined />}> | |
121 | + 新增 | |
122 | + </Button> | |
123 | + </Row> | |
124 | + {fields.map(({ key, name, ...restField }) => ( | |
125 | + <Row gutter={16} key={key}> | |
126 | + <Col className="gutter-row" span={6}> | |
127 | + <Form.Item | |
128 | + {...restField} | |
129 | + name={[name, "taskAims"]} | |
130 | + rules={[{ required: true, message: "请填写单车毛利任务" }]} | |
131 | + > | |
132 | + <InputNumber | |
133 | + formatter={(value) => `${value}元`} | |
134 | + parser={(value: any) => value.replace("元", "")} | |
135 | + min={0} | |
136 | + max={MAX_NUM} | |
137 | + style={{ width: "100%" }} | |
138 | + precision={2} | |
139 | + placeholder="请填写单车毛利任务" | |
140 | + /> | |
141 | + </Form.Item> | |
142 | + </Col> | |
143 | + <Col className="gutter-row" span={15}> | |
144 | + <Form.Item | |
145 | + {...restField} | |
146 | + name={[name, "shopIdList"]} | |
147 | + rules={[{ required: true, message: "请选择适用门店" }]} | |
148 | + > | |
149 | + <ShopSelectNew | |
150 | + multiple | |
151 | + defaultOptions={{ bizTypes: "1" }} | |
152 | + placeholder="请选择适用门店" | |
153 | + // disabledShopIds={selectedShopIds.grossProfit} | |
154 | + /> | |
155 | + </Form.Item> | |
156 | + </Col> | |
157 | + <Col className="gutter-row" span={3}> | |
158 | + <Button | |
159 | + type="link" | |
160 | + style={{ color: "#999" }} | |
161 | + onClick={() => remove(name)} | |
162 | + > | |
163 | + 删除 | |
164 | + </Button> | |
165 | + </Col> | |
166 | + </Row> | |
167 | + ))} | |
168 | + </Card> | |
169 | + )} | |
170 | + </Form.List> | |
171 | + <Form.List name="testDriveTaskList"> | |
172 | + {(fields, { add, remove }) => ( | |
173 | + <Card style={{ marginTop: 20 }}> | |
174 | + <Row | |
175 | + align="middle" | |
176 | + justify="space-between" | |
177 | + style={{ marginBottom: 15 }} | |
178 | + > | |
179 | + <h4 className="title">首客试驾成交</h4> | |
180 | + <Button type="link" onClick={() => add()} icon={<PlusOutlined />}> | |
181 | + 新增 | |
182 | + </Button> | |
183 | + </Row> | |
184 | + {fields.map(({ key, name, ...restField }) => ( | |
185 | + <Row gutter={16} key={key}> | |
186 | + <Col className="gutter-row" span={6}> | |
187 | + <Form.Item | |
188 | + {...restField} | |
189 | + name={[name, "taskAims"]} | |
190 | + rules={[{ required: true, message: "请填写首客试驾成交" }]} | |
191 | + > | |
192 | + <InputNumber | |
193 | + formatter={(value) => `${value}台`} | |
194 | + parser={(value: any) => value.replace("台", "")} | |
195 | + min={0} | |
196 | + max={MAX_NUM} | |
197 | + style={{ width: "100%" }} | |
198 | + precision={0} | |
199 | + placeholder="请填写首客试驾成交" | |
200 | + /> | |
201 | + </Form.Item> | |
202 | + </Col> | |
203 | + <Col className="gutter-row" span={15}> | |
204 | + <Form.Item | |
205 | + {...restField} | |
206 | + name={[name, "shopIdList"]} | |
207 | + rules={[{ required: true, message: "请选择适用门店" }]} | |
208 | + > | |
209 | + <ShopSelectNew | |
210 | + multiple | |
211 | + defaultOptions={{ bizTypes: "1" }} | |
212 | + placeholder="请选择适用门店" | |
213 | + // disabledShopIds={selectedShopIds.testDrive} | |
214 | + /> | |
215 | + </Form.Item> | |
216 | + </Col> | |
217 | + <Col className="gutter-row" span={3}> | |
218 | + <Button | |
219 | + type="link" | |
220 | + style={{ color: "#999" }} | |
221 | + onClick={() => remove(name)} | |
222 | + > | |
223 | + 删除 | |
224 | + </Button> | |
225 | + </Col> | |
226 | + </Row> | |
227 | + ))} | |
228 | + </Card> | |
229 | + )} | |
230 | + </Form.List> | |
231 | + <Form.List name="tackCarTaskList"> | |
232 | + {(fields, { add, remove }) => ( | |
233 | + <Card style={{ marginTop: 20 }}> | |
234 | + <Row | |
235 | + align="middle" | |
236 | + justify="space-between" | |
237 | + style={{ marginBottom: 15 }} | |
238 | + > | |
239 | + <h4 className="title">攻坚车任务</h4> | |
240 | + <Button type="link" onClick={() => add()} icon={<PlusOutlined />}> | |
241 | + 新增 | |
242 | + </Button> | |
243 | + </Row> | |
244 | + {fields.map(({ key, name, ...restField }) => ( | |
245 | + <Row gutter={16} key={key}> | |
246 | + <Col className="gutter-row" span={6}> | |
247 | + <Form.Item | |
248 | + {...restField} | |
249 | + name={[name, "taskAims"]} | |
250 | + rules={[{ required: true, message: "请填写攻坚车任务" }]} | |
251 | + > | |
252 | + <InputNumber | |
253 | + formatter={(value) => `${value}台`} | |
254 | + parser={(value: any) => value.replace("台", "")} | |
255 | + min={0} | |
256 | + max={MAX_NUM} | |
257 | + style={{ width: "100%" }} | |
258 | + precision={0} | |
259 | + placeholder="请填写攻坚车任务" | |
260 | + /> | |
261 | + </Form.Item> | |
262 | + </Col> | |
263 | + <Col className="gutter-row" span={15}> | |
264 | + <Form.Item | |
265 | + {...restField} | |
266 | + name={[name, "shopIdList"]} | |
267 | + rules={[{ required: true, message: "请选择适用门店" }]} | |
268 | + > | |
269 | + <ShopSelectNew | |
270 | + multiple | |
271 | + defaultOptions={{ bizTypes: "1" }} | |
272 | + placeholder="请选择适用门店" | |
273 | + // disabledShopIds={selectedShopIds.tackCar} | |
274 | + /> | |
275 | + </Form.Item> | |
276 | + </Col> | |
277 | + <Col className="gutter-row" span={3}> | |
278 | + <Button | |
279 | + type="link" | |
280 | + style={{ color: "#999" }} | |
281 | + onClick={() => remove(name)} | |
282 | + > | |
283 | + 删除 | |
284 | + </Button> | |
285 | + </Col> | |
286 | + </Row> | |
287 | + ))} | |
288 | + </Card> | |
289 | + )} | |
290 | + </Form.List> | |
291 | + <Row align="middle" justify="center" style={{ marginTop: 20 }}> | |
292 | + <Button onClick={props.onCancel}>取消</Button> | |
293 | + <Button | |
294 | + type="primary" | |
295 | + style={{ marginLeft: 10 }} | |
296 | + onClick={() => batchSetSaleTask(false)} | |
297 | + > | |
298 | + 分配到门店 | |
299 | + </Button> | |
300 | + <Button | |
301 | + type="primary" | |
302 | + style={{ marginLeft: 10 }} | |
303 | + onClick={() => batchSetSaleTask(true)} | |
304 | + > | |
305 | + 分配到门店和顾问 | |
306 | + </Button> | |
307 | + </Row> | |
308 | + </Form> | |
309 | + ); | |
310 | +} | ... | ... |
src/pages/order3/SaleTask/components/index.less
0 → 100644
src/pages/order3/SaleTask/index.tsx
... | ... | @@ -15,14 +15,15 @@ import { history } from "umi"; |
15 | 15 | import moment, { Moment } from "moment"; |
16 | 16 | import useInitial from "@/hooks/useInitail"; |
17 | 17 | import { Provider, useStore } from "./store"; |
18 | -import { default as ApprovalProgressModal } from "@/pages/stock/AdvanceProgress/components/ApproveModal"; | |
18 | +import ApprovalProgressModal from "@/pages/stock/AdvanceProgress/components/ApproveModal"; | |
19 | 19 | import EntryTaskPreview from "./components/EntryTaskPreview"; |
20 | 20 | import { OrderTaskApprovalType } from "./entity"; |
21 | 21 | import AdviserTaskPreview from "./components/AdviserTaskPreview"; |
22 | 22 | import SeriesTaskPreview from "./components/SeriesTaskPreview"; |
23 | 23 | import ApproveModal from "@/pages/order3/Common/ApproveModal"; |
24 | - | |
25 | -const { Column } = Table; | |
24 | +import SaleTaskAutoAssign from "./components/SaleTaskAutoAssign"; | |
25 | +import SaleTaskBatchSet from "./components/SaleTaskBatchSet"; | |
26 | +import { ColumnsType } from "antd/es/table"; | |
26 | 27 | |
27 | 28 | export default () => ( |
28 | 29 | <Provider> |
... | ... | @@ -42,6 +43,9 @@ function SaleTaskList() { |
42 | 43 | const [stpVisible, setStpVisible] = useState(false); |
43 | 44 | const [seriesTaskParams, setSeriesTaskParams] = useState({}); |
44 | 45 | |
46 | + const [autoVisible, setAutoVisible] = useState(false); | |
47 | + const [batchVisible, setBatchVisible] = useState(false); | |
48 | + | |
45 | 49 | const { data, loading, setParams } = useInitial( |
46 | 50 | API.getSaleTaskApi, |
47 | 51 | {} as API.GetSaleTaskApiRes, |
... | ... | @@ -71,6 +75,19 @@ function SaleTaskList() { |
71 | 75 | }); |
72 | 76 | }; |
73 | 77 | |
78 | + // 查看销顾任务 | |
79 | + const goToAdviserPage = (record: API.ShopTaskItem) => { | |
80 | + history.push({ | |
81 | + pathname: "/order3/saleTask/edit", | |
82 | + query: { | |
83 | + readOnly: isReadOnly ? "1" : "0", | |
84 | + shopId: String(record.shopId), | |
85 | + taskDate: String(targetMonth.valueOf()), | |
86 | + currTab: "2", | |
87 | + }, | |
88 | + }); | |
89 | + }; | |
90 | + | |
74 | 91 | // 查看流程进度 |
75 | 92 | const viewProcess = () => { |
76 | 93 | setApprove({ |
... | ... | @@ -128,30 +145,242 @@ function SaleTaskList() { |
128 | 145 | setEtpVisible(true); |
129 | 146 | }; |
130 | 147 | |
148 | + // 销顾任务 | |
149 | + const showAdviserModal = ( | |
150 | + record: API.TaskListItem, | |
151 | + type: OrderTaskApprovalType | |
152 | + ) => { | |
153 | + const params: any = { | |
154 | + id: data.id, | |
155 | + taskId: record.id, | |
156 | + orderTaskApprovalType: OrderTaskApprovalType.门店维度, // 只有门店有查看销顾任务 | |
157 | + }; | |
158 | + switch (type) { | |
159 | + case OrderTaskApprovalType.门店维度: | |
160 | + params.shopId = record.dataId; | |
161 | + break; | |
162 | + case OrderTaskApprovalType.销售顾问维度: | |
163 | + params.staffId = record.dataId; | |
164 | + break; | |
165 | + case OrderTaskApprovalType.新车一级管理维度: | |
166 | + params.firstManageId = record.dataId; | |
167 | + break; | |
168 | + case OrderTaskApprovalType.新车二级管理维度: | |
169 | + params.secondManageId = record.dataId; | |
170 | + break; | |
171 | + case OrderTaskApprovalType.新车三级管理维度: | |
172 | + params.thirdManageId = record.dataId; | |
173 | + break; | |
174 | + default: | |
175 | + break; | |
176 | + } | |
177 | + setAdviserTaskParams(params); | |
178 | + setAtpVisible(true); | |
179 | + }; | |
180 | + | |
181 | + // 销顾任务--查看车系任务 | |
182 | + const showSeriesModalByAdviser = (record: API.TaskListItem) => { | |
183 | + const params = { ...adviserTaskParams } as any; | |
184 | + params.taskId = record.id; | |
185 | + params.orderTaskApprovalType = OrderTaskApprovalType.车系; | |
186 | + params.staffId = record.dataId; | |
187 | + setSeriesTaskParams(params); | |
188 | + setStpVisible(true); | |
189 | + }; | |
190 | + | |
191 | + // 车系任务 | |
192 | + const showSeriesModal = ( | |
193 | + record: API.TaskListItem, | |
194 | + type: OrderTaskApprovalType | |
195 | + ) => { | |
196 | + const params: any = { | |
197 | + id: data.id, | |
198 | + taskId: record.id, | |
199 | + orderTaskApprovalType: OrderTaskApprovalType.车系, | |
200 | + }; | |
201 | + switch (type) { | |
202 | + case OrderTaskApprovalType.门店维度: | |
203 | + params.shopId = record.dataId; | |
204 | + break; | |
205 | + case OrderTaskApprovalType.销售顾问维度: | |
206 | + params.staffId = record.dataId; | |
207 | + break; | |
208 | + case OrderTaskApprovalType.新车一级管理维度: | |
209 | + params.firstManageId = record.dataId; | |
210 | + break; | |
211 | + case OrderTaskApprovalType.新车二级管理维度: | |
212 | + params.secondManageId = record.dataId; | |
213 | + break; | |
214 | + case OrderTaskApprovalType.新车三级管理维度: | |
215 | + params.thirdManageId = record.dataId; | |
216 | + break; | |