登录和列表
This commit is contained in:
parent
90d40386ac
commit
4946911f1c
17
api/src/main/java/com/lktx/center/config/AllException.java
Normal file
17
api/src/main/java/com/lktx/center/config/AllException.java
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package com.lktx.center.config;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.exception.NotLoginException;
|
||||||
|
import cn.hserver.core.ioc.annotation.Bean;
|
||||||
|
import cn.hserver.core.server.util.JsonResult;
|
||||||
|
import cn.hserver.plugin.web.context.Webkit;
|
||||||
|
import cn.hserver.plugin.web.interfaces.GlobalException;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public class AllException implements GlobalException {
|
||||||
|
@Override
|
||||||
|
public void handler(Throwable throwable, int httpStatusCode, String errorDescription, Webkit webkit) {
|
||||||
|
if (throwable.getCause() instanceof NotLoginException){
|
||||||
|
webkit.httpResponse.sendJson(JsonResult.error(-2, errorDescription));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
package com.lktx.center.controller;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||||
|
import cn.hserver.core.ioc.annotation.Autowired;
|
||||||
|
import cn.hserver.core.server.util.JsonResult;
|
||||||
|
import cn.hserver.plugin.web.annotation.Controller;
|
||||||
|
import cn.hserver.plugin.web.annotation.GET;
|
||||||
|
import com.lktx.center.service.AppCenterService;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Controller("/app-center")
|
||||||
|
public class AppCenterController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AppCenterService appCenterService;
|
||||||
|
|
||||||
|
@GET("/list")
|
||||||
|
@SaCheckLogin
|
||||||
|
public JsonResult list(){
|
||||||
|
Map<String, Object> appList = appCenterService.getAppList();
|
||||||
|
if (appList != null) {
|
||||||
|
return JsonResult.ok().put("data", appList);
|
||||||
|
}
|
||||||
|
return JsonResult.error();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -52,19 +52,4 @@ public class HomeController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@GET("/logout")
|
|
||||||
public void logout(HttpResponse response) {
|
|
||||||
if (StpUtil.isLogin()){
|
|
||||||
//可以全局退出
|
|
||||||
SaSession session = StpUtil.getSession();
|
|
||||||
AuthToken authToken = session.get(Data.AuthToken,null);
|
|
||||||
if (authToken != null){
|
|
||||||
AuthResponse revoke = authRequest.revoke(authToken);
|
|
||||||
System.out.println(revoke.getMsg());
|
|
||||||
}
|
|
||||||
//子系统退出
|
|
||||||
StpUtil.logout();
|
|
||||||
}
|
|
||||||
response.redirect("/");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,11 +5,13 @@ import cn.dev33.satoken.stp.StpUtil;
|
|||||||
import cn.hserver.core.ioc.annotation.Autowired;
|
import cn.hserver.core.ioc.annotation.Autowired;
|
||||||
import cn.hserver.core.server.util.JsonResult;
|
import cn.hserver.core.server.util.JsonResult;
|
||||||
import cn.hserver.plugin.web.annotation.Controller;
|
import cn.hserver.plugin.web.annotation.Controller;
|
||||||
|
import cn.hserver.plugin.web.annotation.GET;
|
||||||
import cn.hserver.plugin.web.annotation.RequestMapping;
|
import cn.hserver.plugin.web.annotation.RequestMapping;
|
||||||
import cn.hserver.plugin.web.interfaces.HttpRequest;
|
import cn.hserver.plugin.web.interfaces.HttpRequest;
|
||||||
import cn.hserver.plugin.web.interfaces.HttpResponse;
|
import cn.hserver.plugin.web.interfaces.HttpResponse;
|
||||||
import com.lktx.center.config.Data;
|
import com.lktx.center.config.Data;
|
||||||
import com.lktx.center.config.SsoAuthRequest;
|
import com.lktx.center.config.SsoAuthRequest;
|
||||||
|
import com.lktx.center.domain.vo.LoginInfo;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import me.zhyd.oauth.model.AuthCallback;
|
import me.zhyd.oauth.model.AuthCallback;
|
||||||
import me.zhyd.oauth.model.AuthResponse;
|
import me.zhyd.oauth.model.AuthResponse;
|
||||||
@ -41,10 +43,36 @@ public class RestAuthController {
|
|||||||
StpUtil.login(login.getData().getUuid());
|
StpUtil.login(login.getData().getUuid());
|
||||||
SaSession session = StpUtil.getSession();
|
SaSession session = StpUtil.getSession();
|
||||||
session.set(Data.AuthToken, token);
|
session.set(Data.AuthToken, token);
|
||||||
return JsonResult.ok().put("data", data);
|
|
||||||
|
LoginInfo build = LoginInfo.builder()
|
||||||
|
.userId(data.getUuid())
|
||||||
|
.avatar(data.getAvatar())
|
||||||
|
.username(data.getUsername())
|
||||||
|
.nickname(data.getNickname())
|
||||||
|
.token(StpUtil.getTokenInfo().tokenValue)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return JsonResult.ok().put("data", build);
|
||||||
}catch (Exception e) {
|
}catch (Exception e) {
|
||||||
log.error("login error",e);
|
log.error("login error",e);
|
||||||
}
|
}
|
||||||
return JsonResult.error();
|
return JsonResult.error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GET("/logout")
|
||||||
|
public JsonResult logout() {
|
||||||
|
System.out.println(StpUtil.getSession().getId());
|
||||||
|
if (StpUtil.isLogin()){
|
||||||
|
SaSession session = StpUtil.getSession();
|
||||||
|
AuthToken authToken = session.get(Data.AuthToken,null);
|
||||||
|
if (authToken != null){
|
||||||
|
AuthResponse<Void> revoke = authRequest.revoke(authToken);
|
||||||
|
System.out.println(revoke.getMsg());
|
||||||
|
}
|
||||||
|
//子系统退出
|
||||||
|
StpUtil.logout();
|
||||||
|
}
|
||||||
|
return JsonResult.ok();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
14
api/src/main/java/com/lktx/center/domain/vo/LoginInfo.java
Normal file
14
api/src/main/java/com/lktx/center/domain/vo/LoginInfo.java
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package com.lktx.center.domain.vo;
|
||||||
|
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public class LoginInfo {
|
||||||
|
private String userId;
|
||||||
|
private String nickname;
|
||||||
|
private String username;
|
||||||
|
private String avatar;
|
||||||
|
private String token;
|
||||||
|
}
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
package com.lktx.center.service;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.session.SaSession;
|
||||||
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
|
import cn.hserver.core.ioc.annotation.Autowired;
|
||||||
|
import cn.hserver.core.ioc.annotation.Bean;
|
||||||
|
import cn.hserver.core.server.util.JsonResult;
|
||||||
|
import com.google.common.cache.Cache;
|
||||||
|
import com.google.common.cache.CacheBuilder;
|
||||||
|
import com.lktx.center.config.Data;
|
||||||
|
import com.lktx.center.config.SsoAuthRequest;
|
||||||
|
import com.lktx.center.domain.bean.SsoApp;
|
||||||
|
import com.lktx.center.domain.vo.SsoUserAppVO;
|
||||||
|
import me.zhyd.oauth.model.AuthResponse;
|
||||||
|
import me.zhyd.oauth.model.AuthToken;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public class AppCenterService {
|
||||||
|
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SsoAuthRequest ssoAuthRequest;
|
||||||
|
|
||||||
|
|
||||||
|
private final Cache<String, Map<String,Object>> expiringCache = CacheBuilder.newBuilder()
|
||||||
|
.expireAfterWrite(30, TimeUnit.MINUTES) // 写入后30分钟过期
|
||||||
|
.maximumSize(1)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
public Map<String,Object> getAppList(){
|
||||||
|
Map<String, Object> appList = expiringCache.getIfPresent("appList");
|
||||||
|
if(appList != null){
|
||||||
|
return appList;
|
||||||
|
}
|
||||||
|
SaSession session = StpUtil.getSession();
|
||||||
|
AuthToken authToken = session.get(Data.AuthToken,null);
|
||||||
|
if (authToken != null){
|
||||||
|
AuthResponse<SsoUserAppVO> center = ssoAuthRequest.center(authToken);
|
||||||
|
if (center.ok()) {
|
||||||
|
Map<String, Object> data = Map.of(
|
||||||
|
"user", center.getData().getSsoUser(),
|
||||||
|
"appList", center.getData().getSsoAppList(),
|
||||||
|
"appGroup", center.getData().getSsoAppList().stream().map(SsoApp::getSsoAppGroup).collect(Collectors.toSet())
|
||||||
|
);
|
||||||
|
expiringCache.put("appList", data);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
8
web/src/api/appcenter.js
Normal file
8
web/src/api/appcenter.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import http from '../data/http'
|
||||||
|
|
||||||
|
export function appCenterList() {
|
||||||
|
return http({
|
||||||
|
url: '/app-center/list',
|
||||||
|
method: 'get',
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -7,3 +7,9 @@ export function login(data) {
|
|||||||
data
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
export function logout() {
|
||||||
|
return http({
|
||||||
|
url: '/oauth/logout',
|
||||||
|
method: 'get',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@ -21,7 +21,7 @@ service.interceptors.request.use(
|
|||||||
// let each request carry token
|
// let each request carry token
|
||||||
// ['X-Token'] is a custom headers key
|
// ['X-Token'] is a custom headers key
|
||||||
// please modify it according to the actual situation
|
// please modify it according to the actual situation
|
||||||
config.headers['token'] = userInfo.getUserInfo().token
|
config.headers['satoken'] = userInfo.getUserInfo().token
|
||||||
}
|
}
|
||||||
return config
|
return config
|
||||||
},
|
},
|
||||||
@ -49,8 +49,9 @@ service.interceptors.response.use(
|
|||||||
// if the custom code is not 20000, it is judged as an error.
|
// if the custom code is not 20000, it is judged as an error.
|
||||||
if (res.code !== 200) {
|
if (res.code !== 200) {
|
||||||
// 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
|
// 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
|
||||||
if (res.code === -2 || res.code === -3 || res.code === -4 || res.code === -5) {
|
if (res.code === -2) {
|
||||||
location.href = "/login"
|
location.href = "/login"
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -76,7 +76,7 @@
|
|||||||
|
|
||||||
<div class="flex flex-col items-center p-4">
|
<div class="flex flex-col items-center p-4">
|
||||||
<div class="w-14 h-14 rounded-lg bg-primary/10 flex items-center justify-center mb-3">
|
<div class="w-14 h-14 rounded-lg bg-primary/10 flex items-center justify-center mb-3">
|
||||||
<el-icon :size="24" :class="element.icon"></el-icon>
|
<el-avatar :src="element.icon" />
|
||||||
</div>
|
</div>
|
||||||
<h3 class="font-medium text-gray-800 mb-1 text-center truncate w-full">{{ element.name }}</h3>
|
<h3 class="font-medium text-gray-800 mb-1 text-center truncate w-full">{{ element.name }}</h3>
|
||||||
<p class="text-xs text-gray-500 text-center truncate w-full">{{ element.description }}</p>
|
<p class="text-xs text-gray-500 text-center truncate w-full">{{ element.description }}</p>
|
||||||
@ -123,7 +123,7 @@
|
|||||||
>
|
>
|
||||||
<div class="flex flex-col items-center p-4">
|
<div class="flex flex-col items-center p-4">
|
||||||
<div class="w-14 h-14 rounded-lg bg-primary/10 flex items-center justify-center mb-3">
|
<div class="w-14 h-14 rounded-lg bg-primary/10 flex items-center justify-center mb-3">
|
||||||
<el-icon :size="24" :class="app.icon"></el-icon>
|
<el-avatar :src="app.icon" />
|
||||||
</div>
|
</div>
|
||||||
<h3 class="font-medium text-gray-800 mb-1 text-center truncate w-full">{{ app.name }}</h3>
|
<h3 class="font-medium text-gray-800 mb-1 text-center truncate w-full">{{ app.name }}</h3>
|
||||||
<p class="text-xs text-gray-500 text-center truncate w-full">{{ app.description }}</p>
|
<p class="text-xs text-gray-500 text-center truncate w-full">{{ app.description }}</p>
|
||||||
@ -181,7 +181,7 @@
|
|||||||
:label="app.id"
|
:label="app.id"
|
||||||
class="flex items-center"
|
class="flex items-center"
|
||||||
>
|
>
|
||||||
<el-icon :class="app.icon" class="mr-2"></el-icon>
|
<el-avatar :src="app.icon" />
|
||||||
<span class="text-sm">{{ app.name }}</span>
|
<span class="text-sm">{{ app.name }}</span>
|
||||||
</el-checkbox>
|
</el-checkbox>
|
||||||
</el-checkbox-group>
|
</el-checkbox-group>
|
||||||
@ -212,6 +212,7 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, computed, onMounted } from 'vue'
|
import { ref, computed, onMounted } from 'vue'
|
||||||
|
import {appCenterList} from '../api/appcenter'
|
||||||
import draggable from 'vuedraggable'
|
import draggable from 'vuedraggable'
|
||||||
import {
|
import {
|
||||||
Collection,
|
Collection,
|
||||||
@ -240,11 +241,6 @@ import { ElMessage, ElDialog } from 'element-plus'
|
|||||||
|
|
||||||
// 应用分类数据
|
// 应用分类数据
|
||||||
const categories = ref([
|
const categories = ref([
|
||||||
{ id: 'workflow', name: '工作流程' },
|
|
||||||
{ id: 'data', name: '数据分析' },
|
|
||||||
{ id: 'communication', name: '沟通协作' },
|
|
||||||
{ id: 'document', name: '文档管理' },
|
|
||||||
{ id: 'system', name: '系统工具' }
|
|
||||||
])
|
])
|
||||||
|
|
||||||
// 应用类型定义
|
// 应用类型定义
|
||||||
@ -261,166 +257,7 @@ const drag=ref(false)
|
|||||||
|
|
||||||
// 所有应用数据
|
// 所有应用数据
|
||||||
const allApps = ref<App[]>([
|
const allApps = ref<App[]>([
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
name: '项目管理系统',
|
|
||||||
description: '管理项目进度、任务分配和资源',
|
|
||||||
icon: Monitor,
|
|
||||||
category: 'workflow',
|
|
||||||
url: '/project-management'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
name: '文档中心',
|
|
||||||
description: '企业级文档管理和协作平台',
|
|
||||||
icon: Document,
|
|
||||||
category: 'document',
|
|
||||||
url: '/document-center'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
name: '企业邮箱',
|
|
||||||
description: '安全可靠的企业邮件系统',
|
|
||||||
icon: Message,
|
|
||||||
category: 'communication',
|
|
||||||
url: '/mail'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
name: '人力资源系统',
|
|
||||||
description: '员工信息管理和人事流程',
|
|
||||||
icon: User,
|
|
||||||
category: 'workflow',
|
|
||||||
url: '/hr-system'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 5,
|
|
||||||
name: '数据分析平台',
|
|
||||||
description: '企业数据可视化和分析工具',
|
|
||||||
icon: PieChart,
|
|
||||||
category: 'data',
|
|
||||||
url: '/data-analysis'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 6,
|
|
||||||
name: '日程安排',
|
|
||||||
description: '团队和个人日程管理',
|
|
||||||
icon: Calendar,
|
|
||||||
category: 'workflow',
|
|
||||||
url: '/calendar'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 7,
|
|
||||||
name: '知识库',
|
|
||||||
description: '企业知识沉淀和共享平台',
|
|
||||||
icon: Folder,
|
|
||||||
category: 'document',
|
|
||||||
url: '/knowledge-base'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 8,
|
|
||||||
name: '视频会议',
|
|
||||||
description: '高清视频会议和远程协作',
|
|
||||||
icon: PieChart,
|
|
||||||
category: 'communication',
|
|
||||||
url: '/video-conference'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 9,
|
|
||||||
name: '系统设置',
|
|
||||||
description: '企业系统配置和管理',
|
|
||||||
icon: Setting,
|
|
||||||
category: 'system',
|
|
||||||
url: '/system-settings'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 10,
|
|
||||||
name: '数据备份',
|
|
||||||
description: '企业数据定期备份和恢复',
|
|
||||||
icon: Download,
|
|
||||||
category: 'system',
|
|
||||||
url: '/data-backup'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 11,
|
|
||||||
name: '报表生成器',
|
|
||||||
description: '自定义报表和数据导出',
|
|
||||||
icon: PieChart,
|
|
||||||
category: 'data',
|
|
||||||
url: '/report-generator'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 12,
|
|
||||||
name: '移动办公',
|
|
||||||
description: '随时随地处理工作事务',
|
|
||||||
icon: PieChart,
|
|
||||||
category: 'workflow',
|
|
||||||
url: '/mobile-office'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 13,
|
|
||||||
name: '文件传输',
|
|
||||||
description: '安全高效的大文件传输工具',
|
|
||||||
icon: Upload,
|
|
||||||
category: 'system',
|
|
||||||
url: '/file-transfer'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 14,
|
|
||||||
name: '工单系统',
|
|
||||||
description: 'IT服务请求和问题跟踪',
|
|
||||||
icon: PieChart,
|
|
||||||
category: 'workflow',
|
|
||||||
url: '/work-order'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 15,
|
|
||||||
name: '实时监控',
|
|
||||||
description: '系统性能和状态实时监控',
|
|
||||||
icon: Clock,
|
|
||||||
category: 'system',
|
|
||||||
url: '/monitoring'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 16,
|
|
||||||
name: '企业公告',
|
|
||||||
description: '公司通知和重要消息发布',
|
|
||||||
icon: Bell,
|
|
||||||
category: 'communication',
|
|
||||||
url: '/announcements'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 17,
|
|
||||||
name: '权限管理',
|
|
||||||
description: '用户权限和访问控制',
|
|
||||||
icon: Lock,
|
|
||||||
category: 'system',
|
|
||||||
url: '/permission-management'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 18,
|
|
||||||
name: '数据同步',
|
|
||||||
description: '多系统间数据实时同步',
|
|
||||||
icon: PieChart,
|
|
||||||
category: 'data',
|
|
||||||
url: '/data-sync'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 19,
|
|
||||||
name: '协作白板',
|
|
||||||
description: '团队在线协作和头脑风暴',
|
|
||||||
icon: Share,
|
|
||||||
category: 'communication',
|
|
||||||
url: '/collaboration-board'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 20,
|
|
||||||
name: '应用商店',
|
|
||||||
description: '发现和安装企业应用',
|
|
||||||
icon: Star,
|
|
||||||
category: 'system',
|
|
||||||
url: '/app-store'
|
|
||||||
}
|
|
||||||
])
|
])
|
||||||
|
|
||||||
// 我的应用ID列表(从本地存储加载或设置默认值)
|
// 我的应用ID列表(从本地存储加载或设置默认值)
|
||||||
@ -608,8 +445,35 @@ const loadMyAppsFromLocalStorage = () => {
|
|||||||
selectedApps.value = [...myAppIds.value]
|
selectedApps.value = [...myAppIds.value]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const loadAppList = () => {
|
||||||
|
appCenterList().then(res=>{
|
||||||
|
if (res.code===200){
|
||||||
|
|
||||||
|
categories.value = res.data.appGroup.map(item=>({
|
||||||
|
id: item.ssoAppGroupId,
|
||||||
|
name: item.name
|
||||||
|
}))
|
||||||
|
|
||||||
|
allApps.value = res.data.appList.map(item=>({
|
||||||
|
id: item.ssoAppId,
|
||||||
|
name: item.appName,
|
||||||
|
description: item.remark,
|
||||||
|
icon: item.appIcon,
|
||||||
|
category: item.ssoAppGroupId,
|
||||||
|
url: item.url
|
||||||
|
}))
|
||||||
|
|
||||||
|
|
||||||
|
console.log(res)
|
||||||
|
// allApps.value = res.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 生命周期钩子:组件挂载后加载我的应用
|
// 生命周期钩子:组件挂载后加载我的应用
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
loadAppList()
|
||||||
loadMyAppsFromLocalStorage()
|
loadMyAppsFromLocalStorage()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -39,8 +39,14 @@
|
|||||||
|
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<img :src="userInfoData?.avatar" alt="User Avatar" class="w-8 h-8 rounded-full object-cover">
|
<img :src="userInfoData?.avatar" alt="User Avatar" class="w-8 h-8 rounded-full object-cover">
|
||||||
<span class="ml-2 hidden sm:block">{{ userInfoData?.nickname }}</span>
|
<el-dropdown trigger="click">
|
||||||
<el-icon><CaretBottom /></el-icon>
|
<span class="el-dropdown-link text-white cursor-pointer ml-2">{{ userInfoData?.nickname }}</span>
|
||||||
|
<template #dropdown>
|
||||||
|
<el-dropdown-menu>
|
||||||
|
<el-dropdown-item @click="handelLogout">退出登录</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</template>
|
||||||
|
</el-dropdown>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
@ -117,7 +123,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script setup>
|
||||||
import {onMounted, ref} from 'vue'
|
import {onMounted, ref} from 'vue'
|
||||||
import {
|
import {
|
||||||
Document,
|
Document,
|
||||||
@ -140,16 +146,17 @@ import {
|
|||||||
|
|
||||||
import userInfo from '../../data/userInfo.js'
|
import userInfo from '../../data/userInfo.js'
|
||||||
import {useRouter} from "vue-router";
|
import {useRouter} from "vue-router";
|
||||||
|
import { logout } from '../../api/login';
|
||||||
const router=useRouter();
|
const router=useRouter();
|
||||||
const userInfoData=ref(null);
|
const userInfoData=ref(null);
|
||||||
|
|
||||||
const isCollapse = ref(false)
|
const isCollapse = ref(false)
|
||||||
|
|
||||||
const handleOpen = (key: string, keyPath: string[]) => {
|
const handleOpen = (key, keyPath) => {
|
||||||
console.log(key, keyPath)
|
console.log(key, keyPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleClose = (key: string, keyPath: string[]) => {
|
const handleClose = (key, keyPath) => {
|
||||||
console.log(key, keyPath)
|
console.log(key, keyPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,6 +170,14 @@ onMounted(()=>{
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const handelLogout = () => {
|
||||||
|
logout().then(res=>{
|
||||||
|
if (res.code===200){
|
||||||
|
userInfo.removeUserInfo()
|
||||||
|
location.reload()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user