|
|
@@ -0,0 +1,362 @@
|
|
|
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
|
|
+import styles from './index.module.scss'
|
|
|
+import { Button, Cascader, Input, Select } from 'antd'
|
|
|
+import { useParams } from 'react-router-dom'
|
|
|
+import {
|
|
|
+ H1_APIgetInfo,
|
|
|
+ H1_APIsave,
|
|
|
+ H1_APIdelete,
|
|
|
+ H1_APIgetShowGoodPage
|
|
|
+} from '@/store/action/Hexhibits/H1loan'
|
|
|
+import { API_getFileListByIds } from '@/store/action/Cledger/C4file'
|
|
|
+import ExhibitionModal, { ExhibitionFormValues } from '../components/ExhibitionModal'
|
|
|
+import { MessageFu } from '@/utils/message'
|
|
|
+import MyPopconfirm from '@/components/MyPopconfirm'
|
|
|
+import history from '@/utils/history'
|
|
|
+import dayjs from 'dayjs'
|
|
|
+import { baseURL } from '@/utils/http'
|
|
|
+import { FileListType } from '@/components/Z3upFiles/data'
|
|
|
+import MyTable from '@/components/MyTable'
|
|
|
+import { getDictFu, selectObj } from '@/utils/dataChange'
|
|
|
+import { showGoodTableC } from '@/utils/tableData'
|
|
|
+
|
|
|
+type DetailInfo = {
|
|
|
+ id?: number
|
|
|
+ name?: string
|
|
|
+ type?: string
|
|
|
+ dateOpen?: string
|
|
|
+ dateEnd?: string
|
|
|
+ region?: string
|
|
|
+ planner?: string
|
|
|
+ remark?: string
|
|
|
+ fileIds?: string
|
|
|
+}
|
|
|
+
|
|
|
+const EMPTY_VAL = '(空)'
|
|
|
+
|
|
|
+const formatVal = (v: React.ReactNode) =>
|
|
|
+ v === undefined || v === null || v === '' ? EMPTY_VAL : v
|
|
|
+
|
|
|
+const DetailRow = ({
|
|
|
+ label,
|
|
|
+ value,
|
|
|
+ fullRow
|
|
|
+}: {
|
|
|
+ label: string
|
|
|
+ value: React.ReactNode
|
|
|
+ fullRow?: boolean
|
|
|
+}) => (
|
|
|
+ <div className={styles.detailRow} data-full={fullRow}>
|
|
|
+ <span className={styles.detailLabel}>{label}</span>
|
|
|
+ <span className={styles.detailValue}>{formatVal(value)}</span>
|
|
|
+ </div>
|
|
|
+)
|
|
|
+
|
|
|
+function H1detail() {
|
|
|
+ const { id } = useParams<any>()
|
|
|
+ const [info, setInfo] = useState<DetailInfo>({})
|
|
|
+ const [fileList, setFileList] = useState<FileListType[]>([])
|
|
|
+ const [exhibitionModalOpen, setExhibitionModalOpen] = useState(false)
|
|
|
+
|
|
|
+ const getInfo = useCallback(async () => {
|
|
|
+ if (!id) return
|
|
|
+ const res = await H1_APIgetInfo(Number(id))
|
|
|
+ if (res?.code === 0 && res.data) {
|
|
|
+ setInfo(res.data)
|
|
|
+ const fileIds = res.data.fileIds || ''
|
|
|
+ if (fileIds) {
|
|
|
+ const fileRes = await API_getFileListByIds(fileIds.split(',').filter(Boolean))
|
|
|
+ if (fileRes?.code === 0 && fileRes.data) {
|
|
|
+ setFileList(fileRes.data)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }, [id])
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ getInfo()
|
|
|
+ }, [getInfo])
|
|
|
+
|
|
|
+ const dateStr = React.useMemo(() => {
|
|
|
+ const { dateOpen, dateEnd } = info
|
|
|
+ if (!dateOpen && !dateEnd) return '长期'
|
|
|
+ const open = dateOpen ? dayjs(dateOpen).format('YYYY年MM月DD日') : EMPTY_VAL
|
|
|
+ const end = dateEnd ? dayjs(dateEnd).format('YYYY年MM月DD日') : EMPTY_VAL
|
|
|
+ return `${open} - ${end}`
|
|
|
+ }, [info])
|
|
|
+
|
|
|
+ const regionStr = React.useMemo(() => {
|
|
|
+ const r = info.region
|
|
|
+ if (!r) return EMPTY_VAL
|
|
|
+ const arr = typeof r === 'string' ? r.split(',').filter(Boolean) : Array.isArray(r) ? r : []
|
|
|
+ return arr.length ? arr.join('、') : EMPTY_VAL
|
|
|
+ }, [info])
|
|
|
+
|
|
|
+ const titleTag = React.useMemo(() => {
|
|
|
+ const type = info.type || EMPTY_VAL
|
|
|
+ const planner = info.planner || EMPTY_VAL
|
|
|
+ return `${type} | ${dateStr} | ${planner}`
|
|
|
+ }, [info, dateStr])
|
|
|
+
|
|
|
+ const handleDelete = useCallback(async () => {
|
|
|
+ if (!info.id) return
|
|
|
+ const res = await H1_APIdelete(info.id)
|
|
|
+ if (res?.code === 0) {
|
|
|
+ MessageFu.success('删除成功')
|
|
|
+ history.push('/loan')
|
|
|
+ } else {
|
|
|
+ MessageFu.error(res?.message || '删除失败')
|
|
|
+ }
|
|
|
+ }, [info.id])
|
|
|
+
|
|
|
+ const handleEditOk = useCallback(
|
|
|
+ async (values: ExhibitionFormValues) => {
|
|
|
+ const res = await H1_APIsave({
|
|
|
+ ...values,
|
|
|
+ id: info.id,
|
|
|
+ region: values.region.join(',')
|
|
|
+ })
|
|
|
+ if (res?.code === 0) {
|
|
|
+ MessageFu.success('编辑成功')
|
|
|
+ setExhibitionModalOpen(false)
|
|
|
+ getInfo()
|
|
|
+ } else {
|
|
|
+ return Promise.reject(res?.message || '编辑失败')
|
|
|
+ }
|
|
|
+ },
|
|
|
+ [info.id, getInfo]
|
|
|
+ )
|
|
|
+
|
|
|
+ // 展品清单
|
|
|
+ const [goodFormData, setGoodFormData] = useState({
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ searchKey: '',
|
|
|
+ searchTagName: '',
|
|
|
+ level: undefined as string | undefined,
|
|
|
+ typeDictId: undefined as (string | number)[] | undefined,
|
|
|
+ region: undefined as string | undefined,
|
|
|
+ status: undefined as number | undefined
|
|
|
+ })
|
|
|
+ const goodFormDataRef = useRef(goodFormData)
|
|
|
+ useEffect(() => {
|
|
|
+ goodFormDataRef.current = goodFormData
|
|
|
+ }, [goodFormData])
|
|
|
+ const [goodTimeKey, setGoodTimeKey] = useState(0)
|
|
|
+ const [goodList, setGoodList] = useState<any[]>([])
|
|
|
+ const [goodTotal, setGoodTotal] = useState(0)
|
|
|
+
|
|
|
+ const getGoodList = useCallback(async () => {
|
|
|
+ if (!info.id) return
|
|
|
+ const fd = goodFormDataRef.current
|
|
|
+ const params: any = {
|
|
|
+ ...fd,
|
|
|
+ showId: info.id
|
|
|
+ }
|
|
|
+ if (Array.isArray(fd.typeDictId) && fd.typeDictId.length) {
|
|
|
+ params.typeDictId = fd.typeDictId[fd.typeDictId.length - 1]
|
|
|
+ }
|
|
|
+ const res = await H1_APIgetShowGoodPage(params)
|
|
|
+ if (res?.code === 0) {
|
|
|
+ setGoodList(res.data?.records || [])
|
|
|
+ setGoodTotal(res.data?.total || 0)
|
|
|
+ }
|
|
|
+ }, [info.id])
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ getGoodList()
|
|
|
+ }, [getGoodList, goodTimeKey])
|
|
|
+
|
|
|
+ const goodClickSearch = useCallback(() => {
|
|
|
+ setGoodFormData(d => ({ ...d, pageNum: 1 }))
|
|
|
+ setTimeout(() => setGoodTimeKey(Date.now()), 50)
|
|
|
+ }, [])
|
|
|
+
|
|
|
+ const goodResetFu = useCallback(() => {
|
|
|
+ setGoodFormData({
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ searchKey: '',
|
|
|
+ searchTagName: '',
|
|
|
+ level: undefined,
|
|
|
+ typeDictId: undefined,
|
|
|
+ region: undefined,
|
|
|
+ status: undefined
|
|
|
+ })
|
|
|
+ setTimeout(() => setGoodTimeKey(Date.now()), 50)
|
|
|
+ }, [])
|
|
|
+
|
|
|
+ const goodPaginationChange = useCallback((pageNum: number, pageSize: number) => {
|
|
|
+ setGoodFormData(d => ({ ...d, pageNum, pageSize }))
|
|
|
+ setTimeout(() => setGoodTimeKey(Date.now()), 50)
|
|
|
+ }, [])
|
|
|
+
|
|
|
+ const regionOptions = useMemo(() => {
|
|
|
+ const r = info.region
|
|
|
+ if (!r) return []
|
|
|
+ const arr = typeof r === 'string' ? r.split(',').filter(Boolean) : []
|
|
|
+ return arr.map(v => ({ label: v, value: v }))
|
|
|
+ }, [info.region])
|
|
|
+
|
|
|
+ const typeDictOptions = useMemo(() => {
|
|
|
+ try {
|
|
|
+ return getDictFu('藏品类别') || []
|
|
|
+ } catch {
|
|
|
+ return []
|
|
|
+ }
|
|
|
+ }, [])
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div className={styles.H1detail}>
|
|
|
+ <div className='H1detailMain'>
|
|
|
+ <div className='H1detailMainTitle'>
|
|
|
+ <div>
|
|
|
+ <span>{info.name}</span>
|
|
|
+ <Button type='dashed' style={{ pointerEvents: 'none' }}>
|
|
|
+ {titleTag}
|
|
|
+ </Button>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <Button type='primary' onClick={() => setExhibitionModalOpen(true)} disabled={!info.id}>
|
|
|
+ 编辑
|
|
|
+ </Button>
|
|
|
+ <MyPopconfirm
|
|
|
+ txtK='删除'
|
|
|
+ Dom={
|
|
|
+ <Button color='danger' disabled={!info.id}>
|
|
|
+ 删除
|
|
|
+ </Button>
|
|
|
+ }
|
|
|
+ onConfirm={handleDelete}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div className={styles.detailContent}>
|
|
|
+ <div className={styles.detailGrid}>
|
|
|
+ <DetailRow label='起止日期:' value={dateStr} />
|
|
|
+ <DetailRow label='展览类型:' value={info.type} />
|
|
|
+ <DetailRow label='展区设置:' value={regionStr} />
|
|
|
+ <DetailRow label='策展人:' value={info.planner} />
|
|
|
+ <DetailRow label='展览说明:' value={info.remark} fullRow />
|
|
|
+ <DetailRow
|
|
|
+ label='附件:'
|
|
|
+ value={
|
|
|
+ fileList.length ? (
|
|
|
+ <span className={styles.fileList}>
|
|
|
+ {fileList.map(f => (
|
|
|
+ <a
|
|
|
+ key={f.id}
|
|
|
+ href={baseURL + f.filePath}
|
|
|
+ download
|
|
|
+ target='_blank'
|
|
|
+ rel='noreferrer'
|
|
|
+ >
|
|
|
+ {f.fileName}
|
|
|
+ </a>
|
|
|
+ ))}
|
|
|
+ </span>
|
|
|
+ ) : undefined
|
|
|
+ }
|
|
|
+ fullRow
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div className='H1detailMain'>
|
|
|
+ <div className='H1detailMainTitle'>
|
|
|
+ <span>展品清单</span>
|
|
|
+ <div>
|
|
|
+ <Button>展位设置</Button>
|
|
|
+ <Button
|
|
|
+ onClick={() => info.id && history.push(`/outStorage_edit/1/null?showId=${info.id}`)}
|
|
|
+ disabled={!info.id}
|
|
|
+ >
|
|
|
+ 借展出库
|
|
|
+ </Button>
|
|
|
+ <Button>归还展品</Button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div className={styles.goodSearchRow}>
|
|
|
+ <Input
|
|
|
+ placeholder='搜索藏品登记号、藏品名称'
|
|
|
+ maxLength={30}
|
|
|
+ value={goodFormData.searchKey}
|
|
|
+ onChange={e => setGoodFormData(d => ({ ...d, searchKey: e.target.value }))}
|
|
|
+ allowClear
|
|
|
+ style={{ width: 250 }}
|
|
|
+ />
|
|
|
+ <Input
|
|
|
+ placeholder='搜索藏品标签'
|
|
|
+ value={goodFormData.searchTagName}
|
|
|
+ onChange={e => setGoodFormData(d => ({ ...d, searchTagName: e.target.value }))}
|
|
|
+ allowClear
|
|
|
+ style={{ width: 200 }}
|
|
|
+ />
|
|
|
+ <Select
|
|
|
+ placeholder='级别'
|
|
|
+ allowClear
|
|
|
+ value={goodFormData.level}
|
|
|
+ onChange={v => setGoodFormData(d => ({ ...d, level: v }))}
|
|
|
+ options={selectObj['藏品级别']}
|
|
|
+ style={{ width: 120 }}
|
|
|
+ />
|
|
|
+ <Cascader
|
|
|
+ placeholder='类别'
|
|
|
+ allowClear
|
|
|
+ value={goodFormData.typeDictId}
|
|
|
+ onChange={(v: any) => setGoodFormData(d => ({ ...d, typeDictId: v }))}
|
|
|
+ options={typeDictOptions}
|
|
|
+ fieldNames={{ label: 'name', value: 'id', children: 'children' }}
|
|
|
+ style={{ width: 160 }}
|
|
|
+ />
|
|
|
+ <Select
|
|
|
+ placeholder='展区'
|
|
|
+ allowClear
|
|
|
+ value={goodFormData.region}
|
|
|
+ onChange={v => setGoodFormData(d => ({ ...d, region: v }))}
|
|
|
+ options={regionOptions}
|
|
|
+ style={{ width: 120 }}
|
|
|
+ />
|
|
|
+ <Select
|
|
|
+ placeholder='展览状态'
|
|
|
+ allowClear
|
|
|
+ value={goodFormData.status}
|
|
|
+ onChange={v => setGoodFormData(d => ({ ...d, status: v }))}
|
|
|
+ options={selectObj['展览状态']}
|
|
|
+ style={{ width: 120 }}
|
|
|
+ />
|
|
|
+ <Button type='primary' onClick={goodClickSearch}>
|
|
|
+ 查询
|
|
|
+ </Button>
|
|
|
+ <Button onClick={goodResetFu}>重置</Button>
|
|
|
+ </div>
|
|
|
+ <div className={styles.goodTableWrap}>
|
|
|
+ <MyTable
|
|
|
+ classKey='H1detailGood'
|
|
|
+ list={goodList}
|
|
|
+ columnsTemp={showGoodTableC}
|
|
|
+ total={goodTotal}
|
|
|
+ pageNum={goodFormData.pageNum}
|
|
|
+ pageSize={goodFormData.pageSize}
|
|
|
+ yHeight={400}
|
|
|
+ onChange={goodPaginationChange}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <ExhibitionModal
|
|
|
+ open={exhibitionModalOpen}
|
|
|
+ onOk={handleEditOk}
|
|
|
+ onCancel={() => setExhibitionModalOpen(false)}
|
|
|
+ initialValues={info}
|
|
|
+ initialFileList={fileList}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+const MemoH1detail = React.memo(H1detail)
|
|
|
+
|
|
|
+export default MemoH1detail
|