Commit 8564e2f5 by 周海峰

用户管理

parent 45e60497
...@@ -63,7 +63,11 @@ export function saveKeyParams(data) { ...@@ -63,7 +63,11 @@ export function saveKeyParams(data) {
}) })
} }
/**
* 上传HSM配置
* @param {*} formData
* @returns
*/
export function uploadHsmConfig(formData) { export function uploadHsmConfig(formData) {
return request({ return request({
url: '/key/manager/uploadHsmConfig', url: '/key/manager/uploadHsmConfig',
...@@ -73,4 +77,86 @@ export function uploadHsmConfig(formData) { ...@@ -73,4 +77,86 @@ export function uploadHsmConfig(formData) {
'Content-Type': 'multipart/form-data' 'Content-Type': 'multipart/form-data'
} }
}) })
} }
\ No newline at end of file
/**
* 下载HSM配置
* @description 该方法用于下载HSM配置文件,通常用于测试或配置验证
* @param {Object} query - 查询参数,通常包含必要的配置或标识
* @returns {Promise} - 返回一个Promise对象,表示下载操作的结果
* @param {*} query
* @returns
*/
export function downloadHsmConfig(query) {
return request({
url: 'key/manager/downloadHsmConfig',
method: 'get',
params: query
})
}
/**
* 下载CloudHsm配置
* @description 该方法用于下载CloudHsm配置文件,通常用于测试或配置验证
* @param {Object} query - 查询参数,通常包含必要的配置或标识
* @returns {Promise} - 返回一个Promise对象,表示下载操作的结果
* @param {*} query
* @returns
*/
export function downloadCloudHsmConfig(query) {
return request({
url: 'key/manager/downloadCloudHsmConfig',
method: 'get',
params: query
})
}
/**
* 下载三维密管配置
* @description 该方法用于下载三维密管配置文件,通常用于测试或配置验证
* @param {Object} query - 查询参数,通常包含必要的配置或标识
* @returns {Promise} - 返回一个Promise对象,表示下载操作的结果
* @param {*} query
* @returns
*/
export function downloadSanWeiConfig(query) {
return request({
url: 'key/manager/downloadSanWeiConfig',
method: 'get',
params: query
})
}
/** * 上传三维密管配置
* @description 该方法用于上传三维密管配置文件,通常用于测试或配置验证
* @param {Object} formData - 包含文件数据的FormData对象
* @returns {Promise} - 返回一个Promise对象, 表示上传操作的结果
* @param {*} formData
* @returns
*/
export function uploadSanWeiConfig(formData) {
return request({
url: '/key/manager/uploadSanWeiConfig',
method: 'post',
data: formData,
headers: {
'Content-Type': 'multipart/form-data'
}
})
}
/** * 下载中电信密管配置
* @description 该方法用于下载中电信密管配置文件,通常用于测试或配置验证
* @param {Object} query - 查询参数,通常包含必要的配置或标识
* @returns {Promise} - 返回一个Promise对象,表示下载操作的结果
* @param {*} query
* @returns
*/
export function downloadZdxlzjceConfig(query) {
return request({
url: 'key/manager/downloadZdxlzjceConfig',
method: 'get',
params: query
})
}
import request from '@/utils/request'
import { parseStrEmpty } from "@/utils/ruoyi"
/**
* 组列表查询
* @param {} query
* @returns
*/
export function queryAll(query) {
return request({
url: '/console/usergroup/queryAll',
method: 'get',
params: query
})
}
\ No newline at end of file
import request from '@/utils/request'
import { parseStrEmpty } from "@/utils/ruoyi"
/**
* 菜单列表查询
* @param {*} query
* @returns
*/
export function queryAll(query) {
return request({
url: '/console/menu/queryAll',
method: 'get',
params: query
})
}
\ No newline at end of file
import request from '@/utils/request'
import { parseStrEmpty } from "@/utils/ruoyi"
/**
* 角色列表查询
* @param {*} query
* @returns
*/
export function queryAll(query) {
return request({
url: '/console/role/queryAll',
method: 'get',
params: query
})
}
\ No newline at end of file
import request from '@/utils/request'
import { parseStrEmpty } from "@/utils/ruoyi"
/**
* 用户列表查询
* @param {*} query
* @returns
*/
export function query(query) {
return request({
url: '/console/user/query',
method: 'get',
params: query
})
}
/**
* 用户编辑初始化
* @param {*} query
* @returns
*/
export function initEdit(query) {
return request({
url: '/console/user/initEdit',
method: 'get',
params: query
})
}
/**
* 添加用户
* @param {*} data
* @returns
*/
export function add(data) {
return request({
url: '/console/user/add',
method: 'post',
data: data
})
}
\ No newline at end of file
<template>
<div style="font-weight: bold; font-size: 16px; margin-top: 12px;margin-bottom: 12px;">权限设置</div>
<div>
<div class="permission-area">
<div class="all-select">
<el-checkbox :model-value="allSelected" @change="onAllChange">全选</el-checkbox>
</div>
<div class="permission-list">
<div v-for="(item, index) in permissionList" :key="index" class="permission-item">
<div class="permission-header" @click="item.children && item.children.length > 0 && toggleExpand(item)">
<div class="left">
<span class="expand-icon-placeholder">
<el-icon v-if="item.children && item.children.length > 0" class="expand-icon" :class="{ expanded: item.expanded }">
<component :is="item.expanded ? 'ArrowDown' : 'ArrowRight'" />
</el-icon>
</span>
<el-checkbox
v-model="item.selected"
:indeterminate="item.indeterminate"
@change="val => emit('permission-change', item, val)"
>
{{ item.name }}
</el-checkbox>
</div>
<div class="right">
<el-tag size="small" v-if="item.children && item.children.length > 0">{{ item.children.length }}</el-tag>
</div>
</div>
<div v-if="item.children" class="sub-permissions" v-show="item.expanded">
<el-checkbox
v-for="child in item.children"
:key="child.id"
v-model="child.selected"
@change="val => emit('sub-permission-change', item, child, val)"
>
{{ child.name }}
</el-checkbox>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, watch } from 'vue'
import { ArrowRight, ArrowDown } from '@element-plus/icons-vue'
// 定义组件名称
defineOptions({
name: 'PermissionArea'
})
// 定义props
const props = defineProps({
permissionList: {
type: Array,
required: true
},
allPermissionsSelected: {
type: Boolean,
required: true
}
})
// 定义emit
const emit = defineEmits(['update:allPermissionsSelected', 'permission-change', 'sub-permission-change'])
// 定义响应式数据
const allSelected = ref(props.allPermissionsSelected)
// 监听props变化
watch(() => props.allPermissionsSelected, (newVal) => {
allSelected.value = newVal
})
// 方法
const toggleExpand = (item) => {
item.expanded = !item.expanded
}
const onAllChange = (val) => {
allSelected.value = val
emit('update:allPermissionsSelected', val)
}
</script>
<style scoped>
.permission-area {
border: 1px solid #dcdfe6;
border-radius: 4px;
width: 100%;
display: flex;
flex-direction: column;
height: 350px;
overflow-y: auto;
}
.all-select {
padding: 2px 12px;
background-color: #f5f7fa;
border-bottom: 1px solid #dcdfe6;
}
.permission-list {
padding: 12px;
}
.permission-item {
border-bottom: 1px solid #ebeef5;
}
.permission-item:last-child {
border-bottom: none;
}
.permission-header {
display: flex;
align-items: center;
justify-content: flex-start;
padding: 5px 0;
cursor: pointer;
gap: 12px;
}
.permission-header .left {
display: flex;
align-items: center;
gap: 8px;
}
.sub-permissions {
padding: 5px 0 5px 32px;
display: flex;
flex-direction: column;
gap: 12px;
background-color: #f8f9fb;
border-top: 1px solid #ebeef5;
}
.sub-permissions .el-checkbox {
margin-left: 0 !important;
}
.expand-icon-placeholder {
display: inline-block;
min-width: 22px;
height: 22px;
vertical-align: middle;
}
.expand-icon {
min-width: 22px;
text-align: center;
display: inline-flex;
}
</style>
<template>
<div style="font-weight: bold; font-size: 16px; margin-bottom: 12px;">角色选择</div>
<div class="role-transfer">
<div class="transfer-list">
<div class="transfer-header">
<span>角色列表</span>
<span class="select-all-action" @click="handleSelectAllAction">全选</span>
</div>
<div class="role-list">
<div v-for="role in filteredRoles" :key="role.id" class="role-item" @click="handleRoleDirectSelect(role)">
{{ role.name }}
</div>
</div>
</div>
<div class="transfer-list">
<div class="transfer-header">
<span>已选择角色列表</span>
<el-button link type="primary" @click="clearSelected">清空</el-button>
</div>
<div class="selected-list">
<div v-for="role in selectedRoles" :key="role.id" class="role-item" @click="handleRoleRemove(role)">
{{ role.name }}
</div>
</div>
</div>
</div>
</template>
<script setup>
import { computed } from 'vue'
// 定义组件名称
defineOptions({
name: 'RoleTransfer'
})
// 定义props
const props = defineProps({
roles: {
type: Array,
required: true
},
selectedRoles: {
type: Array,
required: true
},
searchRole: {
type: String,
default: ''
}
})
// 定义emit
const emit = defineEmits(['update:roles', 'update:selectedRoles', 'update:searchRole'])
// 计算属性
const filteredRoles = computed(() => {
return props.roles.filter(role =>
role.name.toLowerCase().includes(props.searchRole.toLowerCase())
)
})
// 方法
const handleSelectAllAction = () => {
emit('update:selectedRoles', [...props.selectedRoles, ...props.roles])
emit('update:roles', [])
}
const handleRoleDirectSelect = (role) => {
emit('update:selectedRoles', [...props.selectedRoles, role])
emit('update:roles', props.roles.filter(r => r.id !== role.id))
}
const handleRoleRemove = (role) => {
emit('update:roles', [...props.roles, { ...role, selected: false }])
emit('update:selectedRoles', props.selectedRoles.filter(r => r.id !== role.id))
}
const clearSelected = () => {
emit('update:roles', [...props.roles, ...props.selectedRoles])
emit('update:selectedRoles', [])
}
</script>
<style scoped>
.role-transfer {
display: flex;
align-items: flex-start;
gap: 10px;
}
.transfer-list {
flex: 1;
border: 1px solid #dcdfe6;
border-radius: 4px;
height: 300px;
display: flex;
flex-direction: column;
width: 310px;
}
.transfer-header {
padding: 8px 12px;
border-bottom: 1px solid #dcdfe6;
display: flex;
justify-content: space-between;
align-items: center;
background-color: #f5f7fa;
}
.select-all-action {
color: #409EFF;
cursor: pointer;
font-size: 14px;
margin-left: 10px;
user-select: none;
transition: color 0.2s;
}
.select-all-action:hover {
color: #66b1ff;
}
.role-list, .selected-list {
flex: 1;
overflow-y: auto;
padding: 6px 0;
}
.role-item {
padding: 6px 12px;
cursor: pointer;
}
.role-item:hover {
background-color: #f5f7fa;
}
</style>
...@@ -16,14 +16,14 @@ ...@@ -16,14 +16,14 @@
<el-form-item label="私钥授权码" required> <el-form-item label="私钥授权码" required>
<div class="input-group"> <div class="input-group">
<el-input v-model="params.sdkpassword" type="password" placeholder="****" show-password style="width: 500px" :disabled="!editable" /> <el-input v-model="params.sdkpassword" type="password" placeholder="pass" show-password style="width: 500px" :disabled="!editable" />
<div class="tip-text">* SDKPassword: SM2加密私钥授权码</div> <div class="tip-text">* SDKPassword: SM2加密私钥授权码</div>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="配置文件" required> <el-form-item label="配置文件" required>
<div class="input-group"> <div class="input-group">
<el-input v-model="params.sdkPath" placeholder="/home/ghca/data/" style="width: 500px" :disabled="!editable" /> <el-input v-model="params.hsmfiledir" placeholder="/home/ghca/data/" style="width: 500px" :disabled="!editable" />
<div class="button-group"> <div class="button-group">
<el-button type="primary" @click="downloadTemplate">下载配置模板</el-button> <el-button type="primary" @click="downloadTemplate">下载配置模板</el-button>
<el-button type="primary" @click="uploadConfig">上传配置文件</el-button> <el-button type="primary" @click="uploadConfig">上传配置文件</el-button>
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
title="编辑用户" title="编辑用户"
:model-value="visible" :model-value="visible"
@update:model-value="$emit('update:visible', $event)" @update:model-value="$emit('update:visible', $event)"
width="800px" width="600px"
:close-on-click-modal="false" :close-on-click-modal="false"
append-to-body append-to-body
destroy-on-close destroy-on-close
...@@ -63,111 +63,54 @@ ...@@ -63,111 +63,54 @@
</el-form-item> </el-form-item>
<!-- 用户组 --> <!-- 用户组 -->
<el-form-item label="用户组" prop="userGroup"> <el-form-item label="用户组" prop="userGroup">
<el-select v-model="form.userGroup" placeholder="请选择"> <el-select v-model="userGroup" multiple placeholder="请选择">
<el-option <el-option
v-for="item in userGroupOptions" v-for="item in userGroupOptions"
:key="item.value" :key="item.value"
:label="item.label" :label="item.label"
:value="item.value" :value="item.value"
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<!-- 备注 --> <!-- 备注 -->
<el-form-item label="备注" prop="remark"> <el-form-item label="备注" prop="remark">
<el-input <el-input
v-model="form.remark" v-model="form.remark"
type="textarea"
placeholder="请输入备注" placeholder="请输入备注"
/> />
</el-form-item> </el-form-item>
<!-- 用户是否禁用 --> <!-- 用户是否禁用 -->
<el-form-item label="用户是否禁用"> <div style="display: flex; justify-content: flex-end; width: 100%;">
<el-switch v-model="form.isDisabled" /> <el-form-item label="用户是否禁用">
</el-form-item> <el-switch
v-model="form.isenable"
:active-value="0"
:inactive-value="1"
/>
</el-form-item>
</div>
</el-form>
<!-- 角色选择 --> <!-- 角色选择 -->
<el-form-item label="选择角色"> <RoleTransfer
<div class="role-transfer"> :roles="roles"
<div class="transfer-list"> :selectedRoles="selectedRoles"
<div class="transfer-header"> :searchRole="searchRole"
<span>角色列表</span> @update:roles="val => roles = val"
<el-checkbox v-model="allSelected" @change="handleSelectAll">全选</el-checkbox> @update:selectedRoles="val => selectedRoles = val"
</div> @update:searchRole="val => searchRole = val"
<el-input v-model="searchRole" placeholder="请输入搜索内容" /> />
<div class="role-list">
<div v-for="role in filteredRoles" :key="role.id" class="role-item">
<el-checkbox
v-model="role.selected"
@change="(val) => handleRoleSelect(role, val)"
>
{{ role.name }}
</el-checkbox>
</div>
</div>
</div>
<div class="transfer-operation">
<el-button type="primary" plain icon="ArrowRight" @click="addSelected" />
<el-button type="primary" plain icon="ArrowLeft" @click="removeSelected" />
</div>
<div class="transfer-list">
<div class="transfer-header">
<span>已选择角色列表</span>
<el-button link type="primary" @click="clearSelected">清空</el-button>
</div>
<div class="selected-list">
<div v-for="role in selectedRoles" :key="role.id" class="role-item">
{{ role.name }}
</div>
</div>
</div>
</div>
</el-form-item>
<!-- 权限设置 --> <!-- 权限设置 -->
<el-form-item label="权限设置"> <PermissionArea
<div class="permission-area"> :permissionList="permissionList"
<div class="all-select"> :allPermissionsSelected="allPermissionsSelected"
<el-checkbox v-model="allPermissionsSelected" @change="handleAllPermissionsChange">全选</el-checkbox> @update:allPermissionsSelected="val => allPermissionsSelected = val"
</div> @permission-change="handlePermissionChange"
<div class="permission-list"> @sub-permission-change="handleSubPermissionChange"
<div v-for="(item, index) in permissionList" :key="index" class="permission-item"> />
<!-- 父级权限项 -->
<div class="permission-header" @click="toggleExpand(item)">
<div class="left">
<el-icon class="expand-icon" :class="{ expanded: item.expanded }">
<ArrowRight />
</el-icon>
<el-checkbox
v-model="item.selected"
:indeterminate="item.indeterminate"
@change="(val) => handlePermissionChange(item, val)"
>
{{ item.name }}
</el-checkbox>
</div>
<div class="right">
<el-tag size="small" v-if="item.children">{{ item.children.length }}</el-tag>
</div>
</div>
<!-- 子级权限列表 -->
<div v-if="item.children" class="sub-permissions" v-show="item.expanded">
<el-checkbox
v-for="child in item.children"
:key="child.id"
v-model="child.selected"
@change="(val) => handleSubPermissionChange(item, child, val)"
>
{{ child.name }}
</el-checkbox>
</div>
</div>
</div>
</div>
</el-form-item>
</el-form>
</div> </div>
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
...@@ -180,259 +123,301 @@ ...@@ -180,259 +123,301 @@
</el-dialog> </el-dialog>
</template> </template>
<script> <script setup>
export default { import { ref, reactive, computed, watch, getCurrentInstance } from 'vue'
name: 'UserEdit', import { query, initEdit, add } from '@/api/safetyManagement/userConfig.js'
props: { import { queryAll as queryAllRole } from '@/api/safetyManagement/roleConfig.js'
visible: { import { queryAll as queryAllGroup } from '@/api/safetyManagement/groupConfig.js'
type: Boolean, import { queryAll as queryAllMenu } from '@/api/safetyManagement/menuConfig.js'
default: false import RoleTransfer from '@/components/RoleTransfer/index.vue'
}, import PermissionArea from '@/components/PermissionArea/index.vue'
formData: {
type: Object, // 定义组件名称
default: () => null defineOptions({
} name: 'UserEdit'
}, })
emits: ['update:visible', 'success'],
watch: { // 定义props和emit
visible(val) { const props = defineProps({
if (val && this.formData) { visible: {
this.form = { type: Boolean,
...this.formData, default: false
password: '',
confirmPassword: ''
}
}
}
}, },
data() { formData: {
// 密码验证 type: Object,
const validatePassword = (rule, value, callback) => { default: () => null
if (value === '') { }
callback(new Error('请输入密码')) })
} else {
if (this.form.confirmPassword !== '') { const emit = defineEmits(['update:visible', 'success'])
this.$refs.formRef.validateField('confirmPassword')
} // 表单引用
callback() const formRef = ref(null)
}
// 响应式数据
const form = reactive({
id: null,
realname: '',
username: '',
password: '',
confirmPassword: '',
email: '',
remark: '',
isenable: 1,
groupList: [],
rolesList: [],
menuList: []
})
const userGroup = ref([]) // 用户组
const userGroupOptions = ref([])
const searchRole = ref('')
const roles = ref([])
const selectedRoles = ref([])
const allPermissionsSelected = ref(false)
const permissionList = ref([])
const instance = getCurrentInstance()
// 表单校验规则
const validatePassword = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入密码'))
} else {
if (form.confirmPassword !== '') {
formRef.value.validateField('confirmPassword')
} }
// 确认密码验证 callback()
const validateConfirmPassword = (rule, value, callback) => { }
if (value === '') { }
callback(new Error('请再次输入密码'))
} else if (value !== this.form.password) { const validateConfirmPassword = (rule, value, callback) => {
callback(new Error('两次输入密码不一致!')) if (value === '') {
} else { callback(new Error('请再次输入密码'))
callback() } else if (value !== form.password) {
callback(new Error('两次输入密码不一致!'))
} else {
callback()
}
}
const rules = {
realname: [
{ required: true, message: '请输入真实姓名', trigger: 'blur' }
],
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' }
],
password: [
{ required: true, validator: validatePassword, trigger: 'blur' }
],
confirmPassword: [
{ required: true, validator: validateConfirmPassword, trigger: 'blur' }
],
email: [
{ required: false, message: '请输入邮箱', trigger: 'blur' },
{ type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur' }
]
}
// 监听visible变化
watch(() => props.visible, (val) => {
if (val && props.formData && props.formData.id) {
// 弹窗打开且有id时,拉取用户详情和相关数据
initEditData(props.formData.id)
} else {
// 新增,只需查询角色、用户组、菜单权限
Promise.all([
queryAllRole(),
queryAllGroup(),
queryAllMenu()
]).then(([roleRes, groupRes, menuRes]) => {
// 用户组
userGroupOptions.value = (groupRes.data || []).map(g => ({ value: g.id, label: g.groupname }))
// 角色
roles.value = (roleRes.data || []).map(r => ({
id: r.id,
name: r.rolename || r.name || '',
selected: false
}))
selectedRoles.value = []
// 权限
function mapMenu(menuArr) {
return (menuArr || []).filter(item => item.type !== '3' || item.type === 1).map(item => {
const hasChildren = Array.isArray(item.children) && item.children.length > 0
let children = hasChildren ? mapMenu(item.children) : null
return {
id: item.id,
name: item.type === '2'? '项目管理-'+item.name : item.name,
selected: false,
indeterminate: false,
expanded: false,
children
}
})
} }
} permissionList.value = mapMenu(menuRes.data)
})
}
})
return { // 初始化编辑数据
form: { const initEditData = async (id) => {
realname: '', // 1. 查询用户详情
username: '', const userRes = await initEdit({ userId: id })
password: '', userGroup.value = userRes.data.groupList ? userRes.data.groupList.map(g => g.id) : []
confirmPassword: '', // 2. 查询角色、用户组、菜单权限
email: '', const [roleRes, groupRes, menuRes] = await Promise.all([
userGroup: '', queryAllRole(),
remark: '', queryAllGroup(),
isDisabled: false queryAllMenu()
}, ])
rules: { // 3. 数据匹配
realname: [ Object.assign(form, {
{ required: true, message: '请输入真实姓名', trigger: 'blur' } ...userRes.data,
], confirmPassword: userRes.data.password
username: [ })
{ required: true, message: '请输入用户名', trigger: 'blur' } // 用户组
], userGroupOptions.value = (groupRes.data || []).map(g => ({ value: g.id, label: g.groupname }))
password: [ // 未选中角色
{ required: true, validator: validatePassword, trigger: 'blur' } roles.value = roleRes.data
], .filter(r => !(userRes.data.rolesList.map(m => m.id) || []).includes(r.id))
confirmPassword: [ .map(r => ({
{ required: true, validator: validateConfirmPassword, trigger: 'blur' } id: r.id,
], name: r.rolename || r.name || ''
email: [ }))
{ required: true, message: '请输入邮箱', trigger: 'blur' }, // 选中的角色
{ type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur' } selectedRoles.value = roleRes.data
] .filter(r => (userRes.data.rolesList.map(m => m.id) || []).includes(r.id))
}, .map(r => ({
userGroupOptions: [ id: r.id,
{ value: 'admin', label: '管理员' }, name: r.rolename || r.name || ''
{ value: 'user', label: '普通用户' } }))
], // 权限
allSelected: false, function mapMenu(menuArr, selectedIds = []) {
searchRole: '', return (menuArr || []).filter(item => item.type !== '3' || item.type === 1).map(item => {
roles: [ const hasChildren = Array.isArray(item.children) && item.children.length > 0
{ id: 1, name: '系统管理员', selected: false }, let children = hasChildren ? mapMenu(item.children, selectedIds) : null
{ id: 2, name: '2222', selected: false } let selected = selectedIds.includes(item.id)
], let indeterminate = false
selectedRoles: [], if (hasChildren) {
allPermissionsSelected: false, const selectedCount = children.filter(c => c.selected).length
permissionList: [ if (selectedCount === 0) {
{ selected = false
id: 1, indeterminate = false
name: '管理首页', } else if (selectedCount === children.length) {
selected: false, selected = true
expanded: false, indeterminate = false
indeterminate: false } else {
}, selected = false
{ indeterminate = true
id: 2,
name: '项目管理',
selected: false,
expanded: false
},
{
id: 3,
name: '规则管理',
selected: false,
children: [
{ id: '3-1', name: '规则管理子项1', selected: false },
{ id: '3-2', name: '规则管理子项2', selected: false }
]
},
{
id: 4,
name: '资产库',
selected: false
},
{
id: 5,
name: '系统设置',
selected: false,
children: [
{ id: '5-1', name: '设置子项1', selected: false },
{ id: '5-2', name: '设置子项2', selected: false }
]
},
{
id: 6,
name: '用户管理',
selected: false,
children: [
{ id: '6-1', name: '用户管理子项1', selected: false },
{ id: '6-2', name: '用户管理子项2', selected: false }
]
} }
]
}
},
computed: {
filteredRoles() {
return this.roles.filter(role =>
role.name.toLowerCase().includes(this.searchRole.toLowerCase())
)
}
},
methods: {
handleClose() {
this.$emit('update:visible', false)
this.$refs.formRef?.resetFields()
this.form = {
realname: '',
username: '',
password: '',
confirmPassword: '',
email: '',
userGroup: '',
remark: '',
isDisabled: false
} }
}, return {
handleSubmit() { id: item.id,
this.$refs.formRef.validate((valid) => { name: item.type === '2'? '项目管理-'+item.name : item.name,
if (valid) { selected,
// 提交表单逻辑 indeterminate,
const params = { ...this.form } expanded: false,
// 如果是编辑模式且没有修改密码,则不提交密码字段 children
if (this.formData && !params.password) { }
delete params.password })
delete params.confirmPassword }
permissionList.value = mapMenu(menuRes.data, userRes.data.menuList ? userRes.data.menuList.map(m => m.id) : [])
}
// 关闭弹窗
const handleClose = () => {
emit('update:visible', false)
formRef.value?.resetFields()
Object.assign(form, {
realname: '',
username: '',
password: '',
confirmPassword: '',
email: '',
userGroup: [],
remark: '',
isenable: 1
})
}
// 提交表单
const handleSubmit = () => {
formRef.value.validate((valid) => {
if (valid) {
// 提交表单逻辑
const params = { ...form }
// 选中的角色和分组和权限
params.rolesList = selectedRoles.value.map(r => ({id :r.id}))
params.groupList = userGroup.value.map(g => ({ id: g }))
const selectedMenuIds = []
function collectSelectedMenus(menus) {
menus.forEach(menu => {
if (menu.selected) {
selectedMenuIds.push(menu.id)
}
if (menu.children && menu.children.length > 0) {
collectSelectedMenus(menu.children)
} }
console.log('submit form', params)
// 调用接口保存数据
this.$emit('success')
this.handleClose()
}
})
},
handleSelectAll(val) {
this.roles.forEach(role => {
role.selected = val
})
},
handleRoleSelect(role, val) {
role.selected = val
this.allSelected = this.roles.every(role => role.selected)
},
addSelected() {
const selectedRoles = this.roles.filter(role => role.selected)
this.selectedRoles = [...new Set([...this.selectedRoles, ...selectedRoles])]
this.roles = this.roles.filter(role => !role.selected)
this.allSelected = false
},
removeSelected() {
this.roles = [...this.roles, ...this.selectedRoles]
this.selectedRoles = []
},
clearSelected() {
this.roles = [...this.roles, ...this.selectedRoles]
this.selectedRoles = []
},
// 权限相关方法
handleAllPermissionsChange(val) {
// 处理全选
this.permissionList.forEach(item => {
item.selected = val
if (item.children) {
item.children.forEach(child => {
child.selected = val
})
}
})
},
handlePermissionChange(item, val) {
// 处理父级权限选择
item.selected = val
item.indeterminate = false // 清除半选状态
if (item.children) {
item.children.forEach(child => {
child.selected = val
}) })
} }
this.checkAllPermissionsStatus() collectSelectedMenus(permissionList.value)
}, params.menuList = selectedMenuIds.map(id => ({ id }))
handleSubPermissionChange(parent, child, val) {
// 处理子级权限选择 console.log('submit form', params)
child.selected = val add(params).then(res => {
// 检查父级状态 if (res.code === 'POP_00014') {
if (parent.children) { instance.appContext.config.globalProperties.$modal.msgSuccess('保存成功')
// 如果所有子项都选中,父级完全选中 emit('success')
const allSelected = parent.children.every(c => c.selected) handleClose()
// 如果部分子项选中,父级半选 } else {
const someSelected = parent.children.some(c => c.selected) instance.appContext.config.globalProperties.$modal.msgError(res.msg || '保存失败')
parent.selected = allSelected
parent.indeterminate = !allSelected && someSelected
}
this.checkAllPermissionsStatus()
},
checkAllPermissionsStatus() {
// 检查是否全部选中
this.allPermissionsSelected = this.permissionList.every(item => {
if (item.children) {
return item.selected && item.children.every(child => child.selected)
} }
return item.selected }).catch(() => {
instance.appContext.config.globalProperties.$modal.msgError('保存异常')
}) })
}, // 调用接口保存数据
toggleExpand(item) { emit('success')
// 展开/收起子菜单 handleClose()
item.expanded = !item.expanded
} }
})
}
// 处理权限选择
const handlePermissionChange = (item, val) => {
item.selected = val
item.indeterminate = false // 清除半选状态
if (item.children) {
item.children.forEach(child => {
child.selected = val
})
}
checkAllPermissionsStatus()
}
const handleSubPermissionChange = (parent, child, val) => {
child.selected = val
// 检查父级状态
if (parent.children) {
// 如果所有子项都选中,父级完全选中
const allSelected = parent.children.every(c => c.selected)
// 如果部分子项选中,父级半选
const someSelected = parent.children.some(c => c.selected)
parent.selected = allSelected
parent.indeterminate = !allSelected && someSelected
} }
checkAllPermissionsStatus()
}
const checkAllPermissionsStatus = () => {
allPermissionsSelected.value = permissionList.value.every(item => {
if (item.children) {
return item.selected && item.children.every(child => child.selected)
}
return item.selected
})
} }
</script> </script>
...@@ -449,6 +434,7 @@ export default { ...@@ -449,6 +434,7 @@ export default {
height: 300px; height: 300px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 310px;
.transfer-header { .transfer-header {
padding: 8px 12px; padding: 8px 12px;
...@@ -457,6 +443,18 @@ export default { ...@@ -457,6 +443,18 @@ export default {
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
background-color: #f5f7fa; background-color: #f5f7fa;
.select-all-action {
color: #409EFF;
cursor: pointer;
font-size: 14px;
margin-left: 10px;
user-select: none;
transition: color 0.2s;
&:hover {
color: #66b1ff;
cursor: pointer;
}
}
} }
.role-list, .selected-list { .role-list, .selected-list {
...@@ -489,9 +487,11 @@ export default { ...@@ -489,9 +487,11 @@ export default {
width: 100%; width: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 350px;
overflow-y: auto;
.all-select { .all-select {
padding: 8px 12px; padding: 2px 12px;
background-color: #f5f7fa; background-color: #f5f7fa;
border-bottom: 1px solid #dcdfe6; border-bottom: 1px solid #dcdfe6;
} }
...@@ -509,34 +509,26 @@ export default { ...@@ -509,34 +509,26 @@ export default {
.permission-header { .permission-header {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: flex-start;
padding: 12px 0; padding: 5px 0;
cursor: pointer; cursor: pointer;
gap: 12px;
.left { .left {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px; gap: 8px;
.expand-icon {
transition: transform 0.3s;
font-size: 12px;
color: #909399;
&.expanded {
transform: rotate(90deg);
}
}
} }
} }
.sub-permissions { .sub-permissions {
padding: 8px 0 8px 32px; padding: 5px 0 5px 32px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 12px; gap: 12px;
background-color: #f8f9fb; background-color: #f8f9fb;
border-top: 1px solid #ebeef5; border-top: 1px solid #ebeef5;
.el-checkbox {
margin-left: 0 !important;
}
} }
} }
} }
...@@ -586,4 +578,15 @@ export default { ...@@ -586,4 +578,15 @@ export default {
} }
} }
.permission-header .expand-icon-placeholder {
display: inline-block;
min-width: 22px;
height: 22px;
vertical-align: middle;
}
.permission-header .expand-icon {
min-width: 22px;
text-align: center;
display: inline-flex;
}
</style> </style>
...@@ -62,7 +62,9 @@ ...@@ -62,7 +62,9 @@
<!-- 分页 --> <!-- 分页 -->
<div class="pagination"> <div class="pagination">
<div class="pagination-info">共有记录 1条,每页显示 8条,共 1页</div> <div class="pagination-info">
共有记录 {{ total }} 条,每页显示 {{ pageSize }} 条,共 {{ Math.max(1, Math.ceil(total / pageSize)) }}
</div>
<el-pagination <el-pagination
background background
layout="prev, pager, next, jumper" layout="prev, pager, next, jumper"
...@@ -82,72 +84,98 @@ ...@@ -82,72 +84,98 @@
</div> </div>
</template> </template>
<script> <script setup>
import { ref, reactive, onMounted, getCurrentInstance } from 'vue'
import { ElMessageBox } from 'element-plus'
import { User } from '@element-plus/icons-vue'
import UserEdit from './edit.vue' import UserEdit from './edit.vue'
import { query } from '@/api/safetyManagement/userConfig.js'
export default { // 定义组件名称
name: 'UserConfig', defineOptions({
components: { name: 'UserConfig'
UserEdit })
},
data() { // 响应式数据
return { const searchForm = reactive({
searchForm: { name: '',
name: '', username: '',
username: '', remark: ''
remark: '' })
}, const userList = ref([])
userList: [ const total = ref(1)
{ const currentPage = ref(1)
realname: 'admin', const pageSize = ref(8)
username: 'admin', const editVisible = ref(false)
remark: '' const editData = ref(null)
} const instance = getCurrentInstance()
],
total: 1, // 获取用户列表
currentPage: 1, const getList = async () => {
pageSize: 8, const params = {
editVisible: false, ...searchForm,
editData: null pageno: currentPage.value,
} pagesize: pageSize.value
}, }
methods: { try {
handleSearch() { const res = await query(params)
// 实现搜索逻辑 if (res.code === 'POP_00014') {
}, userList.value = res.data.list || []
handleAdd() { total.value = res.data.total || 0
// 打开新增用户弹窗 } else {
this.editData = null const modal = instance?.appContext.config.globalProperties.$modal
this.editVisible = true modal && modal.msgError ? modal.msgError(res.msg || '查询失败') : alert(res.msg || '查询失败')
},
handlePageChange(page) {
// 实现分页逻辑
},
handleDelete(row) {
// 实现删除用户逻辑
this.$confirm('确认删除该用户吗?', '提示', {
type: 'warning'
}).then(() => {
// 调用删除接口
console.log('删除用户', row)
}).catch(() => {})
},
handleEdit(row) {
// 打开编辑用户弹窗
this.editData = { ...row }
this.editVisible = true
},
handleEditSuccess() {
// 编辑成功后的回调
this.editVisible = false
// 刷新列表数据
this.getList()
},
getList() {
// 获取用户列表数据
} }
} catch (e) {
const modal = instance?.appContext.config.globalProperties.$modal
modal && modal.msgError ? modal.msgError('查询异常') : alert('查询异常')
} }
} }
// 处理搜索
const handleSearch = () => {
currentPage.value = 1
getList()
}
// 添加用户
const handleAdd = () => {
editData.value = null
editVisible.value = true
}
// 分页变化
const handlePageChange = (page) => {
currentPage.value = page
getList()
}
// 删除用户
const handleDelete = (row) => {
ElMessageBox.confirm('确认删除该用户吗?', '提示', {
type: 'warning'
}).then(() => {
// 调用删除接口
console.log('删除用户', row)
}).catch(() => {})
}
// 编辑用户
const handleEdit = async (row) => {
editData.value = { id: row.id }
editVisible.value = true
}
// 编辑成功回调
const handleEditSuccess = () => {
editVisible.value = false
getList()
}
// 页面挂载时获取数据
onMounted(() => {
getList()
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论