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,6 +246,10 @@ export default [ | ||
246 | path: '/cas/cassetting/manHoursDiscountConfig/create/:id/:brandId?', //工时减免规则配置 | 246 | path: '/cas/cassetting/manHoursDiscountConfig/create/:id/:brandId?', //工时减免规则配置 |
247 | component: './cas/afterSaleConfiguration/manHoursDiscountConfig/subpages/ConfigCreate' | 247 | component: './cas/afterSaleConfiguration/manHoursDiscountConfig/subpages/ConfigCreate' |
248 | }, | 248 | }, |
249 | + { | ||
250 | + path: '/cas/cassetting/manhoursProportionConfig', // 机修组工时分成比例配置 | ||
251 | + component: './cas/afterSaleConfiguration/manhoursProportionConfig' | ||
252 | + }, | ||
249 | // { | 253 | // { |
250 | // path: '/cas/part/plantype', // 备件计划类型 | 254 | // path: '/cas/part/plantype', // 备件计划类型 |
251 | // component: './cas/spareParts/PlanType' | 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 | +} |