|
@@ -0,0 +1,145 @@
|
|
|
+import { useRef, useState, useMemo, useContext } from 'react'
|
|
|
+import { Button, Drawer, Radio, Select, Spin, Tag } from 'antd'
|
|
|
+import { Actions, FlowContext } from '../../context'
|
|
|
+import debounce from 'lodash/debounce'
|
|
|
+import type { RadioChangeEvent } from 'antd'
|
|
|
+import { queryAcountList } from '@/services/api/institution'
|
|
|
+import consts from '@/utils/consts'
|
|
|
+const debounceTimeout = 800
|
|
|
+
|
|
|
+export enum ApprovalType {
|
|
|
+ TARGET = '1', // 指定成员
|
|
|
+ SUPERIOR = '2', // 上级
|
|
|
+ ROLE = '3', // 角色
|
|
|
+ INITIATOR = '4', // 发起人自选
|
|
|
+ MULTISTAGE = '5' // 连续多级上级
|
|
|
+}
|
|
|
+
|
|
|
+const FlowDrawer = () => {
|
|
|
+ const { flowState, dispatch } = useContext(FlowContext)
|
|
|
+ const { drawerConfig } = flowState
|
|
|
+
|
|
|
+ const fetchRef = useRef(0)
|
|
|
+ const [state, setState] = useState({
|
|
|
+ approvalType: ApprovalType.TARGET,
|
|
|
+ fetching: false,
|
|
|
+ options: [],
|
|
|
+ staffOptions: []
|
|
|
+ })
|
|
|
+
|
|
|
+ const handleCancel = () => dispatch({ type: Actions.CLOSE_MODAL })
|
|
|
+
|
|
|
+ const plainOptions = [
|
|
|
+ { label: '指定成员', value: ApprovalType.TARGET },
|
|
|
+ { label: '上级', value: ApprovalType.SUPERIOR },
|
|
|
+ { label: '角色', value: ApprovalType.ROLE },
|
|
|
+ { label: '发起人自选', value: ApprovalType.INITIATOR },
|
|
|
+ { label: '连续多级上级', value: ApprovalType.MULTISTAGE }
|
|
|
+ ]
|
|
|
+
|
|
|
+ const approvalTypeChange = (e: RadioChangeEvent) => {
|
|
|
+ const { target } = e
|
|
|
+ if (target?.value) {
|
|
|
+ setState({ ...state, approvalType: target.value })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const fetchOptions = async params => {
|
|
|
+ const { code = -1, data = {} } = await queryAcountList({
|
|
|
+ ...params,
|
|
|
+ current: 1,
|
|
|
+ pageSize: 100,
|
|
|
+ dataID: 'e01b8695-c43b-4d2d-8169-a021aa6b69ae'
|
|
|
+ })
|
|
|
+ if (code === consts.RET_CODE.SUCCESS) {
|
|
|
+ return data.items.map(item => ({ label: item.name, value: item.ID }))
|
|
|
+ }
|
|
|
+ return []
|
|
|
+ }
|
|
|
+
|
|
|
+ const debounceFetcher = useMemo(() => {
|
|
|
+ const loadOptions = params => {
|
|
|
+ fetchRef.current += 1
|
|
|
+ const fetchId = fetchRef.current
|
|
|
+ setState({ ...state, options: [], fetching: true })
|
|
|
+
|
|
|
+ fetchOptions(params).then(newOptions => {
|
|
|
+ if (fetchId !== fetchRef.current) {
|
|
|
+ // for fetch callback order
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ setState({ ...state, options: newOptions, fetching: false })
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ return debounce(loadOptions, debounceTimeout)
|
|
|
+ }, [fetchOptions, debounceTimeout])
|
|
|
+
|
|
|
+ const staffIds = state.staffOptions.map(i => i.value)
|
|
|
+ const triggerChange = (val, option) => {
|
|
|
+ if (!staffIds.includes(val)) {
|
|
|
+ setState({ ...state, staffOptions: [...state.staffOptions, option] })
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const handleOnOk = () => {
|
|
|
+ const payload = {
|
|
|
+ id: drawerConfig.nodeId,
|
|
|
+ node: {
|
|
|
+ approvalType: state.approvalType,
|
|
|
+ staffOptions: state.staffOptions
|
|
|
+ }
|
|
|
+ }
|
|
|
+ dispatch({
|
|
|
+ type: Actions.SET_FLOW_NODE,
|
|
|
+ payload
|
|
|
+ })
|
|
|
+ handleCancel()
|
|
|
+ }
|
|
|
+
|
|
|
+ return (
|
|
|
+ <Drawer
|
|
|
+ visible={drawerConfig.visible}
|
|
|
+ onClose={handleCancel}
|
|
|
+ footer={
|
|
|
+ <div className="flex justify-end">
|
|
|
+ <Button onClick={handleCancel}>取消</Button>
|
|
|
+ <Button className="ml-8px" type="primary" onClick={handleOnOk}>
|
|
|
+ 确认
|
|
|
+ </Button>
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+ title={<span className="font-medium">设置审批人</span>}
|
|
|
+ width="30%">
|
|
|
+ <div>
|
|
|
+ <Radio.Group
|
|
|
+ options={plainOptions}
|
|
|
+ onChange={approvalTypeChange}
|
|
|
+ value={state.approvalType}
|
|
|
+ />
|
|
|
+ <div className="mt-40px flex flex-col">
|
|
|
+ <div className="text-sm mb-4">
|
|
|
+ <span className="font-medium mr-1 text-14px">添加员工</span>
|
|
|
+ <span className="text-hex-000000 text-opacity-45">不得超过20人</span>
|
|
|
+ </div>
|
|
|
+ <Select
|
|
|
+ showSearch
|
|
|
+ value={null}
|
|
|
+ onChange={triggerChange}
|
|
|
+ filterOption={false}
|
|
|
+ onSearch={v => debounceFetcher({ search: v })}
|
|
|
+ notFoundContent={state.fetching ? <Spin size="small" /> : null}
|
|
|
+ options={state.options?.filter(item => !staffIds.includes(item.value))}
|
|
|
+ />
|
|
|
+ <div className="mt-4">
|
|
|
+ {state.staffOptions.map(item => (
|
|
|
+ <Tag key={item.value}>{item.label}</Tag>
|
|
|
+ ))}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </Drawer>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+export default FlowDrawer
|