Browse Source

feat: 人资加班参数设置添加申请人+添加对象

outaozhen 4 năm trước cách đây
mục cha
commit
5442a66867

+ 120 - 0
src/pages/Business/Attendance/components/AddObjectModal/index.tsx

@@ -0,0 +1,120 @@
+import { useRequest } from 'umi'
+import { Button, Input, message, Modal } from 'antd'
+import React, { useState, useRef, useEffect } from 'react'
+import { fetchStaffList } from '@/services/user/api'
+import { addAttendance } from '@/services/user/system'
+import '@/pages/Role/System/components/ConnectModal/index.less'
+import { LoadingOutlined, MoreOutlined } from '@ant-design/icons'
+
+interface AddObjectModalProps {
+  title: string
+}
+const AddObjectModal: React.FC<AddObjectModalProps> = ({ title }) => {
+  const containerRef = useRef<HTMLDivElement>(null)
+  const [visible, setVisible] = useState(false)
+  const [searchVal, setSearchVal] = useState('')
+
+  const { run: tryAddAttendance } = useRequest(
+    (params: API.Addattendance) => addAttendance(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 = (applicantStaffId: string) => {
+    tryAddAttendance({ applicantStaffId })
+  }
+  return (
+    <>
+      <Button type="primary" onClick={() => setVisible(true)}>
+        {title}
+      </Button>
+      <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 AddObjectModal

+ 125 - 0
src/pages/Business/Attendance/components/ApplicantModal/index.tsx

@@ -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

+ 15 - 19
src/pages/Business/Attendance/index.tsx

@@ -2,12 +2,10 @@ import React, { useState, useEffect } from 'react'
 import AttendanceMenu from './components/AttendanceMenu/attendanceMenu'
 import { useRequest } from 'umi'
 import Icon from '@/components/IconPark'
-import ConnectModal from '@/pages/Role/System/components/ConnectModal'
-import { Table,Tag } from 'antd'
-import {
-  fetchAttendanceList,
-  deleteAttendance
-} from '@/services/user/system'
+import AddObjectModal from './components/AddObjectModal'
+import ApplicantModal from './components/ApplicantModal'
+import { Table, Tag } from 'antd'
+import { fetchAttendanceList, deleteAttendance } from '@/services/user/system'
 
 const Attendance = () => {
   const [state, setState] = useState({
@@ -32,7 +30,7 @@ const Attendance = () => {
       }
     }
   )
-  
+
   useEffect(() => {
     if (state.id) {
       tryGetRoleStaffList(state.id)
@@ -46,24 +44,26 @@ const Attendance = () => {
     {
       title: '申请人名称',
       dataIndex: 'applicantStaffName',
-      width: '10%'
+      width: '15%'
     },
     {
       title: '申请对象',
       dataIndex: 'staff',
       align: 'left',
       width: '70%',
-      render: (_,record) => (
+      render: (_, record) => (
         <>
-          {record.staff.map((item) => (
+          {record.staff.map(item => (
             // console.log(item.staffName)
             <span key={item.staffId} className="zh-mg-bottom-5 zh-block">
-              <Tag closable={true} onClose={() => trydeleteAttendance(item.staffId,record.id )}>{item.staffName}</Tag>
+              <Tag
+                closable={true}
+                onClose={() => trydeleteAttendance({ staffId: item.staffId, id: record.id })}>
+                {item.staffName}
+              </Tag>
             </span>
           ))}
-          <span className="hover:text-hex-886ab5 cursor-pointer text-purple-500">
-            <Icon type="plus" />添加
-          </span>
+          <ApplicantModal dataId={record.id} />
         </>
       )
     },
@@ -85,10 +85,7 @@ const Attendance = () => {
       <div className="w-max-3/4">
         <div className="ml-8 bg-white p-4 shadow-md shadow-hex-3e2c5a relative">
           <div className="absolute right-7 top-7 z-100">
-            {/* 添加新申请人 */}
-            <ConnectModal
-              title="添加新申请人"
-            />
+            <AddObjectModal title="添加新申请人" />
           </div>
           <Table
             bordered
@@ -97,7 +94,6 @@ const Attendance = () => {
             dataSource={state.attendanceList}
             rowKey={row => row.id}
           />
-          
         </div>
       </div>
     </div>

+ 6 - 6
src/services/user/system.ts

@@ -14,22 +14,22 @@ export async function fetchAttendanceList() {
 export async function deleteAttendance(params: API.DeleteAttendance) {
   return request('/attendance/unlinkStaff', {
     method: 'POST',
-    data:params
+    data: params
   })
 }
 
 /** 关联加班人 */
-export async function linkAttendance({ id }: { id: string }) {
+export async function linkAttendance(params: API.LinkAttendance) {
   return request('/attendance/linkStaff', {
     method: 'POST',
-    data: { id }
+    data: params
   })
 }
 
 /** 新增申请人 */
-export async function addAttendance({ id }: { id: string }) {
+export async function addAttendance(params: API.Addattendance) {
   return request('/attendance/add', {
     method: 'POST',
-    data: { id }
+    data: params
   })
-}
+}

+ 12 - 3
src/services/user/typings.d.ts

@@ -185,11 +185,20 @@ declare namespace API {
     id: string
     applicantStaffId: string
     applicantStaffName: string
-    staff: {id:string; staff:string}[]
+    staff: { id: string; staff: string }[]
   }
 
-  type DeleteAttendance ={
+  type DeleteAttendance = {
     id: string
-    staffId:string
+    staffId: string
+  }
+
+  type LinkAttendance = {
+    id: string
+    staffId: string
+  }
+
+  type Addattendance = {
+    applicantStaffId: string
   }
 }