Commit 44417aca75a383c50ec72e362eea874bef3769db

Authored by 王强
2 parents 19326b63 1cf36756

Merge remote-tracking branch 'origin/master' into ehr

Showing 23 changed files with 633 additions and 72 deletions
config/routers/finance.ts
... ... @@ -168,7 +168,7 @@ export default [
168 168 path: '/finance2/poundageConfig/posAuth', //pos机授权
169 169 component: './finance/PoundageConfig/POSAuth',
170 170 },
171   -
  171 +
172 172 {
173 173 path: '/finance2/financeInvestor', //投资主体(旧)
174 174 component: './finance/FinanceInvestor',
... ... @@ -254,7 +254,7 @@ export default [
254 254 component: './finance/PayDataImport/EditComfirm/index',
255 255 },
256 256  
257   - //款项归属配置
  257 + //款项归属配置
258 258 {
259 259 path: '/finance2/allocationOfFunds',
260 260 component: './finance/AllocationOfFunds',
... ... @@ -263,4 +263,8 @@ export default [
263 263 path: '/finance2/kt/itemamount/config', //事项款设置
264 264 component: './contract/ItemAmountSetting',
265 265 },
  266 + {
  267 + path: '/finance2/proactiveReimbursement', //主动报销款项配置
  268 + component: './finance/proactiveReimbursement',
  269 + },
266 270 ];
... ...
src/pages/approval/ApprovalSetting/api.ts
... ... @@ -53,7 +53,7 @@ export function getPreconditionTypes(): http.PromiseResp<ApprovalSetting.Option[
53 53  
54 54 export interface GetCanApproveRolesReq {
55 55 configuredRoleCodes?: string;
56   - shopBizTypes?: string;
  56 + // shopBizTypes?: string; // 审批配置(霏微配置)不传此参数
57 57 }
58 58 /**
59 59 * 查询所有角色列表
... ...
src/pages/approval/ApprovalSetting/subpages/components/CommonSettingForm.tsx
1 1 import React, { useEffect, useState } from 'react';
2 2 import { Button, Form, InputNumber, Modal, Popconfirm, Radio, Row, Space, Table } from 'antd';
3 3 import { PlusOutlined } from '@ant-design/icons';
4   -import SelectorWithFull from '@/components/SelectorWithFull';
5 4 import { getCanApproveRoles } from '@/pages/approval/ApprovalSetting/api';
6 5 import _ from 'lodash';
7 6 import { geneRandomNum } from '@/utils/tools';
8 7 import { useRequest } from 'umi';
9 8 import { getRolesByGroup } from '@/pages/approval/FlowSetting/api';
  9 +import { ApprovalRolesSelector } from './Selectors';
10 10  
11 11 const { Column } = Table;
12 12  
... ... @@ -257,7 +257,7 @@ export default function CommonSettingForm({ small = false, shopBizTypes, roles,
257 257 >
258 258 <Form form={roleForm}>
259 259 <Form.Item name="role" rules={[{ required: true, message: '请选择至少一个审批角色' }]}>
260   - <SelectorWithFull
  260 + {/* <SelectorWithFull
261 261 showSearch
262 262 treeNodeFilterProp="label"
263 263 maxTagCount={100}
... ... @@ -272,6 +272,16 @@ export default function CommonSettingForm({ small = false, shopBizTypes, roles,
272 272 });
273 273 }}
274 274 data={roleList.map((item) => ({ key: item.roleCode, value: item.roleCode, label: item.roleName }))}
  275 + /> */}
  276 + <ApprovalRolesSelector
  277 + value={current.roles?.map((item) => ({ key: item.roleCode, value: item.roleCode, label: item.roleName }))}
  278 + list={roleList}
  279 + onChange={(value) => {
  280 + setCurrent({
  281 + ...current,
  282 + roles: value.map((item: ApprovalSetting.Option) => ({ roleCode: item.value, roleName: item.label })),
  283 + });
  284 + }}
275 285 />
276 286 </Form.Item>
277 287 </Form>
... ...
src/pages/approval/ApprovalSetting/subpages/components/DefaultFlowNewOrEdit.tsx
... ... @@ -191,6 +191,10 @@ export default function DefaultSettingNewOrEdit(props: Props) {
191 191 const clearRoles = (newCondVals: ApprovalSetting.ConditionVal[]) => {
192 192 const oldShopBizTypes = [...shopBizTypes];
193 193 const newShopBizTypes = getShopBizTypes(newCondVals);
  194 + if (newShopBizTypes.length === 1 && newShopBizTypes[0] === -1) {
  195 + // 【全部门店】时不清空审批角色
  196 + return;
  197 + }
194 198 oldShopBizTypes.forEach((i) => {
195 199 if (!newShopBizTypes.includes(i)) {
196 200 // 清空已添加审批角色列表
... ...
src/pages/approval/ApprovalSetting/subpages/components/Selectors/ApprovalRolesSelector.tsx 0 → 100644
  1 +import React, { useState } from 'react';
  2 +import SelectorWithFull from '@/components/SelectorWithFull';
  3 +import type { LabeledValue } from 'antd/lib/select';
  4 +
  5 +interface Props {
  6 + value: any;
  7 + list: CommonApi.RoleCodeVO[];
  8 + onChange: (value: any) => void;
  9 +}
  10 +
  11 +// 审批角色
  12 +export const ApprovalRolesSelector = ({ value = [], list, onChange }: Props) => {
  13 + const [searchValue, setSearchValue] = useState('');
  14 +
  15 + const getFilteredData = () => {
  16 + const oriOptions = list.map((item) => ({ key: item.roleCode, value: item.roleCode, label: item.roleName }));
  17 + if (searchValue.trim() === '') {
  18 + return oriOptions;
  19 + }
  20 + return oriOptions.filter((i) => i.label!.toString().toLowerCase().includes(searchValue.trim().toLowerCase()));
  21 + };
  22 +
  23 + const handleSelect = (_: LabeledValue, option: any) => {
  24 + const oriNames = value.length > 0 ? value.map((i: any) => i.label) : [];
  25 + // value 更新为异步,需手动拼接最新选择值以判断当前筛选值是否已被勾选完
  26 + oriNames.push(option.label);
  27 + const valueMatchArr = oriNames.filter((i: string) => i.toLowerCase().includes(searchValue.trim().toLowerCase()));
  28 + const filteredData = getFilteredData();
  29 + if (valueMatchArr.length === filteredData.length) {
  30 + setSearchValue('');
  31 + }
  32 + };
  33 +
  34 + return (
  35 + <SelectorWithFull
  36 + showSearch
  37 + searchValue={searchValue}
  38 + onSearch={(value) => {
  39 + setSearchValue(value);
  40 + }}
  41 + onSelect={handleSelect}
  42 + treeNodeFilterProp="label"
  43 + maxTagCount={100}
  44 + labelInValue
  45 + value={value}
  46 + multiple
  47 + placeholder="请选择角色或输入关键字筛选"
  48 + onChange={onChange}
  49 + data={list.map((item) => ({ key: item.roleCode, value: item.roleCode, label: item.roleName }))}
  50 + />
  51 + );
  52 +};
... ...
src/pages/approval/ApprovalSetting/subpages/components/Selectors/index.ts
... ... @@ -16,3 +16,4 @@ export { BizTypeSelector } from &#39;./BizTypeSelector&#39;;
16 16 export { ShopBizTypeSelector } from './ShopBizTypeSelector';
17 17 export { OfficeWordTypeSelector } from './OfficeWordTypeSelector';
18 18 export { ContractTypeSelector } from './ContractTypeSelector';
  19 +export { ApprovalRolesSelector } from './ApprovalRolesSelector';
... ...
src/pages/approval/FlowSetting/api.ts
... ... @@ -201,7 +201,7 @@ export function getIndicatorList(params: any): http.PromiseResp&lt;IndicatorItem[]&gt;
201 201  
202 202 export interface GetRolesByGroupReq {
203 203 configuredRoleCodes?: string;
204   - shopBizTypes?: string;
  204 + shopBizTypes?: string; // 为空:全业态角色;-1:全业态角色+特定业态角色
205 205 }
206 206  
207 207 /**
... ...
src/pages/approval/FlowSetting/components/PostsSelectorByAll.tsx
... ... @@ -7,23 +7,15 @@ import usePagination from &#39;@/hooks/usePagination&#39;;
7 7 interface Props {
8 8 value?: LabelInValueType[];
9 9 onChange?: (value: LabelInValueType[]) => void;
10   - disabled?: boolean;
11   - disabledTip?: string;
12 10 defaultTip?: string;
13 11 style?: React.CSSProperties;
14 12 }
15 13  
16   -export default function PostsSelectorByAll({
17   - value = [],
18   - onChange,
19   - disabled = false,
20   - disabledTip = '请选择岗位',
21   - defaultTip = '请选择岗位',
22   - style,
23   -}: Props) {
  14 +export default function PostsSelectorByAll({ value = [], onChange, defaultTip = '请选择发起人岗位或输入关键字筛选', style }: Props) {
24 15 const [delay, setDelay] = useState(true);
25 16 const [postList, setPostList] = useState<any[]>([]);
26 17 const { list, setParams, loading } = usePagination(getPost, {}, { delay });
  18 + const [searchValue, setSearchValue] = useState('');
27 19  
28 20 useEffect(() => {
29 21 if (list && list.length > 0) {
... ... @@ -40,9 +32,38 @@ export default function PostsSelectorByAll({
40 32 setDelay(false);
41 33 }, []);
42 34  
  35 + const getFilteredData = () => {
  36 + const oriOptions = postList.map((item) => ({ key: item.id, value: item.id, label: item.postName }));
  37 + if (searchValue.trim() === '') {
  38 + return oriOptions;
  39 + }
  40 + return oriOptions.filter((i) => i.label.toString().toLowerCase().includes(searchValue.trim().toLowerCase()));
  41 + };
  42 +
  43 + const handleSelect = (currValue: any) => {
  44 + // 【全部】时清空
  45 + if (currValue.value === -1) {
  46 + setSearchValue('');
  47 + return;
  48 + }
  49 + const oriNames = value.length > 0 ? value.map((i: any) => i.label) : [];
  50 + // value 更新为异步,需手动拼接最新选择值以判断当前筛选值是否已被勾选完
  51 + oriNames.push(currValue.label);
  52 + const valueMatchArr = oriNames.filter((i: string) => i.toLowerCase().includes(searchValue.trim().toLowerCase()));
  53 + const filteredData = getFilteredData();
  54 + if (valueMatchArr.length === filteredData.length) {
  55 + setSearchValue('');
  56 + }
  57 + };
  58 +
43 59 return (
44   - <Spin spinning={loading && !disabled}>
  60 + <Spin spinning={loading}>
45 61 <Select
  62 + searchValue={searchValue}
  63 + onSearch={(value) => {
  64 + setSearchValue(value);
  65 + }}
  66 + onSelect={handleSelect}
46 67 labelInValue
47 68 value={value}
48 69 mode="multiple"
... ... @@ -55,10 +76,9 @@ export default function PostsSelectorByAll({
55 76 }}
56 77 style={style || { flex: 1 }}
57 78 allowClear
58   - placeholder={disabled ? disabledTip : defaultTip}
  79 + placeholder={defaultTip}
59 80 showSearch
60 81 optionFilterProp="children"
61   - disabled={disabled}
62 82 // getPopupContainer={(triggerNode) => triggerNode.parentNode}
63 83 >
64 84 {postList.map((post) => (
... ...
src/pages/approval/FlowSetting/subpages/CommonSetting/components/CustomFlowNewOrEdit.tsx
... ... @@ -69,7 +69,7 @@ export default function CustomFlowNewOrEdit(props: Props) {
69 69 <Form form={form}>
70 70 <Form.Item name="id" hidden />
71 71 <Form.Item label="发起人岗位" name="posts" rules={[{ required: true, message: '请选择发起人岗位' }]}>
72   - <PostsSelectorByAll defaultTip="请选择发起人岗位或输入关键字筛选" />
  72 + <PostsSelectorByAll />
73 73 </Form.Item>
74 74 <RolesSettingForm shopBizTypes={[]} roles={roles} setRoles={setRoles} />
75 75 </Form>
... ...
src/pages/approval/FlowSetting/subpages/CommonSetting/components/CustomFlows.tsx
... ... @@ -6,7 +6,7 @@ import * as API from &#39;../../../api&#39;;
6 6 import usePagination from '@/hooks/usePagination';
7 7 import { useRequest } from 'umi';
8 8 import st from '@/pages/approval/style.less';
9   -import { useDebounceEffect } from 'ahooks';
  9 +import _ from 'lodash';
10 10  
11 11 const { Column } = Table;
12 12  
... ... @@ -17,7 +17,6 @@ interface Props {
17 17 export default function ConditionSettingForm({ approvalConfigId }: Props) {
18 18 const [visible, setVisible] = useState<boolean>(false);
19 19 const [current, setCurrent] = useState<FlowSetting.ProcessItem>();
20   - const [customSearch, setCustomSearch] = useState('');
21 20 const [condValModal, setCondValModal] = useState<{ visible: boolean; title?: string; value?: string[] }>({ visible: false });
22 21  
23 22 const { list: customProcessList, loading, innerParams, setParams } = usePagination(API.getCustomFlowList, { configId: approvalConfigId });
... ... @@ -34,15 +33,9 @@ export default function ConditionSettingForm({ approvalConfigId }: Props) {
34 33 });
35 34  
36 35 // 搜索过滤
37   - useDebounceEffect(
38   - () => {
39   - setParams({ ...innerParams, name: customSearch }, true);
40   - },
41   - [customSearch],
42   - {
43   - wait: 1000,
44   - },
45   - );
  36 + const onChange = _.debounce((newParams) => {
  37 + setParams({ ...innerParams, ...newParams, current: 1 }, true);
  38 + }, 1000);
46 39  
47 40 const onDelete = (id: number) => {
48 41 const hide = message.loading('删除中');
... ... @@ -112,7 +105,7 @@ export default function ConditionSettingForm({ approvalConfigId }: Props) {
112 105 <Card title="自定义审批流程">
113 106 <Row align="middle" justify="space-between" style={{ marginBottom: 20 }}>
114 107 <div style={{ width: 260 }}>
115   - <Input.Search allowClear placeholder="搜索流程名称" value={customSearch} onChange={(e) => setCustomSearch(e.target.value)} />
  108 + <Input.Search allowClear placeholder="搜索流程名称" onChange={(e) => onChange({ name: e.target.value })} />
116 109 </div>
117 110 <Button
118 111 type="primary"
... ...
src/pages/approval/FlowSetting/subpages/CommonSetting/components/DefaultFlows.tsx
1 1 import React, { useEffect, useState } from 'react';
2 2 import { Button, Card, Form, InputNumber, Modal, Popconfirm, Radio, Row, Space, Table, message } from 'antd';
3 3 import { PlusOutlined } from '@ant-design/icons';
4   -import SelectorWithFull from '@/components/SelectorWithFull';
5 4 import { getRolesByGroup } from '@/pages/approval/FlowSetting/api';
6 5 import _ from 'lodash';
7 6 import { geneRandomNum } from '@/utils/tools';
... ... @@ -9,6 +8,7 @@ import usePagination from &#39;@/hooks/usePagination&#39;;
9 8 import * as API from '../../../api';
10 9 import { useRequest } from 'umi';
11 10 import PreviewProcessModal from '@/pages/approval/components/PreviewProcessModal';
  11 +import { ApprovalRolesSelector } from '@/pages/approval/ApprovalSetting/subpages/components/Selectors';
12 12  
13 13 const { Column } = Table;
14 14  
... ... @@ -311,7 +311,17 @@ export default function DefaultFlows({ approvalConfigId }: Props) {
311 311 >
312 312 <Form form={roleForm}>
313 313 <Form.Item name="role" rules={[{ required: true, message: '请选择至少一个审批角色' }]}>
314   - <SelectorWithFull
  314 + <ApprovalRolesSelector
  315 + value={current.roles?.map((item) => ({ key: item.roleCode, value: item.roleCode, label: item.roleName }))}
  316 + list={roleList}
  317 + onChange={(value) => {
  318 + setCurrent({
  319 + ...current,
  320 + roles: value.map((item: ApprovalSetting.Option) => ({ roleCode: item.value, roleName: item.label })),
  321 + });
  322 + }}
  323 + />
  324 + {/* <SelectorWithFull
315 325 showSearch
316 326 treeNodeFilterProp="label"
317 327 maxTagCount={100}
... ... @@ -326,7 +336,7 @@ export default function DefaultFlows({ approvalConfigId }: Props) {
326 336 });
327 337 }}
328 338 data={roleList.map((item) => ({ key: item.roleCode, value: item.roleCode, label: item.roleName }))}
329   - />
  339 + /> */}
330 340 </Form.Item>
331 341 </Form>
332 342 </Modal>
... ...
src/pages/approval/FlowSetting/subpages/ConditionSetting/components/CustomFlowNewOrEdit.tsx
... ... @@ -204,6 +204,10 @@ export default function CustomFlowNewOrEdit(props: Props) {
204 204 const clearRoles = (newCondVals: FlowSetting.ConditionVal[]) => {
205 205 const oldShopBizTypes = [...shopBizTypes];
206 206 const newShopBizTypes = getShopBizTypes(newCondVals);
  207 + if (newShopBizTypes.length === 1 && newShopBizTypes[0] === -1) {
  208 + // 【全部门店】时不清空审批角色
  209 + return;
  210 + }
207 211 oldShopBizTypes.forEach((i) => {
208 212 if (!newShopBizTypes.includes(i)) {
209 213 // 清空已添加审批角色列表
... ... @@ -456,7 +460,7 @@ export default function CustomFlowNewOrEdit(props: Props) {
456 460 })}
457 461  
458 462 <Form.Item label="发起人岗位" name="posts" rules={[{ required: true, message: '请选择发起人岗位' }]}>
459   - <PostsSelectorByAll defaultTip="请选择发起人岗位或输入关键字筛选" />
  463 + <PostsSelectorByAll />
460 464 </Form.Item>
461 465 <RolesSettingForm shopBizTypes={shopBizTypes} roles={roles} setRoles={setRoles} />
462 466 </Form>
... ...
src/pages/approval/FlowSetting/subpages/ConditionSetting/components/CustomFlows.tsx
... ... @@ -10,7 +10,6 @@ import * as API from &#39;../../../api&#39;;
10 10 import { Judge_Rule_Enum } from '@/pages/approval/ApprovalSetting/subpages/components/PreSettingForm/entity';
11 11 import { formatConditions } from '../../../entity';
12 12 import st from '@/pages/approval/style.less';
13   -import { useDebounceEffect } from 'ahooks';
14 13 import TextWithMore from '@/components/TextWithMore';
15 14  
16 15 const { Column } = Table;
... ... @@ -25,8 +24,6 @@ export default function CustomFlows({ approvalConfigId, conds }: Props) {
25 24 const [visible, setVisible] = useState<boolean>(false);
26 25 const [current, setCurrent] = useState<FlowSetting.ProcessItemFE>();
27 26  
28   - const [customSearch, setCustomSearch] = useState<API.GetGroupDefaultFlowListReq>({});
29   -
30 27 const {
31 28 list: customProcessList,
32 29 loading,
... ... @@ -72,15 +69,9 @@ export default function CustomFlows({ approvalConfigId, conds }: Props) {
72 69 };
73 70  
74 71 // 搜索过滤
75   - useDebounceEffect(
76   - () => {
77   - setParams({ ...innerParams, name: customSearch.name }, true);
78   - },
79   - [customSearch.name],
80   - {
81   - wait: 1000,
82   - },
83   - );
  72 + const onChange = _.debounce((newParams) => {
  73 + setParams({ ...innerParams, ...newParams, current: 1 }, true);
  74 + }, 1000);
84 75  
85 76 const onDelete = (id: number) => {
86 77 const hide = message.loading('删除中');
... ... @@ -132,23 +123,21 @@ export default function CustomFlows({ approvalConfigId, conds }: Props) {
132 123 <Input.Search
133 124 allowClear
134 125 placeholder="搜索流程名称"
135   - value={customSearch.name}
136   - onChange={(e) => setCustomSearch({ ...customSearch, name: e.target.value })}
  126 + onChange={(e) => {
  127 + onChange({ name: e.target.value });
  128 + }}
137 129 />
138 130 </div>
139 131 <div style={{ width: 260, marginLeft: 20 }}>
140 132 <Select
141 133 allowClear
142   - value={customSearch.postId}
143 134 placeholder="筛选岗位"
144 135 style={{ width: 250, marginRight: 10 }}
145 136 onSelect={(value) => {
146   - setCustomSearch({ ...customSearch, postId: value });
147   - setParams({ ...innerParams, postId: value }, true);
  137 + onChange({ postId: value });
148 138 }}
149 139 onClear={() => {
150   - setCustomSearch({ ...customSearch, postId: undefined });
151   - setParams({ ...innerParams, postId: undefined }, true);
  140 + onChange({ postId: undefined });
152 141 }}
153 142 showSearch
154 143 optionFilterProp="children"
... ...
src/pages/approval/FlowSetting/subpages/ConditionSetting/components/DefaultFlows.tsx
... ... @@ -10,7 +10,6 @@ import { Judge_Rule_Enum } from &#39;@/pages/approval/ApprovalSetting/subpages/compo
10 10 import { formatConditions } from '../../../entity';
11 11 import PreviewProcessModal from '@/pages/approval/components/PreviewProcessModal';
12 12 import st from '@/pages/approval/style.less';
13   -import { useDebounceEffect } from 'ahooks';
14 13 import TextWithMore from '@/components/TextWithMore';
15 14  
16 15 const { Column } = Table;
... ... @@ -24,7 +23,6 @@ export default function DefaultFlows({ approvalConfigId, conds }: Props) {
24 23 const [visible, setVisible] = useState<boolean>(false);
25 24 const [current, setCurrent] = useState<ApprovalSetting.ProcessItemFE>();
26 25  
27   - const [defaultSearch, setDefaultSearch] = useState('');
28 26 const [previewModal, setPreviewModal] = useState<{ visible: boolean; value?: ApprovalSetting.ProcessItem }>({ visible: false });
29 27  
30 28 const {
... ... @@ -65,15 +63,9 @@ export default function DefaultFlows({ approvalConfigId, conds }: Props) {
65 63 };
66 64  
67 65 // 搜索过滤
68   - useDebounceEffect(
69   - () => {
70   - setParams({ ...innerParams, name: defaultSearch }, true);
71   - },
72   - [defaultSearch],
73   - {
74   - wait: 1000,
75   - },
76   - );
  66 + const onChange = _.debounce((newParams) => {
  67 + setParams({ ...innerParams, ...newParams, current: 1 }, true);
  68 + }, 1000);
77 69  
78 70 const onDelete = (id: number) => {
79 71 const hide = message.loading('删除中');
... ... @@ -126,7 +118,7 @@ export default function DefaultFlows({ approvalConfigId, conds }: Props) {
126 118 <Card title="默认审批流程">
127 119 <Row align="middle" justify="space-between" style={{ marginBottom: 20 }}>
128 120 <div style={{ width: 260 }}>
129   - <Input.Search allowClear placeholder="搜索流程名称" value={defaultSearch} onChange={(e) => setDefaultSearch(e.target.value)} />
  121 + <Input.Search allowClear placeholder="搜索流程名称" onChange={(e) => onChange({ name: e.target.value })} />
130 122 </div>
131 123 <Button
132 124 type="primary"
... ...
src/pages/approval/FlowSetting/subpages/ConditionSetting/components/RolesSettingForm.tsx
1 1 import React, { useEffect, useState } from 'react';
2 2 import { Button, Form, Modal, Popconfirm, Row, Space, Table } from 'antd';
3 3 import { PlusOutlined } from '@ant-design/icons';
4   -import SelectorWithFull from '@/components/SelectorWithFull';
5 4 import { getRolesByGroup } from '@/pages/approval/FlowSetting/api';
6 5 import _ from 'lodash';
7 6 import { geneRandomNum } from '@/utils/tools';
8 7 import { useRequest } from 'umi';
  8 +import { ApprovalRolesSelector } from '@/pages/approval/ApprovalSetting/subpages/components/Selectors';
9 9  
10 10 const { Column } = Table;
11 11  
... ... @@ -167,7 +167,18 @@ export default function RolesSettingForm({ shopBizTypes, roles, setRoles: onChan
167 167 >
168 168 <Form form={roleForm}>
169 169 <Form.Item name="role" rules={[{ required: true, message: '请选择至少一个审批角色' }]}>
170   - <SelectorWithFull
  170 + <ApprovalRolesSelector
  171 + value={current.roles?.map((item) => ({ key: item.roleCode, value: item.roleCode, label: item.roleName }))}
  172 + list={roleList}
  173 + onChange={(value) => {
  174 + console.log(value);
  175 + setCurrent({
  176 + ...current,
  177 + roles: value.map((item: ApprovalSetting.Option) => ({ roleCode: item.value, roleName: item.label })),
  178 + });
  179 + }}
  180 + />
  181 + {/* <SelectorWithFull
171 182 showSearch
172 183 treeNodeFilterProp="label"
173 184 maxTagCount={100}
... ... @@ -182,7 +193,7 @@ export default function RolesSettingForm({ shopBizTypes, roles, setRoles: onChan
182 193 });
183 194 }}
184 195 data={roleList.map((item) => ({ key: item.roleCode, value: item.roleCode, label: item.roleName }))}
185   - />
  196 + /> */}
186 197 </Form.Item>
187 198 </Form>
188 199 </Modal>
... ...
src/pages/finance/SpecialAccount/FinancingCompany/components/CreateModal.tsx
... ... @@ -137,7 +137,7 @@ export default function CreateModal() {
137 137  
138 138 return (
139 139 <Modal
140   - title={`${current.compId ? "编辑" : "新增"}厂家往来银行`}
  140 + title={`${current.compId ? "编辑" : "新增"}库存融资银行`}
141 141 open={visible}
142 142 confirmLoading={saveLoading}
143 143 onOk={form.submit}
... ... @@ -216,7 +216,11 @@ export default function CreateModal() {
216 216 <Radio value={3}>一般户90% </Radio>
217 217 </Radio.Group>
218 218 </FormItem> */}
219   - <FormItem name="depositAccount" label="还款保证金账户">
  219 + <FormItem
  220 + name="depositAccount"
  221 + label="还款保证金账户"
  222 + rules={[{ required: true, message: "请选择还款保证金账户" }]}
  223 + >
220 224 <Select labelInValue placeholder="请选择账户" showSearch optionFilterProp="children" allowClear>
221 225 {accountList.map((item) => (
222 226 <Option key={item.id} value={item.id}>
... ...
src/pages/finance/proactiveReimbursement/api.ts 0 → 100644
  1 +import { http } from "@/typing/http";
  2 +import request from "@/utils/request";
  3 +import { FINANCE2_HOST } from "@/utils/host";
  4 +
  5 +type PrRes<T> = http.PromiseResp<T>;
  6 +type PrRageRes<T> = http.PromisePageResp<T>;
  7 +
  8 +export interface RpTypesItem {
  9 + value?: number;
  10 + name?: string; //名称
  11 +}
  12 +
  13 +interface Params {
  14 + type?: number; //类型(See: 收支类型枚举
  15 + parent?: string; //父级
  16 + typeName?: string; //款项名称模糊搜索
  17 +}
  18 +
  19 +/**
  20 + * 获取款项配置列表
  21 + * /rp/type/config/list
  22 + */
  23 +export function getRpTypeConfigApi(params: RpTypeConfig.TypeListParams): PrRageRes<RpTypeConfig.TypeListItems> {
  24 + return request.get(`${FINANCE2_HOST}/rp/type/config/list`, { params });
  25 +}
  26 +
  27 +/**
  28 + * 删除款项配置
  29 + * /rp/type/config/delete/{id}
  30 + * /rp/type/config/delete/{id}
  31 + */
  32 +export function typeConfigDeleteApi(id?: number): PrRes<void> {
  33 + return request.post(`${FINANCE2_HOST}/rp/type/config/delete/${id}`);
  34 +}
  35 +
  36 +/**
  37 + * 查询收支类型
  38 + * /common/rpTypes
  39 + */
  40 +export function commonRpTypesApi(params: Params): PrRes<RpTypesItem[]> {
  41 + return request.get(`${FINANCE2_HOST}/common/rpTypes`, { params });
  42 +}
  43 +
  44 +interface SavaParams {
  45 + groupId?: number; //集团id
  46 + userId?: number; //用户id
  47 + userName?: string; //用户名称
  48 + id?: number; //配置项id,编辑时不为空
  49 + typeValue?: number; //款项
  50 + configType?: number; //配置类型:1 收入录入,2 付款申请,3 缴费申请,4 事项申请(See: 财务款项配置类型)
  51 + processMode?: number; //款项处理:1 默认收付,2 冲应付款,3 挂应收(See: 款项处理方式)
  52 + roles?: string[];//可申请角色
  53 + companyTypes?: number[]; //往来单位业务类型
  54 +}
  55 +
  56 +/**
  57 + * 保存款项配置
  58 + * /rp/type/config/save
  59 + */
  60 +export function getRpTypeConfigSaveApi(params: SavaParams): PrRageRes<null> {
  61 + return request.post(`${FINANCE2_HOST}/rp/type/config/save`, params);
  62 +}
... ...
src/pages/finance/proactiveReimbursement/components/ApitalModal.tsx 0 → 100644
  1 +import React, { useState, useEffect } from "react";
  2 +import { Modal, Form, Select, message, Radio } from "antd";
  3 +import { useStore } from "../index";
  4 +import { getRpTypeConfigSaveApi, commonRpTypesApi, RpTypesItem } from "@/pages/finance/PaymentAllocation/api";
  5 +import useInitial from "@/hooks/useInitail";
  6 +import { ProcessMode2, ProcessModeEnum } from '@/pages/finance/entitys';
  7 +import { getCompanyBusinessTypesApi } from "@/pages/finance/TradeCompany/api";
  8 +import { getAllRoleCodeApi } from "@/common/api";
  9 +
  10 +const FormItem = Form.Item;
  11 +const { Option } = Select;
  12 +
  13 +
  14 +export default function CreateModal() {
  15 + const { visible, setVisible, current, setCurrent, setLoading, } =
  16 + useStore();
  17 + /**查询收支类型(款项);type:1收 2支
  18 + * 配置类型configType:1 收入录入,2 付款申请,3 缴费申请,4 事项申请
  19 + *
  20 + */
  21 + const { data } = useInitial<RpTypesItem[], any>(commonRpTypesApi, [], { type: 2, configType: 5 });
  22 + const [form] = Form.useForm();
  23 + const [saveLoading, setSaveLoading] = useState(false);
  24 +
  25 + // 往来单位业务类型列表
  26 + const { data: comBussinessList, loading: comBussinessLoading } = useInitial(getCompanyBusinessTypesApi, [], null);
  27 + // 查询所有角色列表
  28 + const { data: roleList, loading } = useInitial(getAllRoleCodeApi, [], {});
  29 +
  30 + useEffect(() => {
  31 + if (visible && current) {
  32 + const res = toFormData(current);
  33 + form.setFieldsValue({ ...current, ...res, typeValue: { label: current.typeName, value: current.typeValue } });
  34 + }
  35 + }, [visible]);
  36 +
  37 + function toFormData(data: ApitalAccount.ApitalList) {
  38 + const res = {};
  39 + if (data.compTypeList && data.compTypeList.length) {
  40 + res.companyTypes = data.compTypeList.map((item) => ({ label: item.name, value: item.id }));
  41 + }
  42 + if (data.roleList && data.roleList.length) {
  43 + res.roles = data.roleList.map((item) => ({ label: item.name, value: item.id }));
  44 + }
  45 + return res;
  46 + }
  47 +
  48 + function transformDTO(item: any) {
  49 + const res = {};
  50 + if (item.roles && item.roles.length) {
  51 + res.roles = item.roles.map((it) => it.value);
  52 + }
  53 + if (item.companyTypes && item.companyTypes.length) {
  54 + res.companyTypes = item.companyTypes.map((it) => it.value);
  55 + }
  56 + return res;
  57 + }
  58 +
  59 + function submit(item: any) {
  60 + const res = transformDTO(item);
  61 + const params = {
  62 + ...item,
  63 + ...res,
  64 + configType: 5,
  65 + id: current.id,
  66 + typeValue: item.typeValue && item.typeValue.value
  67 + };
  68 + setSaveLoading(true);
  69 + const saveApi = getRpTypeConfigSaveApi;
  70 + saveApi(params)
  71 + .then(() => {
  72 + message.success("保存成功");
  73 + setSaveLoading(false);
  74 + setVisible(false);
  75 + setLoading(true);
  76 + })
  77 + .catch((e) => {
  78 + message.error(e.message);
  79 + setSaveLoading(false);
  80 + });
  81 + }
  82 +
  83 + function onCancel() {
  84 + setVisible(false);
  85 + }
  86 +
  87 + return (
  88 + <Modal
  89 + title={`${current.id ? '编辑' : '新增'}主动报销款项配置`}
  90 + open={visible}
  91 + onOk={() => form.submit()}
  92 + onCancel={onCancel}
  93 + maskClosable={false}
  94 + confirmLoading={saveLoading}
  95 + afterClose={() => {
  96 + form.resetFields();
  97 + setCurrent({});
  98 + }}
  99 + >
  100 + <Form form={form} onFinish={submit} labelCol={{ span: 7 }} wrapperCol={{ span: 16 }}>
  101 + <FormItem name="typeValue" label="主动报销款项" rules={[{ required: true, message: '请选择款项' }]}>
  102 + <Select placeholder="请选择主动报销款项" labelInValue showSearch optionFilterProp="children" disabled={!!current.id}>
  103 + {data.map((item) => (
  104 + <Option key={item.value} value={item.value}>
  105 + {item.name}
  106 + </Option>
  107 + ))}
  108 + </Select>
  109 + </FormItem>
  110 +
  111 + <FormItem name="processMode" label="款项处理" rules={[{ required: true, message: '请选择款项处理方式' }]}>
  112 + <Select placeholder="请选择款项处理方式" showSearch optionFilterProp="children">
  113 + {ProcessMode2.map((item) => (
  114 + <Option key={item.value} value={item.value}>
  115 + {item.label}
  116 + </Option>
  117 + ))}
  118 + </Select>
  119 + </FormItem>
  120 + <FormItem noStyle shouldUpdate={(prevValues, curValues) => prevValues.processMode !== curValues.processMode}>
  121 + {({ getFieldValue }) => {
  122 + const _processMode = getFieldValue('processMode') || {};
  123 + console.log('_processMode999:', _processMode);
  124 + return _processMode === ProcessModeEnum['冲应付款'] ? (
  125 + <FormItem label="是否提前导入应付款" initialValue={false} name="mustImport" rules={[{ required: true, message: '请选择' }]}>
  126 + <Radio.Group>
  127 + <Radio value>是</Radio>
  128 + <Radio value={false}>否</Radio>
  129 + </Radio.Group>
  130 + </FormItem>
  131 + ) : null;
  132 + }}
  133 + </FormItem>
  134 + <FormItem name="companyTypes" label="往来单位业务类型">
  135 + <Select
  136 + placeholder="请选择往来单位业务类型"
  137 + mode="multiple"
  138 + labelInValue
  139 + showSearch
  140 + optionFilterProp="children"
  141 + loading={comBussinessLoading}
  142 + >
  143 + {comBussinessList.map((item) => (
  144 + <Option key={item.id} value={item.id}>
  145 + {item.name}
  146 + </Option>
  147 + ))}
  148 + </Select>
  149 + </FormItem>
  150 + <FormItem name="roles" label="可申请角色">
  151 + <Select
  152 + placeholder="请选择角色"
  153 + mode="multiple"
  154 + labelInValue
  155 + showSearch
  156 + optionFilterProp="children"
  157 + loading={loading}
  158 + autoClearSearchValue={false}
  159 + >
  160 + {roleList.map((item) => (
  161 + <Option key={item.roleCode} value={item.roleCode}>
  162 + {item.roleName}
  163 + </Option>
  164 + ))}
  165 + </Select>
  166 + </FormItem>
  167 + </Form>
  168 + </Modal>
  169 + );
  170 +}
... ...
src/pages/finance/proactiveReimbursement/components/Filter.tsx 0 → 100644
  1 +import React from 'react';
  2 +import { Button, Row, Input, Col } from 'antd';
  3 +import { debounce } from 'lodash';
  4 +const Search = Input.Search;
  5 +import { useStore } from '../index';
  6 +
  7 +export default function AccountList() {
  8 + const { setVisible, setParams } = useStore();
  9 +
  10 + const fetchListByName = debounce(value => {
  11 + setParams({ keywords: value }, true);
  12 + }, 500);
  13 +
  14 + return (
  15 + <div
  16 + style={{
  17 + display: "flex",
  18 + flexDirection: "row",
  19 + justifyContent: "space-between",
  20 + alignItems: "center",
  21 + marginBottom: 20,
  22 + }}
  23 + >
  24 + <Row style={{ display: "flex", flex: 1 }}>
  25 + <Col span={8}>
  26 + <Search
  27 + allowClear
  28 + placeholder="搜索主动报销款项"
  29 + onChange={(e) => fetchListByName(e.target.value || undefined)}
  30 + style={{ width: 260, marginLeft: 10 }}
  31 + />
  32 + </Col>
  33 + </Row>
  34 + <Button type="primary" onClick={() => setVisible(true)}>
  35 + 新增
  36 + </Button>
  37 + </div>
  38 + );
  39 +};
... ...
src/pages/finance/proactiveReimbursement/components/List.tsx 0 → 100644
  1 +import React, { useState } from "react";
  2 +import { Table, Button, Popconfirm, Divider, message } from "antd";
  3 +import { useStore } from "../index";
  4 +import { ProcessModeEnum } from "@/pages/finance/entitys";
  5 +import PersonModal from "./PersonModal";
  6 +import { typeConfigDeleteApi } from "../api";
  7 +const { Column } = Table;
  8 +export default function AccountList() {
  9 + const {
  10 + typeConifgList,
  11 + loading,
  12 + paginationConfig,
  13 + modalVisible,
  14 + setModalVisible,
  15 + setCurrent,
  16 + setVisible,
  17 + setLoading,
  18 + } = useStore();
  19 + // 删除
  20 + async function handleDelete(id?: number) {
  21 + try {
  22 + const { result, success } = await typeConfigDeleteApi(id);
  23 + if (!success) {
  24 + message.error(result);
  25 + return;
  26 + }
  27 + message.success(result, 1.5);
  28 + setLoading(true);
  29 + } catch (e: any) {
  30 + message.error(e.message, 1.5);
  31 + }
  32 + }
  33 + return (
  34 + <>
  35 + <Table dataSource={typeConifgList} rowKey="id" loading={loading} pagination={paginationConfig}>
  36 + <Column title="主动报销款项" dataIndex="typeName" />
  37 + <Column title="款项处理" dataIndex="processMode" render={(mode) => ProcessModeEnum[mode]} />
  38 + <Column title="是否提前导入应付款" dataIndex="mustImport" render={(value: string) => (value ? '是' : '否')} />
  39 + <Column
  40 + title="往来单位业务类型"
  41 + dataIndex="compTypeList"
  42 + render={(comptype: any[], record: ApitalAccount.ApitalList) =>
  43 + comptype && comptype.length > 0 ? (
  44 + <Button
  45 + type="link"
  46 + onClick={() => {
  47 + setModalVisible({ visible: true, data: comptype });
  48 + }}
  49 + >
  50 + 查看
  51 + </Button>
  52 + ) : (
  53 + '--'
  54 + )
  55 + }
  56 + />
  57 + <Column
  58 + title="可申请角色"
  59 + dataIndex="compTypeList"
  60 + render={(roles: any[]) =>
  61 + roles && roles.length > 0 ? (
  62 + <Button
  63 + type="link"
  64 + onClick={() => {
  65 + setModalVisible({ visible: true, data: roles });
  66 + }}
  67 + >
  68 + 查看
  69 + </Button>
  70 + ) : (
  71 + '--'
  72 + )
  73 + }
  74 + />
  75 + <Column
  76 + title="操作"
  77 + align="center"
  78 + render={(_, record: ApitalAccount.ApitalList) => (
  79 + <>
  80 + <Button
  81 + type="link"
  82 + onClick={() => {
  83 + setCurrent(record);
  84 + setVisible(true);
  85 + }}
  86 + >
  87 + 编辑
  88 + </Button>
  89 + <Divider type="vertical" />
  90 + <Popconfirm title={`是否删除【${record.typeName}】?`} onConfirm={() => handleDelete(+record.id!)} okText="确定" cancelText="取消">
  91 + <a href="">删除</a>
  92 + </Popconfirm>
  93 + </>
  94 + )}
  95 + />
  96 + </Table>
  97 + <PersonModal item={modalVisible} setShopModal={setModalVisible} />
  98 + </>
  99 + );
  100 +}
... ...
src/pages/finance/proactiveReimbursement/components/PersonModal.tsx 0 → 100644
  1 +import React from "react";
  2 +import { List, Modal } from "antd";
  3 +
  4 +interface Props {
  5 + item: RpTypeConfig.PersonModal;
  6 + setShopModal: Function;
  7 +}
  8 +
  9 +export default function PersonModal({ item, setShopModal }: Props) {
  10 + const { visible, data } = item;
  11 +
  12 + return (
  13 + <Modal
  14 + title="查看"
  15 + centered
  16 + open={visible}
  17 + onCancel={() => setShopModal({ data: [], visible: false })}
  18 + footer={null}
  19 + >
  20 + <List
  21 + size="small"
  22 + bordered
  23 + style={{ maxHeight: 400, overflow: "auto" }}
  24 + dataSource={data}
  25 + renderItem={(item: { id: number; name: string }, index) => (
  26 + <List.Item>
  27 + {`${index + 1}.`}
  28 + {item.name}
  29 + </List.Item>
  30 + )}
  31 + />
  32 + </Modal>
  33 + );
  34 +}
... ...
src/pages/finance/proactiveReimbursement/index.tsx 0 → 100644
  1 +import React from 'react';
  2 +import { Card } from 'antd';
  3 +import { PageHeaderWrapper } from '@ant-design/pro-layout';
  4 +import Filter from './components/Filter';
  5 +import List from './components/List';
  6 +import { createStore } from '@/hooks/moz';
  7 +import store from './useStore';
  8 +import ApitalModal from './components/ApitalModal';
  9 +export const { Provider, useStore } = createStore(store);
  10 +
  11 +function ProactiveReimbursement() {
  12 + return (
  13 + <PageHeaderWrapper title="主动报销款项配置">
  14 + <Card>
  15 + <Filter />
  16 + <List />
  17 + </Card>
  18 + <ApitalModal />
  19 + </PageHeaderWrapper>
  20 + );
  21 +}
  22 +export default () => {
  23 + return (
  24 + <Provider>
  25 + <ProactiveReimbursement />
  26 + </Provider>
  27 + )
  28 +};
... ...
src/pages/finance/proactiveReimbursement/useStore.ts 0 → 100644
  1 +import { useState } from "react";
  2 +import usePagination from "@/hooks/usePagination";
  3 +import * as api from "./api";
  4 +
  5 +export default function useStore() {
  6 + const [visible, setVisible] = useState(false);
  7 + const [modalVisible, setModalVisible] = useState<{ visible: boolean; data: any[] }>({ visible: false, data: [] });
  8 + //款项配置列表
  9 + const {
  10 + list: typeConifgList,
  11 + loading,
  12 + setLoading,
  13 + paginationConfig,
  14 + innerParams,
  15 + setParams,
  16 + } = usePagination<RpTypeConfig.TypeListItems>(api.getRpTypeConfigApi, {configType: 5});
  17 +
  18 + const [current, setCurrent] = useState<ApitalAccount.ApitalList>({});
  19 +
  20 + return {
  21 + visible,
  22 + setVisible,
  23 + current,
  24 + setCurrent,
  25 + modalVisible,
  26 + setModalVisible,
  27 + typeConifgList,
  28 + loading,
  29 + setLoading,
  30 + paginationConfig,
  31 + innerParams,
  32 + setParams,
  33 + };
  34 +}
... ...