import { Button, Card, Drawer, Form, Input, message, Popconfirm, Space, Table, Tag, Typography, InputNumber, Row, Col, Select, Empty } from "antd"; import { useEffect, useState, useMemo } from "react"; import { useTranslation } from "react-i18next"; import { createOrg, deleteOrg, listOrgs, updateOrg, listTenants } from "../api"; import { usePermission } from "../hooks/usePermission"; import { PlusOutlined, EditOutlined, DeleteOutlined, ApartmentOutlined, ReloadOutlined, ShopOutlined } from "@ant-design/icons"; import type { SysOrg, SysTenant, OrgNode } from "../types"; const { Title, Text } = Typography; function buildOrgTree(list: SysOrg[]): OrgNode[] { const map = new Map(); const roots: OrgNode[] = []; list.forEach((item) => { map.set(item.id, { ...item, children: [] }); }); map.forEach((node) => { if (node.parentId && map.has(node.parentId)) { map.get(node.parentId)!.children.push(node); } else { roots.push(node); } }); const sortTree = (nodes: OrgNode[]) => { nodes.sort((a, b) => (a.sortOrder || 0) - (b.sortOrder || 0)); nodes.forEach(n => n.children && sortTree(n.children)); }; sortTree(roots); return roots; } export default function Orgs() { const { t } = useTranslation(); const { can } = usePermission(); const [loading, setLoading] = useState(false); const [saving, setSaving] = useState(false); const [data, setData] = useState([]); const [tenants, setTenants] = useState([]); const [selectedTenantId, setSelectedTenantId] = useState(undefined); // Platform admin check const isPlatformMode = useMemo(() => { const profileStr = sessionStorage.getItem("userProfile"); if (profileStr) { const profile = JSON.parse(profileStr); return profile.isPlatformAdmin && localStorage.getItem("activeTenantId") === "0"; } return false; }, []); const activeTenantId = useMemo(() => Number(localStorage.getItem("activeTenantId") || 0), []); const [drawerOpen, setDrawerOpen] = useState(false); const [editing, setEditing] = useState(null); const [form] = Form.useForm(); const loadTenants = async () => { try { const resp = await listTenants({ current: 1, size: 100 }); const list = resp.records || []; setTenants(list); if (!isPlatformMode) { setSelectedTenantId(activeTenantId); } else if (list.length > 0 && selectedTenantId === undefined) { setSelectedTenantId(list[0].id); } } catch (e) { message.error(t('common.error')); } }; const loadOrgs = async () => { if (selectedTenantId === undefined) return; setLoading(true); try { const list = await listOrgs(selectedTenantId); setData(list || []); } catch (e) { message.error(t('common.error')); } finally { setLoading(false); } }; useEffect(() => { loadTenants(); }, []); useEffect(() => { loadOrgs(); }, [selectedTenantId]); const treeData = useMemo(() => buildOrgTree(data), [data]); const parentOptions = useMemo(() => { return data.map(o => ({ label: o.orgName, value: o.id })); }, [data]); const openCreate = (parentId?: number) => { setEditing(null); form.resetFields(); form.setFieldsValue({ tenantId: selectedTenantId, parentId: parentId, status: 1, sortOrder: 0 }); setDrawerOpen(true); }; const openEdit = (record: SysOrg) => { setEditing(record); form.setFieldsValue(record); setDrawerOpen(true); }; const handleDelete = async (id: number) => { try { await deleteOrg(id); message.success(t('common.success')); loadOrgs(); } catch (e: any) { message.error(e.message || t('common.error')); } }; const submit = async () => { try { const values = await form.validateFields(); setSaving(true); if (editing) { await updateOrg(editing.id, values); message.success(t('common.success')); } else { await createOrg(values); message.success(t('common.success')); } setDrawerOpen(false); loadOrgs(); } catch (e) { if (e instanceof Error && e.message) message.error(e.message); } finally { setSaving(false); } }; const columns = [ { title: t('orgs.orgName'), dataIndex: "orgName", key: "orgName", render: (text: string) => {text} }, { title: t('orgs.orgCode'), dataIndex: "orgCode", key: "orgCode", width: 150, render: (text: string) => {text || "-"} }, { title: t('orgs.sort'), dataIndex: "sortOrder", width: 100, className: "tabular-nums" }, { title: t('common.status'), dataIndex: "status", width: 100, render: (s: number) => {s === 1 ? "启用" : "禁用"} }, { title: t('common.action'), key: "action", width: 180, render: (_: any, record: SysOrg) => ( {can("sys:org:create") && ( )} {can("sys:org:update") && ( )} {isPlatformMode && ( {t('users.tenant')}: ({ label: t.tenantName, value: t.id }))} /> {!isPlatformMode && ( t.id === activeTenantId)?.tenantName || "当前租户"} disabled /> )}