@@ -283,7 +288,7 @@ export default function Devices() {
-
+
diff --git a/frontend/src/pages/Dictionaries.tsx b/frontend/src/pages/Dictionaries.tsx
index 6d2152d..a6122dd 100644
--- a/frontend/src/pages/Dictionaries.tsx
+++ b/frontend/src/pages/Dictionaries.tsx
@@ -30,7 +30,9 @@ import {
} from "../api";
import { usePermission } from "../hooks/usePermission";
import { PlusOutlined, EditOutlined, DeleteOutlined, BookOutlined, ProfileOutlined } from "@ant-design/icons";
+import { useDict } from "../hooks/useDict";
import type { SysDictItem, SysDictType } from "../types";
+import PageHeader from "../components/shared/PageHeader";
import "./Dictionaries.css";
const { Title, Text } = Typography;
@@ -44,6 +46,9 @@ export default function Dictionaries() {
const [loadingTypes, setLoadingTypes] = useState(false);
const [loadingItems, setLoadingItems] = useState(false);
+ // Dictionaries
+ const { items: statusDict } = useDict("sys_common_status");
+
// Type Drawer
const [typeDrawerVisible, setTypeDrawerVisible] = useState(false);
const [editingType, setEditingType] = useState
(null);
@@ -158,12 +163,19 @@ export default function Dictionaries() {
return (
-
-
-
{t('dicts.title')}
- {t('dicts.subtitle')}
-
-
+
}
+ onClick={handleAddType}
+ >
+ {t('common.create')}
+
+ )}
+ />
@@ -175,18 +187,6 @@ export default function Dictionaries() {
}
className="full-height-card shadow-sm"
- extra={
- can("sys_dict:type:create") && (
- }
- onClick={handleAddType}
- >
- {t('common.create')}
-
- )
- }
>
(
-
- {v === 1 ? "启用" : "禁用"}
-
- )
+ render: (v) => {
+ const item = statusDict.find(i => i.itemValue === String(v));
+ return (
+
+ {item ? item.itemLabel : (v === 1 ? "启用" : "禁用")}
+
+ );
+ }
},
{
title: t('common.action'),
@@ -412,10 +415,7 @@ export default function Dictionaries() {
diff --git a/frontend/src/pages/Logs.tsx b/frontend/src/pages/Logs.tsx
index c76196d..ee03e2e 100644
--- a/frontend/src/pages/Logs.tsx
+++ b/frontend/src/pages/Logs.tsx
@@ -2,8 +2,10 @@ import { Card, Table, Tabs, Tag, Input, Space, Button, DatePicker, Select, Typog
import { useEffect, useState, useMemo } from "react";
import { useTranslation } from "react-i18next";
import { fetchLogs } from "../api";
-import { SearchOutlined, ReloadOutlined, InfoCircleOutlined, EyeOutlined, UserOutlined } from "@ant-design/icons";
+import { SearchOutlined, ReloadOutlined, InfoCircleOutlined, EyeOutlined, UserOutlined, FileTextOutlined } from "@ant-design/icons";
import { SysLog, UserProfile } from "../types";
+import { useDict } from "../hooks/useDict";
+import PageHeader from "../components/shared/PageHeader";
const { RangePicker } = DatePicker;
const { Text, Title } = Typography;
@@ -26,6 +28,10 @@ export default function Logs() {
sortOrder: "descend" as any
});
+ // Dictionaries
+ const { items: logTypeDict } = useDict("sys_log_type");
+ const { items: logStatusDict } = useDict("sys_log_status");
+
// Get user profile to check platform admin
const userProfile = useMemo(() => {
const stored = sessionStorage.getItem("userProfile");
@@ -151,11 +157,14 @@ export default function Logs() {
dataIndex: "status",
key: "status",
width: 90,
- render: (status: number) => (
-
- {status === 1 ? "成功" : "失败"}
-
- )
+ render: (status: number) => {
+ const item = logStatusDict.find(i => i.itemValue === String(status));
+ return (
+
+ {item ? item.itemLabel : (status === 1 ? "成功" : "失败")}
+
+ );
+ }
},
{
title: t('logs.time'),
@@ -196,10 +205,10 @@ export default function Logs() {
return (
-
-
{t('logs.title')}
- {t('logs.subtitle')}
-
+
@@ -217,10 +226,7 @@ export default function Logs() {
allowClear
value={params.status}
onChange={v => setParams({ ...params, status: v })}
- options={[
- { label: "成功", value: 1 },
- { label: "失败", value: 0 }
- ]}
+ options={logStatusDict.map(i => ({ label: i.itemLabel, value: Number(i.itemValue) }))}
aria-label={t('common.status')}
/>
- {t('logs.opLog')}}
- key="OPERATION"
- />
- {t('logs.loginLog')}}
- key="LOGIN"
- />
+ {logTypeDict.length > 0 ? (
+ logTypeDict.map(item => (
+
+ {item.itemValue === 'OPERATION' ? : }
+ {item.itemLabel}
+
+ }
+ key={item.itemValue}
+ />
+ ))
+ ) : (
+ <>
+ {t('logs.opLog')}}
+ key="OPERATION"
+ />
+ {t('logs.loginLog')}}
+ key="LOGIN"
+ />
+ >
+ )}
{selectedLog.duration ? `${selectedLog.duration}ms` : "-"}
- {selectedLog.status === 1 ? "成功" : "失败"}
+ {logStatusDict.find(i => i.itemValue === String(selectedLog.status))?.itemLabel || (selectedLog.status === 1 ? "成功" : "失败")}
{selectedLog.createdAt?.replace('T', ' ')}
diff --git a/frontend/src/pages/Orgs.tsx b/frontend/src/pages/Orgs.tsx
index 1f19ea4..b7ad87f 100644
--- a/frontend/src/pages/Orgs.tsx
+++ b/frontend/src/pages/Orgs.tsx
@@ -20,6 +20,7 @@ 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 { useDict } from "../hooks/useDict";
import {
PlusOutlined,
EditOutlined,
@@ -29,6 +30,7 @@ import {
ShopOutlined
} from "@ant-design/icons";
import type { SysOrg, SysTenant, OrgNode } from "../types";
+import PageHeader from "../components/shared/PageHeader";
const { Title, Text } = Typography;
@@ -59,6 +61,10 @@ function buildOrgTree(list: SysOrg[]): OrgNode[] {
export default function Orgs() {
const { t } = useTranslation();
const { can } = usePermission();
+
+ // Dictionaries
+ const { items: statusDict } = useDict("sys_common_status");
+
const [loading, setLoading] = useState(false);
const [saving, setSaving] = useState(false);
const [data, setData] = useState([]);
@@ -200,7 +206,14 @@ export default function Orgs() {
title: t('common.status'),
dataIndex: "status",
width: 100,
- render: (s: number) => {s === 1 ? "启用" : "禁用"}
+ render: (s: number) => {
+ const item = statusDict.find(i => i.itemValue === String(s));
+ return (
+
+ {item ? item.itemLabel : (s === 1 ? "启用" : "禁用")}
+
+ );
+ }
},
{
title: t('common.action'),
@@ -226,17 +239,15 @@ export default function Orgs() {
return (
-
-
-
{t('orgs.title')}
- {t('orgs.subtitle')}
-
- {can("sys:org:create") && (
+
} onClick={() => openCreate()}>
{t('orgs.createRoot')}
)}
-
+ />
{isPlatformMode && (
@@ -332,7 +343,7 @@ export default function Orgs() {
-
+
diff --git a/frontend/src/pages/Permissions.tsx b/frontend/src/pages/Permissions.tsx
index d95184b..b2fcebd 100644
--- a/frontend/src/pages/Permissions.tsx
+++ b/frontend/src/pages/Permissions.tsx
@@ -21,6 +21,7 @@ import { useTranslation } from "react-i18next";
import { createPermission, deletePermission, listMyPermissions, updatePermission } from "../api";
import type { SysPermission } from "../types";
import { usePermission } from "../hooks/usePermission";
+import { useDict } from "../hooks/useDict";
import {
PlusOutlined,
EditOutlined,
@@ -32,6 +33,7 @@ import {
CheckSquareOutlined,
InfoCircleOutlined
} from "@ant-design/icons";
+import PageHeader from "../components/shared/PageHeader";
const { Title, Text } = Typography;
@@ -75,6 +77,12 @@ export default function Permissions() {
const { can } = usePermission();
const level = Form.useWatch("level", form);
+ // Dictionaries
+ const { items: statusDict } = useDict("sys_common_status");
+ const { items: typeDict } = useDict("sys_permission_type");
+ const { items: visibleDict } = useDict("sys_common_visibility");
+ const { items: levelDict } = useDict("sys_permission_level");
+
const load = async () => {
setLoading(true);
try {
@@ -206,11 +214,14 @@ export default function Permissions() {
title: t('permissions.permType'),
dataIndex: "permType",
width: 90,
- render: (type: string) => (
-
- {type === 'menu' ? '菜单' : '按钮'}
-
- )
+ render: (type: string) => {
+ const item = typeDict.find(i => i.itemValue === type);
+ return (
+
+ {item ? item.itemLabel : type}
+
+ );
+ }
},
{
title: t('permissions.sort'),
@@ -233,13 +244,19 @@ export default function Permissions() {
title: t('permissions.visible'),
dataIndex: "isVisible",
width: 80,
- render: (v: number) => (v === 1 ? 可见 : 隐藏)
+ render: (v: number) => {
+ const item = visibleDict.find(i => i.itemValue === String(v));
+ return (v === 1 ? {item?.itemLabel || '可见'} : {item?.itemLabel || '隐藏'});
+ }
},
{
title: t('common.status'),
dataIndex: "status",
width: 80,
- render: (v: number) => (v === 1 ? 启用 : 禁用)
+ render: (v: number) => {
+ const item = statusDict.find(i => i.itemValue === String(v));
+ return (v === 1 ? {item?.itemLabel || '启用'} : {item?.itemLabel || '禁用'});
+ }
},
{
title: t('common.action'),
@@ -284,12 +301,10 @@ export default function Permissions() {
return (
-
-
-
{t('permissions.title')}
- {t('permissions.subtitle')}
-
- {can("sys:permission:create") && (
+
}
@@ -298,7 +313,7 @@ export default function Permissions() {
{t('common.create')}
)}
-
+ />
@@ -324,10 +339,7 @@ export default function Permissions() {
allowClear
value={query.permType || undefined}
onChange={(v) => setQuery({ ...query, permType: v || "" })}
- options={[
- { value: "menu", label: "菜单" },
- { value: "button", label: "按钮" }
- ]}
+ options={typeDict.map(i => ({ value: i.itemValue, label: i.itemLabel }))}
style={{ width: 120 }}
aria-label={t('permissions.permType')}
/>
@@ -395,16 +407,18 @@ export default function Permissions() {
-
+
-
+
-
+
@@ -484,12 +498,12 @@ export default function Permissions() {
-
+
-
+
diff --git a/frontend/src/pages/PlatformSettings.tsx b/frontend/src/pages/PlatformSettings.tsx
index 83b95a8..3475fad 100644
--- a/frontend/src/pages/PlatformSettings.tsx
+++ b/frontend/src/pages/PlatformSettings.tsx
@@ -22,6 +22,7 @@ import {
FileTextOutlined
} from "@ant-design/icons";
import type { SysPlatformConfig } from "../types";
+import PageHeader from "../components/shared/PageHeader";
const { Title, Text } = Typography;
@@ -85,20 +86,20 @@ export default function PlatformSettings() {
return (
-
-
-
{t('platformSettings.title')}
- {t('platformSettings.subtitle')}
-
-
}
- loading={saving}
- onClick={() => form.submit()}
- >
- {t('common.save')}
-
-
+
}
+ loading={saving}
+ onClick={() => form.submit()}
+ >
+ {t('common.save')}
+
+ )}
+ />