shaogen1995 1 месяц назад
Родитель
Сommit
42e2edbfd5
32 измененных файлов с 2303 добавлено и 33 удалено
  1. 3 1
      后台管理/src/components/MyPopconfirm.tsx
  2. 4 0
      后台管理/src/components/MyTable/index.tsx
  3. 3 1
      后台管理/src/components/Z3upFiles/index.tsx
  4. 2 0
      后台管理/src/pages/A0goodsInfo/Tab1info/index.module.scss
  5. 26 0
      后台管理/src/pages/A0goodsInfo/Tab3stock/index.module.scss
  6. 134 3
      后台管理/src/pages/A0goodsInfo/Tab3stock/index.tsx
  7. 59 12
      后台管理/src/pages/A0goodsInfo/index.tsx
  8. 45 0
      后台管理/src/pages/A0selectGoods/index.module.scss
  9. 195 0
      后台管理/src/pages/A0selectGoods/index.tsx
  10. 9 0
      后台管理/src/pages/B1ledger/data.ts
  11. 1 1
      后台管理/src/pages/B4delete/B4look/index.tsx
  12. 87 0
      后台管理/src/pages/C2storageIn/C2look/index.module.scss
  13. 450 3
      后台管理/src/pages/C2storageIn/C2look/index.tsx
  14. 39 0
      后台管理/src/pages/C2storageIn/data.ts
  15. 19 0
      后台管理/src/pages/C2storageIn/index.module.scss
  16. 163 1
      后台管理/src/pages/C2storageIn/index.tsx
  17. 87 0
      后台管理/src/pages/C4storageOut/C4look/index.module.scss
  18. 442 2
      后台管理/src/pages/C4storageOut/C4look/index.tsx
  19. 19 0
      后台管理/src/pages/C4storageOut/index.module.scss
  20. 163 1
      后台管理/src/pages/C4storageOut/index.tsx
  21. 6 3
      后台管理/src/pages/Layout/data.ts
  22. 16 0
      后台管理/src/store/action/B1ledger.ts
  23. 49 0
      后台管理/src/store/action/C2storageIn.ts
  24. 49 0
      后台管理/src/store/action/C3storageMove.ts
  25. 49 0
      后台管理/src/store/action/C4storageOut.ts
  26. 28 0
      后台管理/src/store/reducer/C2storageIn.ts
  27. 28 0
      后台管理/src/store/reducer/C3storageMove.ts
  28. 28 0
      后台管理/src/store/reducer/C4storageOut.ts
  29. 6 1
      后台管理/src/store/reducer/index.ts
  30. 1 1
      后台管理/src/types/api/layot.d.ts
  31. 54 1
      后台管理/src/utils/deriveFu.ts
  32. 39 2
      后台管理/src/utils/tableData.ts

+ 3 - 1
后台管理/src/components/MyPopconfirm.tsx

@@ -2,7 +2,7 @@ import React, { useMemo } from 'react'
 import { Button, Popconfirm } from 'antd'
 
 type Props = {
-  txtK: '删除' | '取消' | '重置密码' | '退出登录' | '重新提交'
+  txtK: '删除' | '删除2' | '取消' | '返回' | '重置密码' | '退出登录' | '重新提交'
   onConfirm: () => void
   Dom?: React.ReactNode
   loc?: 'bottom'
@@ -12,7 +12,9 @@ function MyPopconfirm({ txtK, onConfirm, Dom, loc }: Props) {
   const txt = useMemo(() => {
     const obj = {
       删除: ['删除后无法恢复,是否删除?', '删除'],
+      删除2: ['确定发起删除订单吗?', '确定'],
       取消: ['放弃编辑后,信息将不会保存!', '放弃'],
+      返回: ['放弃编辑后,信息将不会保存!', '放弃'],
       重置密码: ['密码重制后为Aa147852,是否重置?', '重置'],
       退出登录: ['确定退出吗?', '确定'],
       重新提交: ['确定重新提交吗?', '确定']

+ 4 - 0
后台管理/src/components/MyTable/index.tsx

@@ -3,6 +3,7 @@ import styles from './index.module.scss'
 import { Table } from 'antd'
 import ImageLazy from '../ImageLazy'
 import dayjs from 'dayjs'
+import { siteLocChange } from '@/utils/deriveFu'
 
 type Props = {
   yHeight?: number //设置表格的高度
@@ -105,6 +106,9 @@ function MyTable({
             />
           </div>
         ),
+        siteLoc: (item: any) => {
+          return siteLocChange(item[v[2]])
+        },
         time: (item: any) => {
           let txt = isNull
           if (item[v[2]]) {

+ 3 - 1
后台管理/src/components/Z3upFiles/index.tsx

@@ -300,7 +300,9 @@ function Z3upFiles(
           </div>
         </div>
       </div>
-      {isLook && fileList.length <= 0 ? <div>(空)</div> : null}
+      {isLook && fileList.length <= 0 ? (
+        <div style={{ height: 32, lineHeight: '32px' }}>(空)</div>
+      ) : null}
     </div>
   )
 }

+ 2 - 0
后台管理/src/pages/A0goodsInfo/Tab1info/index.module.scss

@@ -54,6 +54,8 @@
       display: flex;
       & > div {
         &:nth-of-type(1) {
+          min-height: 32px;
+          line-height: 32px;
           width: 100px;
           text-align: right;
           font-weight: 700;

+ 26 - 0
后台管理/src/pages/A0goodsInfo/Tab3stock/index.module.scss

@@ -1,4 +1,30 @@
 .Tab3stock {
+  font-size: 16px;
   :global {
+    .T3top {
+      display: flex;
+      flex-wrap: wrap;
+      margin-bottom: 10px;
+      .T3topRow {
+        width: 40%;
+        display: flex;
+        align-items: center;
+        margin-bottom: 10px;
+        .T3topRowll {
+          width: 100px;
+          text-align: right;
+          font-weight: 700;
+        }
+        .T3topRowrr {
+          width: calc(100% - 100px);
+        }
+      }
+      // .T3topRowAll {
+      //   width: 100%;
+      // }
+    }
+    .ant-table-cell {
+      padding: 8px !important;
+    }
   }
 }

+ 134 - 3
后台管理/src/pages/A0goodsInfo/Tab3stock/index.tsx

@@ -1,9 +1,140 @@
-import React from 'react'
+import React, { useCallback, useEffect, useMemo, useState } from 'react'
 import styles from './index.module.scss'
-function Tab3stock() {
+import { B1listType } from '@/pages/B1ledger/data'
+import { API_getStorageLog } from '@/store/action/B1ledger'
+import { storageSelect } from '@/utils/select'
+import MyTable from '@/components/MyTable'
+import tabLeftArr from '@/pages/Layout/data'
+import { Button } from 'antd'
+import { authorityFu } from '@/utils/authority'
+import { openLink } from '@/utils/history'
+import { MessageFu } from '@/utils/message'
+import { siteLocChange, timeChange } from '@/utils/deriveFu'
+import { goodsStorageTableC } from '@/utils/tableData'
+
+type Props = {
+  info: B1listType
+}
+
+function Tab3stock({ info }: Props) {
+  const [loding, setLoding] = useState(false)
+
+  const [list, setList] = useState<B1listType[]>([])
+
+  const getListFu = useCallback(async () => {
+    const res = await API_getStorageLog(info.id)
+    if (res.code === 0) {
+      setLoding(true)
+      setList(res.data)
+
+      // 第一条入库信息
+    }
+  }, [info.id])
+
+  useEffect(() => {
+    getListFu()
+  }, [getListFu])
+
+  // 库存状态
+  const staTxt = useMemo(() => {
+    let txt = '(空)'
+    const obj = storageSelect.find(v => v.value === info.siteStatus)
+    if (obj) txt = obj.label
+    return txt
+  }, [info.siteStatus])
+
+  const dataChange = useCallback((item: B1listType) => {
+    const arr = tabLeftArr[2].son
+    const obj = arr.find(v => v.pageType === item.type)
+    return obj
+  }, [])
+
+  const staBtn = useMemo(() => {
+    return [
+      {
+        title: '日期',
+        render: (item: B1listType) => timeChange(item.date)
+      },
+      {
+        title: '订单类型',
+        render: (item: B1listType) => {
+          const obj = dataChange(item)
+
+          return obj ? obj.name : '(空)'
+        }
+      }
+    ]
+  }, [dataChange])
+
+  const tableLastBtn = useMemo(() => {
+    return [
+      {
+        title: '操作',
+        render: (item: B1listType) => {
+          return (
+            <Button
+              size='small'
+              type='text'
+              onClick={() => {
+                const obj = dataChange(item)
+                if (obj) {
+                  authorityFu(obj.id, `您没有${obj.name}页面权限`, () => {
+                    openLink(`${obj.path}_look/3/${item.id}`)
+                  })
+                } else MessageFu.warning(`type字段:${item.type} 错误`)
+              }}
+            >
+              查看
+            </Button>
+          )
+        }
+      }
+    ]
+  }, [dataChange])
+
+  // // 最新一条出库信息
+  // const chuKuObj = useMemo(() => {
+  //   let obj = list.find(v => v.type === 'CK' && v.status === 3)
+  //   return obj || ({} as B1listType)
+  // }, [list])
+
+  // // 最新一条入库信息
+  // const ruKuObj = useMemo(() => {
+  //   let obj = list.find(v => v.type === 'RK' && v.status === 3)
+  //   return obj || ({} as B1listType)
+  // }, [list])
+
   return (
     <div className={styles.Tab3stock}>
-      <h1>Tab3stock 待完善</h1>
+      <div className='T3top'>
+        <div className='T3topRow'>
+          <div className='T3topRowll'>库存状态:</div>
+          <div className='T3topRowrr'>{staTxt}</div>
+        </div>
+        <div className='T3topRow'>
+          <div className='T3topRowll'>当前位置:</div>
+          <div className='T3topRowrr'>{siteLocChange(info.siteLoc)}</div>
+        </div>
+        <div className='T3topRow'>
+          <div className='T3topRowll'>入库时间:</div>
+          <div className='T3topRowrr'>{timeChange(info.siteDateIn)}</div>
+        </div>
+        <div className='T3topRow'>
+          <div className='T3topRowll'>出库时间:</div>
+          <div className='T3topRowrr'>{timeChange(info.siteDateOut)}</div>
+        </div>
+      </div>
+
+      {loding ? (
+        <MyTable
+          yHeight={690}
+          list={list}
+          columnsTemp={goodsStorageTableC}
+          staBtn={staBtn}
+          lastBtn={tableLastBtn}
+          pagingInfo={false}
+        />
+      ) : null}
     </div>
   )
 }

+ 59 - 12
后台管理/src/pages/A0goodsInfo/index.tsx

@@ -13,6 +13,8 @@ import A0addGoods from '../A0addGoods'
 import history from '@/utils/history'
 import { B4_APIcreate } from '@/store/action/B4delete'
 import { authorityFu } from '@/utils/authority'
+import MyPopconfirm from '@/components/MyPopconfirm'
+import { storageSelect } from '@/utils/select'
 const topBtnArr = ['藏品信息', '编辑记录', '库存状态']
 
 function A0goodsInfo() {
@@ -59,10 +61,9 @@ function A0goodsInfo() {
       {
         key: '2',
         label: (
-          <span
-            className='AIdroRow'
-            style={{ color: '#ff4d4d' }}
-            onClick={() => {
+          <MyPopconfirm
+            txtK='删除2'
+            onConfirm={() => {
               authorityFu(600, '您没有藏品删除页面权限', async () => {
                 if (goodsInfo.status === 3) MessageFu.warning('该藏品删除审核中,无法重复删除')
                 else if (goodsInfo.status === 2) MessageFu.warning('该藏品修改审核中,无法删除')
@@ -75,9 +76,12 @@ function A0goodsInfo() {
                 }
               })
             }}
-          >
-            删除
-          </span>
+            Dom={
+              <span className='AIdroRow' style={{ color: '#ff4d4d' }}>
+                删除
+              </span>
+            }
+          />
         )
       }
     ]
@@ -85,24 +89,67 @@ function A0goodsInfo() {
     return arr
   }, [goodsInfo])
 
+  const siteStatusTxt = useMemo(() => {
+    return storageSelect.find(v => v.value === goodsInfo.siteStatus)?.label
+  }, [goodsInfo.siteStatus])
+
   const items2 = useMemo(() => {
     let arr: MenuProps['items'] = [
       {
         key: '1',
-        label: <span className='AIdroRow'>入库</span>
+        label: (
+          <span
+            className='AIdroRow'
+            onClick={() => {
+              authorityFu(800, '您没有藏品入库页面权限', () => {
+                if ([1, 2, 3, 4].includes(goodsInfo.siteStatus)) {
+                  MessageFu.warning(`该藏品${siteStatusTxt},无法入库`)
+                } else history.push(`/storageIn_look/1/0?oldId=${goodsInfo.id}`)
+              })
+            }}
+          >
+            入库
+          </span>
+        )
       },
       {
         key: '2',
-        label: <span className='AIdroRow'>移库</span>
+        label: (
+          <span
+            className='AIdroRow'
+            onClick={() => {
+              authorityFu(900, '您没有藏品移库库页面权限', () => {
+                if ([0, 1, 3, 4, 5].includes(goodsInfo.siteStatus)) {
+                  MessageFu.warning(`该藏品${siteStatusTxt},无法移库`)
+                } else history.push(`/storageMove_look/1/0?oldId=${goodsInfo.id}`)
+              })
+            }}
+          >
+            移库
+          </span>
+        )
       },
       {
         key: '3',
-        label: <span className='AIdroRow'>出库</span>
+        label: (
+          <span
+            className='AIdroRow'
+            onClick={() => {
+              authorityFu(1000, '您没有藏品出库页面权限', () => {
+                if ([0, 1, 3, 4, 5].includes(goodsInfo.siteStatus)) {
+                  MessageFu.warning(`该藏品${siteStatusTxt},无法出库`)
+                } else history.push(`/storageOut_look/1/0?oldId=${goodsInfo.id}`)
+              })
+            }}
+          >
+            出库
+          </span>
+        )
       }
     ]
 
     return arr
-  }, [])
+  }, [goodsInfo.id, goodsInfo.siteStatus, siteStatusTxt])
 
   return (
     <div className={styles.A0goodsInfo}>
@@ -136,7 +183,7 @@ function A0goodsInfo() {
         <div className='AImain'>
           {btnAc === '藏品信息' ? <Tab1info info={goodsInfo} /> : null}
           {btnAc === '编辑记录' ? <Tab2log sId={goodsInfo.id} /> : null}
-          {btnAc === '库存状态' ? <Tab3stock /> : null}
+          {btnAc === '库存状态' ? <Tab3stock info={goodsInfo} /> : null}
         </div>
       ) : null}
 

+ 45 - 0
后台管理/src/pages/A0selectGoods/index.module.scss

@@ -0,0 +1,45 @@
+.A0selectGoods {
+  :global {
+    .AStit {
+      display: flex;
+      justify-content: space-between;
+    }
+    .ant-modal-close {
+      display: none;
+    }
+
+    .ant-modal {
+      width: 1600px !important;
+      min-width: 1600px;
+      top: 40px !important;
+    }
+
+    .ant-modal-body {
+      border-top: 1px solid #ccc;
+
+      .AStop {
+        padding-top: 15px;
+        margin-bottom: 15px;
+        display: flex;
+        justify-content: space-between;
+      }
+    }
+
+    .ant-table-cell {
+      padding: 8px !important;
+      text-align: center !important;
+    }
+    .ant-btn-text {
+      color: var(--themeColor);
+    }
+    .tableImgAuto {
+      display: flex;
+      justify-content: center;
+    }
+    .ASbtn {
+      position: relative;
+      top: 15px;
+      text-align: center;
+    }
+  }
+}

+ 195 - 0
后台管理/src/pages/A0selectGoods/index.tsx

@@ -0,0 +1,195 @@
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
+import styles from './index.module.scss'
+import { Button, Checkbox, Input, Modal, Select } from 'antd'
+import { B1fromDataBase, B1listType } from '../B1ledger/data'
+import { API_selectGoods } from '@/store/action/B1ledger'
+import { dictSelect } from '@/utils/select'
+import MyTable from '@/components/MyTable'
+import { selectGoodsAddTableC } from '@/utils/tableData'
+import { openLink } from '@/utils/history'
+import MyPopconfirm from '@/components/MyPopconfirm'
+
+type Props = {
+  type: '入库' | '移库' | '出库'
+  closeFu: () => void
+  dataResFu: (data: B1listType[]) => void
+  oldCheckArr: B1listType[]
+}
+
+function A0selectGoods({ type, closeFu, dataResFu, oldCheckArr }: Props) {
+  const [tableList, setTableList] = useState<B1listType[]>([])
+  const [tableListAll, setTableListAll] = useState<B1listType[]>([])
+
+  // 多选
+  const [checkArr, setCheckArr] = useState<B1listType[]>([])
+
+  // 旧数组
+  useEffect(() => {
+    setCheckArr(oldCheckArr)
+  }, [oldCheckArr])
+
+  const [formData, setFormData] = useState({ ...B1fromDataBase, pageSize: 999999 })
+
+  // 输入框改变
+  const timeRef = useRef(-1)
+  const txtChangeFu = useCallback(
+    (e: React.ChangeEvent<HTMLInputElement>, key: 'searchKey') => {
+      clearTimeout(timeRef.current)
+      timeRef.current = window.setTimeout(() => {
+        setFormData({
+          ...formData,
+          [key]: e.target.value,
+          pageNum: 1
+        })
+      }, 500)
+    },
+    [formData]
+  )
+
+  // 点击重置
+  const [inputKey, setInputKey] = useState(1)
+  const resetSelectFu = useCallback(() => {
+    // 把2个输入框和时间选择器清空
+    setInputKey(Date.now())
+    setFormData(B1fromDataBase)
+  }, [])
+
+  const getListFu = useCallback(async () => {
+    const res = await API_selectGoods(type, formData)
+    if (res.code === 0) {
+      setTableList(res.data.records)
+      if (timeRef.current === -1) {
+        timeRef.current = 1
+        setTableListAll(res.data.records)
+      }
+    }
+  }, [formData, type])
+
+  useEffect(() => {
+    getListFu()
+  }, [getListFu])
+
+  // 过滤掉 tableList 里面没有的id
+  const resNum = useMemo(() => {
+    const tableIds = tableListAll.map(v => v.id)
+    const arr = checkArr.filter(v => tableIds.includes(v.id))
+    return arr.length
+  }, [checkArr, tableListAll])
+
+  const checkFu = useCallback(
+    (item: B1listType) => {
+      // 藏品编辑只能单选
+      if (checkArr.map(v => v.id).includes(item.id))
+        setCheckArr(checkArr.filter(v => v.id !== item.id))
+      else setCheckArr([...checkArr, item])
+    },
+    [checkArr]
+  )
+
+  const startBtn = useMemo(() => {
+    return [
+      {
+        title: '选择',
+        width: 50,
+        render: (item: B1listType) => (
+          <Checkbox
+            checked={checkArr.map(v => v.id).includes(item.id)}
+            onChange={() => checkFu(item)}
+          />
+        )
+      }
+    ]
+  }, [checkArr, checkFu])
+
+  const tableLastBtn = useMemo(() => {
+    return [
+      {
+        title: '查看',
+        width: 80,
+        render: (item: B1listType) => (
+          <Button size='small' type='text' onClick={() => openLink(`/goodsLook/${item.id}`)}>
+            查看
+          </Button>
+        )
+      }
+    ]
+  }, [])
+
+  // 点击提交
+  const btnOk = useCallback(() => {
+    dataResFu(checkArr)
+    closeFu()
+  }, [checkArr, closeFu, dataResFu])
+
+  return (
+    <Modal
+      wrapClassName={styles.A0selectGoods}
+      open={true}
+      title={
+        <div className='AStit'>
+          <div>选择藏品</div> <div>已选中 {resNum} 条</div>
+        </div>
+      }
+      footer={
+        [] // 设置footer为空,去掉 取消 确定默认按钮
+      }
+    >
+      {/* 顶部筛选 */}
+      <div className='AStop'>
+        <div>
+          <Input
+            placeholder='请填入藏品编号或标题'
+            maxLength={30}
+            showCount
+            key={inputKey}
+            allowClear
+            onChange={e => txtChangeFu(e, 'searchKey')}
+            style={{ width: 300 }}
+          />
+          &emsp;
+          <Select
+            allowClear
+            style={{ width: 200 }}
+            placeholder='类型'
+            options={dictSelect('藏品类型')}
+            value={formData.typeDictId}
+            onChange={e => setFormData({ ...formData, typeDictId: e })}
+          />
+          &emsp;
+          <Select
+            allowClear
+            style={{ width: 200 }}
+            placeholder='材质'
+            options={dictSelect('藏品材质')}
+            value={formData.textureDictId}
+            onChange={e => setFormData({ ...formData, textureDictId: e })}
+          />
+        </div>
+        <Button onClick={resetSelectFu}>重置</Button>
+      </div>
+
+      {/* 表格 */}
+      <MyTable
+        yHeight={575}
+        classKey='AStable'
+        list={tableList}
+        columnsTemp={selectGoodsAddTableC}
+        staBtn={startBtn}
+        lastBtn={tableLastBtn}
+        pagingInfo={false}
+      />
+
+      <div className='ASbtn'>
+        <Button type='primary' disabled={resNum === 0} onClick={btnOk}>
+          提交
+        </Button>
+        &emsp;
+        <MyPopconfirm txtK='取消' onConfirm={closeFu} />
+      </div>
+    </Modal>
+  )
+}
+
+const MemoA0selectGoods = React.memo(A0selectGoods)
+
+export default MemoA0selectGoods

+ 9 - 0
后台管理/src/pages/B1ledger/data.ts

@@ -79,6 +79,15 @@ export type B1listType = {
   oldGoods: string
 
   type: string
+
+  // 入库
+  reason: string
+  date: string
+  id2?: number
+  siteIn: string
+
+  // 出库
+  siteOut: string
 }
 
 export type GoodsAduitsType = {

+ 1 - 1
后台管理/src/pages/B4delete/B4look/index.tsx

@@ -80,7 +80,7 @@ function B4look() {
   }, [auditSta, id, rtfOpinion])
 
   return (
-    <div className={styles.B4look}>
+    <div className={styles.B4look} ref={boxRef}>
       <div className='pageTitle'>藏品删除 - {key === '1' ? '查看' : '审批'}</div>
 
       {info.id ? (

+ 87 - 0
后台管理/src/pages/C2storageIn/C2look/index.module.scss

@@ -1,4 +1,91 @@
 .C2look {
+  background-color: #fff;
+  border-radius: 10px;
+  font-size: 16px;
+  overflow: auto;
+  padding: 20px;
   :global {
+    .C2lTit {
+      font-weight: 700;
+      font-size: 18px;
+      color: var(--themeColor);
+      margin-right: 20px;
+    }
+
+    .C2lTit2 {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+    }
+
+    .C2lTop {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      border-bottom: 1px solid #ccc;
+      padding-bottom: 15px;
+
+      .C2lTopll {
+        display: flex;
+        align-items: center;
+      }
+      .C2lToprr {
+        position: absolute;
+        top: 20px;
+        right: 20px;
+        z-index: 10;
+      }
+      .C2lTopllBtn {
+        pointer-events: none;
+      }
+    }
+
+    .C2form {
+      display: flex;
+      flex-wrap: wrap;
+      display: flex;
+      justify-content: space-between;
+      border-bottom: 1px solid #ccc;
+      padding: 15px 0;
+      margin-bottom: 15px;
+      padding-right: 15%;
+    }
+    .C2formRow {
+      width: 49%;
+      display: flex;
+      margin-bottom: 15px;
+      .C2formRowll {
+        position: relative;
+        width: 110px;
+        font-weight: 700;
+        text-align: right;
+        min-height: 32px;
+        line-height: 32px;
+        & > span {
+          color: #ff4d4f;
+        }
+      }
+
+      .C2formRowrr {
+        width: calc(100% - 110px);
+        .ant-btn {
+          margin-right: 20px;
+        }
+      }
+      .C2formRowrr2 {
+        height: 32px;
+        line-height: 32px;
+      }
+    }
+    .C2formRowAll {
+      width: 100%;
+    }
+
+    .ant-table-wrapper {
+      margin-top: 15px;
+      .ant-table-cell {
+        padding: 8px !important;
+      }
+    }
   }
 }

+ 450 - 3
后台管理/src/pages/C2storageIn/C2look/index.tsx

@@ -1,9 +1,456 @@
-import React from 'react'
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
 import styles from './index.module.scss'
+import { useParams } from 'react-router-dom'
+import {
+  C2_APIaduit,
+  C2_APIcreate,
+  C2_APIgetInfo,
+  C2_APIresubmit
+} from '@/store/action/C2storageIn'
+import { C2lookPageStaObj, locTxtChangeFu, locTxtValueFu } from '../data'
+import { B1listType } from '@/pages/B1ledger/data'
+import { Button, DatePicker, Input } from 'antd'
+import { statusSelect } from '@/utils/select'
+import history, { backPageFu, openLink } from '@/utils/history'
+import MyPopconfirm from '@/components/MyPopconfirm'
+import { MessageFu } from '@/utils/message'
+import dayjs from 'dayjs'
+import TextArea from 'antd/es/input/TextArea'
+import Z3upFiles from '@/components/Z3upFiles'
+import MyTable from '@/components/MyTable'
+import { auditTableC, goodsSelectTableC } from '@/utils/tableData'
+import A0selectGoods from '@/pages/A0selectGoods'
+import { API_getGoodsInfo } from '@/store/action/B1ledger'
 function C2look() {
+  const { key, id } = useParams<any>()
+  // key:1-新增 2-重新提交/编辑 3-查看 4-审批
+
+  // 从藏品信息模块进来,带上当前藏品信息
+  const isGoodsInfoRu = useCallback(async (id: number) => {
+    const res = await API_getGoodsInfo(id)
+    if (res.code === 0) {
+      setSnaps([res.data])
+    }
+  }, [])
+
+  useEffect(() => {
+    const urlAll = window.location.href
+    if (key === '1' && urlAll.includes('?oldId=')) {
+      isGoodsInfoRu(Number(urlAll.split('?oldId=')[1]))
+    }
+  }, [isGoodsInfoRu, key])
+
+  // 顶部数据
+  const [info, setInfo] = useState({} as B1listType)
+
+  // 新增的时候进页面创建订单
+  const createFu = useCallback(async () => {
+    const res = await C2_APIcreate()
+    if (res.code === 0) {
+      setInfo(res.data)
+    }
+  }, [])
+
+  // 获取详情
+  const getInfoFu = useCallback(async () => {
+    const res = await C2_APIgetInfo(id)
+    if (res.code === 0) {
+      // console.log('获取详情:', res)
+      const data = res.data
+      setInfo(data)
+      // 设置附件(需要异步)
+
+      setTimeout(() => {
+        filesRef.current?.showList(data.files || [])
+      }, 100)
+
+      // 藏品清单快照信息id对比
+      const arrTemp: any = []
+      const snapsTemp = data.snaps || []
+
+      snapsTemp.forEach((v: any) => {
+        snapsID2ref.current.push({ goodsId: v.goodsId, id: v.id })
+
+        const obj = JSON.parse(v.snap || '{}')
+        if (obj.id) obj.id2 = v.id
+
+        arrTemp.push({ ...obj })
+      })
+
+      setSnaps(arrTemp)
+    }
+  }, [id])
+
+  useEffect(() => {
+    if (key === '1') createFu()
+    else if (['2', '3', '4'].includes(key)) getInfoFu()
+  }, [createFu, getInfoFu, key])
+
+  // 申请状态
+  const topStatusRes = useMemo(() => {
+    let txt = '创建订单'
+    const obj = statusSelect.find(v => v.value === info.status)
+    if (obj) txt = obj.label
+    return txt
+  }, [info.status])
+
+  // 审批的sta
+  const [auditSta, setAuDitSta] = useState('')
+  const [rtfOpinion, setRtfOpinion] = useState('')
+
+  const boxRef = useRef<HTMLDivElement>(null)
+
+  // 上传附件的ref
+  const filesRef = useRef<any>(null)
+
+  // 藏品清单 和 快照数据
+
+  const [snaps, setSnaps] = useState<B1listType[]>([])
+  const delSnapIdsRef = useRef<number[]>([])
+
+  const snapsID2ref = useRef<{ goodsId: number; id: number }[]>([])
+
+  const goodsTableBtn = useMemo(() => {
+    return [
+      {
+        title: '入库位置',
+        render: (item: B1listType) => {
+          return (
+            <>
+              {['柜号', '层数', '层格编号'].map((txt, index) => (
+                <div key={index} className='C2TableTxt'>
+                  <Input
+                    readOnly={['3', '4'].includes(key)}
+                    placeholder={['3', '4'].includes(key) ? '(空)' : `请输入${txt}`}
+                    maxLength={10}
+                    value={locTxtValueFu(index, item.siteIn)}
+                    showCount
+                    onChange={e =>
+                      setSnaps(
+                        snaps.map(v => ({
+                          ...v,
+                          siteIn:
+                            v.id === item.id
+                              ? locTxtChangeFu(index, e.target.value.trim(), item.siteIn)
+                              : v.siteIn
+                        }))
+                      )
+                    }
+                  />
+                </div>
+              ))}
+            </>
+          )
+        }
+      },
+      {
+        title: '操作',
+        render: (item: B1listType) => {
+          return (
+            <>
+              <Button size='small' type='text' onClick={() => openLink(`/goodsLook/${item.id}`)}>
+                查看
+              </Button>
+              {['3', '4'].includes(key) ? null : (
+                <MyPopconfirm
+                  txtK='删除'
+                  onConfirm={() => {
+                    if (item.id2 && !delSnapIdsRef.current.includes(item.id2))
+                      delSnapIdsRef.current.push(item.id2)
+
+                    setSnaps(snaps.filter(v => v.id !== item.id))
+                  }}
+                />
+              )}
+            </>
+          )
+        }
+      }
+    ]
+  }, [key, snaps])
+
+  // 点击提交
+  const btnOk = useCallback(async () => {
+    if (key === '4') {
+      // 审批
+      if (!auditSta) {
+        MessageFu.warning('请选择审批结果')
+        boxRef.current?.scrollTo({ top: 0, behavior: 'smooth' })
+        return
+      }
+
+      const res = await C2_APIaduit({
+        orderId: info.id,
+        rtfOpinion,
+        status: auditSta === '同意' ? 1 : 2
+      })
+
+      if (res.code === 0) {
+        MessageFu.success('审批成功')
+        history.replace(`/storageIn_look/3/${info.id}`)
+      }
+    } else if (['1', '2'].includes(key)) {
+      // 新增和重新提交
+
+      // 处理日期格式
+      if (!info.date) {
+        MessageFu.warning('请选择入库日期')
+        boxRef.current?.scrollTo({ top: 0, behavior: 'smooth' })
+        return
+      }
+
+      if (!info.num) {
+        MessageFu.warning('请输入入库单编号')
+        boxRef.current?.scrollTo({ top: 0, behavior: 'smooth' })
+        return
+      }
+
+      if (snaps.length === 0) return MessageFu.warning('请添加藏品')
+
+      // 附件
+      let fileIds = ''
+      const fileArr: any[] = filesRef.current?.filesRes()
+      if (fileArr && fileArr.length) fileIds = fileArr.map(v => v.id).join(',')
+
+      const snapsRes = snaps.map(v => ({
+        goodsId: v.id,
+        id: v.id2 ? v.id2 : null,
+        orderId: info.id,
+        siteIn: v.siteIn,
+        snap: JSON.stringify(v)
+      }))
+
+      const obj = {
+        date: info.date,
+        delSnapIds: delSnapIdsRef.current.length ? delSnapIdsRef.current : '',
+        fileIds,
+        goodIds: snaps.map(v => v.id).join(','),
+        id: info.id,
+        num: info.num,
+        reason: info.reason,
+        snaps: snapsRes
+      }
+
+      // if (1 + 1 === 2) {
+      //   console.log(123, obj)
+      //   return
+      // }
+
+      const res = await C2_APIresubmit(obj)
+
+      if (res.code === 0) {
+        MessageFu.success(key === '1' ? '创建订单成功' : '重新提交成功')
+        history.replace(`/storageIn_look/3/${info.id}`)
+      }
+    }
+  }, [auditSta, info, key, rtfOpinion, snaps])
+
+  // 点击新增打开弹窗
+  const [addShow, setAddShow] = useState(false)
+
   return (
-    <div className={styles.C2look}>
-      <h1>C2look</h1>
+    <div className={styles.C2look} ref={boxRef}>
+      <div className='pageTitle'>藏品入库 - {Reflect.get(C2lookPageStaObj, key)}</div>
+
+      {info.id ? (
+        <>
+          <div className='C2lTop'>
+            <div className='C2lTopll'>
+              <div className='C2lTit'>申请信息</div>
+              <div className='C2lTopllBtn'>
+                <Button type='dashed'>{topStatusRes}</Button>
+              </div>
+            </div>
+            <div className='C2lToprr'>
+              {key !== '3' ? (
+                <>
+                  <Button type='primary' onClick={btnOk}>
+                    提交
+                  </Button>
+                  &emsp;
+                </>
+              ) : null}
+
+              {['1', '2'].includes(key) ? (
+                <MyPopconfirm txtK='返回' onConfirm={() => backPageFu('/storageIn')} />
+              ) : (
+                <Button onClick={() => backPageFu('/storageIn')}>返回</Button>
+              )}
+            </div>
+          </div>
+
+          <div className='C2form'>
+            {['3', '4'].includes(key) ? (
+              <>
+                <div className='C2formRow'>
+                  <div className='C2formRowll'>订单类型:</div>
+                  <div className='C2formRowrr C2formRowrr2'>藏品入库</div>
+                </div>
+
+                <div className='C2formRow'>
+                  <div className='C2formRowll'>发起人员:</div>
+                  <div className='C2formRowrr C2formRowrr2'>
+                    {info.creatorName + ' - ' + info.createTime}
+                  </div>
+                </div>
+              </>
+            ) : null}
+
+            <div className='C2formRow'>
+              <div className='C2formRowll'>
+                <span>* </span>入库日期:
+              </div>
+              <div className='C2formRowrr'>
+                <DatePicker
+                  disabled={['3', '4'].includes(key)}
+                  allowClear={false}
+                  value={info.date ? dayjs(info.date) : null}
+                  onChange={e => setInfo({ ...info, date: dayjs(e).format('YYYY-MM-DD') })}
+                />
+              </div>
+            </div>
+
+            <div className='C2formRow'>
+              <div className='C2formRowll'>
+                <span>* </span>入库单编号:
+              </div>
+              <div className='C2formRowrr'>
+                <Input
+                  value={info.num}
+                  onChange={e => setInfo({ ...info, num: e.target.value.trim() })}
+                  readOnly={['3', '4'].includes(key)}
+                  placeholder='请输入内容'
+                  maxLength={30}
+                  showCount
+                />
+              </div>
+            </div>
+
+            <div className='C2formRow C2formRowAll'>
+              <div className='C2formRowll'>事由说明:</div>
+              <div className='C2formRowrr'>
+                <TextArea
+                  value={info.reason}
+                  onChange={e => setInfo({ ...info, reason: e.target.value })}
+                  readOnly={['3', '4'].includes(key)}
+                  placeholder={['3', '4'].includes(key) ? '(空)' : '请输入内容'}
+                  maxLength={1000}
+                  showCount
+                />
+              </div>
+            </div>
+
+            {['3', '4'].includes(key) ? (
+              <div style={{ width: '100%', height: '10px' }}></div>
+            ) : null}
+
+            <div className='C2formRow C2formRowAll'>
+              <div className='C2formRowll'>附件:</div>
+              <div className='C2formRowrr'>
+                <Z3upFiles
+                  size={500}
+                  isLook={['3', '4'].includes(key)}
+                  ref={filesRef}
+                  fileCheck={false}
+                  dirCode='storageIn_look'
+                  myUrl='cms/orderSite/in/upload'
+                />
+              </div>
+            </div>
+
+            {/* 审批相关 */}
+            {key === '4' ? (
+              <>
+                <div className='C2formRow C2formRowAll'>
+                  <div className='C2formRowll'>
+                    <span>* </span>审批结果:
+                  </div>
+                  <div className='C2formRowrr'>
+                    {['同意', '不同意'].map(v => (
+                      <Button
+                        key={v}
+                        onClick={() => setAuDitSta(v)}
+                        type={auditSta === v ? 'primary' : 'default'}
+                      >
+                        {v}
+                      </Button>
+                    ))}
+                  </div>
+                </div>
+                <div className='C2formRow C2formRowAll' style={{ marginBottom: 25 }}>
+                  <div className='C2formRowll'>审批意见:</div>
+                  <div className='C2formRowrr'>
+                    <TextArea
+                      value={rtfOpinion}
+                      onChange={e => setRtfOpinion(e.target.value)}
+                      placeholder='请输入内容'
+                      maxLength={200}
+                      showCount
+                    />
+                  </div>
+                </div>
+              </>
+            ) : null}
+          </div>
+
+          <div className='C2lTit2'>
+            <div className='C2lTit'>藏品清单</div>
+            {['1', '2'].includes(key) ? (
+              <Button type='primary' onClick={() => setAddShow(true)}>
+                新增
+              </Button>
+            ) : (
+              <div></div>
+            )}
+          </div>
+
+          <MyTable
+            list={snaps}
+            columnsTemp={goodsSelectTableC}
+            lastBtn={goodsTableBtn}
+            pagingInfo={false}
+          />
+
+          {['3', '4'].includes(key) ? (
+            <>
+              <div className='C2lTit'>申请流程</div>
+
+              <MyTable
+                list={info.audits || []}
+                columnsTemp={auditTableC}
+                pagingInfo={false}
+                widthSet={{ rtfOpinion: 600 }}
+              />
+            </>
+          ) : null}
+        </>
+      ) : null}
+
+      {/* 打开藏品选择弹窗 */}
+      {addShow ? (
+        <A0selectGoods
+          type='入库'
+          closeFu={() => setAddShow(false)}
+          oldCheckArr={snaps}
+          dataResFu={data => {
+            //需要过滤掉已经有id的-不替换数据,没有id的替换数据 因为数据可能已经在另外一个弹窗更新了
+            const nowIds = snaps.map(v => v.id)
+            let dataRes = data.map((v, i) => {
+              if (nowIds.includes(v.id)) return snaps[i]
+              else return v
+            })
+
+            dataRes.forEach(v => {
+              // id2表示的是自己这条数据的id id才是goodsId
+              const obj = snapsID2ref.current.find(c => c.goodsId === v.id)
+
+              if (obj) v.id2 = obj.id
+            })
+
+            setSnaps(dataRes)
+          }}
+        />
+      ) : null}
     </div>
   )
 }

+ 39 - 0
后台管理/src/pages/C2storageIn/data.ts

@@ -0,0 +1,39 @@
+// export const C2fromDataBaseFu =(val:'RK'|'YK'|'CK',txt:'入库'|'移库'|'出库')=>{
+
+// }
+
+export type C2fromDataType = {
+  startTime: string
+  endTime: string
+  num: string
+  status: null | number
+  pageNum: number
+  pageSize: number
+}
+
+export const C2fromDataBase: C2fromDataType = {
+  startTime: '',
+  endTime: '',
+  num: '',
+  status: null,
+  pageNum: 1,
+  pageSize: 10
+}
+
+export const C2lookPageStaObj = {
+  1: '新增',
+  2: '重新提交',
+  3: '查看',
+  4: '审批'
+}
+
+// 处理位置字段-1分3、3分1
+export const locTxtValueFu = (index: number, val: string) => {
+  const arr = val ? val.split('-') : ['', '', '']
+  return arr[index]
+}
+export const locTxtChangeFu = (index: number, val: string, valAll: string) => {
+  const arr = valAll ? valAll.split('-') : ['', '', '']
+  arr[index] = val
+  return arr.join('-')
+}

+ 19 - 0
后台管理/src/pages/C2storageIn/index.module.scss

@@ -1,4 +1,23 @@
 .C2storageIn {
+  background-color: #fff;
+  border-radius: 10px;
+  padding: 20px;
   :global {
+    .C2top {
+      display: flex;
+      justify-content: space-between;
+      margin-bottom: 15px;
+      .C2topll {
+        display: flex;
+      }
+      .C2toprr {
+        .ant-btn {
+          margin-left: 15px;
+        }
+      }
+    }
+    .ant-table-cell {
+      padding: 8px !important;
+    }
   }
 }

+ 163 - 1
后台管理/src/pages/C2storageIn/index.tsx

@@ -1,9 +1,171 @@
-import React from 'react'
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
 import styles from './index.module.scss'
+import { useDispatch, useSelector } from 'react-redux'
+import { C2fromDataBase } from './data'
+import { C2_APIgetlist } from '@/store/action/C2storageIn'
+import { RootState } from '@/store'
+import { B1listType } from '../B1ledger/data'
+import { Button, DatePicker, Input, Select } from 'antd'
+import history, { aduitBtnRoleFu, resubmitBtnRoleFu } from '@/utils/history'
+import { statusSelect } from '@/utils/select'
+import MyTable from '@/components/MyTable'
+import { C2tableCFu } from '@/utils/tableData'
+import { C2devFu } from '@/utils/deriveFu'
+
+const { RangePicker } = DatePicker
+
 function C2storageIn() {
+  const dispatch = useDispatch()
+  const [formData, setFormData] = useState({ ...C2fromDataBase, type: 'RK' })
+
+  const getListFu = useCallback(() => {
+    dispatch(C2_APIgetlist(formData))
+  }, [dispatch, formData])
+
+  useEffect(() => {
+    getListFu()
+  }, [getListFu])
+
+  // 输入框改变
+  const timeRef = useRef(-1)
+  const txtChangeFu = useCallback(
+    (e: React.ChangeEvent<HTMLInputElement>, key: 'num') => {
+      clearTimeout(timeRef.current)
+      timeRef.current = window.setTimeout(() => {
+        setFormData({
+          ...formData,
+          [key]: e.target.value,
+          pageNum: 1
+        })
+      }, 500)
+    },
+    [formData]
+  )
+
+  // 时间选择器改变
+  const timeChange = useCallback(
+    (date: any, dateString: any) => {
+      let startTime = ''
+      let endTime = ''
+      if (dateString[0] && dateString[1]) {
+        startTime = dateString[0] + ' 00:00:00'
+        endTime = dateString[1] + ' 23:59:59'
+      }
+      setFormData({ ...formData, startTime, endTime, pageNum: 1 })
+    },
+    [formData]
+  )
+
+  // 点击重置
+  const [inputKey, setInputKey] = useState(1)
+  const resetSelectFu = useCallback(() => {
+    // 把2个输入框和时间选择器清空
+    setInputKey(Date.now())
+    setFormData({ ...C2fromDataBase, type: 'RK' })
+  }, [])
+
+  // 从仓库拿数据
+  const tableInfo = useSelector((state: RootState) => state.C2storageIn.tableInfo)
+
+  const tableLastBtn = useMemo(() => {
+    return [
+      {
+        title: '操作',
+        render: (item: B1listType) => {
+          return (
+            <>
+              <Button
+                size='small'
+                type='text'
+                onClick={() => history.push(`/storageIn_look/3/${item.id}`)}
+              >
+                查看
+              </Button>
+
+              {aduitBtnRoleFu(item) ? (
+                <Button
+                  size='small'
+                  type='text'
+                  onClick={() => history.push(`/storageIn_look/4/${item.id}`)}
+                >
+                  审批
+                </Button>
+              ) : null}
+
+              {resubmitBtnRoleFu(item) ? (
+                <Button
+                  size='small'
+                  type='text'
+                  onClick={() => history.push(`/storageIn_look/2/${item.id}`)}
+                >
+                  重新提交
+                </Button>
+              ) : null}
+            </>
+          )
+        }
+      }
+    ]
+  }, [])
+
+  // 页码变化
+  const paginationChange = useCallback(
+    (pageNum: number, pageSize: number) => {
+      setFormData({ ...formData, pageNum, pageSize })
+    },
+    [formData]
+  )
+
   return (
     <div className={styles.C2storageIn}>
       <div className='pageTitle'>藏品入库</div>
+
+      <div className='C2top'>
+        <div className='C2topll' key={inputKey}>
+          <RangePicker
+            placeholder={['入库日期起', '入库日期终']}
+            style={{ width: 240 }}
+            onChange={timeChange}
+          />
+          &emsp;
+          <Input
+            placeholder='入库单编号'
+            maxLength={30}
+            showCount
+            allowClear
+            onChange={e => txtChangeFu(e, 'num')}
+            style={{ width: 200 }}
+          />
+          &emsp;
+          <Select
+            allowClear
+            style={{ width: 200 }}
+            placeholder='申请状态'
+            options={statusSelect}
+            value={formData.status}
+            onChange={e => setFormData({ ...formData, status: e })}
+          />
+          &emsp;
+        </div>
+        <div className='C2toprr'>
+          <Button onClick={resetSelectFu}>重置</Button>&emsp;
+          <Button type='primary' onClick={() => C2devFu(formData, '入库')}>
+            数据导出
+          </Button>
+        </div>
+      </div>
+
+      {/* 表格 */}
+      <MyTable
+        yHeight={655}
+        list={tableInfo.list}
+        columnsTemp={C2tableCFu('入库')}
+        lastBtn={tableLastBtn}
+        pageNum={formData.pageNum}
+        pageSize={formData.pageSize}
+        total={tableInfo.total}
+        onChange={(pageNum, pageSize) => paginationChange(pageNum, pageSize)}
+      />
     </div>
   )
 }

+ 87 - 0
后台管理/src/pages/C4storageOut/C4look/index.module.scss

@@ -1,4 +1,91 @@
 .C4look {
+  background-color: #fff;
+  border-radius: 10px;
+  font-size: 16px;
+  overflow: auto;
+  padding: 20px;
   :global {
+    .C4lTit {
+      font-weight: 700;
+      font-size: 18px;
+      color: var(--themeColor);
+      margin-right: 20px;
+    }
+
+    .C4lTit2 {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+    }
+
+    .C4lTop {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      border-bottom: 1px solid #ccc;
+      padding-bottom: 15px;
+
+      .C4lTopll {
+        display: flex;
+        align-items: center;
+      }
+      .C4lToprr {
+        position: absolute;
+        top: 20px;
+        right: 20px;
+        z-index: 10;
+      }
+      .C4lTopllBtn {
+        pointer-events: none;
+      }
+    }
+
+    .C4form {
+      display: flex;
+      flex-wrap: wrap;
+      display: flex;
+      justify-content: space-between;
+      border-bottom: 1px solid #ccc;
+      padding: 15px 0;
+      margin-bottom: 15px;
+      padding-right: 15%;
+    }
+    .C4formRow {
+      width: 49%;
+      display: flex;
+      margin-bottom: 15px;
+      .C4formRowll {
+        position: relative;
+        width: 110px;
+        font-weight: 700;
+        text-align: right;
+        min-height: 32px;
+        line-height: 32px;
+        & > span {
+          color: #ff4d4f;
+        }
+      }
+
+      .C4formRowrr {
+        width: calc(100% - 110px);
+        .ant-btn {
+          margin-right: 20px;
+        }
+      }
+      .C4formRowrr2 {
+        height: 32px;
+        line-height: 32px;
+      }
+    }
+    .C4formRowAll {
+      width: 100%;
+    }
+
+    .ant-table-wrapper {
+      margin-top: 15px;
+      .ant-table-cell {
+        padding: 8px !important;
+      }
+    }
   }
 }

+ 442 - 2
后台管理/src/pages/C4storageOut/C4look/index.tsx

@@ -1,9 +1,449 @@
-import React from 'react'
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
 import styles from './index.module.scss'
+import { useParams } from 'react-router-dom'
+import { B1listType } from '@/pages/B1ledger/data'
+import {
+  C4_APIaduit,
+  C4_APIcreate,
+  C4_APIgetInfo,
+  C4_APIresubmit
+} from '@/store/action/C4storageOut'
+import { statusSelect } from '@/utils/select'
+import { Button, DatePicker, Input } from 'antd'
+import history, { backPageFu, openLink } from '@/utils/history'
+import MyPopconfirm from '@/components/MyPopconfirm'
+import { MessageFu } from '@/utils/message'
+import { C2lookPageStaObj } from '@/pages/C2storageIn/data'
+import dayjs from 'dayjs'
+import TextArea from 'antd/es/input/TextArea'
+import Z3upFiles from '@/components/Z3upFiles'
+import MyTable from '@/components/MyTable'
+import { auditTableC, goodsSelectTableC } from '@/utils/tableData'
+import A0selectGoods from '@/pages/A0selectGoods'
+import { API_getGoodsInfo } from '@/store/action/B1ledger'
 function C4look() {
+  const { key, id } = useParams<any>()
+  // key:1-新增 2-重新提交/编辑 3-查看 4-审批
+
+  // 从藏品信息模块进来,带上当前藏品信息
+  const isGoodsInfoRu = useCallback(async (id: number) => {
+    const res = await API_getGoodsInfo(id)
+    if (res.code === 0) {
+      setSnaps([res.data])
+    }
+  }, [])
+
+  useEffect(() => {
+    const urlAll = window.location.href
+    if (key === '1' && urlAll.includes('?oldId=')) {
+      isGoodsInfoRu(Number(urlAll.split('?oldId=')[1]))
+    }
+  }, [isGoodsInfoRu, key])
+
+  // 顶部数据
+  const [info, setInfo] = useState({} as B1listType)
+
+  // 新增的时候进页面创建订单
+  const createFu = useCallback(async () => {
+    const res = await C4_APIcreate()
+    if (res.code === 0) {
+      setInfo(res.data)
+    }
+  }, [])
+
+  // 获取详情
+  const getInfoFu = useCallback(async () => {
+    const res = await C4_APIgetInfo(id)
+    if (res.code === 0) {
+      // console.log('获取详情:', res)
+      const data = res.data
+      setInfo(data)
+      // 设置附件(需要异步)
+
+      setTimeout(() => {
+        filesRef.current?.showList(data.files || [])
+      }, 100)
+
+      // 藏品清单快照信息id对比
+      const arrTemp: any = []
+      const snapsTemp = data.snaps || []
+
+      snapsTemp.forEach((v: any) => {
+        snapsID2ref.current.push({ goodsId: v.goodsId, id: v.id })
+
+        const obj = JSON.parse(v.snap || '{}')
+        if (obj.id) obj.id2 = v.id
+
+        arrTemp.push({ ...obj })
+      })
+
+      setSnaps(arrTemp)
+    }
+  }, [id])
+
+  useEffect(() => {
+    if (key === '1') createFu()
+    else if (['2', '3', '4'].includes(key)) getInfoFu()
+  }, [createFu, getInfoFu, key])
+
+  // 申请状态
+  const topStatusRes = useMemo(() => {
+    let txt = '创建订单'
+    const obj = statusSelect.find(v => v.value === info.status)
+    if (obj) txt = obj.label
+    return txt
+  }, [info.status])
+
+  // 审批的sta
+  const [auditSta, setAuDitSta] = useState('')
+  const [rtfOpinion, setRtfOpinion] = useState('')
+
+  const boxRef = useRef<HTMLDivElement>(null)
+
+  // 上传附件的ref
+  const filesRef = useRef<any>(null)
+
+  // 藏品清单 和 快照数据
+
+  const [snaps, setSnaps] = useState<B1listType[]>([])
+  const delSnapIdsRef = useRef<number[]>([])
+
+  const snapsID2ref = useRef<{ goodsId: number; id: number }[]>([])
+
+  const goodsTableBtn = useMemo(() => {
+    return [
+      {
+        title: '去向',
+        render: (item: B1listType) => {
+          return (
+            <>
+              <Input
+                readOnly={['3', '4'].includes(key)}
+                placeholder={['3', '4'].includes(key) ? '(空)' : `请输入内容`}
+                maxLength={10}
+                value={item.siteOut}
+                showCount
+                onChange={e =>
+                  setSnaps(
+                    snaps.map(v => ({
+                      ...v,
+                      siteOut: v.id === item.id ? e.target.value.trim() : v.siteOut
+                    }))
+                  )
+                }
+              />
+            </>
+          )
+        }
+      },
+      {
+        title: '操作',
+        render: (item: B1listType) => {
+          return (
+            <>
+              <Button size='small' type='text' onClick={() => openLink(`/goodsLook/${item.id}`)}>
+                查看
+              </Button>
+              {['3', '4'].includes(key) ? null : (
+                <MyPopconfirm
+                  txtK='删除'
+                  onConfirm={() => {
+                    if (item.id2 && !delSnapIdsRef.current.includes(item.id2))
+                      delSnapIdsRef.current.push(item.id2)
+
+                    setSnaps(snaps.filter(v => v.id !== item.id))
+                  }}
+                />
+              )}
+            </>
+          )
+        }
+      }
+    ]
+  }, [key, snaps])
+
+  // 点击提交
+  const btnOk = useCallback(async () => {
+    if (key === '4') {
+      // 审批
+      if (!auditSta) {
+        MessageFu.warning('请选择审批结果')
+        boxRef.current?.scrollTo({ top: 0, behavior: 'smooth' })
+        return
+      }
+
+      const res = await C4_APIaduit({
+        orderId: info.id,
+        rtfOpinion,
+        status: auditSta === '同意' ? 1 : 2
+      })
+
+      if (res.code === 0) {
+        MessageFu.success('审批成功')
+        history.replace(`/storageOut_look/3/${info.id}`)
+      }
+    } else if (['1', '2'].includes(key)) {
+      // 新增和重新提交
+
+      // 处理日期格式
+      if (!info.date) {
+        MessageFu.warning('请选择出库日期')
+        boxRef.current?.scrollTo({ top: 0, behavior: 'smooth' })
+        return
+      }
+
+      if (!info.num) {
+        MessageFu.warning('请输入出库单编号')
+        boxRef.current?.scrollTo({ top: 0, behavior: 'smooth' })
+        return
+      }
+
+      if (snaps.length === 0) return MessageFu.warning('请添加藏品')
+
+      // 附件
+      let fileIds = ''
+      const fileArr: any[] = filesRef.current?.filesRes()
+      if (fileArr && fileArr.length) fileIds = fileArr.map(v => v.id).join(',')
+
+      const snapsRes = snaps.map(v => ({
+        goodsId: v.id,
+        id: v.id2 ? v.id2 : null,
+        orderId: info.id,
+        siteOut: v.siteOut,
+        snap: JSON.stringify(v)
+      }))
+
+      const obj = {
+        date: info.date,
+        delSnapIds: delSnapIdsRef.current.length ? delSnapIdsRef.current : '',
+        fileIds,
+        goodIds: snaps.map(v => v.id).join(','),
+        id: info.id,
+        num: info.num,
+        reason: info.reason,
+        snaps: snapsRes
+      }
+
+      // if (1 + 1 === 2) {
+      //   console.log(123, obj)
+      //   return
+      // }
+
+      const res = await C4_APIresubmit(obj)
+
+      if (res.code === 0) {
+        MessageFu.success(key === '1' ? '创建订单成功' : '重新提交成功')
+        history.replace(`/storageOut_look/3/${info.id}`)
+      }
+    }
+  }, [auditSta, info, key, rtfOpinion, snaps])
+
+  // 点击新增打开弹窗
+  const [addShow, setAddShow] = useState(false)
+
   return (
     <div className={styles.C4look}>
-      <h1>C4look</h1>
+      <div className='pageTitle'>藏品出库 - {Reflect.get(C2lookPageStaObj, key)}</div>
+
+      {info.id ? (
+        <>
+          <div className='C4lTop'>
+            <div className='C4lTopll'>
+              <div className='C4lTit'>申请信息</div>
+              <div className='C4lTopllBtn'>
+                <Button type='dashed'>{topStatusRes}</Button>
+              </div>
+            </div>
+            <div className='C4lToprr'>
+              {key !== '3' ? (
+                <>
+                  <Button type='primary' onClick={btnOk}>
+                    提交
+                  </Button>
+                  &emsp;
+                </>
+              ) : null}
+
+              {['1', '2'].includes(key) ? (
+                <MyPopconfirm txtK='返回' onConfirm={() => backPageFu('/storageOut')} />
+              ) : (
+                <Button onClick={() => backPageFu('/storageOut')}>返回</Button>
+              )}
+            </div>
+          </div>
+
+          <div className='C4form'>
+            {['3', '4'].includes(key) ? (
+              <>
+                <div className='C4formRow'>
+                  <div className='C4formRowll'>订单类型:</div>
+                  <div className='C4formRowrr C4formRowrr2'>藏品出库</div>
+                </div>
+
+                <div className='C4formRow'>
+                  <div className='C4formRowll'>发起人员:</div>
+                  <div className='C4formRowrr C4formRowrr2'>
+                    {info.creatorName + ' - ' + info.createTime}
+                  </div>
+                </div>
+              </>
+            ) : null}
+
+            <div className='C4formRow'>
+              <div className='C4formRowll'>
+                <span>* </span>出库日期:
+              </div>
+              <div className='C4formRowrr'>
+                <DatePicker
+                  disabled={['3', '4'].includes(key)}
+                  allowClear={false}
+                  value={info.date ? dayjs(info.date) : null}
+                  onChange={e => setInfo({ ...info, date: dayjs(e).format('YYYY-MM-DD') })}
+                />
+              </div>
+            </div>
+
+            <div className='C4formRow'>
+              <div className='C4formRowll'>
+                <span>* </span>出库单编号:
+              </div>
+              <div className='C4formRowrr'>
+                <Input
+                  value={info.num}
+                  onChange={e => setInfo({ ...info, num: e.target.value.trim() })}
+                  readOnly={['3', '4'].includes(key)}
+                  placeholder='请输入内容'
+                  maxLength={30}
+                  showCount
+                />
+              </div>
+            </div>
+
+            <div className='C4formRow C4formRowAll'>
+              <div className='C4formRowll'>事由说明:</div>
+              <div className='C4formRowrr'>
+                <TextArea
+                  value={info.reason}
+                  onChange={e => setInfo({ ...info, reason: e.target.value })}
+                  readOnly={['3', '4'].includes(key)}
+                  placeholder={['3', '4'].includes(key) ? '(空)' : '请输入内容'}
+                  maxLength={1000}
+                  showCount
+                />
+              </div>
+            </div>
+
+            {['3', '4'].includes(key) ? (
+              <div style={{ width: '100%', height: '10px' }}></div>
+            ) : null}
+
+            <div className='C4formRow C4formRowAll'>
+              <div className='C4formRowll'>附件:</div>
+              <div className='C4formRowrr'>
+                <Z3upFiles
+                  size={500}
+                  isLook={['3', '4'].includes(key)}
+                  ref={filesRef}
+                  fileCheck={false}
+                  dirCode='storageOut_look'
+                  myUrl='cms/orderSite/out/upload'
+                />
+              </div>
+            </div>
+
+            {/* 审批相关 */}
+            {key === '4' ? (
+              <>
+                <div className='C4formRow C4formRowAll'>
+                  <div className='C4formRowll'>
+                    <span>* </span>审批结果:
+                  </div>
+                  <div className='C4formRowrr'>
+                    {['同意', '不同意'].map(v => (
+                      <Button
+                        key={v}
+                        onClick={() => setAuDitSta(v)}
+                        type={auditSta === v ? 'primary' : 'default'}
+                      >
+                        {v}
+                      </Button>
+                    ))}
+                  </div>
+                </div>
+                <div className='C4formRow C4formRowAll' style={{ marginBottom: 25 }}>
+                  <div className='C4formRowll'>审批意见:</div>
+                  <div className='C4formRowrr'>
+                    <TextArea
+                      value={rtfOpinion}
+                      onChange={e => setRtfOpinion(e.target.value)}
+                      placeholder='请输入内容'
+                      maxLength={200}
+                      showCount
+                    />
+                  </div>
+                </div>
+              </>
+            ) : null}
+          </div>
+
+          <div className='C4lTit2'>
+            <div className='C4lTit'>藏品清单</div>
+            {['1', '2'].includes(key) ? (
+              <Button type='primary' onClick={() => setAddShow(true)}>
+                新增
+              </Button>
+            ) : (
+              <div></div>
+            )}
+          </div>
+
+          <MyTable
+            list={snaps}
+            columnsTemp={goodsSelectTableC}
+            lastBtn={goodsTableBtn}
+            pagingInfo={false}
+          />
+
+          {['3', '4'].includes(key) ? (
+            <>
+              <div className='C4lTit'>申请流程</div>
+
+              <MyTable
+                list={info.audits || []}
+                columnsTemp={auditTableC}
+                pagingInfo={false}
+                widthSet={{ rtfOpinion: 600 }}
+              />
+            </>
+          ) : null}
+        </>
+      ) : null}
+
+      {/* 打开藏品选择弹窗 */}
+      {addShow ? (
+        <A0selectGoods
+          type='出库'
+          closeFu={() => setAddShow(false)}
+          oldCheckArr={snaps}
+          dataResFu={data => {
+            //需要过滤掉已经有id的-不替换数据,没有id的替换数据 因为数据可能已经在另外一个弹窗更新了
+            const nowIds = snaps.map(v => v.id)
+            let dataRes = data.map((v, i) => {
+              if (nowIds.includes(v.id)) return snaps[i]
+              else return v
+            })
+
+            dataRes.forEach(v => {
+              // id2表示的是自己这条数据的id id才是goodsId
+              const obj = snapsID2ref.current.find(c => c.goodsId === v.id)
+
+              if (obj) v.id2 = obj.id
+            })
+
+            setSnaps(dataRes)
+          }}
+        />
+      ) : null}
     </div>
   )
 }

+ 19 - 0
后台管理/src/pages/C4storageOut/index.module.scss

@@ -1,4 +1,23 @@
 .C4storageOut {
+  background-color: #fff;
+  border-radius: 10px;
+  padding: 20px;
   :global {
+    .C4top {
+      display: flex;
+      justify-content: space-between;
+      margin-bottom: 15px;
+      .C4topll {
+        display: flex;
+      }
+      .C4toprr {
+        .ant-btn {
+          margin-left: 15px;
+        }
+      }
+    }
+    .ant-table-cell {
+      padding: 8px !important;
+    }
   }
 }

+ 163 - 1
后台管理/src/pages/C4storageOut/index.tsx

@@ -1,9 +1,171 @@
-import React from 'react'
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
 import styles from './index.module.scss'
+import { Button, DatePicker, Input, Select } from 'antd'
+import { useDispatch, useSelector } from 'react-redux'
+import { C2fromDataBase } from '../C2storageIn/data'
+import { C4_APIgetlist } from '@/store/action/C4storageOut'
+import { RootState } from '@/store'
+import { B1listType } from '../B1ledger/data'
+import history, { aduitBtnRoleFu, resubmitBtnRoleFu } from '@/utils/history'
+import { statusSelect } from '@/utils/select'
+import { C2devFu } from '@/utils/deriveFu'
+import MyTable from '@/components/MyTable'
+import { C2tableCFu } from '@/utils/tableData'
+
+const { RangePicker } = DatePicker
+
 function C4storageOut() {
+  const dispatch = useDispatch()
+  const [formData, setFormData] = useState({ ...C2fromDataBase, type: 'CK' })
+
+  const getListFu = useCallback(() => {
+    dispatch(C4_APIgetlist(formData))
+  }, [dispatch, formData])
+
+  useEffect(() => {
+    getListFu()
+  }, [getListFu])
+
+  // 输入框改变
+  const timeRef = useRef(-1)
+  const txtChangeFu = useCallback(
+    (e: React.ChangeEvent<HTMLInputElement>, key: 'num') => {
+      clearTimeout(timeRef.current)
+      timeRef.current = window.setTimeout(() => {
+        setFormData({
+          ...formData,
+          [key]: e.target.value,
+          pageNum: 1
+        })
+      }, 500)
+    },
+    [formData]
+  )
+
+  // 时间选择器改变
+  const timeChange = useCallback(
+    (date: any, dateString: any) => {
+      let startTime = ''
+      let endTime = ''
+      if (dateString[0] && dateString[1]) {
+        startTime = dateString[0] + ' 00:00:00'
+        endTime = dateString[1] + ' 23:59:59'
+      }
+      setFormData({ ...formData, startTime, endTime, pageNum: 1 })
+    },
+    [formData]
+  )
+
+  // 点击重置
+  const [inputKey, setInputKey] = useState(1)
+  const resetSelectFu = useCallback(() => {
+    // 把2个输入框和时间选择器清空
+    setInputKey(Date.now())
+    setFormData({ ...C2fromDataBase, type: 'RK' })
+  }, [])
+
+  // 从仓库拿数据
+  const tableInfo = useSelector((state: RootState) => state.C4storageOut.tableInfo)
+
+  const tableLastBtn = useMemo(() => {
+    return [
+      {
+        title: '操作',
+        render: (item: B1listType) => {
+          return (
+            <>
+              <Button
+                size='small'
+                type='text'
+                onClick={() => history.push(`/storageOut_look/3/${item.id}`)}
+              >
+                查看
+              </Button>
+
+              {aduitBtnRoleFu(item) ? (
+                <Button
+                  size='small'
+                  type='text'
+                  onClick={() => history.push(`/storageOut_look/4/${item.id}`)}
+                >
+                  审批
+                </Button>
+              ) : null}
+
+              {resubmitBtnRoleFu(item) ? (
+                <Button
+                  size='small'
+                  type='text'
+                  onClick={() => history.push(`/storageOut_look/2/${item.id}`)}
+                >
+                  重新提交
+                </Button>
+              ) : null}
+            </>
+          )
+        }
+      }
+    ]
+  }, [])
+
+  // 页码变化
+  const paginationChange = useCallback(
+    (pageNum: number, pageSize: number) => {
+      setFormData({ ...formData, pageNum, pageSize })
+    },
+    [formData]
+  )
+
   return (
     <div className={styles.C4storageOut}>
       <div className='pageTitle'>藏品出库</div>
+
+      <div className='C4top'>
+        <div className='C4topll' key={inputKey}>
+          <RangePicker
+            placeholder={['出库日期起', '出库日期终']}
+            style={{ width: 240 }}
+            onChange={timeChange}
+          />
+          &emsp;
+          <Input
+            placeholder='出库单编号'
+            maxLength={30}
+            showCount
+            allowClear
+            onChange={e => txtChangeFu(e, 'num')}
+            style={{ width: 200 }}
+          />
+          &emsp;
+          <Select
+            allowClear
+            style={{ width: 200 }}
+            placeholder='申请状态'
+            options={statusSelect}
+            value={formData.status}
+            onChange={e => setFormData({ ...formData, status: e })}
+          />
+          &emsp;
+        </div>
+        <div className='C4toprr'>
+          <Button onClick={resetSelectFu}>重置</Button>&emsp;
+          <Button type='primary' onClick={() => C2devFu(formData, '出库')}>
+            数据导出
+          </Button>
+        </div>
+      </div>
+
+      {/* 表格 */}
+      <MyTable
+        yHeight={655}
+        list={tableInfo.list}
+        columnsTemp={C2tableCFu('出库')}
+        lastBtn={tableLastBtn}
+        pageNum={formData.pageNum}
+        pageSize={formData.pageSize}
+        total={tableInfo.total}
+        onChange={(pageNum, pageSize) => paginationChange(pageNum, pageSize)}
+      />
     </div>
   )
 }

+ 6 - 3
后台管理/src/pages/Layout/data.ts

@@ -69,19 +69,22 @@ const tabLeftArr: RouterType = [
         id: 800,
         name: '藏品入库',
         path: '/storageIn',
-        Com: React.lazy(() => import('../C2storageIn'))
+        Com: React.lazy(() => import('../C2storageIn')),
+        pageType: 'RK'
       },
       {
         id: 900,
         name: '藏品移库',
         path: '/storageMove',
-        Com: React.lazy(() => import('../C3storageMove'))
+        Com: React.lazy(() => import('../C3storageMove')),
+        pageType: 'YK'
       },
       {
         id: 1000,
         name: '藏品出库',
         path: '/storageOut',
-        Com: React.lazy(() => import('../C4storageOut'))
+        Com: React.lazy(() => import('../C4storageOut')),
+        pageType: 'CK'
       }
     ]
   },

+ 16 - 0
后台管理/src/store/action/B1ledger.ts

@@ -42,8 +42,24 @@ export const API_getGoodsLog = (goodsId: number) => {
 }
 
 /**
+ * 藏品详情-库存状态
+ */
+export const API_getStorageLog = (goodsId: number) => {
+  return http.get(`cms/goods/order/site/${goodsId}`)
+}
+
+/**
  * 附件-根据附件ids查询
  */
 export const API_getFileListByIds = (data: number[]) => {
   return http.post('cms/goods/file/getList', data)
 }
+
+/**
+ * 获取藏品选择列表
+ */
+export const API_selectGoods = (type: '入库' | '移库' | '出库', data: any) => {
+  const urlType = type === '入库' ? 'in' : type === '出库' ? 'out' : 'move'
+
+  return http.post(`cms/orderSite/${urlType}/goods/page`, data)
+}

+ 49 - 0
后台管理/src/store/action/C2storageIn.ts

@@ -0,0 +1,49 @@
+import http from '@/utils/http'
+import { AppDispatch } from '..'
+/**
+ * 藏品入库-获取列表
+ */
+export const C2_APIgetlist = (data: any, exportFlag?: boolean): any => {
+  if (exportFlag) return http.post('cms/orderSite/in/page', data)
+  else {
+    return async (dispatch: AppDispatch) => {
+      const res = await http.post('cms/orderSite/in/page', data)
+      if (res.code === 0) {
+        const obj = {
+          list: res.data.records,
+          total: res.data.total
+        }
+
+        dispatch({ type: 'C2/getList', payload: obj })
+      }
+    }
+  }
+}
+
+/**
+ * 藏品入库-创建订单
+ */
+export const C2_APIcreate = () => {
+  return http.get('cms/orderSite/in/create')
+}
+
+/**
+ * 藏品入库-提交
+ */
+export const C2_APIresubmit = (data: any) => {
+  return http.post('cms/orderSite/in/apply', data)
+}
+
+/**
+ * 藏品入库-获取详情
+ */
+export const C2_APIgetInfo = (id: number) => {
+  return http.get(`cms/orderSite/in/detail/${id}`)
+}
+
+/**
+ * 藏品入库-审批
+ */
+export const C2_APIaduit = (data: any) => {
+  return http.post('cms/orderSite/in/audit', data)
+}

+ 49 - 0
后台管理/src/store/action/C3storageMove.ts

@@ -0,0 +1,49 @@
+import http from '@/utils/http'
+import { AppDispatch } from '..'
+/**
+ * 藏品移库-获取列表
+ */
+export const C3_APIgetlist = (data: any, exportFlag?: boolean): any => {
+  if (exportFlag) return http.post('cms/orderSite/move/page', data)
+  else {
+    return async (dispatch: AppDispatch) => {
+      const res = await http.post('cms/orderSite/move/page', data)
+      if (res.code === 0) {
+        const obj = {
+          list: res.data.records,
+          total: res.data.total
+        }
+
+        dispatch({ type: 'C3/getList', payload: obj })
+      }
+    }
+  }
+}
+
+/**
+ * 藏品移库-创建订单
+ */
+export const C3_APIcreate = () => {
+  return http.get('cms/orderSite/move/create')
+}
+
+/**
+ * 藏品移库-提交
+ */
+export const C3_APIresubmit = (data: any) => {
+  return http.post('cms/orderSite/move/apply', data)
+}
+
+/**
+ * 藏品移库-获取详情
+ */
+export const C3_APIgetInfo = (id: number) => {
+  return http.get(`cms/orderSite/move/detail/${id}`)
+}
+
+/**
+ * 藏品移库-审批
+ */
+export const C3_APIaduit = (data: any) => {
+  return http.post('cms/orderSite/move/audit', data)
+}

+ 49 - 0
后台管理/src/store/action/C4storageOut.ts

@@ -0,0 +1,49 @@
+import http from '@/utils/http'
+import { AppDispatch } from '..'
+/**
+ * 藏品出库-获取列表
+ */
+export const C4_APIgetlist = (data: any, exportFlag?: boolean): any => {
+  if (exportFlag) return http.post('cms/orderSite/out/page', data)
+  else {
+    return async (dispatch: AppDispatch) => {
+      const res = await http.post('cms/orderSite/out/page', data)
+      if (res.code === 0) {
+        const obj = {
+          list: res.data.records,
+          total: res.data.total
+        }
+
+        dispatch({ type: 'C4/getList', payload: obj })
+      }
+    }
+  }
+}
+
+/**
+ * 藏品出库-创建订单
+ */
+export const C4_APIcreate = () => {
+  return http.get('cms/orderSite/out/create')
+}
+
+/**
+ * 藏品出库-提交
+ */
+export const C4_APIresubmit = (data: any) => {
+  return http.post('cms/orderSite/out/apply', data)
+}
+
+/**
+ * 藏品出库-获取详情
+ */
+export const C4_APIgetInfo = (id: number) => {
+  return http.get(`cms/orderSite/out/detail/${id}`)
+}
+
+/**
+ * 藏品出库-审批
+ */
+export const C4_APIaduit = (data: any) => {
+  return http.post('cms/orderSite/out/audit', data)
+}

+ 28 - 0
后台管理/src/store/reducer/C2storageIn.ts

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

+ 28 - 0
后台管理/src/store/reducer/C3storageMove.ts

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

+ 28 - 0
后台管理/src/store/reducer/C4storageOut.ts

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

+ 6 - 1
后台管理/src/store/reducer/index.ts

@@ -8,7 +8,9 @@ import B2register from './B2register'
 import B3edit from './B3edit'
 import B4delete from './B4delete'
 import C1storageSet from './C1storageSet'
-
+import C2storageIn from './C2storageIn'
+import C3storageMove from './C3storageMove'
+import C4storageOut from './C4storageOut'
 import D1dict from './D1dict'
 import D2approval from './D2approval'
 import D3role from './D3role'
@@ -23,6 +25,9 @@ const rootReducer = combineReducers({
   B3edit,
   B4delete,
   C1storageSet,
+  C3storageMove,
+  C2storageIn,
+  C4storageOut,
   D1dict,
   D2approval,
   D3role,

+ 1 - 1
后台管理/src/types/api/layot.d.ts

@@ -10,7 +10,7 @@ export type RouterTypeRow = {
   path: string
   pathLast?: string
   Com: React.LazyExoticComponent<React.MemoExoticComponent<() => JSX.Element>>
-  pageType?: 'DJ' | 'XG' | 'SC'
+  pageType?: string
 }[]
 
 export type RouterType = {

+ 54 - 1
后台管理/src/utils/deriveFu.ts

@@ -8,6 +8,9 @@ import { B2_APIgetlist } from '@/store/action/B2register'
 import { B3_APIgetlist } from '@/store/action/B3edit'
 import { B4_APIgetlist } from '@/store/action/B4delete'
 import { C1_APIgetlist } from '@/store/action/C1storageSet'
+import { C2_APIgetlist } from '@/store/action/C2storageIn'
+import { C3_APIgetlist } from '@/store/action/C3storageMove'
+import { C4_APIgetlist } from '@/store/action/C4storageOut'
 
 // 入口
 const devDownFu = (
@@ -82,14 +85,28 @@ export const sizeChange = (val1?: number, val2?: number, val3?: number, val4?: s
   else return arr.join(' - ')
 }
 
+// 库房位置处理
+export const siteLocChange = (val: string) => {
+  if (val) {
+    let arr = val.split('-')
+    arr = arr.map(v => (v ? v : '(空)'))
+    const txt = arr.join('-')
+    if (txt === '(空)-(空)-(空)') return '(空)'
+    else return arr.join('-')
+  } else return '(空)'
+}
+
 const dataChange = (key: string, val: any, val2?: any) => {
-  if (['inHouseTime', 'registerTime', 'createTime', 'siteDateIn', 'siteDateOut'].includes(key))
+  if (
+    ['inHouseTime', 'registerTime', 'createTime', 'siteDateIn', 'siteDateOut', 'date'].includes(key)
+  )
     return timeChange(val)
   else if (['typeDictId'].includes(key)) return selectChange(dictSelect('藏品类型'), val)
   else if (['textureDictId'].includes(key)) return selectChange(dictSelect('藏品材质'), val)
   else if (['pcs'].includes(key)) return pcsPingFu(dictSelect('数量单位'), val, val2)
   else if (['status'].includes(key)) return selectChange(statusSelect, val)
   else if (['siteStatus'].includes(key)) return selectChange(storageSelect, val)
+  else if (['siteLoc'].includes(key)) return siteLocChange(val)
   else return val
 }
 
@@ -228,3 +245,39 @@ export const B3devFu = async (formData: any) => {
     devDownFu(data, '库房管理', arr1, arr2)
   }
 }
+
+// ------------------入库 移库 出库
+export const C2devFu = async (formData: any, txt: '入库' | '移库' | '出库') => {
+  const obj = { ...formData, pageNum: 1, pageSize: 99999 }
+
+  const res =
+    txt === '入库'
+      ? await C2_APIgetlist(obj, true)
+      : txt === '移库'
+      ? await C3_APIgetlist(obj, true)
+      : await C4_APIgetlist(obj, true)
+
+  if (res.code === 0) {
+    let data: any[] = res.data.records || []
+
+    if (data.length <= 0) return MessageFu.warning('当前搜索条件没有数据')
+
+    const arr1 = ['date', 'num', 'creatorName', 'createTime', 'status']
+
+    const arr2 = [`${txt}日期`, `${txt}单编号`, '发起人', '发起日期', '申请状态']
+
+    data.forEach(v => {
+      let val2: any = undefined
+
+      arr1.forEach(c => {
+        if (v[c] || v[c] === 0) {
+          if (c === 'pcs') val2 = v.pcsUnitDictId
+          else val2 = undefined
+          v[c] = dataChange(c, v[c], val2)
+        } else v[c] = '(空)'
+      })
+    })
+
+    devDownFu(data, `藏品${txt}`, arr1, arr2)
+  }
+}

+ 39 - 2
后台管理/src/utils/tableData.ts

@@ -24,12 +24,39 @@ export const auditTableC = [
   ['text', '审批意见', 'rtfOpinion', 100]
 ]
 
+export const goodsSelectTableC = [
+  ['txt', '藏品编号', 'num'],
+  ['txt', '藏品标题', 'name'],
+  ['img', '封面图', 'thumb'],
+  ['select', '类型', 'typeDictId', dictSelect('藏品类型')],
+  ['select', '材质', 'textureDictId', dictSelect('藏品材质')],
+  ['ping', '数量', 'pcs', 'pcsUnitDictId', dictSelect('数量单位')]
+]
+
+export const selectGoodsAddTableC = [
+  ['txt', '藏品编号', 'num'],
+  ['txt', '藏品标题', 'name'],
+  ['img', '封面图', 'thumb'],
+  ['select', '类型', 'typeDictId', dictSelect('藏品类型')],
+  ['select', '材质', 'textureDictId', dictSelect('藏品材质')],
+  ['siteLoc', '所在位置', 'siteLoc'],
+  ['ping', '数量', 'pcs', 'pcsUnitDictId', dictSelect('数量单位')],
+  ['txt', '有无说明牌', 'isNote']
+]
+
 export const goodsLogTableC = [
   ['txt', '发起人', 'creatorName'],
   ['time', '发起日期', 'createTime'],
   ['select', '申请状态', 'status', statusSelect]
 ]
 
+export const goodsStorageTableC = [
+  ['txt', '申请编号', 'num'],
+  ['txt', '发起人', 'creatorName'],
+  ['time', '发起日期', 'createTime'],
+  ['select', '申请状态', 'status', statusSelect]
+]
+
 export const B1tableC = [
   ['txt', '藏品编号', 'num'],
   ['txt', '藏品标题', 'name'],
@@ -40,7 +67,7 @@ export const B1tableC = [
   ['time', '出库时间', 'siteDateOut'],
   ['select', '类型', 'typeDictId', dictSelect('藏品类型')],
   ['select', '材质', 'textureDictId', dictSelect('藏品材质')],
-  ['txt', '当前位置', 'siteLoc'],
+  ['siteLoc', '当前位置', 'siteLoc'],
   ['ping', '数量', 'pcs', 'pcsUnitDictId', dictSelect('数量单位')],
   ['txt', '有无说明牌', 'isNote'],
   ['select', '状态', 'status', goodsSelect]
@@ -56,7 +83,7 @@ export const B2tableC = [
 ]
 
 export const C1tableC = [
-  ['txt', '库房位置', 'siteLoc'],
+  ['siteLoc', '库房位置', 'siteLoc'],
   ['txt', '藏品编号', 'num'],
   ['txt', '藏品名称', 'name'],
   ['img', '封面图', 'thumb'],
@@ -68,6 +95,16 @@ export const C1tableC = [
   ['ping', '数量', 'pcs', 'pcsUnitDictId', dictSelect('数量单位')]
 ]
 
+export const C2tableCFu = (txt: '入库' | '移库' | '出库') => {
+  return [
+    ['time', `${txt}日期`, 'date'],
+    ['txt', `${txt}单编号`, 'num'],
+    ['txt', '发起人', 'creatorName'],
+    ['time', '发起日期', 'createTime'],
+    ['select', '申请状态', 'status', statusSelect]
+  ]
+}
+
 export const D2tableC = [
   ['txt', '流程名称', 'name'],
   ['text', '流程说明', 'remark', '100'],