Commit 76653b9a by wuqian

feat:权限相关bug修复

parent db9ed506
......@@ -77,7 +77,8 @@ import {
} from 'vue'
import type { CustomColumn } from '@/types/table'
import RenderColumn from './RenderColumn.vue'
import { ElTable } from 'element-plus'
// 此处必须注释掉,不然使用该组件的表格样式会错乱
// import { ElTable } from 'element-plus'
import type { TableInstance } from 'element-plus'
const tableRef = shallowRef<TableInstance>()
......
<template>
<div class="page_main h-100" :class="{ mobile: isMobile }">
<div class="page_main h-100">
<!-- 头部插槽 -->
<div v-if="$slots.header" class="page_header">
<slot name="header" />
......@@ -41,7 +41,6 @@
<script setup lang="ts">
import { ref, computed, useAttrs } from 'vue'
import type { CSSProperties } from 'vue'
import { isMobile } from '@/utils/index.ts'
const props = defineProps({
isleftshow: {
type: Boolean,
......
......@@ -181,6 +181,7 @@ export function buildDynamicRoutes(
if (!loader) continue
records.push({
path: p,
name: p,
// 使用异步加载的 component
component: loader as unknown as RouteComponent,
meta: { title },
......
......@@ -88,10 +88,8 @@ router.beforeEach(
return
}
// 把 getSysPermissionApi 从 afterEach 整体挪到 beforeEach 并 await:
// 保证组件 onMounted 触发 getTreeNum 时,reqMenu.buttons 已就绪,
// 避免 children 一上来就被 roleShow 一次性过滤成空数组。
// 进入新页面前先把 buttons 清空,避免上一页按钮残留(option 4 思路)。
// 把 getSysPermissionApi 放到 beforeEach 并 await:
// 进入新页面前先把 buttons 清空,避免上一页按钮残留。
if (token && to.path !== '/user/login') {
const reqMenu = (to.meta?.permissionRoute as string) || to.path
if (reqMenu && reqMenu !== pendingReqMenu) {
......
......@@ -33,7 +33,7 @@ const useMenuTreeStore = defineStore('menuTree', () => {
const setMenuTree = (data: MenuTreeNode[]) => {
menusTree.value = data
writeToStorage(data)
// writeToStorage(data) // 这里不写入本地存储,避免覆盖 menusTreeNoBtn
}
const clearMenuTree = () => {
......
.el-table thead {
color: #333;
font-size: 14px;
height: 50px;
min-height: 50px;
}
.el-table .cell {
white-space: nowrap;
}
.el-table thead th.el-table__cell {
color: #333;
background-color: #fafafa;
}
.el-table .cell {
white-space: nowrap;
}
.el-table__row {
height: 40px;
min-height: 40px;
......
......@@ -64,8 +64,4 @@ export function downloadByUrl(url: string, filename?: string) {
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
}
export const isMobile: boolean =
/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i.test(
navigator.userAgent,
)
\ No newline at end of file
}
\ No newline at end of file
......@@ -135,23 +135,34 @@ export function useOrderStatusTree(options: UseOrderStatusTreeOptions) {
const loadStatusTreeCounts = async () => {
try {
const res = await getPodOrderStateGroupListApi()
const GROUP_MARK = new Set(['PICKING']) // "配货中—" 这样的“分组容器”要自己加
const GROUP_MARK = new Set(['PICKING']) // 所有分组容器
const filterTree = (nodes: StatusTreeNode[]): StatusTreeNode[] => {
const result: StatusTreeNode[] = []
for (const node of nodes) {
if (GROUP_MARK.has(node.status) || roleShow(node.status)) {
const newNode = { ...node }
if (newNode.children) {
newNode.children = filterTree(newNode.children)
}
result.push(newNode)
let filteredChildren: StatusTreeNode[] = []
if (node.children) {
filteredChildren = filterTree(node.children)
}
const hasPermission = roleShow(node.status)
const isGroupContainer = GROUP_MARK.has(node.status)
if (
hasPermission ||
(isGroupContainer && filteredChildren.length > 0)
) {
result.push({ ...node, children: filteredChildren })
}
}
return result
}
const result = filterTree(res.data) // 递归过滤掉没有权限的节点
const filteredData = filterTree(res.data)
statusTree.value = [
{ status: 'ALL', statusName: '全部', quantity: 0, children: result },
{
status: 'ALL',
statusName: '全部',
quantity: 0,
children: filteredData,
},
]
nextTick(() => {
treeRef.value?.setCurrentKey(status.value, true)
......
......@@ -42,7 +42,7 @@
padding: 10px 10px 0;
"
>
<div>
<div v-if="currentRole.name" style="line-height: 40px">
<span style="font-weight: bold; font-size: 18px"> 角色名称: </span>
<span style="font-weight: bold; font-size: 20px; color: red">
{{ currentRole.name }}
......@@ -51,6 +51,7 @@
<div>
<ElButton
v-if="activeRoleId != '1'"
:disabled="!currentRole.name"
type="primary"
@click="editRole()"
>
......@@ -58,6 +59,7 @@
</ElButton>
<ElButton
v-if="activeRoleId != '1'"
:disabled="!currentRole.name"
type="success"
@click="copyRole()"
>
......@@ -65,16 +67,28 @@
</ElButton>
<ElButton
v-if="activeRoleId != '1'"
:disabled="!currentRole.name"
type="danger"
@click="removeRole()"
>
删除
</ElButton>
<ElButton type="primary" @click="addRole()"> 添加 </ElButton>
<ElButton type="success" @click="saveSelect()"> 保存 </ElButton>
<ElButton
:disabled="!currentRole.name"
type="success"
@click="saveSelect()"
>
保存
</ElButton>
</div>
</div>
<ElTabs v-model="tabActive" @tab-click="tabClick">
<div v-if="!currentRole.name" class="no_role_tip">
<span style="color: red; font-weight: bold; font-size: 18px"
>请先添加角色吧!</span
>
</div>
<ElTabs v-else v-model="tabActive" @tab-click="tabClick">
<ElTabPane label="功能权限" name="second">
<div
style="
......@@ -458,11 +472,27 @@ function syncNodeCheckState(node: MenuTreeNode) {
const anyIndeter = children.some((c) => c.indeter)
node.indeter = (childSelectedCount > 0 && !allSelected) || anyIndeter
const idx = menuCheckList.value.indexOf(node.id)
if (allSelected && !anyIndeter) {
if (childSelectedCount > 0) {
// 只要有任一子节点被选中,父节点 id 也应进入 checklist(视觉上仍由 indeter 决定半/全勾)
if (idx === -1) menuCheckList.value.push(node.id)
} else if (childSelectedCount === 0 && !anyIndeter) {
} else {
// 没有任何子节点被选中,移除父节点 id
if (idx !== -1) menuCheckList.value.splice(idx, 1)
node.indeter = false
}
}
function findMenuNode(id: number | string): MenuTreeNode | undefined {
const walk = (list?: MenuTreeNode[]): MenuTreeNode | undefined => {
if (!list) return undefined
for (const node of list) {
if (node.id === id) return node
const found = walk(node.children)
if (found) return found
}
return undefined
}
return walk(menuList.value)
}
function updateParentsIndeter(
......@@ -496,6 +526,8 @@ function selectChecked(item: MenuTreeNode) {
}
}
walk(item.children)
// 同步当前节点的 id 和 indeterminate
syncNodeCheckState(item)
// 更新父级 indeterminate
updateParentsIndeter(menuList.value, item)
}
......@@ -512,16 +544,20 @@ function clearChecked(item: MenuTreeNode) {
}
}
walk(item.children)
// 同步当前节点的 id 和 indeterminate
syncNodeCheckState(item)
updateParentsIndeter(menuList.value, item)
}
function checkChange(item: MenuTreeNode, value: boolean | string | number) {
if (value || item.indeter) {
selectChecked(item)
// 一级传入的是合成对象,需查找真实树节点,避免只改到临时对象的 indeter
const target = findMenuNode(item.id) ?? item
if (value || target.indeter) {
selectChecked(target)
} else {
clearChecked(item)
clearChecked(target)
}
item.indeter = false
target.indeter = false
}
async function saveSelect() {
......@@ -552,7 +588,7 @@ async function getActiveData() {
const res = await getRolePermsApi(activeRoleId.value)
if (res.code == 200) {
menuCheckList.value = (res.data?.menuIds as number[]) || []
checkMenus(menuCheckList.value, menuList.value)
checkMenus(menuList.value)
}
} catch (e) {
console.log(e)
......@@ -560,20 +596,12 @@ async function getActiveData() {
await getUsers()
}
function checkMenus(checklist: number[], menulist: MenuTreeNode[]) {
function checkMenus(menulist: MenuTreeNode[]) {
const check = (list: MenuTreeNode[]) => {
list.forEach((item) => {
if (item.children && item.children.length > 0) {
const hasSelectedChild = item.children.some((c) =>
checklist.includes(c.id),
)
if (!hasSelectedChild) {
const index = checklist.indexOf(item.id)
if (index !== -1) {
checklist.splice(index, 1)
}
}
check(item.children)
syncNodeCheckState(item)
}
})
}
......@@ -619,6 +647,12 @@ async function getList(role: RoleItem | null = null) {
currentActiveIndex >= 0 ? String(currentActiveIndex + 1) : '1'
await getActiveData()
}
if (groupLists.value.length === 0) {
activeRoleId.value = ''
currentRole.value = {} as RoleItem
menuCheckList.value = []
userLists.value = []
}
return res
} catch (err) {
console.log(err)
......@@ -687,6 +721,12 @@ onMounted(() => {
height: 100%;
display: flex;
}
.no_role_tip {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.menu_name {
display: inline-block;
min-width: 160px;
......
......@@ -388,9 +388,10 @@ const save = async () => {
const roleIdsStr = Array.isArray(editForm.value.roleIds)
? editForm.value.roleIds.join(',')
: editForm.value.roleIds
const hasSuper = Array.isArray(editForm.value.roleIds)
? editForm.value.roleIds.includes(1)
: editForm.value.roleIds.split(',').map(Number).includes(1)
const hasSuper = getRoleName(editForm.value.roleIds)
.split(',')
.filter(Boolean)
.includes('超级管理员')
try {
if (!editId.value) {
await addUserApi({
......
......@@ -138,13 +138,16 @@
></ElPagination>
</template>
<template #bottom>
<StockingApplyOrderDetailTabs :selected-row="selectedRow" />
<StockingApplyOrderDetailTabs :selected-row="selectedRow ?? null" />
</template>
</SplitDiv>
</div>
</div>
<!-- 提交入库弹框 -->
<SubmitWarehousingDialog ref="submitWarehousingDialogRef" @refresh="onRefresh" />
<SubmitWarehousingDialog
ref="submitWarehousingDialogRef"
@refresh="onRefresh"
/>
</div>
</template>
<script setup lang="tsx">
......@@ -168,7 +171,8 @@ const treeData = ref<TreeData[]>([])
const treeRef = ref()
const tableRef = ref()
const selectedRow = ref<TableData | null>(null)
const submitWarehousingDialogRef = ref<InstanceType<typeof SubmitWarehousingDialog>>()
const submitWarehousingDialogRef =
ref<InstanceType<typeof SubmitWarehousingDialog>>()
const [searchForm, resetSearchForm] = useValue<SearchForm>({} as SearchForm)
const status = ref<string>('TO_BE_RECEIPT')
const warehouseList = ref<WarehouseListData[]>([])
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment