chore(web): 收口前几轮后台改动(品牌 / 媒资上传 / 轮播图 / 类型管理 / 操作日志 / App 用户)
为什么:这些改动在前几轮就已完成并在 :3005 验证过,但一直留在工作区没有入库。 下一步 3-4 的四个页面依赖其中的公共样式入口(src/styles/business/index.css)与 api/admin 的公共类型(PageResult 等),如果不先收口,新页面的提交就会夹带旧改动, 既说不清 diff 边界,也让 index.css 这类多轮共用的文件长期处于半提交状态。 本提交只做归档,不改行为: - 品牌与接口基址改成 FruitShorts / 短剧服务(.env.*、README、vite 代理) - 去掉前端 mock 数据目录(src/data、src/permissions、stores/auth),改为走真实接口 - 新增 api/admin 下的接口封装与 src/utils/uploader.ts(媒资分片直传) - 新增/改造:轮播图管理、类型管理、操作日志、App 用户管理、后台布局与公共样式
This commit is contained in:
1 parent
40546bfd01
commit
44c2c46a68
59 files changed
+4082
-982
No files matched your search
@@ -1,54 +1,77 @@
|
||||
import { computed, nextTick, ref, watch } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { roleData } from '../../../data/roles'
|
||||
import { customMenus } from '../../../data/customMenus'
|
||||
import { permissionGroups } from '../../../permissions/permissions'
|
||||
import { useAuth } from '../../../stores/auth'
|
||||
import { useRbac } from '../../../stores/rbac'
|
||||
import { computed, nextTick, onMounted, ref, watch } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import {
|
||||
createRoleApi,
|
||||
deleteRoleApi,
|
||||
listPermissionGroupsApi,
|
||||
listRoleCategoriesApi,
|
||||
listRolesApi,
|
||||
updateRolePermissionsApi
|
||||
} from '@/api/admin/role'
|
||||
import { useUserStoreWithOut } from '@/store/modules/user'
|
||||
import { useRbac } from '@/stores/rbac'
|
||||
|
||||
export function useRolePermissionEditor() {
|
||||
const { rolePermissions, updateRolePermission, createRole } = useRbac()
|
||||
const { currentRole } = useAuth()
|
||||
const selectedRole = ref(roleData[0].name)
|
||||
const userStore = useUserStoreWithOut()
|
||||
const { can } = useRbac()
|
||||
|
||||
const roleData = ref([])
|
||||
const categories = ref([])
|
||||
const permissionGroups = ref([])
|
||||
const selectedRoleId = ref(null)
|
||||
const dialogVisible = ref(false)
|
||||
const newRoleName = ref('')
|
||||
const newRoleCategoryId = ref(undefined)
|
||||
const treeRef = ref()
|
||||
const syncingTree = ref(false)
|
||||
const permissionTree = computed(() => {
|
||||
const groups = permissionGroups.map((group) => ({
|
||||
|
||||
const permissionTree = computed(() =>
|
||||
permissionGroups.value.map((group) => ({
|
||||
id: `group-${group.name}`,
|
||||
label: group.name,
|
||||
children: group.items.map((permission) => ({ id: permission, label: permission, permission }))
|
||||
children: group.items.map((item) => ({
|
||||
id: item.code,
|
||||
label: item.name,
|
||||
permission: item.code
|
||||
}))
|
||||
}))
|
||||
if (customMenus.length) {
|
||||
groups.push({
|
||||
id: 'group-custom-menus',
|
||||
label: '自定义菜单',
|
||||
children: customMenus.map((menu) => ({
|
||||
id: menu.permission,
|
||||
label: menu.title,
|
||||
permission: menu.permission
|
||||
}))
|
||||
})
|
||||
}
|
||||
return groups
|
||||
})
|
||||
const currentLevel = computed(
|
||||
() => roleData.find((role) => role.name === currentRole.value)?.level || 1
|
||||
)
|
||||
const selectedRoleRecord = computed(() =>
|
||||
roleData.find((role) => role.name === selectedRole.value)
|
||||
)
|
||||
const canEditSelectedRole = computed(
|
||||
() => (selectedRoleRecord.value?.level || 1) >= currentLevel.value
|
||||
)
|
||||
|
||||
const selectedRoleRecord = computed(() =>
|
||||
roleData.value.find((role) => role.id === selectedRoleId.value)
|
||||
)
|
||||
const selectedRole = computed(() => selectedRoleRecord.value?.name || '—')
|
||||
const currentLevel = computed(() => {
|
||||
const code = userStore.getUserInfo?.role
|
||||
return roleData.value.find((role) => role.code === code)?.level ?? 1
|
||||
})
|
||||
const canEditSelectedRole = computed(
|
||||
() =>
|
||||
can('system:role') &&
|
||||
!!selectedRoleRecord.value &&
|
||||
selectedRoleRecord.value.level >= currentLevel.value
|
||||
)
|
||||
|
||||
async function load() {
|
||||
const [rolesRes, groupsRes, categoriesRes] = await Promise.all([
|
||||
listRolesApi(),
|
||||
listPermissionGroupsApi(),
|
||||
listRoleCategoriesApi()
|
||||
])
|
||||
roleData.value = rolesRes.data || []
|
||||
permissionGroups.value = groupsRes.data || []
|
||||
categories.value = categoriesRes.data || []
|
||||
if (!selectedRoleId.value && roleData.value.length) {
|
||||
selectedRoleId.value = roleData.value[0].id
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
selectedRole,
|
||||
async (role) => {
|
||||
[selectedRoleId, permissionGroups],
|
||||
async () => {
|
||||
syncingTree.value = true
|
||||
await nextTick()
|
||||
treeRef.value?.setCheckedKeys(rolePermissions[role] || [])
|
||||
treeRef.value?.setCheckedKeys(selectedRoleRecord.value?.permissions || [])
|
||||
await nextTick()
|
||||
syncingTree.value = false
|
||||
},
|
||||
@@ -56,36 +79,72 @@ export function useRolePermissionEditor() {
|
||||
)
|
||||
|
||||
function selectRole(row) {
|
||||
selectedRole.value = row.name
|
||||
selectedRoleId.value = row.id
|
||||
}
|
||||
function handleCheck(data, checked) {
|
||||
if (!syncingTree.value && data.permission && canEditSelectedRole.value) {
|
||||
updateRolePermission(selectedRole.value, data.permission, checked)
|
||||
}
|
||||
|
||||
function readCheckedCodes() {
|
||||
const checked = treeRef.value?.getCheckedKeys() || []
|
||||
return checked.filter((key) => typeof key === 'string' && !key.startsWith('group-'))
|
||||
}
|
||||
function addRole() {
|
||||
|
||||
/** 勾选即保存:把整棵树的权限码提交给后端覆盖。 */
|
||||
async function handleCheck() {
|
||||
if (syncingTree.value || !canEditSelectedRole.value) return
|
||||
const role = selectedRoleRecord.value
|
||||
if (!role) return
|
||||
const codes = readCheckedCodes()
|
||||
await updateRolePermissionsApi(role.id, codes)
|
||||
role.permissions = codes
|
||||
ElMessage.success('权限已保存')
|
||||
}
|
||||
|
||||
async function addRole() {
|
||||
const name = newRoleName.value.trim()
|
||||
if (!name) return ElMessage.warning('请输入角色名称')
|
||||
if (roleData.some((role) => role.name === name)) return ElMessage.warning('角色名称已存在')
|
||||
roleData.push({
|
||||
id: Date.now(),
|
||||
if (roleData.value.some((role) => role.name === name)) {
|
||||
return ElMessage.warning('角色名称已存在')
|
||||
}
|
||||
await createRoleApi({
|
||||
name,
|
||||
description: '自定义权限角色',
|
||||
memberCount: 0,
|
||||
category: '自定义角色',
|
||||
categoryId: newRoleCategoryId.value || categories.value[0]?.id || 0,
|
||||
level: currentLevel.value + 1,
|
||||
status: '启用'
|
||||
description: '自定义角色',
|
||||
permissions: []
|
||||
})
|
||||
createRole(name)
|
||||
selectedRole.value = name
|
||||
newRoleName.value = ''
|
||||
newRoleCategoryId.value = undefined
|
||||
dialogVisible.value = false
|
||||
ElMessage.success('角色已创建')
|
||||
await load()
|
||||
const created = roleData.value.find((role) => role.name === name)
|
||||
if (created) selectedRoleId.value = created.id
|
||||
}
|
||||
|
||||
async function removeRole() {
|
||||
const role = selectedRoleRecord.value
|
||||
if (!role) return ElMessage.warning('请先选择角色')
|
||||
if (role.builtin) return ElMessage.warning('内置角色不可删除')
|
||||
try {
|
||||
await ElMessageBox.confirm(`确定删除角色「${role.name}」吗?`, '删除确认', {
|
||||
confirmButtonText: '确认删除',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
confirmButtonClass: 'el-button--danger'
|
||||
})
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
await deleteRoleApi(role.id)
|
||||
ElMessage.success('角色已删除')
|
||||
selectedRoleId.value = null
|
||||
await load()
|
||||
}
|
||||
|
||||
onMounted(load)
|
||||
|
||||
return {
|
||||
roleData,
|
||||
rolePermissions,
|
||||
categories,
|
||||
selectedRole,
|
||||
selectedRoleRecord,
|
||||
canEditSelectedRole,
|
||||
@@ -93,8 +152,10 @@ export function useRolePermissionEditor() {
|
||||
treeRef,
|
||||
dialogVisible,
|
||||
newRoleName,
|
||||
newRoleCategoryId,
|
||||
selectRole,
|
||||
handleCheck,
|
||||
addRole
|
||||
addRole,
|
||||
removeRole
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user