diff --git a/gofaster/app/dist/renderer/js/index.js b/gofaster/app/dist/renderer/js/index.js index 9c2501f..8a8c658 100644 --- a/gofaster/app/dist/renderer/js/index.js +++ b/gofaster/app/dist/renderer/js/index.js @@ -1603,6 +1603,333 @@ input[type="checkbox"][data-v-de6ba976] { /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___); +/***/ }), + +/***/ "./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/modules/role-management/components/RolePermissionAssignment.vue?vue&type=style&index=0&id=91c1b50a&scoped=true&lang=css": +/*!*********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/modules/role-management/components/RolePermissionAssignment.vue?vue&type=style&index=0&id=91c1b50a&scoped=true&lang=css ***! + \*********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ +/***/ ((module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../../../../node_modules/css-loader/dist/runtime/noSourceMaps.js */ "./node_modules/css-loader/dist/runtime/noSourceMaps.js"); +/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../../../../node_modules/css-loader/dist/runtime/api.js */ "./node_modules/css-loader/dist/runtime/api.js"); +/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__); +// Imports + + +var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default())); +// Module +___CSS_LOADER_EXPORT___.push([module.id, ` +.role-permission-assignment[data-v-91c1b50a] { + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; +} +.large-modal[data-v-91c1b50a] { + width: 90%; + max-width: 1200px; + height: 80vh; + max-height: 800px; +} +.modal-overlay[data-v-91c1b50a] { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.5); + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; +} +.modal[data-v-91c1b50a] { + background: white; + border-radius: 8px; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15); + display: flex; + flex-direction: column; + max-height: 90vh; +} +.modal-header[data-v-91c1b50a] { + display: flex; + justify-content: space-between; + align-items: center; + padding: 20px 24px; + border-bottom: 1px solid #e5e7eb; + background: #f9fafb; + border-radius: 8px 8px 0 0; +} +.modal-header h3[data-v-91c1b50a] { + margin: 0; + color: #1f2937; + font-size: 18px; + font-weight: 600; +} +.close-btn[data-v-91c1b50a] { + background: none; + border: none; + font-size: 18px; + cursor: pointer; + color: #6b7280; + padding: 4px; + border-radius: 4px; + transition: all 0.2s; +} +.close-btn[data-v-91c1b50a]:hover { + background: #e5e7eb; + color: #374151; +} +.modal-body[data-v-91c1b50a] { + flex: 1; + padding: 24px; + overflow-y: auto; +} +.modal-footer[data-v-91c1b50a] { + display: flex; + justify-content: flex-end; + gap: 12px; + padding: 20px 24px; + border-top: 1px solid #e5e7eb; + background: #f9fafb; + border-radius: 0 0 8px 8px; +} +.loading[data-v-91c1b50a] { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 40px; + color: #6b7280; +} +.loading i[data-v-91c1b50a] { + font-size: 24px; + margin-bottom: 12px; +} +.role-info[data-v-91c1b50a] { + margin-bottom: 24px; + padding: 16px; + background: #f8fafc; + border-radius: 8px; + border: 1px solid #e2e8f0; +} +.role-details h4[data-v-91c1b50a] { + margin: 0 0 8px 0; + color: #1e293b; + font-size: 16px; + font-weight: 600; +} +.role-description[data-v-91c1b50a] { + margin: 0 0 12px 0; + color: #64748b; + font-size: 14px; +} +.role-stats[data-v-91c1b50a] { + display: flex; + gap: 16px; +} +.stat-item[data-v-91c1b50a] { + display: flex; + align-items: center; + gap: 6px; + color: #475569; + font-size: 14px; +} +.stat-item i[data-v-91c1b50a] { + color: #3b82f6; +} +.permission-assignment[data-v-91c1b50a] { + border: 1px solid #e2e8f0; + border-radius: 8px; + overflow: hidden; +} +.assignment-tabs[data-v-91c1b50a] { + display: flex; + background: #f1f5f9; + border-bottom: 1px solid #e2e8f0; +} +.tab-btn[data-v-91c1b50a] { + flex: 1; + padding: 12px 16px; + background: none; + border: none; + cursor: pointer; + font-size: 14px; + font-weight: 500; + color: #64748b; + transition: all 0.2s; + display: flex; + align-items: center; + justify-content: center; + gap: 8px; +} +.tab-btn.active[data-v-91c1b50a] { + background: white; + color: #3b82f6; + border-bottom: 2px solid #3b82f6; +} +.tab-btn[data-v-91c1b50a]:hover:not(.active) { + background: #e2e8f0; + color: #475569; +} +.permission-list[data-v-91c1b50a] { + padding: 20px; +} +.list-header[data-v-91c1b50a] { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 16px; +} +.list-header h5[data-v-91c1b50a] { + margin: 0; + color: #1e293b; + font-size: 16px; + font-weight: 600; +} +.list-actions[data-v-91c1b50a] { + display: flex; + gap: 8px; +} +.empty-state[data-v-91c1b50a] { + text-align: center; + padding: 40px 20px; + color: #64748b; +} +.empty-state i[data-v-91c1b50a] { + font-size: 48px; + margin-bottom: 16px; + opacity: 0.5; +} +.empty-state p[data-v-91c1b50a] { + margin: 0; + font-size: 14px; +} +.permission-items[data-v-91c1b50a] { + display: flex; + flex-direction: column; + gap: 8px; +} +.permission-item[data-v-91c1b50a] { + display: flex; + align-items: center; + padding: 12px; + border: 1px solid #e2e8f0; + border-radius: 6px; + cursor: pointer; + transition: all 0.2s; + background: white; +} +.permission-item[data-v-91c1b50a]:hover { + border-color: #3b82f6; + box-shadow: 0 2px 4px rgba(59, 130, 246, 0.1); +} +.permission-item.selected[data-v-91c1b50a] { + border-color: #3b82f6; + background: #eff6ff; +} +.permission-checkbox[data-v-91c1b50a] { + margin-right: 12px; +} +.permission-checkbox input[type="checkbox"][data-v-91c1b50a] { + width: 16px; + height: 16px; + cursor: pointer; +} +.permission-info[data-v-91c1b50a] { + flex: 1; +} +.permission-name[data-v-91c1b50a] { + font-weight: 500; + color: #1e293b; + margin-bottom: 4px; +} +.permission-details[data-v-91c1b50a] { + display: flex; + gap: 12px; + margin-bottom: 4px; +} +.permission-code[data-v-91c1b50a] { + font-family: 'Courier New', monospace; + font-size: 12px; + color: #64748b; + background: #f1f5f9; + padding: 2px 6px; + border-radius: 4px; +} +.permission-resource[data-v-91c1b50a] { + font-size: 12px; + color: #8b5cf6; + background: #f3f4f6; + padding: 2px 6px; + border-radius: 4px; +} +.permission-description[data-v-91c1b50a] { + font-size: 12px; + color: #64748b; + line-height: 1.4; +} +.permission-actions[data-v-91c1b50a] { + margin-left: 12px; +} +.btn[data-v-91c1b50a] { + padding: 6px 12px; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 12px; + font-weight: 500; + transition: all 0.2s; + display: inline-flex; + align-items: center; + gap: 4px; +} +.btn-sm[data-v-91c1b50a] { + padding: 4px 8px; + font-size: 11px; +} +.btn-primary[data-v-91c1b50a] { + background: #3b82f6; + color: white; +} +.btn-primary[data-v-91c1b50a]:hover:not(:disabled) { + background: #2563eb; +} +.btn-primary[data-v-91c1b50a]:disabled { + background: #9ca3af; + cursor: not-allowed; +} +.btn-danger[data-v-91c1b50a] { + background: #ef4444; + color: white; +} +.btn-danger[data-v-91c1b50a]:hover:not(:disabled) { + background: #dc2626; +} +.btn-danger[data-v-91c1b50a]:disabled { + background: #9ca3af; + cursor: not-allowed; +} +.btn-secondary[data-v-91c1b50a] { + background: #6b7280; + color: white; +} +.btn-secondary[data-v-91c1b50a]:hover:not(:disabled) { + background: #4b5563; +} +.btn-secondary[data-v-91c1b50a]:disabled { + background: #9ca3af; + cursor: not-allowed; +} +`, ""]); +// Exports +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___); + + /***/ }), /***/ "./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/modules/role-management/components/UserRoleAssignment.vue?vue&type=style&index=0&id=7f7c6d92&scoped=true&lang=css": @@ -1953,6 +2280,9 @@ th[data-v-03643bfa] { .actions .btn-sm.btn-danger[data-v-03643bfa]:hover { color: #d32f2f; } +.actions .btn-sm.btn-warning[data-v-03643bfa]:hover { + color: #ff9800; +} .btn[data-v-03643bfa]:hover { opacity: 0.9; } @@ -4684,32 +5014,62 @@ __webpack_require__.r(__webpack_exports__); try { console.log('🧹 开始清理缓存...') - // 清理localStorage - const keysToClear = [ - 'gofaster-settings', - 'isLoggedIn', - 'token', - 'user', - 'app-settings', - 'theme-settings', - 'user-preferences' - ] - - keysToClear.forEach(key => { - if (localStorage.getItem(key)) { - localStorage.removeItem(key) - console.log('✅ 已清理localStorage键:', key) - } - }) + // 询问用户是否要清理用户设置 + const clearSettings = confirm('是否要清理用户设置?\n\n选择"确定"将清理所有设置(包括主题、记住密码等)\n选择"取消"将保留用户设置,只清理其他缓存') - // 清理所有以gofaster开头的键 - const allKeys = Object.keys(localStorage) - allKeys.forEach(key => { - if (key.startsWith('gofaster') || key.startsWith('electron')) { - localStorage.removeItem(key) - console.log('✅ 已清理localStorage键:', key) - } - }) + if (clearSettings) { + // 清理所有localStorage + const keysToClear = [ + 'gofaster-settings', + 'isLoggedIn', + 'token', + 'user', + 'app-settings', + 'theme-settings', + 'user-preferences' + ] + + keysToClear.forEach(key => { + if (localStorage.getItem(key)) { + localStorage.removeItem(key) + console.log('✅ 已清理localStorage键:', key) + } + }) + + // 清理所有以gofaster开头的键 + const allKeys = Object.keys(localStorage) + allKeys.forEach(key => { + if (key.startsWith('gofaster') || key.startsWith('electron')) { + localStorage.removeItem(key) + console.log('✅ 已清理localStorage键:', key) + } + }) + } else { + // 只清理非设置相关的缓存 + const keysToClear = [ + 'isLoggedIn', + 'token', + 'user', + 'app-settings', + 'theme-settings' + ] + + keysToClear.forEach(key => { + if (localStorage.getItem(key)) { + localStorage.removeItem(key) + console.log('✅ 已清理localStorage键:', key) + } + }) + + // 清理以electron开头的键,但保留gofaster-settings + const allKeys = Object.keys(localStorage) + allKeys.forEach(key => { + if (key.startsWith('electron')) { + localStorage.removeItem(key) + console.log('✅ 已清理localStorage键:', key) + } + }) + } // 通过IPC清理Electron缓存 if (window.electronAPI && window.electronAPI.clearElectronCache) { @@ -4832,39 +5192,8 @@ __webpack_require__.r(__webpack_exports__); } ;(0,vue__WEBPACK_IMPORTED_MODULE_0__.onMounted)(() => { - // 清理localStorage以修复缓存问题 - try { - console.log('🔧 开始清理localStorage...') - const keysToClear = [ - 'gofaster-settings', - 'isLoggedIn', - 'token', - 'user', - 'app-settings', - 'theme-settings', - 'user-preferences' - ] - - keysToClear.forEach(key => { - if (localStorage.getItem(key)) { - localStorage.removeItem(key) - console.log('✅ 已清理localStorage键:', key) - } - }) - - // 清理所有以gofaster开头的键 - const allKeys = Object.keys(localStorage) - allKeys.forEach(key => { - if (key.startsWith('gofaster') || key.startsWith('electron')) { - localStorage.removeItem(key) - console.log('✅ 已清理localStorage键:', key) - } - }) - - console.log('✅ localStorage清理完成') - } catch (error) { - console.error('❌ 清理localStorage失败:', error) - } + // 不再自动清理localStorage,保留用户设置 + console.log('🔧 应用启动,保留用户设置...') // 初始化收藏菜单 updateFavoriteMenu() @@ -5786,6 +6115,238 @@ __webpack_require__.r(__webpack_exports__); }); +/***/ }), + +/***/ "./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/modules/role-management/components/RolePermissionAssignment.vue?vue&type=script&lang=js": +/*!*************************************************************************************************************************************************************************!*\ + !*** ./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/modules/role-management/components/RolePermissionAssignment.vue?vue&type=script&lang=js ***! + \*************************************************************************************************************************************************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ "./node_modules/vue/dist/vue.runtime.esm-bundler.js"); +/* harmony import */ var _services_roleService_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../services/roleService.js */ "./src/renderer/modules/role-management/services/roleService.js"); + + + + +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({ + name: 'RolePermissionAssignment', + props: { + modelValue: { + type: Boolean, + default: false + }, + role: { + type: Object, + default: null + } + }, + emits: ['update:modelValue', 'permissions-updated'], + setup(props, { emit }) { + const visible = (0,vue__WEBPACK_IMPORTED_MODULE_0__.ref)(false) + const loading = (0,vue__WEBPACK_IMPORTED_MODULE_0__.ref)(false) + const currentRole = (0,vue__WEBPACK_IMPORTED_MODULE_0__.ref)(null) + const allPermissions = (0,vue__WEBPACK_IMPORTED_MODULE_0__.ref)([]) + const assignedPermissions = (0,vue__WEBPACK_IMPORTED_MODULE_0__.ref)([]) + const selectedAssignedPermissions = (0,vue__WEBPACK_IMPORTED_MODULE_0__.ref)([]) + const selectedAvailablePermissions = (0,vue__WEBPACK_IMPORTED_MODULE_0__.ref)([]) + const activeTab = (0,vue__WEBPACK_IMPORTED_MODULE_0__.ref)('assigned') + + // 计算可分配权限 + const availablePermissions = (0,vue__WEBPACK_IMPORTED_MODULE_0__.computed)(() => { + const assignedIds = assignedPermissions.value.map(p => p.id) + return allPermissions.value.filter(p => !assignedIds.includes(p.id)) + }) + + // 监听visible变化 + ;(0,vue__WEBPACK_IMPORTED_MODULE_0__.watch)(() => props.modelValue, (newVal) => { + visible.value = newVal + if (newVal && props.role) { + currentRole.value = props.role + loadData() + } + }) + + // 加载数据 + const loadData = async () => { + if (!currentRole.value) return + + loading.value = true + try { + await Promise.all([ + loadAllPermissions(), + loadRolePermissions() + ]) + } catch (error) { + console.error('加载权限数据失败:', error) + } finally { + loading.value = false + } + } + + // 加载所有权限 + const loadAllPermissions = async () => { + try { + const response = await _services_roleService_js__WEBPACK_IMPORTED_MODULE_1__["default"].getPermissions() + if (response.code === 200) { + allPermissions.value = response.data || [] + } + } catch (error) { + console.error('加载权限列表失败:', error) + } + } + + // 加载角色权限 + const loadRolePermissions = async () => { + try { + const response = await _services_roleService_js__WEBPACK_IMPORTED_MODULE_1__["default"].getRolePermissions(currentRole.value.id) + if (response.code === 200) { + assignedPermissions.value = response.data || [] + } + } catch (error) { + console.error('加载角色权限失败:', error) + } + } + + // 切换已分配权限选择 + const toggleAssignedPermission = (permissionId) => { + const index = selectedAssignedPermissions.value.indexOf(permissionId) + if (index > -1) { + selectedAssignedPermissions.value.splice(index, 1) + } else { + selectedAssignedPermissions.value.push(permissionId) + } + } + + // 切换可分配权限选择 + const toggleAvailablePermission = (permissionId) => { + const index = selectedAvailablePermissions.value.indexOf(permissionId) + if (index > -1) { + selectedAvailablePermissions.value.splice(index, 1) + } else { + selectedAvailablePermissions.value.push(permissionId) + } + } + + // 清除已分配权限选择 + const clearAssignedSelection = () => { + selectedAssignedPermissions.value = [] + } + + // 清除可分配权限选择 + const clearAvailableSelection = () => { + selectedAvailablePermissions.value = [] + } + + // 分配单个权限 + const assignPermission = async (permissionId) => { + try { + const response = await _services_roleService_js__WEBPACK_IMPORTED_MODULE_1__["default"].assignPermissionsToRole(currentRole.value.id, [permissionId]) + if (response.code === 200) { + await loadRolePermissions() + emit('permissions-updated') + } + } catch (error) { + console.error('分配权限失败:', error) + } + } + + // 移除单个权限 + const removePermission = async (permissionId) => { + try { + const response = await _services_roleService_js__WEBPACK_IMPORTED_MODULE_1__["default"].removePermissionsFromRole(currentRole.value.id, [permissionId]) + if (response.code === 200) { + await loadRolePermissions() + emit('permissions-updated') + } + } catch (error) { + console.error('移除权限失败:', error) + } + } + + // 批量分配权限 + const assignSelectedPermissions = async () => { + if (selectedAvailablePermissions.value.length === 0) return + + try { + const response = await _services_roleService_js__WEBPACK_IMPORTED_MODULE_1__["default"].assignPermissionsToRole( + currentRole.value.id, + selectedAvailablePermissions.value + ) + if (response.code === 200) { + selectedAvailablePermissions.value = [] + await loadRolePermissions() + emit('permissions-updated') + } + } catch (error) { + console.error('批量分配权限失败:', error) + } + } + + // 批量移除权限 + const removeSelectedPermissions = async () => { + if (selectedAssignedPermissions.value.length === 0) return + + try { + const response = await _services_roleService_js__WEBPACK_IMPORTED_MODULE_1__["default"].removePermissionsFromRole( + currentRole.value.id, + selectedAssignedPermissions.value + ) + if (response.code === 200) { + selectedAssignedPermissions.value = [] + await loadRolePermissions() + emit('permissions-updated') + } + } catch (error) { + console.error('批量移除权限失败:', error) + } + } + + // 刷新权限 + const refreshPermissions = async () => { + await loadData() + } + + // 关闭对话框 + const handleClose = () => { + visible.value = false + emit('update:modelValue', false) + // 重置状态 + selectedAssignedPermissions.value = [] + selectedAvailablePermissions.value = [] + activeTab.value = 'assigned' + } + + return { + visible, + loading, + currentRole, + allPermissions, + assignedPermissions, + availablePermissions, + selectedAssignedPermissions, + selectedAvailablePermissions, + activeTab, + toggleAssignedPermission, + toggleAvailablePermission, + clearAssignedSelection, + clearAvailableSelection, + assignPermission, + removePermission, + assignSelectedPermissions, + removeSelectedPermissions, + refreshPermissions, + handleClose + } + } +}); + + /***/ }), /***/ "./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/modules/role-management/components/UserRoleAssignment.vue?vue&type=script&lang=js": @@ -5994,17 +6555,24 @@ __webpack_require__.r(__webpack_exports__); /* harmony export */ }); /* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ "./node_modules/vue/dist/vue.runtime.esm-bundler.js"); /* harmony import */ var _services_roleService_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../services/roleService.js */ "./src/renderer/modules/role-management/services/roleService.js"); +/* harmony import */ var _components_RolePermissionAssignment_vue__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../components/RolePermissionAssignment.vue */ "./src/renderer/modules/role-management/components/RolePermissionAssignment.vue"); + /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({ name: 'RoleManagement', + components: { + RolePermissionAssignment: _components_RolePermissionAssignment_vue__WEBPACK_IMPORTED_MODULE_2__["default"] + }, setup() { const loading = (0,vue__WEBPACK_IMPORTED_MODULE_0__.ref)(false) const saving = (0,vue__WEBPACK_IMPORTED_MODULE_0__.ref)(false) const showCreateDialog = (0,vue__WEBPACK_IMPORTED_MODULE_0__.ref)(false) + const showPermissionDialog = (0,vue__WEBPACK_IMPORTED_MODULE_0__.ref)(false) const editingRole = (0,vue__WEBPACK_IMPORTED_MODULE_0__.ref)(null) + const selectedRole = (0,vue__WEBPACK_IMPORTED_MODULE_0__.ref)(null) const roles = (0,vue__WEBPACK_IMPORTED_MODULE_0__.ref)([]) const currentPage = (0,vue__WEBPACK_IMPORTED_MODULE_0__.ref)(1) @@ -6138,27 +6706,43 @@ __webpack_require__.r(__webpack_exports__); return new Date(dateStr).toLocaleString('zh-CN') } + // 分配权限 + const assignPermissions = (role) => { + selectedRole.value = role + showPermissionDialog.value = true + } + + // 处理权限更新 + const handlePermissionsUpdated = () => { + console.log('权限分配已更新') + // 可以在这里添加一些提示或刷新逻辑 + } + ;(0,vue__WEBPACK_IMPORTED_MODULE_0__.onMounted)(() => { loadRoles() }) - return { - loading, - saving, - showCreateDialog, - editingRole, - roles, - currentPage, - pageSize, - total, - roleForm, - createNewRole, - editRole, - saveRole, - deleteRole, - handleCurrentChange, - formatDate - } + return { + loading, + saving, + showCreateDialog, + showPermissionDialog, + editingRole, + selectedRole, + roles, + currentPage, + pageSize, + total, + roleForm, + createNewRole, + editRole, + saveRole, + deleteRole, + assignPermissions, + handlePermissionsUpdated, + handleCurrentChange, + formatDate + } } }); @@ -8524,6 +9108,304 @@ function render(_ctx, _cache, $props, $setup, $data, $options) { /***/ }), +/***/ "./node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/modules/role-management/components/RolePermissionAssignment.vue?vue&type=template&id=91c1b50a&scoped=true": +/*!*****************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/modules/role-management/components/RolePermissionAssignment.vue?vue&type=template&id=91c1b50a&scoped=true ***! + \*****************************************************************************************************************************************************************************************************************************************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ render: () => (/* binding */ render) +/* harmony export */ }); +/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ "./node_modules/vue/dist/vue.runtime.esm-bundler.js"); + + +const _hoisted_1 = { class: "role-permission-assignment" } +const _hoisted_2 = { class: "modal-header" } +const _hoisted_3 = { class: "modal-body" } +const _hoisted_4 = { + key: 0, + class: "loading" +} +const _hoisted_5 = { + key: 1, + class: "permission-content" +} +const _hoisted_6 = { class: "role-info" } +const _hoisted_7 = { class: "role-details" } +const _hoisted_8 = { class: "role-description" } +const _hoisted_9 = { class: "role-stats" } +const _hoisted_10 = { class: "stat-item" } +const _hoisted_11 = { class: "stat-item" } +const _hoisted_12 = { class: "permission-assignment" } +const _hoisted_13 = { class: "assignment-tabs" } +const _hoisted_14 = { + key: 0, + class: "permission-list assigned-permissions" +} +const _hoisted_15 = { class: "list-header" } +const _hoisted_16 = { class: "list-actions" } +const _hoisted_17 = ["disabled"] +const _hoisted_18 = { + key: 0, + class: "empty-state" +} +const _hoisted_19 = { + key: 1, + class: "permission-items" +} +const _hoisted_20 = ["onClick"] +const _hoisted_21 = { class: "permission-checkbox" } +const _hoisted_22 = ["checked", "onChange"] +const _hoisted_23 = { class: "permission-info" } +const _hoisted_24 = { class: "permission-name" } +const _hoisted_25 = { class: "permission-details" } +const _hoisted_26 = { class: "permission-code" } +const _hoisted_27 = { class: "permission-resource" } +const _hoisted_28 = { class: "permission-description" } +const _hoisted_29 = { class: "permission-actions" } +const _hoisted_30 = ["onClick"] +const _hoisted_31 = { + key: 1, + class: "permission-list available-permissions" +} +const _hoisted_32 = { class: "list-header" } +const _hoisted_33 = { class: "list-actions" } +const _hoisted_34 = ["disabled"] +const _hoisted_35 = { + key: 0, + class: "empty-state" +} +const _hoisted_36 = { + key: 1, + class: "permission-items" +} +const _hoisted_37 = ["onClick"] +const _hoisted_38 = { class: "permission-checkbox" } +const _hoisted_39 = ["checked", "onChange"] +const _hoisted_40 = { class: "permission-info" } +const _hoisted_41 = { class: "permission-name" } +const _hoisted_42 = { class: "permission-details" } +const _hoisted_43 = { class: "permission-code" } +const _hoisted_44 = { class: "permission-resource" } +const _hoisted_45 = { class: "permission-description" } +const _hoisted_46 = { class: "permission-actions" } +const _hoisted_47 = ["onClick"] +const _hoisted_48 = { class: "modal-footer" } +const _hoisted_49 = ["disabled"] + +function render(_ctx, _cache, $props, $setup, $data, $options) { + return ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("div", _hoisted_1, [ + ($setup.visible) + ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("div", { + key: 0, + class: "modal-overlay", + onClick: _cache[10] || (_cache[10] = (...args) => ($setup.handleClose && $setup.handleClose(...args))) + }, [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", { + class: "modal large-modal", + onClick: _cache[9] || (_cache[9] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.withModifiers)(() => {}, ["stop"])) + }, [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_2, [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("h3", null, "角色权限分配 - " + (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.currentRole?.name), 1 /* TEXT */), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("button", { + class: "close-btn", + onClick: _cache[0] || (_cache[0] = (...args) => ($setup.handleClose && $setup.handleClose(...args))) + }, _cache[11] || (_cache[11] = [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("i", { class: "fas fa-times" }, null, -1 /* CACHED */) + ])) + ]), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_3, [ + ($setup.loading) + ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("div", _hoisted_4, _cache[12] || (_cache[12] = [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("i", { class: "fas fa-spinner fa-spin" }, null, -1 /* CACHED */), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("span", null, "加载中...", -1 /* CACHED */) + ]))) + : ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("div", _hoisted_5, [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(" 角色信息 "), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_6, [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_7, [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("h4", null, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.currentRole?.name), 1 /* TEXT */), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("p", _hoisted_8, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.currentRole?.description), 1 /* TEXT */), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_9, [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("span", _hoisted_10, [ + _cache[13] || (_cache[13] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("i", { class: "fas fa-shield-alt" }, null, -1 /* CACHED */)), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createTextVNode)(" 已分配权限: " + (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.assignedPermissions.length), 1 /* TEXT */) + ]), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("span", _hoisted_11, [ + _cache[14] || (_cache[14] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("i", { class: "fas fa-list" }, null, -1 /* CACHED */)), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createTextVNode)(" 总权限数: " + (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.allPermissions.length), 1 /* TEXT */) + ]) + ]) + ]) + ]), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(" 权限分配区域 "), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_12, [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_13, [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("button", { + class: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeClass)(["tab-btn", { active: $setup.activeTab === 'assigned' }]), + onClick: _cache[1] || (_cache[1] = $event => ($setup.activeTab = 'assigned')) + }, [ + _cache[15] || (_cache[15] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("i", { class: "fas fa-check-circle" }, null, -1 /* CACHED */)), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createTextVNode)(" 已分配权限 (" + (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.assignedPermissions.length) + ") ", 1 /* TEXT */) + ], 2 /* CLASS */), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("button", { + class: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeClass)(["tab-btn", { active: $setup.activeTab === 'available' }]), + onClick: _cache[2] || (_cache[2] = $event => ($setup.activeTab = 'available')) + }, [ + _cache[16] || (_cache[16] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("i", { class: "fas fa-plus-circle" }, null, -1 /* CACHED */)), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createTextVNode)(" 可分配权限 (" + (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.availablePermissions.length) + ") ", 1 /* TEXT */) + ], 2 /* CLASS */) + ]), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(" 已分配权限列表 "), + ($setup.activeTab === 'assigned') + ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("div", _hoisted_14, [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_15, [ + _cache[18] || (_cache[18] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("h5", null, "已分配权限", -1 /* CACHED */)), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_16, [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("button", { + class: "btn btn-sm btn-danger", + onClick: _cache[3] || (_cache[3] = (...args) => ($setup.removeSelectedPermissions && $setup.removeSelectedPermissions(...args))), + disabled: $setup.selectedAssignedPermissions.length === 0 + }, [ + _cache[17] || (_cache[17] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("i", { class: "fas fa-minus" }, null, -1 /* CACHED */)), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createTextVNode)(" 移除选中 (" + (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.selectedAssignedPermissions.length) + ") ", 1 /* TEXT */) + ], 8 /* PROPS */, _hoisted_17), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("button", { + class: "btn btn-sm btn-secondary", + onClick: _cache[4] || (_cache[4] = (...args) => ($setup.clearAssignedSelection && $setup.clearAssignedSelection(...args))) + }, " 清除选择 ") + ]) + ]), + ($setup.assignedPermissions.length === 0) + ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("div", _hoisted_18, _cache[19] || (_cache[19] = [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("i", { class: "fas fa-inbox" }, null, -1 /* CACHED */), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("p", null, "该角色暂无分配权限", -1 /* CACHED */) + ]))) + : ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("div", _hoisted_19, [ + ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(true), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(vue__WEBPACK_IMPORTED_MODULE_0__.Fragment, null, (0,vue__WEBPACK_IMPORTED_MODULE_0__.renderList)($setup.assignedPermissions, (permission) => { + return ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("div", { + key: permission.id, + class: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeClass)(["permission-item", { selected: $setup.selectedAssignedPermissions.includes(permission.id) }]), + onClick: $event => ($setup.toggleAssignedPermission(permission.id)) + }, [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_21, [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("input", { + type: "checkbox", + checked: $setup.selectedAssignedPermissions.includes(permission.id), + onChange: $event => ($setup.toggleAssignedPermission(permission.id)) + }, null, 40 /* PROPS, NEED_HYDRATION */, _hoisted_22) + ]), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_23, [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_24, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)(permission.name), 1 /* TEXT */), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_25, [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("span", _hoisted_26, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)(permission.code), 1 /* TEXT */), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("span", _hoisted_27, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)(permission.resource), 1 /* TEXT */) + ]), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_28, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)(permission.description), 1 /* TEXT */) + ]), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_29, [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("button", { + class: "btn btn-sm btn-danger", + onClick: (0,vue__WEBPACK_IMPORTED_MODULE_0__.withModifiers)($event => ($setup.removePermission(permission.id)), ["stop"]), + title: "移除权限" + }, [...(_cache[20] || (_cache[20] = [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("i", { class: "fas fa-minus" }, null, -1 /* CACHED */) + ]))], 8 /* PROPS */, _hoisted_30) + ]) + ], 10 /* CLASS, PROPS */, _hoisted_20)) + }), 128 /* KEYED_FRAGMENT */)) + ])) + ])) + : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)("v-if", true), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(" 可分配权限列表 "), + ($setup.activeTab === 'available') + ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("div", _hoisted_31, [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_32, [ + _cache[22] || (_cache[22] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("h5", null, "可分配权限", -1 /* CACHED */)), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_33, [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("button", { + class: "btn btn-sm btn-primary", + onClick: _cache[5] || (_cache[5] = (...args) => ($setup.assignSelectedPermissions && $setup.assignSelectedPermissions(...args))), + disabled: $setup.selectedAvailablePermissions.length === 0 + }, [ + _cache[21] || (_cache[21] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("i", { class: "fas fa-plus" }, null, -1 /* CACHED */)), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createTextVNode)(" 分配选中 (" + (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.selectedAvailablePermissions.length) + ") ", 1 /* TEXT */) + ], 8 /* PROPS */, _hoisted_34), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("button", { + class: "btn btn-sm btn-secondary", + onClick: _cache[6] || (_cache[6] = (...args) => ($setup.clearAvailableSelection && $setup.clearAvailableSelection(...args))) + }, " 清除选择 ") + ]) + ]), + ($setup.availablePermissions.length === 0) + ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("div", _hoisted_35, _cache[23] || (_cache[23] = [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("i", { class: "fas fa-check-circle" }, null, -1 /* CACHED */), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("p", null, "所有权限已分配完毕", -1 /* CACHED */) + ]))) + : ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("div", _hoisted_36, [ + ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(true), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(vue__WEBPACK_IMPORTED_MODULE_0__.Fragment, null, (0,vue__WEBPACK_IMPORTED_MODULE_0__.renderList)($setup.availablePermissions, (permission) => { + return ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("div", { + key: permission.id, + class: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeClass)(["permission-item", { selected: $setup.selectedAvailablePermissions.includes(permission.id) }]), + onClick: $event => ($setup.toggleAvailablePermission(permission.id)) + }, [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_38, [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("input", { + type: "checkbox", + checked: $setup.selectedAvailablePermissions.includes(permission.id), + onChange: $event => ($setup.toggleAvailablePermission(permission.id)) + }, null, 40 /* PROPS, NEED_HYDRATION */, _hoisted_39) + ]), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_40, [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_41, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)(permission.name), 1 /* TEXT */), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_42, [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("span", _hoisted_43, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)(permission.code), 1 /* TEXT */), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("span", _hoisted_44, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)(permission.resource), 1 /* TEXT */) + ]), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_45, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)(permission.description), 1 /* TEXT */) + ]), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_46, [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("button", { + class: "btn btn-sm btn-primary", + onClick: (0,vue__WEBPACK_IMPORTED_MODULE_0__.withModifiers)($event => ($setup.assignPermission(permission.id)), ["stop"]), + title: "分配权限" + }, [...(_cache[24] || (_cache[24] = [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("i", { class: "fas fa-plus" }, null, -1 /* CACHED */) + ]))], 8 /* PROPS */, _hoisted_47) + ]) + ], 10 /* CLASS, PROPS */, _hoisted_37)) + }), 128 /* KEYED_FRAGMENT */)) + ])) + ])) + : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)("v-if", true) + ]) + ])) + ]), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_48, [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("button", { + class: "btn btn-secondary", + onClick: _cache[7] || (_cache[7] = (...args) => ($setup.handleClose && $setup.handleClose(...args))) + }, "关闭"), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("button", { + class: "btn btn-primary", + onClick: _cache[8] || (_cache[8] = (...args) => ($setup.refreshPermissions && $setup.refreshPermissions(...args))), + disabled: $setup.loading + }, _cache[25] || (_cache[25] = [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("i", { class: "fas fa-sync-alt" }, null, -1 /* CACHED */), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createTextVNode)(" 刷新权限 ", -1 /* CACHED */) + ]), 8 /* PROPS */, _hoisted_49) + ]) + ]) + ])) + : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)("v-if", true) + ])) +} + +/***/ }), + /***/ "./node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/modules/role-management/components/UserRoleAssignment.vue?vue&type=template&id=7f7c6d92&scoped=true": /*!***********************************************************************************************************************************************************************************************************************************************************!*\ !*** ./node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/modules/role-management/components/UserRoleAssignment.vue?vue&type=template&id=7f7c6d92&scoped=true ***! @@ -8710,29 +9592,32 @@ const _hoisted_6 = { key: 2 } const _hoisted_7 = { class: "actions" } const _hoisted_8 = ["onClick"] const _hoisted_9 = ["onClick"] -const _hoisted_10 = { +const _hoisted_10 = ["onClick"] +const _hoisted_11 = { key: 3, class: "pagination" } -const _hoisted_11 = ["disabled"] -const _hoisted_12 = { class: "page-info" } -const _hoisted_13 = ["disabled"] -const _hoisted_14 = { class: "modal-header" } -const _hoisted_15 = { class: "modal-body" } -const _hoisted_16 = { class: "form-group" } +const _hoisted_12 = ["disabled"] +const _hoisted_13 = { class: "page-info" } +const _hoisted_14 = ["disabled"] +const _hoisted_15 = { class: "modal-header" } +const _hoisted_16 = { class: "modal-body" } const _hoisted_17 = { class: "form-group" } const _hoisted_18 = { class: "form-group" } -const _hoisted_19 = { class: "form-actions" } -const _hoisted_20 = ["disabled"] +const _hoisted_19 = { class: "form-group" } +const _hoisted_20 = { class: "form-actions" } +const _hoisted_21 = ["disabled"] function render(_ctx, _cache, $props, $setup, $data, $options) { + const _component_RolePermissionAssignment = (0,vue__WEBPACK_IMPORTED_MODULE_0__.resolveComponent)("RolePermissionAssignment") + return ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("div", _hoisted_1, [ (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_2, [ - _cache[13] || (_cache[13] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("h2", null, "角色管理", -1 /* CACHED */)), + _cache[14] || (_cache[14] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("h2", null, "角色管理", -1 /* CACHED */)), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("button", { class: "btn btn-primary", onClick: _cache[0] || (_cache[0] = (...args) => ($setup.createNewRole && $setup.createNewRole(...args))) - }, _cache[12] || (_cache[12] = [ + }, _cache[13] || (_cache[13] = [ (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("i", { class: "fas fa-plus" }, null, -1 /* CACHED */), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createTextVNode)(" 新建角色 ", -1 /* CACHED */) ])) @@ -8740,26 +9625,26 @@ function render(_ctx, _cache, $props, $setup, $data, $options) { (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(" 角色列表 "), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_3, [ ($setup.loading) - ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("div", _hoisted_4, _cache[14] || (_cache[14] = [ + ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("div", _hoisted_4, _cache[15] || (_cache[15] = [ (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("i", { class: "fas fa-spinner fa-spin" }, null, -1 /* CACHED */), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("span", null, "加载中...", -1 /* CACHED */) ]))) : ($setup.roles.length === 0) ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("div", _hoisted_5, [ - _cache[16] || (_cache[16] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("p", null, [ + _cache[17] || (_cache[17] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("p", null, [ (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("i", { class: "fas fa-inbox" }), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createTextVNode)(" 暂无角色数据") ], -1 /* CACHED */)), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("button", { class: "btn btn-primary", onClick: _cache[1] || (_cache[1] = (...args) => ($setup.createNewRole && $setup.createNewRole(...args))) - }, _cache[15] || (_cache[15] = [ + }, _cache[16] || (_cache[16] = [ (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("i", { class: "fas fa-plus" }, null, -1 /* CACHED */), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createTextVNode)(" 创建第一个角色 ", -1 /* CACHED */) ])) ])) : ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("table", _hoisted_6, [ - _cache[19] || (_cache[19] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("thead", null, [ + _cache[21] || (_cache[21] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("thead", null, [ (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("tr", null, [ (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("th", null, "ID"), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("th", null, "角色名称"), @@ -8783,16 +9668,25 @@ function render(_ctx, _cache, $props, $setup, $data, $options) { (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_7, [ (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("button", { class: "btn btn-sm btn-info", - onClick: $event => ($setup.editRole(role)) - }, [...(_cache[17] || (_cache[17] = [ + onClick: $event => ($setup.editRole(role)), + title: "编辑角色" + }, [...(_cache[18] || (_cache[18] = [ (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("i", { class: "fas fa-edit" }, null, -1 /* CACHED */) ]))], 8 /* PROPS */, _hoisted_8), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("button", { + class: "btn btn-sm btn-warning", + onClick: $event => ($setup.assignPermissions(role)), + title: "分配权限" + }, [...(_cache[19] || (_cache[19] = [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("i", { class: "fas fa-shield-alt" }, null, -1 /* CACHED */) + ]))], 8 /* PROPS */, _hoisted_9), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("button", { class: "btn btn-sm btn-danger", - onClick: $event => ($setup.deleteRole(role)) - }, [...(_cache[18] || (_cache[18] = [ + onClick: $event => ($setup.deleteRole(role)), + title: "删除角色" + }, [...(_cache[20] || (_cache[20] = [ (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("i", { class: "fas fa-trash" }, null, -1 /* CACHED */) - ]))], 8 /* PROPS */, _hoisted_9) + ]))], 8 /* PROPS */, _hoisted_10) ]) ]) ])) @@ -8801,24 +9695,24 @@ function render(_ctx, _cache, $props, $setup, $data, $options) { ])), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(" 分页 "), ($setup.total > $setup.pageSize) - ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("div", _hoisted_10, [ + ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("div", _hoisted_11, [ (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("button", { disabled: $setup.currentPage === 1, onClick: _cache[2] || (_cache[2] = $event => ($setup.handleCurrentChange($setup.currentPage - 1))), class: "btn btn-sm" - }, _cache[20] || (_cache[20] = [ + }, _cache[22] || (_cache[22] = [ (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("i", { class: "fas fa-chevron-left" }, null, -1 /* CACHED */), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createTextVNode)(" 上一页 ", -1 /* CACHED */) - ]), 8 /* PROPS */, _hoisted_11), - (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("span", _hoisted_12, " 第 " + (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.currentPage) + " 页,共 " + (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)(Math.ceil($setup.total / $setup.pageSize)) + " 页 ", 1 /* TEXT */), + ]), 8 /* PROPS */, _hoisted_12), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("span", _hoisted_13, " 第 " + (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.currentPage) + " 页,共 " + (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)(Math.ceil($setup.total / $setup.pageSize)) + " 页 ", 1 /* TEXT */), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("button", { disabled: $setup.currentPage >= Math.ceil($setup.total / $setup.pageSize), onClick: _cache[3] || (_cache[3] = $event => ($setup.handleCurrentChange($setup.currentPage + 1))), class: "btn btn-sm" - }, _cache[21] || (_cache[21] = [ + }, _cache[23] || (_cache[23] = [ (0,vue__WEBPACK_IMPORTED_MODULE_0__.createTextVNode)(" 下一页 ", -1 /* CACHED */), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("i", { class: "fas fa-chevron-right" }, null, -1 /* CACHED */) - ]), 8 /* PROPS */, _hoisted_13) + ]), 8 /* PROPS */, _hoisted_14) ])) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)("v-if", true) ]), @@ -8833,21 +9727,21 @@ function render(_ctx, _cache, $props, $setup, $data, $options) { class: "modal", onClick: _cache[10] || (_cache[10] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.withModifiers)(() => {}, ["stop"])) }, [ - (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_14, [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_15, [ (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("h3", null, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.editingRole ? '编辑角色' : '新建角色'), 1 /* TEXT */), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("button", { class: "close-btn", onClick: _cache[4] || (_cache[4] = $event => ($setup.showCreateDialog = false)) - }, _cache[22] || (_cache[22] = [ + }, _cache[24] || (_cache[24] = [ (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("i", { class: "fas fa-times" }, null, -1 /* CACHED */) ])) ]), - (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_15, [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_16, [ (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("form", { onSubmit: _cache[9] || (_cache[9] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.withModifiers)((...args) => ($setup.saveRole && $setup.saveRole(...args)), ["prevent"])) }, [ - (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_16, [ - _cache[23] || (_cache[23] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("label", null, "角色名称 *", -1 /* CACHED */)), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_17, [ + _cache[25] || (_cache[25] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("label", null, "角色名称 *", -1 /* CACHED */)), (0,vue__WEBPACK_IMPORTED_MODULE_0__.withDirectives)((0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("input", { "onUpdate:modelValue": _cache[5] || (_cache[5] = $event => (($setup.roleForm.name) = $event)), type: "text", @@ -8857,8 +9751,8 @@ function render(_ctx, _cache, $props, $setup, $data, $options) { [vue__WEBPACK_IMPORTED_MODULE_0__.vModelText, $setup.roleForm.name] ]) ]), - (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_17, [ - _cache[24] || (_cache[24] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("label", null, "角色代码 *", -1 /* CACHED */)), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_18, [ + _cache[26] || (_cache[26] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("label", null, "角色代码 *", -1 /* CACHED */)), (0,vue__WEBPACK_IMPORTED_MODULE_0__.withDirectives)((0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("input", { "onUpdate:modelValue": _cache[6] || (_cache[6] = $event => (($setup.roleForm.code) = $event)), type: "text", @@ -8868,8 +9762,8 @@ function render(_ctx, _cache, $props, $setup, $data, $options) { [vue__WEBPACK_IMPORTED_MODULE_0__.vModelText, $setup.roleForm.code] ]) ]), - (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_18, [ - _cache[25] || (_cache[25] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("label", null, "描述", -1 /* CACHED */)), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_19, [ + _cache[27] || (_cache[27] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("label", null, "描述", -1 /* CACHED */)), (0,vue__WEBPACK_IMPORTED_MODULE_0__.withDirectives)((0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("textarea", { "onUpdate:modelValue": _cache[7] || (_cache[7] = $event => (($setup.roleForm.description) = $event)), rows: "3", @@ -8878,7 +9772,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) { [vue__WEBPACK_IMPORTED_MODULE_0__.vModelText, $setup.roleForm.description] ]) ]), - (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_19, [ + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_20, [ (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("button", { type: "button", class: "btn btn-secondary", @@ -8888,13 +9782,20 @@ function render(_ctx, _cache, $props, $setup, $data, $options) { type: "submit", class: "btn btn-primary", disabled: $setup.saving - }, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.saving ? '保存中...' : ($setup.editingRole ? '更新' : '创建')), 9 /* TEXT, PROPS */, _hoisted_20) + }, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.saving ? '保存中...' : ($setup.editingRole ? '更新' : '创建')), 9 /* TEXT, PROPS */, _hoisted_21) ]) ], 32 /* NEED_HYDRATION */) ]) ]) ])) - : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)("v-if", true) + : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)("v-if", true), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(" 权限分配对话框 "), + (0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)(_component_RolePermissionAssignment, { + modelValue: $setup.showPermissionDialog, + "onUpdate:modelValue": _cache[12] || (_cache[12] = $event => (($setup.showPermissionDialog) = $event)), + role: $setup.selectedRole, + onPermissionsUpdated: $setup.handlePermissionsUpdated + }, null, 8 /* PROPS */, ["modelValue", "role", "onPermissionsUpdated"]) ])) } @@ -10356,6 +11257,39 @@ if(true) { /***/ }), +/***/ "./node_modules/vue-style-loader/index.js??clonedRuleSet-12.use[0]!./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/modules/role-management/components/RolePermissionAssignment.vue?vue&type=style&index=0&id=91c1b50a&scoped=true&lang=css": +/*!***************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/vue-style-loader/index.js??clonedRuleSet-12.use[0]!./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/modules/role-management/components/RolePermissionAssignment.vue?vue&type=style&index=0&id=91c1b50a&scoped=true&lang=css ***! + \***************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +// style-loader: Adds some css to the DOM by adding a diff --git a/gofaster/app/src/renderer/modules/role-management/services/roleService.js b/gofaster/app/src/renderer/modules/role-management/services/roleService.js index a0ea8bd..b7a5f2f 100644 --- a/gofaster/app/src/renderer/modules/role-management/services/roleService.js +++ b/gofaster/app/src/renderer/modules/role-management/services/roleService.js @@ -136,6 +136,40 @@ export const roleService = { } catch (error) { throw error } + }, + + // 获取角色的权限列表 + async getRolePermissions(roleId) { + try { + const response = await api.get(`/auth/permissions/roles/${roleId}`) + return response + } catch (error) { + throw error + } + }, + + // 为角色分配权限 + async assignPermissionsToRole(roleId, permissionIds) { + try { + const response = await api.post(`/auth/permissions/roles/${roleId}/assign`, { + permission_ids: permissionIds + }) + return response + } catch (error) { + throw error + } + }, + + // 从角色移除权限 + async removePermissionsFromRole(roleId, permissionIds) { + try { + const response = await api.delete(`/auth/permissions/roles/${roleId}/remove`, { + data: { permission_ids: permissionIds } + }) + return response + } catch (error) { + throw error + } } } diff --git a/gofaster/app/src/renderer/modules/role-management/views/RoleManagement.vue b/gofaster/app/src/renderer/modules/role-management/views/RoleManagement.vue index f28cfdf..4cf1bdb 100644 --- a/gofaster/app/src/renderer/modules/role-management/views/RoleManagement.vue +++ b/gofaster/app/src/renderer/modules/role-management/views/RoleManagement.vue @@ -41,12 +41,15 @@