소스 검색

add: material classify

dev
powersir 1 년 전
부모
커밋
1950241f29
3개의 변경된 파일209개의 추가작업 그리고 2개의 파일을 삭제
  1. +205
    -0
      src/pages/custom/product/material/classify.tsx
  2. +2
    -0
      src/pages/custom/product/material/index.tsx
  3. +2
    -2
      src/request/service/material-classify.ts

+ 205
- 0
src/pages/custom/product/material/classify.tsx 파일 보기

@@ -0,0 +1,205 @@
import React, { useState, useEffect, useRef } from 'react';
import { Tree, Space, Input } from 'antd';
import type { InputRef } from 'antd';
import type { DataNode, TreeProps } from 'antd/es/tree';
import { t } from '@/utils/i18n';
import { DownOutlined, EditOutlined, DeleteOutlined, PlusOutlined, CheckOutlined, CloseOutlined } from '@ant-design/icons';
import { useRequest } from '@/hooks/use-request';
import { antdUtils } from '@/utils/antd';
import { MaterialClassifyVO } from '@/models';
import classifyService from '@/request/service/material-classify';
import { Key } from 'antd/lib/table/interface';

interface TreeDataNode extends DataNode {
parentId? : Key;
isNewNode: boolean
}

const convert2DataNode = (source: MaterialClassifyVO) => {
const node: TreeDataNode = {
title: source.classifyName,
key: source.id,
parentId: source.parentId??-1,
isNewNode: false
};
if (source.childrens && source.childrens.length > 0) {
node.children = source.childrens.map(it => convert2DataNode(it))
}
return node;
}

export default () => {
const { runAsync: getTreeApi } = useRequest(classifyService.getMaterialClassifyTreeApi, { manual: true });
const { runAsync: deleteApi } = useRequest(classifyService.deleteMaterialClassifyApi, { manual: true });
const { runAsync: updateApi } = useRequest(classifyService.updateMaterialClassifyApi, { manual: true });
const { runAsync: createApi } = useRequest(classifyService.createMaterialClassifyApi, { manual: true });

const [dataSource, setDataSource] = useState<TreeDataNode[]>([]);
const [selectedItem, setSelectedItem] = useState<Key | null>(null);
const [hoveredItem, setHoveredItem] = useState<Key | null>(null);
const [editItem, setEditItem] = useState<TreeDataNode | null>(null);
const [expandedKeys, setExpandedKeys] = useState<Key[]>([]);
const inputRef = useRef<InputRef>(null);
const [inputStatus, setInputStatus] = useState<"" | "error" | "warning">("");

const load = async () => {
const [error, { data }] = await getTreeApi();
if (!error) {
setDataSource([{
title: '全部素材',
key: -1,
isNewNode: false,
children: data.map(it => convert2DataNode(it))
}]);
}
};

const onSelect: TreeProps['onSelect'] = (selectedKeys) => {
if (selectedKeys.length > 0) {
setSelectedItem(selectedKeys[0]);
} else {
setSelectedItem(null);
}
};

const onHover = (node: TreeDataNode) => {
setHoveredItem(node.key);
}

useEffect(() => {
load();
}, []);

const onEdit = (node: TreeDataNode) => {
// 编辑节点title
onQuitEdit();
setEditItem(node);
};

const onAdd = (node: TreeDataNode) => {
// 新增子节点
if (!node.children) {
node.children = [];
}
const subNode: TreeDataNode = {
title: '新增分类',
key: new Date().getTime(),
parentId: node.key,
isNewNode: true
};
node.children?.push(subNode);
setDataSource([...dataSource]);
if (expandedKeys.indexOf(node.key) < 0) {
setExpandedKeys([...expandedKeys, node.key])
}
onQuitEdit();
setEditItem(subNode);
};

const filterNode: (nodes: TreeDataNode[], item: TreeDataNode) => TreeDataNode[] = (nodes: TreeDataNode[], item: TreeDataNode) => {
return nodes.filter(child => child.key !== item.key)
.map(child => {
if (child.children && child.children.length > 0) {
return { ...child, children: filterNode(child.children as TreeDataNode[] || [], item) }
} else {
return { ...child }
}
});
}
const onDelete = async (node: TreeDataNode) => {
// 删除子节点
if(!node.isNewNode) {
await deleteApi(node.key)
}
const newTreeData = filterNode(dataSource, node)
setDataSource(newTreeData);
};

const onSaveEditValue = async (node: TreeDataNode) => {
const newValue = inputRef.current?.input?.value;
const api = node.isNewNode ? createApi : updateApi;
const param = node.isNewNode? {
parentId: node.parentId??-1 < 0 ? 0 : node.parentId,
classifyName: inputRef.current?.input?.value
}: {
id: node.key as number,
classifyName: inputRef.current?.input?.value
}
const [error, { code, msg }] = await api(param);
if(!error && code === 0) {
node.title = newValue;
setEditItem(null);
} else {
antdUtils.message?.error(msg);
setInputStatus('error');
}
}

const onQuitEdit = () => {
if(editItem != null && editItem.isNewNode) {
onDelete(editItem);
}
setEditItem(null);
}

const shouldShowActions = (key: Key) => {
return key === selectedItem || key === hoveredItem;
};

const renderEditItem = (node: TreeDataNode) => {
return (
<Space>
<Input size='small' status={inputStatus} ref={inputRef} defaultValue={node.title as string} />
<CheckOutlined onClick={() => onSaveEditValue(node)} />
<CloseOutlined onClick={onQuitEdit} />
</Space>
)
}

const renderItem = (node: TreeDataNode) => {
return (<div className='flex'
onMouseEnter={() => { onHover(node) }}
onMouseLeave={() => { setHoveredItem(null) }}>
{
editItem?.key === node.key ? (renderEditItem(node)) : node.title as string
}
{
shouldShowActions(node.key) && editItem?.key !== node.key ? (<div className='ml-4'>
<Space>
<PlusOutlined onClick={() => onAdd(node)} />
{
node.key !== -1 ? (<>
<EditOutlined onClick={() => onEdit(node)} />
<DeleteOutlined onClick={() => onDelete(node)} />
</>) : null
}

</Space>
</div>) : null
}
</div>)
}

const onExpand: TreeProps['onExpand'] = (expandedKeys) => {
console.log(expandedKeys)
setExpandedKeys(expandedKeys)
}

return (
<>
<div>
<Tree
showLine
switcherIcon={<DownOutlined />}
onSelect={onSelect}
treeData={dataSource}
onExpand={onExpand}
expandedKeys={expandedKeys}
autoExpandParent={true}
titleRender={(node) => renderItem(node)}
>
</Tree>
</div>
</>
);
};

+ 2
- 0
src/pages/custom/product/material/index.tsx 파일 보기

@@ -7,6 +7,7 @@ import { t } from '@/utils/i18n';
import { PlusOutlined, ExclamationCircleFilled, DeleteOutlined, SearchOutlined } from '@ant-design/icons';
import { antdUtils } from '@/utils/antd';
import mData from '../../../../../mock/findMaterialPage.json'
import MaterialClassifyView from './classify';

const { Search } = Input;

@@ -311,6 +312,7 @@ const TablePage: React.FC = () => {
<>
<div className='flex flex-row'>
<Card className='basis-1/4 w-[100px] mb-[10px] dark:bg-[rgb(33,41,70)] bg-white roundle-lg px[12px]'>
<MaterialClassifyView/>
</Card>
<Card className='basis-3/4 mb-[10px] ml-[10px] dark:bg-[rgb(33,41,70)] bg-white roundle-lg px[12px]' bodyStyle={{
paddingTop: 0,


+ 2
- 2
src/request/service/material-classify.ts 파일 보기

@@ -1,5 +1,5 @@
import request from '@/request';
import { MaterialClassifyVO, MaterialClassifyPageReqVO, CategoryTreeVO, PageData } from '@/models';
import { MaterialClassifyVO, MaterialClassifyPageReqVO, PageData } from '@/models';

const BASE_URL = '/admin-api/material/classify';

@@ -23,7 +23,7 @@ export default {

// 获得所有素材分类(树结构)
getMaterialClassifyTreeApi: () => {
return request.get<CategoryTreeVO[]>(`${BASE_URL}/getMaterialClassifyAllTree`)
return request.get<MaterialClassifyVO[]>(`${BASE_URL}/getMaterialClassifyAllTree`)
},

// 查询素材分类详情


불러오는 중...
취소
저장