Files
bj_power/bj_power_mes/frontend/src/pages/RoleManage.vue
T

217 lines
8.0 KiB
Vue
Raw Normal View History

<template>
<div>
<el-card shadow="never" class="mb12">
<div style="display:flex;justify-content:space-between;align-items:center">
<div>
<b>角色管理</b>
<span style="margin-left:8px;color:#909399;font-size:12px">
角色决定账号的菜单与按钮权限内置角色超级管理员/生产操作员/质检员不可删除
</span>
</div>
<el-button v-if="can('sys.role:add')" type="primary" @click="openCreate">新增角色</el-button>
</div>
</el-card>
<el-card shadow="never">
<el-table :data="roles" border size="small" v-loading="loading" empty-text="暂无角色">
<el-table-column prop="id" label="ID" width="64" align="center" />
<el-table-column label="名称" min-width="150">
<template #default="{ row }">
<el-tag :type="row.code === 'SUPER_ADMIN' ? 'danger' : 'primary'" size="small">{{ row.name }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="remark" label="备注" min-width="180">
<template #default="{ row }">{{ row.remark || '-' }}</template>
</el-table-column>
<el-table-column label="权限数" width="90" align="center">
<template #default="{ row }">{{ permCount(row) }} </template>
</el-table-column>
<el-table-column label="权限明细" min-width="240">
<template #default="{ row }">
<el-tooltip :content="permSummary(row)" placement="top" :show-after="300">
<span style="color:#606266">{{ permSummary(row) }}</span>
</el-tooltip>
</template>
</el-table-column>
<el-table-column label="操作" width="150" align="center" fixed="right">
<template #default="{ row }">
<el-button v-if="can('sys.role:edit')" link type="primary" size="small"
:disabled="row.code === 'SUPER_ADMIN'" @click="openEdit(row)">编辑权限</el-button>
<el-button v-if="can('sys.role:delete')" link type="danger" size="small"
:disabled="['SUPER_ADMIN', 'OPERATOR', 'INSPECTOR'].includes(row.code)" @click="removeRole(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
<el-dialog v-model="dialog.show" :title="dialog.editingId ? '编辑角色权限' : '新增角色'" width="600px"
append-to-body destroy-on-close>
<el-form label-width="90px">
<el-form-item label="角色名称" required>
<el-input v-model="dialog.name" placeholder="如 库房管理员" />
</el-form-item>
<el-form-item label="角色编码" required>
<el-input v-model="dialog.code" :disabled="!!dialog.editingId" placeholder="如 intro-manager(创建后不可改)" />
</el-form-item>
<el-form-item label="备注">
<el-input v-model="dialog.remark" placeholder="备注(可空)" />
</el-form-item>
<el-form-item label="权限设置">
<div class="perm-tree" v-loading="!perms.length">
<template v-if="perms.length">
<div class="perm-tip">勾选菜单=可见该菜单其下按钮勾选=可用该按钮勾选互不影响</div>
<el-tree ref="treeRef" :data="permTree" show-checkbox node-key="code"
check-strictly default-expand-all :props="{ label: 'label', children: 'children' }" />
</template>
<el-empty v-else description="暂无权限数据" :image-size="60" />
</div>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialog.show = false">取消</el-button>
<el-button type="primary" :loading="saving" @click="save">保存</el-button>
</template>
</el-dialog>
</div>
<PageHelp :data="helpRole" page="RoleManage" />
</template>
<script setup>
defineOptions({ name: 'RoleManage' })
import { computed, onMounted, reactive, ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import request from '../utils/request'
import { can } from '../utils/perm'
import PageHelp from '../components/PageHelp.vue'
import { helpRole } from '../help'
const loading = ref(false)
const roles = ref([])
const perms = ref([]) // 全部权限定义(MENU + BUTTON
const treeRef = ref()
const codeName = computed(() => {
const m = {}
for (const p of perms.value) m[p.code] = p.name
return m
})
// MES 无 parentCode:按钮码形如 菜单码:动作,父菜单 = 冒号前段(菜单码不含冒号)
const permTree = computed(() => {
const menus = perms.value.filter((p) => p.type === 'MENU')
const buttons = perms.value.filter((p) => p.type === 'BUTTON')
const nodes = menus.map((m) => ({
label: m.name,
code: m.code,
children: buttons
.filter((b) => b.code.startsWith(m.code + ':'))
.map((b) => ({ label: b.name, code: b.code }))
}))
const stray = buttons.filter((b) => !menus.some((m) => b.code.startsWith(m.code + ':')))
if (stray.length) {
nodes.push({ label: '通用', global: true, children: stray.map((b) => ({ label: b.name, code: b.code })) })
}
return nodes
})
function permCount(row) {
const codes = row.permissionCodes || []
if (row.code === 'SUPER_ADMIN') return codes
return codes.filter((c) => c !== '*').length
}
function permSummary(row) {
const codes = row.permissionCodes || []
if (codes.includes('*')) return '全部权限'
return codes.map((c) => codeName.value[c] || c).join('、') || '-'
}
async function loadRoles() {
loading.value = true
try {
roles.value = (await request.get('/roles')) || []
} finally {
loading.value = false
}
}
async function loadPerms() {
try {
perms.value = (await request.get('/permissions')) || []
} catch { /* 拦截器已提示 */ }
}
/* ---------- 新增 / 编辑 ---------- */
const dialog = reactive({ show: false, editingId: 0, name: '', code: '', remark: '', checked: [] })
const saving = ref(false)
function openCreate() {
Object.assign(dialog, { show: true, editingId: 0, name: '', code: '', remark: '', checked: [] })
}
function openEdit(row) {
Object.assign(dialog, {
show: true, editingId: row.id, name: row.name || '', code: row.code || '',
remark: row.remark || '', checked: [...(row.permissionCodes || [])]
})
// 弹窗打开待树渲染后回显
setTimeout(() => {
if (treeRef.value) treeRef.value.setCheckedKeys(dialog.checked)
}, 60)
}
function treeCheckedCodes() {
if (!treeRef.value) return dialog.checked
const keys = treeRef.value.getCheckedKeys() || []
return [...new Set(keys)]
}
async function save() {
if (!dialog.name.trim()) return ElMessage.warning('请输入角色名称')
if (!dialog.editingId && !dialog.code.trim()) return ElMessage.warning('请输入角色编码')
const payload = {
id: dialog.editingId,
name: dialog.name.trim(),
code: dialog.code.trim(),
remark: dialog.remark.trim() || undefined,
permissionCodes: treeCheckedCodes()
}
saving.value = true
try {
if (dialog.editingId) {
await request.put('/roles', payload)
ElMessage.success('保存成功')
} else {
await request.post('/roles', payload)
ElMessage.success('角色创建成功')
}
dialog.show = false
await loadRoles()
} finally {
saving.value = false
}
}
async function removeRole(row) {
try {
await ElMessageBox.confirm(`确定删除角色「${row.name}」?该角色下的用户将受影响。`, '删除确认', {
type: 'warning', confirmButtonText: '删除', cancelButtonText: '取消'
})
} catch {
return
}
try {
await request.delete(`/roles/${row.id}`)
ElMessage.success('已删除')
await loadRoles()
} catch { /* 拦截器已提示 */ }
}
onMounted(async () => {
await Promise.all([loadRoles(), loadPerms()])
})
</script>
<style scoped>
.mb12 { margin-bottom: 12px; }
.perm-tree { border: 1px solid #ebeef5; border-radius: 4px; padding: 12px; max-height: 360px; overflow: auto; }
.perm-tip { color: #909399; font-size: 12px; margin-bottom: 8px; }
</style>