소스 검색

feat: 流程管理

chenlei 3 달 전
부모
커밋
0a38891e7b

+ 124 - 0
src/pages/A_workbench/A3flow/data.ts

@@ -0,0 +1,124 @@
+import { selectObj } from '@/utils/select'
+import { A3flowSearchType, IA3flowListParams } from './types'
+import { businessTypeObj, statusObj } from '@/utils/tableData'
+import { D4_APIdel } from '@/store/action/D4impStor'
+
+export const DEFAULT_A3FLOW_PARAMS: IA3flowListParams = {
+  pageNum: 1,
+  pageSize: 10,
+  num: '',
+  type: '',
+  name: '',
+  deptName: '',
+  userName: '',
+  date: '',
+  status: '',
+  userType: ''
+}
+
+export const A3FLOW_PARAM_ROWS: A3flowSearchType[] = [
+  { name: '业务类型', key: 'type', type: '下拉框', data: selectObj['业务类型'] },
+  { name: '业务编号', key: 'num', type: '输入框' },
+  { name: '申请名称', key: 'name', type: '输入框' },
+  { name: '发起部门', key: 'deptName', type: '输入框' },
+  { name: '发起人', key: 'userName', type: '输入框' },
+  { name: '发起日期范围', key: 'date', type: '日期选择' },
+  { name: '申请状态', key: 'status', type: '下拉框', data: selectObj['流程申请状态'] },
+  { name: '选择角色', key: 'userType', type: '下拉框', data: selectObj['角色'] }
+]
+
+export const A3FLOW_TABLE_COLUMNS = [
+  ['txtChange', '业务类型', 'type', businessTypeObj],
+  ['txt', '业务编号', 'num'],
+  ['txt', '申请名称', 'name'],
+  ['txt', '发起部门', 'deptName'],
+  ['txt', '发起人', 'userName'],
+  ['txt', '发起日期', 'createTime'],
+  ['txtChange', '申请状态', 'status', statusObj]
+]
+
+// TOFIX: 待完善
+// 业务类型详情映射
+export const BUSINESS_DETAIL_PATH_MAP: Record<string, string> = {
+  // 藏品征集
+  ZJ: 'collection_add',
+  // 藏品鉴定
+  JD: 'identify_edit',
+  // 藏品入馆
+  RG: 'enterMuseum_edit',
+  // 藏品入藏
+  RC: 'collection_store',
+  // 藏品登记
+  DJ: 'collection_register',
+  // 藏品编辑
+  BJ: 'collection_edit',
+  // 藏品删除
+  SC: 'collection_delete',
+  // 藏品入库
+  RK: 'impStor_edit',
+  // 藏品移库
+  YK: 'moveStor_edit',
+  // 藏品出库
+  CK: 'outStor_edit',
+  // 藏品注销
+  ZX: 'collection_writeoff',
+  // 藏品盘点
+  PD: 'collection_inventory',
+  // 人员出入库
+  CR: 'person_access',
+  // 事故登记
+  SG: 'accident_edit',
+  // 残损登记
+  CS: 'damage_edit',
+  // 现状登记
+  XZ: 'status_edit',
+  // 文物修复
+  XF: 'recovery_edit',
+  // 展览申请
+  ZL: 'exhibit_apply',
+  // 藏品总登记号
+  ZDJ: 'collection_mainRegister'
+}
+
+// TOFIX: 待完善
+// 业务类型删除接口映射
+export const BUSINESS_DELETE_API_MAP: Record<string, Function> = {
+  // 藏品征集
+  ZJ: D4_APIdel,
+  // 藏品鉴定
+  JD: D4_APIdel,
+  // 藏品入馆
+  RG: D4_APIdel,
+  // 藏品入藏
+  RC: D4_APIdel,
+  // 藏品登记
+  DJ: D4_APIdel,
+  // 藏品编辑
+  BJ: D4_APIdel,
+  // 藏品删除
+  SC: D4_APIdel,
+  // 藏品入库
+  RK: D4_APIdel,
+  // 藏品移库
+  YK: D4_APIdel,
+  // 藏品出库
+  CK: D4_APIdel,
+  // 藏品注销
+  ZX: D4_APIdel,
+  // 藏品盘点
+  PD: D4_APIdel,
+  // 人员出入库
+  CR: D4_APIdel,
+  // 事故登记
+  SG: D4_APIdel,
+  // 残损登记
+  CS: D4_APIdel,
+  // 现状登记
+  XZ: D4_APIdel,
+  // 文物修复
+  XF: D4_APIdel,
+  // 展览申请
+  ZL: D4_APIdel,
+  // 藏品总登记号
+  ZDJ: D4_APIdel
+}

+ 58 - 0
src/pages/A_workbench/A3flow/index.module.scss

@@ -1,4 +1,62 @@
 .A3flow {
+  background-color: #fff;
+  border-radius: 10px;
+  padding: 24px 24px 0;
+  position: relative;
   :global {
+    .C1top {
+      display: flex;
+      justify-content: space-between;
+      .C1topll {
+        display: flex;
+        & > div {
+          display: flex;
+          align-items: center;
+          position: relative;
+          &:not(:last-child) {
+            margin-right: 15px;
+          }
+          & > span {
+            position: absolute;
+            top: -18px;
+            left: 0;
+            pointer-events: none;
+          }
+        }
+      }
+
+      .C1toprrSuo {
+        width: 100%;
+        margin-top: 15px;
+        text-align: right;
+      }
+
+      .C1toprrKai {
+        position: relative;
+        top: 10px;
+        width: 310px;
+        height: 84px;
+        display: flex;
+        flex-wrap: wrap;
+        justify-content: center;
+      }
+
+      .C1topllAll {
+        width: 100%;
+        & > div {
+          flex: 1;
+          .ant-input {
+            width: 100%;
+          }
+          .ant-select {
+            width: 100%;
+          }
+        }
+      }
+    }
+    .C1top2 {
+      margin: 15px 0;
+      justify-content: flex-end;
+    }
   }
 }

+ 265 - 2
src/pages/A_workbench/A3flow/index.tsx

@@ -1,10 +1,273 @@
-import React from 'react'
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
+import { Button, Cascader, DatePicker, Input, Select } from 'antd'
+import { A3flowItemType, A3flowSearchType, IA3flowListParams } from './types'
+import {
+  DEFAULT_A3FLOW_PARAMS,
+  A3FLOW_PARAM_ROWS,
+  A3FLOW_TABLE_COLUMNS,
+  BUSINESS_DETAIL_PATH_MAP,
+  BUSINESS_DELETE_API_MAP
+} from './data'
 import styles from './index.module.scss'
+import MyTable from '@/components/MyTable'
+import { RootState } from '@/store'
+import { useDispatch, useSelector } from 'react-redux'
+import { A3_APIList } from '@/store/action/A3flow'
+import ExportJsonExcel from 'js-export-excel'
+import dayjs from 'dayjs'
+import { MessageFu } from '@/utils/message'
+import { businessTypeObj, statusObj } from '@/utils/tableData'
+import history, { btnFlagFu } from '@/utils/history'
+import MyPopconfirm from '@/components/MyPopconfirm'
+
+const { RangePicker } = DatePicker
+
 function A3flow() {
+  // 从仓库拿数据
+  const tableInfo = useSelector((state: RootState) => state.A3flow.tableInfo)
+  const [formData, setFormData] = useState({ ...DEFAULT_A3FLOW_PARAMS })
+  const formDataRef = useRef({ ...DEFAULT_A3FLOW_PARAMS })
+  const dispatch = useDispatch()
+
+  // 输入框的改变
+  const txtChangeFu = useCallback(
+    (txt: string, key: keyof IA3flowListParams) => {
+      setFormData({
+        ...formData,
+        [key]: txt
+      })
+    },
+    [formData]
+  )
+
+  // 顶部筛选
+  const searchDom = useCallback(
+    (arr: A3flowSearchType[]) => {
+      return arr.map(item => {
+        return (
+          <div key={item.name}>
+            <span>{item.name}:</span>
+            {item.type === '输入框' ? (
+              <Input
+                placeholder='请输入'
+                maxLength={30}
+                value={formData[item.key]}
+                onChange={e => txtChangeFu(e.target.value, item.key)}
+              />
+            ) : item.type === '下拉框' ? (
+              <Select
+                options={item.data}
+                placeholder='全部'
+                allowClear={true}
+                value={formData[item.key as 'num'] ? formData[item.key as 'num'] : null}
+                onChange={e => setFormData({ ...formData, [item.key]: e })}
+              />
+            ) : item.type === '日期选择' ? (
+              <RangePicker
+                format='YYYY-MM-DD'
+                allowClear={true}
+                onChange={(e, dateStrings) => setFormData({ ...formData, [item.key]: dateStrings })}
+              />
+            ) : (
+              <Cascader
+                options={item.data}
+                placeholder='全部'
+                fieldNames={{ label: 'name', value: 'id', children: 'children' }}
+                allowClear={true}
+                value={
+                  formData[item.key as 'num']
+                    ? (formData[item.key as 'num'] as string).split(',')
+                    : []
+                }
+                onChange={e => setFormData({ ...formData, [item.key]: e ? e.join(',') : '' })}
+              />
+            )}
+          </div>
+        )
+      })
+    },
+    [formData, txtChangeFu]
+  )
+
+  // 点击搜索的 时间戳
+  const [timeKey, setTimeKey] = useState(0)
+  // 点击搜索
+  const clickSearch = useCallback(() => {
+    setFormData({ ...formData, pageNum: 1 })
+    setTimeout(() => {
+      setTimeKey(Date.now())
+    }, 50)
+  }, [formData])
+
+  // 点击重置
+  const resetSelectFu = useCallback(() => {
+    setFormData({ ...DEFAULT_A3FLOW_PARAMS })
+    setTimeout(() => {
+      setTimeKey(Date.now())
+    }, 50)
+  }, [])
+
+  // 页码变化
+  const paginationChange = useCallback(
+    (pageNum: number, pageSize: number) => {
+      setFormData({ ...formData, pageNum, pageSize })
+      setTimeout(() => {
+        setTimeKey(Date.now())
+      }, 50)
+    },
+    [formData]
+  )
+
+  // 封装发送请求的函数
+  const getListFu = useCallback(() => {
+    const { date, ...rest } = formDataRef.current
+    if (Array.isArray(date) && date.length) {
+      // @ts-ignore
+      rest.startTime = date[0]
+      // @ts-ignore
+      rest.endTime = date[1]
+    }
+    dispatch(A3_APIList(rest))
+  }, [dispatch])
+
+  const handleExport = async () => {
+    const name = '流程管理' + dayjs(new Date()).format('YYYY-MM-DD HH:mm')
+
+    const res = await A3_APIList(
+      {
+        ...formDataRef.current,
+        pageNum: 1,
+        pageSize: 99999
+      },
+      true
+    )
+
+    if (res.code === 0) {
+      if (res.data.records.length <= 0) return MessageFu.warning('当前搜索条件没有数据!')
+
+      const option = {
+        fileName: name,
+        datas: [
+          {
+            sheetData: res.data.records.map((v: A3flowItemType) => ({
+              ...v,
+              type: Reflect.get(businessTypeObj, v.type) || '(空)',
+              status: Reflect.get(statusObj, v.status) || '(空)'
+            })),
+            sheetName: name,
+            sheetFilter: ['type', 'num', 'name', 'deptName', 'userName', 'createTime', 'status'],
+            sheetHeader: [
+              '业务类型',
+              '业务编号',
+              '申请名称',
+              '发起部门',
+              '发起人',
+              '发起日期',
+              '申请状态'
+            ],
+            columnWidths: [10, 10, 10, 10, 10, 10, 10]
+          }
+        ]
+      }
+
+      const toExcel = new ExportJsonExcel(option) //new
+      toExcel.saveExcel() //保存
+    }
+  }
+
+  // 点击操作按钮
+  const tableBtnFu = useCallback((item: A3flowItemType, key: string) => {
+    history.push(`/${BUSINESS_DETAIL_PATH_MAP[item.type]}/${key}/${item.id}`)
+  }, [])
+
+  // 点击删除
+  const delTableFu = useCallback(
+    async (item: A3flowItemType) => {
+      const res = await BUSINESS_DELETE_API_MAP[item.type]?.(item.id)
+      if (res.code === 0) {
+        MessageFu.success('删除成功')
+        getListFu()
+      }
+    },
+    [getListFu]
+  )
+
+  const tableLastBtn = useMemo(() => {
+    return [
+      {
+        title: '操作',
+        render: (item: any) => {
+          let obj = btnFlagFu(item)
+          return !Object.values(obj).some(Boolean) ? (
+            '-'
+          ) : (
+            <>
+              {obj['编辑'] ? (
+                <Button size='small' type='text' onClick={() => tableBtnFu(item, '2')}>
+                  编辑
+                </Button>
+              ) : null}
+
+              {obj['审批'] ? (
+                <Button size='small' type='text' onClick={() => tableBtnFu(item, '3')}>
+                  审批
+                </Button>
+              ) : null}
+              {obj['查看'] ? (
+                <Button size='small' type='text' onClick={() => tableBtnFu(item, '4')}>
+                  查看
+                </Button>
+              ) : null}
+
+              {obj['删除'] ? <MyPopconfirm txtK='删除' onConfirm={() => delTableFu(item)} /> : null}
+            </>
+          )
+        }
+      }
+    ]
+  }, [delTableFu, tableBtnFu])
+
+  useEffect(() => {
+    getListFu()
+  }, [getListFu, timeKey])
+
+  useEffect(() => {
+    formDataRef.current = formData
+  }, [formData])
+
   return (
     <div className={styles.A3flow}>
       <div className='pageTitle'>流程管理</div>
-      <p>待开发</p>
+
+      {/* 第一行 */}
+      <div className='C1top'>
+        <div className='C1topll C1topllAll'>{searchDom(A3FLOW_PARAM_ROWS)}</div>
+      </div>
+
+      {/* 第二行 */}
+      <div className='C1top C1top2'>
+        <Button type='primary' onClick={handleExport}>
+          批量导出
+        </Button>
+        &emsp;
+        <Button type='primary' onClick={clickSearch}>
+          查询
+        </Button>
+        &emsp;
+        <Button onClick={resetSelectFu}>重置</Button>
+      </div>
+
+      {/* 表格 */}
+      <MyTable
+        yHeight={595}
+        list={tableInfo.list}
+        columnsTemp={A3FLOW_TABLE_COLUMNS}
+        lastBtn={tableLastBtn}
+        pageNum={formData.pageNum}
+        pageSize={formData.pageSize}
+        total={tableInfo.total}
+        onChange={(pageNum, pageSize) => paginationChange(pageNum, pageSize)}
+      />
     </div>
   )
 }

+ 32 - 0
src/pages/A_workbench/A3flow/types.ts

@@ -0,0 +1,32 @@
+export interface IA3flowListParams {
+  pageSize: number
+  pageNum: number
+  num: string
+  type: string
+  name: string
+  deptName: string
+  userName: string
+  date: string
+  status: string
+  userType: string
+}
+
+export type A3flowSearchType = {
+  name: string
+  key: keyof IA3flowListParams
+  type: '输入框' | '下拉框' | '级联' | '日期选择'
+  data?: any[]
+}
+
+export type A3flowItemType = {
+  id: number
+  num: string
+  type: string
+  name: string
+  deptName: string
+  userName: string
+  date: string
+  status: string
+  userType: string
+  createTime: string
+}

+ 20 - 0
src/store/action/A3flow.ts

@@ -0,0 +1,20 @@
+import http from '@/utils/http'
+import { AppDispatch } from '..'
+
+/**
+ * 业务中心-编辑用户信息
+ */
+export const A3_APIList = (data: any, exportFlag = false): any => {
+  if (exportFlag) return http.post('/cms/flowManage/page', data)
+  return async (dispatch: AppDispatch) => {
+    const res = await http.post('/cms/flowManage/page', data)
+    if (res.code === 0) {
+      const obj = {
+        list: res.data.records,
+        total: res.data.total
+      }
+
+      dispatch({ type: 'A3/getList', payload: obj })
+    }
+  }
+}

+ 28 - 0
src/store/reducer/A3flow.ts

@@ -0,0 +1,28 @@
+import { A3flowItemType } from '@/pages/A_workbench/A3flow/types'
+
+// 初始化状态
+const initState = {
+  // 列表数据
+  tableInfo: {
+    list: [] as A3flowItemType[],
+    total: 0
+  }
+}
+
+// 定义 action 类型
+type Props = {
+  type: 'A3/getList'
+  payload: { list: A3flowItemType[]; total: number }
+}
+
+// reducer
+export default function userReducer(state = initState, action: Props) {
+  switch (action.type) {
+    // 获取列表数据
+    case 'A3/getList':
+      return { ...state, tableInfo: action.payload }
+
+    default:
+      return state
+  }
+}

+ 3 - 1
src/store/reducer/index.ts

@@ -25,6 +25,7 @@ import Z4organization from './Z4organization'
 import Z5role from './Z5role'
 import Z6user from './Z6user'
 import Z7log from './Z7log'
+import A3flow from './A3flow'
 
 // 合并 reducer
 const rootReducer = combineReducers({
@@ -50,7 +51,8 @@ const rootReducer = combineReducers({
   Z4organization,
   Z5role,
   Z6user,
-  Z7log
+  Z7log,
+  A3flow
 })
 
 // 默认导出

+ 0 - 1
src/utils/exportWordTemplates.ts

@@ -175,7 +175,6 @@ export const exportWordHandler = async (type: EXPORT_WORD_ENUM, data: Record<any
   if (item.perLine) {
     // @ts-ignore
     page = calcTablePages(temp.goods, item)
-    console.log(page)
   }
 
   switch (type) {

+ 26 - 0
src/utils/select.ts

@@ -78,5 +78,31 @@ export const selectObj = {
   展览状态: [
     { value: '6', label: '外部借展' },
     { value: '5', label: '内部借展' }
+  ],
+  流程申请状态: [
+    { value: 2, label: '待审批' },
+    { value: 3, label: '审批不通过' },
+    { value: 4, label: '已完成' }
+  ],
+  业务类型: [
+    { value: 'ZJ', label: '藏品征集' },
+    { value: 'JD', label: '藏品鉴定' },
+    { value: 'RG', label: '藏品入馆' },
+    { value: 'RC', label: '藏品入藏' },
+    { value: 'DJ', label: '藏品登记' },
+    { value: 'BJ', label: '藏品编辑' },
+    { value: 'SC', label: '藏品删除' },
+    { value: 'RK', label: '藏品入库' },
+    { value: 'YK', label: '藏品移库' },
+    { value: 'CK', label: '藏品出库' },
+    { value: 'ZX', label: '藏品注销' },
+    { value: 'PD', label: '藏品盘点' },
+    { value: 'CR', label: '人员出入库' },
+    { value: 'SG', label: '事故登记' },
+    { value: 'CS', label: '残损登记' },
+    { value: 'XZ', label: '现状登记' },
+    { value: 'XF', label: '文物修复' },
+    { value: 'ZL', label: '展览申请' },
+    { value: 'ZDJ', label: '藏品总登记号' }
   ]
 }

+ 6 - 0
src/utils/tableData.ts

@@ -35,6 +35,12 @@ selectObj['入藏状态'].forEach(v => {
   statusCollectObj[v.value] = v.label
 })
 
+// 业务类型obj
+export const businessTypeObj: any = {}
+selectObj['业务类型'].forEach(v => {
+  businessTypeObj[v.value] = v.label
+})
+
 export const B1TableC = [
   ['txt', '线索名称', 'name'],
   ['txt', '线索类别', 'type'],