添加相关页面,调整登录方式
This commit is contained in:
parent
9b4f574093
commit
90d40386ac
@ -3,17 +3,21 @@ package com.lktx.center.controller;
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
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.RequestMapping;
|
||||
import cn.hserver.plugin.web.interfaces.HttpRequest;
|
||||
import cn.hserver.plugin.web.interfaces.HttpResponse;
|
||||
import com.lktx.center.config.Data;
|
||||
import com.lktx.center.config.SsoAuthRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthResponse;
|
||||
import me.zhyd.oauth.model.AuthToken;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.utils.AuthStateUtils;
|
||||
|
||||
@Slf4j
|
||||
@Controller("/oauth")
|
||||
public class RestAuthController {
|
||||
|
||||
@ -27,16 +31,20 @@ public class RestAuthController {
|
||||
}
|
||||
|
||||
@RequestMapping("/callback")
|
||||
public void login(AuthCallback callback,HttpResponse response) {
|
||||
public JsonResult login(AuthCallback callback, HttpRequest request) {
|
||||
try {
|
||||
String rawData = request.getRawData();
|
||||
System.out.println(rawData);
|
||||
AuthResponse<AuthUser> login = authRequest.login(callback);
|
||||
AuthUser data = login.getData();
|
||||
AuthToken token = login.getData().getToken();
|
||||
StpUtil.login(login.getData().getUuid());
|
||||
SaSession session = StpUtil.getSession();
|
||||
session.set(Data.AuthToken, token);
|
||||
response.redirect("/");
|
||||
return JsonResult.ok().put("data", data);
|
||||
}catch (Exception e) {
|
||||
response.redirect("/");
|
||||
}
|
||||
log.error("login error",e);
|
||||
}
|
||||
return JsonResult.error();
|
||||
}
|
||||
}
|
||||
22
api/src/main/java/com/lktx/center/filter/CorsFilter.java
Normal file
22
api/src/main/java/com/lktx/center/filter/CorsFilter.java
Normal file
@ -0,0 +1,22 @@
|
||||
package com.lktx.center.filter;
|
||||
|
||||
import cn.hserver.core.ioc.annotation.Bean;
|
||||
import cn.hserver.core.ioc.annotation.Order;
|
||||
import cn.hserver.plugin.web.context.Webkit;
|
||||
import cn.hserver.plugin.web.interfaces.FilterAdapter;
|
||||
import io.netty.handler.codec.http.HttpMethod;
|
||||
|
||||
@Bean
|
||||
@Order(1)
|
||||
public class CorsFilter implements FilterAdapter {
|
||||
@Override
|
||||
public void doFilter(Webkit webkit) throws Exception {
|
||||
webkit.httpResponse.setHeader("Access-Control-Allow-Origin", "*");
|
||||
webkit.httpResponse.setHeader("Access-Control-Allow-Methods", "*");
|
||||
webkit.httpResponse.setHeader("Access-Control-Allow-Credentials", "*");
|
||||
webkit.httpResponse.setHeader("Access-Control-Allow-Headers", "*");
|
||||
if (webkit.httpRequest.getRequestType().equals(HttpMethod.OPTIONS)) {
|
||||
webkit.httpResponse.sendHtml("");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
oauth:
|
||||
client-id: 65013a3d89d14fab8ff3eb2c0f3981a3
|
||||
client-secret: 22b5ce70d67f41b79b27cbedb57c976a
|
||||
redirect-uri: http://127.0.0.1:8981/oauth/callback
|
||||
redirect-uri: http://127.0.0.1:5173/login
|
||||
url: http://192.168.0.206:8911/21/
|
||||
@ -10,7 +10,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@tailwindcss/vite": "^4.1.11",
|
||||
"axios": "^1.11.0",
|
||||
"element-plus": "^2.10.4",
|
||||
"font-awesome": "^4.7.0",
|
||||
"vue": "^3.5.17",
|
||||
"vue-router": "4",
|
||||
"vuedraggable": "^4.1.0"
|
||||
|
||||
9
web/src/api/login.js
Normal file
9
web/src/api/login.js
Normal file
@ -0,0 +1,9 @@
|
||||
import http from '../data/http'
|
||||
|
||||
export function login(data) {
|
||||
return http({
|
||||
url: '/oauth/callback',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
4
web/src/data/host.js
Normal file
4
web/src/data/host.js
Normal file
@ -0,0 +1,4 @@
|
||||
//API地址
|
||||
export const host = 'http://127.0.0.1:8981'
|
||||
//登录回调调整地址
|
||||
export const login = 'http://127.0.0.1:8981/oauth/render'
|
||||
66
web/src/data/http.js
Normal file
66
web/src/data/http.js
Normal file
@ -0,0 +1,66 @@
|
||||
import axios from 'axios'
|
||||
import userInfo from './userInfo.js'
|
||||
import {host} from './host.js'
|
||||
|
||||
// create an axios instance
|
||||
const service = axios.create({
|
||||
|
||||
// baseURL: "http://127.0.0.1:9090", // url = base url + request url
|
||||
// baseURL: "http://xxx.com", // url = base url + request url
|
||||
baseURL: host, // url = base url + request url
|
||||
// withCredentials: true, // send cookies when cross-domain requests
|
||||
timeout: 500000 // request timeout
|
||||
})
|
||||
|
||||
// request interceptor
|
||||
service.interceptors.request.use(
|
||||
config => {
|
||||
// do something before request is sent
|
||||
|
||||
if (userInfo.getUserInfo()) {
|
||||
// let each request carry token
|
||||
// ['X-Token'] is a custom headers key
|
||||
// please modify it according to the actual situation
|
||||
config.headers['token'] = userInfo.getUserInfo().token
|
||||
}
|
||||
return config
|
||||
},
|
||||
error => {
|
||||
// do something with request error
|
||||
console.log(error) // for debug
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
// response interceptor
|
||||
service.interceptors.response.use(
|
||||
/**
|
||||
* If you want to get http information such as headers or status
|
||||
* Please return response => response
|
||||
*/
|
||||
|
||||
/**
|
||||
* Determine the request status by custom code
|
||||
* Here is just an example
|
||||
* You can also judge the status by HTTP Status Code
|
||||
*/
|
||||
response => {
|
||||
const res = response.data
|
||||
// if the custom code is not 20000, it is judged as an error.
|
||||
if (res.code !== 200) {
|
||||
// 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
|
||||
if (res.code === -2 || res.code === -3 || res.code === -4 || res.code === -5) {
|
||||
location.href = "/login"
|
||||
}
|
||||
return res
|
||||
} else {
|
||||
return res
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log('err' + error) // for debug
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
export default service
|
||||
16
web/src/data/userInfo.js
Normal file
16
web/src/data/userInfo.js
Normal file
@ -0,0 +1,16 @@
|
||||
export default {
|
||||
KEY: "USER_INFO",
|
||||
setUserInfo(userInfo) {
|
||||
localStorage.setItem(this.KEY, JSON.stringify(userInfo))
|
||||
},
|
||||
getUserInfo() {
|
||||
try {
|
||||
return JSON.parse(localStorage.getItem(this.KEY))
|
||||
} catch (e) {
|
||||
return null
|
||||
}
|
||||
},
|
||||
removeUserInfo(){
|
||||
localStorage.removeItem(this.KEY)
|
||||
}
|
||||
}
|
||||
@ -4,4 +4,5 @@ import App from './App.vue'
|
||||
import router from './router/index.js'
|
||||
import ElementPlus from 'element-plus'
|
||||
import 'element-plus/dist/index.css'
|
||||
import 'font-awesome/css/font-awesome.min.css'
|
||||
createApp(App).use(router).use(ElementPlus).mount('#app')
|
||||
|
||||
@ -1,23 +1,35 @@
|
||||
import { createMemoryHistory, createRouter } from 'vue-router'
|
||||
import {createMemoryHistory, createRouter, createWebHashHistory, createWebHistory} from 'vue-router'
|
||||
|
||||
import index from '../views/index.vue'
|
||||
import login from '../views/login.vue'
|
||||
import home from '../views/home.vue'
|
||||
import appcenter from '../views/appcenter.vue'
|
||||
import news from '../views/news.vue'
|
||||
import announcement from '../views/announcement.vue'
|
||||
import staffstyle from '../views/staffstyle.vue'
|
||||
import chat from '../views/chat.vue'
|
||||
import suggestionbox from '../views/suggestionbox.vue'
|
||||
|
||||
const routes = [
|
||||
{path: '/login', component: login},
|
||||
{
|
||||
path: '/', component: index,
|
||||
children:[
|
||||
{path: '', redirect: '/home'},
|
||||
{ path: '/home', component: home },
|
||||
{ path: '/app-center', component: appcenter }
|
||||
{ path: '/app-center', component: appcenter },
|
||||
{ path: '/news', component: news },
|
||||
{ path: '/announcement', component: announcement },
|
||||
{ path: '/staff-style', component: staffstyle },
|
||||
{ path: '/chat', component: chat },
|
||||
{ path: '/suggestion-box', component: suggestionbox }
|
||||
]
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
const router = createRouter({
|
||||
history: createMemoryHistory(),
|
||||
history: createWebHistory(),
|
||||
routes,
|
||||
})
|
||||
|
||||
|
||||
63
web/src/views/announcement.vue
Normal file
63
web/src/views/announcement.vue
Normal file
@ -0,0 +1,63 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { ElCard, ElTag, ElDivider } from 'element-plus';
|
||||
|
||||
// 模拟公告数据
|
||||
const announcements = ref([
|
||||
{
|
||||
id: 1,
|
||||
title: '系统维护通知',
|
||||
content: '为了给大家提供更稳定、高效的服务,本系统将于本周日凌晨 02:00 - 04:00 进行维护,届时系统将暂停服务,请您提前做好相应准备,感谢您的理解与支持!',
|
||||
date: '2025-07-25',
|
||||
type: '维护'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: '假期安排通知',
|
||||
content: '根据国家法定节假日安排,结合公司实际情况,现将今年国庆节放假安排通知如下:10 月 1 日至 10 月 7 日放假调休,共 7 天。10 月 8 日(星期六)、10 月 9 日(星期日)上班。请各位员工提前做好工作安排。',
|
||||
date: '2025-07-24',
|
||||
type: '假期'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: '新政策发布',
|
||||
content: '公司新的绩效考核政策已经正式发布,该政策将从下个月开始实施。请各位员工仔细阅读政策文件,如有疑问可随时咨询人力资源部门。',
|
||||
date: '2025-07-23',
|
||||
type: '政策'
|
||||
}
|
||||
]);
|
||||
|
||||
const getTagType = (type: string) => {
|
||||
switch (type) {
|
||||
case '维护':
|
||||
return 'warning';
|
||||
case '假期':
|
||||
return 'success';
|
||||
case '政策':
|
||||
return 'info';
|
||||
default:
|
||||
return 'default';
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="max-w-7xl mx-auto p-6">
|
||||
<h1 class="text-3xl font-bold text-gray-800 mb-8 text-center">企业公告</h1>
|
||||
<div class="space-y-6">
|
||||
<ElCard v-for="announcement in announcements" :key="announcement.id" class="shadow-md hover:shadow-xl transition-shadow">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h2 class="text-xl font-semibold text-gray-700">{{ announcement.title }}</h2>
|
||||
<el-tag :type="getTagType(announcement.type)" size="small">{{ announcement.type }}</el-tag>
|
||||
</div>
|
||||
<ElDivider />
|
||||
<p class="text-gray-600 mb-4">{{ announcement.content }}</p>
|
||||
<div class="text-right text-sm text-gray-500">发布时间:{{ announcement.date }}</div>
|
||||
</ElCard>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
417
web/src/views/chat.vue
Normal file
417
web/src/views/chat.vue
Normal file
@ -0,0 +1,417 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
<div class="font-inter bg-gray-100 text-dark flex overflow-hidden h-full">
|
||||
<!-- 左侧聊天列表 -->
|
||||
<div class="w-80 bg-white border-r border-gray-200 flex flex-col h-full shadow-sm z-10">
|
||||
<!-- 头部 -->
|
||||
<div class="p-4 border-b border-gray-200">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h1 class="text-xl font-bold text-primary">企业沟通</h1>
|
||||
<button class="p-2 rounded-full hover:bg-gray-100 transition-colors">
|
||||
<i class="fa fa-plus text-gray-600"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 搜索框 -->
|
||||
<div class="relative">
|
||||
<input type="text" placeholder="搜索聊天..." class="w-full py-2 pl-10 pr-4 rounded-lg bg-gray-100 focus:outline-none focus:ring-2 focus:ring-primary/30 transition-all">
|
||||
<i class="fa fa-search absolute left-3 top-3 text-gray-400"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 聊天列表导航 -->
|
||||
<div class="flex border-b border-gray-200">
|
||||
<button class="flex-1 py-3 text-primary border-b-2 border-primary font-medium">
|
||||
最近聊天
|
||||
</button>
|
||||
<button class="flex-1 py-3 text-gray-500 hover:text-gray-700 transition-colors">
|
||||
群聊
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 聊天列表内容 -->
|
||||
<div class="flex-1 overflow-y-auto scrollbar-hide">
|
||||
<!-- 当前选中的聊天 -->
|
||||
<div class="flex items-center p-3 bg-primary/5 border-l-4 border-primary cursor-pointer">
|
||||
<img src="https://picsum.photos/id/1005/200/200" alt="研发部群聊" class="w-12 h-12 rounded-full object-cover">
|
||||
<div class="ml-3 flex-1 min-w-0">
|
||||
<div class="flex justify-between items-center">
|
||||
<h3 class="text-sm font-semibold text-gray-900 truncate">研发部群聊</h3>
|
||||
<span class="text-xs text-gray-500">14:32</span>
|
||||
</div>
|
||||
<p class="text-sm text-gray-600 truncate mt-1">
|
||||
<span class="font-medium">你:</span>这个需求我已经完成了
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 未读消息聊天 -->
|
||||
<div class="flex items-center p-3 hover:bg-gray-50 cursor-pointer transition-colors">
|
||||
<img src="https://picsum.photos/id/1012/200/200" alt="张经理" class="w-12 h-12 rounded-full object-cover">
|
||||
<div class="ml-3 flex-1 min-w-0">
|
||||
<div class="flex justify-between items-center">
|
||||
<h3 class="text-sm font-semibold text-gray-900 truncate">张经理</h3>
|
||||
<span class="text-xs text-gray-500">13:45</span>
|
||||
</div>
|
||||
<p class="text-sm text-gray-600 truncate mt-1">
|
||||
下周的项目评审会议需要提前准备
|
||||
</p>
|
||||
<div class="absolute right-4 top-4 w-5 h-5 bg-primary rounded-full flex items-center justify-center text-white text-xs font-medium">
|
||||
2
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 普通聊天 -->
|
||||
<div class="flex items-center p-3 hover:bg-gray-50 cursor-pointer transition-colors">
|
||||
<img src="https://picsum.photos/id/1027/200/200" alt="产品组" class="w-12 h-12 rounded-full object-cover">
|
||||
<div class="ml-3 flex-1 min-w-0">
|
||||
<div class="flex justify-between items-center">
|
||||
<h3 class="text-sm font-semibold text-gray-900 truncate">产品组</h3>
|
||||
<span class="text-xs text-gray-500">昨天</span>
|
||||
</div>
|
||||
<p class="text-sm text-gray-500 truncate mt-1">
|
||||
李华:新功能原型已经上传到共享文件夹
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center p-3 hover:bg-gray-50 cursor-pointer transition-colors">
|
||||
<img src="https://picsum.photos/id/1025/200/200" alt="王工程师" class="w-12 h-12 rounded-full object-cover">
|
||||
<div class="ml-3 flex-1 min-w-0">
|
||||
<div class="flex justify-between items-center">
|
||||
<h3 class="text-sm font-semibold text-gray-900 truncate">王工程师</h3>
|
||||
<span class="text-xs text-gray-500">昨天</span>
|
||||
</div>
|
||||
<p class="text-sm text-gray-500 truncate mt-1">
|
||||
数据库优化方案我已经发你邮箱了
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center p-3 hover:bg-gray-50 cursor-pointer transition-colors">
|
||||
<img src="https://picsum.photos/id/1066/200/200" alt="市场部" class="w-12 h-12 rounded-full object-cover">
|
||||
<div class="ml-3 flex-1 min-w-0">
|
||||
<div class="flex justify-between items-center">
|
||||
<h3 class="text-sm font-semibold text-gray-900 truncate">市场部</h3>
|
||||
<span class="text-xs text-gray-500">周一</span>
|
||||
</div>
|
||||
<p class="text-sm text-gray-500 truncate mt-1">
|
||||
张敏:下个月的市场活动计划已更新
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 中间聊天界面 -->
|
||||
<div class="flex-1 flex flex-col bg-gray-50 h-full overflow-hidden">
|
||||
<!-- 聊天头部 -->
|
||||
<div class="bg-white border-b border-gray-200 p-4 flex items-center justify-between shadow-sm">
|
||||
<div class="flex items-center">
|
||||
<img src="https://picsum.photos/id/1005/200/200" alt="研发部群聊" class="w-10 h-10 rounded-full object-cover">
|
||||
<div class="ml-3">
|
||||
<h2 class="font-semibold">研发部群聊</h2>
|
||||
<p class="text-xs text-gray-500">12名成员,8人在线</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex space-x-2">
|
||||
<button class="p-2 rounded-full hover:bg-gray-100 transition-colors text-gray-600">
|
||||
<i class="fa fa-search"></i>
|
||||
</button>
|
||||
<button class="p-2 rounded-full hover:bg-gray-100 transition-colors text-gray-600">
|
||||
<i class="fa fa-phone"></i>
|
||||
</button>
|
||||
<button class="p-2 rounded-full hover:bg-gray-100 transition-colors text-gray-600">
|
||||
<i class="fa fa-video-camera"></i>
|
||||
</button>
|
||||
<button class="p-2 rounded-full hover:bg-gray-100 transition-colors text-gray-600">
|
||||
<i class="fa fa-ellipsis-v"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 聊天消息区域 -->
|
||||
<div class="flex-1 overflow-y-auto p-6 space-y-6 scrollbar-hide" id="chat-messages">
|
||||
<!-- 日期分隔线 -->
|
||||
<div class="flex justify-center">
|
||||
<span class="text-xs bg-gray-200 text-gray-500 px-3 py-1 rounded-full">今天</span>
|
||||
</div>
|
||||
|
||||
<!-- 他人消息 -->
|
||||
<div class="flex items-start">
|
||||
<img src="https://picsum.photos/id/1025/200/200" alt="王工程师" class="w-8 h-8 rounded-full object-cover">
|
||||
<div class="ml-2 max-w-[80%]">
|
||||
<div class="flex items-center mb-1">
|
||||
<span class="text-xs font-medium text-gray-700">王工程师</span>
|
||||
<span class="text-xs text-gray-400 ml-2">09:32</span>
|
||||
</div>
|
||||
<div class="bg-white p-3 rounded-lg message-bubble-left shadow-sm">
|
||||
<p>大家上午好,昨天部署的新版本运行情况如何?有没有发现什么问题?</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 他人消息 - 图片 -->
|
||||
<div class="flex items-start">
|
||||
<img src="https://picsum.photos/id/1012/200/200" alt="张经理" class="w-8 h-8 rounded-full object-cover">
|
||||
<div class="ml-2 max-w-[80%]">
|
||||
<div class="flex items-center mb-1">
|
||||
<span class="text-xs font-medium text-gray-700">张经理</span>
|
||||
<span class="text-xs text-gray-400 ml-2">10:15</span>
|
||||
</div>
|
||||
<div class="bg-white p-3 rounded-lg message-bubble-left shadow-sm">
|
||||
<p>我这边发现一个界面显示问题,主要在IE浏览器上:</p>
|
||||
<div class="mt-2 rounded overflow-hidden border border-gray-100">
|
||||
<img src="https://picsum.photos/id/0/400/200" alt="问题截图" class="w-full h-auto hover:opacity-90 transition-opacity cursor-pointer">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 他人消息 - 文件 -->
|
||||
<div class="flex items-start">
|
||||
<img src="https://picsum.photos/id/1066/200/200" alt="李华" class="w-8 h-8 rounded-full object-cover">
|
||||
<div class="ml-2 max-w-[80%]">
|
||||
<div class="flex items-center mb-1">
|
||||
<span class="text-xs font-medium text-gray-700">李华</span>
|
||||
<span class="text-xs text-gray-400 ml-2">11:45</span>
|
||||
</div>
|
||||
<div class="bg-white p-3 rounded-lg message-bubble-left shadow-sm">
|
||||
<p>这是修复方案的文档,请查收:</p>
|
||||
<div class="mt-2 flex items-center p-2 bg-gray-50 rounded">
|
||||
<div class="w-10 h-10 bg-primary/10 rounded flex items-center justify-center text-primary">
|
||||
<i class="fa fa-file-pdf-o text-xl"></i>
|
||||
</div>
|
||||
<div class="ml-3 flex-1">
|
||||
<p class="text-sm font-medium text-gray-800 truncate">前端兼容性修复方案.pdf</p>
|
||||
<p class="text-xs text-gray-500">2.4 MB</p>
|
||||
</div>
|
||||
<button class="text-primary hover:text-primary/80 transition-colors">
|
||||
<i class="fa fa-download"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 自己的消息 -->
|
||||
<div class="flex items-start justify-end">
|
||||
<div class="mr-2 max-w-[80%]">
|
||||
<div class="flex items-center justify-end mb-1">
|
||||
<span class="text-xs text-gray-400">13:20</span>
|
||||
</div>
|
||||
<div class="bg-primary text-white p-3 rounded-lg message-bubble-right shadow-sm">
|
||||
<p>我看了一下,这个问题是由于IE对flex布局的支持不完善导致的,我会尽快修复。</p>
|
||||
</div>
|
||||
</div>
|
||||
<img src="https://picsum.photos/id/1001/200/200" alt="我" class="w-8 h-8 rounded-full object-cover">
|
||||
</div>
|
||||
|
||||
<!-- 自己的消息 - 表情包 -->
|
||||
<div class="flex items-start justify-end">
|
||||
<div class="mr-2 max-w-[80%]">
|
||||
<div class="flex items-center justify-end mb-1">
|
||||
<span class="text-xs text-gray-400">13:22</span>
|
||||
</div>
|
||||
<div class="bg-primary text-white p-3 rounded-lg message-bubble-right shadow-sm">
|
||||
<p>收到文档了,谢谢!👍👍</p>
|
||||
</div>
|
||||
</div>
|
||||
<img src="https://picsum.photos/id/1001/200/200" alt="我" class="w-8 h-8 rounded-full object-cover">
|
||||
</div>
|
||||
|
||||
<!-- 他人消息 -->
|
||||
<div class="flex items-start">
|
||||
<img src="https://picsum.photos/id/1025/200/200" alt="王工程师" class="w-8 h-8 rounded-full object-cover">
|
||||
<div class="ml-2 max-w-[80%]">
|
||||
<div class="flex items-center mb-1">
|
||||
<span class="text-xs font-medium text-gray-700">王工程师</span>
|
||||
<span class="text-xs text-gray-400 ml-2">14:30</span>
|
||||
</div>
|
||||
<div class="bg-white p-3 rounded-lg message-bubble-left shadow-sm">
|
||||
<p>数据库性能监控系统已经部署完成,大家可以通过内部地址访问查看实时数据。</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 自己的消息 -->
|
||||
<div class="flex items-start justify-end">
|
||||
<div class="mr-2 max-w-[80%]">
|
||||
<div class="flex items-center justify-end mb-1">
|
||||
<span class="text-xs text-gray-400">14:32</span>
|
||||
</div>
|
||||
<div class="bg-primary text-white p-3 rounded-lg message-bubble-right shadow-sm">
|
||||
<p>这个需求我已经完成了</p>
|
||||
</div>
|
||||
</div>
|
||||
<img src="https://picsum.photos/id/1001/200/200" alt="我" class="w-8 h-8 rounded-full object-cover">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 输入区域 -->
|
||||
<div class="bg-white border-t border-gray-200 p-3">
|
||||
<div class="flex items-center mb-2 space-x-1">
|
||||
<button class="p-2 text-gray-500 hover:text-primary hover:bg-gray-100 rounded-full transition-colors" title="表情">
|
||||
<i class="fa fa-smile-o text-lg"></i>
|
||||
</button>
|
||||
<button class="p-2 text-gray-500 hover:text-primary hover:bg-gray-100 rounded-full transition-colors" title="图片">
|
||||
<i class="fa fa-picture-o text-lg"></i>
|
||||
</button>
|
||||
<button class="p-2 text-gray-500 hover:text-primary hover:bg-gray-100 rounded-full transition-colors" title="文件">
|
||||
<i class="fa fa-paperclip text-lg"></i>
|
||||
</button>
|
||||
<button class="p-2 text-gray-500 hover:text-primary hover:bg-gray-100 rounded-full transition-colors" title="视频">
|
||||
<i class="fa fa-video-camera text-lg"></i>
|
||||
</button>
|
||||
<button class="p-2 text-gray-500 hover:text-primary hover:bg-gray-100 rounded-full transition-colors" title="截图">
|
||||
<i class="fa fa-desktop text-lg"></i>
|
||||
</button>
|
||||
<div class="flex-1"></div>
|
||||
<button class="p-2 text-gray-500 hover:text-primary hover:bg-gray-100 rounded-full transition-colors" title="更多选项">
|
||||
<i class="fa fa-ellipsis-h text-lg"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="flex">
|
||||
<textarea placeholder="输入消息..." class="flex-1 border border-gray-200 rounded-l-lg focus:outline-none focus:ring-2 focus:ring-primary/30 focus:border-primary p-3 resize-none transition-all" rows="3"></textarea>
|
||||
<button class="bg-primary hover:bg-primary/90 text-white px-6 rounded-r-lg transition-colors flex items-center">
|
||||
<span>发送</span>
|
||||
<i class="fa fa-paper-plane ml-2"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧在线人员 -->
|
||||
<div class="w-72 bg-white border-l border-gray-200 flex flex-col h-full shadow-sm hidden lg:block">
|
||||
<!-- 头部 -->
|
||||
<div class="p-4 border-b border-gray-200">
|
||||
<h2 class="font-semibold">在线成员 (8)</h2>
|
||||
</div>
|
||||
|
||||
<!-- 搜索 -->
|
||||
<div class="p-3 border-b border-gray-200">
|
||||
<div class="relative">
|
||||
<input type="text" placeholder="搜索成员..." class="w-full py-2 pl-10 pr-4 rounded-lg bg-gray-100 focus:outline-none focus:ring-2 focus:ring-primary/30 transition-all text-sm">
|
||||
<i class="fa fa-search absolute left-3 top-3 text-gray-400"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分类 -->
|
||||
<div class="p-2 border-b border-gray-200">
|
||||
<button class="text-sm text-primary font-medium">全部</button>
|
||||
<button class="text-sm text-gray-500 ml-3 hover:text-gray-700 transition-colors">部门</button>
|
||||
<button class="text-sm text-gray-500 ml-3 hover:text-gray-700 transition-colors">角色</button>
|
||||
</div>
|
||||
|
||||
<!-- 成员列表 -->
|
||||
<div class="flex-1 overflow-y-auto scrollbar-hide p-2">
|
||||
<!-- 自己 -->
|
||||
<div class="flex items-center p-2 rounded-lg hover:bg-gray-50 cursor-pointer transition-colors">
|
||||
<div class="relative">
|
||||
<img src="https://picsum.photos/id/1001/200/200" alt="自己" class="w-10 h-10 rounded-full object-cover">
|
||||
<span class="absolute bottom-0 right-0 w-3 h-3 bg-success border-2 border-white rounded-full"></span>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<h3 class="text-sm font-medium text-gray-900">我 (自己)</h3>
|
||||
<p class="text-xs text-gray-500">前端开发</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 在线成员 -->
|
||||
<div class="flex items-center p-2 rounded-lg hover:bg-gray-50 cursor-pointer transition-colors">
|
||||
<div class="relative">
|
||||
<img src="https://picsum.photos/id/1012/200/200" alt="张经理" class="w-10 h-10 rounded-full object-cover">
|
||||
<span class="absolute bottom-0 right-0 w-3 h-3 bg-success border-2 border-white rounded-full"></span>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<h3 class="text-sm font-medium text-gray-900">张经理</h3>
|
||||
<p class="text-xs text-gray-500">研发经理</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center p-2 rounded-lg hover:bg-gray-50 cursor-pointer transition-colors">
|
||||
<div class="relative">
|
||||
<img src="https://picsum.photos/id/1025/200/200" alt="王工程师" class="w-10 h-10 rounded-full object-cover">
|
||||
<span class="absolute bottom-0 right-0 w-3 h-3 bg-success border-2 border-white rounded-full"></span>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<h3 class="text-sm font-medium text-gray-900">王工程师</h3>
|
||||
<p class="text-xs text-gray-500">后端开发</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center p-2 rounded-lg hover:bg-gray-50 cursor-pointer transition-colors">
|
||||
<div class="relative">
|
||||
<img src="https://picsum.photos/id/1066/200/200" alt="李华" class="w-10 h-10 rounded-full object-cover">
|
||||
<span class="absolute bottom-0 right-0 w-3 h-3 bg-success border-2 border-white rounded-full"></span>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<h3 class="text-sm font-medium text-gray-900">李华</h3>
|
||||
<p class="text-xs text-gray-500">前端开发</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center p-2 rounded-lg hover:bg-gray-50 cursor-pointer transition-colors">
|
||||
<div class="relative">
|
||||
<img src="https://picsum.photos/id/1027/200/200" alt="赵设计师" class="w-10 h-10 rounded-full object-cover">
|
||||
<span class="absolute bottom-0 right-0 w-3 h-3 bg-success border-2 border-white rounded-full"></span>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<h3 class="text-sm font-medium text-gray-900">赵设计师</h3>
|
||||
<p class="text-xs text-gray-500">UI/UX设计</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 离开状态 -->
|
||||
<div class="flex items-center p-2 rounded-lg hover:bg-gray-50 cursor-pointer transition-colors">
|
||||
<div class="relative">
|
||||
<img src="https://picsum.photos/id/1074/200/200" alt="陈测试" class="w-10 h-10 rounded-full object-cover">
|
||||
<span class="absolute bottom-0 right-0 w-3 h-3 bg-warning border-2 border-white rounded-full"></span>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<h3 class="text-sm font-medium text-gray-900">陈测试</h3>
|
||||
<p class="text-xs text-gray-500">测试工程师</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 离线成员 -->
|
||||
<div class="mt-4">
|
||||
<h3 class="text-xs text-gray-500 uppercase font-medium px-2 mb-2">离线成员 (4)</h3>
|
||||
|
||||
<div class="flex items-center p-2 rounded-lg hover:bg-gray-50 cursor-pointer transition-colors">
|
||||
<div class="relative">
|
||||
<img src="https://picsum.photos/id/1083/200/200" alt="孙产品" class="w-10 h-10 rounded-full object-cover opacity-70">
|
||||
<span class="absolute bottom-0 right-0 w-3 h-3 bg-gray-300 border-2 border-white rounded-full"></span>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<h3 class="text-sm font-medium text-gray-600">孙产品</h3>
|
||||
<p class="text-xs text-gray-400">产品经理</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center p-2 rounded-lg hover:bg-gray-50 cursor-pointer transition-colors">
|
||||
<div class="relative">
|
||||
<img src="https://picsum.photos/id/1076/200/200" alt="周运维" class="w-10 h-10 rounded-full object-cover opacity-70">
|
||||
<span class="absolute bottom-0 right-0 w-3 h-3 bg-gray-300 border-2 border-white rounded-full"></span>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<h3 class="text-sm font-medium text-gray-600">周运维</h3>
|
||||
<p class="text-xs text-gray-400">运维工程师</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import Layout from "./components/layout.vue";
|
||||
import Layout from "./menu/index.vue";
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
128
web/src/views/login.vue
Normal file
128
web/src/views/login.vue
Normal file
@ -0,0 +1,128 @@
|
||||
<script setup>
|
||||
import {onMounted, ref} from "vue";
|
||||
import { useRoute } from 'vue-router'
|
||||
import {login as loginUrl} from "../data/host.js";
|
||||
import {login} from "../api/login.js";
|
||||
import userInfo from "../data/userInfo.js";
|
||||
const route = useRoute()
|
||||
|
||||
const loginState = ref(0)
|
||||
|
||||
const setBar=(progress)=>{
|
||||
const progressBar = document.getElementById('progress-bar');
|
||||
progressBar.style.width = `${progress}%`;
|
||||
}
|
||||
|
||||
const jumpLogin = () => {
|
||||
location.href=loginUrl
|
||||
}
|
||||
|
||||
const handlerLogin = () => {
|
||||
const code= route.query.code
|
||||
const state= route.query.state
|
||||
if (code&&state) {
|
||||
setBar(50)
|
||||
login({code,state}).then(res=>{
|
||||
console.log(res)
|
||||
if (res.code===200){
|
||||
setBar(100)
|
||||
loginState.value=1
|
||||
userInfo.setUserInfo(res.data)
|
||||
location.href="/"
|
||||
}else {
|
||||
setBar(0)
|
||||
loginState.value=2
|
||||
}
|
||||
})
|
||||
}else {
|
||||
jumpLogin()
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(()=>{
|
||||
handlerLogin()
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
<div class="font-inter bg-gray-50 min-h-screen flex items-center justify-center p-4">
|
||||
<div class="max-w-md w-full bg-white rounded-xl shadow-lg overflow-hidden animate-fade-in">
|
||||
<!-- 头部区域 -->
|
||||
<div class="bg-primary p-6 text-white text-center">
|
||||
<div class="flex items-center justify-center">
|
||||
<i class="fa fa-sign-in text-4xl mr-3"></i>
|
||||
<h1 class="text-2xl font-bold">企业登录系统</h1>
|
||||
</div>
|
||||
<p class="mt-2 text-primary-100 opacity-90">正在验证您的身份,请稍候...</p>
|
||||
</div>
|
||||
|
||||
<!-- 内容区域 -->
|
||||
<div class="p-8">
|
||||
<!-- 状态指示器 -->
|
||||
<div id="status-container" class="flex flex-col items-center">
|
||||
<!-- 加载状态 -->
|
||||
<div v-if="loginState===0" class="animate-slide-up">
|
||||
<div class="w-16 h-16 border-4 border-primary/20 border-t-primary rounded-full animate-spin mx-auto"></div>
|
||||
<p class="mt-4 text-gray-600 text-center">正在验证授权码...</p>
|
||||
<p id="loading-details" class="mt-2 text-center text-sm text-gray-500">请不要关闭此页面</p>
|
||||
</div>
|
||||
|
||||
<!-- 成功状态 (默认隐藏) -->
|
||||
<div v-if="loginState===1" class=" animate-slide-up">
|
||||
<p class="mt-4 text-gray-600 text-center">验证成功</p>
|
||||
<p id="success-details" class="mt-2 text-sm text-center text-gray-500">正在跳转至应用...</p>
|
||||
</div>
|
||||
|
||||
<!-- 错误状态 (默认隐藏) -->
|
||||
<div v-if="loginState===2" class=" animate-slide-up text-center">
|
||||
<p class="mt-4 text-gray-600 text-center">登录失败</p>
|
||||
<p id="error-details" class="mt-2 text-sm text-gray-500 text-center">授权码无效或已过期</p>
|
||||
<button @click="jumpLogin" class=" mt-6 px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary/90 transition-colors">
|
||||
重试
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 进度条 -->
|
||||
<div class="mt-8">
|
||||
<div class="h-2 bg-gray-100 rounded-full overflow-hidden">
|
||||
<div id="progress-bar" class="h-full bg-primary rounded-full w-0 transition-all duration-300"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部区域 -->
|
||||
<div class="p-4 bg-gray-50 text-center text-sm text-gray-500">
|
||||
<p>© 2025 企业内部系统 | 技术支持: it-support@company.com</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@layer utilities {
|
||||
.content-auto {
|
||||
content-visibility: auto;
|
||||
}
|
||||
.animate-pulse-slow {
|
||||
animation: pulse 3s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||
}
|
||||
.animate-fade-in {
|
||||
animation: fadeIn 0.5s ease-in-out;
|
||||
}
|
||||
.animate-slide-up {
|
||||
animation: slideUp 0.5s ease-out;
|
||||
}
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
@keyframes slideUp {
|
||||
from { transform: translateY(20px); opacity: 0; }
|
||||
to { transform: translateY(0); opacity: 1; }
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -20,8 +20,8 @@
|
||||
@open="handleOpen"
|
||||
router
|
||||
>
|
||||
<el-menu-item index="/app-center">新闻中心</el-menu-item>
|
||||
<el-menu-item index="/home">公告</el-menu-item>
|
||||
<el-menu-item index="/news">新闻中心</el-menu-item>
|
||||
<el-menu-item index="/announcement">公告</el-menu-item>
|
||||
</el-menu>
|
||||
</div>
|
||||
</div>
|
||||
@ -38,8 +38,8 @@
|
||||
</div>
|
||||
|
||||
<div class="flex items-center">
|
||||
<img src="https://picsum.photos/200/200?random=1" alt="User Avatar" class="w-8 h-8 rounded-full object-cover">
|
||||
<span class="ml-2 hidden sm:block">管理员</span>
|
||||
<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-icon><CaretBottom /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
@ -61,9 +61,25 @@
|
||||
<template #title>首页</template>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="/app-center">
|
||||
<el-icon><IconMenu /></el-icon>
|
||||
<el-icon><Orange /></el-icon>
|
||||
<template #title>应用中心</template>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="/staff-style">
|
||||
<el-icon><UserFilled /></el-icon>
|
||||
<template #title>员工风采</template>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="/app-center">
|
||||
<el-icon><StarFilled /></el-icon>
|
||||
<template #title>企业论坛</template>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="/chat">
|
||||
<el-icon><Comment /></el-icon>
|
||||
<template #title>企业聊天</template>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="/suggestion-box">
|
||||
<el-icon><QuestionFilled /></el-icon>
|
||||
<template #title>意见箱</template>
|
||||
</el-menu-item>
|
||||
<!-- <el-sub-menu index="2">-->
|
||||
<!-- <template #title>-->
|
||||
<!-- <el-icon><Location /></el-icon>-->
|
||||
@ -102,12 +118,18 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import {onMounted, ref} from 'vue'
|
||||
import {
|
||||
Document,
|
||||
Menu as IconMenu,
|
||||
Location,
|
||||
Setting,
|
||||
Switch,
|
||||
StarFilled,
|
||||
UserFilled,
|
||||
Comment,
|
||||
QuestionFilled,
|
||||
Orange,
|
||||
// 新增:导入需要使用的图标
|
||||
Fold,
|
||||
Platform,
|
||||
@ -115,6 +137,12 @@ import {
|
||||
CaretBottom
|
||||
} from '@element-plus/icons-vue'
|
||||
|
||||
|
||||
import userInfo from '../../data/userInfo.js'
|
||||
import {useRouter} from "vue-router";
|
||||
const router=useRouter();
|
||||
const userInfoData=ref(null);
|
||||
|
||||
const isCollapse = ref(false)
|
||||
|
||||
const handleOpen = (key: string, keyPath: string[]) => {
|
||||
@ -124,6 +152,17 @@ const handleOpen = (key: string, keyPath: string[]) => {
|
||||
const handleClose = (key: string, keyPath: string[]) => {
|
||||
console.log(key, keyPath)
|
||||
}
|
||||
|
||||
onMounted(()=>{
|
||||
const info=userInfo.getUserInfo()
|
||||
if (!info){
|
||||
router.push({path: '/login'})
|
||||
}else {
|
||||
userInfoData.value=info
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
52
web/src/views/news.vue
Normal file
52
web/src/views/news.vue
Normal file
@ -0,0 +1,52 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { ElCard, ElTag } from 'element-plus';
|
||||
|
||||
// 模拟新闻数据,添加 imageUrl 字段
|
||||
const newsList = ref([
|
||||
{
|
||||
id: 1,
|
||||
title: '公司年度会议通知',
|
||||
content: '公司将于下周五召开年度会议,请各位员工提前做好准备。',
|
||||
date: '2025-07-24',
|
||||
imageUrl: 'https://picsum.photos/600/400?random=1'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: '新产品上线公告',
|
||||
content: '我们的全新产品已正式上线,欢迎大家体验。',
|
||||
date: '2025-07-23',
|
||||
imageUrl: 'https://picsum.photos/600/400?random=2'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: '团队建设活动安排',
|
||||
content: '本周末将组织团队建设活动,具体安排请查看内部通知。',
|
||||
date: '2025-07-22',
|
||||
imageUrl: 'https://picsum.photos/600/400?random=3'
|
||||
},
|
||||
]);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="max-w-7xl mx-auto p-6">
|
||||
<h1 class="text-2xl font-bold text-gray-800 mb-6 text-center">新闻列表</h1>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<ElCard v-for="news in newsList" :key="news.id" class="shadow-md hover:shadow-lg transition-shadow">
|
||||
<!-- 展示新闻图片 -->
|
||||
<img :src="news.imageUrl" alt="news image" class="w-full h-48 object-cover rounded-t-md">
|
||||
<template #header>
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-xl font-semibold text-gray-700">{{ news.title }}</span>
|
||||
<ElTag type="info" size="small">{{ news.date }}</ElTag>
|
||||
</div>
|
||||
</template>
|
||||
<p class="text-gray-600 p-4">{{ news.content }}</p>
|
||||
</ElCard>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
58
web/src/views/staffstyle.vue
Normal file
58
web/src/views/staffstyle.vue
Normal file
@ -0,0 +1,58 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { ElCard, ElTag } from 'element-plus';
|
||||
|
||||
// 模拟员工数据
|
||||
const staffList = ref([
|
||||
{
|
||||
id: 1,
|
||||
name: '张三',
|
||||
position: '高级前端开发工程师',
|
||||
avatar: 'https://picsum.photos/200/200?random=1',
|
||||
intro: '张三在前端开发领域拥有丰富的经验,擅长 Vue、React 等主流框架,对前端性能优化有深入研究。',
|
||||
honors: ['优秀员工', '技术创新奖']
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '李四',
|
||||
position: '后端架构师',
|
||||
avatar: 'https://picsum.photos/200/200?random=2',
|
||||
intro: '李四专注于后端系统设计与开发,精通 Java、Go 语言,主导过多个大型项目的架构设计。',
|
||||
honors: ['杰出贡献奖', '最佳团队成员']
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: '王五',
|
||||
position: '产品经理',
|
||||
avatar: 'https://picsum.photos/200/200?random=3',
|
||||
intro: '王五具备敏锐的市场洞察力和出色的产品规划能力,成功打造过多款用户喜爱的产品。',
|
||||
honors: ['优秀产品奖', '最佳创意奖']
|
||||
}
|
||||
]);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="max-w-7xl mx-auto p-6">
|
||||
<h1 class="text-3xl font-bold text-gray-800 mb-8 text-center">员工风采</h1>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<ElCard v-for="staff in staffList" :key="staff.id" class="shadow-md hover:shadow-xl transition-shadow">
|
||||
<div class="flex flex-col items-center">
|
||||
<img :src="staff.avatar" alt="staff avatar" class="w-32 h-32 rounded-full object-cover mb-4">
|
||||
<h2 class="text-xl font-semibold text-gray-700">{{ staff.name }}</h2>
|
||||
<p class="text-gray-600 text-sm mb-4">{{ staff.position }}</p>
|
||||
</div>
|
||||
<ElDivider />
|
||||
<p class="text-gray-600 mb-4">{{ staff.intro }}</p>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<ElTag v-for="honor in staff.honors" :key="honor" type="success" size="small">
|
||||
{{ honor }}
|
||||
</ElTag>
|
||||
</div>
|
||||
</ElCard>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
127
web/src/views/suggestionbox.vue
Normal file
127
web/src/views/suggestionbox.vue
Normal file
@ -0,0 +1,127 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
|
||||
// 定义表单数据结构
|
||||
interface FeedbackForm {
|
||||
department: string;
|
||||
contact: string;
|
||||
phone: string;
|
||||
content: string;
|
||||
}
|
||||
|
||||
const formData = ref<FeedbackForm>({
|
||||
department: '',
|
||||
contact: '',
|
||||
phone: '',
|
||||
content: ''
|
||||
});
|
||||
|
||||
// 提交方法(可根据实际需求对接接口)
|
||||
const handleSubmit = () => {
|
||||
console.log('提交的表单数据:', formData.value);
|
||||
// 这里可补充 axios 等请求库调用后端接口逻辑,示例仅打印
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="feedback-container">
|
||||
<h2 class="title">意见反馈</h2>
|
||||
<div class="form-wrapper">
|
||||
<div class="form-item">
|
||||
<label class="form-label">部门:</label>
|
||||
<input
|
||||
class="form-input"
|
||||
v-model="formData.department"
|
||||
placeholder="请输入部门名称"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label class="form-label">联系人:</label>
|
||||
<input
|
||||
class="form-input"
|
||||
v-model="formData.contact"
|
||||
placeholder="请输入联系人姓名"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label class="form-label">联系电话:</label>
|
||||
<input
|
||||
class="form-input"
|
||||
v-model="formData.phone"
|
||||
placeholder="请输入联系电话"
|
||||
type="tel"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label class="form-label">需求内容:</label>
|
||||
<textarea
|
||||
class="form-textarea"
|
||||
v-model="formData.content"
|
||||
placeholder="请详细描述需求内容"
|
||||
></textarea>
|
||||
</div>
|
||||
<button class="submit-btn" @click="handleSubmit">提交意见</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.feedback-container {
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.title {
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.form-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
margin-bottom: 6px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.form-input,
|
||||
.form-textarea {
|
||||
caret-color: white;
|
||||
padding: 8px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.form-textarea {
|
||||
resize: vertical;
|
||||
min-height: 80px;
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
align-self: flex-end;
|
||||
padding: 10px 20px;
|
||||
background-color: #0078d4;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.submit-btn:hover {
|
||||
background-color: #005a9e;
|
||||
}
|
||||
</style>
|
||||
Loading…
x
Reference in New Issue
Block a user