collect-system/apps/web/src/app/main/devicepage/select/Device-manager.tsx

483 lines
14 KiB
TypeScript
Raw Normal View History

2025-05-20 10:29:13 +08:00
// apps/web/src/components/models/term/term-manager.tsx
import { Button, Input, Modal, Space, Table, TreeSelect, Select } from "antd";
import { api } from "@nice/client";
import { useState, useEffect } from "react";
import { PlusOutlined, EditOutlined, DeleteOutlined } from "@ant-design/icons";
import { ObjectType } from "@nice/common";
interface TermManagerProps {
title: string;
}
export default function DeviceManager({ title }: TermManagerProps) {
const [isModalVisible, setIsModalVisible] = useState(false);
const [editingTerm, setEditingTerm] = useState<any>(null);
const [termName, setTermName] = useState("");
const [parentId, setParentId] = useState<string | null>(null);
const [taxonomyId, setTaxonomyId] = useState<string | null>(null);
const [searchValue, setSearchValue] = useState("");
const [treeData, setTreeData] = useState<any[]>([]);
const [taxonomySelectDisabled, setTaxonomySelectDisabled] = useState(false);
// 获取所有taxonomy
const { data: taxonomies } = api.taxonomy.getAll.useQuery({
type: ObjectType.DEVICE,
});
// 获取所有故障类型taxonomy
// 故障网系类别taxonomy
const { data: systemTypeTaxonomy } = api.taxonomy.findBySlug.useQuery({
slug: "system_type",
});
// 故障类型taxonomy
const { data: deviceTypeTaxonomy } = api.taxonomy.findBySlug.useQuery({
slug: "device_type",
});
// 获取所有网系类别条目
const { data: systemTypeTerms, refetch: refetchSystemType } =
api.term.findMany.useQuery({
where: {
taxonomy: { slug: "system_type" },
deletedAt: null,
},
include: {
children: true,
},
orderBy: { order: "asc" },
});
// 获取所有故障类型条目
const { data: deviceTypeTerms, refetch: refetchDeviceType } =
api.term.findMany.useQuery({
where: {
taxonomy: { slug: "device_type" },
deletedAt: null,
},
include: {
children: true,
},
orderBy: { order: "asc" },
});
// 构建包含两种分类的树形数据
useEffect(() => {
if (systemTypeTerms && deviceTypeTerms) {
// 先获取顶级网系类别
const rootTerms = systemTypeTerms.filter((term) => !term.parentId);
// 构建树形数据
const buildTreeData = (items: any[]): any[] => {
return items.map((item) => {
// 找到与此网系类别关联的故障类型
const deviceChildren = deviceTypeTerms.filter(
(t) => t.parentId === item.id
);
// 为每个故障类型找到其子故障
const processedDeviceChildren = deviceChildren.map((deviceType) => {
const deviceItems = deviceTypeTerms.filter(
(t) => t.parentId === deviceType.id
);
return {
...deviceType,
key: deviceType.id,
children: deviceItems.map((device) => ({
...device,
key: device.id,
})),
};
});
return {
...item,
key: item.id,
children: processedDeviceChildren,
};
});
};
setTreeData(buildTreeData(rootTerms));
}
}, [systemTypeTerms, deviceTypeTerms]);
// 搜索过滤逻辑
useEffect(() => {
if (systemTypeTerms && deviceTypeTerms) {
if (!searchValue) {
// 重新构建完整的树形结构
const rootTerms = systemTypeTerms.filter((term) => !term.parentId);
const buildTreeData = (items: any[]): any[] => {
return items.map((item) => {
const deviceChildren = deviceTypeTerms.filter(
(t) => t.parentId === item.id
);
const processedDeviceChildren = deviceChildren.map((deviceType) => {
const deviceItems = deviceTypeTerms.filter(
(t) => t.parentId === deviceType.id
);
return {
...deviceType,
key: deviceType.id,
children: deviceItems.map((device) => ({
...device,
key: device.id,
})),
};
});
return {
...item,
key: item.id,
children: processedDeviceChildren,
};
});
};
setTreeData(buildTreeData(rootTerms));
} else {
// 搜索匹配所有项
const allTerms = [...systemTypeTerms, ...deviceTypeTerms];
const filtered = allTerms.filter((term) =>
term.name.toLowerCase().includes(searchValue.toLowerCase())
);
setTreeData(filtered.map((item) => ({ ...item, key: item.id })));
}
}
}, [systemTypeTerms, deviceTypeTerms, searchValue]);
const handleSearch = (value: string) => {
setSearchValue(value);
};
// API调用
const { mutate: createTerm } = api.term.create.useMutation({
onSuccess: () => {
refetchSystemType();
refetchDeviceType();
setIsModalVisible(false);
setTermName("");
setParentId(null);
setTaxonomyId(null);
},
});
const { mutate: updateTerm } = api.term.update.useMutation({
onSuccess: () => {
refetchSystemType();
refetchDeviceType();
setIsModalVisible(false);
setEditingTerm(null);
setTermName("");
setParentId(null);
setTaxonomyId(null);
},
});
const { mutate: softDeleteByIds } = api.term.softDeleteByIds.useMutation({
onSuccess: () => {
refetchSystemType();
refetchDeviceType();
},
});
// 操作处理函数
// 修改handleAdd函数
const handleAdd = (parentRecord?: any) => {
setEditingTerm(null);
setTermName("");
setParentId(parentRecord?.id || null);
refetchSystemType();
refetchDeviceType();
// 根据父记录类型自动选择taxonomy
if (parentRecord) {
// 如果父类是网系类别,则自动设置为故障类型
if (parentRecord.taxonomyId === systemTypeTaxonomy?.id) {
setTaxonomyId(deviceTypeTaxonomy?.id);
// 可以设置状态来禁用Select组件
setTaxonomySelectDisabled(true);
} else {
setTaxonomyId(parentRecord.taxonomyId);
setTaxonomySelectDisabled(false);
}
} else {
// 如果是顶级项,默认设为网系类别
setTaxonomyId(systemTypeTaxonomy?.id || null);
setTaxonomySelectDisabled(false);
}
setIsModalVisible(true);
};
const handleEdit = (term: any) => {
setEditingTerm(term);
setTermName(term.name);
setParentId(term.parentId);
setTaxonomyId(term.taxonomyId);
setIsModalVisible(true);
refetchSystemType();
refetchDeviceType();
};
const handleDelete = (term: any) => {
Modal.confirm({
title: "确认删除",
content: `确定要删除"${term.name}"吗?这将同时删除其下所有子项!`,
onOk: () => softDeleteByIds({ ids: [term.id] }),
});
refetchSystemType();
refetchDeviceType();
};
const handleSave = () => {
if (!termName.trim() || !taxonomyId) return;
if (editingTerm) {
updateTerm({
where: { id: editingTerm.id },
data: {
name: termName,
parentId: parentId,
hasChildren: editingTerm.hasChildren,
},
});
} else {
createTerm({
data: {
name: termName,
taxonomyId: taxonomyId,
parentId: parentId,
},
});
}
refetchSystemType();
refetchDeviceType();
};
// 构建父级选择器的选项
const getParentOptions = () => {
if (!systemTypeTerms || !deviceTypeTerms) return [];
const allTerms = [...systemTypeTerms, ...deviceTypeTerms];
// 根据编辑对象和当前选择的taxonomy过滤有效的父级选项
let validParents = allTerms;
// 如果是编辑现有项
if (editingTerm) {
// 递归查找所有子孙节点ID避免循环引用
const findAllDescendantIds = (itemId: string): string[] => {
const directChildren = allTerms.filter((t) => t.parentId === itemId);
const descendantIds = directChildren.map((c) => c.id);
directChildren.forEach((child) => {
const childDescendants = findAllDescendantIds(child.id);
descendantIds.push(...childDescendants);
});
return descendantIds;
};
const invalidIds = [
editingTerm.id,
...findAllDescendantIds(editingTerm.id),
];
validParents = allTerms.filter((t) => !invalidIds.includes(t.id));
}
// 如果是添加故障类型,只能选择网系类别作为父级
if (!editingTerm && taxonomyId === deviceTypeTaxonomy?.id) {
validParents = systemTypeTerms;
}
// 如果是添加具体故障,只能选择故障类型作为父级
if (
!editingTerm &&
taxonomyId &&
taxonomyId !== systemTypeTaxonomy?.id &&
taxonomyId !== deviceTypeTaxonomy?.id
) {
validParents = deviceTypeTerms;
}
// 转换为TreeSelect需要的格式
const buildTreeOptions = (items: any[], depth = 0): any[] => {
return items
.filter((item) => (depth === 0 ? !item.parentId : true))
.map((item) => {
const children = allTerms.filter((t) => t.parentId === item.id);
return {
title: "—".repeat(depth) + (depth > 0 ? " " : "") + item.name,
value: item.id,
children:
children.length > 0
? buildTreeOptions(children, depth + 1)
: undefined,
};
});
};
return buildTreeOptions(validParents);
};
return (
<div>
<div
style={{
display: "flex",
justifyContent: "flex-end",
marginBottom: 16,
alignItems: "center",
gap: "10px",
}}
>
<Input.Search
placeholder={`根据${title}搜索`}
onSearch={handleSearch}
onChange={(e) => handleSearch(e.target.value)}
value={searchValue}
style={{ width: 400 }}
allowClear
/>
<Button
type="primary"
icon={<PlusOutlined />}
onClick={() => handleAdd()}
>
{title}
</Button>
</div>
<Table
dataSource={treeData}
expandable={{
defaultExpandAllRows: true,
}}
columns={[
{
title: "名称",
dataIndex: "name",
key: "name",
},
{
title: "分类类型",
key: "taxonomyType",
render: (_, record) => {
if (record.taxonomyId === systemTypeTaxonomy?.id) {
return "网系类别";
} else if (record.taxonomyId === deviceTypeTaxonomy?.id) {
return "故障类型";
} else {
return "具体故障";
}
},
},
{
title: "操作",
key: "action",
width: 200,
render: (_, record: any) => (
<Space>
<Button
type="text"
icon={<PlusOutlined />}
onClick={() => handleAdd(record)}
style={{ color: "green" }}
>
</Button>
<Button
type="text"
icon={<EditOutlined />}
onClick={() => handleEdit(record)}
style={{ color: "#1890ff" }}
/>
<Button
type="text"
danger
icon={<DeleteOutlined />}
onClick={() => handleDelete(record)}
/>
</Space>
),
},
]}
rowKey="id"
pagination={false}
rowClassName={(record, index) =>
index % 2 === 0 ? "bg-white" : "bg-gray-100"
}
onHeaderRow={() => {
return {
style: {
backgroundColor: "#d6e4ff",
},
};
}}
bordered
size="middle"
locale={{ emptyText: "暂无数据" }}
/>
<Modal
title={editingTerm ? `编辑${title}` : `添加${title}`}
open={isModalVisible}
onOk={handleSave}
onCancel={() => setIsModalVisible(false)}
>
<div style={{ marginBottom: 16 }}>
<label style={{ display: "block", marginBottom: 8 }}></label>
<Input
placeholder={`请输入${title}名称`}
value={termName}
onChange={(e) => setTermName(e.target.value)}
/>
</div>
{!editingTerm && (
<div style={{ marginBottom: 16 }}>
<label style={{ display: "block", marginBottom: 8 }}>
</label>
<Select
style={{ width: "100%" }}
placeholder="请选择分类类型"
value={taxonomyId}
onChange={setTaxonomyId}
disabled={taxonomySelectDisabled}
options={taxonomies?.map((tax) => ({
label: tax.name,
value: tax.id,
}))}
/>
</div>
)}
<div>
<label style={{ display: "block", marginBottom: 8 }}>
</label>
<TreeSelect
style={{ width: "100%" }}
dropdownStyle={{ maxHeight: 400, overflow: "auto" }}
placeholder="请选择上级分类"
allowClear
treeDefaultExpandAll
value={parentId}
onChange={setParentId}
treeData={getParentOptions()}
/>
</div>
</Modal>
</div>
);
}