From 92e6b9fd4d7ef72f89009946106b0ca2c24d21ed Mon Sep 17 00:00:00 2001 From: chenhao Date: Thu, 26 Mar 2026 13:44:57 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E8=A7=92=E8=89=B2?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=9D=83=E9=99=90=E7=AE=A1=E7=90=86=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 `zh-CN.json` 中新增与Bot凭证相关的国际化字符串 - 在 `index.tsx` 中添加数据权限管理标签页,支持自定义部门选择 - 更新API接口,新增获取和保存角色数据权限的方法 - 重构角色选择逻辑,加载角色时同时获取权限和数据权限信息 - 优化用户绑定和权限保存操作的提示信息 --- frontend/src/api/index.ts | 25 +- frontend/src/locales/en-US.json | 13 +- frontend/src/locales/zh-CN.json | 13 +- frontend/src/pages/access/roles/index.tsx | 332 +++++++++++++------- frontend/src/pages/profile/index.tsx | 364 ++++++++++++++-------- frontend/src/types/index.ts | 18 +- 6 files changed, 513 insertions(+), 252 deletions(-) diff --git a/frontend/src/api/index.ts b/frontend/src/api/index.ts index c3b3ff4..4719458 100644 --- a/frontend/src/api/index.ts +++ b/frontend/src/api/index.ts @@ -1,6 +1,6 @@ import http from "./http"; import { - DeviceInfo, SysPermission, SysRole, SysUser, UserProfile, SysParamVO, SysParamQuery, PageResult, + BotCredential, DeviceInfo, RoleDataScope, SysPermission, SysRole, SysUser, UserProfile, SysParamVO, SysParamQuery, PageResult, PermissionNode } from "../types"; @@ -29,7 +29,6 @@ export async function listUsers(params?: { tenantId?: number; orgId?: number }) return resp.data.data as SysUser[]; } - export async function createUser(payload: Partial) { const resp = await http.post("/sys/api/users", payload); return resp.data.data as boolean; @@ -110,6 +109,16 @@ export async function updateMyPassword(payload: any) { return resp.data.data as boolean; } +export async function getMyBotCredential() { + const resp = await http.get("/sys/api/users/bot-credential"); + return resp.data.data as BotCredential; +} + +export async function generateMyBotCredential() { + const resp = await http.post("/sys/api/users/bot-credential/generate"); + return resp.data.data as BotCredential; +} + export async function createPermission(payload: Partial) { const resp = await http.post("/sys/api/permissions", payload); return resp.data.data as boolean; @@ -165,6 +174,16 @@ export async function saveRolePermissions(roleId: number, permIds: number[]) { return resp.data.data as boolean; } +export async function getRoleDataScope(roleId: number) { + const resp = await http.get(`/sys/api/roles/${roleId}/data-scope`); + return resp.data.data as RoleDataScope; +} + +export async function saveRoleDataScope(roleId: number, payload: RoleDataScope) { + const resp = await http.post(`/sys/api/roles/${roleId}/data-scope`, payload); + return resp.data.data as boolean; +} + export async function fetchUsersByRoleId(roleId: number) { const resp = await http.get(`/sys/api/roles/${roleId}/users`); return resp.data.data as SysUser[]; @@ -194,5 +213,3 @@ export * from "./dict"; export * from "./tenant"; export * from "./org"; export * from "./platform"; - - diff --git a/frontend/src/locales/en-US.json b/frontend/src/locales/en-US.json index f4e8186..f2bb2f4 100644 --- a/frontend/src/locales/en-US.json +++ b/frontend/src/locales/en-US.json @@ -260,7 +260,18 @@ "saveChanges": "Save Changes", "updatePassword": "Update Password", "passwordsDoNotMatch": "Passwords do not match.", - "standardUser": "Standard User" + "standardUser": "Standard User", + "botCredentialTab": "Bot Credential", + "botCredentialHint": "Use this credential pair to access /mcp with X-Bot-Id and X-Bot-Secret.", + "botCredentialHintDesc": "The secret is shown only after generation. Store it securely after copying.", + "botBindStatus": "Binding Status", + "botBound": "Bound", + "botUnbound": "Not Generated", + "botSecretHidden": "Hidden. Generate or reset to get a new secret.", + "botLastAccessTime": "Last Access Time", + "botLastAccessIp": "Last Access IP", + "generateBotCredential": "Generate Credential", + "regenerateBotCredential": "Regenerate Credential" }, "rolesExt": { "roleList": "Role List", diff --git a/frontend/src/locales/zh-CN.json b/frontend/src/locales/zh-CN.json index 502f547..91b70c3 100644 --- a/frontend/src/locales/zh-CN.json +++ b/frontend/src/locales/zh-CN.json @@ -260,7 +260,18 @@ "saveChanges": "保存修改", "updatePassword": "更新密码", "passwordsDoNotMatch": "两次输入的密码不一致。", - "standardUser": "普通用户" + "standardUser": "普通用户", + "botCredentialTab": "Bot 凭证", + "botCredentialHint": "使用这组凭证通过 X-Bot-Id 和 X-Bot-Secret 访问 /mcp。", + "botCredentialHintDesc": "Secret 只会在生成后显示一次,请复制后妥善保管。", + "botBindStatus": "绑定状态", + "botBound": "已绑定", + "botUnbound": "未生成", + "botSecretHidden": "已隐藏。如需查看新的 Secret,请重新生成。", + "botLastAccessTime": "最近访问时间", + "botLastAccessIp": "最近访问 IP", + "generateBotCredential": "生成凭证", + "regenerateBotCredential": "重置凭证" }, "rolesExt": { "roleList": "角色列表", diff --git a/frontend/src/pages/access/roles/index.tsx b/frontend/src/pages/access/roles/index.tsx index 0ce2b03..a282df2 100644 --- a/frontend/src/pages/access/roles/index.tsx +++ b/frontend/src/pages/access/roles/index.tsx @@ -1,7 +1,6 @@ -import { Avatar, Badge, Button, Card, Col, Drawer, Empty, Form, Input, List, Pagination, message, Modal, Popconfirm, Select, Space, Table, Tabs, Tag, Tooltip, Tree, Typography, Row } from "antd"; +import { Avatar, Button, Card, Col, Drawer, Empty, Form, Input, List, Pagination, Radio, message, Modal, Popconfirm, Select, Space, Table, Tabs, Tag, Tooltip, Tree, Typography, Row } from "antd"; import type { DataNode } from "antd/es/tree"; import { useEffect, useMemo, useState } from "react"; -import { useTranslation } from "react-i18next"; import { ApartmentOutlined, CheckCircleFilled, @@ -22,11 +21,14 @@ import { createRole, deleteRole, fetchUsersByRoleId, + getRoleDataScope, + listOrgs, listPermissions, listRolePermissions, listTenants, listUsers, pageRoles, + saveRoleDataScope, saveRolePermissions, unbindUserFromRole, updateRole @@ -34,14 +36,25 @@ import { import { useDict } from "@/hooks/useDict"; import { usePermission } from "@/hooks/usePermission"; import PageHeader from "@/components/shared/PageHeader"; -import type { SysPermission, SysRole, SysTenant, SysUser } from "@/types"; +import type { RoleDataScope, SysOrg, SysPermission, SysRole, SysTenant, SysUser } from "@/types"; import "./index.less"; const { Text, Title } = Typography; type PermissionNode = SysPermission & { key: number; children?: PermissionNode[] }; +type OrgTreeNode = SysOrg & { key: number; children?: OrgTreeNode[] }; +type RoleTabKey = "permissions" | "dataScope" | "users"; + const DEFAULT_STATUS = 1; const DEFAULT_ROLE_PAGE_SIZE = 10; +const BUTTON_SHORT_LABEL = "按钮"; +const DATA_SCOPE_OPTIONS = [ + { label: "全部", value: "ALL" }, + { label: "个人", value: "SELF" }, + { label: "本部门", value: "DEPT" }, + { label: "本部门及下级部门", value: "DEPT_AND_CHILD" }, + { label: "自定义部门", value: "CUSTOM" } +] as const; function normalizeNumber(value: unknown): number | undefined { if (typeof value === "number") { @@ -56,6 +69,7 @@ function normalizeNumber(value: unknown): number | undefined { } return undefined; } + function buildPermissionTree(list: SysPermission[]): PermissionNode[] { const active = (list || []).filter((permission) => permission.status !== 0); const map = new Map(); @@ -85,7 +99,7 @@ function buildPermissionTree(list: SysPermission[]): PermissionNode[] { return roots; } -function toTreeData(nodes: PermissionNode[], t: (key: string, options?: Record) => string, buttonShortLabel: string): DataNode[] { +function toPermissionTreeData(nodes: PermissionNode[], buttonShortLabel: string): DataNode[] { return nodes.map((node) => ({ key: node.permId, title: ( @@ -94,14 +108,63 @@ function toTreeData(nodes: PermissionNode[], t: (key: string, options?: Record{buttonShortLabel} : null} ), - children: node.children?.length ? toTreeData(node.children, t, buttonShortLabel) : undefined + children: node.children?.length ? toPermissionTreeData(node.children, buttonShortLabel) : undefined })); } +function buildOrgTree(list: SysOrg[]): OrgTreeNode[] { + const map = new Map(); + const roots: OrgTreeNode[] = []; + + list.forEach((item) => { + map.set(item.id, { ...item, key: item.id, children: [] }); + }); + + map.forEach((node) => { + if (node.parentId && map.has(node.parentId)) { + map.get(node.parentId)!.children!.push(node); + } else { + roots.push(node); + } + }); + + const sortNodes = (nodes: OrgTreeNode[]) => { + nodes.sort((left, right) => (left.sortOrder || 0) - (right.sortOrder || 0)); + nodes.forEach((node) => node.children && sortNodes(node.children)); + }; + + sortNodes(roots); + return roots; +} + +function toOrgTreeData(nodes: OrgTreeNode[]): DataNode[] { + return nodes.map((node) => ({ + key: node.id, + title: node.orgName, + children: node.children?.length ? toOrgTreeData(node.children) : undefined + })); +} + +function getDataScopeDescription(scopeType: string) { + switch (scopeType) { + case "ALL": + return "当前角色可访问当前租户全部数据。"; + case "SELF": + return "当前角色仅可访问本人数据。"; + case "DEPT": + return "当前角色可访问本人所在部门的数据。"; + case "DEPT_AND_CHILD": + return "当前角色可访问本人所在部门及所有下级部门的数据。"; + case "CUSTOM": + return "当前角色可访问选中部门的数据。"; + default: + return ""; + } +} + const generateRoleCode = () => `ROLE_${Date.now().toString(36).toUpperCase()}`; export default function Roles() { - const { t } = useTranslation(); const { can } = usePermission(); const { items: statusDict } = useDict("sys_common_status"); const [loading, setLoading] = useState(false); @@ -119,21 +182,14 @@ export default function Roles() { const [userSearchText, setUserSearchText] = useState(""); const [searchText, setSearchText] = useState(""); const [rolePage, setRolePage] = useState({ current: 1, size: DEFAULT_ROLE_PAGE_SIZE, total: 0 }); - - const handleSearch = () => { - setSearchText((value) => value.trim()); - setRolePage((prev) => ({ ...prev, current: 1 })); - }; - - const handleResetSearch = () => { - setSearchText(""); - setFilterTenantId(undefined); - setRolePage((prev) => ({ ...prev, current: 1 })); - }; const [filterTenantId, setFilterTenantId] = useState(undefined); const [drawerOpen, setDrawerOpen] = useState(false); const [editing, setEditing] = useState(null); const [tenants, setTenants] = useState([]); + const [activeTab, setActiveTab] = useState("permissions"); + const [dataScopeType, setDataScopeType] = useState("SELF"); + const [scopeOrgIds, setScopeOrgIds] = useState([]); + const [scopeOrgTree, setScopeOrgTree] = useState([]); const [form] = Form.useForm(); const isPlatformMode = useMemo(() => { @@ -144,12 +200,15 @@ export default function Roles() { }, []); const activeTenantId = useMemo(() => normalizeNumber(localStorage.getItem("activeTenantId")) ?? 0, []); - const buttonShortLabel = useMemo(() => { - const label = t("buttonShort"); - return !label || label === "buttonShort" ? "BTN" : label; - }, [t]); - const permissionTreeData = useMemo(() => toTreeData(buildPermissionTree(permissions), t, buttonShortLabel), [buttonShortLabel, permissions, t]); - + const permissionTreeData = useMemo(() => toPermissionTreeData(buildPermissionTree(permissions), BUTTON_SHORT_LABEL), [permissions]); + const filteredModalUsers = useMemo(() => { + const existingIds = new Set(roleUsers.map((user) => user.userId)); + return allUsers.filter( + (user) => + !existingIds.has(user.userId) && + (user.username.toLowerCase().includes(userSearchText.toLowerCase()) || user.displayName.toLowerCase().includes(userSearchText.toLowerCase())) + ); + }, [allUsers, roleUsers, userSearchText]); useEffect(() => { if (!isPlatformMode) return; @@ -160,23 +219,31 @@ export default function Roles() { try { const list = await listPermissions(); setPermissions(list || []); + return list || []; } catch { setPermissions([]); + return [] as SysPermission[]; } }; - const selectRole = async (role: SysRole) => { + const selectRole = async (role: SysRole, permissionList: SysPermission[] = permissions) => { setSelectedRole(role); + setLoadingUsers(true); try { - const ids = await listRolePermissions(role.roleId); + const [ids, users, dataScope, orgs] = await Promise.all([ + listRolePermissions(role.roleId), + fetchUsersByRoleId(role.roleId), + getRoleDataScope(role.roleId), + listOrgs(role.tenantId) + ]); const normalized = (ids || []).map((id) => Number(id)).filter((id) => !Number.isNaN(id)); - const leafIds = normalized.filter((id) => !permissions.some((permission) => permission.parentId === id)); + const leafIds = normalized.filter((id) => !permissionList.some((permission) => permission.parentId === id)); setSelectedPermIds(leafIds); setHalfCheckedIds([]); - - setLoadingUsers(true); - const users = await fetchUsersByRoleId(role.roleId); setRoleUsers(users || []); + setDataScopeType(dataScope?.scopeType || role.dataScopeType || "SELF"); + setScopeOrgIds((dataScope?.orgIds || []).map((id) => Number(id)).filter((id) => !Number.isNaN(id))); + setScopeOrgTree(toOrgTreeData(buildOrgTree(orgs || []))); } finally { setLoadingUsers(false); } @@ -185,6 +252,7 @@ export default function Roles() { const loadRoles = async (page = rolePage.current, size = rolePage.size) => { setLoading(true); try { + const permissionList = await loadPermissions(); const response = await pageRoles({ current: page, size, @@ -199,24 +267,26 @@ export default function Roles() { setRoleUsers([]); setSelectedPermIds([]); setHalfCheckedIds([]); + setDataScopeType("SELF"); + setScopeOrgIds([]); + setScopeOrgTree([]); } else if (!selectedRole) { - await selectRole(roles[0]); + await selectRole(roles[0], permissionList); } else { const updated = roles.find((role) => role.roleId === selectedRole.roleId); if (updated) { - setSelectedRole(updated); + await selectRole(updated, permissionList); } else { - await selectRole(roles[0]); + await selectRole(roles[0], permissionList); } } - await loadPermissions(); } finally { setLoading(false); } }; useEffect(() => { - loadRoles(rolePage.current, rolePage.size); + void loadRoles(rolePage.current, rolePage.size); }, [filterTenantId, rolePage.current, rolePage.size, searchText]); const loadAllUsers = async () => { @@ -229,7 +299,7 @@ export default function Roles() { }; const openUserModal = () => { - loadAllUsers(); + void loadAllUsers(); setSelectedUserKeys([]); setUserModalOpen(true); }; @@ -237,33 +307,22 @@ export default function Roles() { const handleAddUsers = async () => { if (!selectedRole || selectedUserKeys.length === 0) return; await bindUsersToRole(selectedRole.roleId, selectedUserKeys); - message.success(t("common.success")); + message.success("操作成功"); setUserModalOpen(false); - selectRole(selectedRole); + await selectRole(selectedRole); }; const handleUnbindUser = async (userId: number) => { if (!selectedRole) return; if (selectedRole.roleCode === "TENANT_ADMIN" && roleUsers.length <= 1) { - message.warning(t("rolesExt.tenantAdminWarning")); + message.warning("租户管理员角色至少需要保留一个绑定用户"); return; } await unbindUserFromRole(selectedRole.roleId, userId); - message.success(t("common.success")); - selectRole(selectedRole); + message.success("操作成功"); + await selectRole(selectedRole); }; - const filteredModalUsers = useMemo(() => { - const existingIds = new Set(roleUsers.map((user) => user.userId)); - return allUsers.filter( - (user) => - !existingIds.has(user.userId) && - (user.username.toLowerCase().includes(userSearchText.toLowerCase()) || user.displayName.toLowerCase().includes(userSearchText.toLowerCase())) - ); - }, [allUsers, roleUsers, userSearchText]); - - - const openCreate = () => { setEditing(null); form.resetFields(); @@ -281,9 +340,9 @@ export default function Roles() { const handleRemove = async (event: React.MouseEvent, id: number) => { event.stopPropagation(); await deleteRole(id); - message.success(t("common.success")); + message.success("操作成功"); if (selectedRole?.roleId === id) setSelectedRole(null); - loadRoles(rolePage.current, rolePage.size); + await loadRoles(rolePage.current, rolePage.size); }; const submitBasic = async () => { @@ -295,16 +354,17 @@ export default function Roles() { roleName: values.roleName, remark: values.remark, status: values.status ?? DEFAULT_STATUS, - tenantId: values.tenantId + tenantId: values.tenantId, + dataScopeType: editing?.dataScopeType || "SELF" }; if (editing) { await updateRole(editing.roleId, payload); } else { await createRole(payload); } - message.success(t("common.success")); + message.success("操作成功"); setDrawerOpen(false); - loadRoles(rolePage.current, rolePage.size); + await loadRoles(rolePage.current, rolePage.size); } finally { setSaving(false); } @@ -319,33 +379,63 @@ export default function Roles() { setSaving(true); try { await saveRolePermissions(selectedRole.roleId, Array.from(new Set([...selectedPermIds, ...halfCheckedIds]))); - message.success(t("common.success")); + message.success("操作成功"); } finally { setSaving(false); } }; + const saveDataScope = async () => { + if (!selectedRole) return; + if (dataScopeType === "CUSTOM" && scopeOrgIds.length === 0) { + message.warning("请选择至少一个部门"); + return; + } + setSaving(true); + try { + const payload: RoleDataScope = { + roleId: selectedRole.roleId, + scopeType: dataScopeType, + orgIds: dataScopeType === "CUSTOM" ? scopeOrgIds : [] + }; + await saveRoleDataScope(selectedRole.roleId, payload); + message.success("操作成功"); + setSelectedRole((prev) => (prev ? { ...prev, dataScopeType } : prev)); + setData((prev) => prev.map((item) => item.roleId === selectedRole.roleId ? { ...item, dataScopeType } : item)); + } finally { + setSaving(false); + } + }; + + const handlePrimarySave = () => { + if (activeTab === "permissions") { + void savePermissions(); + return; + } + if (activeTab === "dataScope") { + void saveDataScope(); + } + }; + + const saveDisabled = !selectedRole || activeTab === "users" || (activeTab === "permissions" && !can("sys:role:permission:save")) || (activeTab === "dataScope" && !can("sys:role:update")); + const saveLabel = activeTab === "dataScope" ? "保存数据权限" : "保存"; + return (
- +
- {can("sys:role:create") && } + {can("sys:role:create") && }
- {t("rolesExt.roleList")} - {/**/} - } bordered={false} className="app-page__panel-card roles-side-card"> + {"角色列表"}} bordered={false} className="app-page__panel-card roles-side-card">
{isPlatformMode && ( } value={searchText} onChange={(event) => setSearchText(event.target.value)} allowClear /> - + } value={searchText} onChange={(event) => setSearchText(event.target.value)} allowClear /> +
@@ -365,17 +455,17 @@ export default function Roles() { loading={loading} dataSource={data} pagination={false} - locale={{ emptyText: }} + locale={{ emptyText: }} renderItem={(item) => ( -
selectRole(item)}> +
void selectRole(item)}>
{item.roleName} - {isPlatformMode && {item.tenantId === 0 ? t("rolesExt.systemTenant") : tenants.find((tenant) => tenant.id === item.tenantId)?.tenantName || `${t("rolesExt.tenantLabel")}:${item.tenantId}`}} - {item.status === 0 && {t("rolesExt.disabled")}} + {isPlatformMode && {item.tenantId === 0 ? "平台租户" : tenants.find((tenant) => tenant.id === item.tenantId)?.tenantName || `租户:${item.tenantId}`}} + {item.status === 0 && {"停用"}}
{item.roleCode}
@@ -386,11 +476,11 @@ export default function Roles() { ) : null}
- + } + extra={} > - - {t("roles.funcPerms")}} key="permissions"> + setActiveTab(key as RoleTabKey)} className="role-detail-tabs"> + {"功能权限"}} key="permissions">
- {t("rolesExt.membersTab")} ({roleUsers.length})} key="users"> + {"数据权限"}} key="dataScope"> +
+
+ setDataScopeType(event.target.value)} optionType="button" buttonStyle="solid"> + {DATA_SCOPE_OPTIONS.map((item) => ( + {item.label} + ))} + +
+
{getDataScopeDescription(dataScopeType)}
+ {dataScopeType === "CUSTOM" ? ( +
+ { + const checked = Array.isArray(keys) ? keys : keys.checked; + setScopeOrgIds(checked.map((key) => Number(key))); + }} + defaultExpandAll + /> +
+ ) : ( + + )} +
+
+ {`成员管理 (${roleUsers.length})`}} key="users">
- {t("rolesExt.assignedUsers")} - + {"已绑定用户"} +
( + title: "用户信息", + render: (_: unknown, user: SysUser) => ( } style={{ backgroundColor: "#f0f2f5", color: "#8c8c8c" }} />
@@ -468,14 +587,14 @@ export default function Roles() { ) }, - { title: t("rolesExt.phone"), dataIndex: "phone", className: "tabular-nums" }, - { title: t("common.status"), dataIndex: "status", width: 80, render: (status: number) => {status === 1 ? t("logsExt.success") : t("rolesExt.disabled")} }, + { title: "手机号", dataIndex: "phone", className: "tabular-nums" }, + { title: "状态", dataIndex: "status", width: 80, render: (status: number) => {status === 1 ? "启用" : "停用"} }, { - title: t("common.action"), + title: "操作", key: "action", width: 80, - render: (_: any, user: SysUser) => ( - handleUnbindUser(user.userId)} disabled={!can("sys:role:update")}> + render: (_: unknown, user: SysUser) => ( + void handleUnbindUser(user.userId)} disabled={!can("sys:role:update")}>
- setUserModalOpen(false)} onOk={handleAddUsers} okText={t("common.confirm")} cancelText={t("common.cancel")} width={650} destroyOnClose> + setUserModalOpen(false)} onOk={() => void handleAddUsers()} okText="确定" cancelText="取消" width={650} destroyOnClose>
- } value={userSearchText} onChange={(event) => setUserSearchText(event.target.value)} allowClear /> + } value={userSearchText} onChange={(event) => setUserSearchText(event.target.value)} allowClear />
-
setSelectedUserKeys(keys as number[]) }} columns={[{ title: t("rolesExt.displayName"), dataIndex: "displayName" }, { title: t("users.username"), dataIndex: "username" }, { title: t("rolesExt.phone"), dataIndex: "phone" }]} /> +
setSelectedUserKeys(keys as number[]) }} columns={[{ title: "显示名称", dataIndex: "displayName" }, { title: "用户名", dataIndex: "username" }, { title: "手机号", dataIndex: "phone" }]} /> - setDrawerOpen(false)} width={420} destroyOnClose footer={
}> + setDrawerOpen(false)} width={420} destroyOnClose footer={
}>
-
- - } style={{ backgroundColor: "#1677ff", marginBottom: 16 }} /> - {user?.displayName} - @{user?.username} -
- {user?.isPlatformAdmin ? {t("users.platformAdmin")} : {t("profile.standardUser")}} -
-
- - - - {t("profile.basicInfo")}, - children: ( -
- - - - - - - - - -
- -
- - ) - }, - { - key: "password", - label: {t("profile.security")}, - children: ( -
- - - - - - - ({ - validator(_, value) { - if (!value || getFieldValue("newPassword") === value) { - return Promise.resolve(); - } - return Promise.reject(new Error(t("profile.passwordsDoNotMatch"))); - } - }) - ]} - > - - -
- -
- - ) - } - ]} - /> -
- - - - ); -} \ No newline at end of file diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts index a4972ee..25611f8 100644 --- a/frontend/src/types/index.ts +++ b/frontend/src/types/index.ts @@ -12,6 +12,7 @@ export interface SysUser extends BaseEntity { displayName: string; email?: string; phone?: string; + password?: string; passwordHash?: string; tenantId: number; orgId?: number; @@ -33,12 +34,28 @@ export interface UserProfile { pwdResetRequired?: number; } +export interface BotCredential { + bound: boolean; + botId?: string; + botSecret?: string; + status?: string; + expireTime?: string; + lastAccessTime?: string; + lastAccessIp?: string; +} export interface SysRole extends BaseEntity { roleId: number; roleCode: string; roleName: string; remark?: string; + dataScopeType?: string; +} + +export interface RoleDataScope { + roleId?: number; + scopeType: string; + orgIds: number[]; } export interface SysPermission extends BaseEntity { @@ -167,4 +184,3 @@ export interface MenuRoute { element: ReactNode; perm?: string; } -