Explorar o código

Merge branch 'master' of http://192.168.0.115:3000/shaogen1995/qingDao_goods into master

shaogen1995 hai 20 horas
pai
achega
67076c65b8

+ 1 - 1
src/components/MyTable/form.tsx

@@ -219,7 +219,7 @@ const MyTable = forwardRef<MyTableMethods, MyTableProps>(
           },
           },
           input: (item: any) => {
           input: (item: any) => {
             return (
             return (
-              <Form.Item noStyle name={`${item.id}-${v[2]}`}>
+              <Form.Item noStyle name={`${item.id}-${v[2]}`} initialValue={item[v[2]]}>
                 <Input
                 <Input
                   allowClear
                   allowClear
                   readOnly={readOnly}
                   readOnly={readOnly}

+ 263 - 107
src/pages/Abench/A1statistics/index.tsx

@@ -1,97 +1,225 @@
-import React, { useCallback, useEffect } from 'react'
+import React, { useCallback, useEffect, useRef, useState } from 'react'
 import styles from './index.module.scss'
 import styles from './index.module.scss'
 import { Select } from 'antd'
 import { Select } from 'antd'
 import { iconUrl } from '@/utils/http'
 import { iconUrl } from '@/utils/http'
 import * as echarts from 'echarts'
 import * as echarts from 'echarts'
+import {
+  A1_APIworkCount,
+  A1_APIgetDictById,
+  A1_APIgetDataTextureByTagId,
+  A1_APIgetDataTagByTagId,
+  A1_APIgetTotal,
+  A1_APIgetDataTagLevel
+} from '@/store/action/Abench/A1'
 
 
-const chartData1 = [
-  { name: '啤酒产品类', value: 2500 },
-  { name: '饮用器皿类', value: 1800 },
-  { name: '品牌文化与节庆类', value: 1200 },
-  { name: '企业文化与档案类', value: 800 },
-  { name: '艺术与礼品类', value: 1000 },
-  { name: '工具与设备类', value: 900 },
-  { name: '其他综合类', value: 2500 }
-]
-
-const chartData2 = [
-  { name: '酒类实物', value: 2500 },
-  { name: '包装与标识', value: 1800 },
-  { name: '杯子', value: 1200 },
-  { name: '品牌节庆活动', value: 1300 },
-  { name: '品牌视觉传播', value: 1600 },
-  { name: '文书档案', value: 1700 },
-  { name: '影像资料', value: 2200 },
-  { name: '荣誉与表彰', value: 1800 },
-  { name: '企业藏品', value: 1800 },
-  { name: '其他', value: 1900 }
-]
+// 生成年度选项:2025 到今年
+const currentYear = new Date().getFullYear()
+const yearOptions = Array.from({ length: currentYear - 2025 + 1 }, (_, i) => {
+  const year = 2025 + i
+  return { value: year, label: `${year}年度` }
+})
 
 
 const DEFAULT_COLORS = ['#c11b2d', '#243220', '#24664b', '#8acfb2', '#806e4c', '#988364', '#972d00']
 const DEFAULT_COLORS = ['#c11b2d', '#243220', '#24664b', '#8acfb2', '#806e4c', '#988364', '#972d00']
 
 
-const binData1 = [
-  {
-    name: '啤酒产品类',
-    value: 2500
-  },
-  {
-    name: '饮用器皿类',
-    value: 1800
-  },
-  {
-    name: '品牌文化与节庆类',
-    value: 1200
-  },
-  {
-    name: '企业历史与档案类',
-    value: 800
-  },
-  {
-    name: '艺术与礼品类',
-    value: 1000
-  },
-  {
-    name: '工具与设备类',
-    value: 900
-  },
-  {
-    name: '其他综合类',
-    value: 600
-  }
-]
-
-const binData2 = [
-  {
-    name: '酒起',
-    value: 400
-  },
-  {
-    name: '杯子',
-    value: 100
-  },
-  {
-    name: '护肤品',
-    value: 100
-  },
-  {
-    name: '冰箱贴',
-    value: 100
-  },
-  {
-    name: '衣服',
-    value: 100
-  }
-]
-
 // 先写一些静态的
 // 先写一些静态的
+type DictItem = { name: string; id: number }
+type TextureItem = { name: string; id: number; count: number }
+type TotalItem = { pcs: number | null; level: string | null }
+
 function A1statistics() {
 function A1statistics() {
+  const [yearCountYear, setYearCountYear] = useState(currentYear)
+  const [yearCount, setYearCount] = useState<number | null>(null)
+
+  // 藏品总数、藏品总数量、定级文物数量
+  const [totalList, setTotalList] = useState<TotalItem[] | null>(null)
+
+  // 材质统计
+  const [textureOptions, setTextureOptions] = useState<DictItem[]>([])
+  const [textureTagId, setTextureTagId] = useState<number | null>(null)
+  const [textureData, setTextureData] = useState<{ name: string; value: number }[]>([])
+
+  // 品类统计
+  const [categoryOptions, setCategoryOptions] = useState<DictItem[]>([])
+  const [categoryTagId, setCategoryTagId] = useState<number | null>(null)
+  const [categoryData, setCategoryData] = useState<{ name: string; value: number }[]>([])
+
+  // 一级/二级分类
+  const [level1Data, setLevel1Data] = useState<{ name: string; value: number }[]>([])
+  const [level2Data, setLevel2Data] = useState<{ name: string; value: number }[]>([])
+
+  const textureInitialized = useRef(false)
+  const categoryInitialized = useRef(false)
+
+  // 获取一级/二级分类数据
+  useEffect(() => {
+    const fetchTagLevel = async () => {
+      try {
+        const res = await A1_APIgetDataTagLevel()
+        if (res?.code === 0 && res.data) {
+          const list1 = (res.data.level_1 || []).map((it: { name: string; count: number }) => ({
+            name: it.name,
+            value: it.count
+          }))
+          const list2 = (res.data.level_2 || []).map((it: { name: string; count: number }) => ({
+            name: it.name,
+            value: it.count
+          }))
+          setLevel1Data(list1)
+          setLevel2Data(list2)
+        } else {
+          setLevel1Data([])
+          setLevel2Data([])
+        }
+      } catch {
+        setLevel1Data([])
+        setLevel2Data([])
+      }
+    }
+    fetchTagLevel()
+  }, [])
+
+  // 获取藏品总数统计
+  useEffect(() => {
+    const fetchTotal = async () => {
+      try {
+        const res = await A1_APIgetTotal()
+        if (res?.code === 0 && Array.isArray(res.data)) {
+          setTotalList(res.data as TotalItem[])
+        } else {
+          setTotalList(null)
+        }
+      } catch {
+        setTotalList(null)
+      }
+    }
+    fetchTotal()
+  }, [])
+
+  // 藏品总数、藏品总数量、定级文物按级别统计
+  const totalStats = totalList
+    ? (() => {
+        const totalCount = totalList.length
+        const totalPcs = totalList.reduce((sum, it) => sum + (it.pcs ?? 0), 0)
+        const withLevel = totalList.filter(it => it.level != null && String(it.level).trim() !== '')
+        const level1 = totalList.filter(it => it.level === '一级').length
+        const level2 = totalList.filter(it => it.level === '二级').length
+        const level3 = totalList.filter(it => it.level === '三级').length
+        const level4 = totalList.filter(it => it.level === '一般').length
+        return {
+          totalCount,
+          totalPcs,
+          leveledCount: withLevel.length,
+          level1,
+          level2,
+          level3,
+          level4
+        }
+      })()
+    : null
+
+  // 获取筛选字典(材质+品类)
+  useEffect(() => {
+    const fetchDict = async () => {
+      try {
+        const res = await A1_APIgetDictById()
+        if (res?.code === 0 && res.data) {
+          const list3 = res.data.texture || []
+          const list4 = res.data.category || []
+          setTextureOptions(list3)
+          setCategoryOptions(list4)
+          if (list3.length > 0 && !textureInitialized.current) {
+            textureInitialized.current = true
+            setTextureTagId(list3[0].id)
+          }
+          if (list4.length > 0 && !categoryInitialized.current) {
+            categoryInitialized.current = true
+            setCategoryTagId(list4[0].id)
+          }
+        } else {
+          setTextureOptions([])
+          setCategoryOptions([])
+        }
+      } catch {
+        setTextureOptions([])
+        setCategoryOptions([])
+      }
+    }
+    fetchDict()
+  }, [])
+
+  // 材质 tagId 变化时获取数据
+  useEffect(() => {
+    if (textureTagId == null) {
+      setTextureData([])
+      return
+    }
+    const fetch = async () => {
+      try {
+        const res = await A1_APIgetDataTextureByTagId(textureTagId)
+        if (res?.code === 0 && Array.isArray(res.data)) {
+          setTextureData(
+            (res.data as TextureItem[]).map(({ name, count }) => ({ name, value: count }))
+          )
+        } else {
+          setTextureData([])
+        }
+      } catch {
+        setTextureData([])
+      }
+    }
+    fetch()
+  }, [textureTagId])
+
+  // 品类 tagId 变化时获取数据
+  useEffect(() => {
+    if (categoryTagId == null) {
+      setCategoryData([])
+      return
+    }
+    const fetch = async () => {
+      try {
+        const res = await A1_APIgetDataTagByTagId(categoryTagId)
+        if (res?.code === 0 && Array.isArray(res.data)) {
+          setCategoryData(
+            (res.data as TextureItem[]).map(({ name, count }) => ({ name, value: count }))
+          )
+        } else {
+          setCategoryData([])
+        }
+      } catch {
+        setCategoryData([])
+      }
+    }
+    fetch()
+  }, [categoryTagId])
+
+  // 获取年度新增产品数量
+  useEffect(() => {
+    const fetchYearCount = async () => {
+      try {
+        const res = await A1_APIworkCount(yearCountYear)
+        if (res?.code === 0) {
+          const count = typeof res.data === 'number' ? res.data : (res.data?.count ?? 0)
+          setYearCount(count)
+        }
+      } catch {
+        setYearCount(null)
+      }
+    }
+    fetchYearCount()
+  }, [yearCountYear])
+
   // 生成柱状图
   // 生成柱状图
   const initEchFu = useCallback((data: any[], dom: any) => {
   const initEchFu = useCallback((data: any[], dom: any) => {
     if (!dom) return
     if (!dom) return
 
 
+    const myChart = echarts.getInstanceByDom(dom) || echarts.init(dom)
+
     // 计算总数用于百分比
     // 计算总数用于百分比
     const total = data.reduce((sum, item) => sum + item.value, 0)
     const total = data.reduce((sum, item) => sum + item.value, 0)
-    const myChart = echarts.getInstanceByDom(dom) || echarts.init(dom)
+    const dataMax = Math.max(...data.map(d => d.value))
+    const yMax = Math.max(5, dataMax)
+    const yInterval = Math.max(1, Math.ceil(yMax / 5))
 
 
     const option: echarts.EChartsOption = {
     const option: echarts.EChartsOption = {
       tooltip: {
       tooltip: {
@@ -129,6 +257,9 @@ function A1statistics() {
           rotate: 30,
           rotate: 30,
           fontSize: 12,
           fontSize: 12,
           color: '#000',
           color: '#000',
+          formatter: (value: string) => {
+            return value.length > 4 ? value.slice(0, 5) + '...' : value
+          },
           margin: 15 // 调整标签与柱子的距离
           margin: 15 // 调整标签与柱子的距离
         },
         },
         axisLine: {
         axisLine: {
@@ -168,11 +299,9 @@ function A1statistics() {
             color: '#e0e0e0'
             color: '#e0e0e0'
           }
           }
         },
         },
-        // 设置Y轴最大值
-        max: 3000,
+        max: yMax,
         min: 0,
         min: 0,
-        // 调整Y轴刻度
-        interval: 500
+        interval: yInterval
       },
       },
       series: [
       series: [
         {
         {
@@ -234,10 +363,25 @@ function A1statistics() {
   const binInitFu = useCallback((data: any[], dom: any) => {
   const binInitFu = useCallback((data: any[], dom: any) => {
     if (!dom) return
     if (!dom) return
 
 
+    const myChart = echarts.getInstanceByDom(dom) || echarts.init(dom)
+    if (!data || data.length === 0) {
+      myChart.clear()
+      myChart.setOption({
+        graphic: [
+          {
+            type: 'text',
+            left: 'center',
+            top: 'center',
+            style: { text: '暂无数据', fontSize: 14, fill: '#999', textAlign: 'center' }
+          }
+        ]
+      })
+      return
+    }
+
     // 计算总数用于百分比
     // 计算总数用于百分比
     const total = data.reduce((sum, item) => sum + item.value, 0)
     const total = data.reduce((sum, item) => sum + item.value, 0)
 
 
-    const myChart = echarts.getInstanceByDom(dom) || echarts.init(dom)
     const option = {
     const option = {
       color: DEFAULT_COLORS, // 设置颜色方案
       color: DEFAULT_COLORS, // 设置颜色方案
       tooltip: {
       tooltip: {
@@ -298,12 +442,20 @@ function A1statistics() {
   }, [])
   }, [])
 
 
   useEffect(() => {
   useEffect(() => {
-    initEchFu(chartData1, document.querySelector('#echBox1'))
-    initEchFu(chartData2, document.querySelector('#echBox2'))
+    initEchFu(level1Data, document.querySelector('#echBox1'))
+  }, [initEchFu, level1Data])
 
 
-    binInitFu(binData1, document.querySelector('#echBox3'))
-    binInitFu(binData2, document.querySelector('#echBox4'))
-  }, [binInitFu, initEchFu])
+  useEffect(() => {
+    initEchFu(level2Data, document.querySelector('#echBox2'))
+  }, [initEchFu, level2Data])
+
+  useEffect(() => {
+    binInitFu(textureData, document.querySelector('#echBox3'))
+  }, [binInitFu, textureData])
+
+  useEffect(() => {
+    binInitFu(categoryData, document.querySelector('#echBox4'))
+  }, [binInitFu, categoryData])
 
 
   return (
   return (
     <div className={styles.A1statistics}>
     <div className={styles.A1statistics}>
@@ -316,7 +468,7 @@ function A1statistics() {
             <h3>藏品总数</h3>
             <h3>藏品总数</h3>
           </div>
           </div>
           <p>
           <p>
-            <span>3741</span>(件/套)
+            <span>{totalStats?.totalCount ?? 'empty'}</span>(件/套)
           </p>
           </p>
         </div>
         </div>
         <div>
         <div>
@@ -325,7 +477,7 @@ function A1statistics() {
             <h3>藏品总数量</h3>
             <h3>藏品总数量</h3>
           </div>
           </div>
           <p>
           <p>
-            <span>5834</span>(个)
+            <span>{totalStats?.totalPcs ?? 'empty'}</span>(个)
           </p>
           </p>
         </div>
         </div>
 
 
@@ -335,18 +487,18 @@ function A1statistics() {
             <h3>定级文物数量</h3>
             <h3>定级文物数量</h3>
           </div>
           </div>
           <p>
           <p>
-            <span>120</span>(件/套)
+            <span>{totalStats?.leveledCount ?? 'empty'}</span>(件/套)
             <i>
             <i>
-              一级<i>20</i>
+              一级<i>{totalStats?.level1 ?? 0}</i>
             </i>
             </i>
             <i>
             <i>
-              二级<i>30</i>
+              二级<i>{totalStats?.level2 ?? 0}</i>
             </i>
             </i>
             <i>
             <i>
-              三级<i>40</i>
+              三级<i>{totalStats?.level3 ?? 0}</i>
             </i>
             </i>
             <i>
             <i>
-              一般<i>30</i>
+              一般<i>{totalStats?.level4 ?? 0}</i>
             </i>
             </i>
           </p>
           </p>
         </div>
         </div>
@@ -356,18 +508,11 @@ function A1statistics() {
             <img src={iconUrl + '/a44.png'} alt='' />
             <img src={iconUrl + '/a44.png'} alt='' />
             <h3>年度新增产品数量</h3>
             <h3>年度新增产品数量</h3>
             <div className='A1_1_4_1'>
             <div className='A1_1_4_1'>
-              <Select
-                defaultValue={2026}
-                options={[
-                  { value: 2026, label: '2026年度' },
-                  { value: 2025, label: '2025年度' },
-                  { value: 2024, label: '2024年度' }
-                ]}
-              />
+              <Select value={yearCountYear} onChange={setYearCountYear} options={yearOptions} />
             </div>
             </div>
           </div>
           </div>
           <p>
           <p>
-            <span>123</span>(件/套)
+            <span>{yearCount ?? 'empty'}</span>(件/套)
           </p>
           </p>
         </div>
         </div>
       </div>
       </div>
@@ -387,7 +532,14 @@ function A1statistics() {
           <div className='A1_3row'>
           <div className='A1_3row'>
             <div className='A1tit2'>
             <div className='A1tit2'>
               <div>材质统计</div>
               <div>材质统计</div>
-              <Select defaultValue={'杯子'} options={[{ value: '杯子', label: '杯子' }]} />
+              <Select
+                value={textureTagId ?? undefined}
+                onChange={v => setTextureTagId(v ?? null)}
+                options={textureOptions.map(({ id, name }) => ({ value: id, label: name }))}
+                placeholder='请选择'
+                allowClear
+                style={{ width: 200 }}
+              />
             </div>
             </div>
             <div className='A1_3ech' id='echBox3'></div>
             <div className='A1_3ech' id='echBox3'></div>
           </div>
           </div>
@@ -396,8 +548,12 @@ function A1statistics() {
             <div className='A1tit2'>
             <div className='A1tit2'>
               <div>品类统计</div>
               <div>品类统计</div>
               <Select
               <Select
-                defaultValue={'文创产品'}
-                options={[{ value: '文创产品', label: '文创产品' }]}
+                value={categoryTagId ?? undefined}
+                onChange={v => setCategoryTagId(v ?? null)}
+                options={categoryOptions.map(({ id, name }) => ({ value: id, label: name }))}
+                placeholder='请选择'
+                allowClear
+                style={{ width: 200 }}
               />
               />
             </div>
             </div>
             <div className='A1_3ech' id='echBox4'></div>
             <div className='A1_3ech' id='echBox4'></div>

+ 9 - 6
src/pages/Cledger/C1ledger/index.tsx

@@ -1,7 +1,7 @@
 import React, { useCallback, useEffect, useMemo, useState } from 'react'
 import React, { useCallback, useEffect, useMemo, useState } from 'react'
 import styles from './index.module.scss'
 import styles from './index.module.scss'
 import { authorityFu } from '@/utils/authority'
 import { authorityFu } from '@/utils/authority'
-import { selectObj, getDictFu, resJiLianFu } from '@/utils/dataChange'
+import { selectObj, getDictFu, resJiLianFu, resTagFu } from '@/utils/dataChange'
 import history, { openLink } from '@/utils/history'
 import history, { openLink } from '@/utils/history'
 import TableList from '@/pages/Zother/TableList'
 import TableList from '@/pages/Zother/TableList'
 import { useSelector } from 'react-redux'
 import { useSelector } from 'react-redux'
@@ -150,7 +150,6 @@ function C1ledger() {
         placeholder: '完残程度',
         placeholder: '完残程度',
         options: selectObj['完残程度']
         options: selectObj['完残程度']
       },
       },
-      // TODO
       {
       {
         type: 'select',
         type: 'select',
         key: 'status',
         key: 'status',
@@ -265,10 +264,14 @@ function C1ledger() {
         : allData
         : allData
 
 
     const listData = filteredData.map((item: any) => {
     const listData = filteredData.map((item: any) => {
+      let applySiteStatus = '(空)'
+      const obj1 = selectObj['藏品库存状态'].find((v: any) => v.value === item.siteStatus)
+      if (obj1) applySiteStatus = obj1.label
       return {
       return {
         藏品登记号: item.num,
         藏品登记号: item.num,
         封面: item.thumb,
         封面: item.thumb,
-        藏品标签: item.tagDictId,
+        藏品标签: resTagFu(item.tagDictId || '', '藏品'),
+        文化标签: resTagFu(item.artDictId || '', '文创'),
         藏品名称: item.name,
         藏品名称: item.name,
         级别: item.level,
         级别: item.level,
         年代: resJiLianFu(item.ageDictId),
         年代: resJiLianFu(item.ageDictId),
@@ -276,14 +279,14 @@ function C1ledger() {
         完残程度: item.tornLevel,
         完残程度: item.tornLevel,
         数量: item.pcs,
         数量: item.pcs,
         入藏状态: item.status,
         入藏状态: item.status,
-        库存状态: item.siteStatus,
-        库房位置: item.siteLoc
+        库存状态: applySiteStatus,
+        库房位置: `${item.storageName}-${item.siteLoc}`
       }
       }
     })
     })
     console.log(years)
     console.log(years)
     exportExcelFile(
     exportExcelFile(
       listData,
       listData,
-      [100, 100, 100, 100, 100, 200, 200, 200, 100, 100, 100, 100, 100],
+      [100, 100, 200, 200, 200, 100, 200, 200, 100, 100, 100, 100, 200],
       '藏品总账数据'
       '藏品总账数据'
     )
     )
     setIsModalOpen(false)
     setIsModalOpen(false)

+ 4 - 2
src/pages/Fstorehouse/F1inStorage/F1edit/index.tsx

@@ -130,7 +130,8 @@ function F1editContent() {
           ...v,
           ...v,
           id: v.isNew || flag ? null : v.id,
           id: v.isNew || flag ? null : v.id,
           siteLoc,
           siteLoc,
-          siteId
+          siteId,
+          siteLocRemark: values[`${v.id}-siteLocRemark`] ?? v.siteLocRemark ?? ''
         })
         })
       }
       }
     })
     })
@@ -209,7 +210,8 @@ function F1editContent() {
                   )
                   )
                 }
                 }
               }
               }
-            ]
+            ],
+            ['input', '位置备注', 'siteLocRemark', { maxLength: 50, placeholder: '请输入' }]
           ]}
           ]}
           fileUpInfo={{ myUrl: 'cms/orderSite/in/upload', dirCode: 'inStorageGoods' }}
           fileUpInfo={{ myUrl: 'cms/orderSite/in/upload', dirCode: 'inStorageGoods' }}
           selectApi={F1_APIgetClueList}
           selectApi={F1_APIgetClueList}

+ 4 - 2
src/pages/Fstorehouse/F2moveStorage/F2edit/index.tsx

@@ -122,7 +122,8 @@ function F2editContent() {
           id: v.isNew || flag ? null : v.id,
           id: v.isNew || flag ? null : v.id,
           siteLoc,
           siteLoc,
           siteId,
           siteId,
-          storageInId: siteId
+          storageInId: siteId,
+          siteLocRemark: values[`${v.id}-siteLocRemark`] ?? v.siteLocRemark ?? ''
         })
         })
       }
       }
     })
     })
@@ -213,7 +214,8 @@ function F2editContent() {
                   )
                   )
                 }
                 }
               }
               }
-            ]
+            ],
+            ['input', '位置备注', 'siteLocRemark', { maxLength: 50, placeholder: '请输入' }]
           ]}
           ]}
           fileUpInfo={{ myUrl: 'cms/orderSite/in/upload', dirCode: 'inStorageGoods' }}
           fileUpInfo={{ myUrl: 'cms/orderSite/in/upload', dirCode: 'inStorageGoods' }}
           selectApi={F2_APIgetClueList}
           selectApi={F2_APIgetClueList}

+ 2 - 1
src/pages/Fstorehouse/F3outStorage/F3edit/index.tsx

@@ -136,7 +136,8 @@ function F3editContent() {
             ['txtC', '质地', 'textureDictId'],
             ['txtC', '质地', 'textureDictId'],
             ['select', '完残程度', 'tornLevel', selectObj['完残程度']],
             ['select', '完残程度', 'tornLevel', selectObj['完残程度']],
             ['ping', '数量', 'pcs', 'pcsUnitDictId'],
             ['ping', '数量', 'pcs', 'pcsUnitDictId'],
-            ['connectTxt', '库房位置', 'storageName', 'siteLoc']
+            ['connectTxt', '库房位置', 'storageName', 'siteLoc'],
+            ['txt', '位置备注', 'siteLocRemark']
           ]}
           ]}
           fileUpInfo={{ myUrl: 'cms/orderSite/out/upload', dirCode: 'outStorageGoods' }}
           fileUpInfo={{ myUrl: 'cms/orderSite/out/upload', dirCode: 'outStorageGoods' }}
           selectApi={F3_APIgetClueList}
           selectApi={F3_APIgetClueList}

+ 4 - 2
src/pages/Fstorehouse/F4check/F4edit/index.tsx

@@ -114,7 +114,8 @@ function F1editContent() {
           ...v,
           ...v,
           id: v.isNew || flag ? null : v.id,
           id: v.isNew || flag ? null : v.id,
           newPcs: values[`${v.id}-newPcs`] ?? v.newPcs,
           newPcs: values[`${v.id}-newPcs`] ?? v.newPcs,
-          pdRemark: values[`${v.id}-pdRemark`] ?? v.pdRemark
+          pdRemark: values[`${v.id}-pdRemark`] ?? v.pdRemark,
+          siteLocRemark: values[`${v.id}-siteLocRemark`] ?? v.siteLocRemark ?? ''
         })
         })
       }
       }
     })
     })
@@ -229,7 +230,8 @@ function F1editContent() {
                   )
                   )
                 }
                 }
               }
               }
-            ]
+            ],
+            ['input', '位置备注', 'siteLocRemark', { maxLength: 50, placeholder: '请输入' }]
           ]}
           ]}
           fileUpInfo={{ myUrl: 'cms/orderSite/check/upload', dirCode: 'checkGoods' }}
           fileUpInfo={{ myUrl: 'cms/orderSite/check/upload', dirCode: 'checkGoods' }}
           selectApi={F4_APIgetClueList}
           selectApi={F4_APIgetClueList}

+ 45 - 2
src/pages/Hexhibits/H1loan/H1detail/index.tsx

@@ -12,6 +12,7 @@ import {
 import { API_getFileListByIds } from '@/store/action/Cledger/C4file'
 import { API_getFileListByIds } from '@/store/action/Cledger/C4file'
 import ExhibitionModal, { ExhibitionFormValues } from '../components/ExhibitionModal'
 import ExhibitionModal, { ExhibitionFormValues } from '../components/ExhibitionModal'
 import RegionSettingModal from '../components/RegionSettingModal'
 import RegionSettingModal from '../components/RegionSettingModal'
+import ReturnGoodsModal from '../components/ReturnGoodsModal'
 import { MessageFu } from '@/utils/message'
 import { MessageFu } from '@/utils/message'
 import MyPopconfirm from '@/components/MyPopconfirm'
 import MyPopconfirm from '@/components/MyPopconfirm'
 import history, { openLink } from '@/utils/history'
 import history, { openLink } from '@/utils/history'
@@ -19,7 +20,7 @@ import dayjs from 'dayjs'
 import { baseURL } from '@/utils/http'
 import { baseURL } from '@/utils/http'
 import { FileListType } from '@/components/Z3upFiles/data'
 import { FileListType } from '@/components/Z3upFiles/data'
 import MyTable from '@/components/MyTable'
 import MyTable from '@/components/MyTable'
-import { selectObj } from '@/utils/dataChange'
+import { getDictFu, selectObj } from '@/utils/dataChange'
 import { showGoodTableC } from '@/utils/tableData'
 import { showGoodTableC } from '@/utils/tableData'
 import store from '@/store'
 import store from '@/store'
 import { tagApiArr } from '@/pages/ZgoodsInfo/data'
 import { tagApiArr } from '@/pages/ZgoodsInfo/data'
@@ -62,6 +63,7 @@ function H1detail() {
   const [fileList, setFileList] = useState<FileListType[]>([])
   const [fileList, setFileList] = useState<FileListType[]>([])
   const [exhibitionModalOpen, setExhibitionModalOpen] = useState(false)
   const [exhibitionModalOpen, setExhibitionModalOpen] = useState(false)
   const [regionSettingOpen, setRegionSettingOpen] = useState(false)
   const [regionSettingOpen, setRegionSettingOpen] = useState(false)
+  const [returnGoodsOpen, setReturnGoodsOpen] = useState(false)
   const [regionEditList, setRegionEditList] = useState<
   const [regionEditList, setRegionEditList] = useState<
     { id: number; goodNum: string; goodName: string; region: string; address: string }[]
     { id: number; goodNum: string; goodName: string; region: string; address: string }[]
   >([])
   >([])
@@ -142,6 +144,7 @@ function H1detail() {
     searchKey: '',
     searchKey: '',
     searchTagName: '',
     searchTagName: '',
     level: undefined as string | undefined,
     level: undefined as string | undefined,
+    typeDictId: undefined as (string | number)[] | undefined,
     region: undefined as string | undefined,
     region: undefined as string | undefined,
     status: undefined as number | undefined,
     status: undefined as number | undefined,
     subTagIds: '',
     subTagIds: '',
@@ -173,6 +176,9 @@ function H1detail() {
       }
       }
     })
     })
 
 
+    if (Array.isArray(fd.typeDictId) && fd.typeDictId.length) {
+      params.typeDictId = fd.typeDictId[fd.typeDictId.length - 1]
+    }
     const res = await H1_APIgetShowGoodPage(params)
     const res = await H1_APIgetShowGoodPage(params)
     if (res?.code === 0) {
     if (res?.code === 0) {
       setGoodList(res.data?.records || [])
       setGoodList(res.data?.records || [])
@@ -196,6 +202,7 @@ function H1detail() {
       searchKey: '',
       searchKey: '',
       searchTagName: '',
       searchTagName: '',
       level: undefined,
       level: undefined,
+      typeDictId: undefined,
       region: undefined,
       region: undefined,
       status: undefined,
       status: undefined,
       subTagIds: '',
       subTagIds: '',
@@ -264,6 +271,24 @@ function H1detail() {
     []
     []
   )
   )
 
 
+  const openReturnGoods = useCallback(() => {
+    setReturnGoodsOpen(true)
+  }, [])
+
+  const handleReturnGoodsConfirm = useCallback(
+    (goodIds: number[]) => {
+      if (!info.id || !info.name) return
+      const params = new URLSearchParams({
+        goodIds: goodIds.join(','),
+        showId: String(info.id),
+        showName: info.name
+      })
+      history.push(`/inStorage_edit/1/null?${params.toString()}`)
+      setReturnGoodsOpen(false)
+    },
+    [info.id, info.name]
+  )
+
   const regionOptions = useMemo(() => {
   const regionOptions = useMemo(() => {
     const r = info.region
     const r = info.region
     if (!r) return []
     if (!r) return []
@@ -271,6 +296,15 @@ function H1detail() {
     return arr.map(v => ({ label: v, value: v }))
     return arr.map(v => ({ label: v, value: v }))
   }, [info.region])
   }, [info.region])
 
 
+  const typeDictOptions = useMemo(() => {
+    // 待完善sg
+    try {
+      return getDictFu('藏品类别') || []
+    } catch {
+      return []
+    }
+  }, [])
+
   return (
   return (
     <div className={styles.H1detail}>
     <div className={styles.H1detail}>
       <div className='H1detailMain'>
       <div className='H1detailMain'>
@@ -345,7 +379,9 @@ function H1detail() {
             >
             >
               借展出库
               借展出库
             </Button>
             </Button>
-            <Button>归还展品</Button>
+            <Button onClick={openReturnGoods} disabled={!info.id || !goodList.length}>
+              归还展品
+            </Button>
           </div>
           </div>
         </div>
         </div>
         <div className={styles.goodSearchRow}>
         <div className={styles.goodSearchRow}>
@@ -467,6 +503,13 @@ function H1detail() {
         onUpdateItem={updateRegionEditItem}
         onUpdateItem={updateRegionEditItem}
         onSubmit={handleRegionSubmit}
         onSubmit={handleRegionSubmit}
       />
       />
+
+      <ReturnGoodsModal
+        open={returnGoodsOpen}
+        onCancel={() => setReturnGoodsOpen(false)}
+        goodList={goodList.map((item: any) => ({ ...item, goodId: item.goodId ?? item.id }))}
+        onConfirm={handleReturnGoodsConfirm}
+      />
     </div>
     </div>
   )
   )
 }
 }

+ 68 - 0
src/pages/Hexhibits/H1loan/components/ReturnGoodsModal.tsx

@@ -0,0 +1,68 @@
+import React, { useCallback, useMemo, useState } from 'react'
+import { Button, Modal } from 'antd'
+import { showGoodTableC } from '@/utils/tableData'
+import MyTable from '@/components/MyTable'
+
+type Props = {
+  open: boolean
+  onCancel: () => void
+  goodList: any[]
+  onConfirm: (goodIds: number[]) => void
+}
+
+function ReturnGoodsModal({ open, onCancel, goodList, onConfirm }: Props) {
+  const [selectedRowKeys, setSelectedRowKeys] = useState<number[]>([])
+
+  const rowSelection = useMemo(
+    () => ({
+      selectedRowKeys,
+      onChange: (keys: React.Key[]) => setSelectedRowKeys(keys as number[])
+    }),
+    [selectedRowKeys]
+  )
+
+  const handleConfirm = useCallback(() => {
+    if (!selectedRowKeys.length) return
+    onConfirm(selectedRowKeys)
+    setSelectedRowKeys([])
+    onCancel()
+  }, [selectedRowKeys, onConfirm, onCancel])
+
+  const handleCancel = useCallback(() => {
+    setSelectedRowKeys([])
+    onCancel()
+  }, [onCancel])
+
+  return (
+    <Modal
+      title='归还展品'
+      open={open}
+      onCancel={handleCancel}
+      footer={null}
+      width={900}
+      destroyOnClose
+    >
+      <MyTable
+        classKey='ReturnGoodsModal'
+        list={goodList}
+        columnsTemp={showGoodTableC}
+        pagingInfo={false}
+        rowKey='goodId'
+        rowSelection={rowSelection}
+      />
+      <div style={{ marginTop: 16, textAlign: 'right' }}>
+        <Button onClick={handleCancel}>取消</Button>
+        <Button
+          type='primary'
+          onClick={handleConfirm}
+          style={{ marginLeft: 8 }}
+          disabled={!selectedRowKeys.length}
+        >
+          确定
+        </Button>
+      </div>
+    </Modal>
+  )
+}
+
+export default React.memo(ReturnGoodsModal)

+ 1 - 0
src/pages/Isystem/I1storageSet/index.tsx

@@ -225,6 +225,7 @@ function I1storageSet() {
           setWarehouseModalVisible(false)
           setWarehouseModalVisible(false)
           setWarehouseEditData(null)
           setWarehouseEditData(null)
           getWarehouseListFu()
           getWarehouseListFu()
+          getAllWarehouseListFu()
         }}
         }}
       />
       />
 
 

+ 18 - 3
src/pages/Zother/EditTop/index.tsx

@@ -17,7 +17,7 @@ import ImageLazy from '@/components/ImageLazy'
 import { openLink } from '@/utils/history'
 import { openLink } from '@/utils/history'
 import MyPopconfirm from '@/components/MyPopconfirm'
 import MyPopconfirm from '@/components/MyPopconfirm'
 import { API_getFileListByIds } from '@/store/action/Cledger/C4file'
 import { API_getFileListByIds } from '@/store/action/Cledger/C4file'
-import { API_getGoodsInfo } from '@/store/action/Cledger/C1ledger'
+import { API_getGoodsInfo, API_getGoodsByIds } from '@/store/action/Cledger/C1ledger'
 
 
 export const pageKeyTxtObj = {
 export const pageKeyTxtObj = {
   1: '新增',
   1: '新增',
@@ -86,9 +86,24 @@ function EditTop({ rowArr, pageTxt, APIobj, fileUpInfo, moreDom }: Props) {
     if (res.code === 0) {
     if (res.code === 0) {
       setInfoFu(res.data)
       setInfoFu(res.data)
 
 
-      // 从盘点过来---回显数据
       const urlAll = window.location.href
       const urlAll = window.location.href
-      if (urlAll.includes('?pNum=')) {
+      const urlParams = new URLSearchParams(urlAll.split('?')[1] || '')
+
+      // 从借展归还过来---回显借展归还和藏品清单
+      const goodIdsStr = urlParams.get('goodIds')
+      const showId = urlParams.get('showId')
+      const showName = urlParams.get('showName')
+      if (goodIdsStr && showId && showName) {
+        const goodIds = goodIdsStr.split(',').map(Number).filter(Boolean)
+        if (goodIds.length) {
+          const res2 = await API_getGoodsByIds(goodIds)
+          const list = Array.isArray(res2?.data) ? res2.data : res2?.data?.list || []
+          const snapsData = list.map((v: any) => ({ ...v, idTemp: v.id }))
+          setSnapsFu(snapsData)
+          setInfoFu((prev: any) => ({ ...prev, showId: Number(showId), showName }))
+        }
+      } else if (urlAll.includes('?pNum=')) {
+        // 从盘点过来---回显数据
         const txt = urlAll.split('?pNum=')[1]
         const txt = urlAll.split('?pNum=')[1]
         const arr = txt.split(',')
         const arr = txt.split(',')
         const goodId = Number(arr[1])
         const goodId = Number(arr[1])

+ 48 - 0
src/store/action/Abench/A1.ts

@@ -0,0 +1,48 @@
+import http from '@/utils/http'
+
+/**
+ * 年度新增藏品数量
+ */
+export const A1_APIworkCount = (yearCountYear: string | number) => {
+  return http.get(`cms/workCount/getByYear/${yearCountYear}`)
+}
+
+/**
+ * 获取筛选字典(材质+品类)
+ * 返回 {texture:any[]; category:any[]}
+ */
+export const A1_APIgetDictById = () => {
+  return http.get(`cms/workCount/getDictById`)
+}
+
+/**
+ * 根据 tagId 获取材质统计数据
+ * 返回 {name:string; id:number; count:number}[]
+ */
+export const A1_APIgetDataTextureByTagId = (tagId: number) => {
+  return http.get(`cms/workCount/getDataTextureByTagId/${tagId}`)
+}
+
+/**
+ * 根据 tagId 获取品类统计数据
+ * 返回 {name:string; id:number; count:number}[]
+ */
+export const A1_APIgetDataTagByTagId = (tagId: number) => {
+  return http.get(`cms/workCount/getDataTagByTagId/${tagId}`)
+}
+
+/**
+ * 获取藏品总数统计
+ * 返回 {pcs:null|number; level:string}[] 藏品级别:一级、二级、三级、一般
+ */
+export const A1_APIgetTotal = () => {
+  return http.get(`cms/workCount/getTotal`)
+}
+
+/**
+ * 获取一级/二级分类数据
+ * 返回 {level_1:{name:string;count:number}[]; level_2:{name:string;count:number}[]}
+ */
+export const A1_APIgetDataTagLevel = () => {
+  return http.get(`cms/workCount/getDataTagLevel`)
+}

+ 7 - 0
src/store/action/Cledger/C1ledger.ts

@@ -39,6 +39,13 @@ export const API_getGoodsInfo = (id: number) => {
 }
 }
 
 
 /**
 /**
+ * 藏品总账-根据id列表批量获取藏品
+ */
+export const API_getGoodsByIds = (ids: number[]) => {
+  return http.post('cms/good/ledger/findByIds', ids)
+}
+
+/**
  * 藏品总账-获取藏品分页列表
  * 藏品总账-获取藏品分页列表
  */
  */
 export const API_getGoodsList = (data: any): any => {
 export const API_getGoodsList = (data: any): any => {