feat: 完成客户端联调与通用列表组件

This commit is contained in:
2026-08-01 12:17:33 +08:00
parent be7675954a
commit beb86d53e7
31 changed files with 1326 additions and 378 deletions
+9 -4
View File
@@ -15,6 +15,7 @@ const selectedCodes = ref<string[]>([])
const savedCodes = ref<string[]>([])
const loading = ref(false)
const loadError = ref('')
const saving = ref(false)
const selectedRole = computed(() => store.roles.find((role) => role.id === selectedRoleId.value))
const editable = computed(() => Boolean(auth.hasPermission('company:permission:assign') && selectedRole.value && !selectedRole.value.builtin && selectedRole.value.status === 'ACTIVE'))
@@ -70,15 +71,18 @@ function resetPermissions() {
}
async function savePermissions() {
if (!selectedRole.value || !editable.value) return
if (!selectedRole.value || !editable.value || saving.value) return
if (!selectedCodes.value.includes('account:profile:view')) selectedCodes.value.unshift('account:profile:view')
if (!selectedCodes.value.includes('dashboard:view')) selectedCodes.value.unshift('dashboard:view')
saving.value = true
try {
await store.setRolePermissions(selectedRole.value.id, selectedCodes.value)
savedCodes.value = [...selectedCodes.value]
ElMessage.success('角色菜单及操作权限已保存')
} catch (error) {
ElMessage.error(error instanceof Error ? error.message : '保存失败')
} finally {
saving.value = false
}
}
</script>
@@ -102,7 +106,7 @@ async function savePermissions() {
<div class="permission-content">
<div class="permission-heading client-card">
<div><span class="section-label">PERMISSIONS</span><h2>{{ selectedRole?.name }}</h2><p>{{ selectedRole?.description }}</p></div>
<div class="permission-actions"><el-button :disabled="!editable || !hasChanges" @click="resetPermissions"><RotateCcw :size="16" />撤销修改</el-button><el-button type="primary" :disabled="!editable || !hasChanges" @click="savePermissions"><Save :size="16" />保存权限</el-button></div>
<div class="permission-actions"><el-button :disabled="!editable || !hasChanges || saving" @click="resetPermissions"><RotateCcw :size="16" />撤销修改</el-button><el-button type="primary" :loading="saving" :disabled="!editable || !hasChanges || saving" @click="savePermissions"><Save :size="16" />保存权限</el-button></div>
</div>
<div v-if="selectedRole?.builtin" class="permission-notice"><LockKeyhole :size="18" /><span>当前角色为系统内置角色,权限由平台统一维护,不允许修改。</span></div>
@@ -141,6 +145,7 @@ async function savePermissions() {
.role-selector h3 { margin-bottom: 0; }
.role-selector > button { display: flex; width: 100%; min-height: 58px; align-items: center; gap: 9px; margin: 3px 0; padding: 9px; border: 0; border-radius: 8px; background: transparent; color: var(--navy); cursor: pointer; text-align: left; }
.role-selector > button:hover, .role-selector > button.active { background: #edf6f4; }
.role-selector > button:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.role-selector > button.active { color: var(--primary); }
.role-select-icon { display: grid; width: 32px; height: 32px; flex: 0 0 32px; place-items: center; background: #f0f5f4; }
.role-selector > button > span:nth-child(2) { display: flex; min-width: 0; flex: 1; flex-direction: column; gap: 3px; }
@@ -151,8 +156,8 @@ async function savePermissions() {
.permission-heading h2 { margin: 5px 0; font-size: 19px; }
.permission-heading p { margin: 0; color: var(--muted); font-size: 11px; }
.permission-actions { display: flex; gap: 8px; }
.permission-notice { display: flex; align-items: center; gap: 9px; padding: 12px 15px; border-left: 3px solid var(--primary); background: #edf6f4; color: #45615d; font-size: 11px; }
.permission-notice.warning { border-left-color: #d97706; background: #fff7ed; color: #9a5a09; }
.permission-notice { display: flex; align-items: center; gap: 9px; padding: 12px 15px; border: 1px solid #cfe1dc; background: #edf6f4; color: #45615d; font-size: 11px; }
.permission-notice.warning { border-color: #f1d4a8; background: #fff7ed; color: #9a5a09; }
.permission-groups { display: grid; gap: 12px; }
.permission-group { padding: 0; overflow: hidden; }
.permission-group > header { padding: 14px 18px; border-bottom: 1px solid var(--border); background: #fafcfc; }