fix: 管理员用户详情弹窗崩溃与多俱乐部分配UI
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -3,7 +3,7 @@ const CLUB_SCOPE_KEY = 'admin_club_scope';
|
||||
const CLUB_CONTEXT_KEY = 'admin_club_context';
|
||||
const MENU_ACCESS_KEY = 'kefu_menu_access';
|
||||
const MENU_SESSION_KEY = 'kefu_menu_session_v';
|
||||
const MENU_SESSION_VERSION = '11';
|
||||
const MENU_SESSION_VERSION = '12';
|
||||
const DEFAULT_CLUB_ID = 'xq';
|
||||
|
||||
let menuAccessInflight = null;
|
||||
@@ -25,27 +25,49 @@ export function setAdminClubContext(ctx) {
|
||||
|
||||
export function mergeServerClubContext(serverCtx) {
|
||||
if (!serverCtx) return;
|
||||
const allowedIds = new Set((serverCtx.clubs || []).map((c) => c.club_id));
|
||||
const prevScope = localStorage.getItem(CLUB_SCOPE_KEY);
|
||||
const prevClubId = localStorage.getItem(CLUB_ID_KEY);
|
||||
const merged = { ...serverCtx };
|
||||
if (prevScope) {
|
||||
merged.scope = prevScope === 'all' ? 'ALL_CLUBS' : 'SINGLE_CLUB';
|
||||
merged.club_id = prevClubId || merged.club_id || DEFAULT_CLUB_ID;
|
||||
|
||||
let clubId = serverCtx.club_id || DEFAULT_CLUB_ID;
|
||||
let scopeKey = serverCtx.scope === 'ALL_CLUBS' ? 'all' : 'single';
|
||||
|
||||
if (prevClubId && allowedIds.has(prevClubId)) {
|
||||
clubId = prevClubId;
|
||||
if (prevScope === 'all' && serverCtx.is_group_admin) {
|
||||
scopeKey = 'all';
|
||||
} else if (prevScope === 'single') {
|
||||
scopeKey = 'single';
|
||||
}
|
||||
} else if (prevScope === 'all' && serverCtx.is_group_admin) {
|
||||
scopeKey = 'all';
|
||||
}
|
||||
localStorage.setItem(CLUB_CONTEXT_KEY, JSON.stringify(merged));
|
||||
if (prevClubId) {
|
||||
localStorage.setItem(CLUB_ID_KEY, prevClubId);
|
||||
} else {
|
||||
localStorage.setItem(CLUB_ID_KEY, merged.club_id || DEFAULT_CLUB_ID);
|
||||
}
|
||||
if (prevScope) {
|
||||
localStorage.setItem(CLUB_SCOPE_KEY, prevScope);
|
||||
} else {
|
||||
localStorage.setItem(CLUB_SCOPE_KEY, merged.scope === 'ALL_CLUBS' ? 'all' : 'single');
|
||||
|
||||
const merged = {
|
||||
...serverCtx,
|
||||
club_id: clubId,
|
||||
scope: scopeKey === 'all' ? 'ALL_CLUBS' : 'SINGLE_CLUB',
|
||||
};
|
||||
|
||||
if (scopeKey === 'single' && merged.assignments?.length) {
|
||||
const hit = merged.assignments.find((a) => a.club_id === clubId);
|
||||
if (hit) {
|
||||
merged.role_code = hit.role_code;
|
||||
merged.role_name = hit.role_name;
|
||||
}
|
||||
}
|
||||
|
||||
setAdminClubContext(merged);
|
||||
return merged;
|
||||
}
|
||||
|
||||
export function resetAdminClubContextOnLogin() {
|
||||
localStorage.removeItem(CLUB_ID_KEY);
|
||||
localStorage.removeItem(CLUB_SCOPE_KEY);
|
||||
localStorage.removeItem(CLUB_CONTEXT_KEY);
|
||||
clearMenuAccess();
|
||||
}
|
||||
|
||||
export function getAdminClubContext() {
|
||||
try {
|
||||
const raw = localStorage.getItem(CLUB_CONTEXT_KEY);
|
||||
|
||||
@@ -268,6 +268,7 @@ import {
|
||||
canSwitchClubByMenu,
|
||||
ensureMenuAccess,
|
||||
canShowMenuPage,
|
||||
clearMenuAccess,
|
||||
} from '@/utils/club-context'
|
||||
|
||||
const menuAccessState = ref(getMenuAccess())
|
||||
@@ -359,14 +360,18 @@ const onScopeSelectChange = (val) => {
|
||||
})
|
||||
ElMessage.success('已切换至:集团汇总(全部子公司)')
|
||||
} else {
|
||||
const assign = (ctx.assignments || []).find((a) => a.club_id === val)
|
||||
setAdminClubContext({
|
||||
...ctx,
|
||||
scope: 'SINGLE_CLUB',
|
||||
club_id: val,
|
||||
role_code: assign?.role_code || ctx.role_code,
|
||||
role_name: assign?.role_name || ctx.role_name,
|
||||
})
|
||||
const hit = clubOptions.value.find((c) => c.club_id === val)
|
||||
ElMessage.success(`已切换至:${hit?.name || val}`)
|
||||
}
|
||||
clearMenuAccess()
|
||||
window.location.reload()
|
||||
}
|
||||
|
||||
@@ -523,9 +528,9 @@ provide('permPrefixMap', permPrefixMap)
|
||||
provide('goeasyAppkey', goeasyAppkey)
|
||||
provide('hasAnyChatPerm', hasAnyChatPerm)
|
||||
|
||||
onMounted(() => {
|
||||
loadMenuAccess()
|
||||
loadClubContext()
|
||||
onMounted(async () => {
|
||||
await loadClubContext()
|
||||
await loadMenuAccess()
|
||||
fetchStats()
|
||||
fetchKefuPermission()
|
||||
proxy.$emitter?.on('refresh-stats', fetchStats)
|
||||
|
||||
@@ -65,7 +65,7 @@ import { useRouter } from 'vue-router'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { User, Lock, Key } from '@element-plus/icons-vue'
|
||||
import axios from 'axios' // 直接使用 axios,不经过封装的 request
|
||||
import { JITUAN_API, getDefaultLandingPath, setAdminClubContext, setMenuAccess } from '@/utils/club-context'
|
||||
import { JITUAN_API, getDefaultLandingPath, setAdminClubContext, setMenuAccess, resetAdminClubContextOnLogin } from '@/utils/club-context'
|
||||
|
||||
const router = useRouter()
|
||||
const loading = ref(false)
|
||||
@@ -90,6 +90,7 @@ const handleLogin = async () => {
|
||||
}
|
||||
|
||||
loading.value = true
|
||||
resetAdminClubContextOnLogin()
|
||||
try {
|
||||
// 直接使用 axios 发送请求,baseURL 从 window.$baseURL 获取
|
||||
const response = await axios.post(
|
||||
|
||||
@@ -35,8 +35,8 @@
|
||||
<el-option label="全部角色" value="" />
|
||||
<el-option
|
||||
v-for="role in roleList"
|
||||
:key="role.role_code"
|
||||
:label="role.role_name"
|
||||
:key="`${role.club_id || ''}-${role.role_code}`"
|
||||
:label="roleClubLabel(role)"
|
||||
:value="role.role_code"
|
||||
/>
|
||||
</el-select>
|
||||
@@ -53,12 +53,31 @@
|
||||
<el-table-column prop="phone" label="账号" width="140" />
|
||||
<el-table-column prop="yonghuid" label="用户ID" width="100" />
|
||||
<el-table-column prop="nicheng" label="昵称" width="150" />
|
||||
<el-table-column label="角色" min-width="180">
|
||||
<el-table-column label="俱乐部任职" min-width="200">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-for="role in row.roles" :key="role.role_code" size="small" style="margin-right: 6px;">
|
||||
{{ role.role_name }}
|
||||
<el-tag
|
||||
v-for="a in row.assignments || []"
|
||||
:key="a.id"
|
||||
size="small"
|
||||
:type="a.is_primary ? 'success' : 'info'"
|
||||
style="margin-right: 6px; margin-bottom: 4px;"
|
||||
>
|
||||
{{ a.club_label }}{{ a.is_primary ? '·主' : '' }}
|
||||
</el-tag>
|
||||
<span v-if="!row.roles.length">无角色</span>
|
||||
<span v-if="!(row.assignments || []).length" class="muted-text">未分配</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="角色" min-width="200">
|
||||
<template #default="{ row }">
|
||||
<el-tag
|
||||
v-for="role in (row.roles || [])"
|
||||
:key="`${role.club_id || ''}-${role.role_code}`"
|
||||
size="small"
|
||||
style="margin-right: 6px;"
|
||||
>
|
||||
{{ roleClubLabel(role) }}
|
||||
</el-tag>
|
||||
<span v-if="!(row.roles || []).length">无角色</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" label="状态" width="100">
|
||||
@@ -91,13 +110,15 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 用户详情弹窗 -->
|
||||
<!-- 用户详情弹窗(须在 v-if/v-else 外,避免被条件渲染挡住) -->
|
||||
<el-dialog
|
||||
v-model="detailDialogVisible"
|
||||
:title="`编辑用户 - ${currentUser?.phone}`"
|
||||
width="700px"
|
||||
:title="detailDialogTitle"
|
||||
width="720px"
|
||||
class="user-dialog"
|
||||
destroy-on-close
|
||||
append-to-body
|
||||
align-center
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<div class="dialog-content">
|
||||
<!-- 基本信息 -->
|
||||
@@ -140,10 +161,36 @@
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 俱乐部任职 -->
|
||||
<div class="club-section">
|
||||
<div class="section-title">
|
||||
<span>俱乐部任职(切换范围)</span>
|
||||
<el-button type="primary" size="small" @click="openAddClubDialog">
|
||||
<el-icon><Plus /></el-icon> 添加俱乐部
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="club-assign-list">
|
||||
<div
|
||||
v-for="a in currentUserAssignments"
|
||||
:key="a.id"
|
||||
class="club-assign-item"
|
||||
>
|
||||
<el-tag :type="a.is_primary ? 'success' : 'info'" size="small">
|
||||
{{ a.club_label }}{{ a.is_primary ? '(主任职)' : '' }}
|
||||
</el-tag>
|
||||
<span class="assign-role-label">{{ a.role_name }}</span>
|
||||
<el-button type="danger" link size="small" @click="removeClubAssignment(a)">移除</el-button>
|
||||
</div>
|
||||
<div v-if="currentUserAssignments.length === 0" class="empty-role">
|
||||
暂未分配俱乐部,添加后该用户顶栏可切换;无角色则看不到菜单
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 角色管理 -->
|
||||
<div class="role-section">
|
||||
<div class="section-title">
|
||||
<span>所属角色</span>
|
||||
<span>功能角色(按俱乐部)</span>
|
||||
<el-button type="primary" size="small" @click="openAddRoleForUser">
|
||||
<el-icon><Plus /></el-icon> 添加角色
|
||||
</el-button>
|
||||
@@ -151,10 +198,10 @@
|
||||
<div class="role-list">
|
||||
<div
|
||||
v-for="role in currentUserRoles"
|
||||
:key="role.role_code"
|
||||
:key="`${role.club_id}-${role.role_code}`"
|
||||
class="role-tag"
|
||||
>
|
||||
{{ role.role_name }}
|
||||
{{ roleClubLabel(role) }}
|
||||
<el-icon class="remove-icon" @click="removeUserRole(role)">
|
||||
<Close />
|
||||
</el-icon>
|
||||
@@ -176,14 +223,28 @@
|
||||
<el-dialog
|
||||
v-model="addRoleForUserVisible"
|
||||
title="添加角色"
|
||||
width="500px"
|
||||
width="520px"
|
||||
class="role-select-dialog"
|
||||
append-to-body
|
||||
align-center
|
||||
>
|
||||
<el-form label-width="100px">
|
||||
<el-form-item label="所属俱乐部" required>
|
||||
<el-select v-model="roleBindClubId" placeholder="先选俱乐部" style="width: 100%" @change="selectedRoleCodes = []">
|
||||
<el-option
|
||||
v-for="c in clubOptions"
|
||||
:key="c.club_id"
|
||||
:label="c.name"
|
||||
:value="c.club_id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="role-select-list">
|
||||
<el-checkbox-group v-model="selectedRoleCodes">
|
||||
<div
|
||||
v-for="role in availableRolesForUser"
|
||||
:key="role.role_code"
|
||||
:key="`${role.club_id}-${role.role_code}`"
|
||||
class="role-select-item"
|
||||
>
|
||||
<el-checkbox :label="role.role_code">
|
||||
@@ -191,6 +252,8 @@
|
||||
</el-checkbox>
|
||||
</div>
|
||||
</el-checkbox-group>
|
||||
<div v-if="!roleBindClubId" class="empty-role">请先选择俱乐部</div>
|
||||
<div v-else-if="!availableRolesForUser.length" class="empty-role">该俱乐部下无可选角色</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="addRoleForUserVisible = false">取消</el-button>
|
||||
@@ -198,13 +261,47 @@
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 添加俱乐部任职 -->
|
||||
<el-dialog v-model="addClubVisible" title="添加俱乐部任职" width="480px" append-to-body align-center>
|
||||
<el-form label-width="100px">
|
||||
<el-form-item label="俱乐部" required>
|
||||
<el-select v-model="clubAssignForm.club_id" placeholder="选择俱乐部" style="width: 100%">
|
||||
<el-option
|
||||
v-for="c in availableClubsForAssign"
|
||||
:key="c.club_id"
|
||||
:label="c.name"
|
||||
:value="c.club_id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="任职标签">
|
||||
<el-select v-model="clubAssignForm.role_code" style="width: 100%">
|
||||
<el-option label="俱乐部管理员" value="CLUB_ADMIN" />
|
||||
<el-option label="俱乐部总负责人" value="CLUB_OWNER" />
|
||||
<el-option label="俱乐部财务" value="CLUB_FINANCE" />
|
||||
<el-option label="俱乐部售后" value="CLUB_AFTER_SALES" />
|
||||
<el-option label="俱乐部运营" value="CLUB_OPERATOR" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="主任职">
|
||||
<el-switch v-model="clubAssignForm.is_primary" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="form-hint">添加后用户顶栏可切到该俱乐部;再为该俱乐部绑功能角色才有菜单。</div>
|
||||
<template #footer>
|
||||
<el-button @click="addClubVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="assigningClub" @click="confirmAddClubAssignment">保存</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 添加用户弹窗 -->
|
||||
<el-dialog
|
||||
v-model="addUserDialogVisible"
|
||||
title="添加后台用户"
|
||||
width="600px"
|
||||
class="user-dialog"
|
||||
destroy-on-close
|
||||
append-to-body
|
||||
align-center
|
||||
>
|
||||
<div class="dialog-content">
|
||||
<el-form :model="newUserForm" label-width="100px" ref="addUserFormRef">
|
||||
@@ -235,11 +332,11 @@
|
||||
<el-checkbox-group v-model="newUserRoleCodes">
|
||||
<div
|
||||
v-for="role in roleList"
|
||||
:key="role.role_code"
|
||||
:key="`${role.club_id || ''}-${role.role_code}`"
|
||||
class="role-select-item"
|
||||
>
|
||||
<el-checkbox :label="role.role_code">
|
||||
<span>{{ role.role_name }}</span>
|
||||
<span>{{ roleClubLabel(role) }}</span>
|
||||
</el-checkbox>
|
||||
</div>
|
||||
</el-checkbox-group>
|
||||
@@ -249,20 +346,35 @@
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="addUserDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="confirmAddUser">确认添加</el-button>
|
||||
<el-button type="primary" :loading="addingUser" :disabled="addingUser" @click="confirmAddUser">确认添加</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { ref, computed, onMounted, nextTick } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Plus, Close } from '@element-plus/icons-vue'
|
||||
import request from '@/utils/request'
|
||||
import { JITUAN_API, getAdminClubContext } from '@/utils/club-context'
|
||||
|
||||
const username = localStorage.getItem('username') || ''
|
||||
|
||||
const clubOptions = ref([])
|
||||
const clubNameMap = computed(() => {
|
||||
const m = {}
|
||||
for (const c of clubOptions.value) m[c.club_id] = c.name
|
||||
return m
|
||||
})
|
||||
|
||||
const roleClubLabel = (role) => {
|
||||
if (!role) return ''
|
||||
const cid = role.club_id || ''
|
||||
const cname = cid ? (clubNameMap.value[cid] || cid) : '全局'
|
||||
return `[${cname}] ${role.role_name || role.role_code || ''}`
|
||||
}
|
||||
|
||||
// 权限状态
|
||||
const hasPermission = ref(true)
|
||||
|
||||
@@ -293,13 +405,39 @@ const editForm = ref({
|
||||
status: 1
|
||||
})
|
||||
const currentUserRoles = ref([])
|
||||
const currentUserAssignments = ref([])
|
||||
|
||||
const detailDialogTitle = computed(() => {
|
||||
const u = currentUser.value
|
||||
if (!u) return '编辑用户'
|
||||
return `编辑用户 - ${u.phone || u.yonghuid || ''}`
|
||||
})
|
||||
|
||||
// 为用户添加角色弹窗
|
||||
const addRoleForUserVisible = ref(false)
|
||||
const selectedRoleCodes = ref([])
|
||||
const roleBindClubId = ref('')
|
||||
|
||||
// 俱乐部任职
|
||||
const addClubVisible = ref(false)
|
||||
const assigningClub = ref(false)
|
||||
const clubAssignForm = ref({ club_id: '', role_code: 'CLUB_ADMIN', is_primary: false })
|
||||
|
||||
const availableClubsForAssign = computed(() => {
|
||||
const assigned = new Set(currentUserAssignments.value.map((a) => a.club_id))
|
||||
return clubOptions.value.filter((c) => !assigned.has(c.club_id))
|
||||
})
|
||||
|
||||
const availableRolesForUser = computed(() => {
|
||||
const existingCodes = currentUserRoles.value.map(r => r.role_code)
|
||||
return roleList.value.filter(r => !existingCodes.includes(r.role_code))
|
||||
if (!roleBindClubId.value) return []
|
||||
const existing = new Set(
|
||||
currentUserRoles.value
|
||||
.filter((r) => (r.club_id || '') === roleBindClubId.value)
|
||||
.map((r) => r.role_code)
|
||||
)
|
||||
return roleList.value.filter(
|
||||
(r) => (r.club_id || '') === roleBindClubId.value && !existing.has(r.role_code)
|
||||
)
|
||||
})
|
||||
|
||||
// 添加用户弹窗
|
||||
@@ -311,12 +449,16 @@ const newUserForm = ref({
|
||||
nicheng: ''
|
||||
})
|
||||
const newUserRoleCodes = ref([])
|
||||
const addingUser = ref(false)
|
||||
|
||||
// ==================== 接口调用 ====================
|
||||
// 获取角色列表(第一个接口)
|
||||
// 获取角色列表(全部俱乐部,用于分俱乐部绑角色)
|
||||
const fetchRoleList = async () => {
|
||||
try {
|
||||
const res = await request.post('/houtai/hqyhjsgl', { username })
|
||||
let res = await request.post('/houtai/hqyhjsgl', { username, all_clubs: true })
|
||||
if (res.code !== 0) {
|
||||
res = await request.post('/houtai/hqyhjsgl', { username })
|
||||
}
|
||||
if (res.code === 0) {
|
||||
roleList.value = res.data.roles || []
|
||||
return true
|
||||
@@ -333,6 +475,20 @@ const fetchRoleList = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const loadClubOptions = async () => {
|
||||
try {
|
||||
const res = await request.get(JITUAN_API.clubList, { skipErrorToast: true })
|
||||
if (res.code === 0 && Array.isArray(res.data)) {
|
||||
clubOptions.value = res.data.map((c) => ({ club_id: c.club_id, name: c.name }))
|
||||
return
|
||||
}
|
||||
} catch {
|
||||
// fallback
|
||||
}
|
||||
const ctx = getAdminClubContext()
|
||||
clubOptions.value = ctx?.clubs || []
|
||||
}
|
||||
|
||||
// 获取用户列表
|
||||
const fetchUserList = async () => {
|
||||
if (!hasPermission.value) return
|
||||
@@ -372,16 +528,25 @@ const resetFilters = () => {
|
||||
}
|
||||
|
||||
// 打开用户详情弹窗
|
||||
const openDetailDialog = (user) => {
|
||||
currentUser.value = user
|
||||
editForm.value = {
|
||||
nicheng: user.nicheng || '',
|
||||
password: '',
|
||||
erjimima: '',
|
||||
status: user.status
|
||||
const openDetailDialog = async (user) => {
|
||||
if (!user) return
|
||||
try {
|
||||
currentUser.value = { ...user }
|
||||
editForm.value = {
|
||||
nicheng: user.nicheng || '',
|
||||
password: '',
|
||||
erjimima: '',
|
||||
status: user.status ?? 1,
|
||||
}
|
||||
currentUserRoles.value = Array.isArray(user.roles) ? [...user.roles] : []
|
||||
currentUserAssignments.value = Array.isArray(user.assignments) ? [...user.assignments] : []
|
||||
detailDialogVisible.value = false
|
||||
await nextTick()
|
||||
detailDialogVisible.value = true
|
||||
} catch (e) {
|
||||
console.error('openDetailDialog failed:', e)
|
||||
ElMessage.error('打开详情失败,请刷新页面重试')
|
||||
}
|
||||
currentUserRoles.value = [...(user.roles || [])]
|
||||
detailDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 保存用户修改(昵称、密码、二级密码、状态、角色已通过其他接口单独处理)
|
||||
@@ -418,11 +583,81 @@ const saveUserInfo = async () => {
|
||||
// 为用户添加角色(打开弹窗)
|
||||
const openAddRoleForUser = () => {
|
||||
selectedRoleCodes.value = []
|
||||
roleBindClubId.value = currentUserAssignments.value[0]?.club_id || clubOptions.value[0]?.club_id || ''
|
||||
addRoleForUserVisible.value = true
|
||||
}
|
||||
|
||||
const openAddClubDialog = () => {
|
||||
clubAssignForm.value = {
|
||||
club_id: availableClubsForAssign.value[0]?.club_id || '',
|
||||
role_code: 'CLUB_ADMIN',
|
||||
is_primary: currentUserAssignments.value.length === 0,
|
||||
}
|
||||
addClubVisible.value = true
|
||||
}
|
||||
|
||||
const confirmAddClubAssignment = async () => {
|
||||
if (!clubAssignForm.value.club_id) {
|
||||
ElMessage.warning('请选择俱乐部')
|
||||
return
|
||||
}
|
||||
assigningClub.value = true
|
||||
try {
|
||||
const res = await request.post('/houtai/xghtyhsj', {
|
||||
username,
|
||||
action: 'add_club_assignment',
|
||||
yonghuid: currentUser.value.yonghuid,
|
||||
phone: currentUser.value.phone,
|
||||
club_id: clubAssignForm.value.club_id,
|
||||
role_code: clubAssignForm.value.role_code,
|
||||
is_primary: clubAssignForm.value.is_primary,
|
||||
})
|
||||
if (res.code === 0) {
|
||||
ElMessage.success('俱乐部任职已添加')
|
||||
addClubVisible.value = false
|
||||
await fetchUserList()
|
||||
const updated = userList.value.find((u) => u.yonghuid === currentUser.value.yonghuid)
|
||||
if (updated) {
|
||||
currentUserAssignments.value = [...(updated.assignments || [])]
|
||||
}
|
||||
} else {
|
||||
ElMessage.error(res.msg || '添加失败')
|
||||
}
|
||||
} catch {
|
||||
ElMessage.error('网络错误')
|
||||
} finally {
|
||||
assigningClub.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const removeClubAssignment = async (row) => {
|
||||
try {
|
||||
await ElMessageBox.confirm(`移除 ${row.club_label} 任职?`, '提示', { type: 'warning' })
|
||||
const res = await request.post('/houtai/xghtyhsj', {
|
||||
username,
|
||||
action: 'remove_club_assignment',
|
||||
yonghuid: currentUser.value.yonghuid,
|
||||
phone: currentUser.value.phone,
|
||||
assignment_id: row.id,
|
||||
})
|
||||
if (res.code === 0) {
|
||||
ElMessage.success('已移除')
|
||||
currentUserAssignments.value = currentUserAssignments.value.filter((a) => a.id !== row.id)
|
||||
fetchUserList()
|
||||
} else {
|
||||
ElMessage.error(res.msg || '移除失败')
|
||||
}
|
||||
} catch {
|
||||
// cancel
|
||||
}
|
||||
}
|
||||
|
||||
// 确认添加角色
|
||||
const confirmAddUserRoles = async () => {
|
||||
if (!roleBindClubId.value) {
|
||||
ElMessage.warning('请先选择俱乐部')
|
||||
return
|
||||
}
|
||||
if (selectedRoleCodes.value.length === 0) {
|
||||
ElMessage.warning('请至少选择一个角色')
|
||||
return
|
||||
@@ -433,17 +668,17 @@ const confirmAddUserRoles = async () => {
|
||||
action: 'add_user_roles',
|
||||
yonghuid: currentUser.value.yonghuid,
|
||||
phone: currentUser.value.phone,
|
||||
role_codes: selectedRoleCodes.value
|
||||
role_codes: selectedRoleCodes.value,
|
||||
target_club_id: roleBindClubId.value,
|
||||
})
|
||||
if (res.code === 0) {
|
||||
ElMessage.success('角色添加成功')
|
||||
// 刷新当前用户的角色列表
|
||||
const updatedUser = userList.value.find(u => u.phone === currentUser.value.phone)
|
||||
if (updatedUser) {
|
||||
currentUserRoles.value = [...(updatedUser.roles || []), ...roleList.value.filter(r => selectedRoleCodes.value.includes(r.role_code))]
|
||||
}
|
||||
addRoleForUserVisible.value = false
|
||||
fetchUserList() // 刷新列表
|
||||
await fetchUserList()
|
||||
const updated = userList.value.find((u) => u.yonghuid === currentUser.value.yonghuid)
|
||||
if (updated) {
|
||||
currentUserRoles.value = [...(updated.roles || [])]
|
||||
}
|
||||
} else {
|
||||
ElMessage.error(res.msg || '添加失败')
|
||||
}
|
||||
@@ -460,7 +695,8 @@ const removeUserRole = async (role) => {
|
||||
action: 'remove_user_role',
|
||||
yonghuid: currentUser.value.yonghuid,
|
||||
phone: currentUser.value.phone,
|
||||
role_code: role.role_code
|
||||
role_code: role.role_code,
|
||||
target_club_id: role.club_id || '',
|
||||
})
|
||||
if (res.code === 0) {
|
||||
ElMessage.success('角色移除成功')
|
||||
@@ -484,6 +720,7 @@ const openAddUserDialog = () => {
|
||||
|
||||
// 确认添加用户
|
||||
const confirmAddUser = async () => {
|
||||
if (addingUser.value) return
|
||||
if (!newUserForm.value.phone || !newUserForm.value.password || !newUserForm.value.erjimima || !newUserForm.value.nicheng) {
|
||||
ElMessage.warning('请填写完整信息')
|
||||
return
|
||||
@@ -492,6 +729,7 @@ const confirmAddUser = async () => {
|
||||
ElMessage.warning('密码和二级密码至少6位')
|
||||
return
|
||||
}
|
||||
addingUser.value = true
|
||||
try {
|
||||
const res = await request.post('/houtai/tjyhjs', {
|
||||
username,
|
||||
@@ -510,6 +748,8 @@ const confirmAddUser = async () => {
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error('网络错误')
|
||||
} finally {
|
||||
addingUser.value = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -519,6 +759,7 @@ onMounted(async () => {
|
||||
ElMessage.error('未获取到用户信息')
|
||||
return
|
||||
}
|
||||
await loadClubOptions()
|
||||
const success = await fetchRoleList()
|
||||
if (success) {
|
||||
await fetchUserList()
|
||||
@@ -672,6 +913,28 @@ onMounted(async () => {
|
||||
padding: 20px 0;
|
||||
text-align: center;
|
||||
}
|
||||
.muted-text {
|
||||
color: rgba(255,255,255,0.45);
|
||||
font-size: 13px;
|
||||
}
|
||||
.club-assign-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
.club-assign-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 8px 12px;
|
||||
background: rgba(255,255,255,0.05);
|
||||
border-radius: 8px;
|
||||
}
|
||||
.assign-role-label {
|
||||
flex: 1;
|
||||
color: rgba(255,255,255,0.65);
|
||||
font-size: 13px;
|
||||
}
|
||||
.role-select-list {
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
:closable="false"
|
||||
show-icon
|
||||
class="scope-tip"
|
||||
title="操作权限在「角色管理」里配"
|
||||
description="查看会员=3300a、财务=caiwu、订单=002ab 等:角色管理 → 角色详情 → 添加权限。给账号绑角色:管理员用户。"
|
||||
title="多俱乐部 + 分俱乐部权限(推荐)"
|
||||
description="1)本页「添加任职」:同一账号可添加多条,分别指定星阙、星之界等俱乐部(无需集团权限即可顶栏切换)。2)「角色管理」为各俱乐部创建角色并配权限码。3)「管理员用户」绑定角色时,请先在顶栏切到对应俱乐部再绑,或传 target_club_id。切换俱乐部后菜单/权限按该俱乐部的角色生效。"
|
||||
/>
|
||||
|
||||
<el-alert
|
||||
@@ -16,8 +16,8 @@
|
||||
:closable="false"
|
||||
show-icon
|
||||
class="scope-tip"
|
||||
title="集团高管 / 查看全部订单与用户"
|
||||
description="功能权限:角色管理里给「订单 002ab」「用户列表」等权限。数据范围:本页添加任职,范围选「全部俱乐部 ALL_CLUBS」,登录后顶栏切「集团汇总」即可看全部订单/财务/用户(统计按各俱乐部汇总,不串单俱乐部数据)。"
|
||||
title="集团汇总(可选)"
|
||||
description="仅当需要一次看全部子公司汇总数据时,才添加「集团(全部子公司)」任职。普通多俱乐部负责人不必给集团权限,分别添加各俱乐部任职即可。"
|
||||
/>
|
||||
|
||||
<div class="action-bar">
|
||||
@@ -167,7 +167,7 @@
|
||||
<el-option label="俱乐部售后" value="CLUB_AFTER_SALES" />
|
||||
<el-option label="俱乐部运营" value="CLUB_OPERATOR" />
|
||||
</el-select>
|
||||
<div class="role-hint">任职角色只是备注标签,<strong>不能</strong>替代「角色管理」里的功能权限。</div>
|
||||
<div class="role-hint">任职角色为管理标签;实际菜单权限请在「角色管理」为该俱乐部创建角色,并在「管理员用户」绑定。</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="主任职">
|
||||
|
||||
Reference in New Issue
Block a user