|
@@ -0,0 +1,125 @@
|
|
|
+import { useRequest } from 'umi'
|
|
|
+import { Input, message, Modal } from 'antd'
|
|
|
+import React, { useState, useRef, useEffect } from 'react'
|
|
|
+import Icon from '@/components/IconPark'
|
|
|
+import { fetchStaffList } from '@/services/user/api'
|
|
|
+import { linkAttendance } from '@/services/user/system'
|
|
|
+import '@/pages/Role/System/components/ConnectModal/index.less'
|
|
|
+import { LoadingOutlined, MoreOutlined } from '@ant-design/icons'
|
|
|
+
|
|
|
+interface ConnectModalProps {
|
|
|
+ title: string
|
|
|
+ dataId: string
|
|
|
+}
|
|
|
+const ApplicantModal: React.FC<ConnectModalProps> = ({ dataId }) => {
|
|
|
+ const containerRef = useRef<HTMLDivElement>(null)
|
|
|
+ const [visible, setVisible] = useState(false)
|
|
|
+ const [searchVal, setSearchVal] = useState('')
|
|
|
+
|
|
|
+ const { run: tryLinkAttendance } = useRequest(
|
|
|
+ (params: API.LinkAttendance) => linkAttendance(params),
|
|
|
+ {
|
|
|
+ manual: true,
|
|
|
+ onSuccess: () => {
|
|
|
+ message.success('关联成功')
|
|
|
+ setVisible(false)
|
|
|
+ },
|
|
|
+ onError: e => {
|
|
|
+ message.error(e.message)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ )
|
|
|
+
|
|
|
+ const {
|
|
|
+ run: tryQueryStaffList,
|
|
|
+ data,
|
|
|
+ noMore,
|
|
|
+ loadMore,
|
|
|
+ loadingMore
|
|
|
+ } = useRequest(
|
|
|
+ result =>
|
|
|
+ fetchStaffList({
|
|
|
+ current: result?.list.length / 10 + 1 || 1,
|
|
|
+ pageSize: 10,
|
|
|
+ search: searchVal
|
|
|
+ }),
|
|
|
+ {
|
|
|
+ manual: true,
|
|
|
+ loadMore: true,
|
|
|
+ ref: containerRef,
|
|
|
+ isNoMore: (res: API.BasicFetchResult<API.StaffItem>) => res.list.length >= res.total,
|
|
|
+ refreshDeps: [searchVal]
|
|
|
+ }
|
|
|
+ )
|
|
|
+
|
|
|
+ const handleSearch = (value: string) => {
|
|
|
+ setSearchVal(value)
|
|
|
+ setTimeout(() => {
|
|
|
+ tryQueryStaffList()
|
|
|
+ }, 250)
|
|
|
+ }
|
|
|
+
|
|
|
+ const { list = [] }: { list: API.StaffItem[] } = data || {}
|
|
|
+ useEffect(() => {
|
|
|
+ if (visible) {
|
|
|
+ tryQueryStaffList()
|
|
|
+ }
|
|
|
+ }, [visible])
|
|
|
+
|
|
|
+ const itemSelectHandler = (staffId: string) => {
|
|
|
+ tryLinkAttendance({ id: dataId, staffId })
|
|
|
+ }
|
|
|
+ return (
|
|
|
+ <>
|
|
|
+ <span
|
|
|
+ className="hover:text-hex-886ab5 cursor-pointer text-purple-500"
|
|
|
+ onClick={() => setVisible(true)}>
|
|
|
+ <Icon type="plus" />
|
|
|
+ 添加
|
|
|
+ </span>
|
|
|
+ <Modal
|
|
|
+ visible={visible}
|
|
|
+ onCancel={() => setVisible(false)}
|
|
|
+ getContainer={false}
|
|
|
+ width="60vw"
|
|
|
+ title={
|
|
|
+ <Input.Search
|
|
|
+ placeholder="搜索员工(姓名)"
|
|
|
+ onSearch={value => handleSearch(value)}
|
|
|
+ onPressEnter={e => handleSearch(e.currentTarget.value)}
|
|
|
+ style={{ width: '95%' }}
|
|
|
+ allowClear={true}></Input.Search>
|
|
|
+ }>
|
|
|
+ <div ref={containerRef} className="h-60vh overflow-y-auto overflow-x-hidden modal-content">
|
|
|
+ {list.map(item => (
|
|
|
+ <div className="card" key={item.id}>
|
|
|
+ <div className="w-4/3 flex justify-between">
|
|
|
+ <span className="w-1/5">{item.username}</span>
|
|
|
+ <span className="w-2/5">{item.phone}</span>
|
|
|
+ <span className="w-1/5">{item.position}</span>
|
|
|
+ <span className="w-1/5">{item.category}</span>
|
|
|
+ </div>
|
|
|
+ <div className="w-1/4 flex justify-end">
|
|
|
+ <span className="btn-outline" onClick={() => itemSelectHandler(item.id)}>
|
|
|
+ 选择ta
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ ))}
|
|
|
+ {noMore && <div className="text-center text-gray-400">已到底部</div>}
|
|
|
+ {!noMore && (
|
|
|
+ <div className="text-center mt-3 cursor-pointer">
|
|
|
+ {loadingMore ? (
|
|
|
+ <LoadingOutlined />
|
|
|
+ ) : (
|
|
|
+ <MoreOutlined rotate={90} style={{ fontSize: 24 }} onClick={loadMore} />
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
+ </Modal>
|
|
|
+ </>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+export default ApplicantModal
|