Commit b77a515f09fbb0b729b58a4be7b1928301f831d8
Merge branch 'd-cas' into 'master'
售后:新增门店机修组工时分成比例配置 See merge request !266
Showing
4 changed files
with
263 additions
and
0 deletions
config/routers/cas.ts
... | ... | @@ -246,6 +246,10 @@ export default [ |
246 | 246 | path: '/cas/cassetting/manHoursDiscountConfig/create/:id/:brandId?', //工时减免规则配置 |
247 | 247 | component: './cas/afterSaleConfiguration/manHoursDiscountConfig/subpages/ConfigCreate' |
248 | 248 | }, |
249 | + { | |
250 | + path: '/cas/cassetting/manhoursProportionConfig', // 机修组工时分成比例配置 | |
251 | + component: './cas/afterSaleConfiguration/manhoursProportionConfig' | |
252 | + }, | |
249 | 253 | // { |
250 | 254 | // path: '/cas/part/plantype', // 备件计划类型 |
251 | 255 | // component: './cas/spareParts/PlanType' | ... | ... |
src/pages/cas/afterSaleConfiguration/manhoursProportionConfig/api.ts
0 → 100644
1 | +import { http } from "@/typing/http"; | |
2 | +import request from "@/utils/request"; | |
3 | +import { CAS_HOST } from "@/utils/host"; | |
4 | + | |
5 | +type PromisePageResp<T> = http.PromisePageResp<T>; | |
6 | + | |
7 | +// 列表参数 | |
8 | +interface ListParam { | |
9 | + current?: number; | |
10 | + pageSize?: number; | |
11 | + keyword?: string; | |
12 | + shopId?: number; | |
13 | + groupId?: number; | |
14 | + userId?: number; | |
15 | + userName?: string; | |
16 | + teamId?: number; | |
17 | +} | |
18 | + | |
19 | +// 列表结果 | |
20 | +export interface ListResult { | |
21 | + groupId: number; // 集团id | |
22 | + shopId: number; // 门店id | |
23 | + shopName: string; // 门店名称 | |
24 | + roleCode: string; // 角色编码 | |
25 | + roleName: string; // 角色名称 | |
26 | + teamId: number; // 组id | |
27 | + teamName: string; // 组名 | |
28 | + userInfoVOS: Staff[]; // 组员工信息 | |
29 | +} | |
30 | + | |
31 | +// 机修组员工信息 | |
32 | +export interface Staff { | |
33 | + id?: string; // 配置id | |
34 | + staffId: string; // 组员id | |
35 | + staffName: string; // 组员名称 | |
36 | + manHoursProp: number; // 工时分成占比(以小数表示,如0.5表示50%,全部组员相加为1) | |
37 | +} | |
38 | + | |
39 | +/** 工时分成配置列表 */ | |
40 | +export function getListApi(params: ListParam): PromisePageResp<ListResult[]> { | |
41 | + return request.get(`${CAS_HOST}/erp/team/setting/list`, { params }); | |
42 | +} | |
43 | + | |
44 | +export interface SaveParams { | |
45 | + shopId: number; // 门店id | |
46 | + shopName: string; // 门店名称 | |
47 | + teamId: number; // 小组id | |
48 | + teamName: string; // 小组名称 | |
49 | + userId?: number; // 用户id | |
50 | + userName?: string; // 用户名称 | |
51 | + groupId?: number; // 集团id | |
52 | + userInfoVOS?: Staff[]; // 各组员分成比例配置 | |
53 | +} | |
54 | + | |
55 | +/** 修改配置 */ | |
56 | +export function saveApi(params: SaveParams) { | |
57 | + return request.post(`${CAS_HOST}/erp/team/setting/save`, params); | |
58 | +} | ... | ... |
src/pages/cas/afterSaleConfiguration/manhoursProportionConfig/components/ConfigModal.tsx
0 → 100644
1 | +import React, { useState, useEffect } from "react"; | |
2 | +import "@ant-design/compatible/assets/index.css"; | |
3 | +import { Alert, Modal, Form, message, InputNumber } from "antd"; | |
4 | +import { ListResult, SaveParams, saveApi, Staff } from "../api"; | |
5 | + | |
6 | +const FormItem = Form.Item; | |
7 | +const maxFormProps = { | |
8 | + labelCol: { span: 6 }, | |
9 | + wrapperCol: { span: 14 }, | |
10 | +}; | |
11 | + | |
12 | +interface Props { | |
13 | + visible: boolean; | |
14 | + onCancel: () => any; | |
15 | + detail?: ListResult; | |
16 | +} | |
17 | + | |
18 | +export default function ConfigModal({ visible, onCancel, detail }: Props) { | |
19 | + const [form] = Form.useForm(); | |
20 | + console.log("detail", detail); | |
21 | + | |
22 | + const [confirmLoading, setConfirmLoading] = useState<boolean>(false); | |
23 | + | |
24 | + useEffect(() => { | |
25 | + if (visible) { | |
26 | + form.resetFields(); | |
27 | + // init form values | |
28 | + const initialValues: any = {}; | |
29 | + detail?.userInfoVOS?.forEach((user: Staff) => { | |
30 | + initialValues[user.staffId] = user.manHoursProp; | |
31 | + }); | |
32 | + form.setFieldsValue(initialValues); | |
33 | + } | |
34 | + }, [visible]); | |
35 | + | |
36 | + function handleSubmit(fieldsValue: any) { | |
37 | + const configItems = detail!.userInfoVOS.map((user: Staff) => ({ | |
38 | + id: user.id, | |
39 | + staffId: user.staffId, | |
40 | + staffName: user.staffName, | |
41 | + manHoursProp: fieldsValue[user.staffId], | |
42 | + })); | |
43 | + const sum = configItems.reduce((acc: number, cur: Staff) => acc + cur.manHoursProp, 0); | |
44 | + if (sum !== 1) { | |
45 | + message.error("所有人员分成占比之和必须等于1"); | |
46 | + return; | |
47 | + } | |
48 | + | |
49 | + const params: SaveParams = { | |
50 | + shopId: detail!.shopId, | |
51 | + shopName: detail!.shopName, | |
52 | + teamId: detail!.teamId, | |
53 | + teamName: detail!.teamName, | |
54 | + userInfoVOS: configItems, | |
55 | + }; | |
56 | + | |
57 | + setConfirmLoading(true); | |
58 | + saveApi(params) | |
59 | + .then(() => { | |
60 | + message.success("配置成功!"); | |
61 | + setConfirmLoading(false); | |
62 | + onCancel(); | |
63 | + }) | |
64 | + .catch((e) => { | |
65 | + setConfirmLoading(false); | |
66 | + message.error(e.message); | |
67 | + }); | |
68 | + } | |
69 | + | |
70 | + return ( | |
71 | + <Modal | |
72 | + title="配置机修组工时分成比例" | |
73 | + width={640} | |
74 | + open={visible} | |
75 | + confirmLoading={confirmLoading} | |
76 | + onOk={() => form.submit()} | |
77 | + onCancel={onCancel} | |
78 | + > | |
79 | + <Alert message="每人分成占比以小数表示,所有人员分成占比之和必须等于1" type="info" style={{ marginBottom: 20 }} /> | |
80 | + | |
81 | + <Form form={form} onFinish={handleSubmit}> | |
82 | + {detail?.userInfoVOS?.map((user: Staff) => ( | |
83 | + <FormItem | |
84 | + key={user.id} | |
85 | + name={user.staffId} | |
86 | + label={user.staffName} | |
87 | + rules={[{ required: true, message: "必填" }]} | |
88 | + {...maxFormProps} | |
89 | + > | |
90 | + <InputNumber style={{ width: 200 }} max={1} min={0} step={0.1} defaultValue={user.manHoursProp} /> | |
91 | + </FormItem> | |
92 | + ))} | |
93 | + </Form> | |
94 | + </Modal> | |
95 | + ); | |
96 | +} | ... | ... |
src/pages/cas/afterSaleConfiguration/manhoursProportionConfig/index.tsx
0 → 100644
1 | +import React, { useState, useEffect } from "react"; | |
2 | +import { Card, Table, Button, Tag, message, Select, Input } from "antd"; | |
3 | +import { PageHeaderWrapper } from "@ant-design/pro-layout"; | |
4 | + | |
5 | +import usePagination from "@/hooks/usePagination"; | |
6 | +import { getShopApi } from "@/common/api"; | |
7 | +import { getListApi, ListResult, Staff } from "./api"; | |
8 | + | |
9 | +import ConfigModal from "./components/ConfigModal"; | |
10 | + | |
11 | +const { Option } = Select; | |
12 | +const { Column } = Table; | |
13 | + | |
14 | +export default function ManhoursProportionConfig() { | |
15 | + const { loading, setLoading, list, paginationConfig, setParams } = usePagination(getListApi, {}); | |
16 | + | |
17 | + const [shops, setShops] = useState<CommonApi.OptionVO[]>([]); | |
18 | + const [visible, setVisible] = useState(false); | |
19 | + const [detail, setDetail] = useState<any>({}); | |
20 | + | |
21 | + useEffect(() => { | |
22 | + getShopApi({}) | |
23 | + .then((res) => { | |
24 | + const { data = [] } = res; | |
25 | + setShops(data); | |
26 | + }) | |
27 | + .catch((e) => { | |
28 | + message.error(e.message); | |
29 | + }); | |
30 | + }, []); | |
31 | + | |
32 | + return ( | |
33 | + <PageHeaderWrapper title="机修组工时分成比例配置"> | |
34 | + <Card> | |
35 | + <div style={{ display: "flex", marginBottom: "20px" }}> | |
36 | + <Select | |
37 | + style={{ width: 240 }} | |
38 | + showSearch | |
39 | + allowClear | |
40 | + optionFilterProp="children" | |
41 | + placeholder="请选择门店搜索" | |
42 | + onChange={(value) => setParams({ shopId: value }, true)} | |
43 | + > | |
44 | + {shops.map((shop) => ( | |
45 | + <Option value={shop.id} key={shop.id}> | |
46 | + {shop.name} | |
47 | + </Option> | |
48 | + ))} | |
49 | + </Select> | |
50 | + | |
51 | + <Input.Search | |
52 | + style={{ width: 240, marginLeft: 20 }} | |
53 | + placeholder="请输入机修组名称搜索" | |
54 | + allowClear | |
55 | + onSearch={(value) => setParams({ keyword: value }, true)} | |
56 | + /> | |
57 | + </div> | |
58 | + | |
59 | + <Table dataSource={list} loading={loading} pagination={paginationConfig} rowKey="teamId"> | |
60 | + <Column title="门店" dataIndex="shopName" width={200} /> | |
61 | + <Column title="机修组" dataIndex="teamName" width={200} /> | |
62 | + <Column | |
63 | + title="分成比例" | |
64 | + dataIndex="userInfoVOS" | |
65 | + render={(users: Staff[]) => { | |
66 | + return users.map((user) => ( | |
67 | + <Tag color="blue" key={user.id} style={{ marginRight: 10 }}> | |
68 | + {user.staffName}:{user.manHoursProp} | |
69 | + </Tag> | |
70 | + )); | |
71 | + }} | |
72 | + /> | |
73 | + <Column | |
74 | + title="操作" | |
75 | + dataIndex="teamId" | |
76 | + align="center" | |
77 | + width={150} | |
78 | + render={(val, record: ListResult) => ( | |
79 | + <Button | |
80 | + size="small" | |
81 | + type="primary" | |
82 | + onClick={() => { | |
83 | + setDetail(record); | |
84 | + setVisible(true); | |
85 | + }} | |
86 | + > | |
87 | + 编辑 | |
88 | + </Button> | |
89 | + )} | |
90 | + /> | |
91 | + </Table> | |
92 | + </Card> | |
93 | + | |
94 | + <ConfigModal | |
95 | + visible={visible} | |
96 | + detail={detail} | |
97 | + onCancel={() => { | |
98 | + setVisible(false); | |
99 | + setDetail({}); | |
100 | + setLoading(true); | |
101 | + }} | |
102 | + /> | |
103 | + </PageHeaderWrapper> | |
104 | + ); | |
105 | +} | ... | ... |