Commit 2829593b3f2bc1a07e973e9bd5d1640322f3ab2b
Merge remote-tracking branch 'origin/master' into kaiShopId
Showing
37 changed files
with
1378 additions
and
372 deletions
src/components/ApprovalProgress/api.ts
... | ... | @@ -16,6 +16,8 @@ export interface ApprovalProgressItemVO { |
16 | 16 | duration?: string; // 审批时长 |
17 | 17 | opinion?: string; // 审批意见 |
18 | 18 | expTime?: number; |
19 | + efficientTime?: number; | |
20 | + createTime?: number; | |
19 | 21 | roleNames: string[]; |
20 | 22 | } |
21 | 23 | |
... | ... | @@ -24,6 +26,7 @@ export enum ApprovalProgressStatus { |
24 | 26 | '审批通过', |
25 | 27 | '审批拒绝', |
26 | 28 | '审批超时', |
29 | + '未开始' = 6, | |
27 | 30 | } |
28 | 31 | |
29 | 32 | export enum ApprovalProgressStatusColor { |
... | ... | @@ -31,6 +34,7 @@ export enum ApprovalProgressStatusColor { |
31 | 34 | 'blue', |
32 | 35 | 'red', |
33 | 36 | 'orange', |
37 | + '#DEDEDE' = 6, | |
34 | 38 | } |
35 | 39 | |
36 | 40 | export enum ApprovalProgressDotColor { |
... | ... | @@ -38,6 +42,7 @@ export enum ApprovalProgressDotColor { |
38 | 42 | '#4189FD', |
39 | 43 | '#F4333C', |
40 | 44 | '#FF921C', |
45 | + '#DEDEDE' = 6, | |
41 | 46 | } |
42 | 47 | |
43 | 48 | /** | ... | ... |
src/components/ApprovalProgress/components/CountDown/index.tsx
0 → 100644
1 | +import React, { useState, useEffect, useRef } from 'react'; | |
2 | +import { fix0 } from '../../util'; | |
3 | +import classNames from 'classnames'; | |
4 | + | |
5 | +export interface CountDownProps { | |
6 | + seconds: number; // 倒计时总秒数 | |
7 | + size?: number; | |
8 | + color?: string; | |
9 | + chinesse?: boolean; // 是否中文格式 | |
10 | + style?: any; | |
11 | + /** 当倒计时为0时的操作 */ | |
12 | + onFinish?: () => void; | |
13 | + /** 只倒计时秒数 */ | |
14 | + onlySecond?: boolean; | |
15 | + isDay?: boolean; | |
16 | + showMinute?: boolean; | |
17 | +} | |
18 | + | |
19 | +export default function CountDown({ seconds, size, color, chinesse, style = {}, onFinish, onlySecond, isDay = false, showMinute }: CountDownProps) { | |
20 | + const [text, setText] = useState<string>('--'); | |
21 | + const [obj] = useState({ seconds }); | |
22 | + const intervalId = useRef(); | |
23 | + | |
24 | + useEffect(() => { | |
25 | + intervalId.current && clearInterval(intervalId.current); | |
26 | + obj.seconds = seconds - 1; | |
27 | + if (seconds > 0) { | |
28 | + handleText(); | |
29 | + // @ts-ignore | |
30 | + intervalId.current = setInterval(() => { | |
31 | + handleText(); | |
32 | + }, 1000); | |
33 | + } | |
34 | + return () => { | |
35 | + intervalId.current && clearInterval(intervalId.current); | |
36 | + }; | |
37 | + }, [seconds]); | |
38 | + | |
39 | + function handleText() { | |
40 | + obj.seconds -= 1; | |
41 | + const seconds = obj.seconds; | |
42 | + if (seconds <= 0) { | |
43 | + intervalId.current && clearInterval(intervalId.current); | |
44 | + onFinish && onFinish(); | |
45 | + } | |
46 | + let day = 0, | |
47 | + hour = 0, | |
48 | + minute = 0, | |
49 | + second = 0, | |
50 | + text = ''; | |
51 | + if (seconds > 0) { | |
52 | + // 倒计时不计天 | |
53 | + if (isDay) { | |
54 | + day = Math.floor(seconds / (60 * 60 * 24)); | |
55 | + hour = Math.floor(seconds / (60 * 60)) - day * 24; | |
56 | + minute = Math.floor(seconds / 60) - day * 24 * 60 - hour * 60; | |
57 | + second = Math.floor(seconds) - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60; | |
58 | + } else { | |
59 | + hour = Math.floor(seconds / 3600); | |
60 | + minute = Math.floor(seconds / 60) - hour * 60; | |
61 | + second = Math.floor(seconds) - hour * 60 * 60 - minute * 60; | |
62 | + } | |
63 | + } | |
64 | + if (onlySecond) { | |
65 | + text = `${Math.floor(seconds)}${chinesse ? '秒' : 's'}`; | |
66 | + } | |
67 | + if (!onlySecond && day > 0) { | |
68 | + text = chinesse | |
69 | + ? `${fix0(day)}天${fix0(hour)}时${fix0(minute)}分${fix0(second)}秒` | |
70 | + : `${fix0(day)}d${fix0(hour)}:${fix0(minute)}:${fix0(second)}`; | |
71 | + } | |
72 | + if (!onlySecond && day <= 0) { | |
73 | + text = chinesse ? `${fix0(hour)}时${fix0(minute)}分${fix0(second)}秒` : `${fix0(hour)}:${fix0(minute)}:${fix0(second)}`; | |
74 | + } | |
75 | + | |
76 | + if (!onlySecond && day <= 0 && hour <= 0) { | |
77 | + text = chinesse ? `${fix0(minute)}分${fix0(second)}秒` : `${fix0(minute)}:${fix0(second)}`; | |
78 | + } | |
79 | + | |
80 | + if (showMinute && day > 0) { | |
81 | + text = chinesse ? `${fix0(day)}天${fix0(hour)}时${fix0(minute)}分` : `${fix0(day)}d${fix0(hour)}:${fix0(minute)}`; | |
82 | + } | |
83 | + if (showMinute && day <= 0) { | |
84 | + text = chinesse ? `${fix0(hour)}时${fix0(minute)}分${fix0(second)}秒` : `${fix0(hour)}:${fix0(minute)}:${fix0(second)}`; | |
85 | + } | |
86 | + if (showMinute && hour <= 0) { | |
87 | + text = chinesse ? `${fix0(minute)}分${fix0(second)}秒` : `${fix0(minute)}:${fix0(second)}`; | |
88 | + } | |
89 | + setText(text); | |
90 | + } | |
91 | + | |
92 | + return ( | |
93 | + <span | |
94 | + className={classNames(style)} | |
95 | + style={{ | |
96 | + fontSize: size ?? 10, | |
97 | + color: color ?? '#666', | |
98 | + }} | |
99 | + > | |
100 | + {text || ''} | |
101 | + </span> | |
102 | + ); | |
103 | +} | ... | ... |
src/components/ApprovalProgress/components/CountUp/index.tsx
0 → 100644
1 | +import React, { useState, useEffect, useRef } from 'react'; | |
2 | +import { fix0 } from '../../util'; | |
3 | +import classNames from 'classnames'; | |
4 | + | |
5 | +export interface CountUpProps { | |
6 | + seconds: number; // 正计时秒数基数 | |
7 | + size?: number; // 字体大小 | |
8 | + color?: string; // 字体颜色 | |
9 | + chinesse?: boolean; // 是否中文格式 | |
10 | + style?: any; | |
11 | + /** 只正计时秒数 */ | |
12 | + onlySecond?: boolean; | |
13 | + isDay?: boolean; | |
14 | + showMinute?: boolean; | |
15 | +} | |
16 | + | |
17 | +export default function CountUp({ seconds, size, color, chinesse, style, onlySecond, isDay = false, showMinute }: CountUpProps) { | |
18 | + const [text, setText] = useState<string>('--'); | |
19 | + const [obj] = useState({ seconds }); | |
20 | + const intervalId = useRef(); | |
21 | + | |
22 | + useEffect(() => { | |
23 | + intervalId.current && clearInterval(intervalId.current); | |
24 | + obj.seconds = seconds + 1; | |
25 | + if (seconds > 0) { | |
26 | + handleText(); | |
27 | + // @ts-ignore | |
28 | + intervalId.current = setInterval(() => { | |
29 | + handleText(); | |
30 | + }, 1000); | |
31 | + } | |
32 | + return () => { | |
33 | + intervalId.current && clearInterval(intervalId.current); | |
34 | + }; | |
35 | + }, [seconds]); | |
36 | + | |
37 | + function handleText() { | |
38 | + obj.seconds += 1; | |
39 | + const seconds = obj.seconds; | |
40 | + | |
41 | + let day = 0, | |
42 | + hour = 0, | |
43 | + minute = 0, | |
44 | + second = 0, | |
45 | + text = ''; | |
46 | + if (seconds > 0) { | |
47 | + // 正计时不计天 | |
48 | + if (isDay) { | |
49 | + day = Math.floor(seconds / (60 * 60 * 24)); | |
50 | + hour = Math.floor(seconds / (60 * 60)) - day * 24; | |
51 | + minute = Math.floor(seconds / 60) - day * 24 * 60 - hour * 60; | |
52 | + second = Math.floor(seconds) - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60; | |
53 | + } else { | |
54 | + hour = Math.floor(seconds / 3600); | |
55 | + minute = Math.floor(seconds / 60) - hour * 60; | |
56 | + second = Math.floor(seconds) - hour * 60 * 60 - minute * 60; | |
57 | + } | |
58 | + } | |
59 | + if (onlySecond) { | |
60 | + text = `${Math.floor(seconds)}${chinesse ? '秒' : 's'}`; | |
61 | + } | |
62 | + if (!onlySecond && day > 0) { | |
63 | + text = chinesse | |
64 | + ? `${fix0(day)}天${fix0(hour)}时${fix0(minute)}分${fix0(second)}秒` | |
65 | + : `${fix0(day)}d${fix0(hour)}:${fix0(minute)}:${fix0(second)}`; | |
66 | + } | |
67 | + if (!onlySecond && day <= 0) { | |
68 | + text = chinesse ? `${fix0(hour)}时${fix0(minute)}分${fix0(second)}秒` : `${fix0(hour)}:${fix0(minute)}:${fix0(second)}`; | |
69 | + } | |
70 | + | |
71 | + if (!onlySecond && day <= 0 && hour <= 0) { | |
72 | + text = chinesse ? `${fix0(minute)}分${fix0(second)}秒` : `${fix0(minute)}:${fix0(second)}`; | |
73 | + } | |
74 | + | |
75 | + if (showMinute && day > 0) { | |
76 | + text = chinesse ? `${fix0(day)}天${fix0(hour)}时${fix0(minute)}分` : `${fix0(day)}d${fix0(hour)}:${fix0(minute)}`; | |
77 | + } | |
78 | + if (showMinute && day <= 0) { | |
79 | + text = chinesse ? `${fix0(hour)}时${fix0(minute)}分${fix0(second)}秒` : `${fix0(hour)}:${fix0(minute)}:${fix0(second)}`; | |
80 | + } | |
81 | + if (showMinute && hour <= 0) { | |
82 | + text = chinesse ? `${fix0(minute)}分${fix0(second)}秒` : `${fix0(minute)}:${fix0(second)}`; | |
83 | + } | |
84 | + setText(text); | |
85 | + } | |
86 | + | |
87 | + return ( | |
88 | + <span | |
89 | + className={classNames(style)} | |
90 | + style={{ | |
91 | + fontSize: size ?? 10, | |
92 | + color: color ?? '#666', | |
93 | + }} | |
94 | + > | |
95 | + {text || ''} | |
96 | + </span> | |
97 | + ); | |
98 | +} | ... | ... |
src/components/ApprovalProgress/components/TagPills/index.tsx
0 → 100644
1 | +import React from 'react'; | |
2 | +import st from './style.less'; | |
3 | +import { Row } from 'antd'; | |
4 | +import classNames from 'classnames'; | |
5 | + | |
6 | +interface Props { | |
7 | + style?: React.CSSProperties; | |
8 | + titleStyle?: React.CSSProperties; | |
9 | + contentStyle?: React.CSSProperties; | |
10 | + titleTextStyle?: React.CSSProperties; | |
11 | + contentTextStyle?: React.CSSProperties; | |
12 | + /** 类型 */ | |
13 | + type?: 'default' | 'primary' | 'warn' | 'danger' | 'success'; | |
14 | + /** 标题 */ | |
15 | + title: string; | |
16 | + /** 内容 */ | |
17 | + content: string; | |
18 | + /** 内容节点 */ | |
19 | + children?: React.ReactNode; | |
20 | + onPress?: () => void; | |
21 | +} | |
22 | + | |
23 | +const colors = { | |
24 | + default: '#999', | |
25 | + primary: '#4189FD', | |
26 | + warn: '#FF921C', | |
27 | + danger: '#F4333C', | |
28 | + success: '#42E4A4', | |
29 | +}; | |
30 | + | |
31 | +export default function TagPills({ | |
32 | + style, | |
33 | + titleStyle, | |
34 | + titleTextStyle, | |
35 | + contentStyle, | |
36 | + contentTextStyle, | |
37 | + type = 'default', | |
38 | + title, | |
39 | + content, | |
40 | + children, | |
41 | + onPress, | |
42 | +}: Props) { | |
43 | + return ( | |
44 | + <Row align="middle" justify="center" style={style} onClick={onPress}> | |
45 | + <div className={classNames(st.title, titleStyle)} style={{ backgroundColor: colors[type], borderColor: colors[type] }}> | |
46 | + <span className={classNames(st.titleText, titleTextStyle)}>{title}</span> | |
47 | + </div> | |
48 | + <div className={classNames(st.content, contentStyle)} style={{ borderColor: colors[type] }}> | |
49 | + {children ? ( | |
50 | + children | |
51 | + ) : ( | |
52 | + <span className={classNames(st.contentText, contentTextStyle)} style={{ color: colors[type] }}> | |
53 | + {content} | |
54 | + </span> | |
55 | + )} | |
56 | + </div> | |
57 | + </Row> | |
58 | + ); | |
59 | +} | ... | ... |
src/components/ApprovalProgress/components/TagPills/style.less
0 → 100644
1 | +.title { | |
2 | + align-items: center; | |
3 | + justify-content: center; | |
4 | + min-width: 35px; | |
5 | + height: 16px; | |
6 | + line-height: 12px; | |
7 | + padding: 0 5px; | |
8 | + background-color: #fff; | |
9 | + border-width: 0.5px; | |
10 | + border-style: solid; | |
11 | + border-color: #999; | |
12 | + border-right-width: 0px; | |
13 | + border-top-left-radius: 2px; | |
14 | + border-bottom-left-radius: 2px; | |
15 | +} | |
16 | +.titleText { | |
17 | + color: #fff; | |
18 | + font-weight: 500; | |
19 | + font-size: 10px; | |
20 | + text-align: center; | |
21 | +} | |
22 | +.content { | |
23 | + align-items: center; | |
24 | + justify-content: center; | |
25 | + min-width: 35px; | |
26 | + height: 16px; | |
27 | + line-height: 12px; | |
28 | + padding: 0 5px; | |
29 | + background-color: #fff; | |
30 | + border-width: 0.5px; | |
31 | + border-style: solid; | |
32 | + border-color: #999; | |
33 | + border-left-width: 0px; | |
34 | + border-top-right-radius: 2px; | |
35 | + border-bottom-right-radius: 2px; | |
36 | +} | |
37 | +.contentText { | |
38 | + color: #999; | |
39 | + font-weight: 500; | |
40 | + font-size: 10px; | |
41 | + text-align: center; | |
42 | +} | ... | ... |
src/components/ApprovalProgress/components/TimeInfo/index.tsx
0 → 100644
1 | +import React, { useMemo } from 'react'; | |
2 | + | |
3 | +import st from './style.less'; | |
4 | +import { Row } from 'antd'; | |
5 | +import classNames from 'classnames'; | |
6 | +import { formatTime } from '../../util'; | |
7 | + | |
8 | +interface PageProps { | |
9 | + style?: React.CSSProperties; | |
10 | + /** 是否有时效,没有时不展示时效值,默认展示 */ | |
11 | + hasAging?: boolean; | |
12 | + /** 开始时间:ms */ | |
13 | + startTime: number; | |
14 | + /** 结束时间:ms */ | |
15 | + endTime: number; | |
16 | + /** 时效:需要用时 s */ | |
17 | + requiredTime: number; | |
18 | + /** 实际用时:s */ | |
19 | + usedTime: number; | |
20 | + /** 时效 label */ | |
21 | + requiredLabel?: string; | |
22 | + /** 用时 label */ | |
23 | + usedLabel?: string; | |
24 | +} | |
25 | + | |
26 | +/** | |
27 | + * 时效展示 | |
28 | + * 时效:x分钟 用时:x分钟 | |
29 | + * hasAging=false | |
30 | + * 时效:-- 用时:x分钟 | |
31 | + */ | |
32 | +export default function TimeInfo({ | |
33 | + style = {}, | |
34 | + hasAging = true, | |
35 | + startTime, | |
36 | + endTime, | |
37 | + requiredTime, | |
38 | + usedTime, | |
39 | + requiredLabel = '时效', | |
40 | + usedLabel = '用时', | |
41 | +}: PageProps) { | |
42 | + const time = useMemo(() => formatTime(requiredTime), [requiredTime]); | |
43 | + const timeUsed = useMemo(() => formatTime(usedTime), [usedTime]); | |
44 | + | |
45 | + return ( | |
46 | + <Row style={style}> | |
47 | + {hasAging ? ( | |
48 | + <span className={st.textGrayLightSm}> | |
49 | + {requiredLabel}:<span className={st.textWarnSm}>{time.value}</span> | |
50 | + {time.unit} | |
51 | + {!!time.remainValue && ( | |
52 | + <> | |
53 | + <span className={st.textWarnSm}>{time.remainValue}</span> | |
54 | + {time.remainUnit} | |
55 | + </> | |
56 | + )} | |
57 | + </span> | |
58 | + ) : ( | |
59 | + <span className={st.textGrayLightSm}>{requiredLabel}:--</span> | |
60 | + )} | |
61 | + | |
62 | + {timeUsed.value > 0 && ( | |
63 | + <span className={classNames(st.textGrayLightSm, st.ml30)}> | |
64 | + {usedLabel}:<span className={st.textPrimarySm}>{timeUsed.value}</span> | |
65 | + {timeUsed.unit} | |
66 | + {!!timeUsed.remainValue && ( | |
67 | + <> | |
68 | + <span className={st.textPrimarySm}>{timeUsed.remainValue}</span> | |
69 | + {timeUsed.remainUnit} | |
70 | + </> | |
71 | + )} | |
72 | + </span> | |
73 | + )} | |
74 | + </Row> | |
75 | + ); | |
76 | +} | ... | ... |
src/components/ApprovalProgress/components/TimeInfo/style.less
0 → 100644
1 | +.ml30 { | |
2 | + margin-left: 30px; | |
3 | +} | |
4 | +.textPrimarySm { | |
5 | + color: #4189fd; | |
6 | + font-weight: 500; | |
7 | + font-size: 12px; | |
8 | +} | |
9 | +.textWarnSm { | |
10 | + color: #ff921c; | |
11 | + font-weight: 500; | |
12 | + font-size: 12px; | |
13 | +} | |
14 | +.textGrayLightSm { | |
15 | + color: #999; | |
16 | + font-weight: 500; | |
17 | + font-size: 12px; | |
18 | +} | ... | ... |
src/components/ApprovalProgress/components/TimerTag/index.tsx
0 → 100644
1 | +import React, { useMemo } from 'react'; | |
2 | +import { calculateTime, formatTime } from '../../util'; | |
3 | +import st from './style.less'; | |
4 | +import TagPills from '../TagPills'; | |
5 | +import CountUp from '../CountUp'; | |
6 | +import type { CountUpProps } from '../CountUp'; | |
7 | +import CountDown from '../CountDown'; | |
8 | +import type { CountDownProps } from '../CountDown'; | |
9 | + | |
10 | +interface PageProps { | |
11 | + style?: React.CSSProperties; | |
12 | + /** 开始时间:ms */ | |
13 | + startTime: number; | |
14 | + /** | |
15 | + * 完成时间:ms | |
16 | + * 1.无结束时间,表示进行中 | |
17 | + */ | |
18 | + endTime?: number; | |
19 | + /** | |
20 | + * 预计完成时间: ms | |
21 | + * 1.无预计结束时间,不展示Tag | |
22 | + * 2.有预计结束时间,无endTime,标识进行中: 展示倒计时Tag | |
23 | + */ | |
24 | + expectedTime?: number; | |
25 | + /** 已结束:是否展示已用时间 */ | |
26 | + showUsedTime?: boolean; | |
27 | + /** 倒计时组件 props, 参考CountDown组件props */ | |
28 | + countDownProps?: Partial<CountDownProps>; | |
29 | + countUpProps?: Partial<CountUpProps>; | |
30 | + onPress?: () => void; | |
31 | +} | |
32 | + | |
33 | +/** | |
34 | + * 时效计时器 | |
35 | + * 1. 未超时,已结束,showUsedTime:true, 展示已用时,false 不展示 | |
36 | + * 2. 未超时,进行中,展示倒计时Tag | |
37 | + * 3. 超时,展示已超时Tag | |
38 | + */ | |
39 | +export default function TimerTag({ | |
40 | + style = {}, | |
41 | + startTime = 0, | |
42 | + endTime, | |
43 | + expectedTime = 0, | |
44 | + showUsedTime, | |
45 | + countDownProps, | |
46 | + countUpProps, | |
47 | + onPress, | |
48 | +}: PageProps) { | |
49 | + const { isTimeout, isCountdown, diffSeconds = 0, timeoutStr } = useMemo(() => calculateTime(expectedTime, endTime), [expectedTime, endTime]); | |
50 | + | |
51 | + // 已结束 | |
52 | + const isFinished = (endTime || 0) > 0; | |
53 | + | |
54 | + function navToTimeDetail() { | |
55 | + onPress && onPress(); | |
56 | + } | |
57 | + | |
58 | + // 超时 | |
59 | + if (isTimeout) { | |
60 | + return isFinished ? ( | |
61 | + <TagPills style={style} type="danger" title="超时" content={timeoutStr || ''} onPress={navToTimeDetail} /> | |
62 | + ) : ( | |
63 | + <TagPills style={style} type="danger" title="已超时" content={timeoutStr || ''} onPress={navToTimeDetail}> | |
64 | + <CountUp style={st.timeBarTimeTextDanger} seconds={diffSeconds} {...countUpProps} /> | |
65 | + </TagPills> | |
66 | + ); | |
67 | + } | |
68 | + // 未超时:进行中(倒计时) | |
69 | + if (isCountdown) { | |
70 | + return ( | |
71 | + <TagPills style={style} type="warn" title="倒计时" content="" onPress={navToTimeDetail}> | |
72 | + <CountDown style={st.timeBarTimeTextWarn} seconds={diffSeconds} {...countDownProps} /> | |
73 | + </TagPills> | |
74 | + ); | |
75 | + } | |
76 | + // 未超时:已用时间 | |
77 | + if (showUsedTime) { | |
78 | + const usedTime = ((endTime ?? Date.now()) - startTime) / 1000; // 已用时间:秒 | |
79 | + const usedTimeObj = formatTime(usedTime); | |
80 | + let usedTimeStr = `${usedTimeObj.value}${usedTimeObj.unit}`; | |
81 | + if (usedTimeObj.remainValue) { | |
82 | + usedTimeStr += `${usedTimeObj.remainValue}${usedTimeObj.remainUnit}`; | |
83 | + } | |
84 | + return <TagPills style={style} type="primary" title={isFinished ? '用时' : '已用时'} content={usedTimeStr} onPress={navToTimeDetail} />; | |
85 | + } | |
86 | + // 未超时:不展示 | |
87 | + return null; | |
88 | +} | ... | ... |
src/components/ApprovalProgress/components/TimerTag/style.less
0 → 100644
1 | +// .ml30 { | |
2 | +// margin-left: 30px; | |
3 | +// } | |
4 | +// .textPrimarySm { | |
5 | +// color: #4189FD; | |
6 | +// font-weight: 500; | |
7 | +// font-size: 12px; | |
8 | +// } | |
9 | +// .textWarnSm { | |
10 | +// color: #FF921C; | |
11 | +// font-weight: 500; | |
12 | +// font-size: 12px; | |
13 | +// } | |
14 | +// .textGrayLightSm { | |
15 | +// color: #999; | |
16 | +// font-weight: 500; | |
17 | +// font-size: 12px; | |
18 | +// } | |
19 | + | |
20 | +.timeBarTimeTextWarn { | |
21 | + color: #FF921C; | |
22 | + font-size: 10px; | |
23 | + font-weight: 500; | |
24 | + text-align: center; | |
25 | +} | |
26 | +.timeBarTimeTextDanger { | |
27 | + color: #F4333C; | |
28 | + font-size: 10px; | |
29 | + font-weight: 500; | |
30 | + text-align: center; | |
31 | +} | ... | ... |
src/components/ApprovalProgress/index.tsx
1 | -/* | |
2 | - * @Author: wangqiang@feewee.cn | |
3 | - * @Date: 2022-10-26 09:09:04 | |
4 | - * @LastEditors: wangqiang@feewee.cn | |
5 | - * @LastEditTime: 2022-10-26 10:30:00 | |
6 | - */ | |
7 | 1 | import { ApprovalProgressDotColor, ApprovalProgressItemVO, ApprovalProgressStatus, ApprovalProgressStatusColor, getApprovalProgressApi } from './api'; |
8 | 2 | import { Row, Spin, Tag, Timeline } from 'antd'; |
9 | 3 | import moment from 'moment'; |
... | ... | @@ -11,6 +5,9 @@ import React, { useEffect, useState } from 'react'; |
11 | 5 | import style from './style.less'; |
12 | 6 | import { IMGURL } from '@/utils'; |
13 | 7 | import { ClockCircleFilled, CheckCircleFilled, CloseCircleFilled, QuestionCircleFilled } from '@ant-design/icons'; |
8 | +import TimerTag from './components/TimerTag'; | |
9 | +import classNames from 'classnames'; | |
10 | +import TimeInfo from './components/TimeInfo'; | |
14 | 11 | |
15 | 12 | interface Props { |
16 | 13 | orderNo?: string; // 审批单号 |
... | ... | @@ -24,33 +21,18 @@ interface Progress { |
24 | 21 | |
25 | 22 | const DotIcon = [ |
26 | 23 | <QuestionCircleFilled size={14} />, |
24 | + <ClockCircleFilled size={14} />, // 1 | |
25 | + <CheckCircleFilled size={14} />, // 2 | |
26 | + <CloseCircleFilled size={14} />, // 3 | |
27 | + <ClockCircleFilled size={14} />, // 4 | |
27 | 28 | <ClockCircleFilled size={14} />, |
28 | - <CheckCircleFilled size={14} />, | |
29 | - <CloseCircleFilled size={14} />, | |
30 | - <ClockCircleFilled size={14} />, | |
29 | + <div style={{ width: 14, height: 14, borderRadius: '50%', backgroundColor: '#dedede' }} />, // 6 | |
31 | 30 | ]; |
32 | 31 | |
33 | 32 | export default function ApprovalProgress({ orderNo }: Props) { |
34 | 33 | const [progress, setProgress] = useState<Progress>({ |
35 | 34 | loading: false, |
36 | - // data: [ | |
37 | - // { | |
38 | - // approveTime: Date.now(), | |
39 | - // approverName: "廖洋铭", | |
40 | - // approverId: 2143, | |
41 | - // duration: "30分钟", | |
42 | - // status: 2, | |
43 | - // opinion: "看回放离开家阿斯卡戴假发哈吉手打拉法基", | |
44 | - // }, | |
45 | - // { | |
46 | - // approveTime: Date.now(), | |
47 | - // approverName: "王强", | |
48 | - // approverId: 1401, | |
49 | - // duration: "1小时30分钟", | |
50 | - // status: 3, | |
51 | - // opinion: "看回放离开家阿斯卡戴假发哈吉手打拉法基", | |
52 | - // }, | |
53 | - // ], | |
35 | + data: [], | |
54 | 36 | }); |
55 | 37 | |
56 | 38 | useEffect(() => { |
... | ... | @@ -61,6 +43,41 @@ export default function ApprovalProgress({ orderNo }: Props) { |
61 | 43 | setProgress({ |
62 | 44 | loading: false, |
63 | 45 | data: res.data || [], |
46 | + // data: [ | |
47 | + // { | |
48 | + // // 审批中倒计时 | |
49 | + // approveTime: 1709741004000, | |
50 | + // approverName: 'Shinner', | |
51 | + // approverId: 2144, | |
52 | + // status: 1, | |
53 | + // opinion: '测试理由', | |
54 | + // efficientTime: 1709781004000, | |
55 | + // createTime: 1709721004000, | |
56 | + // roleNames: ['销售一级管理', '销售二级管理', '销售三级管理'], | |
57 | + // }, | |
58 | + // { | |
59 | + // // 审批中超时 | |
60 | + // approveTime: 1799722004000, | |
61 | + // approverName: 'Shinner', | |
62 | + // approverId: 2145, | |
63 | + // status: 1, | |
64 | + // opinion: '测试理由', | |
65 | + // efficientTime: 1709721004000, | |
66 | + // createTime: 1709721004000, | |
67 | + // roleNames: ['销售一级管理', '销售二级管理', '销售三级管理'], | |
68 | + // }, | |
69 | + // { | |
70 | + // // 审批结束超时 | |
71 | + // approveTime: 1799722004000, | |
72 | + // approverName: 'Shinner', | |
73 | + // approverId: 2146, | |
74 | + // status: 2, | |
75 | + // opinion: '测试理由', | |
76 | + // efficientTime: 1709781004000, | |
77 | + // createTime: 1709721004000, | |
78 | + // roleNames: ['销售一级管理', '销售二级管理', '销售三级管理'], | |
79 | + // }, | |
80 | + // ], | |
64 | 81 | }); |
65 | 82 | }) |
66 | 83 | .catch((error) => { |
... | ... | @@ -75,67 +92,86 @@ export default function ApprovalProgress({ orderNo }: Props) { |
75 | 92 | return ( |
76 | 93 | <Spin spinning={progress.loading}> |
77 | 94 | <Timeline className={style.ApprovalProgress_Timeline}> |
78 | - {(progress.data || []).map((item) => ( | |
79 | - <Timeline.Item | |
80 | - className={style.ApprovalProgress_Timeline_Item} | |
81 | - key={item.approverId} | |
82 | - color={item.status ? ApprovalProgressDotColor[item.status] : undefined} | |
83 | - dot={[1, 2, 3, 4].includes(item.status ?? 0) ? DotIcon[item.status ?? 0] : <QuestionCircleFilled size={14} />} | |
84 | - > | |
85 | - <div className={style.ApprovalProgress_Timeline_Item_container}> | |
86 | - <Row align="middle"> | |
87 | - <img | |
88 | - style={{ | |
89 | - width: 30, | |
90 | - height: 30, | |
91 | - borderRadius: '50%', | |
92 | - marginRight: 5, | |
93 | - }} | |
94 | - src={IMGURL.getBAvatar(item.approverId || -1)} | |
95 | - alt="" | |
96 | - /> | |
97 | - <span className={style.name} style={{ marginRight: 5 }}> | |
98 | - {item.approverName || '-'} | |
99 | - </span> | |
100 | - {item.status ? ( | |
101 | - <Tag className={style.tag} color={item.status ? ApprovalProgressStatusColor[item.status] : undefined}> | |
102 | - {ApprovalProgressStatus[item.status]} | |
103 | - </Tag> | |
104 | - ) : null} | |
105 | - </Row> | |
106 | - {item.roleNames && item.roleNames.length > 0 ? ( | |
107 | - <Row align="middle" style={{ marginTop: 4 }}> | |
108 | - {item.roleNames.map((name) => ( | |
109 | - <Tag key={name} className={style.tag} color="gold"> | |
110 | - {name} | |
95 | + {(progress.data || []).map((item) => { | |
96 | + const processNow = item.status === 1; // 审批中 | |
97 | + const processEnd = item.status === 2 || item.status === 3; // 审批结束 | |
98 | + const processfuture = item.status === 6; // 待审批 | |
99 | + return ( | |
100 | + <Timeline.Item | |
101 | + className={style.ApprovalProgress_Timeline_Item} | |
102 | + key={item.approverId} | |
103 | + color={item.status ? ApprovalProgressDotColor[item.status] : undefined} | |
104 | + dot={[1, 2, 3, 4, 6].includes(item.status ?? 0) ? DotIcon[item.status ?? 0] : <QuestionCircleFilled size={14} />} | |
105 | + > | |
106 | + <div className={style.ApprovalProgress_Timeline_Item_container}> | |
107 | + <Row align="middle"> | |
108 | + {/* <img | |
109 | + style={{ | |
110 | + width: 30, | |
111 | + height: 30, | |
112 | + borderRadius: '50%', | |
113 | + marginRight: 5, | |
114 | + }} | |
115 | + src={IMGURL.getBAvatar(item.approverId || -1)} | |
116 | + alt="" | |
117 | + /> */} | |
118 | + <span className={style.name} style={{ marginRight: 5 }}> | |
119 | + {item.approverName || '-'} | |
120 | + </span> | |
121 | + {item.status ? ( | |
122 | + <Tag className={style.tag} color={item.status ? ApprovalProgressStatusColor[item.status] : undefined}> | |
123 | + {ApprovalProgressStatus[item.status]} | |
111 | 124 | </Tag> |
112 | - ))} | |
125 | + ) : null} | |
126 | + {/* 审批中显示超时(当 > 时) | 倒计时(当 < 时) */} | |
127 | + {processNow && item.efficientTime ? <TimerTag startTime={moment().valueOf()} expectedTime={item.efficientTime} /> : null} | |
128 | + {/* 审批结束显示超时(完 > 时) */} | |
129 | + {processEnd && item.efficientTime && item.approveTime ? ( | |
130 | + <TimerTag startTime={item.efficientTime} endTime={item.approveTime} expectedTime={item.efficientTime} /> | |
131 | + ) : null} | |
113 | 132 | </Row> |
114 | - ) : null} | |
115 | - {item.approveTime && (item.status === 2 || item.status === 3) ? ( | |
116 | - <div className={style.time}>{moment(item.approveTime).format('YYYY-MM-DD HH:mm:ss')}</div> | |
117 | - ) : null} | |
118 | - {item.expTime && (item.status === 1 || item.status === 4) && ( | |
119 | - <div className={style.item}> | |
120 | - <span className={style.label}>截止时间:</span> | |
121 | - <span className={style.value}>{item.expTime ? moment(Number(item.expTime)).format('YYYY.MM.DD HH:mm:ss') : '--'}</span> | |
122 | - </div> | |
123 | - )} | |
124 | - {(item.status === 2 || item.status === 3) && ( | |
125 | - <> | |
126 | - <div className={style.item}> | |
127 | - <span className={style.label}>审批意见:</span> | |
128 | - <span className={style.value}>{item.opinion || '--'}</span> | |
129 | - </div> | |
130 | - <div className={style.item}> | |
131 | - <span className={style.label}>审批时长:</span> | |
132 | - <span className={style.value}>{item.duration || '--'}</span> | |
133 | - </div> | |
134 | - </> | |
135 | - )} | |
136 | - </div> | |
137 | - </Timeline.Item> | |
138 | - ))} | |
133 | + {item.roleNames && item.roleNames.length > 0 ? ( | |
134 | + <Row align="middle" style={{ marginTop: 4 }}> | |
135 | + {item.roleNames.map((name) => ( | |
136 | + <Tag key={name} className={style.tag} color="gold"> | |
137 | + {name} | |
138 | + </Tag> | |
139 | + ))} | |
140 | + </Row> | |
141 | + ) : null} | |
142 | + {/* 详情 */} | |
143 | + {!processfuture && ( | |
144 | + <> | |
145 | + {item.createTime ? ( | |
146 | + <div className={style.infoItem}> | |
147 | + 推送时间:{item.createTime ? moment(Number(item.createTime)).format('YYYY.MM.DD HH:mm:ss') : '--'} | |
148 | + </div> | |
149 | + ) : null} | |
150 | + {item.approveTime && processEnd && ( | |
151 | + <div className={style.infoItem}> | |
152 | + 完成时间:{item.approveTime ? moment(Number(item.approveTime)).format('YYYY.MM.DD HH:mm:ss') : '--'} | |
153 | + </div> | |
154 | + )} | |
155 | + {item.createTime && item.efficientTime ? ( | |
156 | + <TimeInfo | |
157 | + style={{ marginTop: 8, lineHeight: '16px' }} | |
158 | + startTime={moment(Number(item.createTime)).valueOf()} | |
159 | + endTime={item.approveTime ?? moment().valueOf()} | |
160 | + requiredTime={(item.efficientTime - moment(Number(item.createTime)).valueOf()) / 1000} | |
161 | + usedTime={item.approveTime ? (item.approveTime - moment(Number(item.createTime)).valueOf()) / 1000 : 0} | |
162 | + /> | |
163 | + ) : null} | |
164 | + {processEnd && ( | |
165 | + <div className={classNames(style.infoItem, { marginBottom: 30 })}> | |
166 | + 审批意见:{item.opinion ? (item.opinion.trim() === '' ? '--' : item.opinion) : '--'} | |
167 | + </div> | |
168 | + )} | |
169 | + </> | |
170 | + )} | |
171 | + </div> | |
172 | + </Timeline.Item> | |
173 | + ); | |
174 | + })} | |
139 | 175 | </Timeline> |
140 | 176 | </Spin> |
141 | 177 | ); | ... | ... |
src/components/ApprovalProgress/style.less
... | ... | @@ -23,29 +23,11 @@ |
23 | 23 | } |
24 | 24 | } |
25 | 25 | } |
26 | - .item { | |
27 | - margin-top: 4px; | |
28 | - } | |
29 | 26 | .name { |
30 | 27 | color: #666; |
31 | 28 | font-weight: 500; |
32 | 29 | font-size: 14px; |
33 | 30 | } |
34 | - .time { | |
35 | - color: #999; | |
36 | - font-size: 10px; | |
37 | - margin-top: 4px; | |
38 | - } | |
39 | - .label { | |
40 | - color: #999; | |
41 | - font-weight: 500; | |
42 | - font-size: 12px; | |
43 | - } | |
44 | - .value { | |
45 | - color: #666; | |
46 | - font-weight: 500; | |
47 | - font-size: 12px; | |
48 | - } | |
49 | 31 | .tag { |
50 | 32 | height: 16px; |
51 | 33 | line-height: 14px; |
... | ... | @@ -53,4 +35,10 @@ |
53 | 35 | padding: 0 5px; |
54 | 36 | } |
55 | 37 | } |
38 | + .infoItem { | |
39 | + color: #999; | |
40 | + font-size: 12px; | |
41 | + margin-top: 8px; | |
42 | + line-height: 16px; | |
43 | + } | |
56 | 44 | } | ... | ... |
src/components/ApprovalProgress/util.ts
0 → 100644
1 | +/** | |
2 | + * 格式化时间展示,值为秒 | |
3 | + * @param time 秒数 | |
4 | + * @returns timeString + unit | |
5 | + */ | |
6 | +export function formatTime(time: number = 0): { | |
7 | + value: number; // 时间值 | |
8 | + unit: string; // 时间单位 | |
9 | + remainValue?: number; // 剩余时间值 | |
10 | + remainUnit?: string; // 剩余时间单位 | |
11 | +} { | |
12 | + // 小于 60秒:展示为秒 | |
13 | + if (time < 60) { | |
14 | + return { | |
15 | + value: Math.floor(time), | |
16 | + unit: time === 0 ? '分钟' : '秒', | |
17 | + }; | |
18 | + } | |
19 | + // 小于 60分钟:展示为分钟 + 秒 | |
20 | + if (time < 60 * 60) { | |
21 | + const remainSeconds = Math.floor(time % 60); | |
22 | + | |
23 | + if (remainSeconds === 0) { | |
24 | + // 整分钟 | |
25 | + return { | |
26 | + value: Math.floor(time / 60), | |
27 | + unit: '分钟', | |
28 | + }; | |
29 | + } | |
30 | + | |
31 | + // 分钟 + 秒 | |
32 | + return { | |
33 | + value: Math.floor((time - remainSeconds) / 60), | |
34 | + unit: '分', | |
35 | + remainValue: remainSeconds, | |
36 | + remainUnit: '秒', | |
37 | + }; | |
38 | + } | |
39 | + // 小于 24小时:展示为小时 + 分钟 | |
40 | + if (time < 60 * 60 * 24) { | |
41 | + const diffMinutes = Math.floor(time / 60); | |
42 | + const remainMinutes = Math.floor(diffMinutes % 60); | |
43 | + | |
44 | + // 整小时 | |
45 | + if (remainMinutes === 0) { | |
46 | + return { | |
47 | + value: Math.floor(diffMinutes / 60), | |
48 | + unit: '小时', | |
49 | + }; | |
50 | + } | |
51 | + | |
52 | + // 小时 + 分钟 | |
53 | + return { | |
54 | + value: Math.floor((diffMinutes - remainMinutes) / 60), | |
55 | + unit: '小时', | |
56 | + remainValue: remainMinutes, // 剩余分钟 | |
57 | + remainUnit: '分', | |
58 | + }; | |
59 | + } | |
60 | + // 大于 24小时:展示为天 + 小时 | |
61 | + const diffHours = Math.floor(time / 60 / 60); | |
62 | + const remainHours = Math.floor(diffHours % 24); | |
63 | + // 整天 | |
64 | + if (remainHours === 0) { | |
65 | + return { | |
66 | + value: diffHours / 24, | |
67 | + unit: '天', | |
68 | + }; | |
69 | + } | |
70 | + // 天 + 小时 | |
71 | + return { | |
72 | + value: Math.floor((diffHours - remainHours) / 24), | |
73 | + unit: '天', | |
74 | + remainValue: remainHours, // 剩余小时 | |
75 | + remainUnit: '小时', | |
76 | + }; | |
77 | +} | |
78 | + | |
79 | +interface CalculatedTime { | |
80 | + isTimeout: boolean; // 是否超时 | |
81 | + isCountdown: boolean; // 是否倒计时 | |
82 | + diffSeconds: number; // 时间差:超时或倒计时 | |
83 | + timeoutStr?: string; // 超时时间字符串 | |
84 | +} | |
85 | + | |
86 | +/** | |
87 | + * 计算时效 | |
88 | + * @param expectedTime 预计完成时间 | |
89 | + * @param endTime 结束时间 | |
90 | + * @description | |
91 | + * 1. 如果 endTime 为 0,表示未结束:计算倒计时 | |
92 | + * 2. 如果 endTime 不为 0,表示已结束:计算超时 | |
93 | + * diffTime = endTime - expectedTime | |
94 | + * 2.1 diffTime <= 0, 未超时 | |
95 | + * 2.2 diffTime > 0, 超时 | |
96 | + * @returns CalculatedTime | |
97 | + */ | |
98 | +export function calculateTime(expectedTime: number = 0, endTime: number = 0): CalculatedTime { | |
99 | + if (expectedTime === 0) { | |
100 | + return { | |
101 | + isTimeout: false, | |
102 | + isCountdown: false, | |
103 | + diffSeconds: 0, | |
104 | + }; | |
105 | + } | |
106 | + | |
107 | + // 1. 如果 endTime 为 0,表示未结束:计算倒计时 | |
108 | + if (endTime === 0) { | |
109 | + const diffTime = (Date.now() - expectedTime) / 1000; // 秒 | |
110 | + if (diffTime < 0) { | |
111 | + return { | |
112 | + isTimeout: false, | |
113 | + isCountdown: true, | |
114 | + diffSeconds: Math.abs(diffTime), | |
115 | + }; | |
116 | + } | |
117 | + // 超时:返回超时字符串 todo refactor | |
118 | + const passTime = formatTime(diffTime); | |
119 | + let passTimeStr = `${Math.floor(passTime.value)}${passTime.unit}`; | |
120 | + if (passTime.remainValue) { | |
121 | + passTimeStr += `${Math.floor(passTime.remainValue)}${passTime.remainUnit}`; | |
122 | + } | |
123 | + return { | |
124 | + isTimeout: true, | |
125 | + isCountdown: false, | |
126 | + diffSeconds: Math.floor(diffTime), | |
127 | + timeoutStr: passTimeStr, | |
128 | + }; | |
129 | + } | |
130 | + | |
131 | + const diffTime = (endTime - expectedTime) / 1000; // 秒 | |
132 | + // 2. 如果 endTime 不为 0,表示已结束 | |
133 | + // 2.1 若 diffTime > 0,表示超时 | |
134 | + if (diffTime > 0) { | |
135 | + // 超时:返回超时字符串 | |
136 | + const passTime = formatTime(diffTime); | |
137 | + let passTimeStr = `${Math.floor(passTime.value)}${passTime.unit}`; | |
138 | + if (passTime.remainValue) { | |
139 | + passTimeStr += `${Math.floor(passTime.remainValue)}${passTime.remainUnit}`; | |
140 | + } | |
141 | + return { | |
142 | + isTimeout: true, | |
143 | + isCountdown: false, | |
144 | + diffSeconds: diffTime, | |
145 | + timeoutStr: passTimeStr, | |
146 | + }; | |
147 | + } | |
148 | + | |
149 | + // 2.2. 若 diffTime <= 0, 表示未超时 | |
150 | + return { | |
151 | + isTimeout: false, | |
152 | + isCountdown: false, | |
153 | + diffSeconds: 0, | |
154 | + }; | |
155 | +} | |
156 | + | |
157 | +/** | |
158 | + * 补零 | |
159 | + * @param number | |
160 | + * @param length | |
161 | + */ | |
162 | +export const fix0 = (number: number, length: number = 2): string => { | |
163 | + let temp = number.toString(); | |
164 | + while (temp.length < length) { | |
165 | + temp = `0${temp}`; | |
166 | + } | |
167 | + return temp; | |
168 | +}; | ... | ... |
src/components/ShopSelectNew/components/ShopModal.tsx
... | ... | @@ -35,8 +35,9 @@ interface Props { |
35 | 35 | */ |
36 | 36 | disabledShopIds?: number[]; |
37 | 37 | disabledOptions?: (keyof ShopSelectNewOptions)[]; |
38 | - showBrand?: boolean //表格中是否展示授权品牌,默认展示 | |
39 | - showAfshop?: boolean //表格中是否展示对应售后门店,默认展示 | |
38 | + showBrand?: boolean; //表格中是否展示授权品牌,默认展示 | |
39 | + showAfshop?: boolean; //表格中是否展示对应售后门店,默认展示 | |
40 | + destroyOnClose?: boolean; | |
40 | 41 | } |
41 | 42 | |
42 | 43 | export default function ShopModal({ |
... | ... | @@ -58,6 +59,7 @@ export default function ShopModal({ |
58 | 59 | disabledOptions, |
59 | 60 | showBrand = true, |
60 | 61 | showAfshop = true, |
62 | + destroyOnClose = false, | |
61 | 63 | }: Props) { |
62 | 64 | const optionsStatus = useMemo(() => { |
63 | 65 | return { |
... | ... | @@ -190,12 +192,12 @@ export default function ShopModal({ |
190 | 192 | setSelected( |
191 | 193 | checked |
192 | 194 | ? listInitial.data |
193 | - .map((item) => ({ | |
194 | - ...item, | |
195 | - value: item.shopId, | |
196 | - label: item.shopShortName, | |
197 | - })) | |
198 | - .filter((item) => (disabledShopIds.includes(item.shopId!) ? selected.find((s) => s.shopId === item.shopId) : true)) | |
195 | + .map((item) => ({ | |
196 | + ...item, | |
197 | + value: item.shopId, | |
198 | + label: item.shopShortName, | |
199 | + })) | |
200 | + .filter((item) => (disabledShopIds.includes(item.shopId!) ? selected.find((s) => s.shopId === item.shopId) : true)) | |
199 | 201 | : selected.filter((s) => disabledShopIds.includes(s.shopId!)), |
200 | 202 | ); |
201 | 203 | }; |
... | ... | @@ -209,6 +211,7 @@ export default function ShopModal({ |
209 | 211 | visible={visible} |
210 | 212 | onCancel={() => setVisible(false)} |
211 | 213 | onOk={() => onOk()} |
214 | + destroyOnClose={destroyOnClose} | |
212 | 215 | > |
213 | 216 | {multiple ? ( |
214 | 217 | <> |
... | ... | @@ -518,7 +521,7 @@ export default function ShopModal({ |
518 | 521 | <Table.Column title="门店业态" dataIndex="bizType" align="left" render={(bizType) => (bizType ? BizType[bizType] : '-')} /> |
519 | 522 | <Table.Column title="归属公司" dataIndex="dealer" align="left" render={(dealer) => dealer?.name || '-'} /> |
520 | 523 | <Table.Column title="门店区域" dataIndex="region" align="left" render={(region) => region?.fullName || '-'} /> |
521 | - {!!showBrand && | |
524 | + {!!showBrand && ( | |
522 | 525 | <Table.Column |
523 | 526 | title="授权品牌" |
524 | 527 | dataIndex="brandList" |
... | ... | @@ -542,10 +545,8 @@ export default function ShopModal({ |
542 | 545 | ) |
543 | 546 | } |
544 | 547 | /> |
545 | - } | |
546 | - {!!showAfshop && | |
547 | - <Table.Column title="对应售后门店" dataIndex="casShopName" align="left" render={(casShopName) => casShopName || '-'} /> | |
548 | - } | |
548 | + )} | |
549 | + {!!showAfshop && <Table.Column title="对应售后门店" dataIndex="casShopName" align="left" render={(casShopName) => casShopName || '-'} />} | |
549 | 550 | </Table> |
550 | 551 | </Modal> |
551 | 552 | ); | ... | ... |
src/components/ShopSelectNew/index.tsx
... | ... | @@ -7,7 +7,7 @@ |
7 | 7 | import useInitial from '@/hooks/useInitail'; |
8 | 8 | import { isObjectChanged } from '@/utils/validate'; |
9 | 9 | import { Tag } from 'antd'; |
10 | -import type { Ref} from 'react'; | |
10 | +import type { Ref } from 'react'; | |
11 | 11 | import React, { forwardRef, memo, useEffect, useImperativeHandle, useState } from 'react'; |
12 | 12 | import type { QueryParams, ShopSelectNewOptions, Value } from './api'; |
13 | 13 | import { getShopListApi, getShopListChooseOptionsApi } from './api'; |
... | ... | @@ -38,8 +38,9 @@ interface Props { |
38 | 38 | disabledShopIds?: number[]; |
39 | 39 | disabledOptions?: (keyof ShopSelectNewOptions)[]; |
40 | 40 | onDefaultOptionsChangeFetch?: boolean; |
41 | - showBrand?: boolean | |
42 | - showAfshop?: boolean | |
41 | + showBrand?: boolean; | |
42 | + showAfshop?: boolean; | |
43 | + destroyOnClose?: boolean; | |
43 | 44 | } |
44 | 45 | |
45 | 46 | export interface ShopSelectNewRef { |
... | ... | @@ -64,6 +65,7 @@ function ShopSelectNew( |
64 | 65 | onDefaultOptionsChangeFetch, |
65 | 66 | showBrand, |
66 | 67 | showAfshop, |
68 | + destroyOnClose, | |
67 | 69 | }: Props, |
68 | 70 | ref: Ref<ShopSelectNewRef>, |
69 | 71 | ) { |
... | ... | @@ -220,6 +222,7 @@ function ShopSelectNew( |
220 | 222 | disabledOptions={disabledOptions} |
221 | 223 | showBrand={showBrand} |
222 | 224 | showAfshop={showAfshop} |
225 | + destroyOnClose={destroyOnClose} | |
223 | 226 | /> |
224 | 227 | )} |
225 | 228 | </div> | ... | ... |
src/pages/carinsur/InsuranceShop/Condition/index.tsx
... | ... | @@ -74,7 +74,7 @@ export default function Condition(props: Props) { |
74 | 74 | useEffect(() => { |
75 | 75 | value.brandId != currentBrandId && setCurrentBrandId(value.brandId); |
76 | 76 | form.setFieldsValue({ |
77 | - brand: brandLabelInValue && value.brandId ? { brandId: value.brandId, brandName: value.brandName } : value.brandId, | |
77 | + brand: brandLabelInValue && value.brandId ? { id: value.brandId, name: value.brandName } : value.brandId, | |
78 | 78 | joinDealer: value |
79 | 79 | ? { type: value.joinDealerType || 1, selected: _.compact((value.joinDealerIds || '').split(',').map((item) => Number(item))) } |
80 | 80 | : defaultDealerValue, |
... | ... | @@ -99,9 +99,9 @@ export default function Condition(props: Props) { |
99 | 99 | } |
100 | 100 | |
101 | 101 | function getTargetCustomer(customer: any[] = []) { |
102 | - let targetCustomer = defaultCustomer; | |
103 | - let _checks: any = []; | |
104 | - let _filter = defaultCustomer.filter || {}; | |
102 | + const targetCustomer = defaultCustomer; | |
103 | + const _checks: any = []; | |
104 | + const _filter = defaultCustomer.filter || {}; | |
105 | 105 | customer.forEach((item) => { |
106 | 106 | let seriesValue = []; |
107 | 107 | _checks.push(item.type); |
... | ... | @@ -154,7 +154,7 @@ export default function Condition(props: Props) { |
154 | 154 | )} |
155 | 155 | <FormItem noStyle shouldUpdate={(prevValues, currentValues) => prevValues.brand != currentValues.brand}> |
156 | 156 | {({ getFieldValue }): any => { |
157 | - const brandId = (brandLabelInValue && getFieldValue('brand') ? getFieldValue('brand').brandId : getFieldValue('brand')) || value.brandId; | |
157 | + const brandId = (brandLabelInValue && getFieldValue('brand') ? getFieldValue('brand').id : getFieldValue('brand')) || value.brandId; | |
158 | 158 | return brandId ? ( |
159 | 159 | <div> |
160 | 160 | {dealerShow && ( | ... | ... |
src/pages/carinsur/InsuranceShop/components/CreateModal.tsx
... | ... | @@ -5,6 +5,8 @@ import { getCompanyList, saveData } from '../api'; |
5 | 5 | import { getShopApi } from '@/common/api'; |
6 | 6 | import useInitial from '@/hooks/useInitail'; |
7 | 7 | import SendToRepairShop from './SendToRepairShop'; |
8 | +import ShopSelectNew from '@/components/ShopSelectNew'; | |
9 | +import _ from 'lodash'; | |
8 | 10 | |
9 | 11 | const FormItem = Form.Item; |
10 | 12 | const Option = Select.Option; |
... | ... | @@ -47,7 +49,7 @@ export default function CreateModal({ onCancel, item = {}, onRrfreshing, visible |
47 | 49 | const params = { |
48 | 50 | insurerId: fieldsValue.insurerId.value, |
49 | 51 | saleShops: fieldsValue.saleShops.map((item: any) => ({ shopId: item.value, shopName: item.label })), |
50 | - stmtShop: { shopId: fieldsValue.stmtShop.value, shopName: fieldsValue.stmtShop.label }, | |
52 | + stmtShop: { shopId: fieldsValue.stmtShop[0].value, shopName: fieldsValue.stmtShop[0].label }, | |
51 | 53 | repairShops: fieldsValue.repairShops.map((item: any) => { |
52 | 54 | const _item = { ...item }; |
53 | 55 | delete _item.key; |
... | ... | @@ -87,7 +89,7 @@ export default function CreateModal({ onCancel, item = {}, onRrfreshing, visible |
87 | 89 | insurerId: item.insurerId ? { value: item.insurerId, label: item.insurerName } : undefined, |
88 | 90 | repairShops: item.repairShops ? item.repairShops.map((i, index) => ({ ...i, key: index + 1 })) : [], |
89 | 91 | saleShops: item.saleShops ? item.saleShops.map((i) => ({ value: i.shopId, label: i.shopName })) : [], |
90 | - stmtShop: item.stmtShop ? { value: item.stmtShop.shopId, label: item.stmtShop.shopName } : undefined, | |
92 | + stmtShop: !_.isEmpty(item.stmtShop) ? [{ value: item.stmtShop.shopId, label: item.stmtShop.shopName }] : undefined, | |
91 | 93 | }} |
92 | 94 | > |
93 | 95 | <FormItem label="保险公司" name="insurerId" rules={[{ required: true, message: '该选项为必填项' }]}> |
... | ... | @@ -107,22 +109,10 @@ export default function CreateModal({ onCancel, item = {}, onRrfreshing, visible |
107 | 109 | </Select> |
108 | 110 | </FormItem> |
109 | 111 | <FormItem label="出保门店" name="saleShops" rules={[{ required: true, message: '该选项为必填项' }]}> |
110 | - <Select placeholder="请选择" labelInValue mode="multiple" style={{ width: '100%' }} showSearch optionFilterProp="children"> | |
111 | - {allshopData.map((item: CommonApi.OptionVO) => ( | |
112 | - <Option key={item.id} value={item.id}> | |
113 | - {item.name} | |
114 | - </Option> | |
115 | - ))} | |
116 | - </Select> | |
112 | + <ShopSelectNew destroyOnClose multiple type={2} shopIds={allshopData.map((i) => i.id!)} placeholder="请选择" /> | |
117 | 113 | </FormItem> |
118 | 114 | <FormItem label="返利结算门店" name="stmtShop" rules={[{ required: true, message: '该选项为必填项' }]}> |
119 | - <Select placeholder="请选择" labelInValue style={{ width: '100%' }} showSearch optionFilterProp="children"> | |
120 | - {allshopData.map((item: CommonApi.OptionVO) => ( | |
121 | - <Option key={item.id} value={item.id}> | |
122 | - {item.name} | |
123 | - </Option> | |
124 | - ))} | |
125 | - </Select> | |
115 | + <ShopSelectNew destroyOnClose type={2} shopIds={allshopData.map((i) => i.id!)} placeholder="请选择" /> | |
126 | 116 | </FormItem> |
127 | 117 | <FormItem name="repairShops" label="送修门店" rules={[{ required: true, message: '送修门店配置不能为空' }]}> |
128 | 118 | <SendToRepairShop shopList={shopList} /> | ... | ... |
src/pages/carinsur/InsuranceShop/components/SendShopModal.tsx
1 | 1 | import React, { useState, useEffect } from 'react'; |
2 | -import { Modal, Skeleton, Table, Select, Form } from 'antd'; | |
2 | +import { Modal, Select, Form } from 'antd'; | |
3 | 3 | import Condition from '../Condition'; |
4 | +import ShopSelectNew from '@/components/ShopSelectNew'; | |
4 | 5 | |
5 | 6 | interface Props { |
6 | 7 | shopList: CommonApi.OptionVO[]; |
... | ... | @@ -26,7 +27,7 @@ export default function Index({ shopList = [], row = {}, value = [], visible = f |
26 | 27 | useEffect(() => { |
27 | 28 | if (Object.keys(row).length) { |
28 | 29 | form.setFieldsValue({ |
29 | - stmtShop: row.stmtShopId && { value: row.stmtShopId, label: row.stmtShopName }, | |
30 | + stmtShop: row.stmtShopId ? [{ value: row.stmtShopId, label: row.stmtShopName }] : undefined, | |
30 | 31 | key: row.key && row.key, |
31 | 32 | }); |
32 | 33 | } |
... | ... | @@ -52,8 +53,8 @@ export default function Index({ shopList = [], row = {}, value = [], visible = f |
52 | 53 | let list = [] as InsurType.repairStmtShopList[]; |
53 | 54 | if (!key) { |
54 | 55 | const tableItem = { |
55 | - stmtShopId: stmtShop.value, | |
56 | - stmtShopName: stmtShop.label, | |
56 | + stmtShopId: stmtShop[0].value, | |
57 | + stmtShopName: stmtShop[0].label, | |
57 | 58 | brandId: brand.id, |
58 | 59 | brandName: brand.name, |
59 | 60 | key: value.length + 1, |
... | ... | @@ -63,8 +64,8 @@ export default function Index({ shopList = [], row = {}, value = [], visible = f |
63 | 64 | list = value.map((it) => { |
64 | 65 | if (it.key === key) { |
65 | 66 | return { |
66 | - stmtShopId: stmtShop.value, | |
67 | - stmtShopName: stmtShop.label, | |
67 | + stmtShopId: stmtShop[0].value, | |
68 | + stmtShopName: stmtShop[0].label, | |
68 | 69 | brandId: brand.id, |
69 | 70 | brandName: brand.name, |
70 | 71 | key, |
... | ... | @@ -88,21 +89,7 @@ export default function Index({ shopList = [], row = {}, value = [], visible = f |
88 | 89 | <Form form={form} labelCol={{ span: '6' }} onFinish={handleItemSave}> |
89 | 90 | <Condition form={form} value={carValue} brandLabelInValue brandShow /> |
90 | 91 | <FormItem label="送修结算门店" name="stmtShop" rules={[{ required: true, message: '该选项为必填项' }]}> |
91 | - <Select | |
92 | - showSearch | |
93 | - filterOption={(input, option: any) => option?.children.indexOf(input) >= 0} | |
94 | - placeholder="请选择" | |
95 | - labelInValue | |
96 | - style={{ width: '100%' }} | |
97 | - > | |
98 | - {shopList | |
99 | - .filter((i) => i.bizType === 2) | |
100 | - .map((item: CommonApi.OptionVO) => ( | |
101 | - <Option key={item.id} value={item.id}> | |
102 | - {item.name} | |
103 | - </Option> | |
104 | - ))} | |
105 | - </Select> | |
92 | + <ShopSelectNew destroyOnClose type={2} shopIds={shopList.filter((i) => i.bizType === 2).map((i) => i.id!)} placeholder="请选择" /> | |
106 | 93 | </FormItem> |
107 | 94 | <FormItem name="key" /> |
108 | 95 | </Form> | ... | ... |
src/pages/carinsur/InsuranceShop/components/ShopModal.tsx
1 | -import React, { useState, useEffect } from 'react'; | |
2 | -import { Modal, Skeleton, Table, Select, Form } from 'antd'; | |
3 | -import Condition from '@/components/Condition'; | |
1 | +import React, { useEffect } from 'react'; | |
2 | +import { Modal, Select, Form } from 'antd'; | |
4 | 3 | import SendToRepairCloseShop from './SendToRepairCloseShop'; |
4 | +import ShopSelectNew from '@/components/ShopSelectNew'; | |
5 | 5 | |
6 | 6 | interface Props { |
7 | 7 | visible: boolean; |
... | ... | @@ -25,7 +25,7 @@ function ShopModal({ visible, shopList, value = [], row = {}, onChange, setVisib |
25 | 25 | useEffect(() => { |
26 | 26 | if (Object.keys(row).length) { |
27 | 27 | form.setFieldsValue({ |
28 | - repairShop: row.shopId && { value: row.shopId, label: row.shopName }, | |
28 | + repairShop: row.shopId ? [{ value: row.shopId, label: row.shopName }] : undefined, | |
29 | 29 | repairStmtShopList: row.repairStmtShopList ? row.repairStmtShopList.map((i, index) => ({ ...i, key: index + 1 })) : [], |
30 | 30 | key: row.key && row.key, |
31 | 31 | }); |
... | ... | @@ -47,8 +47,8 @@ function ShopModal({ visible, shopList, value = [], row = {}, onChange, setVisib |
47 | 47 | let list = [] as InsurType.sendToRepairShopTableList[]; |
48 | 48 | if (!key) { |
49 | 49 | const tableItem = { |
50 | - shopId: repairShop.value, | |
51 | - shopName: repairShop.label, | |
50 | + shopId: repairShop[0].value, | |
51 | + shopName: repairShop[0].label, | |
52 | 52 | repairStmtShopList, |
53 | 53 | key: value.length + 1, |
54 | 54 | }; |
... | ... | @@ -57,8 +57,8 @@ function ShopModal({ visible, shopList, value = [], row = {}, onChange, setVisib |
57 | 57 | list = value.map((it) => { |
58 | 58 | if (it.key === key) { |
59 | 59 | return { |
60 | - shopId: repairShop.value, | |
61 | - shopName: repairShop.label, | |
60 | + shopId: repairShop[0].value, | |
61 | + shopName: repairShop[0].label, | |
62 | 62 | repairStmtShopList, |
63 | 63 | key, |
64 | 64 | }; |
... | ... | @@ -81,21 +81,7 @@ function ShopModal({ visible, shopList, value = [], row = {}, onChange, setVisib |
81 | 81 | > |
82 | 82 | <Form form={form} labelCol={{ span: '6' }} onFinish={handleItemSave}> |
83 | 83 | <FormItem label="送修门店" name="repairShop" rules={[{ required: true, message: '该选项为必填项' }]}> |
84 | - <Select | |
85 | - showSearch | |
86 | - filterOption={(input, option: any) => option?.children.indexOf(input) >= 0} | |
87 | - placeholder="请选择" | |
88 | - labelInValue | |
89 | - style={{ width: '100%' }} | |
90 | - > | |
91 | - {shopList | |
92 | - .filter((i) => i.bizType === 2) | |
93 | - .map((item: CommonApi.OptionVO) => ( | |
94 | - <Option key={item.id} value={item.id}> | |
95 | - {item.name} | |
96 | - </Option> | |
97 | - ))} | |
98 | - </Select> | |
84 | + <ShopSelectNew destroyOnClose type={2} shopIds={shopList.filter((i) => i.bizType === 2).map((i) => i.id!)} placeholder="请选择" /> | |
99 | 85 | </FormItem> |
100 | 86 | <FormItem label="送修结算门店" name="repairStmtShopList" rules={[{ required: true, message: '该选项为必填项' }]}> |
101 | 87 | <SendToRepairCloseShop shopList={shopList} /> | ... | ... |
src/pages/carinsur/InsuranceShopNewMultiple/Condition/index.tsx
... | ... | @@ -74,7 +74,7 @@ export default function Condition(props: Props) { |
74 | 74 | useEffect(() => { |
75 | 75 | value.brandId != currentBrandId && setCurrentBrandId(value.brandId); |
76 | 76 | form.setFieldsValue({ |
77 | - brand: brandLabelInValue && value.brandId ? { brandId: value.brandId, brandName: value.brandName } : value.brandId, | |
77 | + brand: brandLabelInValue && value.brandId ? { id: value.brandId, name: value.brandName } : value.brandId, | |
78 | 78 | joinDealer: value |
79 | 79 | ? { type: value.joinDealerType || 1, selected: _.compact((value.joinDealerIds || '').split(',').map((item) => Number(item))) } |
80 | 80 | : defaultDealerValue, |
... | ... | @@ -154,7 +154,7 @@ export default function Condition(props: Props) { |
154 | 154 | )} |
155 | 155 | <FormItem noStyle shouldUpdate={(prevValues, currentValues) => prevValues.brand != currentValues.brand}> |
156 | 156 | {({ getFieldValue }): any => { |
157 | - const brandId = (brandLabelInValue && getFieldValue('brand') ? getFieldValue('brand').brandId : getFieldValue('brand')) || value.brandId; | |
157 | + const brandId = (brandLabelInValue && getFieldValue('brand') ? getFieldValue('brand').id : getFieldValue('brand')) || value.brandId; | |
158 | 158 | return brandId ? ( |
159 | 159 | <div> |
160 | 160 | {dealerShow && ( | ... | ... |
src/pages/carinsur/InsuranceShopNewMultiple/components/CreateModal.tsx
... | ... | @@ -6,6 +6,8 @@ import { getShopApi } from '@/common/api'; |
6 | 6 | import SendToRepairShop from './SendToRepairShop'; |
7 | 7 | import { getInsurList } from '../../companyConfig/api'; |
8 | 8 | import { useRequest } from 'umi'; |
9 | +import ShopSelectNew from '@/components/ShopSelectNew'; | |
10 | +import _ from 'lodash'; | |
9 | 11 | |
10 | 12 | const FormItem = Form.Item; |
11 | 13 | const Option = Select.Option; |
... | ... | @@ -46,7 +48,7 @@ export default function CreateModal({ onCancel, item = {}, onRrfreshing, visible |
46 | 48 | id: fieldsValue.id, |
47 | 49 | insurerId: fieldsValue.insurerId.value, |
48 | 50 | saleShops: fieldsValue.saleShops.map((item: any) => ({ shopId: item.value, shopName: item.label })), |
49 | - stmtShop: { shopId: fieldsValue.stmtShop.value, shopName: fieldsValue.stmtShop.label }, | |
51 | + stmtShop: { shopId: fieldsValue.stmtShop[0].value, shopName: fieldsValue.stmtShop[0].label }, | |
50 | 52 | repairShops: fieldsValue.repairShops.map((item: any) => { |
51 | 53 | const _item = { ...item }; |
52 | 54 | delete _item.key; |
... | ... | @@ -87,7 +89,7 @@ export default function CreateModal({ onCancel, item = {}, onRrfreshing, visible |
87 | 89 | insurerId: item.insurerId ? { value: item.insurerId, label: item.insurerName } : undefined, |
88 | 90 | repairShops: item.repairShops ? item.repairShops.map((i, index) => ({ ...i, key: index + 1 })) : [], |
89 | 91 | saleShops: item.saleShops ? item.saleShops.map((i) => ({ value: i.shopId, label: i.shopName })) : [], |
90 | - stmtShop: item.stmtShop ? { value: item.stmtShop.shopId, label: item.stmtShop.shopName } : undefined, | |
92 | + stmtShop: !_.isEmpty(item.stmtShop) ? [{ value: item.stmtShop.shopId, label: item.stmtShop.shopName }] : undefined, | |
91 | 93 | }} |
92 | 94 | > |
93 | 95 | <FormItem name="id" hidden /> |
... | ... | @@ -109,32 +111,12 @@ export default function CreateModal({ onCancel, item = {}, onRrfreshing, visible |
109 | 111 | </Select> |
110 | 112 | </FormItem> |
111 | 113 | <FormItem label="出保门店" name="saleShops" rules={[{ required: true, message: '该选项为必填项' }]}> |
112 | - <Select | |
113 | - placeholder="请选择" | |
114 | - labelInValue | |
115 | - mode="multiple" | |
116 | - style={{ width: '100%' }} | |
117 | - loading={getShopApiHook.loading} | |
118 | - showSearch | |
119 | - optionFilterProp="children" | |
120 | - > | |
121 | - {(getShopApiHook.data ?? []).map((item: CommonApi.OptionVO) => ( | |
122 | - <Option key={item.id} value={item.id}> | |
123 | - {item.name} | |
124 | - </Option> | |
125 | - ))} | |
126 | - </Select> | |
114 | + <ShopSelectNew destroyOnClose multiple type={2} shopIds={(getShopApiHook.data ?? []).map((i) => i.id!)} placeholder="请选择" /> | |
127 | 115 | </FormItem> |
128 | 116 | <FormItem label="返利结算门店" name="stmtShop" rules={[{ required: true, message: '该选项为必填项' }]}> |
129 | - <Select placeholder="请选择" labelInValue style={{ width: '100%' }} loading={getShopApiHook.loading} showSearch optionFilterProp="children"> | |
130 | - {(getShopApiHook.data ?? []).map((item: CommonApi.OptionVO) => ( | |
131 | - <Option key={item.id} value={item.id}> | |
132 | - {item.name} | |
133 | - </Option> | |
134 | - ))} | |
135 | - </Select> | |
117 | + <ShopSelectNew destroyOnClose type={2} shopIds={(getShopApiHook.data ?? []).map((i) => i.id!)} placeholder="请选择" /> | |
136 | 118 | </FormItem> |
137 | - <FormItem name="repairShops" label="送修门店" rules={[{ required: true, message: '送修门店配置不能为空' }]}> | |
119 | + <FormItem label="送修门店" name="repairShops" rules={[{ required: true, message: '送修门店配置不能为空' }]}> | |
138 | 120 | <SendToRepairShop shopList={getShopApiHook.data ?? []} /> |
139 | 121 | </FormItem> |
140 | 122 | </Form> | ... | ... |
src/pages/carinsur/InsuranceShopNewMultiple/components/SendShopModal.tsx
1 | 1 | import React, { useState, useEffect } from 'react'; |
2 | -import { Modal, Select, Form } from 'antd'; | |
2 | +import { Modal, Form } from 'antd'; | |
3 | 3 | import Condition from '../Condition'; |
4 | +import ShopSelectNew from '@/components/ShopSelectNew'; | |
4 | 5 | |
5 | 6 | interface Props { |
6 | 7 | shopList: CommonApi.OptionVO[]; |
... | ... | @@ -12,7 +13,6 @@ interface Props { |
12 | 13 | } |
13 | 14 | |
14 | 15 | const FormItem = Form.Item; |
15 | -const Option = Select.Option; | |
16 | 16 | |
17 | 17 | export default function Index({ shopList = [], row = {}, value = [], visible = false, setVisible, onChange }: Props) { |
18 | 18 | const [form] = Form.useForm(); |
... | ... | @@ -26,7 +26,7 @@ export default function Index({ shopList = [], row = {}, value = [], visible = f |
26 | 26 | useEffect(() => { |
27 | 27 | if (Object.keys(row).length) { |
28 | 28 | form.setFieldsValue({ |
29 | - stmtShop: row.stmtShopId && { value: row.stmtShopId, label: row.stmtShopName }, | |
29 | + stmtShop: row.stmtShopId ? [{ value: row.stmtShopId, label: row.stmtShopName }] : undefined, | |
30 | 30 | key: row.key && row.key, |
31 | 31 | }); |
32 | 32 | } |
... | ... | @@ -52,8 +52,8 @@ export default function Index({ shopList = [], row = {}, value = [], visible = f |
52 | 52 | let list = [] as InsurType.repairStmtShopList[]; |
53 | 53 | if (!key) { |
54 | 54 | const tableItem = { |
55 | - stmtShopId: stmtShop.value, | |
56 | - stmtShopName: stmtShop.label, | |
55 | + stmtShopId: stmtShop[0].value, | |
56 | + stmtShopName: stmtShop[0].label, | |
57 | 57 | brandId: brand.id, |
58 | 58 | brandName: brand.name, |
59 | 59 | key: value.length + 1, |
... | ... | @@ -63,8 +63,8 @@ export default function Index({ shopList = [], row = {}, value = [], visible = f |
63 | 63 | list = value.map((it) => { |
64 | 64 | if (it.key === key) { |
65 | 65 | return { |
66 | - stmtShopId: stmtShop.value, | |
67 | - stmtShopName: stmtShop.label, | |
66 | + stmtShopId: stmtShop[0].value, | |
67 | + stmtShopName: stmtShop[0].label, | |
68 | 68 | brandId: brand.id, |
69 | 69 | brandName: brand.name, |
70 | 70 | key, |
... | ... | @@ -88,21 +88,7 @@ export default function Index({ shopList = [], row = {}, value = [], visible = f |
88 | 88 | <Form form={form} labelCol={{ span: '6' }} onFinish={handleItemSave}> |
89 | 89 | <Condition form={form} value={carValue} brandLabelInValue brandShow /> |
90 | 90 | <FormItem label="送修结算门店" name="stmtShop" rules={[{ required: true, message: '该选项为必填项' }]}> |
91 | - <Select | |
92 | - showSearch | |
93 | - filterOption={(input, option: any) => option?.children.indexOf(input) >= 0} | |
94 | - placeholder="请选择" | |
95 | - labelInValue | |
96 | - style={{ width: '100%' }} | |
97 | - > | |
98 | - {shopList | |
99 | - .filter((i) => i.bizType === 2) | |
100 | - .map((item: CommonApi.OptionVO) => ( | |
101 | - <Option key={item.id} value={item.id}> | |
102 | - {item.name} | |
103 | - </Option> | |
104 | - ))} | |
105 | - </Select> | |
91 | + <ShopSelectNew destroyOnClose type={2} shopIds={(shopList ?? []).filter((i) => i.bizType === 2).map((i) => i.id!)} placeholder="请选择" /> | |
106 | 92 | </FormItem> |
107 | 93 | <FormItem name="key" /> |
108 | 94 | </Form> | ... | ... |
src/pages/carinsur/InsuranceShopNewMultiple/components/ShopModal.tsx
1 | 1 | import React, { useEffect } from 'react'; |
2 | -import { Modal, Select, Form } from 'antd'; | |
2 | +import { Modal, Form } from 'antd'; | |
3 | 3 | import SendToRepairCloseShop from './SendToRepairCloseShop'; |
4 | +import ShopSelectNew from '@/components/ShopSelectNew'; | |
4 | 5 | |
5 | 6 | interface Props { |
6 | 7 | visible: boolean; |
... | ... | @@ -11,7 +12,6 @@ interface Props { |
11 | 12 | onChange?: (data: InsurType.sendToRepairShopTableList[]) => void; |
12 | 13 | } |
13 | 14 | const FormItem = Form.Item; |
14 | -const Option = Select.Option; | |
15 | 15 | |
16 | 16 | function ShopModal({ visible, shopList, value = [], row = {}, onChange, setVisible }: Props) { |
17 | 17 | const [form] = Form.useForm(); |
... | ... | @@ -24,7 +24,7 @@ function ShopModal({ visible, shopList, value = [], row = {}, onChange, setVisib |
24 | 24 | useEffect(() => { |
25 | 25 | if (Object.keys(row).length) { |
26 | 26 | form.setFieldsValue({ |
27 | - repairShop: row.shopId && { value: row.shopId, label: row.shopName }, | |
27 | + repairShop: row.shopId ? [{ value: row.shopId, label: row.shopName }] : undefined, | |
28 | 28 | repairStmtShopList: row.repairStmtShopList ? row.repairStmtShopList.map((i, index) => ({ ...i, key: index + 1 })) : [], |
29 | 29 | key: row.key && row.key, |
30 | 30 | }); |
... | ... | @@ -46,8 +46,8 @@ function ShopModal({ visible, shopList, value = [], row = {}, onChange, setVisib |
46 | 46 | let list = [] as InsurType.sendToRepairShopTableList[]; |
47 | 47 | if (!key) { |
48 | 48 | const tableItem = { |
49 | - shopId: repairShop.value, | |
50 | - shopName: repairShop.label, | |
49 | + shopId: repairShop[0].value, | |
50 | + shopName: repairShop[0].label, | |
51 | 51 | repairStmtShopList, |
52 | 52 | key: value.length + 1, |
53 | 53 | }; |
... | ... | @@ -56,8 +56,8 @@ function ShopModal({ visible, shopList, value = [], row = {}, onChange, setVisib |
56 | 56 | list = value.map((it) => { |
57 | 57 | if (it.key === key) { |
58 | 58 | return { |
59 | - shopId: repairShop.value, | |
60 | - shopName: repairShop.label, | |
59 | + shopId: repairShop[0].value, | |
60 | + shopName: repairShop[0].label, | |
61 | 61 | repairStmtShopList, |
62 | 62 | key, |
63 | 63 | }; |
... | ... | @@ -80,21 +80,7 @@ function ShopModal({ visible, shopList, value = [], row = {}, onChange, setVisib |
80 | 80 | > |
81 | 81 | <Form form={form} labelCol={{ span: '6' }} onFinish={handleItemSave}> |
82 | 82 | <FormItem label="送修门店" name="repairShop" rules={[{ required: true, message: '该选项为必填项' }]}> |
83 | - <Select | |
84 | - showSearch | |
85 | - filterOption={(input, option: any) => option?.children.indexOf(input) >= 0} | |
86 | - placeholder="请选择" | |
87 | - labelInValue | |
88 | - style={{ width: '100%' }} | |
89 | - > | |
90 | - {shopList | |
91 | - .filter((i) => i.bizType === 2) | |
92 | - .map((item: CommonApi.OptionVO) => ( | |
93 | - <Option key={item.id} value={item.id}> | |
94 | - {item.name} | |
95 | - </Option> | |
96 | - ))} | |
97 | - </Select> | |
83 | + <ShopSelectNew destroyOnClose type={2} shopIds={(shopList ?? []).filter((i) => i.bizType === 2).map((i) => i.id!)} placeholder="请选择" /> | |
98 | 84 | </FormItem> |
99 | 85 | <FormItem label="送修结算门店" name="repairStmtShopList" rules={[{ required: true, message: '该选项为必填项' }]}> |
100 | 86 | <SendToRepairCloseShop shopList={shopList} /> | ... | ... |
src/pages/carinsur/companyConfig/components/CreateModal.tsx
... | ... | @@ -12,7 +12,6 @@ interface Props { |
12 | 12 | onCancel: Function; |
13 | 13 | onRrfreshing: () => any; |
14 | 14 | visible: boolean; |
15 | - brands: string[]; | |
16 | 15 | } |
17 | 16 | |
18 | 17 | const formItemLayout = { |
... | ... | @@ -32,7 +31,7 @@ const formItemLayoutWithOutLabel = { |
32 | 31 | }, |
33 | 32 | }; |
34 | 33 | |
35 | -export default function Create({ onCancel, item, brands, onRrfreshing, visible }: Props) { | |
34 | +export default function Create({ onCancel, item, onRrfreshing, visible }: Props) { | |
36 | 35 | const [form] = Form.useForm(); |
37 | 36 | const [firmLoading, setFirmLoading] = useState(false); |
38 | 37 | const [loading, setLoading] = useState(false); |
... | ... | @@ -47,7 +46,6 @@ export default function Create({ onCancel, item, brands, onRrfreshing, visible } |
47 | 46 | if (!visible) { |
48 | 47 | form.setFieldsValue({ |
49 | 48 | name: undefined, |
50 | - brand: '', | |
51 | 49 | }); |
52 | 50 | } |
53 | 51 | }, [visible]); |
... | ... | @@ -75,7 +73,7 @@ export default function Create({ onCancel, item, brands, onRrfreshing, visible } |
75 | 73 | }; |
76 | 74 | setFirmLoading(true); |
77 | 75 | saveInsur(params) |
78 | - .then((res) => { | |
76 | + .then(() => { | |
79 | 77 | message.success('操作成功'); |
80 | 78 | onRrfreshing && onRrfreshing(); |
81 | 79 | setFirmLoading(false); |
... | ... | @@ -123,15 +121,6 @@ export default function Create({ onCancel, item, brands, onRrfreshing, visible } |
123 | 121 | ))} |
124 | 122 | </Select> |
125 | 123 | </FormItem> |
126 | - <FormItem label="类型" name="brand" rules={[{ required: true, message: '该选项为必填项' }]}> | |
127 | - <Select placeholder="请选择类型" showSearch optionFilterProp="children"> | |
128 | - {brands.map((item: string, index) => ( | |
129 | - <Select.Option key={index} value={item}> | |
130 | - {item} | |
131 | - </Select.Option> | |
132 | - ))} | |
133 | - </Select> | |
134 | - </FormItem> | |
135 | 124 | <FormItem label="送修差额是否包含驾意险" name="repairMarginContainsDai" rules={[{ required: true, message: '该选项为必选项' }]}> |
136 | 125 | <RadioGroup |
137 | 126 | options={[ |
... | ... | @@ -148,57 +137,72 @@ export default function Create({ onCancel, item, brands, onRrfreshing, visible } |
148 | 137 | ]} |
149 | 138 | /> |
150 | 139 | </FormItem> |
151 | - <Form.List | |
152 | - name="orderInsurerNames" | |
153 | - rules={[ | |
154 | - { | |
155 | - validator: async (_: any, names: any) => { | |
156 | - if (!names || names.length < 1) { | |
157 | - return Promise.reject(new Error('至少配置一个保险公司名称')); | |
158 | - } | |
159 | - }, | |
160 | - }, | |
161 | - ]} | |
140 | + <FormItem | |
141 | + noStyle | |
142 | + shouldUpdate={(prev, curr) => { | |
143 | + if (prev.id !== curr.id) { | |
144 | + const insurName = form.getFieldValue('id') ? form.getFieldValue('id').label : ''; | |
145 | + form.setFieldValue('orderInsurerNames', [insurName]); | |
146 | + } | |
147 | + return prev.id !== curr.id; | |
148 | + }} | |
162 | 149 | > |
163 | - {(fields, { add, remove }, { errors }) => ( | |
164 | - <> | |
165 | - {fields.map((field, index) => ( | |
166 | - <Form.Item | |
167 | - {...(index === 0 ? formItemLayout : formItemLayoutWithOutLabel)} | |
168 | - label={index === 0 ? '保单上保险公司名称' : ''} | |
169 | - required | |
170 | - key={field.key} | |
171 | - > | |
172 | - <Form.Item | |
173 | - {...field} | |
174 | - validateTrigger={['onChange', 'onBlur']} | |
175 | - rules={[ | |
176 | - { | |
177 | - required: true, | |
178 | - whitespace: true, | |
179 | - message: '请输入', | |
180 | - }, | |
181 | - ]} | |
182 | - noStyle | |
183 | - > | |
184 | - <Input placeholder="请输入保单上保险公司名称" allowClear style={{ width: '80%' }} /> | |
185 | - </Form.Item> | |
186 | - {fields.length > 1 ? <MinusCircleOutlined style={{ marginLeft: 10 }} onClick={() => remove(field.name)} /> : null} | |
187 | - </Form.Item> | |
188 | - ))} | |
189 | - <Row justify="center"> | |
190 | - <Button icon={<PlusOutlined />} style={{ width: '50%' }} type="dashed" onClick={() => add()}> | |
191 | - 添加保单上保险公司名称 | |
192 | - </Button> | |
193 | - </Row> | |
194 | - {errors.length > 0 && ( | |
195 | - <Form.Item {...formItemLayoutWithOutLabel} style={{ marginBottom: 0 }}> | |
196 | - <Form.ErrorList errors={errors} /> | |
197 | - </Form.Item> | |
198 | - )} | |
199 | - </> | |
200 | - )} | |
201 | - </Form.List> | |
150 | + {() => { | |
151 | + return ( | |
152 | + <Form.List | |
153 | + name="orderInsurerNames" | |
154 | + rules={[ | |
155 | + { | |
156 | + validator: async (_: any, names: any) => { | |
157 | + if (!names || names.length < 1) { | |
158 | + return Promise.reject(new Error('至少配置一个保险公司名称')); | |
159 | + } | |
160 | + }, | |
161 | + }, | |
162 | + ]} | |
163 | + > | |
164 | + {(fields, { add, remove }, { errors }) => ( | |
165 | + <> | |
166 | + {fields.map((field, index) => ( | |
167 | + <Form.Item | |
168 | + {...(index === 0 ? formItemLayout : formItemLayoutWithOutLabel)} | |
169 | + label={index === 0 ? '保单上保险公司名称' : ''} | |
170 | + required | |
171 | + key={field.key} | |
172 | + > | |
173 | + <Form.Item | |
174 | + {...field} | |
175 | + validateTrigger={['onChange', 'onBlur']} | |
176 | + rules={[ | |
177 | + { | |
178 | + required: true, | |
179 | + whitespace: true, | |
180 | + message: '请输入', | |
181 | + }, | |
182 | + ]} | |
183 | + noStyle | |
184 | + > | |
185 | + <Input placeholder="请输入保单上保险公司名称" allowClear style={{ width: '80%' }} /> | |
186 | + </Form.Item> | |
187 | + {fields.length > 1 ? <MinusCircleOutlined style={{ marginLeft: 10 }} onClick={() => remove(field.name)} /> : null} | |
188 | + </Form.Item> | |
189 | + ))} | |
190 | + <Row justify="center"> | |
191 | + <Button icon={<PlusOutlined />} style={{ width: '50%' }} type="dashed" onClick={() => add()}> | |
192 | + 添加保单上保险公司名称 | |
193 | + </Button> | |
194 | + </Row> | |
195 | + {errors.length > 0 && ( | |
196 | + <Form.Item {...formItemLayoutWithOutLabel} style={{ marginBottom: 0 }}> | |
197 | + <Form.ErrorList errors={errors} /> | |
198 | + </Form.Item> | |
199 | + )} | |
200 | + </> | |
201 | + )} | |
202 | + </Form.List> | |
203 | + ); | |
204 | + }} | |
205 | + </FormItem> | |
202 | 206 | </Form> |
203 | 207 | </Spin> |
204 | 208 | </Modal> | ... | ... |
src/pages/carinsur/companyConfig/index.tsx
... | ... | @@ -2,13 +2,12 @@ import React, { useState } from 'react'; |
2 | 2 | import zhCN from 'antd/lib/locale-provider/zh_CN'; |
3 | 3 | import { PageHeaderWrapper } from '@ant-design/pro-layout'; |
4 | 4 | import { PlusOutlined } from '@ant-design/icons'; |
5 | -import { Button, Card, Popconfirm, Row, Divider, Select, Table, ConfigProvider, message } from 'antd'; | |
5 | +import { Button, Card, Popconfirm, Row, Divider, Table, ConfigProvider, message } from 'antd'; | |
6 | 6 | import CreateModal from './components/CreateModal'; |
7 | 7 | import usePagination from '@/hooks/usePagination'; |
8 | 8 | import Search from 'antd/lib/input/Search'; |
9 | 9 | import * as api from './api'; |
10 | 10 | import debounce from 'lodash/debounce'; |
11 | -import useInitial from '@/hooks/useInitail'; | |
12 | 11 | import TextWithMore from '@/components/TextWithMore'; |
13 | 12 | |
14 | 13 | const indexS = require('./index.less'); |
... | ... | @@ -19,7 +18,6 @@ export default function WorkStationIndex() { |
19 | 18 | const [visible, setVisible] = useState(false); |
20 | 19 | const [item, setItem] = useState<ComInsur.ItemList>({}); |
21 | 20 | const { loading, setLoading, list, setParams, paginationConfig } = usePagination(api.getInsurList, {}); |
22 | - const { data: brands } = useInitial(api.getTypeList, [], {}); | |
23 | 21 | |
24 | 22 | function deleteData(id?: number) { |
25 | 23 | api |
... | ... | @@ -49,21 +47,6 @@ export default function WorkStationIndex() { |
49 | 47 | style={{ width: 250, marginRight: 20 }} |
50 | 48 | onChange={(e) => _onChange({ name: e.target.value })} |
51 | 49 | /> |
52 | - <Select | |
53 | - allowClear | |
54 | - placeholder="类型" | |
55 | - style={{ width: 250 }} | |
56 | - onChange={(value) => _onChange({ brand: value })} | |
57 | - showSearch | |
58 | - optionFilterProp="children" | |
59 | - > | |
60 | - {brands.length > 0 && | |
61 | - brands.map((item: string, index) => ( | |
62 | - <Select.Option key={index} value={item}> | |
63 | - {item} | |
64 | - </Select.Option> | |
65 | - ))} | |
66 | - </Select> | |
67 | 50 | </Row> |
68 | 51 | <Button |
69 | 52 | icon={<PlusOutlined />} |
... | ... | @@ -85,7 +68,6 @@ export default function WorkStationIndex() { |
85 | 68 | <TextWithMore title="保单上保险公司名称" dataIndex="companyName" list={names.map((i) => ({ companyName: i }))} unit="个名称" /> |
86 | 69 | )} |
87 | 70 | /> |
88 | - <Column width="8%" title="类型" dataIndex="brand" /> | |
89 | 71 | <Column |
90 | 72 | width="10%" |
91 | 73 | title="送修差额是否包含驾意险" |
... | ... | @@ -125,7 +107,6 @@ export default function WorkStationIndex() { |
125 | 107 | </Card> |
126 | 108 | <CreateModal |
127 | 109 | visible={visible} |
128 | - brands={brands} | |
129 | 110 | item={item} |
130 | 111 | onCancel={() => setVisible(false)} |
131 | 112 | onRrfreshing={() => { | ... | ... |
src/pages/carinsur/companyConfig/interface.d.ts
src/pages/carinsur/insureSaleconfig/components/CreateModal.tsx
... | ... | @@ -63,10 +63,17 @@ export default function CreateModal({ onCancel, record, onRrfreshing, visible }: |
63 | 63 | } |
64 | 64 | |
65 | 65 | return ( |
66 | - <Modal visible={visible} title={record.insurerId ? '编辑' : '新增'} onOk={handleOk} onCancel={() => onCancel()} confirmLoading={firmLoading}> | |
66 | + <Modal | |
67 | + width={700} | |
68 | + open={visible} | |
69 | + title={record.insurerId ? '编辑' : '新增'} | |
70 | + onOk={handleOk} | |
71 | + onCancel={() => onCancel()} | |
72 | + confirmLoading={firmLoading} | |
73 | + > | |
67 | 74 | <Form |
68 | - labelCol={{ span: 8 }} | |
69 | - wrapperCol={{ span: 12 }} | |
75 | + labelCol={{ span: 6 }} | |
76 | + wrapperCol={{ span: 18 }} | |
70 | 77 | form={form} |
71 | 78 | onFinish={handleOk} |
72 | 79 | initialValues={{ | ... | ... |
src/pages/coupon/CouponConfig/components/WareLimitType/VehicleLimit.tsx
0 → 100644
1 | +import React, { useEffect, useState } from 'react'; | |
2 | +import { Button, Popconfirm, Card, Table, Modal, Form, Select, Space, message, Radio, Tag } from 'antd'; | |
3 | +import * as api from '../../api'; | |
4 | +import TextWithMore from '@/components/TextWithMore'; | |
5 | +import SelectorWithFull from '@/components/SelectorWithFull'; | |
6 | +interface Props { | |
7 | + onChange?: (value: any[]) => any; | |
8 | + form: any; | |
9 | + value?: any; | |
10 | + readonly: boolean; | |
11 | + carSelectApi?: Function; | |
12 | +} | |
13 | + | |
14 | +interface Item { | |
15 | + label: string; | |
16 | + value: number; | |
17 | + key?: number; | |
18 | +} | |
19 | +const { Column } = Table; | |
20 | +const { Option } = Select; | |
21 | + | |
22 | +export default function Index({ onChange, value, readonly, carSelectApi }: Props) { | |
23 | + const [form] = Form.useForm(); | |
24 | + // 控制Modal是否可见 | |
25 | + const [visible, setVisible] = useState<boolean>(false); | |
26 | + //存储表格当前编辑项数据 | |
27 | + const [currentItem, setCurrentItem] = useState<any>({}); | |
28 | + //存储Modal中可选的车系 | |
29 | + const [series, setSeries] = useState<any>([]); | |
30 | + //存储接口返回的车型 | |
31 | + const [specList, setSpecList] = useState<any>([]); | |
32 | + //存储Modal选择的品牌和车系作为表格的数据源 | |
33 | + const [savaData, setSavadata] = useState<any>([]); | |
34 | + /**车型类型是否允许编辑 */ | |
35 | + const [authType, setAuthType] = useState<boolean>(); | |
36 | + | |
37 | + useEffect(() => { | |
38 | + if (value && value.length) { | |
39 | + setSavadata([...value]); | |
40 | + } | |
41 | + }, [value]); | |
42 | + | |
43 | + const [carList, setCarList] = useState<any[]>([]); | |
44 | + | |
45 | + useEffect(() => { | |
46 | + async function fetchData() { | |
47 | + try { | |
48 | + const queryApi = carSelectApi || api.getSpecTree; | |
49 | + const { data = [] } = await queryApi(); | |
50 | + setCarList(data); | |
51 | + } catch (e) { | |
52 | + message.error(e.message); | |
53 | + } | |
54 | + } | |
55 | + fetchData(); | |
56 | + }, []); | |
57 | + | |
58 | + const _onOk = () => { | |
59 | + form | |
60 | + .validateFields() | |
61 | + .then((fileds) => { | |
62 | + const { brand, series, spec, type } = fileds; | |
63 | + const _specs = | |
64 | + spec && | |
65 | + spec.map((item: Item) => ({ | |
66 | + specId: item.value, | |
67 | + specName: item.label, | |
68 | + })); | |
69 | + const params = { | |
70 | + brandId: brand.value, | |
71 | + brandName: brand.label, | |
72 | + seriesId: series.value, | |
73 | + seriesName: series.label, | |
74 | + spec: _specs, | |
75 | + authType: type, | |
76 | + }; | |
77 | + // 编辑 | |
78 | + if (savaData.some((i) => i.seriesId === series.value)) { | |
79 | + const tempData = savaData.map((item: any) => (item.seriesId === currentItem.seriesId ? params : item)); | |
80 | + setSavadata([...tempData]); | |
81 | + onChange && onChange(tempData); | |
82 | + } else { | |
83 | + const newData = savaData.concat(params); | |
84 | + setSavadata([...newData]); | |
85 | + onChange && onChange(newData); | |
86 | + } | |
87 | + setVisible(false); | |
88 | + }) | |
89 | + .catch((err) => console.log(err.message)); | |
90 | + }; | |
91 | + | |
92 | + // 选择部分车辆表格==》删除车系 | |
93 | + const onDelete = (record: any) => { | |
94 | + const _savaData = savaData.filter((item: any) => item.seriesId != record.seriesId); | |
95 | + setSavadata([..._savaData]); | |
96 | + onChange && onChange(_savaData); | |
97 | + }; | |
98 | + | |
99 | + // 编辑车辆 | |
100 | + const onSelectSpec = async (record: any) => { | |
101 | + form.setFieldsValue({ | |
102 | + ...record, | |
103 | + brand: { value: record.brandId, label: record.brandName }, | |
104 | + series: { value: record.seriesId, label: record.seriesName }, | |
105 | + spec: record.spec && record.spec.map((i) => ({ value: i.specId, label: i.specName })), | |
106 | + type: Number(!!record.authType), | |
107 | + }); | |
108 | + const currentBrands = carList.filter((item: { value: number }) => item.value == record.brandId); | |
109 | + const tempData = currentBrands.length ? currentBrands[0].children.filter((item: { value: number }) => item.value == record.seriesId) : []; | |
110 | + const currentSpec = tempData.length ? tempData[0].children : []; | |
111 | + setSpecList(currentSpec); | |
112 | + setAuthType(tempData[0] && tempData[0].all != null ? !!tempData[0].all : true); | |
113 | + setCurrentItem(record); | |
114 | + setVisible(true); | |
115 | + }; | |
116 | + | |
117 | + return ( | |
118 | + <> | |
119 | + <Card> | |
120 | + <div style={{ display: 'flex', justifyContent: 'flex-end' }}> | |
121 | + {!readonly && ( | |
122 | + <Button | |
123 | + type="link" | |
124 | + disabled={readonly} | |
125 | + onClick={() => { | |
126 | + setVisible(true); | |
127 | + form.resetFields(); | |
128 | + }} | |
129 | + > | |
130 | + 新增 | |
131 | + </Button> | |
132 | + )} | |
133 | + </div> | |
134 | + | |
135 | + <Table dataSource={value} rowKey={(record) => String(record.seriesId)} bordered> | |
136 | + <Column | |
137 | + title="品牌" | |
138 | + dataIndex="brandName" | |
139 | + key="brandName" | |
140 | + filters={carList.map((item) => ({ | |
141 | + text: item.name, | |
142 | + value: item.value, | |
143 | + }))} | |
144 | + onFilter={(value, record: any) => { | |
145 | + return record.brandName.indexOf(value) === 0; | |
146 | + }} | |
147 | + /> | |
148 | + <Column title="车系" dataIndex="seriesName" key="seriesName" /> | |
149 | + <Column | |
150 | + title="车型" | |
151 | + dataIndex="spec" | |
152 | + key="spec" | |
153 | + render={(_, record: any) => | |
154 | + record.spec && record.spec.length ? ( | |
155 | + <TextWithMore title="车型" dataIndex="specName" list={record.spec} /> | |
156 | + ) : ( | |
157 | + <Tag>全部车型</Tag> | |
158 | + ) | |
159 | + } | |
160 | + /> | |
161 | + {!readonly && ( | |
162 | + <Column | |
163 | + title="操作" | |
164 | + key="operation" | |
165 | + render={(_, record) => ( | |
166 | + <Space> | |
167 | + <Button type="link" style={{ padding: 0 }} onClick={() => onSelectSpec(record)}> | |
168 | + 编辑 | |
169 | + </Button> | |
170 | + <Popconfirm title="确定删除?" okText="确定" style={{ padding: 0 }} cancelText="取消" onConfirm={() => onDelete(record)}> | |
171 | + <Button type="link" danger> | |
172 | + 删除 | |
173 | + </Button> | |
174 | + </Popconfirm> | |
175 | + </Space> | |
176 | + )} | |
177 | + /> | |
178 | + )} | |
179 | + </Table> | |
180 | + </Card> | |
181 | + | |
182 | + {/* 选择品牌和车系 */} | |
183 | + <Modal | |
184 | + title="选择车辆" | |
185 | + maskClosable={false} | |
186 | + visible={visible} | |
187 | + onOk={() => form.submit()} | |
188 | + onCancel={() => { | |
189 | + setVisible(false); | |
190 | + }} | |
191 | + afterClose={() => { | |
192 | + form.resetFields(); | |
193 | + setCurrentItem({}); | |
194 | + }} | |
195 | + > | |
196 | + <Form onFinish={_onOk} form={form}> | |
197 | + <Form.Item label="品牌" name="brand" rules={[{ required: true, message: '请选择品牌:' }]}> | |
198 | + <Select | |
199 | + labelInValue | |
200 | + disabled={!!currentItem.brandId} | |
201 | + placeholder="请选择品牌" | |
202 | + onChange={(v) => { | |
203 | + form.resetFields(['series']); | |
204 | + const selectedSeries = savaData.map((item: { seriesId: number }) => item.seriesId); | |
205 | + const tempData = carList?.filter((item) => item.value === v.value); | |
206 | + setSeries(tempData.length ? tempData[0].children.filter((i: any) => !selectedSeries.includes(i.value)) : []); | |
207 | + }} | |
208 | + > | |
209 | + {carList.map((item) => ( | |
210 | + <Option value={item.value} key={item.value}> | |
211 | + {item.label} | |
212 | + </Option> | |
213 | + ))} | |
214 | + </Select> | |
215 | + </Form.Item> | |
216 | + <Form.Item label="车系" name="series" rules={[{ required: true, message: '请选择车系' }]}> | |
217 | + <Select | |
218 | + labelInValue | |
219 | + disabled={!!currentItem.brandId} | |
220 | + placeholder="请选择车系" | |
221 | + allowClear | |
222 | + onChange={(v) => { | |
223 | + form.resetFields(['spec']); | |
224 | + const tempData = series?.filter((item: { value: number }) => item.value === v.value); | |
225 | + const currentSpec = tempData.length ? tempData[0].children : []; | |
226 | + setSpecList(currentSpec); | |
227 | + currentSpec.length && form.setFieldValue('type', Number(tempData[0].all)); | |
228 | + setAuthType(tempData[0].all != null ? !!tempData[0].all : true); | |
229 | + }} | |
230 | + > | |
231 | + {series.map((item: any) => ( | |
232 | + <Option value={item.value} key={item.value}> | |
233 | + {item.label} | |
234 | + </Option> | |
235 | + ))} | |
236 | + </Select> | |
237 | + </Form.Item> | |
238 | + <Form.Item label="车型范围" name="type" rules={[{ required: true, message: '请选择' }]}> | |
239 | + <Radio.Group disabled={readonly || !authType}> | |
240 | + <Radio value={1}>全部</Radio> | |
241 | + <Radio value={0}>部分</Radio> | |
242 | + </Radio.Group> | |
243 | + </Form.Item> | |
244 | + <Form.Item noStyle shouldUpdate={(prevValues, currentValues) => prevValues.type != currentValues.type}> | |
245 | + {({ getFieldValue }): any => { | |
246 | + const type = getFieldValue('type'); | |
247 | + if (!type) { | |
248 | + return ( | |
249 | + <Form.Item label="车型" name="spec" rules={[{ required: true, message: '请选择车型' }]}> | |
250 | + <SelectorWithFull | |
251 | + data={specList} | |
252 | + allowClear | |
253 | + labelInValue | |
254 | + multiple | |
255 | + showSearch | |
256 | + fieldKeyNames={{ keyName: 'value', valueName: 'value', labelName: 'label' }} | |
257 | + treeNodeFilterProp="label" | |
258 | + /> | |
259 | + </Form.Item> | |
260 | + ); | |
261 | + } | |
262 | + }} | |
263 | + </Form.Item> | |
264 | + </Form> | |
265 | + </Modal> | |
266 | + </> | |
267 | + ); | |
268 | +} | ... | ... |
src/pages/coupon/CouponConfig/components/WareLimitType/index.tsx
... | ... | @@ -2,6 +2,7 @@ import React, { useState } from 'react'; |
2 | 2 | import { Form, Input, Radio, Space } from 'antd'; |
3 | 3 | import PartItem from '../UsesceneItems/PartLimit'; |
4 | 4 | import SpecLimit from './SpecLimit'; |
5 | +import VehicleLimit from './VehicleLimit'; | |
5 | 6 | import VinLimit from './VinLimit'; |
6 | 7 | import CarCodeLimit from './CarCodeLimit'; |
7 | 8 | import DecorationPart from './decorationPart'; |
... | ... | @@ -32,7 +33,8 @@ const WareLimitType = (props: Props) => { |
32 | 33 | switch (key) { |
33 | 34 | case '1': |
34 | 35 | if (limitType == LimitTypeEnum['限制']) { |
35 | - return <SpecLimit readonly={editDisabled} form={form} carSelectApi={carSelectApi} />; | |
36 | + // return <SpecLimit readonly={editDisabled} form={form} carSelectApi={carSelectApi} />; | |
37 | + return <VehicleLimit readonly={editDisabled} form={form} carSelectApi={carSelectApi} />; | |
36 | 38 | } |
37 | 39 | if (limitType == LimitTypeEnum['指定VIN限制']) { |
38 | 40 | return <VinLimit disabled={editDisabled} form={form} carSelectApi={carSelectApi} />; | ... | ... |
src/pages/coupon/CouponConfig/entity.ts
... | ... | @@ -27,7 +27,7 @@ export enum LimitTypeEnum { |
27 | 27 | '不限制' = 0, |
28 | 28 | '限制', |
29 | 29 | '发券方限制', |
30 | - '指定VIN限制' | |
30 | + '指定VIN限制', | |
31 | 31 | } |
32 | 32 | export const WorkTypeEnum = { |
33 | 33 | jxyhq: 1, //机修 |
... | ... | @@ -83,3 +83,47 @@ export const UseSceneItems = { |
83 | 83 | '7': '购车方式', |
84 | 84 | '8': '整车型号代码', |
85 | 85 | }; |
86 | + | |
87 | +/**车辆限制保存数据转换 */ | |
88 | +export function carLimitTransfer(schemeList: MktConponSpace.LimitList[]) { | |
89 | + const carLimit: any[] = schemeList.filter((i) => i.limitType == 1 && i.schemeType == 1); | |
90 | + if (!carLimit.length) { | |
91 | + return schemeList; | |
92 | + } | |
93 | + const car: { applyValue: number; applyName: number; applyType: number }[] = []; | |
94 | + carLimit[0].valueList.forEach((i) => { | |
95 | + if (i.authType) { | |
96 | + car.push({ applyValue: i.seriesId, applyName: i.seriesName, applyType: 12 }); | |
97 | + } else { | |
98 | + i.spec.forEach((s) => { | |
99 | + car.push({ applyValue: s.specId, applyName: s.specName, applyType: 13 }); | |
100 | + }); | |
101 | + } | |
102 | + }); | |
103 | + const newLimits = schemeList.map((scheme) => (scheme.limitType == 1 && scheme.schemeType == 1 ? { ...scheme, valueList: car } : scheme)); | |
104 | + return newLimits; | |
105 | +} | |
106 | + | |
107 | +/**车辆限制数据初始化*/ | |
108 | +export function initCarLimit(data: MktConponSpace.ConListParams) { | |
109 | + if (!data.vehicleSchemeList || !data.vehicleSchemeList.length) { | |
110 | + return data.schemeList; | |
111 | + } | |
112 | + const carLimit: any[] = []; | |
113 | + data.vehicleSchemeList.forEach((item) => { | |
114 | + const newItem = item.secondaryList && item.secondaryList.map(i => ({ | |
115 | + brandId: item.applyValue, | |
116 | + brandName: item.applyName, | |
117 | + seriesId: Number(i.applyValue), | |
118 | + seriesName: i.applyName, | |
119 | + authType: Number(i.all) || 0, | |
120 | + spec: | |
121 | + i.secondaryList | |
122 | + ? i.secondaryList.map((i) => ({ specId: Number(i.applyValue), specName: i.applyName })) | |
123 | + : [], | |
124 | + })) | |
125 | + carLimit.push(...newItem); | |
126 | + }); | |
127 | + const newLimits = data.schemeList.map((scheme) => (scheme.limitType == 1 && scheme.schemeType == 1 ? { ...scheme, valueList: carLimit } : scheme)); | |
128 | + return newLimits; | |
129 | +} | ... | ... |
src/pages/coupon/CouponConfig/index.tsx
... | ... | @@ -2,6 +2,7 @@ import FullReduce from '@/pages/coupon/CouponConfig/components/FullReduce'; |
2 | 2 | import { Card, Form, Modal, Spin, message } from 'antd'; |
3 | 3 | import React, { useEffect, useState } from 'react'; |
4 | 4 | import * as api from './api'; |
5 | +import { carLimitTransfer, initCarLimit } from './entity'; | |
5 | 6 | |
6 | 7 | type Props = MktConponSpace.CouponProps; |
7 | 8 | |
... | ... | @@ -26,6 +27,7 @@ export default function UpsertCoupon( |
26 | 27 | detailApi(no) |
27 | 28 | .then((res) => { |
28 | 29 | const data = res.data || ({} as any); |
30 | + const schemeList = initCarLimit(data); | |
29 | 31 | setInfo(data); |
30 | 32 | form.setFieldsValue({ |
31 | 33 | ...data, |
... | ... | @@ -34,6 +36,7 @@ export default function UpsertCoupon( |
34 | 36 | exchangeTypeId: data.exchangeTypeId ? { value: data.exchangeTypeId, label: data.exchangeTypeName } : undefined, |
35 | 37 | orgList: data.orgList ? data.orgList.map((i) => ({ value: i.orgId, label: i.orgName })) : undefined, |
36 | 38 | amsCode: data.amsCode ? [{ code: data.amsCode, name: data.amsName, spec: data.amsSpec }] : undefined, |
39 | + schemeList, | |
37 | 40 | }); |
38 | 41 | setLoading(false); |
39 | 42 | }) |
... | ... | @@ -69,6 +72,7 @@ export default function UpsertCoupon( |
69 | 72 | id: info.id, |
70 | 73 | confNo: info.confNo, |
71 | 74 | ...fields, |
75 | + schemeList: carLimitTransfer(fields.schemeList), | |
72 | 76 | orgList: fields.orgList ? fields.orgList.map((i: { value: any; label: any }) => ({ orgId: i.value, orgName: i.label })) : [], |
73 | 77 | classifyCode: fields.classifyCode.value, |
74 | 78 | classifyName: fields.classifyCode.label, | ... | ... |
src/pages/coupon/CouponConfig/interface.d.ts
... | ... | @@ -117,9 +117,11 @@ declare namespace MktConponSpace { |
117 | 117 | schemeList: LimitList[]; //限制规则 |
118 | 118 | discountsType?: number; //折扣类型 1立减2兑换 |
119 | 119 | giftItemId?: number; |
120 | + vehicleSchemeList?: vehicleLimit[]; //组转车辆使用限制规则 | |
120 | 121 | } |
121 | 122 | |
122 | 123 | interface LimitList { |
124 | + limitType: number; | |
123 | 125 | schemeType: number; |
124 | 126 | limitScheme: boolean; |
125 | 127 | externalRely: boolean; |
... | ... | @@ -127,11 +129,19 @@ declare namespace MktConponSpace { |
127 | 129 | } |
128 | 130 | |
129 | 131 | interface LimitRuls { |
132 | + authType?: number; | |
130 | 133 | applyType: number; |
131 | 134 | applyName: string; |
132 | 135 | applyValue: number; |
133 | 136 | } |
134 | 137 | |
138 | + interface vehicleLimit { | |
139 | + applyName: string; | |
140 | + applyValue: number; | |
141 | + applyType: number; | |
142 | + all: boolean; | |
143 | + secondaryList: vehicleLimit[] | |
144 | + } | |
135 | 145 | interface SaveResult { |
136 | 146 | confNo: string; //配置编号 |
137 | 147 | classifyCode: string; //优惠券分类码 | ... | ... |
src/pages/mkt/ActivityCreate/index.tsx
... | ... | @@ -52,11 +52,12 @@ const ActivityCreate = (props: Props) => { |
52 | 52 | if (current == index) { |
53 | 53 | s = 'process'; |
54 | 54 | } |
55 | - return s; | |
55 | + return activityNo ? s : null; | |
56 | 56 | } |
57 | 57 | |
58 | 58 | function _onChange(cur: number) { |
59 | 59 | if (!activityNo && !baseInfo.activityNo) { |
60 | + message.info("请先配置活动基本信息") | |
60 | 61 | return; |
61 | 62 | } |
62 | 63 | if (cur < current) { | ... | ... |
src/pages/order3/AddValueTaskConfig/components/InsureEditModal.tsx
... | ... | @@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react'; |
2 | 2 | import { Modal, Form, Select, InputNumber, Row, Space, Button, Card, message } from 'antd'; |
3 | 3 | import { useStore } from '../index'; |
4 | 4 | import { InsureBuyRequireList, getBrandOrSeriesApi, CarResult } from '../api'; |
5 | +import { isEmpty } from 'lodash'; | |
5 | 6 | |
6 | 7 | interface DataItem { |
7 | 8 | label?: string; |
... | ... | @@ -14,6 +15,7 @@ export default function Index() { |
14 | 15 | const [seriesData, setSeriesData] = useState<CarResult[]>([]); |
15 | 16 | const [loading, setLoading] = useState<boolean>(false); |
16 | 17 | const [seriesList, setSeriesList] = useState<DataItem[]>([]); |
18 | + const [seriesLoading, setSeriesLoading] = useState<boolean>(false); | |
17 | 19 | const [form] = Form.useForm(); |
18 | 20 | |
19 | 21 | useEffect(() => { |
... | ... | @@ -51,7 +53,11 @@ export default function Index() { |
51 | 53 | } |
52 | 54 | |
53 | 55 | function handleSelectSeries(options: any) { |
54 | - setSeriesList(options); | |
56 | + setSeriesList(options?.filter((v: any) => !isEmpty(v))); | |
57 | + form.setFieldValue( | |
58 | + 'series', | |
59 | + options?.filter((v: any) => !isEmpty(v)), | |
60 | + ); | |
55 | 61 | } |
56 | 62 | |
57 | 63 | function afterClose() { |
... | ... | @@ -69,14 +75,24 @@ export default function Index() { |
69 | 75 | } |
70 | 76 | |
71 | 77 | function handleSelectBrand(brandId?: number) { |
78 | + setSeriesLoading(true); | |
72 | 79 | getBrandOrSeriesApi({ shopIds, brandId }) |
73 | 80 | .then((res) => { |
74 | 81 | setSeriesData(res.data || []); |
82 | + setSeriesLoading(false); | |
75 | 83 | }) |
76 | 84 | .catch((err) => { |
77 | 85 | message.error(err.message); |
78 | 86 | setSeriesData([]); |
79 | - }); | |
87 | + setSeriesLoading(false); | |
88 | + }).finally(() => { | |
89 | + setSeriesLoading(false); | |
90 | + }) | |
91 | + } | |
92 | + | |
93 | + function handleBrandChange(brandId?: number) { | |
94 | + handleSelectBrand(brandId); | |
95 | + form.setFieldValue('series', undefined); | |
80 | 96 | } |
81 | 97 | |
82 | 98 | async function handleOk() { |
... | ... | @@ -128,7 +144,7 @@ export default function Index() { |
128 | 144 | <Form form={form}> |
129 | 145 | <Form.Item label="品牌" name="brand" rules={[{ required: true, message: '请选择品牌!' }]}> |
130 | 146 | <Select |
131 | - onChange={(value) => handleSelectBrand(value.value)} | |
147 | + onChange={(value) => handleBrandChange(value.value)} | |
132 | 148 | labelInValue |
133 | 149 | allowClear |
134 | 150 | showSearch |
... | ... | @@ -147,6 +163,8 @@ export default function Index() { |
147 | 163 | filterOption |
148 | 164 | optionFilterProp="children" |
149 | 165 | mode="multiple" |
166 | + loading={seriesLoading} | |
167 | + disabled={seriesLoading} | |
150 | 168 | options={seriesData.map((v) => ({ label: v.dataName, value: v.dataId }))} |
151 | 169 | placeholder="请选择" |
152 | 170 | /> | ... | ... |
src/pages/order3/CarPurchaseSubsidy/AdditionalPurchaseSubsidy/components/List.tsx
... | ... | @@ -62,7 +62,7 @@ export default function List({ status }: Props) { |
62 | 62 | function renderOption(status: number, id: number, preId?: number, approveNumber?: string) { |
63 | 63 | if (status === 5 || status === 30) { |
64 | 64 | return ( |
65 | - <Space> | |
65 | + <Space wrap> | |
66 | 66 | <Popconfirm |
67 | 67 | title="是否删除?" |
68 | 68 | onConfirm={() => handleDeleteConfig(id)} |
... | ... | @@ -84,7 +84,7 @@ export default function List({ status }: Props) { |
84 | 84 | ); |
85 | 85 | } else if ([10, 20].includes(status) && approveNumber) { |
86 | 86 | return ( |
87 | - <Space> | |
87 | + <Space wrap> | |
88 | 88 | <Popconfirm |
89 | 89 | title="是否撤销审批?" |
90 | 90 | onConfirm={() => handleCancleApproval(approveNumber)} |
... | ... | @@ -98,7 +98,7 @@ export default function List({ status }: Props) { |
98 | 98 | ); |
99 | 99 | } else if (status === 15) { |
100 | 100 | return ( |
101 | - <Space><a onClick={() => handleEdit(true, id)} style={{color: "#448EF7" }}>编辑</a> | |
101 | + <Space wrap><a onClick={() => handleEdit(true, id)} style={{color: "#448EF7" }}>编辑</a> | |
102 | 102 | <Popconfirm |
103 | 103 | title="是否禁用" |
104 | 104 | onConfirm={() => handleApplyDisableOrEnabl(id, 2)} |
... | ... | @@ -186,7 +186,8 @@ export default function List({ status }: Props) { |
186 | 186 | width={220} |
187 | 187 | render={(_text, record: any) => ( |
188 | 188 | <> |
189 | - <Tooltip placement="topLeft" color="#FFF" title={<span style={{color: "#666"}}>{record.beginTime && moment(record.beginTime).format("YYYY-MM-DD HH:mm:ss")}至{record.endTime && moment(record.endTime).format("YYYY-MM-DD HH:mm:ss")}</span>}> | |
189 | + <Tooltip placement="topLeft" color="#FFF" title={<span style={{color: "#666"}}> | |
190 | + {record.beginTime && moment(record.beginTime).format("YYYY-MM-DD HH:mm:ss")}至{record.endTime && moment(record.endTime).format("YYYY-MM-DD HH:mm:ss")}</span>}> | |
190 | 191 | <span>{record.beginTime && moment(record.beginTime).format("YYYY-MM-DD HH:mm:ss")}至{record.endTime && moment(record.endTime).format("YYYY-MM-DD HH:mm:ss")}</span> |
191 | 192 | </Tooltip> |
192 | 193 | </> |
... | ... | @@ -209,7 +210,13 @@ export default function List({ status }: Props) { |
209 | 210 | align="left" |
210 | 211 | dataIndex="subsidyDataTips" |
211 | 212 | width={180} |
212 | - render={(_text, record: any) => <a style={{color: "#4189FD"}} onClick={() => onShow({subsidyDataUploadApply: record.subsidyDataUploadApply, subsidyDataUploadNDay: record.subsidyDataUploadNDay, deliveryAfterDays: record.deliveryAfterDays}, "补贴资料")}>{_text}</a>} | |
213 | + render={(_text, record: any) => | |
214 | + <a | |
215 | + style={{color: "#4189FD"}} | |
216 | + onClick={() => onShow({ | |
217 | + subsidyDataUploadApply: record.subsidyDataUploadApply, | |
218 | + subsidyDataUploadNDay: record.subsidyDataUploadNDay, | |
219 | + deliveryAfterDays: record.deliveryAfterDays}, "补贴资料")}>{_text}</a>} | |
213 | 220 | /> |
214 | 221 | <Column |
215 | 222 | title="状态" |
... | ... | @@ -222,11 +229,11 @@ export default function List({ status }: Props) { |
222 | 229 | align="left" |
223 | 230 | render={(_text, record: any) => { |
224 | 231 | return ( |
225 | - <Space> | |
232 | + <> | |
226 | 233 | { |
227 | 234 | renderOption(record.status, record.id, record.preId, record.approveNumber) |
228 | 235 | } |
229 | - </Space> | |
236 | + </> | |
230 | 237 | ); |
231 | 238 | }} |
232 | 239 | /> | ... | ... |
src/pages/order3/CarPurchaseSubsidy/KeyCustomerSubsidy/components/List.tsx
... | ... | @@ -62,7 +62,7 @@ export default function List({status = 1}: Props) { |
62 | 62 | function renderOption(status: number, id: number, preId?: number, approveNumber?: string) { |
63 | 63 | if (status === 5 || status === 30) { |
64 | 64 | return ( |
65 | - <Space> | |
65 | + <Space wrap> | |
66 | 66 | <Popconfirm |
67 | 67 | title="是否删除?" |
68 | 68 | onConfirm={() => handleDeleteConfig(id)} |
... | ... | @@ -84,7 +84,7 @@ export default function List({status = 1}: Props) { |
84 | 84 | ); |
85 | 85 | } else if ([10, 20].includes(status) && approveNumber) { |
86 | 86 | return ( |
87 | - <Space> | |
87 | + <Space wrap> | |
88 | 88 | <Popconfirm |
89 | 89 | title="是否撤销审批?" |
90 | 90 | onConfirm={() => handleCancleApproval(approveNumber)} |
... | ... | @@ -98,7 +98,7 @@ export default function List({status = 1}: Props) { |
98 | 98 | ); |
99 | 99 | } else if (status === 15) { |
100 | 100 | return ( |
101 | - <Space><a onClick={() => handleEdit(true, id)} style={{color: "#448EF7" }}>编辑</a> | |
101 | + <Space wrap><a onClick={() => handleEdit(true, id)} style={{color: "#448EF7" }}>编辑</a> | |
102 | 102 | <Popconfirm |
103 | 103 | title="是否禁用" |
104 | 104 | onConfirm={() => handleApplyDisableOrEnabl(id, 2)} |
... | ... | @@ -191,7 +191,8 @@ export default function List({status = 1}: Props) { |
191 | 191 | width={220} |
192 | 192 | render={(_text, record: any) => ( |
193 | 193 | <> |
194 | - <Tooltip placement="topLeft" color="#FFF" title={<span style={{color: "#666"}}>{record.beginTime && moment(record.beginTime).format("YYYY-MM-DD HH:mm:ss")}至{record.endTime && moment(record.endTime).format("YYYY-MM-DD HH:mm:ss")}</span>}> | |
194 | + <Tooltip placement="topLeft" color="#FFF" title={<span style={{color: "#666"}}> | |
195 | + {record.beginTime && moment(record.beginTime).format("YYYY-MM-DD HH:mm:ss")}至{record.endTime && moment(record.endTime).format("YYYY-MM-DD HH:mm:ss")}</span>}> | |
195 | 196 | <span>{record.beginTime && moment(record.beginTime).format("YYYY-MM-DD HH:mm:ss")}至{record.endTime && moment(record.endTime).format("YYYY-MM-DD HH:mm:ss")}</span> |
196 | 197 | </Tooltip> |
197 | 198 | </> |
... | ... | @@ -201,10 +202,12 @@ export default function List({status = 1}: Props) { |
201 | 202 | title="大客户类型" |
202 | 203 | align="left" |
203 | 204 | dataIndex="customerTypeName" |
204 | - render={(_text, record:any) => ( | |
205 | + render={(_text, record: any) => ( | |
205 | 206 | <> |
206 | - <Tooltip placement="topLeft" color="#FFF" title={<span style={{color: "#666"}}>{record.customerTypeNameList && record.customerTypeNameList.length && record.customerTypeNameList.join(",")}</span>}> | |
207 | - <span style={{display: "block", maxWidth: 120, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap"}}>{record.customerTypeNameList && record.customerTypeNameList.length && record.customerTypeNameList.join(",")}</span> | |
207 | + <Tooltip placement="topLeft" color="#FFF" title={<span style={{color: "#666"}}> | |
208 | + {record.customerTypeNameList && record.customerTypeNameList.length && record.customerTypeNameList.join(",")}</span>}> | |
209 | + <span style={{display: "block", maxWidth: 120, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap"}}> | |
210 | + {record.customerTypeNameList && record.customerTypeNameList.length && record.customerTypeNameList.join(",")}</span> | |
208 | 211 | </Tooltip> |
209 | 212 | </> |
210 | 213 | )} |
... | ... | @@ -226,7 +229,13 @@ export default function List({status = 1}: Props) { |
226 | 229 | align="left" |
227 | 230 | dataIndex="subsidyDataTips" |
228 | 231 | width={180} |
229 | - render={(_text, record: any) => <a style={{color: "#4189FD"}} onClick={() => onShow({subsidyDataUploadApply: record.subsidyDataUploadApply, subsidyDataUploadNDay: record.subsidyDataUploadNDay, deliveryAfterDays: record.deliveryAfterDays}, "补贴资料")}>{_text}</a>} | |
232 | + render={(_text, record: any) => | |
233 | + <a | |
234 | + style={{color: "#4189FD"}} | |
235 | + onClick={() => onShow({ | |
236 | + subsidyDataUploadApply: record.subsidyDataUploadApply, | |
237 | + subsidyDataUploadNDay: record.subsidyDataUploadNDay, | |
238 | + deliveryAfterDays: record.deliveryAfterDays}, "补贴资料")}>{_text}</a>} | |
230 | 239 | /> |
231 | 240 | <Column |
232 | 241 | title="状态" |
... | ... | @@ -239,11 +248,11 @@ export default function List({status = 1}: Props) { |
239 | 248 | align="left" |
240 | 249 | render={(_text, record: any) => { |
241 | 250 | return ( |
242 | - <Space> | |
251 | + <> | |
243 | 252 | { |
244 | 253 | renderOption(record.status, record.id, record.preId, record.approveNumber) |
245 | 254 | } |
246 | - </Space> | |
255 | + </> | |
247 | 256 | ); |
248 | 257 | }} |
249 | 258 | /> | ... | ... |
src/pages/order3/CarPurchaseSubsidy/ReplacementSubsidy/components/List.tsx
... | ... | @@ -62,7 +62,7 @@ export default function List({ status }: Props) { |
62 | 62 | function renderOption(status: number, id: number, preId?: number, approveNumber?: string) { |
63 | 63 | if (status === 5 || status === 30) { |
64 | 64 | return ( |
65 | - <Space> | |
65 | + <Space wrap> | |
66 | 66 | <Popconfirm title="是否删除?" onConfirm={() => handleDeleteConfig(id)} okText="确定" cancelText="取消"> |
67 | 67 | <a style={{ color: '#999' }}>删除</a> |
68 | 68 | </Popconfirm> |
... | ... | @@ -76,7 +76,7 @@ export default function List({ status }: Props) { |
76 | 76 | ); |
77 | 77 | } else if ([10, 20].includes(status) && approveNumber) { |
78 | 78 | return ( |
79 | - <Space> | |
79 | + <Space wrap> | |
80 | 80 | <Popconfirm title="是否撤销审批?" onConfirm={() => handleCancleApproval(approveNumber)} okText="确定" cancelText="取消"> |
81 | 81 | <a style={{ color: '#999' }}>撤销</a> |
82 | 82 | </Popconfirm> |
... | ... | @@ -87,7 +87,7 @@ export default function List({ status }: Props) { |
87 | 87 | ); |
88 | 88 | } else if (status === 15) { |
89 | 89 | return ( |
90 | - <Space> | |
90 | + <Space wrap> | |
91 | 91 | <a onClick={() => handleEdit(true, id)} style={{ color: '#448EF7' }}> |
92 | 92 | 编辑 |
93 | 93 | </a> |
... | ... | @@ -238,7 +238,7 @@ export default function List({ status }: Props) { |
238 | 238 | title="操作" |
239 | 239 | align="left" |
240 | 240 | render={(_text, record: any) => { |
241 | - return <Space>{renderOption(record.status, record.id, record.preId, record.approveNumber)}</Space>; | |
241 | + return <>{renderOption(record.status, record.id, record.preId, record.approveNumber)}</>; | |
242 | 242 | }} |
243 | 243 | /> |
244 | 244 | </Table> | ... | ... |
src/pages/order3/DeliverCentralGoals/components/InsureEditModal.tsx
... | ... | @@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react'; |
2 | 2 | import { Modal, Form, Select, InputNumber, Row, Space, Button, Card, message } from 'antd'; |
3 | 3 | import { useStore } from '../index'; |
4 | 4 | import { InsureBuyRequireList, getBrandOrSeriesApi, CarResult } from '../api'; |
5 | +import { isEmpty } from 'lodash'; | |
5 | 6 | |
6 | 7 | interface DataItem { |
7 | 8 | label?: string; |
... | ... | @@ -14,6 +15,7 @@ export default function Index() { |
14 | 15 | const [seriesData, setSeriesData] = useState<CarResult[]>([]); |
15 | 16 | const [loading, setLoading] = useState<boolean>(false); |
16 | 17 | const [seriesList, setSeriesList] = useState<DataItem[]>([]); |
18 | + const [seriesLoading, setSeriesLoading] = useState<boolean>(false); | |
17 | 19 | const [form] = Form.useForm(); |
18 | 20 | |
19 | 21 | useEffect(() => { |
... | ... | @@ -51,7 +53,11 @@ export default function Index() { |
51 | 53 | } |
52 | 54 | |
53 | 55 | function handleSelectSeries(options: any) { |
54 | - setSeriesList(options); | |
56 | + setSeriesList(options?.filter((v: any) => !isEmpty(v))); | |
57 | + form.setFieldValue( | |
58 | + 'series', | |
59 | + options?.filter((v: any) => !isEmpty(v)), | |
60 | + ); | |
55 | 61 | } |
56 | 62 | |
57 | 63 | function afterClose() { |
... | ... | @@ -69,16 +75,27 @@ export default function Index() { |
69 | 75 | } |
70 | 76 | |
71 | 77 | function handleSelectBrand(brandId?: number) { |
78 | + setSeriesLoading(true); | |
72 | 79 | getBrandOrSeriesApi({ shopIds, brandId }) |
73 | 80 | .then((res) => { |
74 | 81 | setSeriesData(res.data || []); |
82 | + setSeriesLoading(false); | |
75 | 83 | }) |
76 | 84 | .catch((err) => { |
77 | 85 | message.error(err.message); |
78 | 86 | setSeriesData([]); |
87 | + setSeriesLoading(false); | |
88 | + }) | |
89 | + .finally(() => { | |
90 | + setSeriesLoading(false); | |
79 | 91 | }); |
80 | 92 | } |
81 | 93 | |
94 | + function handleBrandChange(brandId?: number) { | |
95 | + handleSelectBrand(brandId); | |
96 | + form.setFieldValue('series', undefined); | |
97 | + } | |
98 | + | |
82 | 99 | async function handleOk() { |
83 | 100 | const params = await form.validateFields(); |
84 | 101 | if ( |
... | ... | @@ -128,7 +145,7 @@ export default function Index() { |
128 | 145 | <Form form={form}> |
129 | 146 | <Form.Item label="品牌" name="brand" rules={[{ required: true, message: '请选择品牌!' }]}> |
130 | 147 | <Select |
131 | - onChange={(value) => handleSelectBrand(value.value)} | |
148 | + onChange={(value) => handleBrandChange(value.value)} | |
132 | 149 | labelInValue |
133 | 150 | allowClear |
134 | 151 | showSearch |
... | ... | @@ -145,6 +162,8 @@ export default function Index() { |
145 | 162 | allowClear |
146 | 163 | showSearch |
147 | 164 | filterOption |
165 | + loading={seriesLoading} | |
166 | + disabled={seriesLoading} | |
148 | 167 | optionFilterProp="children" |
149 | 168 | mode="multiple" |
150 | 169 | options={seriesData.map((v) => ({ label: v.dataName, value: v.dataId }))} | ... | ... |