1414 <template #dropdown >
1515 <el-dropdown-menu >
1616 <el-dropdown-item command =" profile" >设置</el-dropdown-item >
17- <el-dropdown-item divided command =" OIDC" >OIDC设置</el-dropdown-item >
18- <el-dropdown-item divided command =" logout" >退出登录</el-dropdown-item >
17+ <el-dropdown-item divided command =" SSO" >SSO设置</el-dropdown-item >
18+ <el-dropdown-item divided command =" logout"
19+ >退出登录</el-dropdown-item
20+ >
1921 </el-dropdown-menu >
2022 </template >
2123 </el-dropdown >
6870 <h3 >{{ getPageTitle() }}</h3 >
6971 </div >
7072 </template >
71-
73+
7274 <div class =" dashboard-content" >
7375 <div v-if =" activeMenu === 'overview'" class =" overview-page" >
7476 <HomeHero compact />
7577 </div >
76- <UsersPage
78+ <UsersPage
7779 v-else-if =" activeMenu === 'users'"
7880 :users =" users"
7981 :is-admin =" isAdmin"
8991</template >
9092
9193<script setup lang="ts">
92- import { ref , computed , onMounted , watchEffect , nextTick } from ' vue'
93- import { useRouter } from ' vue-router'
94- import { removeToken , getUserProfile , clearUserProfile } from ' @/utils/auth'
95- import { useWarningConfirm } from ' @/utils/msgTip'
96- import {
97- ArrowDown ,
98- House ,
99- User
100- } from ' @element-plus/icons-vue'
101- import UsersPage from ' @/components/dashboard/UsersPage.vue'
102- import HomeHero from ' @/components/HomeHero.vue'
103- import { getUserList } from ' @/api/user'
104- import type { User as ApiUser } from ' @/api/types'
105-
106- type MenuKey = ' overview' | ' projects' | ' users'
107-
108- const router = useRouter ()
109- const activeMenu = ref <MenuKey >(' overview' )
94+ import { ref , computed , onMounted , watchEffect , nextTick } from " vue" ;
95+ import { useRouter } from " vue-router" ;
96+ import { removeToken , getUserProfile , clearUserProfile } from " @/utils/auth" ;
97+ import { useWarningConfirm } from " @/utils/msgTip" ;
98+ import { ArrowDown , House , User } from " @element-plus/icons-vue" ;
99+ import UsersPage from " @/components/dashboard/UsersPage.vue" ;
100+ import HomeHero from " @/components/HomeHero.vue" ;
101+ import { getUserList } from " @/api/user" ;
102+ import type { User as ApiUser } from " @/api/types" ;
103+
104+ type MenuKey = " overview" | " projects" | " users" ;
105+
106+ const router = useRouter ();
107+ const activeMenu = ref <MenuKey >(" overview" );
110108const fullName = computed (() => {
111- const profile = getUserProfile () as any
112- const name = (profile ?.surName ?? ' ' ) + (profile ?.givenName ?? ' ' )
113- return name || ' 用户 '
114- })
109+ const profile = getUserProfile () as any ;
110+ const name = (profile ?.surName ?? " " ) + (profile ?.givenName ?? " " );
111+ return name || " 用户 " ;
112+ });
115113
116114// 用户数据
117- const users = ref <ApiUser []>([])
118- const usersLoading = ref <boolean >(false )
115+ const users = ref <ApiUser []>([]);
116+ const usersLoading = ref <boolean >(false );
119117
120- const profile = computed (() => (getUserProfile () as any ) || {})
121- const isAdmin = computed (() => profile .value ?.role === ' admin' )
122- const isDefault = computed (() => profile .value ?.role === ' default' )
123- const isRestricted = computed (() => profile .value ?.role === ' restricted' )
118+ const profile = computed (() => (getUserProfile () as any ) || {});
119+ const isAdmin = computed (() => profile .value ?.role === " admin" );
120+ const isDefault = computed (() => profile .value ?.role === " default" );
121+ const isRestricted = computed (() => profile .value ?.role === " restricted" );
124122
125123// 获取页面标题
126124const getPageTitle = () => {
127125 const titles: Record <MenuKey , string > = {
128- overview: ' 系统概览' ,
129- projects: ' 项目管理' ,
130- users: ' 用户管理'
131- }
132- return titles [activeMenu .value ]
133- }
126+ overview: " 系统概览" ,
127+ projects: " 项目管理" ,
128+ users: " 用户管理" ,
129+ };
130+ return titles [activeMenu .value ];
131+ };
134132
135133// 处理菜单选择
136134const handleMenuSelect = (index : string ) => {
137- activeMenu .value = index as MenuKey
138- }
135+ activeMenu .value = index as MenuKey ;
136+ };
139137
140138// 处理用户下拉菜单命令
141139const handleCommand = async (command : string ) => {
142140 switch (command ) {
143- case ' profile' :
144- router .push (' /profile' )
145- break
146- case ' logout' :
147- await handleLogout ()
148- break
149- case ' OIDC' :
150- window .open (' https://keycloak.internal.asynclab.club/realms/asynclab/account ' , ' _blank' )
151- break
141+ case " profile" :
142+ router .push (" /profile" );
143+ break ;
144+ case " logout" :
145+ await handleLogout ();
146+ break ;
147+ case " SSO" :
148+ window .open (
149+ " https://sso.internal.asynclab.club/realms/asynclab/account " ,
150+ " _blank"
151+ );
152+ break ;
152153 }
153- }
154+ };
154155
155156// 处理退出登录
156157const handleLogout = async () => {
157158 try {
158- await useWarningConfirm (' 确定要退出登录吗?' )
159- removeToken ()
160- clearUserProfile ()
161- router .push (' /login' )
159+ await useWarningConfirm (" 确定要退出登录吗?" );
160+ removeToken ();
161+ clearUserProfile ();
162+ router .push (" /login" );
162163 } catch {
163164 // 用户取消退出
164165 }
165- }
166+ };
166167
167168// 用户相关方法
168169const createUser = () => {
169- console .log (' 创建用户' )
170- }
170+ console .log (" 创建用户" );
171+ };
171172
172173// 已由 UsersPage 内部处理编辑/删除,通过 refresh 事件回传,这里无需实现
173174
174175// 加载用户列表并按权限过滤
175176onMounted (async () => {
176- if (activeMenu .value !== ' users' ) return
177- })
177+ if (activeMenu .value !== " users" ) return ;
178+ });
178179
179180// 进入用户管理时拉取数据
180181const loadUsers = async () => {
181- usersLoading .value = true
182- const list = await getUserList () as any
183- let data: ApiUser [] = Array .isArray (list ?.data ) ? list .data : (Array .isArray (list ) ? list : [])
182+ usersLoading .value = true ;
183+ const list = (await getUserList ()) as any ;
184+ let data: ApiUser [] = Array .isArray (list ?.data )
185+ ? list .data
186+ : Array .isArray (list )
187+ ? list
188+ : [];
184189 if (isAdmin .value ) {
185- users .value = data
190+ users .value = data ;
186191 } else if (isDefault .value ) {
187192 // 仅同组(按 category 分组)
188- const myCategory = profile .value ?.category
189- users .value = data .filter ((u : any ) => u .category === myCategory && u .role === ' default' )
193+ const myCategory = profile .value ?.category ;
194+ users .value = data .filter (
195+ (u : any ) => u .category === myCategory && u .role === " default"
196+ );
190197 } else if (isRestricted .value ) {
191- users .value = []
198+ users .value = [];
192199 }
193- await nextTick ()
194- usersLoading .value = false
195- }
200+ await nextTick ();
201+ usersLoading .value = false ;
202+ };
196203
197204// 切换到用户管理菜单时触发
198205watchEffect (() => {
199- if (activeMenu .value === ' users' ) {
206+ if (activeMenu .value === " users" ) {
200207 if (isRestricted .value ) {
201208 // 无权限访问
202- users .value = []
203- usersLoading .value = false
209+ users .value = [];
210+ usersLoading .value = false ;
204211 } else {
205- loadUsers ()
212+ loadUsers ();
206213 }
207214 }
208- })
209-
210-
215+ });
211216 </script >
212217
213218<style scoped>
@@ -289,18 +294,30 @@ watchEffect(() => {
289294}
290295
291296@media (max-width : 1200px ) {
292- .dashboard-header { padding : 0 12px ; }
293- .dashboard-main { padding : 12px ; }
297+ .dashboard-header {
298+ padding : 0 12px ;
299+ }
300+ .dashboard-main {
301+ padding : 12px ;
302+ }
294303}
295304
296305@media (max-width : 992px ) {
297- .dashboard-container { display : block ; }
298- .dashboard-sidebar { display : none ; }
306+ .dashboard-container {
307+ display : block ;
308+ }
309+ .dashboard-sidebar {
310+ display : none ;
311+ }
299312}
300313
301314@media (max-width : 768px ) {
302- .dashboard-header { min-height : 56px ; }
303- .dashboard-main { padding : 10px ; }
315+ .dashboard-header {
316+ min-height : 56px ;
317+ }
318+ .dashboard-main {
319+ padding : 10px ;
320+ }
304321}
305322
306323.mobile-nav {
@@ -310,7 +327,9 @@ watchEffect(() => {
310327}
311328
312329@media (max-width : 992px ) {
313- .mobile-nav { display : block ; }
330+ .mobile-nav {
331+ display : block ;
332+ }
314333}
315334
316335/* 概览为空白占位,不添加多余内容 */
@@ -325,15 +344,17 @@ watchEffect(() => {
325344 width : 120px ;
326345 height : 120px ;
327346}
328- </style >
347+ </style >
329348<style >
330349/* 暗色模式覆盖:Dashboard 头部/侧栏/容器/移动导航 */
331350html .dark .dashboard-header {
332351 background : var (--card-bg );
333352 border-bottom-color : var (--border-color );
334353 box-shadow : 0 2px 4px rgba (0 , 0 , 0 , 0.35 );
335354}
336- html .dark .header-left h2 { color : var (--el-color-primary ); }
355+ html .dark .header-left h2 {
356+ color : var (--el-color-primary );
357+ }
337358
338359html .dark .dashboard-sidebar {
339360 background : var (--card-bg );
@@ -349,5 +370,7 @@ html.dark .mobile-nav {
349370 border-bottom-color : var (--border-color );
350371}
351372
352- html .dark .card-header h3 { color : var (--el-text-color-primary ); }
353- </style >
373+ html .dark .card-header h3 {
374+ color : var (--el-text-color-primary );
375+ }
376+ </style >
0 commit comments