Files
TJWaterServer/src/app/OlMap/Controls/PropertyPanel.tsx

235 lines
8.5 KiB
TypeScript

import React from "react";
interface BaseProperty {
label: string;
value: string | number;
unit?: string;
formatter?: (value: string | number) => string;
}
// 新增:表格型属性(用于二级数据)
interface TableProperty {
type: "table";
label: string;
columns: string[]; // 表头
rows: (string | number)[][]; // 每行的数据
}
type PropertyItem = BaseProperty | TableProperty;
interface PropertyPanelProps {
id?: string;
type?: string;
properties?: PropertyItem[];
}
const PropertyPanel: React.FC<PropertyPanelProps> = ({
id,
type = "未知类型",
properties = [],
}) => {
const formatValue = (property: BaseProperty) => {
if (property.formatter) {
return property.formatter(property.value);
}
if (property.unit) {
return `${property.value} ${property.unit}`;
}
return property.value;
};
const isImportantKeys = ["ID", "类型", "Name", "面积", "长度"];
// 统计属性数量(表格型按行数计入)
const totalProps = id
? 2 +
properties.reduce((sum, p) => {
if ("type" in p && p.type === "table") return sum + p.rows.length;
return sum + 1;
}, 0)
: 0;
return (
<div className="absolute top-4 right-4 bg-white shadow-2xl rounded-xl overflow-hidden w-96 max-h-[850px] flex flex-col backdrop-blur-sm z-1300 opacity-95 hover:opacity-100 transition-all duration-300 ">
{/* 头部 */}
<div className="flex justify-between items-center px-5 py-4 bg-[#257DD4] text-white">
<div className="flex items-center gap-2">
<svg
className="w-5 h-5"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
/>
</svg>
<h3 className="text-lg font-semibold"></h3>
</div>
</div>
{/* 内容区域 */}
<div className="flex-1 overflow-y-auto px-4 py-3">
{!id ? (
<div className="flex flex-col items-center justify-center py-12 text-gray-400">
<svg
className="w-16 h-16 mb-3"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.5}
d="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4"
/>
</svg>
<p className="text-sm"></p>
<p className="text-xs mt-1"></p>
</div>
) : (
<div className="space-y-2">
{/* ID 属性 */}
<div className="group rounded-lg p-3 transition-all duration-200 bg-blue-50 hover:bg-blue-100 border-l-4 border-blue-500">
<div className="flex justify-between items-start gap-3">
<span className="font-medium text-xs uppercase tracking-wide text-blue-700">
ID
</span>
<span className="text-sm font-semibold text-right flex-1 text-blue-900">
{id}
</span>
</div>
</div>
{/* 类型属性 */}
<div className="group rounded-lg p-3 transition-all duration-200 bg-blue-50 hover:bg-blue-100 border-l-4 border-blue-500">
<div className="flex justify-between items-start gap-3">
<span className="font-medium text-xs uppercase tracking-wide text-blue-700">
</span>
<span className="text-sm font-semibold text-right flex-1 text-blue-900">
{type}
</span>
</div>
</div>
{/* 其他属性(包含二级表格) */}
{properties.map((property, index) => {
// 二级表格
if ("type" in property && property.type === "table") {
return (
<div
key={`table-${index}`}
className="group rounded-lg p-3 transition-all duration-200 bg-gray-50 hover:bg-gray-100"
>
<div className="flex justify-between items-start gap-3">
<span className="font-medium text-xs uppercase tracking-wide text-gray-600">
{property.label}
</span>
</div>
<div className="ml-4 mt-2 border border-gray-300 rounded-md overflow-hidden shadow-sm">
<table className="w-full text-xs">
<thead className="bg-gray-200 text-gray-700">
<tr>
{property.columns.map((col, ci) => (
<th
key={ci}
className="px-3 py-2 text-left font-semibold"
>
{col}
</th>
))}
</tr>
</thead>
<tbody className="divide-y divide-gray-300">
{property.rows.map((row, ri) => (
<tr key={ri} className="bg-white hover:bg-gray-50">
{row.map((cell, cci) => (
<td
key={cci}
className="px-3 py-2 text-gray-800"
>
{cell}
</td>
))}
</tr>
))}
</tbody>
</table>
</div>
</div>
);
}
// 普通属性
const base = property as BaseProperty;
const isImportant = isImportantKeys.includes(base.label);
return (
<div
key={`prop-${index}`}
className={`group rounded-lg p-3 transition-all duration-200 ${
isImportant
? "bg-blue-50 hover:bg-blue-100 border-l-4 border-blue-500"
: "bg-gray-50 hover:bg-gray-100"
}`}
>
<div className="flex justify-between items-start gap-3">
<span
className={`font-medium text-xs uppercase tracking-wide ${
isImportant ? "text-blue-700" : "text-gray-600"
}`}
>
{base.label}
</span>
<span
className={`text-sm font-semibold text-right flex-1 ${
isImportant ? "text-blue-900" : "text-gray-800"
}`}
>
{formatValue(base)}
</span>
</div>
</div>
);
})}
</div>
)}
</div>
{/* 底部统计区域 */}
<div className="px-5 py-3 bg-gray-50 border-t border-gray-200">
<div className="flex items-center justify-between text-xs">
<span className="text-gray-600 flex items-center gap-1">
<svg
className="w-4 h-4"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"
/>
</svg>
{totalProps}
</span>
{id && (
<span className="text-green-600 flex items-center gap-1 font-medium">
<span className="w-2 h-2 bg-green-500 rounded-full animate-pulse"></span>
</span>
)}
</div>
</div>
</div>
);
};
export default PropertyPanel;