|
@@ -1,9 +1,304 @@
|
|
|
-import React from 'react'
|
|
|
|
|
|
|
+import React, { useMemo, useState, useCallback, useRef, useEffect } from 'react'
|
|
|
import styles from './index.module.scss'
|
|
import styles from './index.module.scss'
|
|
|
|
|
+import { selectObj, getDictFu } from '@/utils/dataChange'
|
|
|
|
|
+import { openLink } from '@/utils/history'
|
|
|
|
|
+import TableList from '@/pages/Zother/TableList'
|
|
|
|
|
+import { useSelector } from 'react-redux'
|
|
|
|
|
+import { RootState } from '@/store'
|
|
|
|
|
+import { API_getGoodsList } from '@/store/action/Cledger/C1ledger'
|
|
|
|
|
+import { baseFormData } from '@/pages/Zother/data'
|
|
|
|
|
+import { goodsSonTableC } from '@/utils/tableData'
|
|
|
|
|
+import { Button, Tree, Input, TreeDataNode } from 'antd'
|
|
|
|
|
+import { filterTreeByName } from '@/pages/Isystem/I2dict/data'
|
|
|
|
|
+
|
|
|
|
|
+const C2topSearch = [
|
|
|
|
|
+ {
|
|
|
|
|
+ type: 'input',
|
|
|
|
|
+ key: 'searchKey',
|
|
|
|
|
+ placeholder: '搜索藏品登记号、藏品名称'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ type: 'cascader',
|
|
|
|
|
+ key: 'textureDictId',
|
|
|
|
|
+ placeholder: '质地',
|
|
|
|
|
+ options: getDictFu('质地')
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ type: 'select',
|
|
|
|
|
+ key: 'tornLevel',
|
|
|
|
|
+ placeholder: '完残程度',
|
|
|
|
|
+ options: selectObj['完残程度']
|
|
|
|
|
+ },
|
|
|
|
|
+ // TODO
|
|
|
|
|
+ {
|
|
|
|
|
+ type: 'select',
|
|
|
|
|
+ key: 'status',
|
|
|
|
|
+ placeholder: '入藏状态',
|
|
|
|
|
+ options: selectObj['藏品入藏状态']
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ type: 'select',
|
|
|
|
|
+ key: 'siteStatus',
|
|
|
|
|
+ placeholder: '库存状态',
|
|
|
|
|
+ options: selectObj['藏品库存状态']
|
|
|
|
|
+ }
|
|
|
|
|
+]
|
|
|
|
|
+
|
|
|
|
|
+const C2baseFormData = {
|
|
|
|
|
+ ...baseFormData,
|
|
|
|
|
+ typeDictId: '',
|
|
|
|
|
+ ageDictId: '',
|
|
|
|
|
+ textureDictId: ''
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const C2columnsTempAdd = [
|
|
|
|
|
+ ...goodsSonTableC(false),
|
|
|
|
|
+ ['select', '入藏状态', 'status', selectObj['藏品入藏状态']],
|
|
|
|
|
+ ['txt', '库存状态', 'siteStatus'],
|
|
|
|
|
+ ['txt', '库房位置', 'siteLoc']
|
|
|
|
|
+]
|
|
|
|
|
+
|
|
|
|
|
+// 递归收集树中所有节点的 key(用于默认全选)
|
|
|
|
|
+const getAllTreeKeys = (nodes: TreeDataNode[]): string[] => {
|
|
|
|
|
+ const keys: string[] = []
|
|
|
|
|
+ const walk = (list: TreeDataNode[]) => {
|
|
|
|
|
+ list.forEach(node => {
|
|
|
|
|
+ keys.push(node.key as string)
|
|
|
|
|
+ if (node.children?.length) walk(node.children)
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ walk(nodes)
|
|
|
|
|
+ return keys
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const C2siderLeftTree = ({ setExtraParams }: { setExtraParams: (params: any) => void }) => {
|
|
|
|
|
+ const { treeData: dictAll } = useSelector((state: RootState) => state.E1tag)
|
|
|
|
|
+ // 当前选中的树节点ID(高亮)
|
|
|
|
|
+ const [acShu, setAcShu] = useState('')
|
|
|
|
|
+ // 勾选中的节点 key,默认全部选中
|
|
|
|
|
+ const [checkedKeys, setCheckedKeys] = useState<string[]>([])
|
|
|
|
|
+ const hasSetDefaultChecked = useRef(false)
|
|
|
|
|
+
|
|
|
|
|
+ // 点击树节点
|
|
|
|
|
+ const onSelect = (id: any) => {
|
|
|
|
|
+ if (id[0]) setAcShu(id[0])
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 搜索高亮
|
|
|
|
|
+ const [value, setValue] = useState('')
|
|
|
|
|
+ const [value2, setValue2] = useState('')
|
|
|
|
|
+
|
|
|
|
|
+ const timeRef = useRef(-1)
|
|
|
|
|
+ const valueChange = useCallback((val: string) => {
|
|
|
|
|
+ setValue(val.trim())
|
|
|
|
|
+ clearTimeout(timeRef.current)
|
|
|
|
|
+ timeRef.current = window.setTimeout(() => {
|
|
|
|
|
+ setValue2(val.trim())
|
|
|
|
|
+ }, 500)
|
|
|
|
|
+ }, [])
|
|
|
|
|
+
|
|
|
|
|
+ // 将带 id/name/num/children 的树数据转为 TreeDataNode,keyPrefix 用于区分分类并传给后端
|
|
|
|
|
+ const loopToTreeNodes = useCallback(
|
|
|
|
|
+ (dataTemp: any[], keyPrefix: string): TreeDataNode[] => {
|
|
|
|
|
+ const data = dataTemp || []
|
|
|
|
|
+ return data.map(item => {
|
|
|
|
|
+ const strTitle = ((item.num ? item.num + ' ' : '') + item.name) as string
|
|
|
|
|
+ const strTitleD = strTitle.toUpperCase()
|
|
|
|
|
+ const valueD = value.toUpperCase()
|
|
|
|
|
+ const index = strTitleD.indexOf(valueD)
|
|
|
|
|
+ const beforeStr = strTitle.substring(0, index)
|
|
|
|
|
+ const afterStr = strTitle.slice(index + value.length)
|
|
|
|
|
+ const title =
|
|
|
|
|
+ index > -1 ? (
|
|
|
|
|
+ <span key={item.id}>
|
|
|
|
|
+ {beforeStr}
|
|
|
|
|
+ <span className='site-tree-search-value'>{value}</span>
|
|
|
|
|
+ {afterStr}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ ) : (
|
|
|
|
|
+ <span key={item.id}>{strTitle}</span>
|
|
|
|
|
+ )
|
|
|
|
|
+ const key = `${keyPrefix}-${item.id}`
|
|
|
|
|
+ if (item.children?.length) {
|
|
|
|
|
+ return { title, key, children: loopToTreeNodes(item.children, keyPrefix) }
|
|
|
|
|
+ }
|
|
|
|
|
+ return { title, key }
|
|
|
|
|
+ })
|
|
|
|
|
+ },
|
|
|
|
|
+ [value]
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ // 按节点名称筛选:藏品类别、藏品年代、藏品标签(树)、藏品级别(平铺)
|
|
|
|
|
+ const categoryFiltered = useMemo(() => {
|
|
|
|
|
+ const list = getDictFu('藏品类别') || []
|
|
|
|
|
+ return value2 ? filterTreeByName(list, value2) : list
|
|
|
|
|
+ }, [value2])
|
|
|
|
|
+
|
|
|
|
|
+ const ageFiltered = useMemo(() => {
|
|
|
|
|
+ const list = getDictFu('藏品年代') || []
|
|
|
|
|
+ return value2 ? filterTreeByName(list, value2) : list
|
|
|
|
|
+ }, [value2])
|
|
|
|
|
+
|
|
|
|
|
+ const tagTreeFiltered = useMemo(() => {
|
|
|
|
|
+ return value2 ? filterTreeByName(dictAll, value2) : dictAll
|
|
|
|
|
+ }, [dictAll, value2])
|
|
|
|
|
+
|
|
|
|
|
+ const levelFiltered = useMemo(() => {
|
|
|
|
|
+ const list = selectObj['藏品级别'] || []
|
|
|
|
|
+ if (!value2) return list
|
|
|
|
|
+ const key = value2.toUpperCase()
|
|
|
|
|
+ return list.filter((item: { label: string }) => item.label.toUpperCase().includes(key))
|
|
|
|
|
+ }, [value2])
|
|
|
|
|
+
|
|
|
|
|
+ // 四个数据源合并为一棵树:藏品类别、藏品年代、藏品标签、藏品级别(key 带前缀便于拆分为分类参数)
|
|
|
|
|
+ const treeData = useMemo(() => {
|
|
|
|
|
+ const rootCategory: TreeDataNode = {
|
|
|
|
|
+ key: 'root-类别',
|
|
|
|
|
+ title: '藏品类别',
|
|
|
|
|
+ children: loopToTreeNodes(categoryFiltered, 'type')
|
|
|
|
|
+ }
|
|
|
|
|
+ const rootAge: TreeDataNode = {
|
|
|
|
|
+ key: 'root-年代',
|
|
|
|
|
+ title: '藏品年代',
|
|
|
|
|
+ children: loopToTreeNodes(ageFiltered, 'age')
|
|
|
|
|
+ }
|
|
|
|
|
+ const rootTag: TreeDataNode = {
|
|
|
|
|
+ key: 'root-标签',
|
|
|
|
|
+ title: '藏品标签',
|
|
|
|
|
+ children: loopToTreeNodes(tagTreeFiltered, 'tag')
|
|
|
|
|
+ }
|
|
|
|
|
+ const rootLevel: TreeDataNode = {
|
|
|
|
|
+ key: 'root-级别',
|
|
|
|
|
+ title: '藏品级别',
|
|
|
|
|
+ children: levelFiltered.map((item: { value: string; label: string }) => ({
|
|
|
|
|
+ key: `level-${item.value}`,
|
|
|
|
|
+ title: item.label
|
|
|
|
|
+ }))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return [rootCategory, rootAge, rootTag, rootLevel]
|
|
|
|
|
+ }, [loopToTreeNodes, categoryFiltered, ageFiltered, tagTreeFiltered, levelFiltered])
|
|
|
|
|
+
|
|
|
|
|
+ // 根据勾选 key 列表解析为后端需要的分类参数字符串(逗号隔开)
|
|
|
|
|
+ const getExtraParamsFromKeys = useCallback((keyList: string[]) => {
|
|
|
|
|
+ const subTypeDictId = keyList.filter(k => k.startsWith('type-')).map(k => k.slice(5))
|
|
|
|
|
+ const subAgeDictId = keyList.filter(k => k.startsWith('age-')).map(k => k.slice(4))
|
|
|
|
|
+ const subTagIds = keyList.filter(k => k.startsWith('tag-')).map(k => k.slice(4))
|
|
|
|
|
+ const subLevel = keyList.filter(k => k.startsWith('level-')).map(k => k.slice(6))
|
|
|
|
|
+ return { subTypeDictId, subAgeDictId, subTagIds, subLevel }
|
|
|
|
|
+ }, [])
|
|
|
|
|
+
|
|
|
|
|
+ // 首次有树数据时默认全部选中
|
|
|
|
|
+ useEffect(() => {
|
|
|
|
|
+ if (!hasSetDefaultChecked.current && treeData?.length) {
|
|
|
|
|
+ const allKeys = getAllTreeKeys(treeData)
|
|
|
|
|
+ if (allKeys.length) {
|
|
|
|
|
+ setCheckedKeys(allKeys)
|
|
|
|
|
+ // 全选树的筛选条件按理等于查询全部,所以先不设置参数,避免多余请求,还是有差别,那还是多请求一次吧
|
|
|
|
|
+ setExtraParams(getExtraParamsFromKeys(allKeys))
|
|
|
|
|
+ hasSetDefaultChecked.current = true
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }, [treeData, getExtraParamsFromKeys, setExtraParams])
|
|
|
|
|
+
|
|
|
|
|
+ const onCheckNode = (keys: any) => {
|
|
|
|
|
+ const next = Array.isArray(keys) ? keys : (keys as { checked: React.Key[] }).checked
|
|
|
|
|
+ const keyList = (next as string[]).filter((k): k is string => typeof k === 'string')
|
|
|
|
|
+ setCheckedKeys(keyList)
|
|
|
|
|
+ setExtraParams(getExtraParamsFromKeys(keyList))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return (
|
|
|
|
|
+ <div className={styles.C2siderLeftTree}>
|
|
|
|
|
+ <div className='C2siderLeftTree1'>
|
|
|
|
|
+ <Input
|
|
|
|
|
+ style={{ width: 300 }}
|
|
|
|
|
+ placeholder='请输入节点名称'
|
|
|
|
|
+ maxLength={30}
|
|
|
|
|
+ showCount
|
|
|
|
|
+ value={value}
|
|
|
|
|
+ onChange={e => valueChange(e.target.value)}
|
|
|
|
|
+ allowClear
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div className='C2siderLeftTree2'>
|
|
|
|
|
+ {treeData?.length ? (
|
|
|
|
|
+ <Tree
|
|
|
|
|
+ checkable
|
|
|
|
|
+ defaultExpandAll={true}
|
|
|
|
|
+ treeData={treeData}
|
|
|
|
|
+ selectedKeys={[acShu]}
|
|
|
|
|
+ checkedKeys={checkedKeys}
|
|
|
|
|
+ onCheck={(keys, _info) => {
|
|
|
|
|
+ onCheckNode(keys)
|
|
|
|
|
+ }}
|
|
|
|
|
+ onSelect={onSelect}
|
|
|
|
|
+ />
|
|
|
|
|
+ ) : null}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ )
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
function C2routing() {
|
|
function C2routing() {
|
|
|
|
|
+ const tableInfo = useSelector((state: RootState) => state.C1ledger.tableInfo)
|
|
|
|
|
+ const [extraParams, setExtraParams] = useState<any>({})
|
|
|
|
|
+ // 故事管理/藏品总账定制右侧内容
|
|
|
|
|
+ const storyTableListToprr = ({
|
|
|
|
|
+ clickSearch,
|
|
|
|
|
+ resetSelectFu
|
|
|
|
|
+ }: {
|
|
|
|
|
+ clickSearch: () => void
|
|
|
|
|
+ resetSelectFu: () => void
|
|
|
|
|
+ }) => {
|
|
|
|
|
+ return (
|
|
|
|
|
+ <>
|
|
|
|
|
+ <Button type='primary' onClick={clickSearch}>
|
|
|
|
|
+ 查询
|
|
|
|
|
+ </Button>
|
|
|
|
|
+ <Button onClick={resetSelectFu}>重置</Button>
|
|
|
|
|
+ </>
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 故事管理/藏品总账定制右侧操作按钮
|
|
|
|
|
+ const storyTableLastBtn = useMemo(() => {
|
|
|
|
|
+ return [
|
|
|
|
|
+ {
|
|
|
|
|
+ title: '操作',
|
|
|
|
|
+ render: (item: any) => (
|
|
|
|
|
+ <Button size='small' type='text' onClick={() => openLink(`/goodsLook/${item.id}`)}>
|
|
|
|
|
+ 查看
|
|
|
|
|
+ </Button>
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ }, [])
|
|
|
|
|
+
|
|
|
return (
|
|
return (
|
|
|
<div className={styles.C2routing}>
|
|
<div className={styles.C2routing}>
|
|
|
<div className='pageTitle'>藏品分账</div>
|
|
<div className='pageTitle'>藏品分账</div>
|
|
|
|
|
+ <div className='sider'>
|
|
|
|
|
+ <div className='siderLeft'>
|
|
|
|
|
+ <C2siderLeftTree setExtraParams={setExtraParams} />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div className='siderRight'>
|
|
|
|
|
+ <TableList
|
|
|
|
|
+ baseFormData={C2baseFormData}
|
|
|
|
|
+ getListAPI={API_getGoodsList}
|
|
|
|
|
+ pageKey='routing'
|
|
|
|
|
+ tableInfo={tableInfo}
|
|
|
|
|
+ columnsTemp={C2columnsTempAdd}
|
|
|
|
|
+ rightBtnWidth={140}
|
|
|
|
|
+ leftRowWidth={'20%'}
|
|
|
|
|
+ yHeight={592}
|
|
|
|
|
+ searchDom={C2topSearch}
|
|
|
|
|
+ storyTableLastBtn={storyTableLastBtn}
|
|
|
|
|
+ storyTableListToprr={storyTableListToprr}
|
|
|
|
|
+ extraParams={extraParams}
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
)
|
|
)
|
|
|
}
|
|
}
|