浩杰测试bug优化

This commit is contained in:
Li1304553726 2025-06-02 19:35:10 +08:00
parent 4f0183b6b9
commit 243696230a
4 changed files with 378 additions and 231 deletions

View File

@ -15,6 +15,7 @@ import {
ExclamationCircleOutlined, ExclamationCircleOutlined,
ImportOutlined, ImportOutlined,
ExportOutlined, ExportOutlined,
DatabaseOutlined,
} from "@ant-design/icons"; } from "@ant-design/icons";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { utils, writeFile, read } from "xlsx"; import { utils, writeFile, read } from "xlsx";
@ -89,13 +90,13 @@ const DeviceTable = forwardRef(
include: { children: true }, // 包含子级术语 include: { children: true }, // 包含子级术语
orderBy: { order: "asc" }, // 按排序字段升序 orderBy: { order: "asc" }, // 按排序字段升序
}); });
// 设备类型术语查询(用于类型名称转换) // 设备类型术语查询(用于类型名称转换)
const { data: deviceTypeTerms, refetch: refetchDeviceType } = const { data: deviceTypeTerms, refetch: refetchDeviceType } =
api.term.findMany.useQuery({ api.term.findMany.useQuery({
where: { taxonomy: { slug: "device_type" }, deletedAt: null }, // 筛选设备类型术语 where: { taxonomy: { slug: "device_type" }, deletedAt: null }, // 筛选设备类型术语
}); });
// 软删除设备的mutation方法通过ID批量删除 // 软删除设备的mutation方法通过ID批量删除
const { mutate: softDeleteByIds } = const { mutate: softDeleteByIds } =
api.device.softDeleteByIds.useMutation(); api.device.softDeleteByIds.useMutation();
@ -165,18 +166,22 @@ const DeviceTable = forwardRef(
dataIndex: "systemType", dataIndex: "systemType",
key: "systemType", key: "systemType",
align: "center", align: "center",
render: (text, record) => { render: (text, record) => (
return getTermNameById(record.systemType, "system_type"); <span className="inline-block bg-blue-50 text-blue-700 px-2 py-1 rounded text-sm border border-blue-200">
}, {getTermNameById(record.systemType, "system_type")}
</span>
),
}, },
{ {
title: "故障类型", title: "故障类型",
dataIndex: "deviceType", dataIndex: "deviceType",
key: "deviceType", key: "deviceType",
align: "center", align: "center",
render: (text, record) => { render: (text, record) => (
return getTermNameById(record.deviceType, "device_type"); <span className="inline-block bg-gray-50 text-gray-700 px-2 py-1 rounded text-sm border border-gray-200">
}, {getTermNameById(record.deviceType, "device_type")}
</span>
),
}, },
{ {
title: "单位", title: "单位",
@ -184,16 +189,15 @@ const DeviceTable = forwardRef(
key: "deptId", key: "deptId",
align: "center", align: "center",
render: (text, record) => { render: (text, record) => {
// 如果有部门关联,显示部门名称 const unitName =
if (record.deptId && (record as any)?.department?.name) { (record as any)?.department?.name ||
return (record as any)?.department?.name; record.responsiblePerson ||
} "未知";
// 否则显示responsiblePerson如果存在 return (
if (record.responsiblePerson) { <span className="inline-block bg-gray-50 text-gray-700 px-2 py-1 rounded text-sm border border-gray-200">
return record.responsiblePerson; {unitName}
} </span>
// 最后才显示未知 );
return "未知";
}, },
}, },
{ {
@ -204,14 +208,11 @@ const DeviceTable = forwardRef(
render: (text, record) => ( render: (text, record) => (
<div <div
onClick={() => handleShowDesc(record)} onClick={() => handleShowDesc(record)}
style={{ className="cursor-pointer p-2 bg-gray-50 hover:bg-blue-50 rounded border border-gray-200 hover:border-blue-300 transition-colors duration-200"
cursor: "pointer",
padding: "8px 0",
// backgroundColor: 'black',
fontWeight: "bold",
}}
> >
{text || "未命名故障"} <span className="font-medium text-gray-800 hover:text-blue-700">
{text || "未命名故障"}
</span>
</div> </div>
), ),
}, },
@ -224,30 +225,29 @@ const DeviceTable = forwardRef(
const statusConfig = { const statusConfig = {
normal: { normal: {
text: "已修复", text: "已修复",
color: "success", className: "bg-green-100 text-green-800 border-green-200",
}, },
maintenance: { maintenance: {
text: "维修中", text: "维修中",
color: "processing", className: "bg-blue-100 text-blue-800 border-blue-200",
}, },
broken: { broken: {
text: "未修复", text: "未修复",
color: "error", className: "bg-red-100 text-red-800 border-red-200",
}, },
}; };
const config = statusConfig[status] || { const config = statusConfig[status] || {
text: "未知", text: "未知",
color: "default", className: "bg-gray-100 text-gray-800 border-gray-200",
}; };
return ( return (
<Tag <span
color={config.color} className={`inline-block px-3 py-1 rounded-full text-sm font-medium border ${config.className}`}
style={{ minWidth: "60px", textAlign: "center" }}
> >
{config.text} {config.text}
</Tag> </span>
); );
}, },
}, },
@ -256,25 +256,30 @@ const DeviceTable = forwardRef(
dataIndex: "createdAt", dataIndex: "createdAt",
key: "createdAt", key: "createdAt",
align: "center", align: "center",
render: (text, record) => render: (text, record) => (
record.createdAt <span className="text-gray-600 text-sm">
? dayjs(record.createdAt).format("YYYY-MM-DD HH:mm:ss") {record.createdAt
: "未知", ? dayjs(record.createdAt).format("YYYY-MM-DD HH:mm:ss")
: "未知"}
</span>
),
}, },
{ {
title: "操作", title: "操作",
key: "action", key: "action",
align: "center", align: "center",
render: (_, record) => ( render: (_, record) => (
<div className="flex space-x-2 justify-center"> <div className="flex gap-2 justify-center">
<Button <Button
type="primary" type="primary"
key={record.id} key={record.id}
onClick={() => handleEdit(record)} onClick={() => handleEdit(record)}
className="bg-blue-600 hover:bg-blue-700 border-blue-600"
size="small"
> >
</Button> </Button>
<Button danger onClick={() => handleDelete(record)}> <Button danger onClick={() => handleDelete(record)} size="small">
</Button> </Button>
</div> </div>
@ -503,7 +508,7 @@ const DeviceTable = forwardRef(
: "单位名称", : "单位名称",
: "示例故障名称", : "示例故障名称",
: "未修复", // 可选值:已修复, 维修中, 未修复 : "未修复", // 可选值:已修复, 维修中, 未修复
: "这是一个示例描述", : "示例描述",
}, },
]; ];
@ -530,7 +535,7 @@ const DeviceTable = forwardRef(
const rowSelection = { const rowSelection = {
selectedRowKeys, selectedRowKeys,
onChange: onSelectChange, onChange: onSelectChange,
columnWidth: 70, columnWidth: 60,
columnTitle: ( columnTitle: (
<div className="flex items-center justify-center"> <div className="flex items-center justify-center">
<Checkbox <Checkbox
@ -550,16 +555,28 @@ const DeviceTable = forwardRef(
onSelectChange(newSelectedRowKeys, checked ? devices : []); onSelectChange(newSelectedRowKeys, checked ? devices : []);
}} }}
/> />
<span className="ml-1.5 text-xs whitespace-nowrap"></span> <span className="ml-1 text-xs text-gray-600 whitespace-nowrap items-center">
</span>
</div> </div>
), ),
preserveSelectedRowKeys: true, // 这个属性保证翻页时选中状态不丢失 preserveSelectedRowKeys: true,
}; };
const TableHeader = () => ( const TableHeader = () => (
<div className="w-full flex justify-between mb-2"> <div className="w-full flex justify-between items-center mb-4 p-4 bg-gray-50 rounded-lg border border-gray-200">
<span></span> <div className="flex items-center gap-3">
<div className="flex space-x-2"> <div className="w-8 h-8 bg-blue-600 rounded-lg flex items-center justify-center">
<DatabaseOutlined className="text-white text-sm" />
</div>
<div>
<h3 className="font-medium text-gray-800 mb-0"></h3>
<p className="text-sm text-gray-500">
{devices?.length ? `${devices.length} 条记录` : "暂无数据"}
</p>
</div>
</div>
<div className="flex items-center gap-2">
<input <input
type="file" type="file"
ref={uploadRef} ref={uploadRef}
@ -569,34 +586,40 @@ const DeviceTable = forwardRef(
/> />
<Button <Button
icon={<ImportOutlined />} icon={<ImportOutlined />}
type="primary"
onClick={handleExportTemplate} onClick={handleExportTemplate}
className="border-gray-300 hover:border-blue-500 hover:text-blue-600"
size="small"
> >
</Button> </Button>
<Button <Button
icon={<ImportOutlined />} icon={<ImportOutlined />}
type="primary"
onClick={handleImportClick} onClick={handleImportClick}
className="border-gray-300 hover:border-green-500 hover:text-green-600"
size="small"
> >
</Button> </Button>
<Button <Button
type="primary"
onClick={handleExportSelected} onClick={handleExportSelected}
disabled={!selectedRowKeys || selectedRowKeys.length === 0} disabled={!selectedRowKeys || selectedRowKeys.length === 0}
icon={<ExportOutlined />} icon={<ExportOutlined />}
type={selectedRowKeys?.length > 0 ? "primary" : "default"}
className={
selectedRowKeys?.length > 0 ? "bg-blue-600 hover:bg-blue-700" : ""
}
size="small"
> >
{selectedRowKeys?.length > 0 {selectedRowKeys?.length > 0
? `导出 (${selectedRowKeys.length})项数据` ? `导出 (${selectedRowKeys.length})`
: "导出选中数据"} : "导出选中"}
</Button> </Button>
</div> </div>
</div> </div>
); );
return ( return (
<> <div className="space-y-4">
<TableHeader /> <TableHeader />
<Table <Table
rowSelection={rowSelection} rowSelection={rowSelection}
@ -606,57 +629,52 @@ const DeviceTable = forwardRef(
size="middle" size="middle"
tableLayout="fixed" tableLayout="fixed"
rowClassName={(record, index) => rowClassName={(record, index) =>
index % 2 === 0 `${
? "bg-white hover:bg-blue-100" index % 2 === 0
: "bg-gray-100 hover:bg-blue-100" ? "bg-white hover:bg-blue-50"
: "bg-gray-50 hover:bg-blue-50"
} transition-colors duration-200`
} }
onRow={(record) => { onRow={(record) => ({
return { style: { cursor: "pointer" },
style: { cursor: "pointer" }, })}
onMouseEnter: () => {}, onHeaderRow={() => ({
}; style: {
}} backgroundColor: "#f8fafc",
onHeaderRow={() => { },
return { })}
style: {
backgroundColor: "#d6e4ff",
},
};
}}
scroll={{ x: "max-content" }} scroll={{ x: "max-content" }}
pagination={{ pagination={{
position: ["bottomCenter"], position: ["bottomCenter"],
className: "flex justify-center mt-4", className: "mt-4",
pageSize: pageSize, pageSize: pageSize,
current: currentPage, current: currentPage,
showSizeChanger: true, showSizeChanger: true,
pageSizeOptions: ["10", "15", "20"], pageSizeOptions: ["10", "15", "20"],
responsive: true, responsive: true,
showTotal: (total, range) => `${total} 条数据`, showTotal: (total, range) => (
<span className="text-gray-600">
{range[0]}-{range[1]} {total}
</span>
),
showQuickJumper: true, showQuickJumper: true,
onChange: handlePageChange, onChange: handlePageChange,
onShowSizeChange: handlePageSizeChange, onShowSizeChange: handlePageSizeChange,
}} }}
components={{
header: {
cell: (props) => (
<th
{...props}
style={{
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
textAlign: "center",
}}
/>
),
},
}}
bordered bordered
className="device-table-no-wrap" className="bg-white rounded-lg shadow-sm"
/> />
{/* 简化的模态框 */}
<Modal <Modal
title={currentDesc.title} title={
<div className="flex items-center gap-2">
<DatabaseOutlined className="text-blue-600" />
<span className="text-lg font-medium text-gray-800">
{currentDesc.title}
</span>
</div>
}
open={descModalVisible} open={descModalVisible}
onCancel={() => setDescModalVisible(false)} onCancel={() => setDescModalVisible(false)}
footer={[ footer={[
@ -664,22 +682,33 @@ const DeviceTable = forwardRef(
</Button>, </Button>,
]} ]}
width={800}
> >
<div className="py-4"> <div className="py-4 space-y-4">
<div className="text-lg font-medium mb-2"></div> <div>
<div className="bg-gray-50 p-4 rounded-md whitespace-pre-wrap"> <div className="text-base font-medium mb-3 text-gray-800">
{currentDesc.desc}
</div>
<div className="bg-gray-50 p-4 rounded-lg border border-gray-200">
<div className="text-gray-700 whitespace-pre-wrap leading-relaxed">
{currentDesc.desc}
</div>
</div>
</div> </div>
{/* 添加附件展示区域 */}
{currentDesc?.id && ( {currentDesc?.id && (
<div className="mt-4"> <div>
<div className="text-lg font-medium mb-2"></div> <div className="text-base font-medium mb-3 text-gray-800">
<ResourceFileList deviceId={currentDesc.id} />
</div>
<div className="bg-white p-4 rounded-lg border border-gray-200">
<ResourceFileList deviceId={currentDesc.id} />
</div>
</div> </div>
)} )}
</div> </div>
</Modal> </Modal>
</> </div>
); );
} }
); );

View File

@ -10,6 +10,10 @@ import {
Tag, Tag,
Dropdown, Dropdown,
Space, Space,
Card,
Row,
Col,
Typography,
} from "antd"; } from "antd";
import { useCallback, useEffect, useState, useRef } from "react"; import { useCallback, useEffect, useState, useRef } from "react";
import _ from "lodash"; import _ from "lodash";
@ -27,6 +31,8 @@ import {
DownOutlined, DownOutlined,
HistoryOutlined, HistoryOutlined,
CloseOutlined, CloseOutlined,
FilterOutlined,
DatabaseOutlined,
} from "@ant-design/icons"; } from "@ant-design/icons";
import DepartmentSelect from "@web/src/components/models/department/department-select"; import DepartmentSelect from "@web/src/components/models/department/department-select";
import SystemTypeSelect from "@web/src/app/main/devicepage/select/System-select"; import SystemTypeSelect from "@web/src/app/main/devicepage/select/System-select";
@ -36,7 +42,7 @@ import FixTypeSelect from "./select/Fix-select";
import { api } from "@nice/client"; import { api } from "@nice/client";
const { RangePicker } = DatePicker; const { RangePicker } = DatePicker;
const { Title } = Typography;
// 添加筛选条件类型 // 添加筛选条件类型
type SearchCondition = { type SearchCondition = {
deletedAt: null; deletedAt: null;
@ -378,112 +384,199 @@ export default function DeviceMessage() {
]; ];
return ( return (
<div className="p-2 min-h-screen bg-white"> <div className="min-h-screen bg-gray-50 p-4">
<div className="flex justify-between items-center mb-4"> {/* 页面标题区域 */}
<h1 className="text-xl font-normal"></h1> <div className="mb-6">
<div className="flex items-center gap-2 justify-end"> <Card className="shadow-sm border border-gray-200">
<Dropdown <div className="flex justify-between items-center">
menu={{ items: historyMenuItems }} <div className="flex items-center gap-3">
trigger={["click"]} <div className="w-10 h-10 bg-blue-600 rounded-lg flex items-center justify-center">
open={showHistory} <DatabaseOutlined className="text-lg text-white" />
onOpenChange={setShowHistory} </div>
placement="bottomRight" <div>
> <Title level={3} className="!mb-0 text-gray-800">
<Button icon={<HistoryOutlined />} title="搜索历史">
</Title>
</Button> <p className="text-gray-500 text-sm mt-1">
</Dropdown>
<Button type="primary" icon={<PlusOutlined />} onClick={handleNew}> </p>
</div>
</Button> </div>
</div> <div className="flex items-center gap-3">
</div> <Dropdown
menu={{ items: historyMenuItems }}
<div className="flex flex-wrap items-center gap-2 mb-4"> trigger={["click"]}
<div className="flex-1 min-w-[200px]"> open={showHistory}
<SystemTypeSelect onOpenChange={setShowHistory}
value={selectedSystem} placement="bottomRight"
onChange={setSelectedSystem}
placeholder="选择网系类别"
className="w-full"
/>
</div>
<div className="flex-1 min-w-[200px]">
<DeviceTypeSelect
value={selectedDeviceType}
onChange={setSelectedDeviceType}
placeholder="选择故障类型"
className="w-full"
systemTypeId={selectedSystemTypeId}
/>
</div>
<div className="flex-1 min-w-[200px]">
<FixTypeSelect
value={selectedFixType}
onChange={setSelectedFixType}
placeholder="选择故障状态"
className="w-full"
/>
</div>
<div className="flex-1 min-w-[200px]">
<DepartmentSelect
placeholder="单位"
className="w-full"
value={selectedDept}
onChange={handleDeptChange}
/>
</div>
<div className="flex-1 min-w-[250px]">
<RangePicker
placeholder={["开始日期", "结束日期"]}
className="w-full"
value={dateRange}
onChange={(dates) => setDateRange(dates)}
format="YYYY-MM-DD"
allowClear
/>
</div>
<Button type="primary" icon={<SearchOutlined />} onClick={handleSearch}>
</Button>
<Button icon={<ReloadOutlined />} onClick={handleReset}>
</Button>
</div>
{/* 显示当前搜索历史标签 */}
{searchHistory.length > 0 && (
<div className="mb-4 flex items-center gap-3 p-3 bg-gray-50 rounded-lg border border-gray-200">
<div className="text-sm font-medium text-gray-700 whitespace-nowrap">
:
</div>
<div className="flex flex-wrap gap-2 flex-1 min-w-0">
{searchHistory.slice(0, 5).map((history) => (
<Tag
key={history.id}
className="cursor-pointer hover:bg-blue-50 transition-colors duration-200 border-blue-200 text-blue-700"
onClick={() => applyHistorySearch(history)}
closable
onClose={(e) => {
e.preventDefault();
removeSearchHistory(history.id, e as any);
}}
> >
<span className="text-xs"> <Button
{history.label.length > 25 icon={<HistoryOutlined />}
? `${history.label.substring(0, 25)}...` className="border-gray-300 hover:border-blue-500 hover:text-blue-600"
: history.label} >
</span>
</Tag> </Button>
))} </Dropdown>
<Button
type="primary"
icon={<PlusOutlined />}
onClick={handleNew}
className="bg-blue-600 hover:bg-blue-700 border-blue-600"
>
</Button>
</div>
</div> </div>
</div> </Card>
)} </div>
<div> {/* 搜索筛选区域 */}
<Card className="mb-6 shadow-sm border border-gray-200">
<div className="mb-4">
<div className="flex items-center gap-2 mb-4">
<FilterOutlined className="text-gray-600" />
<span className="font-medium text-gray-700"></span>
</div>
<Row gutter={[16, 16]}>
<Col xs={24} sm={12} md={8} lg={6}>
<div className="space-y-2">
<label className="text-sm font-medium text-gray-600">
</label>
<SystemTypeSelect
value={selectedSystem}
onChange={(value) => {
setSelectedSystem(value);
setSelectedSystemTypeId(value || ""); // 同步更新
setSelectedDeviceType(null); // 清空故障类型选择
}}
placeholder="选择网系类别"
className="w-full"
/>
</div>
</Col>
<Col xs={24} sm={12} md={8} lg={6}>
<div className="space-y-2">
<label className="text-sm font-medium text-gray-600">
</label>
<DeviceTypeSelect
value={selectedDeviceType}
onChange={setSelectedDeviceType}
placeholder="选择故障类型"
className="w-full"
systemTypeId={selectedSystemTypeId}
/>
</div>
</Col>
<Col xs={24} sm={12} md={8} lg={6}>
<div className="space-y-2">
<label className="text-sm font-medium text-gray-600">
</label>
<FixTypeSelect
value={selectedFixType}
onChange={setSelectedFixType}
placeholder="选择故障状态"
className="w-full"
/>
</div>
</Col>
<Col xs={24} sm={12} md={8} lg={6}>
<div className="space-y-2">
<label className="text-sm font-medium text-gray-600">
</label>
<DepartmentSelect
placeholder="选择单位"
className="w-full"
value={selectedDept}
onChange={handleDeptChange}
/>
</div>
</Col>
<Col xs={24} sm={12} md={16} lg={12}>
<div className="space-y-2">
<label className="text-sm font-medium text-gray-600">
</label>
<RangePicker
placeholder={["开始日期", "结束日期"]}
className="w-full"
value={dateRange}
onChange={(dates) => setDateRange(dates)}
format="YYYY-MM-DD"
allowClear
/>
</div>
</Col>
<Col xs={24} sm={12} md={8} lg={6}>
<div className="space-y-2">
<label className="text-sm font-medium text-gray-600 opacity-0">
</label>
<div className="flex gap-2">
<Button
type="primary"
icon={<SearchOutlined />}
onClick={handleSearch}
className="bg-blue-600 hover:bg-blue-700 border-blue-600"
block
>
</Button>
<Button
icon={<ReloadOutlined />}
onClick={handleReset}
className="border-gray-300 hover:border-gray-400"
>
</Button>
</div>
</div>
</Col>
</Row>
</div>
{/* 搜索历史标签 */}
{searchHistory.length > 0 && (
<div className="mt-4 p-4 bg-gray-50 rounded-lg border border-gray-200">
<div className="flex items-center gap-3 mb-3">
<HistoryOutlined className="text-gray-600" />
<span className="text-sm font-medium text-gray-700">
</span>
</div>
<div className="flex flex-wrap gap-2">
{searchHistory.slice(0, 5).map((history) => (
<Tag
key={history.id}
className="cursor-pointer bg-white border-gray-300 text-gray-700 hover:bg-gray-50 hover:border-blue-400 hover:text-blue-600 transition-colors duration-200"
onClick={() => applyHistorySearch(history)}
closable
onClose={(e) => {
e.preventDefault();
removeSearchHistory(history.id, e as any);
}}
>
<span className="text-xs">
{history.label.length > 25
? `${history.label.substring(0, 25)}...`
: history.label}
</span>
</Tag>
))}
</div>
</div>
)}
</Card>
{/* 表格区域 */}
<Card className="shadow-sm border border-gray-200">
<DeviceTable ref={tableRef} onSelectedChange={handleSelectedChange} /> <DeviceTable ref={tableRef} onSelectedChange={handleSelectedChange} />
<DeviceModal /> <DeviceModal />
</div> </Card>
</div> </div>
); );
} }

View File

@ -87,15 +87,15 @@ export default function DeviceManager({ title }: TermManagerProps) {
orderBy: { order: "asc" }, orderBy: { order: "asc" },
}); });
const handlePageChange = (page: number, size: number) => { const handlePageChange = (page: number, size: number) => {
setCurrentPage(page); setCurrentPage(page);
setPageSize(size); setPageSize(size);
}; };
const handlePageSizeChange = (current: number, size: number) => { const handlePageSizeChange = (current: number, size: number) => {
setCurrentPage(1); // 重置到第一页 setCurrentPage(1); // 重置到第一页
setPageSize(size); setPageSize(size);
}; };
// 构建包含两种分类的树形数据 // 构建包含两种分类的树形数据
useEffect(() => { useEffect(() => {
if (systemTypeTerms && deviceTypeTerms) { if (systemTypeTerms && deviceTypeTerms) {
@ -261,14 +261,18 @@ export default function DeviceManager({ title }: TermManagerProps) {
Modal.confirm({ Modal.confirm({
title: "确认删除", title: "确认删除",
content: `确定要删除"${term.name}"吗?这将同时删除其下所有子项!`, content: `确定要删除"${term.name}"吗?这将同时删除其下所有子项!`,
onOk: () => softDeleteByIds({ ids: [term.id] },{ onOk: () =>
onSuccess: () => { softDeleteByIds(
message.success("删除成功"); { ids: [term.id] },
}, {
onError: () => { onSuccess: () => {
message.error("删除失败"); message.success("删除成功");
}, },
}), onError: () => {
message.error("删除失败");
},
}
),
}); });
refetchSystemType(); refetchSystemType();
refetchDeviceType(); refetchDeviceType();
@ -277,6 +281,12 @@ export default function DeviceManager({ title }: TermManagerProps) {
const handleSave = () => { const handleSave = () => {
if (!termName.trim() || !taxonomyId) return; if (!termName.trim() || !taxonomyId) return;
// 如果是故障类型,上级分类为必填
if (taxonomyId === deviceTypeTaxonomy?.id && !parentId) {
message.error("故障类型必须选择上级分类(网系类别)");
return;
}
if (editingTerm) { if (editingTerm) {
updateTerm({ updateTerm({
where: { id: editingTerm.id }, where: { id: editingTerm.id },
@ -371,7 +381,7 @@ export default function DeviceManager({ title }: TermManagerProps) {
<div className="p-6 min-h-screen bg-gray-50"> <div className="p-6 min-h-screen bg-gray-50">
{/* 主要内容卡片 */} {/* 主要内容卡片 */}
<Card className="shadow-sm" bodyStyle={{ padding: 0 }}> <Card className="shadow-sm" bodyStyle={{ padding: 0 }}>
{/* 统计信息区域 */} {/* 统计信息区域 */}
<div className="p-4 bg-gray-50 border-b border-gray-100"> <div className="p-4 bg-gray-50 border-b border-gray-100">
<Row gutter={16} justify="center"> <Row gutter={16} justify="center">
<Col span={8}> <Col span={8}>
@ -395,15 +405,15 @@ export default function DeviceManager({ title }: TermManagerProps) {
</div> </div>
</Col> </Col>
{/* <Col span={8}> */} {/* <Col span={8}> */}
{/* <div className="text-center"> */} {/* <div className="text-center"> */}
{/* <div className="text-2xl font-bold text-orange-600"> {/* <div className="text-2xl font-bold text-orange-600">
{deviceTypeTerms?.filter(term => {deviceTypeTerms?.filter(term =>
!systemTypeTerms?.some(sysType => sysType.id === term.parentId) && !systemTypeTerms?.some(sysType => sysType.id === term.parentId) &&
deviceTypeTerms?.some(devType => devType.id === term.parentId) deviceTypeTerms?.some(devType => devType.id === term.parentId)
).length || 0} ).length || 0}
</div> </div>
<div className="text-sm text-gray-600"></div> */} <div className="text-sm text-gray-600"></div> */}
{/* </div> {/* </div>
</Col> */} </Col> */}
</Row> </Row>
</div> </div>
@ -438,8 +448,6 @@ export default function DeviceManager({ title }: TermManagerProps) {
</Row> </Row>
</div> </div>
{/* 表格区域 */} {/* 表格区域 */}
<div className="p-4"> <div className="p-4">
<Table <Table
@ -455,7 +463,7 @@ export default function DeviceManager({ title }: TermManagerProps) {
dataIndex: "name", dataIndex: "name",
key: "name", key: "name",
width: "50%", // 增加名称列的宽度 width: "50%", // 增加名称列的宽度
render: (text, record, index, ) => ( render: (text, record, index) => (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
{/* 根据层级添加不同的图标 */} {/* 根据层级添加不同的图标 */}
{record.taxonomyId === systemTypeTaxonomy?.id ? ( {record.taxonomyId === systemTypeTaxonomy?.id ? (
@ -537,7 +545,7 @@ export default function DeviceManager({ title }: TermManagerProps) {
showSizeChanger: true, showSizeChanger: true,
showQuickJumper: true, showQuickJumper: true,
showTotal: (total) => `${total} 条记录`, showTotal: (total) => `${total} 条记录`,
pageSizeOptions: [ "10", "15", "20"], pageSizeOptions: ["10", "15", "20"],
onChange: handlePageChange, onChange: handlePageChange,
onShowSizeChange: handlePageSizeChange, onShowSizeChange: handlePageSizeChange,
}} }}
@ -546,8 +554,8 @@ export default function DeviceManager({ title }: TermManagerProps) {
record.taxonomyId === systemTypeTaxonomy?.id record.taxonomyId === systemTypeTaxonomy?.id
? "bg-blue-25" ? "bg-blue-25"
: record.taxonomyId === deviceTypeTaxonomy?.id : record.taxonomyId === deviceTypeTaxonomy?.id
? "bg-green-25" ? "bg-green-25"
: "bg-orange-25" : "bg-orange-25"
}` }`
} }
onHeaderRow={() => ({ onHeaderRow={() => ({
@ -621,11 +629,27 @@ export default function DeviceManager({ title }: TermManagerProps) {
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">
{/* 根据分类类型动态显示是否必填 */}
{taxonomyId === deviceTypeTaxonomy?.id && (
<span className="text-red-500">*</span>
)}
{/* 当选择故障类型时显示提示信息 */}
{taxonomyId === deviceTypeTaxonomy?.id && (
<div className="text-xs text-gray-500 mt-1 flex">
</div>
)}
</label> </label>
<TreeSelect <TreeSelect
style={{ width: "100%" }} style={{ width: "100%" }}
dropdownStyle={{ maxHeight: 400, overflow: "auto" }} dropdownStyle={{ maxHeight: 400, overflow: "auto" }}
placeholder="请选择上级分类(可选)" placeholder={
taxonomyId === systemTypeTaxonomy?.id
? "请选择上级网系(可选)"
: taxonomyId === deviceTypeTaxonomy?.id
? "请选择上级网系类别(必选)"
: "请选择上级分类(可选)"
}
allowClear allowClear
treeDefaultExpandAll treeDefaultExpandAll
value={parentId} value={parentId}
@ -633,6 +657,7 @@ export default function DeviceManager({ title }: TermManagerProps) {
treeData={getParentOptions()} treeData={getParentOptions()}
size="large" size="large"
/> />
</div> </div>
</div> </div>
</Modal> </Modal>

View File

@ -76,10 +76,10 @@ export default function DeviceTypeSelect({
// 查找所有与该网系类别直接相关的故障类型 // 查找所有与该网系类别直接相关的故障类型
const relatedDeviceTypes = allDeviceTypes.filter( const relatedDeviceTypes = allDeviceTypes.filter(
(device) => // (device) =>
childrenIds.includes(device.id) || device.parentId === systemTypeId // childrenIds.includes(device.id) || device.parentId === systemTypeId
(device) => device.parentId === systemTypeId
); );
console.log("已选系统:", systemTerm.name); console.log("已选系统:", systemTerm.name);
console.log("相关故障类型数量:", relatedDeviceTypes.length); console.log("相关故障类型数量:", relatedDeviceTypes.length);