修复了后端部门详情页新增成员功能

This commit is contained in:
TermiNexus committed 2026-08-04 20:23:09 +08:00
1 parent 50d90e3540
commit bb77b8caf7
9 files changed
+157 -57

No files matched your search

+32 -4
View File
@@ -89,12 +89,27 @@ const {
// vxe-table 实例引用(用于获取选中行) // vxe-table 实例引用(用于获取选中行)
const xTableRef = ref() const xTableRef = ref()
// 父级 query 中匹配列定义的关联字段(如 DeptUUID/UserUUID/WorkgroupUUID):
// 详情页子表场景自动注入新增/编辑表单,保证新记录归属当前详情上下文;
// 注入后隐藏表单项(值由父级上下文决定,不允许用户修改)。
const inheritedQueryFields = computed(() => {
const q = props.query ?? {}
const colFields = new Set(columns.value.map((c) => c.field))
const result: Record<string, unknown> = {}
for (const [k, v] of Object.entries(q)) {
if (v !== undefined && v !== null && v !== '' && colFields.has(k)) {
result[k] = v
}
}
return result
})
// 可见表格列(排除 hidden) // 可见表格列(排除 hidden)
const tableColumns = computed(() => const tableColumns = computed(() =>
columns.value.filter((c: ColumnSchema) => c.visible !== false && c.type !== 'hidden'), columns.value.filter((c: ColumnSchema) => c.visible !== false && c.type !== 'hidden'),
) )
// 弹窗表单可见列(排除隐藏/主键隐藏/不可编辑/divider/html) // 弹窗表单可见列(排除隐藏/主键隐藏/不可编辑/divider/html/父级注入字段)
const formColumns = computed(() => { const formColumns = computed(() => {
const pkField = columns.value.find((c) => c.isPrimary || c.primaryKey)?.field || 'Id' const pkField = columns.value.find((c) => c.isPrimary || c.primaryKey)?.field || 'Id'
return columns.value.filter( return columns.value.filter(
@@ -104,10 +119,23 @@ const formColumns = computed(() => {
c.type !== 'hidden' && c.type !== 'hidden' &&
c.type !== 'divider' && c.type !== 'divider' &&
c.type !== 'html' && c.type !== 'html' &&
c.field !== pkField, c.field !== pkField &&
!(c.field in inheritedQueryFields.value),
) )
}) })
// 新增:先走 useCrudTable 初始化,再注入父级上下文关联字段
function onHandleCreate(): void {
handleCreate()
Object.assign(editingRow, inheritedQueryFields.value)
}
// 提交:保证父级上下文关联字段始终存在(编辑时用户可能误删)
function onHandleSubmit(): void {
Object.assign(editingRow, inheritedQueryFields.value)
handleSubmit()
}
// vxe-table checkbox 变化:同步到 selectedRows // vxe-table checkbox 变化:同步到 selectedRows
function onCheckboxChange(): void { function onCheckboxChange(): void {
const records = xTableRef.value?.getCheckboxRecords?.() || [] const records = xTableRef.value?.getCheckboxRecords?.() || []
@@ -163,7 +191,7 @@ function renderSelectLabel(col: ColumnSchema, value: unknown): string {
<div class="table-header"> <div class="table-header">
<span class="table-title">{{ title || table }}</span> <span class="table-title">{{ title || table }}</span>
<div class="table-actions"> <div class="table-actions">
<el-button type="primary" @click="handleCreate"> <el-button type="primary" @click="onHandleCreate">
<el-icon><Plus /></el-icon>新增 <el-icon><Plus /></el-icon>新增
</el-button> </el-button>
<el-button <el-button
@@ -379,7 +407,7 @@ function renderSelectLabel(col: ColumnSchema, value: unknown): string {
<template #footer> <template #footer>
<el-button @click="dialogVisible = false">取消</el-button> <el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" :loading="submitting" @click="handleSubmit">保存</el-button> <el-button type="primary" :loading="submitting" @click="onHandleSubmit">保存</el-button>
</template> </template>
</el-dialog> </el-dialog>
</div> </div>
+14 -5
View File
@@ -60,8 +60,8 @@ const resolvedNames = ref<Record<string, Record<string, string>>>({})
/** 错误信息(缺参 / 加载失败时展示) */ /** 错误信息(缺参 / 加载失败时展示) */
const errorMsg = ref('') const errorMsg = ref('')
/** 从路由 query 读取公司 UUID */ /** 从路由 query 读取公司 UUID(computed 响应式:同一 tab 复用且 query 变化时自动更新) */
const companyUUID = (route.query.CompanyUUID as string) || '' const companyUUID = computed(() => (route.query.CompanyUUID as string) || '')
/** 公司主键字段名 */ /** 公司主键字段名 */
const PK_FIELD = 'CompanyUUID' const PK_FIELD = 'CompanyUUID'
@@ -96,7 +96,7 @@ function pickList<T = RowData>(res: unknown): T[] {
/** 拉取公司主数据 + 解析关联 UUID */ /** 拉取公司主数据 + 解析关联 UUID */
async function loadCompany(): Promise<void> { async function loadCompany(): Promise<void> {
if (!companyUUID) { if (!companyUUID.value) {
errorMsg.value = '缺少 CompanyUUID 参数,无法加载公司详情。' errorMsg.value = '缺少 CompanyUUID 参数,无法加载公司详情。'
return return
} }
@@ -104,11 +104,11 @@ async function loadCompany(): Promise<void> {
errorMsg.value = '' errorMsg.value = ''
try { try {
const res = await formApi.list<CompanyRecord>('Company', { const res = await formApi.list<CompanyRecord>('Company', {
CompanyUUID: companyUUID, CompanyUUID: companyUUID.value,
pageSize: 1, pageSize: 1,
}) })
const list = pickList<CompanyRecord>(res) const list = pickList<CompanyRecord>(res)
const data = list.find((c) => c.CompanyUUID === companyUUID) || list[0] const data = list.find((c) => c.CompanyUUID === companyUUID.value) || list[0]
if (!data) { if (!data) {
errorMsg.value = '未找到公司数据' errorMsg.value = '未找到公司数据'
return return
@@ -209,6 +209,15 @@ async function copyUUID(uuid: string): Promise<void> {
} }
onMounted(loadCompany) onMounted(loadCompany)
// 同一 tab 复用(v-show 常驻)时 query 变化:重新加载(防展示旧公司数据 / 缺参报错)
watch(companyUUID, () => {
if (!companyUUID.value) {
errorMsg.value = '缺少 CompanyUUID 参数,无法加载公司详情。'
return
}
void loadCompany()
})
</script> </script>
<template> <template>
+15 -6
View File
@@ -17,7 +17,7 @@
* - 子表列定义由后端 Columns 接口返回(含 RoleType 选项 0员工/1负责人),CrudTable 自动渲染 * - 子表列定义由后端 Columns 接口返回(含 RoleType 选项 0员工/1负责人),CrudTable 自动渲染
* - onView 跳用户详情:/system/user-detail?UserUUID=xxx(对齐工程统一用户详情入口) * - onView 跳用户详情:/system/user-detail?UserUUID=xxx(对齐工程统一用户详情入口)
*/ */
import { ref, reactive, computed, onMounted } from 'vue' import { ref, reactive, computed, onMounted, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import DetailPage from '@/components/DetailPage.vue' import DetailPage from '@/components/DetailPage.vue'
@@ -33,8 +33,8 @@ const route = useRoute()
const router = useRouter() const router = useRouter()
const { resolveUUIDs } = useResolveUUIDs() const { resolveUUIDs } = useResolveUUIDs()
// 路由参数:部门 UUID // 路由参数:部门 UUID(computed 响应式:同一 tab 复用且 query 变化时自动更新)
const deptUUID = (route.query.DeptUUID as string) || '' const deptUUID = computed(() => (route.query.DeptUUID as string) || '')
// === 状态 === // === 状态 ===
const loading = ref(false) const loading = ref(false)
@@ -76,15 +76,15 @@ function formatTime(v: unknown): string {
// === 数据加载 === // === 数据加载 ===
async function loadData(): Promise<void> { async function loadData(): Promise<void> {
if (!deptUUID) { if (!deptUUID.value) {
ElMessage.warning('缺少 DeptUUID 参数,无法加载部门详情') ElMessage.warning('缺少 DeptUUID 参数,无法加载部门详情')
return return
} }
loading.value = true loading.value = true
try { try {
const result = await formApi.list('Department', { [PK_FIELD]: deptUUID, pageSize: 1 }) const result = await formApi.list('Department', { [PK_FIELD]: deptUUID.value, pageSize: 1 })
const list: any[] = Array.isArray(result) ? result : (result as any)?.list || [] const list: any[] = Array.isArray(result) ? result : (result as any)?.list || []
const row = list.find((d) => d[PK_FIELD] === deptUUID) || list[0] const row = list.find((d) => d[PK_FIELD] === deptUUID.value) || list[0]
if (!row) { if (!row) {
ElMessage.error('未找到部门数据') ElMessage.error('未找到部门数据')
return return
@@ -163,6 +163,15 @@ function goUserDetail(row: Record<string, any>): void {
onMounted(async () => { onMounted(async () => {
await Promise.all([loadData(), loadColumns()]) await Promise.all([loadData(), loadColumns()])
}) })
// 同一 tab 复用(v-show 常驻)时 query 变化:重新加载(防展示旧部门数据 / 缺参报错)
watch(deptUUID, () => {
if (!deptUUID.value) {
ElMessage.warning('缺少 DeptUUID 参数,无法加载部门详情')
return
}
void loadData()
})
</script> </script>
<template> <template>
+17 -8
View File
@@ -21,7 +21,7 @@
* - 头像 URL 手动附加 getServerScopeParams() 返回的 server / admin_verify。 * - 头像 URL 手动附加 getServerScopeParams() 返回的 server / admin_verify。
* - 编辑弹窗动态渲染列定义,保存调用 formApi.update(对齐已迁移详情页约定)。 * - 编辑弹窗动态渲染列定义,保存调用 formApi.update(对齐已迁移详情页约定)。
*/ */
import { ref, reactive, computed, onMounted } from 'vue' import { ref, reactive, computed, onMounted, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import DetailPage from '@/components/DetailPage.vue' import DetailPage from '@/components/DetailPage.vue'
@@ -72,8 +72,8 @@ const twoFaData = ref<TwoFaInfo | null>(null)
/** 错误信息 */ /** 错误信息 */
const errorMsg = ref('') const errorMsg = ref('')
/** 从路由 query 读取用户 UUID */ /** 从路由 query 读取用户 UUID(computed 响应式:同一 tab 复用且 query 变化时自动更新) */
const userUUID = (route.query.UserUUID as string) || '' const userUUID = computed(() => (route.query.UserUUID as string) || '')
/** 用户主键字段名 */ /** 用户主键字段名 */
const PK_FIELD = 'UserUUID' const PK_FIELD = 'UserUUID'
@@ -107,7 +107,7 @@ function genderText(val: unknown): string {
/** 头像 URL:手动附加 server / admin_verify 作用域参数(el-avatar 不走 axios 拦截器) */ /** 头像 URL:手动附加 server / admin_verify 作用域参数(el-avatar 不走 axios 拦截器) */
const avatarUrl = computed(() => { const avatarUrl = computed(() => {
const params = new URLSearchParams() const params = new URLSearchParams()
params.set('UserUUID', userUUID) params.set('UserUUID', userUUID.value)
const scope = getServerScopeParams() const scope = getServerScopeParams()
if (scope.server) params.set('server', scope.server) if (scope.server) params.set('server', scope.server)
if (scope.admin_verify) params.set('admin_verify', scope.admin_verify) if (scope.admin_verify) params.set('admin_verify', scope.admin_verify)
@@ -143,7 +143,7 @@ function isTruthy(val: unknown): boolean {
/** 拉取用户主数据 + 2FA 信息(2FA 失败不阻塞) */ /** 拉取用户主数据 + 2FA 信息(2FA 失败不阻塞) */
async function loadUser(): Promise<void> { async function loadUser(): Promise<void> {
if (!userUUID) { if (!userUUID.value) {
errorMsg.value = '缺少 UserUUID 参数,无法加载员工详情。' errorMsg.value = '缺少 UserUUID 参数,无法加载员工详情。'
return return
} }
@@ -151,9 +151,9 @@ async function loadUser(): Promise<void> {
errorMsg.value = '' errorMsg.value = ''
twoFaData.value = null twoFaData.value = null
try { try {
const res = await formApi.list<UserRecord>('User', { UserUUID: userUUID, pageSize: 1 }) const res = await formApi.list<UserRecord>('User', { UserUUID: userUUID.value, pageSize: 1 })
const list = pickList<UserRecord>(res) const list = pickList<UserRecord>(res)
const data = list.find((u) => u.UserUUID === userUUID) || list[0] const data = list.find((u) => u.UserUUID === userUUID.value) || list[0]
if (!data) { if (!data) {
errorMsg.value = '未找到用户数据' errorMsg.value = '未找到用户数据'
return return
@@ -164,7 +164,7 @@ async function loadUser(): Promise<void> {
// 并行获取 2FA 信息(失败不阻塞页面) // 并行获取 2FA 信息(失败不阻塞页面)
try { try {
twoFaData.value = await get<TwoFaInfo>('/API/SiteUserManagement/GetUser2FAInfo', { twoFaData.value = await get<TwoFaInfo>('/API/SiteUserManagement/GetUser2FAInfo', {
UserUUID: userUUID, UserUUID: userUUID.value,
}) })
} catch { } catch {
twoFaData.value = null twoFaData.value = null
@@ -233,6 +233,15 @@ async function saveEdit(): Promise<void> {
} }
onMounted(loadUser) onMounted(loadUser)
// 同一 tab 复用(v-show 常驻)时 query 变化:重新加载(防展示旧员工数据 / 缺参报错)
watch(userUUID, () => {
if (!userUUID.value) {
errorMsg.value = '缺少 UserUUID 参数,无法加载员工详情。'
return
}
void loadUser()
})
</script> </script>
<template> <template>
+15 -6
View File
@@ -21,7 +21,7 @@
* - 是否特权模式由 isDefaultServer()/hasAdminVerifyArg() 综合判断(与 AdminBadge 一致)。 * - 是否特权模式由 isDefaultServer()/hasAdminVerifyArg() 综合判断(与 AdminBadge 一致)。
* - 编辑弹窗动态渲染列定义,保存调用 formApi.update(对齐已迁移详情页约定)。 * - 编辑弹窗动态渲染列定义,保存调用 formApi.update(对齐已迁移详情页约定)。
*/ */
import { ref, reactive, computed, onMounted } from 'vue' import { ref, reactive, computed, onMounted, watch } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import DetailPage from '@/components/DetailPage.vue' import DetailPage from '@/components/DetailPage.vue'
@@ -55,8 +55,8 @@ const roleData = ref<RoleRecord | null>(null)
/** 错误信息 */ /** 错误信息 */
const errorMsg = ref('') const errorMsg = ref('')
/** 从路由 query 读取角色 UUID */ /** 从路由 query 读取角色 UUID(computed 响应式:同一 tab 复用且 query 变化时自动更新) */
const roleUUID = (route.query.RoleUUID as string) || '' const roleUUID = computed(() => (route.query.RoleUUID as string) || '')
/** 角色主键字段名 */ /** 角色主键字段名 */
const PK_FIELD = 'RoleUUID' const PK_FIELD = 'RoleUUID'
@@ -107,16 +107,16 @@ function pickList<T = RowData>(res: unknown): T[] {
/** 拉取角色主数据 */ /** 拉取角色主数据 */
async function loadRole(): Promise<void> { async function loadRole(): Promise<void> {
if (!roleUUID) { if (!roleUUID.value) {
errorMsg.value = '缺少 RoleUUID 参数,无法加载角色详情。' errorMsg.value = '缺少 RoleUUID 参数,无法加载角色详情。'
return return
} }
loading.value = true loading.value = true
errorMsg.value = '' errorMsg.value = ''
try { try {
const res = await formApi.list<RoleRecord>('Role', { RoleUUID: roleUUID, pageSize: 1 }) const res = await formApi.list<RoleRecord>('Role', { RoleUUID: roleUUID.value, pageSize: 1 })
const list = pickList<RoleRecord>(res) const list = pickList<RoleRecord>(res)
const data = list.find((r) => r.RoleUUID === roleUUID) || list[0] const data = list.find((r) => r.RoleUUID === roleUUID.value) || list[0]
if (!data) { if (!data) {
errorMsg.value = '未找到角色数据' errorMsg.value = '未找到角色数据'
return return
@@ -181,6 +181,15 @@ async function saveEdit(): Promise<void> {
} }
onMounted(loadRole) onMounted(loadRole)
// 同一 tab 复用(v-show 常驻)时 query 变化:重新加载(防展示旧角色数据 / 缺参报错)
watch(roleUUID, () => {
if (!roleUUID.value) {
errorMsg.value = '缺少 RoleUUID 参数,无法加载角色详情。'
return
}
void loadRole()
})
</script> </script>
<template> <template>
+15 -6
View File
@@ -17,7 +17,7 @@
* - 租户状态码:0→禁用,1→启用 * - 租户状态码:0→禁用,1→启用
* - 原生 _isAdminMode(hasAdminVerifyArg)由拦截器统一处理,无需手动注入 * - 原生 _isAdminMode(hasAdminVerifyArg)由拦截器统一处理,无需手动注入
*/ */
import { ref, reactive, computed, onMounted } from 'vue' import { ref, reactive, computed, onMounted, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import DetailPage from '@/components/DetailPage.vue' import DetailPage from '@/components/DetailPage.vue'
@@ -31,8 +31,8 @@ import type { ColumnSchema } from '@/types/api'
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
// 路由参数:租户 UUID // 路由参数:租户 UUID(computed 响应式:同一 tab 复用且 query 变化时自动更新)
const tenantUUID = (route.query.TenantUUID as string) || '' const tenantUUID = computed(() => (route.query.TenantUUID as string) || '')
// === 状态 === // === 状态 ===
const loading = ref(false) const loading = ref(false)
@@ -92,15 +92,15 @@ const formColumns = computed(() =>
// === 数据加载 === // === 数据加载 ===
async function loadData(): Promise<void> { async function loadData(): Promise<void> {
if (!tenantUUID) { if (!tenantUUID.value) {
ElMessage.warning('缺少 TenantUUID 参数,无法加载租户详情') ElMessage.warning('缺少 TenantUUID 参数,无法加载租户详情')
return return
} }
loading.value = true loading.value = true
try { try {
const result = await formApi.list('Tenant', { [PK_FIELD]: tenantUUID, pageSize: 1 }) const result = await formApi.list('Tenant', { [PK_FIELD]: tenantUUID.value, pageSize: 1 })
const list: any[] = Array.isArray(result) ? result : (result as any)?.list || [] const list: any[] = Array.isArray(result) ? result : (result as any)?.list || []
const row = list.find((t) => t[PK_FIELD] === tenantUUID) || list[0] const row = list.find((t) => t[PK_FIELD] === tenantUUID.value) || list[0]
if (!row) { if (!row) {
ElMessage.error('未找到租户数据') ElMessage.error('未找到租户数据')
return return
@@ -151,6 +151,15 @@ function goCompanyDetail(row: Record<string, any>): void {
onMounted(async () => { onMounted(async () => {
await Promise.all([loadData(), loadColumns()]) await Promise.all([loadData(), loadColumns()])
}) })
// 同一 tab 复用(v-show 常驻)时 query 变化:重新加载(防展示旧租户数据 / 缺参报错)
watch(tenantUUID, () => {
if (!tenantUUID.value) {
ElMessage.warning('缺少 TenantUUID 参数,无法加载租户详情')
return
}
void loadData()
})
</script> </script>
<template> <template>
+15 -6
View File
@@ -16,7 +16,7 @@
* - UUID 解析:所属公司 CompanyUUID → CompanyName,使用 useResolveUUIDs composable(带缓存) * - UUID 解析:所属公司 CompanyUUID → CompanyName,使用 useResolveUUIDs composable(带缓存)
* - 原生 buildApiUrl 无 admin_verify 分支(本页未启用特权模式),拦截器按 URL 自动处理 * - 原生 buildApiUrl 无 admin_verify 分支(本页未启用特权模式),拦截器按 URL 自动处理
*/ */
import { ref, reactive, computed, onMounted } from 'vue' import { ref, reactive, computed, onMounted, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import DetailPage from '@/components/DetailPage.vue' import DetailPage from '@/components/DetailPage.vue'
@@ -32,8 +32,8 @@ const route = useRoute()
const router = useRouter() const router = useRouter()
const { resolveUUIDs } = useResolveUUIDs() const { resolveUUIDs } = useResolveUUIDs()
// 路由参数:工作组 UUID // 路由参数:工作组 UUID(computed 响应式:同一 tab 复用且 query 变化时自动更新)
const workgroupUUID = (route.query.WorkgroupUUID as string) || '' const workgroupUUID = computed(() => (route.query.WorkgroupUUID as string) || '')
// === 状态 === // === 状态 ===
const loading = ref(false) const loading = ref(false)
@@ -56,15 +56,15 @@ const title = computed(() => data.value?.WorkgroupName || '工作组详情')
// === 数据加载 === // === 数据加载 ===
async function loadData(): Promise<void> { async function loadData(): Promise<void> {
if (!workgroupUUID) { if (!workgroupUUID.value) {
ElMessage.warning('缺少 WorkgroupUUID 参数,无法加载工作组详情') ElMessage.warning('缺少 WorkgroupUUID 参数,无法加载工作组详情')
return return
} }
loading.value = true loading.value = true
try { try {
const result = await formApi.list('Workgroup', { [PK_FIELD]: workgroupUUID, pageSize: 1 }) const result = await formApi.list('Workgroup', { [PK_FIELD]: workgroupUUID.value, pageSize: 1 })
const list: any[] = Array.isArray(result) ? result : (result as any)?.list || [] const list: any[] = Array.isArray(result) ? result : (result as any)?.list || []
const row = list.find((w) => w[PK_FIELD] === workgroupUUID) || list[0] const row = list.find((w) => w[PK_FIELD] === workgroupUUID.value) || list[0]
if (!row) { if (!row) {
ElMessage.error('未找到工作组数据') ElMessage.error('未找到工作组数据')
return return
@@ -143,6 +143,15 @@ function goRoleDetail(row: Record<string, any>): void {
onMounted(async () => { onMounted(async () => {
await Promise.all([loadData(), loadColumns()]) await Promise.all([loadData(), loadColumns()])
}) })
// 同一 tab 复用(v-show 常驻)时 query 变化:重新加载(防展示旧工作组数据 / 缺参报错)
watch(workgroupUUID, () => {
if (!workgroupUUID.value) {
ElMessage.warning('缺少 WorkgroupUUID 参数,无法加载工作组详情')
return
}
void loadData()
})
</script> </script>
<template> <template>
+17 -8
View File
@@ -18,7 +18,7 @@
* - 权限树分配:跳 /system/role-permissions?RoleUUID=xxx(RolePermissions 页用 el-tree 实现) * - 权限树分配:跳 /system/role-permissions?RoleUUID=xxx(RolePermissions 页用 el-tree 实现)
* - role_scope 细粒度判断暂用 userStore.isAdmin 二分(TODO) * - role_scope 细粒度判断暂用 userStore.isAdmin 二分(TODO)
*/ */
import { ref, reactive, computed, onMounted } from 'vue' import { ref, reactive, computed, onMounted, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import DetailPage from '@/components/DetailPage.vue' import DetailPage from '@/components/DetailPage.vue'
@@ -34,8 +34,8 @@ const route = useRoute()
const router = useRouter() const router = useRouter()
const userStore = useUserStore() const userStore = useUserStore()
// 路由参数:角色 UUID // 路由参数:角色 UUID(computed 响应式:同一 tab 复用且 query 变化时自动更新)
const roleUUID = (route.query.RoleUUID as string) || '' const roleUUID = computed(() => (route.query.RoleUUID as string) || '')
// === 状态 === // === 状态 ===
const loading = ref(false) const loading = ref(false)
@@ -111,15 +111,15 @@ const formColumns = computed(() =>
// === 数据加载 === // === 数据加载 ===
async function loadData(): Promise<void> { async function loadData(): Promise<void> {
if (!roleUUID) { if (!roleUUID.value) {
ElMessage.warning('缺少 RoleUUID 参数,无法加载角色详情') ElMessage.warning('缺少 RoleUUID 参数,无法加载角色详情')
return return
} }
loading.value = true loading.value = true
try { try {
const result = await formApi.list('Role', { [PK_FIELD]: roleUUID, pageSize: 1 }) const result = await formApi.list('Role', { [PK_FIELD]: roleUUID.value, pageSize: 1 })
const list: any[] = Array.isArray(result) ? result : (result as any)?.list || [] const list: any[] = Array.isArray(result) ? result : (result as any)?.list || []
const row = list.find((r) => r[PK_FIELD] === roleUUID) || list[0] const row = list.find((r) => r[PK_FIELD] === roleUUID.value) || list[0]
if (!row) { if (!row) {
ElMessage.error('未找到角色数据') ElMessage.error('未找到角色数据')
return return
@@ -164,11 +164,11 @@ async function handleSubmit(): Promise<void> {
/** 跳转权限树分配页(RolePermissions) */ /** 跳转权限树分配页(RolePermissions) */
function goPermissionTree(): void { function goPermissionTree(): void {
if (!roleUUID) { if (!roleUUID.value) {
ElMessage.warning('缺少 RoleUUID') ElMessage.warning('缺少 RoleUUID')
return return
} }
router.push({ path: '/system/role-permissions', query: { RoleUUID: roleUUID } }) router.push({ path: '/system/role-permissions', query: { RoleUUID: roleUUID.value } })
} }
// === 子表跳转 === // === 子表跳转 ===
@@ -181,6 +181,15 @@ function goUserDetail(row: Record<string, any>): void {
onMounted(async () => { onMounted(async () => {
await Promise.all([loadData(), loadColumns()]) await Promise.all([loadData(), loadColumns()])
}) })
// 同一 tab 复用(v-show 常驻)时 query 变化:重新加载(防展示旧角色数据 / 缺参报错)
watch(roleUUID, () => {
if (!roleUUID.value) {
ElMessage.warning('缺少 RoleUUID 参数,无法加载角色详情')
return
}
void loadData()
})
</script> </script>
<template> <template>
+17 -8
View File
@@ -20,7 +20,7 @@
* - role_scope 细粒度判断暂用 userStore.isAdmin 二分(TODO:接入 checkAdmin 后补 dept_manager / workgroup_lead) * - role_scope 细粒度判断暂用 userStore.isAdmin 二分(TODO:接入 checkAdmin 后补 dept_manager / workgroup_lead)
* - 2FA 接口:get('/API/SiteUserManagement/GetUser2FAInfo', { UserUUID })(TODO:契约确认) * - 2FA 接口:get('/API/SiteUserManagement/GetUser2FAInfo', { UserUUID })(TODO:契约确认)
*/ */
import { ref, reactive, computed, onMounted } from 'vue' import { ref, reactive, computed, onMounted, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import DetailPage from '@/components/DetailPage.vue' import DetailPage from '@/components/DetailPage.vue'
@@ -37,8 +37,8 @@ const route = useRoute()
const router = useRouter() const router = useRouter()
const userStore = useUserStore() const userStore = useUserStore()
// 路由参数:用户 UUID // 路由参数:用户 UUID(computed 响应式:同一 tab 复用且 query 变化时自动更新)
const userUUID = (route.query.UserUUID as string) || '' const userUUID = computed(() => (route.query.UserUUID as string) || '')
// === 状态 === // === 状态 ===
const loading = ref(false) const loading = ref(false)
@@ -128,15 +128,15 @@ const formColumns = computed(() =>
/** 加载用户主表单条数据 */ /** 加载用户主表单条数据 */
async function loadData(): Promise<void> { async function loadData(): Promise<void> {
if (!userUUID) { if (!userUUID.value) {
ElMessage.warning('缺少 UserUUID 参数,无法加载用户详情') ElMessage.warning('缺少 UserUUID 参数,无法加载用户详情')
return return
} }
loading.value = true loading.value = true
try { try {
const result = await formApi.list('User', { [PK_FIELD]: userUUID, pageSize: 1 }) const result = await formApi.list('User', { [PK_FIELD]: userUUID.value, pageSize: 1 })
const list: any[] = Array.isArray(result) ? result : (result as any)?.list || [] const list: any[] = Array.isArray(result) ? result : (result as any)?.list || []
const row = list.find((u) => u[PK_FIELD] === userUUID) || list[0] const row = list.find((u) => u[PK_FIELD] === userUUID.value) || list[0]
if (!row) { if (!row) {
ElMessage.error('未找到用户数据') ElMessage.error('未找到用户数据')
return return
@@ -150,10 +150,10 @@ async function loadData(): Promise<void> {
/** 加载 2FA 双因素信息(TODO:接口契约确认后补全渲染) */ /** 加载 2FA 双因素信息(TODO:接口契约确认后补全渲染) */
async function loadTwoFactor(): Promise<void> { async function loadTwoFactor(): Promise<void> {
if (!userUUID) return if (!userUUID.value) return
try { try {
// TODO: GetUser2FAInfo 返回字段契约确认(Enabled / BackupCodes / BoundAt 等) // TODO: GetUser2FAInfo 返回字段契约确认(Enabled / BackupCodes / BoundAt 等)
twoFactorInfo.value = await get('/API/SiteUserManagement/GetUser2FAInfo', { UserUUID: userUUID }) twoFactorInfo.value = await get('/API/SiteUserManagement/GetUser2FAInfo', { UserUUID: userUUID.value })
} catch { } catch {
// 2FA 信息加载失败不阻塞主流程(拦截器已统一提示) // 2FA 信息加载失败不阻塞主流程(拦截器已统一提示)
twoFactorInfo.value = null twoFactorInfo.value = null
@@ -208,6 +208,15 @@ onMounted(async () => {
await Promise.all([loadData(), loadColumns()]) await Promise.all([loadData(), loadColumns()])
void loadTwoFactor() void loadTwoFactor()
}) })
// 同一 tab 复用(v-show 常驻)时 query 变化:重新加载(防展示旧用户数据 / 缺参报错)
watch(userUUID, () => {
if (!userUUID.value) {
ElMessage.warning('缺少 UserUUID 参数,无法加载用户详情')
return
}
void loadData()
})
</script> </script>
<template> <template>