zhou zhou
2026-04-13 6877c9caa25162e570a3e2a99a5b2ce3ef88368b
rsf-design/src/views/system/role/modules/role-permission-dialog.vue
@@ -24,10 +24,23 @@
        <div v-else class="space-y-3">
          <div class="flex items-center justify-between gap-3">
            <ElSpace wrap>
              <ElButton @click="handleSelectAll(config.scopeType)">{{ t('pages.system.role.permission.selectAll') }}</ElButton>
              <ElButton @click="handleClear(config.scopeType)">{{ t('pages.system.role.permission.clear') }}</ElButton>
              <ElButton @click="handleSelectAll(config.scopeType)">{{
                t('pages.system.role.permission.selectAll')
              }}</ElButton>
              <ElButton @click="handleClear(config.scopeType)">{{
                t('pages.system.role.permission.clear')
              }}</ElButton>
              <ElButton @click="handleToggleExpand(config.scopeType)">
                {{
                  scopeState[config.scopeType].expandAll
                    ? t('common.actions.collapse')
                    : t('common.actions.expand')
                }}
              </ElButton>
            </ElSpace>
            <ElButton type="primary" @click="handleSave(config.scopeType)">{{ t('pages.system.role.permission.saveCurrent') }}</ElButton>
            <ElButton type="primary" @click="handleSave(config.scopeType)">{{
              t('pages.system.role.permission.saveCurrent')
            }}</ElButton>
          </div>
          <div class="flex items-center gap-3">
@@ -38,16 +51,19 @@
              @clear="handleSearch(config.scopeType)"
              @keyup.enter="handleSearch(config.scopeType)"
            />
            <ElButton @click="handleSearch(config.scopeType)">{{ t('common.actions.search') }}</ElButton>
            <ElButton @click="handleSearch(config.scopeType)">{{
              t('common.actions.search')
            }}</ElButton>
          </div>
          <ElScrollbar height="56vh">
            <ElTree
              :key="`${config.scopeType}-${scopeState[config.scopeType].treeVersion}`"
              :ref="(el) => setTreeRef(config.scopeType, el)"
              :data="scopeState[config.scopeType].treeData"
              node-key="id"
              show-checkbox
              :default-expand-all="true"
              :default-expand-all="scopeState[config.scopeType].expandAll"
              :default-checked-keys="scopeState[config.scopeType].checkedKeys"
              :props="treeProps"
              @check="handleTreeCheck(config.scopeType)"
@@ -73,10 +89,13 @@
    buildRoleScopeSubmitPayload,
    getRoleScopeConfig,
    normalizeScopeKeys,
    normalizeScopeKey,
    normalizeRoleScopeTreeData
  } from '../rolePage.helpers'
  import { fetchGetRoleScopeList, fetchGetRoleScopeTree, fetchUpdateRoleScope } from '@/api/system-manage'
  import {
    fetchGetRoleScopeList,
    fetchGetRoleScopeTree,
    fetchUpdateRoleScope
  } from '@/api/system-manage'
  import { resolveBackendMenuTitle } from '@/utils/backend-menu-title'
  import { formatMenuTitle } from '@/utils/router'
  import { guardRequestWithMessage } from '@/utils/sys/requestGuard'
@@ -92,21 +111,28 @@
  const emit = defineEmits(['update:visible', 'success'])
  const { t } = useI18n()
  const scopeConfigs = ['menu', 'pda', 'matnr', 'warehouse'].map((scopeType) => getRoleScopeConfig(scopeType))
  const scopeConfigs = ['menu', 'pda', 'matnr', 'warehouse'].map((scopeType) =>
    getRoleScopeConfig(scopeType)
  )
  const activeScopeType = ref(props.scopeType || 'menu')
  const treeRefs = reactive({})
  const treeProps = {
    label: 'label',
    children: 'children'
  }
  const scopeState = reactive(Object.fromEntries(scopeConfigs.map((config) => [config.scopeType, createScopeTabState()])))
  const scopeState = reactive(
    Object.fromEntries(scopeConfigs.map((config) => [config.scopeType, createScopeTabState()]))
  )
  const visible = computed({
    get: () => props.visible,
    set: (value) => emit('update:visible', value)
  })
  const roleLabel = computed(() => props.roleData?.name || props.roleData?.code || t('pages.system.role.permission.unselected'))
  const roleLabel = computed(
    () =>
      props.roleData?.name || props.roleData?.code || t('pages.system.role.permission.unselected')
  )
  function createScopeTabState() {
    return {
@@ -115,7 +141,9 @@
      treeData: [],
      checkedKeys: [],
      halfCheckedKeys: [],
      condition: ''
      condition: '',
      expandAll: true,
      treeVersion: 0
    }
  }
@@ -135,13 +163,17 @@
      const selectionRequest = reloadSelection
        ? fetchGetRoleScopeList(config.scopeType, props.roleData.id)
        : Promise.resolve(state.checkedKeys)
      const treeRequest = fetchGetRoleScopeTree(config.scopeType, { condition: state.condition || '' })
      const treeRequest = fetchGetRoleScopeTree(config.scopeType, {
        condition: state.condition || ''
      })
      const guardedResult = await guardRequestWithMessage(
        Promise.all([selectionRequest, treeRequest]),
        null,
        {
          timeoutMessage: t('pages.system.role.permission.scopeLoadTimeout', { title: config.title })
          timeoutMessage: t('pages.system.role.permission.scopeLoadTimeout', {
            title: config.title
          })
        }
      )
      if (!guardedResult) {
@@ -155,9 +187,12 @@
      state.treeData = normalizeRoleScopeTreeData(config.scopeType, treeData)
      state.checkedKeys = normalizeScopeKeys(checkedIds)
      state.halfCheckedKeys = []
      state.treeVersion += 1
      state.loaded = true
    } catch (error) {
      ElMessage.error(error?.message || t('pages.system.role.permission.scopeLoadFailed', { title: config.title }))
      ElMessage.error(
        error?.message || t('pages.system.role.permission.scopeLoadFailed', { title: config.title })
      )
    } finally {
      state.loading = false
      nextTick(() => {
@@ -207,6 +242,16 @@
    handleTreeCheck(scopeType)
  }
  const handleToggleExpand = (scopeType) => {
    const state = scopeState[scopeType]
    state.expandAll = !state.expandAll
    state.treeVersion += 1
    nextTick(() => {
      treeRefs[scopeType]?.setCheckedKeys(state.checkedKeys)
      handleTreeCheck(scopeType)
    })
  }
  const handleSave = async (scopeType) => {
    if (!props.roleData?.id) return
    try {
@@ -241,7 +286,7 @@
    }
    if (activeScopeType.value === 'menu') {
      const resolvedTitle = resolveBackendMenuTitle(rawLabel, data?.component || '')
      return resolvedTitle ? formatMenuTitle(resolvedTitle) : ''
      return resolvedTitle ? formatMenuTitle(resolvedTitle) : rawLabel
    }
    return rawLabel
  }
@@ -292,12 +337,9 @@
    }
  )
  watch(
    activeScopeType,
    async (scopeType) => {
      if (props.visible && scopeType) {
        await ensureScopeLoaded(scopeType)
      }
  watch(activeScopeType, async (scopeType) => {
    if (props.visible && scopeType) {
      await ensureScopeLoaded(scopeType)
    }
  )
  })
</script>