Commit 600397489d088fbd141b3309974b40d1ac03c132

Authored by 莫红玲
2 parents 3456c03f b7f1eb70

Merge branch 'ehr-archives' into 'master'

Ehr archives



See merge request !251
Showing 22 changed files with 1231 additions and 430 deletions
src/pages/ehr/GroupMobileRecord/components/GroupMobileRecordList.tsx
1 1 /*
2 2 * @Date: 2021-01-05 14:24:23
3 3 * @LastEditors: wangqiang@feewee.cn
4   - * @LastEditTime: 2023-03-22 09:38:10
  4 + * @LastEditTime: 2023-05-11 14:06:10
5 5 */
6 6 import React, { useState } from "react";
7 7 import {
... ... @@ -120,6 +120,17 @@ export default function GroupMobileRecordList() {
120 120 )}
121 121 </span>
122 122 </span>
  123 + <Divider type="vertical" />
  124 + <span style={{ color: "#999" }}>
  125 + 最低月租:
  126 + <span>
  127 + {record.monthRent ? (
  128 + <CheckCircleFilled style={{ color: "#52c41a" }} />
  129 + ) : (
  130 + <CloseCircleFilled style={{ color: "#ff4d4f" }} />
  131 + )}
  132 + </span>
  133 + </span>
123 134 </span>
124 135 <br />
125 136 <span>
... ... @@ -173,6 +184,17 @@ export default function GroupMobileRecordList() {
173 184 )}
174 185 </span>
175 186 </span>
  187 + <Divider type="vertical" />
  188 + <span style={{ color: "#999" }}>
  189 + 最低月租:
  190 + <span>
  191 + {record.monthRent ? (
  192 + <CheckCircleFilled style={{ color: "#52c41a" }} />
  193 + ) : (
  194 + <CloseCircleFilled style={{ color: "#ff4d4f" }} />
  195 + )}
  196 + </span>
  197 + </span>
176 198 </span>
177 199 <span className="span_limit_1">
178 200 <span style={{ color: "#999" }}>运营商:</span>
... ...
src/pages/ehr/GroupMobileRecord/components/GroupMobileRecordModal.tsx
1 1 /*
2 2 * @Date: 2021-01-05 14:24:23
3 3 * @LastEditors: wangqiang@feewee.cn
4   - * @LastEditTime: 2023-03-30 14:20:30
  4 + * @LastEditTime: 2023-05-11 11:48:34
5 5 */
6 6 import React, { useEffect, useState } from "react";
7 7 import { Form, Input, Modal, message, Select, Switch } from "antd";
... ... @@ -150,6 +150,9 @@ export default function GroupMobileRecordModal() {
150 150 : currentItem?.businessCard,
151 151 operatorId: val.operator?.value,
152 152 operatorName: val.operator?.label,
  153 + monthRent: elements.includes("mobile:special-function:edit")
  154 + ? val.monthRent
  155 + : currentItem?.monthRent,
153 156 };
154 157 saveMobileApi(params)
155 158 .then((res) => {
... ... @@ -423,6 +426,18 @@ export default function GroupMobileRecordModal() {
423 426 unCheckedChildren="否"
424 427 />
425 428 </FormItem>
  429 + <FormItem
  430 + name="monthRent"
  431 + label="是否有最低月租"
  432 + valuePropName="checked"
  433 + rules={[{ required: true, message: "请选择" }]}
  434 + >
  435 + <Switch
  436 + disabled={editSubject}
  437 + checkedChildren="是"
  438 + unCheckedChildren="否"
  439 + />
  440 + </FormItem>
426 441 </>
427 442 );
428 443 } else {
... ...
src/pages/ehr/GroupMobileRecord/index.tsx
1 1 /*
2 2 * @Date: 2021-01-05 14:24:23
3 3 * @LastEditors: wangqiang@feewee.cn
4   - * @LastEditTime: 2023-04-26 10:34:08
  4 + * @LastEditTime: 2023-05-11 11:50:55
5 5 */
6 6 import React from "react";
7 7 import { Card, Button, Row, Input, ConfigProvider, Select } from "antd";
... ... @@ -233,6 +233,24 @@ function GroupMobileRecord() {
233 233 </Select.Option>
234 234 </Select>
235 235 </FeeweeFilterOption>
  236 + <FeeweeFilterOption title="最低月租">
  237 + <Select
  238 + allowClear
  239 + placeholder="是否有最低月租"
  240 + onChange={(monthRent) => setParams({ monthRent, current: 1 }, true)}
  241 + showSearch
  242 + optionFilterProp="children"
  243 + style={{ width: 260, marginBottom: 10, marginRight: 10 }}
  244 + getPopupContainer={(triggerNode) => triggerNode.parentNode}
  245 + >
  246 + <Select.Option key="是" value>
  247 + 有最低月租
  248 + </Select.Option>
  249 + <Select.Option key="否" value={false}>
  250 + 没有最低月租
  251 + </Select.Option>
  252 + </Select>
  253 + </FeeweeFilterOption>
236 254 <FeeweeFilterOption title="运营商">
237 255 <Select
238 256 allowClear
... ...
src/pages/ehr/GroupMobileRecord/interface.d.ts
... ... @@ -44,6 +44,7 @@ declare namespace GroupMobileRecord {
44 44 operatorName?: string; // 运营商
45 45 postList?: PostVO[];
46 46 preChargeAmount?: number; // 上月预充金额
  47 + monthRent?: boolean; // 是否有最低月租
47 48 }
48 49  
49 50 interface PostVO {
... ...
src/pages/ehr/PhoneChargeAndSubsidy/subpages/SubsidyConfirm/api.ts
... ... @@ -2,7 +2,7 @@
2 2 * @Author: wangqiang@feewee.cn
3 3 * @Date: 2023-03-31 15:24:37
4 4 * @LastEditors: wangqiang@feewee.cn
5   - * @LastEditTime: 2023-04-18 17:04:46
  5 + * @LastEditTime: 2023-05-09 16:44:19
6 6 */
7 7 import request from "@/utils/request";
8 8 import { ARCHIVES_HOST, CONTRACT_HOST } from "@/utils/host";
... ... @@ -67,7 +67,7 @@ export function getCanteenPageListApi(): http.PromisePageResp&lt;EHrSubsidyConfirm.
67 67 /**
68 68 * @description: 获取食堂临时补贴人员信息
69 69 * @param {EHrSubsidyConfirm.CanteenStaffListParams} params
70   - * @return {http.PromiseResp<string>}
  70 + * @return {http.PromiseResp<EHrSubsidyConfirm.CanteenStaffList>}
71 71 */
72 72 export function getSubsidyCanteenStaffListApi(
73 73 params: EHrSubsidyConfirm.CanteenStaffListParams
... ...
src/pages/ehr/PhoneChargeAndSubsidy/subpages/SubsidyConfirm/components/ConfirmItem.tsx
... ... @@ -2,7 +2,7 @@
2 2 * @Author: wangqiang@feewee.cn
3 3 * @Date: 2023-03-13 10:45:17
4 4 * @LastEditors: wangqiang@feewee.cn
5   - * @LastEditTime: 2023-04-20 10:23:16
  5 + * @LastEditTime: 2023-05-09 16:35:17
6 6 */
7 7 import {
8 8 Button,
... ... @@ -38,34 +38,35 @@ export default function SubsidyConfirmItem({
38 38 onChange,
39 39 children,
40 40 }: Props) {
41   - const { setConfirmModalInfo } = useStore();
  41 + const { setStandardConfirmModalInfo } = useStore();
42 42  
43 43 const onClick = (item: EHrSubsidyConfirm.TypeVO, special?: boolean) => {
44   - setConfirmModalInfo({
  44 + setStandardConfirmModalInfo({
45 45 open: true,
46 46 key: item.value,
47 47 keyName: item.desc,
48 48 special,
  49 + attendanceConfigList: item.attendanceConfigList,
49 50 value: special
50   - ? item.staffList?.filter((staff) => staff.specialStaff)
51   - : item.staffList,
  51 + ? item.standardList?.filter((standard) => standard.specialSubsidy)
  52 + : item.standardList,
52 53 onChange: onEditChange,
53 54 });
54 55 };
55 56  
56 57 const onEditChange = (
57 58 key: number,
58   - staffList: EHrSubsidyConfirm.TypeStaffVO[],
  59 + standardList: EHrSubsidyConfirm.StandardVO[],
59 60 special?: boolean
60 61 ) => {
61 62 const val = value?.map((item) => (item.value === key
62 63 ? {
63 64 ...item,
64   - staffList: special
65   - ? item.staffList
66   - ?.filter((staff) => !staff.specialStaff)
67   - .concat(staffList)
68   - : staffList,
  65 + standardList: special
  66 + ? item.standardList
  67 + ?.filter((staff) => !staff.specialSubsidy)
  68 + .concat(standardList)
  69 + : standardList,
69 70 }
70 71 : item)
71 72 );
... ... @@ -77,7 +78,25 @@ export default function SubsidyConfirmItem({
77 78 }
78 79  
79 80 const NormalItem = ({ item }: ItemProps) => {
80   - const staffList = item.staffList?.filter((staff) => staff.selected ?? true);
  81 + const realAmount =
  82 + item.standardList?.reduce(
  83 + (count, standard) => count + (standard.realAmount ?? 0),
  84 + 0
  85 + ) ?? 0;
  86 + const standardAmount =
  87 + item.standardList?.reduce(
  88 + (count, standard) => count + (standard.standardAmount ?? 0),
  89 + 0
  90 + ) ?? 0;
  91 + const staffCount =
  92 + item.standardList?.reduce(
  93 + (count, standard) => count + (standard.staffCnt ?? 0),
  94 + 0
  95 + ) ?? 0;
  96 + const specialStaffCount =
  97 + item.standardList
  98 + ?.filter((standard) => standard.specialSubsidy)
  99 + ?.reduce((count, standard) => count + (standard.staffCnt ?? 0), 0) ?? 0;
81 100 return (
82 101 <Form.Item label={item.desc}>
83 102 <div
... ... @@ -91,9 +110,7 @@ export default function SubsidyConfirmItem({
91 110 <DetailItem
92 111 title="应补贴"
93 112 style={{ marginBottom: 0 }}
94   - desp={
95   - <a onClick={() => onClick(item)}>{staffList?.length ?? 0} 人</a>
96   - }
  113 + desp={<a onClick={() => onClick(item)}>{staffCount} 人</a>}
97 114 />
98 115 <Divider type="vertical" />
99 116 <DetailItem
... ... @@ -101,13 +118,7 @@ export default function SubsidyConfirmItem({
101 118 style={{ marginBottom: 0 }}
102 119 desp={
103 120 <a onClick={() => onClick(item)}>
104   - {priceToThousands(
105   - staffList?.reduce(
106   - (amount, item) => amount + +(item.standardAmount ?? 0),
107   - 0
108   - ) ?? 0
109   - )}{" "}
110   - 元
  121 + {priceToThousands(standardAmount)} 元
111 122 </a>
112 123 }
113 124 />
... ... @@ -117,13 +128,7 @@ export default function SubsidyConfirmItem({
117 128 style={{ marginBottom: 0 }}
118 129 desp={
119 130 <a onClick={() => onClick(item)}>
120   - {priceToThousands(
121   - staffList?.reduce(
122   - (amount, item) => amount + +(item.realAmount ?? 0),
123   - 0
124   - ) ?? 0
125   - )}{" "}
126   - 元
  131 + {priceToThousands(realAmount)} 元
127 132 </a>
128 133 }
129 134 />
... ... @@ -132,9 +137,7 @@ export default function SubsidyConfirmItem({
132 137 title="其中:特殊补贴名单"
133 138 style={{ marginBottom: 0 }}
134 139 desp={
135   - <a onClick={() => onClick(item, true)}>
136   - {staffList?.filter((staff) => staff.specialStaff).length} 人
137   - </a>
  140 + <a onClick={() => onClick(item, true)}>{specialStaffCount} 人</a>
138 141 }
139 142 />
140 143 <span>&nbsp;&nbsp;)&nbsp;&nbsp;</span>
... ... @@ -157,7 +160,7 @@ export default function SubsidyConfirmItem({
157 160 value?.map((_item) => (_item.value === item.value
158 161 ? {
159 162 ..._item,
160   - staffList: val.staffList
  163 + staffList: (val.staffList ?? [])
161 164 .map((staff: any) => ({
162 165 type: item.value,
163 166 staffId: staff.value,
... ... @@ -169,7 +172,7 @@ export default function SubsidyConfirmItem({
169 172 realAmount: val.realAmount,
170 173 remark: val.remark,
171 174 }))
172   - .concat(_item.staffList),
  175 + .concat(_item.staffList ?? []),
173 176 }
174 177 : _item)
175 178 )
... ... @@ -190,12 +193,24 @@ export default function SubsidyConfirmItem({
190 193 );
191 194 }
192 195  
  196 + function onListItemChange(staffList?: EHrSubsidyConfirm.TypeStaffVO[]) {
  197 + onChange?.(
  198 + value?.map((_item) => (_item.value === item.value
  199 + ? {
  200 + ...item,
  201 + staffList,
  202 + }
  203 + : _item)
  204 + )
  205 + );
  206 + }
  207 +
193 208 return (
194 209 <>
195 210 <Form.Item label={item.desc}>
196 211 <EditTable
197 212 value={item.staffList}
198   - onChange={(items) => onEditChange(item.value ?? -1, items ?? [])}
  213 + onChange={onListItemChange}
199 214 pagination={{
200 215 showTotal: (total, range) => `共 ${total} 条数据,当前展示第 ${range[0]}-${range[1]} 条数据`,
201 216 }}
... ... @@ -211,19 +226,19 @@ export default function SubsidyConfirmItem({
211 226 <span className="span_limit_1">
212 227 <span style={{ color: "#999" }}>员工姓名:</span>
213 228 <span style={{ color: "#333" }}>
214   - {record.staffName || "-"}
  229 + {record?.staffName || "-"}
215 230 </span>
216 231 </span>
217 232 <span className="span_limit_1">
218 233 <span style={{ color: "#999" }}>在职门店:</span>
219 234 <span style={{ color: "#333" }}>
220   - {record.shopName || "-"}
  235 + {record?.shopName || "-"}
221 236 </span>
222 237 </span>
223 238 <span className="span_limit_1">
224 239 <span style={{ color: "#999" }}>人员岗位:</span>
225 240 <span style={{ color: "#333" }}>
226   - {record.postName || "-"}
  241 + {record?.postName || "-"}
227 242 </span>
228 243 </span>
229 244 </span>
... ... @@ -241,13 +256,10 @@ export default function SubsidyConfirmItem({
241 256 {
242 257 title: "备注",
243 258 dataIndex: "remark",
  259 + inputType: "text",
244 260 width: 150,
245 261 editable: true,
246   - render: (remark: string) => (
247   - <Popover content={remark || "-"} trigger="click">
248   - <a onClick={(e) => e.stopPropagation()}>查看</a>
249   - </Popover>
250   - ),
  262 + render: (remark: string) => remark ?? "-",
251 263 },
252 264 {
253 265 title: "操作",
... ... @@ -275,6 +287,8 @@ export default function SubsidyConfirmItem({
275 287 maskClosable={false}
276 288 onOk={form.submit}
277 289 onCancel={onCancel}
  290 + zIndex={1001}
  291 + destroyOnClose
278 292 >
279 293 <Form form={form} onFinish={onOk}>
280 294 <Form.Item
... ... @@ -285,7 +299,7 @@ export default function SubsidyConfirmItem({
285 299 <MemberSelectNew
286 300 multiple
287 301 disabledIds={item.staffList?.map(
288   - (staff) => staff.staffId ?? -1
  302 + (staff) => staff?.staffId ?? -1
289 303 )}
290 304 />
291 305 </Form.Item>
... ...
src/pages/ehr/PhoneChargeAndSubsidy/subpages/SubsidyConfirm/components/ConfirmModal.tsx
1   -import React, { useEffect, useState } from "react";
  1 +import React, { useEffect, useRef, useState } from "react";
2 2 import EditTable from "@/pages/ehr/components/EditTable";
3 3 import { useStore } from "../index";
4 4 import {
5   - checkNull,
6   - unique,
7   - validatorNumberCanWithDecimal,
8   -} from "@/utils/validate";
9   -import { message, Modal, Popover, Row, Select } from "antd";
10   -import { priceToThousands } from "@/utils/utils";
11   -import FeeweeFilterOption from "@/pages/notice/components/FeeweeFilterOption";
  5 + Button,
  6 + Divider,
  7 + Input,
  8 + InputRef,
  9 + message,
  10 + Modal,
  11 + Popover,
  12 + Row,
  13 + Space,
  14 +} from "antd";
  15 +import { SearchOutlined } from "@ant-design/icons";
  16 +import { formatObjText, priceToThousands } from "@/utils/utils";
12 17 import moment from "moment";
13   -
14   -interface FilterItem {
15   - value?: number;
16   - label?: string;
17   -}
  18 +import DetailItem from "@/pages/ehr/Authentication/Settings/components/DetailItem";
  19 +import { ColumnType } from "antd/lib/table";
  20 +import { FilterConfirmProps } from "antd/lib/table/interface";
  21 +import { checkNull } from "@/utils/validate";
18 22  
19 23 export default function SubsidyConfirmModal() {
20   - const { confirmModalInfo, setConfirmModalInfo } = useStore();
  24 + const {
  25 + standardConfirmModalInfo,
  26 + confirmModalInfo,
  27 + setConfirmModalInfo,
  28 + ScopeType,
  29 + ScopeUnit,
  30 + } = useStore();
21 31 const [items, setItems] = useState<EHrSubsidyConfirm.TypeStaffVO[]>([]);
22   - const [filters, setFilters] = useState<{
23   - staffs?: FilterItem[];
24   - shops?: FilterItem[];
25   - posts?: FilterItem[];
26   - standardAmounts?: FilterItem[];
27   - }>({});
28   - const [filterValue, setFilterValue] = useState<{
29   - staffId?: number;
30   - shopId?: number;
31   - postId?: number;
32   - standardAmount?: number;
33   - }>({});
  32 +
  33 + const searchInput = useRef<InputRef>(null);
34 34  
35 35 useEffect(() => {
36 36 if (confirmModalInfo.open) {
37 37 setItems(confirmModalInfo.value ?? []);
38   - const staffs = unique(
39   - confirmModalInfo.value?.map((staff) => ({
40   - value: staff.staffId,
41   - label: staff.staffName,
42   - })) || [],
43   - "value"
44   - );
45   - const shops = unique(
46   - confirmModalInfo.value?.map((staff) => ({
47   - value: staff.shopId,
48   - label: staff.shopName,
49   - })) || [],
50   - "value"
51   - );
52   - const posts = unique(
53   - confirmModalInfo.value?.map((staff) => ({
54   - value: staff.postId,
55   - label: staff.postName,
56   - })) || [],
57   - "value"
58   - );
59   - const standardAmounts = unique(
60   - confirmModalInfo.value?.map((staff) => ({
61   - value: staff.standardAmount,
62   - label: `${staff.standardAmount ?? "-"} 元`,
63   - })) || [],
64   - "value"
65   - );
66   - setFilters({ staffs, shops, posts, standardAmounts });
67   - } else {
68   - setFilterValue({});
69 38 }
70 39 }, [confirmModalInfo.open, confirmModalInfo.value]);
71 40  
... ... @@ -123,7 +92,7 @@ export default function SubsidyConfirmModal() {
123 92  
124 93 const onCancel = () => setConfirmModalInfo({ open: false });
125 94  
126   - const onOk = () => {
  95 + const onOk = (): any => {
127 96 const item = items.find(
128 97 (i) => checkNull(i.realAmount) && (i.selected ?? true)
129 98 );
... ... @@ -136,112 +105,263 @@ export default function SubsidyConfirmModal() {
136 105 items
137 106 );
138 107 } else {
139   - confirmModalInfo.onChange?.(
140   - confirmModalInfo.key ?? -1,
141   - items,
142   - confirmModalInfo.special
143   - );
  108 + confirmModalInfo.onChange?.(items);
144 109 }
145 110 onCancel();
146 111 };
147 112  
  113 + const handleSearch = (
  114 + selectedKeys: string[],
  115 + confirm: (param?: FilterConfirmProps) => void,
  116 + dataIndex: keyof EHrSubsidyConfirm.TypeStaffVO
  117 + ) => {
  118 + confirm();
  119 + };
  120 +
  121 + const handleReset = (clearFilters: () => void) => {
  122 + clearFilters();
  123 + };
  124 +
  125 + const getColumnSearchProps = (
  126 + dataIndex: keyof EHrSubsidyConfirm.TypeStaffVO,
  127 + title: string
  128 + ): ColumnType<EHrSubsidyConfirm.TypeStaffVO> => ({
  129 + filterDropdown: ({
  130 + setSelectedKeys,
  131 + selectedKeys,
  132 + confirm,
  133 + clearFilters,
  134 + }) => (
  135 + <div style={{ padding: 8 }} onKeyDown={(e) => e.stopPropagation()}>
  136 + <Input
  137 + ref={searchInput}
  138 + placeholder={`输入 ${title} 搜索`}
  139 + value={selectedKeys[0]}
  140 + onChange={(e) => setSelectedKeys(e.target.value ? [e.target.value] : [])}
  141 + onPressEnter={() => handleSearch(selectedKeys as string[], confirm, dataIndex)}
  142 + style={{ marginBottom: 8, display: "block" }}
  143 + />
  144 + <Space>
  145 + <Button
  146 + type="primary"
  147 + onClick={() => handleSearch(selectedKeys as string[], confirm, dataIndex)}
  148 + icon={<SearchOutlined />}
  149 + size="small"
  150 + style={{ width: 90 }}
  151 + >
  152 + 确定
  153 + </Button>
  154 + <Button
  155 + onClick={() => clearFilters && handleReset(clearFilters)}
  156 + size="small"
  157 + style={{ width: 90 }}
  158 + >
  159 + 重置
  160 + </Button>
  161 + <Button
  162 + type="link"
  163 + size="small"
  164 + onClick={() => {
  165 + confirm({ closeDropdown: false });
  166 + }}
  167 + >
  168 + 过滤
  169 + </Button>
  170 + </Space>
  171 + </div>
  172 + ),
  173 + filterIcon: (filtered: boolean) => (
  174 + <SearchOutlined style={{ color: filtered ? "#1890ff" : undefined }} />
  175 + ),
  176 + onFilter: (value, record) => record?.[dataIndex]
  177 + ?.toString()
  178 + .toLowerCase()
  179 + .includes((value as string).toLowerCase()) ?? false,
  180 + onFilterDropdownOpenChange: (visible) => {
  181 + if (visible) {
  182 + setTimeout(() => searchInput.current?.select(), 0);
  183 + }
  184 + },
  185 + });
  186 +
148 187 return (
149 188 <Modal
150   - title={`补贴确认-${confirmModalInfo.keyName}-列表查看`}
  189 + title={`补贴确认-${standardConfirmModalInfo.keyName}-补贴标准人员列表查看`}
151 190 visible={confirmModalInfo.open}
152 191 maskClosable={false}
153   - width="65%"
  192 + width="85%"
154 193 onOk={onOk}
155 194 onCancel={onCancel}
  195 + zIndex={1002}
  196 + destroyOnClose
156 197 >
157   - <Row justify="start" align="bottom">
158   - <FeeweeFilterOption title="人员">
159   - <Select
160   - allowClear
161   - placeholder="选择人员筛选"
162   - style={{ minWidth: 260, marginRight: 10, marginBottom: 10 }}
163   - value={filterValue.staffId}
164   - onChange={(staffId) => setFilterValue({ ...filterValue, staffId })}
165   - showSearch
166   - optionFilterProp="children"
167   - >
168   - {filters.staffs?.map((staff) => (
169   - <Select.Option key={staff.value} value={staff.value}>
170   - {staff.label}
171   - </Select.Option>
172   - ))}
173   - </Select>
174   - </FeeweeFilterOption>
175   - <FeeweeFilterOption title="在职门店">
176   - <Select
177   - allowClear
178   - placeholder="选择在职门店筛选"
179   - style={{ minWidth: 260, marginRight: 10, marginBottom: 10 }}
180   - value={filterValue.shopId}
181   - onChange={(shopId) => setFilterValue({ ...filterValue, shopId })}
182   - showSearch
183   - optionFilterProp="children"
184   - >
185   - {filters.shops?.map((shop) => (
186   - <Select.Option key={shop.value} value={shop.value}>
187   - {shop.label}
188   - </Select.Option>
189   - ))}
190   - </Select>
191   - </FeeweeFilterOption>
192   - <FeeweeFilterOption title="人员岗位">
193   - <Select
194   - allowClear
195   - placeholder="选择人员岗位筛选"
196   - style={{ minWidth: 260, marginRight: 10, marginBottom: 10 }}
197   - value={filterValue.postId}
198   - onChange={(postId) => setFilterValue({ ...filterValue, postId })}
199   - showSearch
200   - optionFilterProp="children"
201   - >
202   - {filters.posts?.map((post) => (
203   - <Select.Option key={post.value} value={post.value}>
204   - {post.label}
205   - </Select.Option>
206   - ))}
207   - </Select>
208   - </FeeweeFilterOption>
209   - <FeeweeFilterOption title="补贴标准">
210   - <Select
211   - allowClear
212   - placeholder="选择补贴标准筛选"
213   - style={{ minWidth: 260, marginRight: 10, marginBottom: 10 }}
214   - value={filterValue.postId}
215   - onChange={(standardAmount) => setFilterValue({ ...filterValue, standardAmount })}
216   - showSearch
217   - optionFilterProp="children"
218   - >
219   - {filters.standardAmounts?.map((standardAmount) => (
220   - <Select.Option
221   - key={standardAmount.value}
222   - value={standardAmount.value}
  198 + <Row style={{ alignItems: "center", justifyContent: "space-around" }}>
  199 + <DetailItem
  200 + style={{ marginBottom: 0 }}
  201 + title="补贴标准"
  202 + // desp={confirmModalInfo.standard ?? "-"}
  203 + desp={
  204 + <>
  205 + <span>
  206 + {`${priceToThousands(confirmModalInfo.item?.amount ?? "")} ${
  207 + !confirmModalInfo.item?.specialSubsidy
  208 + ? confirmModalInfo.item?.amountType === 1
  209 + ? "元/天"
  210 + : confirmModalInfo.item?.amountType === 3
  211 + ? "元/月"
  212 + : ""
  213 + : "元/月"
  214 + }`}
  215 + </span>
  216 + {confirmModalInfo.item?.specialSubsidy ? (
  217 + <span
  218 + style={{
  219 + fontSize: 12,
  220 + color: "#FF9625",
  221 + padding: "1px 5px",
  222 + marginLeft: 5,
  223 + borderRadius: 2,
  224 + border: "1px solid #FF9625",
  225 + }}
  226 + >
  227 + 特殊
  228 + </span>
  229 + ) : null}
  230 + </>
  231 + }
  232 + />
  233 + <Divider type="vertical" />
  234 + <DetailItem
  235 + style={{ marginBottom: 0 }}
  236 + title="适用门店"
  237 + desp={
  238 + confirmModalInfo.item?.specialSubsidy ? (
  239 + "-"
  240 + ) : confirmModalInfo.item?.shopScope === 1 ? (
  241 + "全部门店"
  242 + ) : (
  243 + <Popover
  244 + trigger="click"
  245 + title={`${confirmModalInfo.item?.shopList?.length || 0}个门店`}
  246 + content={
  247 + <div
  248 + style={{
  249 + display: "flex",
  250 + flexWrap: "wrap",
  251 + justifyContent: "flex-start",
  252 + alignItems: "center",
  253 + maxWidth: 400,
  254 + gap: "0 20px",
  255 + }}
  256 + >
  257 + {confirmModalInfo.item?.shopList?.map((shop) => (
  258 + <p key={shop.shopId}>{shop.shopName}</p>
  259 + ))}
  260 + </div>
  261 + }
  262 + >
  263 + <span>
  264 + {formatObjText(
  265 + confirmModalInfo.item?.shopList ?? [],
  266 + "shopName",
  267 + 2,
  268 + "个门店"
  269 + )}
  270 + <a>查看</a>
  271 + </span>
  272 + </Popover>
  273 + )
  274 + }
  275 + />
  276 + <Divider type="vertical" />
  277 + <DetailItem
  278 + style={{ marginBottom: 0 }}
  279 + title="适用岗位"
  280 + desp={
  281 + confirmModalInfo.item?.specialSubsidy ? (
  282 + "-"
  283 + ) : confirmModalInfo.item?.postScope === 1 ? (
  284 + "全部岗位"
  285 + ) : (
  286 + <Popover
  287 + trigger="click"
  288 + title={`${confirmModalInfo.item?.postList?.length || 0}个岗位`}
  289 + content={
  290 + <div
  291 + style={{
  292 + display: "flex",
  293 + flexWrap: "wrap",
  294 + justifyContent: "flex-start",
  295 + alignItems: "center",
  296 + maxWidth: 400,
  297 + gap: "0 20px",
  298 + }}
  299 + >
  300 + {confirmModalInfo.item?.postList?.map((post) => (
  301 + <p key={post.postId}>{post.postName}</p>
  302 + ))}
  303 + </div>
  304 + }
223 305 >
224   - {standardAmount.label}
225   - </Select.Option>
226   - ))}
227   - </Select>
228   - </FeeweeFilterOption>
  306 + <span>
  307 + {formatObjText(
  308 + confirmModalInfo.item?.postList ?? [],
  309 + "postName",
  310 + 2,
  311 + "个岗位"
  312 + )}
  313 + <a>查看</a>
  314 + </span>
  315 + </Popover>
  316 + )
  317 + }
  318 + />
  319 + <Divider type="vertical" />
  320 + <DetailItem
  321 + style={{ marginBottom: 0 }}
  322 + title="适用范围"
  323 + desp={
  324 + confirmModalInfo.item?.specialSubsidy ? (
  325 + "-"
  326 + ) : confirmModalInfo.item?.scopeStaff ? (
  327 + <span>
  328 + {confirmModalInfo.item?.scopeStaff
  329 + ? ScopeType[confirmModalInfo.item?.scopeStaff]
  330 + : ""}
  331 + {confirmModalInfo.item?.scopeStaff !== 3 ? (
  332 + <>
  333 + 时间
  334 + {confirmModalInfo.item?.scopeStaffTimeMin ?? ""}-
  335 + {confirmModalInfo.item?.scopeStaffTimeMax ?? ""}
  336 + {confirmModalInfo.item?.scopeStaffTimeUnit
  337 + ? ScopeUnit[confirmModalInfo.item?.scopeStaffTimeUnit]
  338 + : ""}
  339 + </>
  340 + ) : null}
  341 + </span>
  342 + ) : (
  343 + "-"
  344 + )
  345 + }
  346 + />
  347 + </Row>
  348 + <Divider />
  349 + <Row>
  350 + <DetailItem
  351 + title="计算方式"
  352 + desp={`日均补贴金额 * (${standardConfirmModalInfo.attendanceConfigList
  353 + ?.map((item) => item.desc + "天数")
  354 + .join("+")})`}
  355 + />
229 356 </Row>
230 357 <EditTable
231   - value={items.filter(
232   - (i) => (filterValue.staffId ? i.staffId === filterValue.staffId : true) &&
233   - (filterValue.shopId ? i.shopId === filterValue.shopId : true) &&
234   - (filterValue.postId ? i.postId === filterValue.postId : true) &&
235   - (!checkNull(filterValue.standardAmount)
236   - ? i.standardAmount === filterValue.standardAmount
237   - : true)
238   - )}
  358 + value={items}
239 359 onChange={(items) => setItems(items || [])}
240 360 pagination={{
241 361 showTotal: (total, range) => `共 ${total} 条数据,当前展示第 ${range[0]}-${range[1]} 条数据`,
242 362 }}
243 363 bordered={false}
244   - scroll={{ scrollToFirstRowOnChange: true, y: "65vh" }}
  364 + scroll={{ scrollToFirstRowOnChange: true, x: 1500, y: "65vh" }}
245 365 rowKey="staffId"
246 366 uniqueKey="staffId"
247 367 onRow={(record) => ({
... ... @@ -260,77 +380,101 @@ export default function SubsidyConfirmModal() {
260 380 }}
261 381 columns={[
262 382 {
263   - title: "员工信息",
264   - render: (record: EHrSubsidyConfirm.TypeStaffVO) => (
265   - <span>
266   - <span className="span_limit_1">
267   - <span style={{ color: "#999" }}>员工姓名:</span>
268   - <span style={{ color: "#333" }}>
269   - {record.staffName || "-"}
270   - </span>
271   - </span>
272   - <span className="span_limit_1">
273   - <span style={{ color: "#999" }}>在职门店:</span>
274   - <span style={{ color: "#333" }}>
275   - {record.shopName || "-"}
276   - </span>
277   - </span>
278   - <span className="span_limit_1">
279   - <span style={{ color: "#999" }}>人员岗位:</span>
280   - <span style={{ color: "#333" }}>
281   - {record.postName || "-"}
282   - </span>
283   - </span>
284   - <span className="span_limit_1">
285   - <span style={{ color: "#999" }}>入职时间:</span>
286   - <span style={{ color: "#333" }}>
287   - {record.entryDate
288   - ? moment(record.entryDate).format("YYYY-MM-DD")
289   - : "-"}
290   - </span>
291   - </span>
292   - <span className="span_limit_1">
293   - <span style={{ color: "#999" }}>转正时间:</span>
294   - <span style={{ color: "#333" }}>
295   - {record.regularDate
296   - ? moment(record.regularDate).format("YYYY-MM-DD")
297   - : "-"}
298   - </span>
299   - </span>
300   - </span>
301   - ),
  383 + title: "员工姓名",
  384 + dataIndex: "staffName",
  385 + width: 120,
  386 + fixed: "left",
  387 + ...getColumnSearchProps("staffName", "员工姓名"),
302 388 },
303 389 {
304   - title: "其他信息",
  390 + title: "人员岗位",
  391 + dataIndex: "postName",
305 392 width: 150,
306   - render: (record: EHrSubsidyConfirm.TypeStaffVO) => (
307   - <span>
308   - <span className="span_limit_1">
309   - <span style={{ color: "#999" }}>上班天数:</span>
310   - <span style={{ color: "#333" }}>
311   - {record.workDays ?? "-"}
312   - </span>
313   - </span>
314   - <span className="span_limit_1">
315   - <span style={{ color: "#999" }}>请假天数:</span>
316   - <span style={{ color: "#333" }}>
317   - {record.askForLeaveDays ?? "-"}
318   - </span>
319   - </span>
320   - <span className="span_limit_1">
321   - <span style={{ color: "#999" }}>出差天数:</span>
322   - <span style={{ color: "#333" }}>
323   - {record.evectionDays ?? "-"}
324   - </span>
325   - </span>
326   - <span className="span_limit_1">
327   - <span style={{ color: "#999" }}>休息天数:</span>
328   - <span style={{ color: "#333" }}>
329   - {record.restDays ?? "-"}
330   - </span>
331   - </span>
332   - </span>
  393 + ...getColumnSearchProps("postName", "人员岗位"),
  394 + },
  395 + {
  396 + title: "在职门店",
  397 + dataIndex: "shopName",
  398 + width: 150,
  399 + ...getColumnSearchProps("shopName", "在职门店"),
  400 + },
  401 + {
  402 + title: "入职时间",
  403 + dataIndex: "entryDate",
  404 + width: 110,
  405 + sorter: (
  406 + a: EHrSubsidyConfirm.TypeStaffVO,
  407 + b: EHrSubsidyConfirm.TypeStaffVO
  408 + ) => (a.entryDate ?? -1) - (b.entryDate ?? -1),
  409 + render: (entryDate: number) => (entryDate ? moment(entryDate).format("YYYY-MM-DD") : "-"),
  410 + },
  411 + {
  412 + title: "转正时间",
  413 + dataIndex: "regularDate",
  414 + width: 110,
  415 + sorter: (
  416 + a: EHrSubsidyConfirm.TypeStaffVO,
  417 + b: EHrSubsidyConfirm.TypeStaffVO
  418 + ) => (a.regularDate ?? -1) - (b.regularDate ?? -1),
  419 + render: (regularDate: number) => (regularDate ? moment(regularDate).format("YYYY-MM-DD") : "-"),
  420 + },
  421 + {
  422 + title: "离职时间",
  423 + dataIndex: "leaveDate",
  424 + width: 110,
  425 + sorter: (
  426 + a: EHrSubsidyConfirm.TypeStaffVO,
  427 + b: EHrSubsidyConfirm.TypeStaffVO
  428 + ) => (a.leaveDate ?? -1) - (b.leaveDate ?? -1),
  429 + render: (leaveDate: number) => (leaveDate ? moment(leaveDate).format("YYYY-MM-DD") : "-"),
  430 + },
  431 + {
  432 + title: "上班天数",
  433 + hide: !standardConfirmModalInfo.attendanceConfigList?.find((item) => item.desc?.includes("上班")
  434 + ),
  435 + dataIndex: "workDays",
  436 + width: 90,
  437 + sorter: (
  438 + a: EHrSubsidyConfirm.TypeStaffVO,
  439 + b: EHrSubsidyConfirm.TypeStaffVO
  440 + ) => (a.workDays ?? -1) - (b.workDays ?? -1),
  441 + render: (workDays: number) => `${workDays ?? 0} 天`,
  442 + },
  443 + {
  444 + title: "请假天数",
  445 + hide: !standardConfirmModalInfo.attendanceConfigList?.find((item) => item.desc?.includes("请假")
333 446 ),
  447 + dataIndex: "askForLeaveDays",
  448 + width: 90,
  449 + sorter: (
  450 + a: EHrSubsidyConfirm.TypeStaffVO,
  451 + b: EHrSubsidyConfirm.TypeStaffVO
  452 + ) => (a.askForLeaveDays ?? -1) - (b.askForLeaveDays ?? -1),
  453 + render: (askForLeaveDays: number) => `${askForLeaveDays ?? 0} 天`,
  454 + },
  455 + {
  456 + title: "出差天数",
  457 + hide: !standardConfirmModalInfo.attendanceConfigList?.find((item) => item.desc?.includes("出差")
  458 + ),
  459 + dataIndex: "evectionDays",
  460 + width: 90,
  461 + sorter: (
  462 + a: EHrSubsidyConfirm.TypeStaffVO,
  463 + b: EHrSubsidyConfirm.TypeStaffVO
  464 + ) => (a.evectionDays ?? -1) - (b.evectionDays ?? -1),
  465 + render: (evectionDays: number) => `${evectionDays ?? 0} 天`,
  466 + },
  467 + {
  468 + title: "休息天数",
  469 + hide: !standardConfirmModalInfo.attendanceConfigList?.find((item) => item.desc?.includes("休息")
  470 + ),
  471 + dataIndex: "evectionDays",
  472 + width: 90,
  473 + sorter: (
  474 + a: EHrSubsidyConfirm.TypeStaffVO,
  475 + b: EHrSubsidyConfirm.TypeStaffVO
  476 + ) => (a.restDays ?? -1) - (b.restDays ?? -1),
  477 + render: (restDays: number) => `${restDays ?? 0} 天`,
334 478 },
335 479 {
336 480 title: "补贴标准",
... ... @@ -345,25 +489,22 @@ export default function SubsidyConfirmModal() {
345 489 {
346 490 title: "实际补贴",
347 491 dataIndex: "realAmount",
348   - width: 200,
  492 + width: 150,
349 493 editable: true,
350 494 inputType: "number",
351 495 max: 999.99,
  496 + fixed: "right",
352 497 render: (realAmount: number) => `${priceToThousands(realAmount)} 元`,
353 498 },
354 499 {
355 500 title: "备注",
356 501 editable: true,
  502 + required: false,
357 503 inputType: "text",
358   - width: 250,
  504 + width: 200,
359 505 dataIndex: "remark",
360   - render: (remark: string) => (remark ? (
361   - <Popover content={remark || "-"} trigger="click">
362   - <a onClick={(e) => e.stopPropagation()}>查看</a>
363   - </Popover>
364   - ) : (
365   - "-"
366   - )),
  506 + fixed: "right",
  507 + render: (remark: string) => remark ?? "-",
367 508 },
368 509 ]}
369 510 />
... ...
src/pages/ehr/PhoneChargeAndSubsidy/subpages/SubsidyConfirm/components/List.tsx
... ... @@ -2,9 +2,9 @@
2 2 * @Author: wangqiang@feewee.cn
3 3 * @Date: 2023-03-13 09:13:01
4 4 * @LastEditors: wangqiang@feewee.cn
5   - * @LastEditTime: 2023-04-27 15:47:02
  5 + * @LastEditTime: 2023-05-10 09:43:09
6 6 */
7   -import { Badge, Divider, message, Popconfirm, Table } from "antd";
  7 +import { Badge, Divider, message, Popconfirm, Popover, Table } from "antd";
8 8 import React from "react";
9 9 import { useStore } from "../index";
10 10 import { cancelSubsidyConfirmAPi } from "../api";
... ... @@ -49,9 +49,45 @@ export default function SubsidyConfirmList() {
49 49 />
50 50 <Table.Column
51 51 title="人员在职门店"
52   - dataIndex="shopName"
  52 + dataIndex="shopList"
53 53 align="left"
54   - render={(shopName: string) => (shopName ?? "-")}
  54 + render={(shopList: string[]) => (
  55 + <Popover
  56 + trigger="click"
  57 + title={`${shopList?.length || 0}个门店`}
  58 + content={
  59 + <div
  60 + style={{
  61 + display: "flex",
  62 + flexWrap: "wrap",
  63 + justifyContent: "flex-start",
  64 + alignItems: "center",
  65 + maxWidth: 400,
  66 + gap: "0 20px",
  67 + }}
  68 + >
  69 + {shopList?.map((shop) => (
  70 + <p key={shop}>{shop}</p>
  71 + ))}
  72 + </div>
  73 + }
  74 + >
  75 + <span>
  76 + {shopList
  77 + ?.slice(0, 3)
  78 + .map((shop) => shop)
  79 + .join("、")}
  80 + {shopList?.length && shopList.length > 3 ? (
  81 + <>
  82 + 等{shopList.length}个门店
  83 + <a>查看</a>
  84 + </>
  85 + ) : (
  86 + ""
  87 + )}
  88 + </span>
  89 + </Popover>
  90 + )}
55 91 />
56 92 <Table.Column
57 93 title="状态"
... ...
src/pages/ehr/PhoneChargeAndSubsidy/subpages/SubsidyConfirm/components/Modal.tsx
... ... @@ -2,15 +2,14 @@ import React, { useEffect, useMemo, useState } from &quot;react&quot;;
2 2 import { useStore } from "../index";
3 3 import { applySubsidyConfirmApi, getSubsidyConfirmDetailApi } from "../api";
4 4 import {
5   - Button,
6 5 Divider,
7 6 Form,
8 7 Input,
9 8 message,
10 9 Modal,
  10 + Popover,
11 11 Skeleton,
12 12 Spin,
13   - Table,
14 13 } from "antd";
15 14 import moment from "moment";
16 15 import ConfirmItem from "./ConfirmItem";
... ... @@ -28,18 +27,52 @@ export default function SubsidyConfirmModal() {
28 27 "typeList",
29 28 form
30 29 );
  30 + const sumStandardAmount = useMemo(
  31 + () => +(
  32 + typeList?.reduce(
  33 + (amount, item) => amount +
  34 + ((item.showWay === "normal"
  35 + ? item.standardList?.reduce(
  36 + (amount, standard) => amount + (standard.standardAmount ?? 0),
  37 + 0
  38 + )
  39 + : item.showWay === "list"
  40 + ? item.staffList
  41 + ?.filter((item) => item?.selected ?? true)
  42 + .reduce(
  43 + (amount, item) => amount + +(item.standardAmount ?? 0),
  44 + 0
  45 + )
  46 + : item.canteenList?.reduce(
  47 + (amount, canteen) => amount +
  48 + (canteen.standardList?.reduce(
  49 + (amount, standard) => amount + +(standard.standardAmount ?? 0),
  50 + 0
  51 + ) ?? 0),
  52 + 0
  53 + ) ?? 0) || 0),
  54 + 0
  55 + ) ?? 0
  56 + ).toFixed(2),
  57 + [typeList]
  58 + );
31 59 const sumAmount = useMemo(
32 60 () => +(
33 61 typeList?.reduce(
34 62 (amount, item) => amount +
35   - ((item.showWay !== "special"
  63 + ((item.showWay === "normal"
  64 + ? item.standardList?.reduce(
  65 + (amount, standard) => amount + (standard.realAmount ?? 0),
  66 + 0
  67 + )
  68 + : item.showWay === "list"
36 69 ? item.staffList
37   - ?.filter((item) => item.selected ?? true)
  70 + ?.filter((item) => item?.selected ?? true)
38 71 .reduce((amount, item) => amount + +(item.realAmount ?? 0), 0)
39 72 : item.canteenList?.reduce(
40 73 (amount, canteen) => amount +
41   - (canteen.staffList?.reduce(
42   - (amount, staff) => amount + +(staff.realAmount ?? 0),
  74 + (canteen.standardList?.reduce(
  75 + (amount, standard) => amount + +(standard.realAmount ?? 0),
43 76 0
44 77 ) ?? 0),
45 78 0
... ... @@ -79,6 +112,21 @@ export default function SubsidyConfirmModal() {
79 112 typeList: typeList?.map((type) => ({
80 113 ...type,
81 114 staffList: type.staffList?.filter((staff) => staff.selected ?? true),
  115 + standardList: type.standardList?.map((standard) => ({
  116 + ...standard,
  117 + staffList: standard.staffList?.filter(
  118 + (staff) => staff.selected ?? true
  119 + ),
  120 + })),
  121 + canteenList: type.canteenList?.map((canteen) => ({
  122 + ...canteen,
  123 + standardList: canteen.standardList?.map((standard) => ({
  124 + ...standard,
  125 + staffList: standard.staffList?.filter(
  126 + (staff) => staff.selected ?? true
  127 + ),
  128 + })),
  129 + })),
82 130 })),
83 131 })
84 132 .then((res) => {
... ... @@ -99,7 +147,7 @@ export default function SubsidyConfirmModal() {
99 147 return (
100 148 <Modal
101 149 title="补贴确认"
102   - width="50%"
  150 + width="60%"
103 151 open={open}
104 152 maskClosable={false}
105 153 confirmLoading={confirmLoading}
... ... @@ -124,13 +172,41 @@ export default function SubsidyConfirmModal() {
124 172 />
125 173 </Form.Item>
126 174 <Form.Item label="人员在职门店">
127   - <Input
128   - value={
129   - current?.shopName ?? "-"
  175 + <Popover
  176 + trigger="click"
  177 + title={`${current?.shopList?.length || 0}个门店`}
  178 + content={
  179 + <div
  180 + style={{
  181 + display: "flex",
  182 + flexWrap: "wrap",
  183 + justifyContent: "flex-start",
  184 + alignItems: "center",
  185 + maxWidth: 400,
  186 + gap: "0 20px",
  187 + }}
  188 + >
  189 + {current?.shopList?.map((shop) => (
  190 + <p key={shop}>{shop}</p>
  191 + ))}
  192 + </div>
130 193 }
131   - bordered={false}
132   - readOnly
133   - />
  194 + >
  195 + <span>
  196 + {current?.shopList
  197 + ?.slice(0, 3)
  198 + .map((shop) => shop)
  199 + .join("、")}
  200 + {current?.shopList?.length && current?.shopList.length > 3 ? (
  201 + <>
  202 + 等{current?.shopList.length}个门店
  203 + <a>查看</a>
  204 + </>
  205 + ) : (
  206 + ""
  207 + )}
  208 + </span>
  209 + </Popover>
134 210 </Form.Item>
135 211 <Divider />
136 212 <Skeleton
... ... @@ -162,27 +238,7 @@ export default function SubsidyConfirmModal() {
162 238 <DetailItem
163 239 title="合计应补贴金额"
164 240 style={{ marginBottom: 0 }}
165   - desp={`${priceToThousands(
166   - typeList?.reduce(
167   - (amount, item) => amount +
168   - ((item.showWay !== "special"
169   - ? item.staffList
170   - ?.filter((item) => item.selected ?? true)
171   - .reduce(
172   - (amount, item) => amount + +(item.standardAmount ?? 0),
173   - 0
174   - )
175   - : item.canteenList?.reduce(
176   - (amount, canteen) => amount +
177   - (canteen.staffList?.reduce(
178   - (amount, staff) => amount + +(staff.standardAmount ?? 0),
179   - 0
180   - ) ?? 0),
181   - 0
182   - )) || 0),
183   - 0
184   - ) ?? 0
185   - )} 元`}
  241 + desp={`${priceToThousands(sumStandardAmount)} 元`}
186 242 />
187 243 <Divider type="vertical" />
188 244 <DetailItem
... ...
src/pages/ehr/PhoneChargeAndSubsidy/subpages/SubsidyConfirm/components/StandardConfirmModal.tsx 0 → 100644
  1 +import React from "react";
  2 +import { useStore } from "../index";
  3 +import { Button, Modal, Popover, Table } from "antd";
  4 +import { formatObjText, priceToThousands } from "@/utils/utils";
  5 +
  6 +export default function SubsidyStandardConfirmModal() {
  7 + const {
  8 + standardConfirmModalInfo,
  9 + setStandardConfirmModalInfo,
  10 + ScopeType,
  11 + ScopeUnit,
  12 + setConfirmModalInfo,
  13 + } = useStore();
  14 + const onCancel = () => setStandardConfirmModalInfo({ open: false });
  15 +
  16 + const staffListClick = (
  17 + item: EHrSubsidyConfirm.StandardVO,
  18 + index: number
  19 + ) => {
  20 + setConfirmModalInfo({
  21 + open: true,
  22 + standard: `${priceToThousands(item.amount ?? 0)} ${
  23 + !item.specialSubsidy
  24 + ? item.amountType === 1
  25 + ? "元/天"
  26 + : item.amountType === 3
  27 + ? "元/月"
  28 + : ""
  29 + : "元/月"
  30 + }`,
  31 + item,
  32 + value: item.staffList,
  33 + onChange(staffList) {
  34 + onItemEdit(index, staffList);
  35 + },
  36 + });
  37 + };
  38 +
  39 + const onItemEdit = (
  40 + index: number,
  41 + staffList: EHrSubsidyConfirm.TypeStaffVO[]
  42 + ) => {
  43 + const changeValues = standardConfirmModalInfo.value?.map((item, i) => {
  44 + if (i === index) {
  45 + const selectedStaffList = staffList?.filter(
  46 + (staff) => staff.selected ?? true
  47 + );
  48 + return {
  49 + ...item,
  50 + staffList,
  51 + staffCnt: selectedStaffList?.length ?? 0,
  52 + standardAmount:
  53 + selectedStaffList?.reduce(
  54 + (amount, staff) => amount + +(staff.standardAmount ?? 0),
  55 + 0
  56 + ) ?? 0,
  57 + realAmount:
  58 + selectedStaffList?.reduce(
  59 + (amount, staff) => amount + +(staff.realAmount ?? 0),
  60 + 0
  61 + ) ?? 0,
  62 + };
  63 + } else {
  64 + return item;
  65 + }
  66 + }) ?? [];
  67 + standardConfirmModalInfo.onChange?.(
  68 + standardConfirmModalInfo.key ?? -1,
  69 + changeValues,
  70 + standardConfirmModalInfo.special
  71 + );
  72 + setTimeout(() => {
  73 + setStandardConfirmModalInfo({
  74 + ...standardConfirmModalInfo,
  75 + value: changeValues,
  76 + });
  77 + });
  78 + };
  79 +
  80 + return (
  81 + <Modal
  82 + title={`补贴确认-${standardConfirmModalInfo.keyName}-补贴标准列表查看`}
  83 + visible={standardConfirmModalInfo.open}
  84 + maskClosable={false}
  85 + width="65%"
  86 + onCancel={onCancel}
  87 + footer={[<Button onClick={onCancel}>关闭</Button>]}
  88 + zIndex={1001}
  89 + >
  90 + <Table
  91 + rowKey={(record, index) => `${record.configId}-${record.specialSubsidy}-${index}`}
  92 + dataSource={standardConfirmModalInfo.value}
  93 + >
  94 + <Table.Column
  95 + title="补贴金额"
  96 + dataIndex="amount"
  97 + align="left"
  98 + render={(amount: number, record: EHrSubsidyConfirm.StandardVO) => (
  99 + <>
  100 + <span>
  101 + {`${priceToThousands(amount)} ${
  102 + !record.specialSubsidy
  103 + ? record.amountType === 1
  104 + ? "元/天"
  105 + : record.amountType === 3
  106 + ? "元/月"
  107 + : ""
  108 + : "元/月"
  109 + }`}
  110 + </span>
  111 + {record.specialSubsidy ? (
  112 + <span
  113 + style={{
  114 + fontSize: 12,
  115 + color: "#FF9625",
  116 + padding: "1px 5px",
  117 + marginLeft: 5,
  118 + borderRadius: 2,
  119 + border: "1px solid #FF9625",
  120 + }}
  121 + >
  122 + 特殊
  123 + </span>
  124 + ) : null}
  125 + </>
  126 + )}
  127 + />
  128 + <Table.Column
  129 + title="适用门店"
  130 + dataIndex="shopList"
  131 + align="left"
  132 + render={(
  133 + shopList: EHrSubsidyConfirm.Shop[],
  134 + record: EHrSubsidyConfirm.StandardVO
  135 + ) => (record.specialSubsidy ? (
  136 + "-"
  137 + ) : record.shopScope === 1 ? (
  138 + "全部门店"
  139 + ) : (
  140 + <Popover
  141 + trigger="click"
  142 + title={`${shopList?.length || 0}个门店`}
  143 + content={
  144 + <div
  145 + style={{
  146 + display: "flex",
  147 + flexWrap: "wrap",
  148 + justifyContent: "flex-start",
  149 + alignItems: "center",
  150 + maxWidth: 400,
  151 + gap: "0 20px",
  152 + }}
  153 + >
  154 + {shopList?.map((shop) => (
  155 + <p key={shop.shopId}>{shop.shopName}</p>
  156 + ))}
  157 + </div>
  158 + }
  159 + >
  160 + <span>
  161 + {formatObjText(shopList, "shopName", 2, "个门店")}
  162 + <a>查看</a>
  163 + </span>
  164 + </Popover>
  165 + ))}
  166 + />
  167 + <Table.Column
  168 + title="适用岗位"
  169 + dataIndex="postList"
  170 + align="left"
  171 + render={(
  172 + postList: EHrSubsidyConfirm.Post[],
  173 + record: EHrSubsidyConfirm.StandardVO
  174 + ) => (record.specialSubsidy ? (
  175 + "-"
  176 + ) : record.postScope === 1 ? (
  177 + "全部岗位"
  178 + ) : (
  179 + <Popover
  180 + trigger="click"
  181 + title={`${postList?.length || 0}个岗位`}
  182 + content={
  183 + <div
  184 + style={{
  185 + display: "flex",
  186 + flexWrap: "wrap",
  187 + justifyContent: "flex-start",
  188 + alignItems: "center",
  189 + maxWidth: 400,
  190 + gap: "0 20px",
  191 + }}
  192 + >
  193 + {postList?.map((post) => (
  194 + <p key={post.postId}>{post.postName}</p>
  195 + ))}
  196 + </div>
  197 + }
  198 + >
  199 + <span>
  200 + {formatObjText(postList, "postName", 2, "个岗位")}
  201 + <a>查看</a>
  202 + </span>
  203 + </Popover>
  204 + ))}
  205 + />
  206 + <Table.Column
  207 + title="适用范围"
  208 + align="left"
  209 + render={(record: EHrSubsidyConfirm.StandardVO) => (record.specialSubsidy ? (
  210 + "-"
  211 + ) : record.scopeStaff ? record.scopeStaff === ScopeType.全部 ? '全部员工' : (
  212 + <span>
  213 + {record.scopeStaff ? ScopeType[record.scopeStaff] : ""}
  214 + {record.scopeStaff !== ScopeType.试用期 && record.scopeStaff !== ScopeType.全部 ? (
  215 + <>
  216 + 时间
  217 + {record.scopeStaffTimeMin ?? ""}-
  218 + {record.scopeStaffTimeMax ?? ""}
  219 + {record.scopeStaffTimeUnit
  220 + ? ScopeUnit[record.scopeStaffTimeUnit]
  221 + : ""}
  222 + </>
  223 + ) : null}
  224 + </span>
  225 + ) : (
  226 + "-"
  227 + ))}
  228 + />
  229 + <Table.Column
  230 + title="补贴人员清单"
  231 + align="left"
  232 + render={(record: EHrSubsidyConfirm.StandardVO, _, index) => (
  233 + <a
  234 + onClick={
  235 + record.staffCnt
  236 + ? () => staffListClick(record, index)
  237 + : undefined
  238 + }
  239 + >
  240 + {record.staffCnt ?? 0} 人
  241 + </a>
  242 + )}
  243 + />
  244 + </Table>
  245 + </Modal>
  246 + );
  247 +}
... ...
src/pages/ehr/PhoneChargeAndSubsidy/subpages/SubsidyConfirm/components/TemporaryMealSubsidyItem.tsx
... ... @@ -2,7 +2,7 @@
2 2 * @Author: wangqiang@feewee.cn
3 3 * @Date: 2023-04-18 15:22:38
4 4 * @LastEditors: wangqiang@feewee.cn
5   - * @LastEditTime: 2023-04-20 14:50:57
  5 + * @LastEditTime: 2023-05-10 10:19:57
6 6 */
7 7 import usePagination from "@/hooks/usePagination";
8 8 import {
... ... @@ -10,13 +10,11 @@ import {
10 10 getSubsidyCanteenStaffListApi,
11 11 } from "@/pages/ehr/PhoneChargeAndSubsidy/subpages/SubsidyConfirm/api";
12 12 import { SubsidyConfirmItemChildrenProps } from "@/pages/ehr/PhoneChargeAndSubsidy/subpages/SubsidyConfirm/components/ConfirmItem";
13   -import { formatObjText, priceToThousands } from "@/utils/utils";
14   -import { checkNull } from "@/utils/validate";
  13 +import { priceToThousands } from "@/utils/utils";
15 14 import {
16 15 Button,
17 16 Divider,
18 17 Form,
19   - Input,
20 18 message,
21 19 Modal,
22 20 Popconfirm,
... ... @@ -25,17 +23,18 @@ import {
25 23 Select,
26 24 Spin,
27 25 Table,
28   - Tag,
29 26 } from "antd";
30   -import { cloneDeepWith } from "lodash";
  27 +import moment from "moment";
31 28 import React, { useEffect, useMemo, useState } from "react";
32 29 import { useStore } from "../index";
  30 +import st from "./style.less";
33 31  
34 32 export default function TemporaryMealSubsidyItem({
35 33 item,
36 34 onItemChange,
37 35 }: SubsidyConfirmItemChildrenProps) {
38   - const { current: currentSubsidyItem, setConfirmModalInfo } = useStore();
  36 + const { current: currentSubsidyItem, setStandardConfirmModalInfo } =
  37 + useStore();
39 38 const canteenPagination = usePagination(getCanteenPageListApi);
40 39 const [open, setOpen] = useState(false);
41 40 const [form] = Form.useForm();
... ... @@ -85,7 +84,7 @@ export default function TemporaryMealSubsidyItem({
85 84 })
86 85 .then((res) => {
87 86 if (res.data) {
88   - res.data.tempStaffList = cloneDeepWith(res.data.staffList);
  87 + res.data.serviceShops = canteenItem?.serviceShops;
89 88 }
90 89 onItemChange({
91 90 ...item,
... ... @@ -105,14 +104,24 @@ export default function TemporaryMealSubsidyItem({
105 104 }
106 105  
107 106 function onStaffClick(canteenItem: EHrSubsidyConfirm.CanteenVo) {
108   - setConfirmModalInfo({
  107 + setStandardConfirmModalInfo({
109 108 open: true,
110 109 key: item.value,
111 110 keyName: item.desc,
112   - value: canteenItem.tempStaffList,
113   - canteenSubsidy: true,
114   - canteenId: canteenItem.canteenId,
115   - onCanteenSubsidyStaffChange,
  111 + attendanceConfigList: canteenItem.attendanceConfigList,
  112 + value: canteenItem.standardList,
  113 + onChange(key, standardList, special?) {
  114 + onItemChange({
  115 + ...item,
  116 + canteenList: item.canteenList?.map((canteen) => ({
  117 + ...canteen,
  118 + standardList:
  119 + canteen.canteenId === canteenItem.canteenId
  120 + ? standardList
  121 + : canteen.standardList,
  122 + })),
  123 + });
  124 + },
116 125 });
117 126 }
118 127  
... ... @@ -204,25 +213,71 @@ export default function TemporaryMealSubsidyItem({
204 213 )}
205 214 />
206 215 <Table.Column
  216 + title="服务门店"
  217 + dataIndex="serviceShops"
  218 + align="left"
  219 + render={(serviceShops: EHrSubsidyConfirm.Shop[]) => (
  220 + <Popover
  221 + trigger="click"
  222 + title={`${serviceShops?.length || 0}个门店`}
  223 + content={
  224 + <div
  225 + style={{
  226 + display: "flex",
  227 + flexWrap: "wrap",
  228 + justifyContent: "flex-start",
  229 + alignItems: "center",
  230 + maxWidth: 400,
  231 + gap: "0 20px",
  232 + }}
  233 + >
  234 + {serviceShops?.map((shop) => (
  235 + <p key={shop.shopId}>{shop.shopName}</p>
  236 + ))}
  237 + </div>
  238 + }
  239 + >
  240 + <span>
  241 + {serviceShops
  242 + ?.slice(0, 3)
  243 + .map((shop) => shop.shopName)
  244 + .join(",")}
  245 + {serviceShops?.length && serviceShops.length > 3 ? (
  246 + <>
  247 + 等{serviceShops.length}个门店
  248 + <a>查看</a>
  249 + </>
  250 + ) : (
  251 + ""
  252 + )}
  253 + </span>
  254 + </Popover>
  255 + )}
  256 + />
  257 + <Table.Column
207 258 title="相关员工"
208   - dataIndex="staffList"
  259 + dataIndex="standardList"
209 260 align="left"
210 261 render={(
211   - staffList: EHrSubsidyConfirm.TypeStaffVO[],
  262 + standardList: EHrSubsidyConfirm.StandardVO[],
212 263 record: EHrSubsidyConfirm.CanteenVo
213 264 ) => (
214 265 <a onClick={() => onStaffClick(record)}>
215   - {staffList?.length ?? "-"}人
  266 + {standardList?.reduce(
  267 + (count, standard) => count + (standard.staffCnt ?? 0),
  268 + 0
  269 + ) ?? "-"}
  270 + 人
216 271 </a>
217 272 )}
218 273 />
219 274 <Table.Column
220 275 title="合计补贴金额"
221   - dataIndex="staffList"
  276 + dataIndex="standardList"
222 277 align="left"
223   - render={(staffList: EHrSubsidyConfirm.TypeStaffVO[]) => priceToThousands(
224   - staffList?.reduce(
225   - (amount, staff) => amount + +(staff.realAmount ?? 0),
  278 + render={(standardList: EHrSubsidyConfirm.StandardVO[]) => priceToThousands(
  279 + standardList?.reduce(
  280 + (amount, standard) => amount + +(standard.realAmount ?? 0),
226 281 0
227 282 )
228 283 )}
... ... @@ -287,7 +342,7 @@ export default function TemporaryMealSubsidyItem({
287 342 name="timeList"
288 343 rules={[{ required: true, message: "请输入该月无法就餐日期" }]}
289 344 >
290   - <CanteenDateItem />
  345 + <CanteenDateItem monthDate={currentSubsidyItem?.monthDate} />
291 346 </Form.Item>
292 347 </Form>
293 348 </Spin>
... ... @@ -296,98 +351,49 @@ export default function TemporaryMealSubsidyItem({
296 351 );
297 352 }
298 353  
299   -function getDaysInMonth(timestamp: number) {
300   - const date = new Date(timestamp);
301   - return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();
302   -}
303   -
304 354 interface CanteenDateItemProps {
  355 + monthDate?: number;
305 356 value?: number[];
306 357 onChange?: (value?: number[]) => void;
307 358 }
308 359  
309   -function CanteenDateItem({ value, onChange }: CanteenDateItemProps) {
310   - const { current } = useStore();
311   - const [inputVal, setInputVal] = useState<string>();
312   - const monthDays = current?.monthDate
313   - ? getDaysInMonth(current?.monthDate)
314   - : 30;
  360 +function CanteenDateItem({ monthDate, value, onChange }: CanteenDateItemProps) {
  361 + const weekdays = moment.weekdaysShort();
  362 + const daysInMonth = moment(monthDate).daysInMonth();
  363 + const days = Array.from({ length: daysInMonth }, (_, i) => i + 1);
  364 + const firstWeekIndex = moment(monthDate).startOf("month").day();
315 365  
316   - function del(index: number) {
317   - onChange?.(value?.filter((_, i) => i !== index));
318   - }
319   -
320   - const add = () => {
321   - if (!inputVal) {
322   - message.error("请输入相关内容");
323   - setInputVal(undefined);
324   - return;
325   - }
326   - if (!checkInputVal1(inputVal)) {
327   - message.error(`请输入大于0小于等于${monthDays}的整数`);
328   - return;
329   - }
330   - if (value?.includes(+inputVal)) {
331   - message.error(`已输入【${inputVal}】号,请更改!`);
332   - return;
333   - }
334   - onChange?.((value ?? []).concat(+inputVal).sort((a, b) => a - b));
335   - setInputVal(undefined);
336   - };
337   -
338   - const checkInputVal1 = (inputVal?: string): boolean => {
339   - if (checkNull(inputVal)) return true; // 输入为 undefined,不判断,返回 true
340   - if (inputVal) {
341   - if (/^(\d)+$/g.test(inputVal)) {
342   - return +inputVal >= 1 && +inputVal <= monthDays;
343   - } else {
344   - return false;
345   - }
  366 + function handleDateClick(date: number) {
  367 + const item = value?.find((v) => v === date);
  368 + if (item) {
  369 + onChange?.(value?.filter((v) => v !== date));
346 370 } else {
347   - return false;
  371 + onChange?.((value ?? []).concat(date));
348 372 }
349   - };
  373 + }
350 374  
351 375 return (
352   - <div
353   - style={{
354   - display: "flex",
355   - flexDirection: "column",
356   - justifyContent: "flex-start",
357   - alignItems: "flex-start",
358   - }}
359   - >
360   - <div
361   - style={{
362   - display: "flex",
363   - flexDirection: "row",
364   - flexWrap: "wrap",
365   - }}
366   - >
367   - {value?.map((item, index) => (
368   - <Tag
369   - style={{ marginBottom: 5 }}
370   - key={item}
371   - closable
372   - onClose={() => del(index)}
  376 + <>
  377 + <div className={st.month}>{moment(monthDate).format("YYYY-MM")}</div>
  378 + <div className={st.datePicker}>
  379 + {weekdays.map((day) => (
  380 + <div key={day} className={st.weekDay}>
  381 + {day}
  382 + </div>
  383 + ))}
  384 + {Array.from({ length: firstWeekIndex }).map((_) => (
  385 + <div className={`${st.date} ${st.empty}`} />
  386 + ))}
  387 + {days.map((date) => (
  388 + <div
  389 + key={date}
  390 + className={`${st.date} ${value?.includes(date) ? st.selected : ""}`}
  391 + onClick={() => handleDateClick(date)}
373 392 >
374   - {item} 号
375   - </Tag>
  393 + {date}
  394 + </div>
376 395 ))}
377 396 </div>
378   - <Input
379   - value={inputVal}
380   - onChange={(e) => setInputVal(e.target.value)}
381   - allowClear
382   - placeholder="请输入当前操作月份的几号,并按回车键添加"
383   - suffix={
384   - <Button type="link" onClick={() => add()}>
385   - 添加
386   - </Button>
387   - }
388   - style={{ width: 350, marginTop: 10 }}
389   - onPressEnter={() => add()}
390   - />
391   - </div>
  397 + </>
392 398 );
393 399 }
... ...
src/pages/ehr/PhoneChargeAndSubsidy/subpages/SubsidyConfirm/components/style.less 0 → 100644
  1 +.month {
  2 + padding: 8px 0;
  3 + text-align: center;
  4 +}
  5 +
  6 +.datePicker {
  7 + display: grid;
  8 + grid-template-rows: auto repeat(6, 1fr);
  9 + grid-template-columns: repeat(7, 1fr);
  10 + gap: 4px;
  11 + padding: 8px;
  12 + color: #333;
  13 + font-size: 14px;
  14 + background-color: #fff;
  15 + border: 1px solid #d9d9d9;
  16 + border-radius: 2px;
  17 +
  18 + .weekDay {
  19 + height: 40px;
  20 + line-height: 40px;
  21 + color: #999;
  22 + font-weight: 500;
  23 + font-size: 12px;
  24 + text-align: center;
  25 + }
  26 +
  27 + .date {
  28 + display: flex;
  29 + flex-direction: column;
  30 + align-items: center;
  31 + justify-content: center;
  32 + height: 40px;
  33 + background-color: #fff;
  34 + border: 1px solid #d9d9d9;
  35 + border-radius: 2px;
  36 + cursor: pointer;
  37 + transition: all 0.3s ease;
  38 +
  39 + &:hover {
  40 + background-color: #f5f5f5;
  41 + }
  42 +
  43 + &.empty {
  44 + border: none;
  45 + }
  46 +
  47 + &.selected {
  48 + color: #fff;
  49 + background-color: #1890ff;
  50 + border-color: #1890ff;
  51 + }
  52 +
  53 + &.disabled {
  54 + color: #ccc;
  55 + pointer-events: none;
  56 + }
  57 + }
  58 +}
... ...
src/pages/ehr/PhoneChargeAndSubsidy/subpages/SubsidyConfirm/index.tsx
  1 +/*
  2 + * @Author: wangqiang@feewee.cn
  3 + * @Date: 2023-04-11 09:52:57
  4 + * @LastEditors: wangqiang@feewee.cn
  5 + * @LastEditTime: 2023-05-09 10:59:23
  6 + */
1 7 import React from "react";
2 8 import { Card, ConfigProvider } from "antd";
3 9 import zhCN from "antd/lib/locale-provider/zh_CN";
... ... @@ -7,6 +13,7 @@ import List from &quot;./components/List&quot;;
7 13 import Modal from "./components/Modal";
8 14 import ApprovalProgressModal from "./components/ApprovalProgressModal";
9 15 import ConfirmModal from "./components/ConfirmModal";
  16 +import StandardConfirmModal from "./components/StandardConfirmModal";
10 17 import { createStore } from "@/hooks/moz";
11 18 import store from "./store";
12 19  
... ... @@ -22,6 +29,7 @@ function SubsidyConfirm() {
22 29 <Modal />
23 30 <ApprovalProgressModal />
24 31 <ConfirmModal />
  32 + <StandardConfirmModal />
25 33 </Card>
26 34 </ConfigProvider>
27 35 </PageHeaderWrapper>
... ...
src/pages/ehr/PhoneChargeAndSubsidy/subpages/SubsidyConfirm/interface.d.ts
... ... @@ -2,7 +2,7 @@
2 2 * @Author: wangqiang@feewee.cn
3 3 * @Date: 2023-03-13 09:12:25
4 4 * @LastEditors: wangqiang@feewee.cn
5   - * @LastEditTime: 2023-04-27 15:47:54
  5 + * @LastEditTime: 2023-05-09 15:14:30
6 6 */
7 7 declare namespace EHrSubsidyConfirm {
8 8 interface QueryParams {
... ... @@ -15,7 +15,7 @@ declare namespace EHrSubsidyConfirm {
15 15 id?: number;
16 16 monthDate?: number; // 月度
17 17 shopId?: number;
18   - shopName?: string;
  18 + shopList?: string[];
19 19 status?: number; // 1未确认 2待审批 3审批拒绝 4审批通过 5审批撤销
20 20 auditNo?: string; // 审批编码
21 21 }
... ... @@ -34,6 +34,37 @@ declare namespace EHrSubsidyConfirm {
34 34 desc?: string;
35 35 staffList?: TypeStaffVO[]; // 人员列表
36 36 canteenList?: CanteenVo[]; // 食堂列表
  37 + attendanceConfigList?: EHrSubsidySetting.AttendanceConfigEnum[]; // 考勤配置
  38 + standardList?: StandardVO[]; // 补贴标准列表
  39 + }
  40 +
  41 + interface StandardVO {
  42 + specialSubsidy?: true; // 是否特殊补贴
  43 + amount?: number; // 补贴金额
  44 + amountType?: number; // 补贴金额类型 1 元/日 3 元/月
  45 + shopScope?: number; // 门店范围 1全部 2部分
  46 + shopList?: Shop[]; // 门店范围
  47 + postScope?: number; // 岗位范围 1全部 2部分
  48 + postList?: Post[]; // 岗位范围
  49 + scopeStaff?: number; // 范围人员 1 入职 2 转正 3 试用期 4 全部
  50 + scopeStaffTimeMax?: number; // 范围人员时间
  51 + scopeStaffTimeUnit?: number; // 范围人员时间单位 3 月 4 年
  52 + scopeStaffTimeMin?: number; // 范围人员时间条件 起始时间
  53 + staffList?: TypeStaffVO[];
  54 + configId?: number;
  55 + staffCnt?: number; // 人员数量
  56 + realAmount?: number; // 实际补贴金额
  57 + standardAmount?: number; // 应补贴金额
  58 + }
  59 +
  60 + interface Shop {
  61 + shopId?: number;
  62 + shopName?: string;
  63 + }
  64 +
  65 + interface Post {
  66 + postId?: number;
  67 + postName?: string;
37 68 }
38 69  
39 70 interface CanteenVo {
... ... @@ -45,6 +76,9 @@ declare namespace EHrSubsidyConfirm {
45 76 shopList?: number[]; // 食堂关联门店ID
46 77 timeList?: number[]; // 不就餐日期列表
47 78 staffList?: TypeStaffVO[]; // 食堂就餐人员列表
  79 + serviceShops?: Shop[]; // 服务门店列表
  80 + attendanceConfigList?: EHrSubsidySetting.AttendanceConfigEnum[]; // 考勤配置
  81 + standardList?: StandardVO[]; // 补贴标准列表
48 82 tempStaffList?: TypeStaffVO[]; // 用于前端展示
49 83 }
50 84  
... ... @@ -65,10 +99,7 @@ declare namespace EHrSubsidyConfirm {
65 99 operationWay?: number;
66 100 repastCountWay?: any;
67 101 repastWay?: any;
68   - serviceShops?: {
69   - shopId?: number;
70   - shopName?: string;
71   - }[];
  102 + serviceShops?: Shop[]; // 服务门店列表
72 103 stmtShop?: any;
73 104 thirdpartyId?: any;
74 105 thirdpartyName?: any;
... ... @@ -101,5 +132,13 @@ declare namespace EHrSubsidyConfirm {
101 132 remark?: string; // 备注
102 133 // 前端校验
103 134 selected?: boolean;
  135 + configId?: number; // 补贴ID
  136 + scopeType?: number; // 配置范围类型 1门店岗位 2人员 后端校验使用
  137 + entryDays?: number; // 入职天数
  138 + leaveDate?: number; // 离职时间
  139 + changeList?: {
  140 + standardAmount?: number; // 标准金额
  141 + changeTime?: number; // 变更时间
  142 + }[]; // 岗位变动对应标准
104 143 }
105 144 }
... ...
src/pages/ehr/PhoneChargeAndSubsidy/subpages/SubsidyConfirm/store.ts
... ... @@ -40,17 +40,30 @@ export default function useStore() {
40 40 const [open, setOpen] = useState(false);
41 41 const [approvalProgressModalInfo, setApprovalProgressModalInfo] =
42 42 useState<PublicNotice.ApprovalProgressModalInfo>({ visible: false });
43   - const [confirmModalInfo, setConfirmModalInfo] = useState<{
  43 + const [standardConfirmModalInfo, setStandardConfirmModalInfo] = useState<{
44 44 open: boolean;
45 45 key?: number; // 补贴类型编辑
46 46 keyName?: string;
47 47 special?: boolean; // 是否特殊补贴编辑
48   - value?: EHrSubsidyConfirm.TypeStaffVO[];
  48 + attendanceConfigList?: EHrSubsidySetting.AttendanceConfigEnum[]; // 考勤配置
  49 + value?: EHrSubsidyConfirm.StandardVO[];
49 50 onChange?:(
50 51 key: number,
51   - staffList: EHrSubsidyConfirm.TypeStaffVO[],
  52 + standardList: EHrSubsidyConfirm.StandardVO[],
52 53 special?: boolean
53 54 ) => void;
  55 + }>({
  56 + open: false,
  57 + });
  58 + const [confirmModalInfo, setConfirmModalInfo] = useState<{
  59 + open: boolean;
  60 + key?: number; // 补贴类型编辑
  61 + keyName?: string;
  62 + special?: boolean; // 是否特殊补贴编辑
  63 + standard?: string; // 补贴标准str
  64 + item?: EHrSubsidyConfirm.StandardVO;
  65 + value?: EHrSubsidyConfirm.TypeStaffVO[];
  66 + onChange?:(staffList: EHrSubsidyConfirm.TypeStaffVO[]) => void;
54 67 canteenSubsidy?: boolean; // 是否临时餐补查看编辑补贴人员信息
55 68 canteenId?: number; // 食堂ID
56 69 onCanteenSubsidyStaffChange?: (
... ... @@ -61,6 +74,18 @@ export default function useStore() {
61 74 open: false,
62 75 });
63 76  
  77 + enum ScopeType {
  78 + "入职" = 1,
  79 + "转正",
  80 + "试用期",
  81 + "全部"
  82 + }
  83 +
  84 + enum ScopeUnit {
  85 + 月 = 3,
  86 + 年 = 4,
  87 + }
  88 +
64 89 return {
65 90 Status,
66 91 StatusList,
... ... @@ -72,7 +97,11 @@ export default function useStore() {
72 97 setOpen,
73 98 approvalProgressModalInfo,
74 99 setApprovalProgressModalInfo,
  100 + standardConfirmModalInfo,
  101 + setStandardConfirmModalInfo,
75 102 confirmModalInfo,
76 103 setConfirmModalInfo,
  104 + ScopeType,
  105 + ScopeUnit,
77 106 };
78 107 }
... ...
src/pages/ehr/PhoneChargeAndSubsidy/subpages/SubsidySettings/components/List.tsx
... ... @@ -2,9 +2,13 @@
2 2 * @Author: wangqiang@feewee.cn
3 3 * @Date: 2023-02-15 17:42:54
4 4 * @LastEditors: wangqiang@feewee.cn
5   - * @LastEditTime: 2023-04-25 17:57:52
  5 + * @LastEditTime: 2023-05-11 11:40:29
6 6 */
7   -import { formatObjText, priceToThousands } from "@/utils/utils";
  7 +import {
  8 + formatObjText,
  9 + priceToThousands,
  10 + formatArrayText,
  11 +} from "@/utils/utils";
8 12 import { Divider, Popconfirm, Popover, Table } from "antd";
9 13 import React from "react";
10 14 import { useStore } from "../index";
... ... @@ -75,7 +79,7 @@ export default function SubsidySettingsList() {
75 79 >
76 80 <span>
77 81 {formatObjText(shopList, "shopName", 2, "个门店")}
78   - <a>查看</a>
  82 + {shopList.length > 2 ? <a>查看</a> : null}
79 83 </span>
80 84 </Popover>
81 85 ))}
... ... @@ -112,7 +116,7 @@ export default function SubsidySettingsList() {
112 116 >
113 117 <span>
114 118 {formatObjText(postList, "postName", 2, "个岗位")}
115   - <a>查看</a>
  119 + {postList.length > 2 ? <a>查看</a> : null}
116 120 </span>
117 121 </Popover>
118 122 ))}
... ... @@ -124,7 +128,7 @@ export default function SubsidySettingsList() {
124 128 render={(record: EHrSubsidySetting.List) => (record.scopeStaff ? (
125 129 <span>
126 130 {record.scopeStaff ? ScopeType[record.scopeStaff] : ""}
127   - {record.scopeStaff !== 3 ? (
  131 + {record.scopeStaff !== 3 && record.scopeStaff !== 4 ? (
128 132 <>
129 133 时间
130 134 {record.scopeStaffTimeMin ?? ""}-
... ... @@ -140,6 +144,42 @@ export default function SubsidySettingsList() {
140 144 ))}
141 145 />
142 146 )}
  147 + {pagination.innerParams.type === 2 ? (
  148 + <Table.Column
  149 + title="适用民族"
  150 + dataIndex="nationNameList"
  151 + align="left"
  152 + render={(nationNameList?: string[]) => (!nationNameList?.length ? (
  153 + "-"
  154 + ) : (
  155 + <Popover
  156 + trigger="click"
  157 + title={`${nationNameList?.length || 0}个民族`}
  158 + content={
  159 + <div
  160 + style={{
  161 + display: "flex",
  162 + flexWrap: "wrap",
  163 + justifyContent: "flex-start",
  164 + alignItems: "center",
  165 + maxWidth: 400,
  166 + gap: "0 20px",
  167 + }}
  168 + >
  169 + {nationNameList?.map((nation) => (
  170 + <p key={nation}>{nation}</p>
  171 + ))}
  172 + </div>
  173 + }
  174 + >
  175 + <span>
  176 + {formatArrayText(nationNameList, 4, "个民族")}
  177 + {nationNameList.length > 4 ? <a>查看</a> : null}
  178 + </span>
  179 + </Popover>
  180 + ))}
  181 + />
  182 + ) : null}
143 183 <Table.Column
144 184 title="符合补贴人员清单"
145 185 align="left"
... ...
src/pages/ehr/PhoneChargeAndSubsidy/subpages/SubsidySettings/components/Modal.tsx
... ... @@ -17,6 +17,7 @@ export default function SubsidySettingsModal() {
17 17 pagination,
18 18 subsidyTypeList,
19 19 postInitial,
  20 + nationInitial,
20 21 } = useStore();
21 22 const { setLoading } = pagination;
22 23 const [form] = Form.useForm();
... ... @@ -104,6 +105,7 @@ export default function SubsidySettingsModal() {
104 105 scopeStaffTimeUnit: val.scope?.unit,
105 106 scopeStaffTimeMin: val.scope?.min,
106 107 scopeStaffTimeMax: val.scope?.max,
  108 + nationList: val.nationList,
107 109 };
108 110 saveSubsidySettingApi(params)
109 111 .then((res) => {
... ... @@ -229,11 +231,23 @@ export default function SubsidySettingsModal() {
229 231 // return Promise.reject(Error("请选择适用范围"));
230 232 } else if (!value.type) {
231 233 return Promise.reject(Error("请选择适用范围类型"));
232   - } else if (value.type !== 3 && checkNull(value.min)) {
  234 + } else if (
  235 + value.type !== 3 &&
  236 + value.type !== 4 &&
  237 + checkNull(value.min)
  238 + ) {
233 239 return Promise.reject(Error("请选择适用范围开始时间"));
234   - } else if (value.type !== 3 && checkNull(value.max)) {
  240 + } else if (
  241 + value.type !== 3 &&
  242 + value.type !== 4 &&
  243 + checkNull(value.max)
  244 + ) {
235 245 return Promise.reject(Error("请选择适用范围结束时间"));
236   - } else if (value.type !== 3 && !value.unit) {
  246 + } else if (
  247 + value.type !== 3 &&
  248 + value.type !== 4 &&
  249 + !value.unit
  250 + ) {
237 251 return Promise.reject(Error("请选择适用范围时间单位"));
238 252 } else {
239 253 return Promise.resolve();
... ... @@ -246,6 +260,23 @@ export default function SubsidySettingsModal() {
246 260 <Scope />
247 261 </Form.Item>
248 262 )}
  263 + {pagination.innerParams.type === 2 ? (
  264 + <Form.Item name="nationList" label="适用民族">
  265 + <Select
  266 + allowClear
  267 + placeholder="请选择适用民族"
  268 + showSearch
  269 + optionFilterProp="children"
  270 + mode="multiple"
  271 + >
  272 + {nationInitial.data.map((nation) => (
  273 + <Select.Option key={nation.value} value={nation.value}>
  274 + {nation.desc}
  275 + </Select.Option>
  276 + ))}
  277 + </Select>
  278 + </Form.Item>
  279 + ) : null}
249 280 </Form>
250 281 </Modal>
251 282 );
... ...
src/pages/ehr/PhoneChargeAndSubsidy/subpages/SubsidySettings/components/Scope.tsx
... ... @@ -2,7 +2,7 @@
2 2 * @Author: wangqiang@feewee.cn
3 3 * @Date: 2023-04-13 10:02:12
4 4 * @LastEditors: wangqiang@feewee.cn
5   - * @LastEditTime: 2023-04-21 17:46:58
  5 + * @LastEditTime: 2023-05-11 11:43:23
6 6 */
7 7 import {
8 8 Radio,
... ... @@ -40,6 +40,9 @@ export default function Scope({ value, onChange }: Props) {
40 40 onChange={(e) => onChange?.({ ...value, type: e.target.value })}
41 41 style={{ marginBottom: 10 }}
42 42 >
  43 + <Radio key={4} value={4}>
  44 + 全部
  45 + </Radio>
43 46 <Radio key={2} value={2}>
44 47 转正
45 48 </Radio>
... ... @@ -50,7 +53,7 @@ export default function Scope({ value, onChange }: Props) {
50 53 试用期
51 54 </Radio>
52 55 </Radio.Group>
53   - {!value?.type || value?.type === 3 ? null : (
  56 + {!value?.type || value?.type === 3 || value?.type === 4 ? null : (
54 57 <Space>
55 58 <span>{value?.type ? ScopeType[value.type] : ""}时间</span>
56 59 <InputNumber
... ...
src/pages/ehr/PhoneChargeAndSubsidy/subpages/SubsidySettings/interface.d.ts
... ... @@ -35,6 +35,8 @@ declare namespace EHrSubsidySetting {
35 35 scopeStaffTimeUnit?: number; // 范围人员时间单位 3月 4年
36 36 scopeStaffTimeMax?: number; // 范围人员时间
37 37 scopeStaffTimeMin?: number; // 范围人员时间条件起始值
  38 + nationList?: number[];
  39 + nationNameList?: string[];
38 40 }
39 41  
40 42 interface Shop {
... ...
src/pages/ehr/PhoneChargeAndSubsidy/subpages/SubsidySettings/store.ts
... ... @@ -2,7 +2,7 @@
2 2 * @Author: wangqiang@feewee.cn
3 3 * @Date: 2023-02-15 15:20:15
4 4 * @LastEditors: wangqiang@feewee.cn
5   - * @LastEditTime: 2023-04-21 16:17:11
  5 + * @LastEditTime: 2023-05-11 11:42:53
6 6 */
7 7 import usePagination from "@/hooks/usePagination";
8 8 import {
... ... @@ -16,6 +16,7 @@ import { message } from &quot;antd&quot;;
16 16 import { SplitKey } from "@/pages/notice/PublicRelease/entity";
17 17 import useInitial from "@/hooks/useInitail";
18 18 import { getPostListByShopIdsApi } from "@/common/api";
  19 +import useNationList from '@/pages/ehr/hooks/useNationList';
19 20  
20 21 export default function useStore() {
21 22 const subsidyType = useSubsidyTypeList();
... ... @@ -34,11 +35,13 @@ export default function useStore() {
34 35 }>({
35 36 visible: false,
36 37 });
  38 + const nationInitial = useNationList();
37 39  
38 40 enum ScopeType {
39 41 "入职" = 1,
40 42 "转正",
41   - "试用期"
  43 + "试用期员工",
  44 + "全部员工",
42 45 }
43 46  
44 47 enum ScopeUnit {
... ... @@ -118,5 +121,6 @@ export default function useStore() {
118 121 staffModal,
119 122 setStaffModal,
120 123 getStaffList,
  124 + nationInitial,
121 125 };
122 126 }
... ...
src/pages/ehr/hooks/useNationList.tsx 0 → 100644
  1 +/*
  2 + * @Author: wangqiang@feewee.cn
  3 + * @Date: 2023-05-11 11:03:57
  4 + * @LastEditors: wangqiang@feewee.cn
  5 + * @LastEditTime: 2023-05-11 11:05:53
  6 + */
  7 +import { getNationListApi } from "@/components/MemberSelectNew/api";
  8 +import useInitial from "@/hooks/useInitail";
  9 +
  10 +export default function useNationList(delay?: boolean) {
  11 + return useInitial(getNationListApi, [], undefined, delay);
  12 +}
... ...
src/utils/utils.ts
... ... @@ -32,6 +32,25 @@ const isAntDesignProOrDev = (): boolean =&gt; {
32 32  
33 33 export { isAntDesignProOrDev, isAntDesignPro, isUrl };
34 34  
  35 +export function formatArrayText(
  36 + list: string[],
  37 + maxCount: number = 2,
  38 + unit: string = "人"
  39 +): string {
  40 + if (!list || (list && !list.length)) return "-";
  41 + else {
  42 + let result = "";
  43 + if (list.length > maxCount) {
  44 + const array = list.slice(0, maxCount);
  45 + result = array.map((item) => item).join("、");
  46 + result += `等 ${list.length} ${unit}`;
  47 + } else {
  48 + result += list.map((item) => item).join("、");
  49 + }
  50 + return result;
  51 + }
  52 +}
  53 +
35 54 export function formatObjText<T>(
36 55 list: T[],
37 56 formatKey: keyof T,
... ...