update RolePermissionAssign style

This commit is contained in:
Timi
2026-08-11 17:34:43 +08:00
parent 1bf53c9d1c
commit c045fbb49b
7 changed files with 76 additions and 145 deletions
@@ -50,6 +50,7 @@ import type { DropdownOption, DropdownValue } from "tdesign-mobile-vue";
import { Toast } from "tdesign-mobile-vue";
import { type Permission, useUserStore } from "timi-web";
import { type Role, usePermissionSettingsStore } from "@/store/permissionSettingsStore";
import { getErrorMessage } from "@/utils/error";
import { corePermissionCodes, coreRoleCodes } from "@/utils/permission";
defineOptions({
@@ -188,16 +189,6 @@ async function loadAuthorizationScope(): Promise<void> {
candidateRoleList.value = roleList;
}
function getErrorMessage(error: unknown, fallback: string): string {
if (error instanceof Error && error.message) {
return error.message;
}
if (typeof error === "string" && error) {
return error;
}
return fallback;
}
onMounted(async () => {
await permissionStore.loadAll();
await loadAuthorizationScope();
+1 -10
View File
@@ -112,6 +112,7 @@ import {
type RoleDraft,
usePermissionSettingsStore
} from "@/store/permissionSettingsStore";
import { getErrorMessage } from "@/utils/error";
import { corePermissionCodes, coreRoleCodes } from "@/utils/permission";
import PermissionCell from "@/pages/permission/component/PermissionCell.vue";
import PermissionLegend from "@/pages/permission/component/PermissionLegend.vue";
@@ -453,16 +454,6 @@ async function getCurrentStoreId(): Promise<string> {
return storeId;
}
function getErrorMessage(error: unknown, fallback: string): string {
if (error instanceof Error && error.message) {
return error.message;
}
if (typeof error === "string" && error) {
return error;
}
return fallback;
}
onMounted(fillForm);
function updateNavBar(): void {
+1 -10
View File
@@ -39,6 +39,7 @@ import { useUserStore } from "timi-web";
import type { Role } from "@/store/permissionSettingsStore";
import { useNavBarStore } from "@/store/navBarStore";
import { usePermissionSettingsStore } from "@/store/permissionSettingsStore";
import { getErrorMessage } from "@/utils/error";
import { corePermissionCodes, coreRoleCodes } from "@/utils/permission";
defineOptions({
@@ -161,15 +162,6 @@ async function refreshAuthorizationScope(): Promise<void> {
}
}
function getErrorMessage(error: unknown, fallback: string): string {
if (error instanceof Error && error.message) {
return error.message;
}
if (typeof error === "string" && error) {
return error;
}
return fallback;
}
</script>
<style scoped lang="less">
@@ -198,4 +190,3 @@ function getErrorMessage(error: unknown, fallback: string): string {
}
</style>
+55 -103
View File
@@ -13,21 +13,23 @@
@change="handleRoleChange"
/>
</t-dropdown-menu>
<div class="show-child-permission">
<span>显示继承权限</span>
<t-switch v-model="showChildRolePermissions" />
</div>
</div>
<div class="inherit">
<span class="label">显示继承权限</span>
<t-switch class="switch" v-model="showChildRolePermissions" />
</div>
<t-cell-group v-if="activeRole && grantablePermissionList.length" title="可配置的直接权限 P" theme="card">
<t-cell-group
v-if="activeRole && grantablePermissionList.length"
class="list"
theme="card"
>
<t-cell
:class="{ inherited: isPermissionInherited(item.id) }"
v-for="item in grantablePermissionList"
:key="item.id"
:title="item.name || item.code"
:class="{ inherited: isPermissionInherited(item.id) }"
:title="item.name"
:description="item.code"
>
<template #description>
<span class="code" v-text="item.code"></span>
</template>
<template #right-icon>
<t-switch
:disabled="!canUpdateRolePermission || !canEditActiveRole || isPermissionInherited(item.id)"
@@ -38,15 +40,6 @@
</t-cell>
</t-cell-group>
<t-empty v-else-if="!permissionStore.loading" description="暂无可配置的直接权限 P" />
<t-button
v-if="canEditActiveRole"
v-can="rolePermissionWriteAccess"
class="save"
theme="primary"
@click="savePermissionList"
>
保存 P
</t-button>
</div>
</template>
@@ -54,7 +47,9 @@
import type { DropdownOption, DropdownValue } from "tdesign-mobile-vue";
import { Toast } from "tdesign-mobile-vue";
import { type Permission, useUserStore } from "timi-web";
import { useNavBarStore } from "@/store/navBarStore";
import { type Role, usePermissionSettingsStore } from "@/store/permissionSettingsStore";
import { getErrorMessage } from "@/utils/error";
import { corePermissionCodes, coreRoleCodes } from "@/utils/permission";
defineOptions({
@@ -62,16 +57,13 @@ defineOptions({
});
const permissionStore = usePermissionSettingsStore();
const navBarStore = useNavBarStore();
const userStore = useUserStore();
const route = useRoute();
// ---------- 角色选择 ----------
const activeRoleId = ref(String(route.query.roleId || route.params.id || ""));
const checkedPermissionIds = ref<string[]>([]);
const unmanagedPermissionIds = ref<string[]>([]);
const inheritedPermissionIds = ref<string[]>([]);
const grantablePermissionList = ref<Permission[]>([]);
const candidateRoleList = ref<Role[]>([]);
const showChildRolePermissions = ref(false);
let permissionSyncSeq = 0;
@@ -94,16 +86,12 @@ const roleOptions = computed<DropdownOption[]>(() => candidateRoleList.value
disabled: false
})));
const rolePermissionWriteAccess = {
value: [
corePermissionCodes.rolePermission.create,
corePermissionCodes.rolePermission.delete
],
mode: "and"
} as const;
// ---------- 权限状态 ----------
const checkedPermissionIds = ref<string[]>([]);
const unmanagedPermissionIds = ref<string[]>([]);
const inheritedPermissionIds = ref<string[]>([]);
const grantablePermissionList = ref<Permission[]>([]);
const checkedPermissionIdSet = computed(() => new Set(checkedPermissionIds.value));
const inheritedPermissionIdSet = computed(() => new Set(inheritedPermissionIds.value));
@@ -152,7 +140,7 @@ async function savePermissionList(): Promise<void> {
...checkedPermissionIds.value,
...unmanagedPermissionIds.value
])));
Toast.success("P 已保存");
Toast.success("已保存");
await loadActiveRolePermissions();
} catch (error) {
clearPermissionState();
@@ -160,11 +148,25 @@ async function savePermissionList(): Promise<void> {
await loadAuthorizationScope();
await loadActiveRolePermissions();
} finally {
Toast.error(getErrorMessage(error, "P 保存失败"));
Toast.error(getErrorMessage(error, "保存失败"));
}
}
}
function updateNavBar(): void {
navBarStore.clearRight();
if (canEditActiveRole.value && canUpdateRolePermission.value) {
navBarStore.setRightText("保存", "var(--td-brand-color)", savePermissionList);
}
}
watch([canEditActiveRole, canUpdateRolePermission], updateNavBar, { immediate: true });
onMounted(updateNavBar);
onUnmounted(() => {
navBarStore.clearRight();
});
// ---------- 权限勾选 ----------
function isPermissionChecked(permissionId: string): boolean {
@@ -204,18 +206,7 @@ function clearPermissionState(): void {
// ---------- 授权范围 ----------
async function loadAuthorizationScope(): Promise<void> {
const roleList = isSystemAdmin.value ? permissionStore.roleList : await permissionStore.loadManageableRoles();
candidateRoleList.value = roleList;
}
function getErrorMessage(error: unknown, fallback: string): string {
if (error instanceof Error && error.message) {
return error.message;
}
if (typeof error === "string" && error) {
return error;
}
return fallback;
candidateRoleList.value = isSystemAdmin.value ? permissionStore.roleList : await permissionStore.loadManageableRoles();
}
onMounted(async () => {
@@ -232,7 +223,7 @@ onMounted(async () => {
.role-permission-assign {
gap: 1rem;
display: flex;
padding: calc(var(--app-nav-height) + 4.5rem) 0 6rem 0;
padding: calc(var(--app-nav-height) + 4rem) 0 1rem 0;
flex-direction: column;
.header {
@@ -241,81 +232,42 @@ onMounted(async () => {
right: 0;
z-index: 20;
display: flex;
padding: 0 1rem;
position: fixed;
background: #fff;
box-shadow: var(--td-shadow-1);
align-items: center;
justify-content: center;
justify-content: space-between;
.role-selector::after {
display: none;
}
}
.inherit {
gap: .75rem;
display: flex;
margin: 0 1rem;
padding: .75rem 1rem;
background: #fff;
align-items: center;
border-radius: .75rem;
justify-content: space-between;
.label {
color: #334155;
font-size: .875rem;
line-height: 1.25rem;
}
.switch {
.show-child-permission {
--td-switch-checked-color: #14b8a6;
gap: .5rem;
display: flex;
align-items: center;
}
}
:deep(.t-cell__title) {
min-width: 0;
}
.list {
:deep(.t-cell__title-text) {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
:deep(.t-cell) {
:deep(.t-cell__description) {
min-width: 0;
}
&.inherited {
:deep(.t-cell__right) {
flex: 0 0 auto;
margin-left: .75rem;
}
.t-cell__title-text {
color: #0f766e;
}
.code {
width: 100%;
display: block;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.inherited {
:deep(.t-cell__title) {
color: #0f766e;
.t-switch--checked.t-switch--disabled {
background: #14b8a6;
opacity: 1;
}
}
}
:deep(.t-switch--checked.t-switch--disabled) {
background: #14b8a6;
opacity: 1;
}
}
.save {
left: 1rem;
right: 1rem;
bottom: calc(.75rem + env(safe-area-inset-bottom, 0));
position: fixed;
}
}
+1 -10
View File
@@ -54,6 +54,7 @@ import ManagedUserAPI from "@/api/ManagedUserAPI";
import { useCurrentStoreStore } from "@/store/currentStoreStore";
import type { Role } from "@/store/permissionSettingsStore";
import type { ManagedUser } from "@/types/ManagedUser";
import { getErrorMessage } from "@/utils/error";
import { corePermissionCodes, gaoRoleCodes } from "@/utils/permission";
defineOptions({
@@ -270,16 +271,6 @@ function getRoleId(role: UserRole | string): string {
return fullRole?.id || "";
}
function getErrorMessage(error: unknown, fallback: string): string {
if (error instanceof Error && error.message) {
return error.message;
}
if (typeof error === "string" && error) {
return error;
}
return fallback;
}
function setRoleChecked(roleId: string, value: boolean): void {
if (value && !checkedRoleIds.value.includes(roleId)) {
checkedRoleIds.value.push(roleId);
+2 -2
View File
@@ -73,7 +73,7 @@ const permissionRoutes: RouteRecordRaw[] = [
depth: 6,
navBarVisible: true,
navBarCanBack: true,
navBarTitle: "角色直接权限 P",
navBarTitle: "角色直接授权权限 P",
tabBarVisible: false,
bodyBackground: "#F5F5F8",
darkBodyBackground: "#10161f"
@@ -147,7 +147,7 @@ const permissionRoutes: RouteRecordRaw[] = [
depth: 4,
navBarVisible: true,
navBarCanBack: true,
navBarTitle: "角色直接权限 P",
navBarTitle: "角色直接授权权限 P",
tabBarVisible: false,
bodyBackground: "#F5F5F8",
darkBodyBackground: "#10161f"
+15
View File
@@ -0,0 +1,15 @@
/**
* 从未知错误值中提取可展示的错误文案。
*
* @param error 未知错误值
* @param fallback 无法提取错误文案时的备用文案
*/
export function getErrorMessage(error: unknown, fallback: string): string {
if (error instanceof Error && error.message) {
return error.message;
}
if (typeof error === "string" && error) {
return error;
}
return fallback;
}