From ffe06be91f95ffd2459ebdb2f9130d1e38d53ea7 Mon Sep 17 00:00:00 2001
From: zzw <228544128@qq.com>
Date: 星期二, 06 十月 2026 18:32:34 +0800
Subject: [PATCH] fix: preserve manually edited menu names
---
emergency-repair-web/src/views/system/RolePermissionDialog.vue | 229 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 229 insertions(+), 0 deletions(-)
diff --git a/emergency-repair-web/src/views/system/RolePermissionDialog.vue b/emergency-repair-web/src/views/system/RolePermissionDialog.vue
new file mode 100644
index 0000000..3180bb7
--- /dev/null
+++ b/emergency-repair-web/src/views/system/RolePermissionDialog.vue
@@ -0,0 +1,229 @@
+<template>
+ <el-dialog
+ title="瑙掕壊鏉冮檺璁剧疆"
+ :visible.sync="dialogVisible"
+ width="860px"
+ append-to-body
+ :close-on-click-modal="false"
+ >
+ <div class="permission-head">
+ <div>
+ <span class="role-label">褰撳墠瑙掕壊</span>
+ <strong>{{ role.name }}</strong>
+ <span class="role-code">{{ role.code }}</span>
+ </div>
+ <span class="selected-total">宸查�夋潈闄� {{ selectedRoleIds.length }} 涓�</span>
+ </div>
+ <div class="permission-toolbar">
+ <el-radio-group v-model="permissionScope" size="small" @change="handleScopeChange">
+ <el-radio-button label="all">鍏ㄩ儴</el-radio-button>
+ <el-radio-button label="assigned">宸茶缃�</el-radio-button>
+ </el-radio-group>
+ <el-checkbox v-if="permissionScope === 'all'" v-model="checkAll" @change="toggleAll">鍏ㄩ��</el-checkbox>
+ <span class="permission-tip">{{ permissionTip }}</span>
+ </div>
+ <div v-loading="loading" class="permission-tree">
+ <el-tree
+ ref="permissionTree"
+ :data="displayMenus"
+ node-key="id"
+ show-checkbox
+ default-expand-all
+ empty-text="璇ヨ鑹插皻鏈缃潈闄�"
+ :render-content="renderContent"
+ :props="{ label: 'name', children: 'children' }"
+ @check="syncCheckAllState"
+ ></el-tree>
+ </div>
+ <template slot="footer">
+ <el-button @click="dialogVisible = false">鍙栨秷</el-button>
+ <el-button type="primary" :loading="saving" v-permission="'system:roles:permission'" @click="save">淇濆瓨</el-button>
+ </template>
+ </el-dialog>
+</template>
+
+<script>
+import api from '@/api'
+export default {
+ name: 'RolePermissionDialog',
+ props: {
+ visible: { type: Boolean, default: false },
+ role: { type: Object, default: () => ({}) }
+ },
+ data() {
+ return {
+ menus: [],
+ flatMenus: [],
+ loading: false,
+ saving: false,
+ checkAll: false,
+ permissionScope: 'all',
+ selectedRoleIds: []
+ }
+ },
+ computed: {
+ dialogVisible: {
+ get() { return this.visible },
+ set(value) { this.$emit('update:visible', value) }
+ },
+ allMenuIds() {
+ return this.flatMenus.map(item => String(item.id))
+ },
+ displayMenus() {
+ if (this.permissionScope === 'all') return this.menus
+ const assigned = new Set(this.selectedRoleIds.map(String))
+ const filterAssigned = nodes => (nodes || []).reduce((result, node) => {
+ const children = filterAssigned(node.children)
+ if (assigned.has(String(node.id)) || children.length) {
+ result.push({ ...node, children })
+ }
+ return result
+ }, [])
+ return filterAssigned(this.menus)
+ },
+ permissionTip() {
+ return this.permissionScope === 'all'
+ ? '鑿滃崟鍜屾寜閽潈闄愬潎鍙嬀閫夛紝淇濆瓨鍚庡垏鎹㈣鑹蹭細鑷姩鍙嶆樉銆�'
+ : '浠呮樉绀哄綋鍓嶈鑹插凡璁剧疆鐨勬潈闄愬強鍏剁埗绾ц妭鐐广��'
+ }
+ },
+ watch: {
+ visible(value) {
+ if (value) this.open()
+ },
+ },
+ methods: {
+ open() {
+ if (!this.role || !this.role.id) return
+ this.loading = true
+ this.checkAll = false
+ this.permissionScope = 'all'
+ this.selectedRoleIds = []
+ Promise.all([
+ api.get('/system/menu/tree'),
+ api.get('/system/menu/list'),
+ api.get('/system/menu-permissions', { params: { roleId: this.role.id } })
+ ]).then(([tree, flat, permissions]) => {
+ this.menus = tree.data || []
+ this.flatMenus = flat.data || []
+ const data = permissions.data || {}
+ this.selectedRoleIds = (data.roleMenuIds || []).map(String)
+ this.$nextTick(() => {
+ if (!this.$refs.permissionTree) return
+ this.$refs.permissionTree.setCheckedKeys(this.displayCheckedKeys(this.selectedRoleIds))
+ this.syncCheckAllState()
+ })
+ }).finally(() => { this.loading = false })
+
+ },
+ handleScopeChange() {
+ this.selectedRoleIds = this.checkedMenuIds()
+ this.$nextTick(() => {
+ if (!this.$refs.permissionTree) return
+ this.$refs.permissionTree.setCheckedKeys(this.displayCheckedKeys(this.selectedRoleIds))
+ this.syncCheckAllState()
+ })
+ },
+ renderContent(h, { data }) {
+ const label = data.menuType === 2 ? data.name + ' [鎸夐挳 ' + (data.permissions || '') + ']' : data.name
+ return h('span', { class: { 'perm-button-node': data.menuType === 2 } }, label)
+ },
+ displayCheckedKeys(ids) {
+ const selected = new Set((ids || []).map(String))
+ const children = {}
+ const menuIds = new Set(this.flatMenus.map(item => String(item.id)))
+ this.flatMenus.forEach(item => {
+ const id = String(item.id)
+ const pid = item.pid == null ? '0' : String(item.pid)
+ if (!children[pid]) children[pid] = []
+ children[pid].push(id)
+ })
+ const result = []
+ const collectFullySelected = id => {
+ if (!selected.has(id)) return false
+ const childIds = children[id] || []
+ if (!childIds.length) {
+ result.push(id)
+ return true
+ }
+ const allChildrenSelected = childIds.map(collectFullySelected).every(Boolean)
+ if (allChildrenSelected) result.push(id)
+ return allChildrenSelected
+ }
+ this.flatMenus
+ .filter(item => item.pid == null || String(item.pid) === '0' || !menuIds.has(String(item.pid)))
+ .forEach(item => collectFullySelected(String(item.id)))
+ return result
+ },
+ checkedMenuIds() {
+ const tree = this.$refs.permissionTree
+ if (!tree) return []
+ return [...new Set([...(tree.getCheckedKeys(false) || []), ...(tree.getHalfCheckedKeys() || [])].map(String))]
+ },
+ syncCheckAllState() {
+ const checked = this.checkedMenuIds()
+ this.selectedRoleIds = checked
+ this.checkAll = checked.length === this.allMenuIds.length
+ },
+ toggleAll() {
+ if (!this.$refs.permissionTree) return
+ this.$refs.permissionTree.setCheckedKeys(this.checkAll ? this.allMenuIds : [])
+ this.$nextTick(this.syncCheckAllState)
+ },
+ save() {
+ const roleMenuIds = this.checkedMenuIds()
+ this.saving = true
+ api.post('/system/menu-permissions', { roleId: this.role.id, roleMenuIds }).then(() => {
+ this.selectedRoleIds = roleMenuIds
+ this.$message.success('瑙掕壊鏉冮檺宸蹭繚瀛�')
+ this.$emit('saved')
+ this.dialogVisible = false
+ }).finally(() => { this.saving = false })
+ }
+ }
+}
+</script>
+
+<style scoped>
+.permission-head {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 12px;
+ color: #31465d;
+}
+.role-label {
+ margin-right: 10px;
+ color: #7b8b9c;
+ font-size: 13px;
+}
+.role-code {
+ margin-left: 8px;
+ color: #93a2b1;
+ font-size: 12px;
+}
+.selected-total {
+ color: #2f658f;
+ font-size: 13px;
+}
+.permission-toolbar {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ margin-bottom: 10px;
+}
+.permission-tip {
+ color: #7b8a9a;
+ font-size: 12px;
+}
+.permission-tree {
+ height: 460px;
+ padding: 8px 10px;
+ border: 1px solid #dce4ec;
+ border-radius: 4px;
+ overflow: auto;
+}
+::v-deep .perm-button-node {
+ color: #b8791f;
+}
+</style>
--
Gitblit v1.9.1