Commit 684caa69 authored by 水玉婷's avatar 水玉婷
Browse files

feat:打通用户信息

parent 219e9ed3
......@@ -10,6 +10,7 @@
"dependencies": {
"@ant-design/icons-vue": "^6.1.0",
"ant-design-vue": "^3.2.0",
"axios": "^1.13.2",
"dayjs": "^1.11.0",
"echarts": "^6.0.0",
"event-source-polyfill": "^1.0.31",
......@@ -671,6 +672,48 @@
"integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==",
"license": "MIT"
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"license": "MIT"
},
"node_modules/axios": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz",
"integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.4",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/call-bind-apply-helpers": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"license": "MIT",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/compute-scroll-into-view": {
"version": "1.0.20",
"resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz",
......@@ -713,6 +756,15 @@
"integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==",
"license": "MIT"
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"license": "MIT",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/dom-align": {
"version": "1.12.4",
"resolved": "https://registry.npmjs.org/dom-align/-/dom-align-1.12.4.tgz",
......@@ -725,6 +777,20 @@
"integrity": "sha512-bvVTQe1lfaUr1oFzZX80ce9KLDlZ3iU+XGNE/bz9HnGdklTieqsbmsLHe+rT2XWqopvL0PckkYqN7ksmm5pe3w==",
"license": "MIT"
},
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
"es-errors": "^1.3.0",
"gopd": "^1.2.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/echarts": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/echarts/-/echarts-6.0.0.tgz",
......@@ -761,6 +827,51 @@
"errno": "cli.js"
}
},
"node_modules/es-define-property": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-errors": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-object-atoms": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-set-tostringtag": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.6",
"has-tostringtag": "^1.0.2",
"hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/esbuild": {
"version": "0.18.20",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz",
......@@ -811,6 +922,42 @@
"integrity": "sha512-4IJSItgS/41IxN5UVAVuAyczwZF7ZIEsM1XAoUzIHA6A+xzusEZUutdXz2Nr+MQPLxfTiCvqE79/C8HT8fKFvA==",
"license": "MIT"
},
"node_modules/follow-redirects": {
"version": "1.15.11",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"license": "MIT",
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/form-data": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
"integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0",
"hasown": "^2.0.2",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
......@@ -826,6 +973,64 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-intrinsic": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"es-define-property": "^1.0.1",
"es-errors": "^1.3.0",
"es-object-atoms": "^1.1.1",
"function-bind": "^1.1.2",
"get-proto": "^1.0.1",
"gopd": "^1.2.0",
"has-symbols": "^1.1.0",
"hasown": "^2.0.2",
"math-intrinsics": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
"license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.1",
"es-object-atoms": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/gopd": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/graceful-fs": {
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
......@@ -834,6 +1039,45 @@
"license": "ISC",
"optional": true
},
"node_modules/has-symbols": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-tostringtag": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"license": "MIT",
"dependencies": {
"has-symbols": "^1.0.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/hasown": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
......@@ -959,6 +1203,15 @@
"node": ">=6"
}
},
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/mime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
......@@ -973,6 +1226,27 @@
"node": ">=4"
}
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"license": "MIT",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/nanoid": {
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
......@@ -1070,6 +1344,12 @@
"node": "^10 || ^12 || >=14"
}
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
"license": "MIT"
},
"node_modules/prr": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
......
......@@ -9,17 +9,18 @@
"preview": "vite preview"
},
"dependencies": {
"vue": "^3.3.0",
"vue-router": "^4.2.0",
"@ant-design/icons-vue": "^6.1.0",
"echarts": "^6.0.0",
"ant-design-vue": "^3.2.0",
"axios": "^1.13.2",
"dayjs": "^1.11.0",
"event-source-polyfill": "^1.0.31"
"echarts": "^6.0.0",
"event-source-polyfill": "^1.0.31",
"vue": "^3.3.0",
"vue-router": "^4.2.0"
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.2.0",
"vite": "^4.3.0",
"less": "^4.4.2"
"less": "^4.4.2",
"vite": "^4.3.0"
}
}
\ No newline at end of file
}
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { setRouter } from './utils/router-manager'
const app = createApp(App)
app.use(router)
// 设置全局路由实例
setRouter(router)
app.mount('#app')
\ No newline at end of file
import { createRouter, createWebHistory } from 'vue-router'
import { createRouter, createWebHashHistory } from 'vue-router' // 改为Hash模式
import wechat from '../utils/wechat'
const routes = [
......@@ -20,7 +20,7 @@ const routes = [
]
const router = createRouter({
history: createWebHistory('/ai/'), // 添加基础路径
history: createWebHashHistory('/ai/'), // 使用Hash模式
routes
})
......
import axios from 'axios'
// 创建axios实例
const instance = axios.create({
baseURL: '/',
timeout: 10000,
headers: {
'Content-Type': 'application/json'
}
})
// 请求拦截器 - 添加认证信息
instance.interceptors.request.use(
(config) => {
// 从localStorage获取用户信息
const userData = localStorage.getItem('wechat_user')
const { extMap = {} } = JSON.parse(userData || '{}')
const userToken = extMap.sessionId;
if (userToken) {
try {
config.headers['x-session-id'] = userToken || ''
} catch (error) {
console.warn('解析用户信息失败', error)
}
}
return config
},
(error) => {
return Promise.reject(error)
}
)
import { navigateToLogin } from './router-manager'
// 响应拦截器 - 处理401错误
instance.interceptors.response.use(
(response) => {
return response
},
(error) => {
if (error.response) {
const { status } = error.response
// 处理401未授权错误
if (status === 401) {
// 清除本地存储的用户信息
localStorage.removeItem('wechat_user')
// 使用全局路由管理器跳转
navigateToLogin()
return Promise.reject(new Error('未授权访问,请重新登录'))
}
// 其他错误处理
console.error(`请求失败: ${status}`, error.response.data)
} else if (error.request) {
console.error('网络错误,请求未发送成功', error)
} else {
console.error('请求配置错误', error.message)
}
return Promise.reject(error)
}
)
// 导出get和post方法
export const get = (url, config = {}) => instance.get(url, config)
export const post = (url, data = {}, config = {}) => instance.post(url, data, config)
// 导出实例(可选)
export default instance
\ No newline at end of file
// 全局路由管理器
let routerInstance = null
export const setRouter = (router) => {
routerInstance = router
}
export const getRouter = () => {
return routerInstance
}
export const navigateToLogin = () => {
if (routerInstance) {
routerInstance.push('/login')
} else {
// 备用方案:使用hash跳转
if (window.location.hash) {
window.location.hash = '/login'
} else {
window.location.pathname = '/login'
}
}
}
\ No newline at end of file
// 简化的微信静默登录工具类
// 引入axios
import { post } from './axios.js'
// 企业微信登录工具类 - 简化版本(直接从URL获取code)
class WeChatLogin {
constructor() {
this.appId = 'YOUR_WECHAT_APPID' // 替换为你的微信公众号AppID
this.isWeChat = this.checkWeChatBrowser()
this.isConfigured = this.appId !== 'YOUR_WECHAT_APPID'
this.corpId = 'ww88c20288b24a8e33' // 企业微信CorpID
this.agentId = '1000002' // 应用AgentId
}
// 检查是否为微信浏览器
checkWeChatBrowser() {
// 检查是否为企业微信浏览器
checkWeChatWorkBrowser() {
const ua = navigator.userAgent.toLowerCase()
return ua.indexOf('micromessenger') !== -1
return ua.indexOf('wxwork') !== -1
}
// 简化的静默登录
async silentLogin() {
// 如果未配置appId,使用模拟登录
if (!this.isConfigured) {
console.log('使用模拟静默登录')
return this.mockLogin()
}
// 如果是微信浏览器,执行真实静默登录
if (this.isWeChat) {
return this.realWeChatLogin()
}
// 非微信浏览器,使用模拟登录
console.log('非微信浏览器,使用模拟登录')
return this.mockLogin()
// 从URL参数获取code
getCodeFromURL() {
const urlParams = new URLSearchParams(window.location.search)
return urlParams.get('code')
}
// 真实微信静默登录
realWeChatLogin() {
return new Promise((resolve, reject) => {
// 检查URL中是否已有授权code
const urlParams = new URLSearchParams(window.location.search)
const code = urlParams.get('code')
if (code) {
// 已有code,直接获取用户信息
this.getUserInfo(code).then(resolve).catch(reject)
} else {
// 重定向到微信授权页面进行静默授权
this.redirectToWeChat()
// 企业微信静默登录 - 核心方法
async silentLogin() {
try {
// 直接从URL获取code
const code = this.getCodeFromURL()
if (!code) {
console.error('未找到code参数,请确保在企业微信内部应用中访问')
return {
isLoggedIn: false,
message: '未找到code参数,请确保在企业微信内部应用中访问'
}
}
})
}
// 重定向到微信授权页面
redirectToWeChat() {
const redirectUri = encodeURIComponent(window.location.origin + window.location.pathname)
const scope = 'snsapi_base' // 静默授权,不弹出授权页面
const state = 'STATE_' + Date.now()
const authUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${this.appId}&redirect_uri=${redirectUri}&response_type=code&scope=${scope}&state=${state}#wechat_redirect`
window.location.href = authUrl
// 获取用户信息
const userInfo = await this.getUserInfo(code)
return {
isLoggedIn: true,
code: code,
userInfo: userInfo
}
} catch (error) {
console.error('登录失败:', error.message)
return {
isLoggedIn: false,
message: error.message || '登录失败'
}
}
}
// 获取用户信息(简化版)
// 获取用户信息 - 使用axios
async getUserInfo(code) {
try {
// 这里需要调用后端接口来获取用户信息
// 微信不允许前端直接调用获取用户信息的接口
const response = await fetch('/api/wechat/userinfo', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ code })
const response = await post('/pedService/wxcp/auth', {
authCode: code
})
if (!response.ok) {
throw new Error('获取用户信息失败')
}
const userInfo = await response.json()
// 保存用户信息到本地存储
localStorage.setItem('wechat_user', JSON.stringify(userInfo))
const result = response.data
return {
isLoggedIn: true,
userInfo: userInfo,
message: '微信静默登录成功'
if (result.code === 0) {
// 保存用户信息
localStorage.setItem('wechat_user', JSON.stringify(result.data))
return result.data
} else {
throw new Error(result.message || '获取用户信息失败')
}
} catch (error) {
console.error('获取用户信息失败:', error)
throw new Error('登录失败,请重试')
throw new Error(`获取用户信息失败: ${error.message}`)
}
}
// 模拟登录(用于开发和测试)
mockLogin() {
return new Promise((resolve) => {
setTimeout(() => {
const mockUser = {
openid: 'mock_openid_' + Date.now(),
nickname: '测试用户',
headimgurl: '',
isMock: true
}
localStorage.setItem('wechat_user', JSON.stringify(mockUser))
resolve({
isLoggedIn: true,
userInfo: mockUser,
message: '模拟登录成功'
})
}, 1000) // 模拟网络延迟
})
}
// 检查登录状态
checkLoginStatus() {
const userData = localStorage.getItem('wechat_user')
if (userData) {
try {
const userInfo = JSON.parse(userData)
return {
isLoggedIn: true,
userInfo: userInfo
userInfo: JSON.parse(userData)
}
} catch (error) {
console.error('解析用户数据失败:', error)
localStorage.removeItem('wechat_user')
}
}
return { isLoggedIn: false }
}
......@@ -136,7 +92,7 @@ class WeChatLogin {
localStorage.removeItem('wechat_user')
}
// 获取当前用户信息
// 获取当前用户
getCurrentUser() {
const status = this.checkLoginStatus()
return status.isLoggedIn ? status.userInfo : null
......
......@@ -17,21 +17,22 @@
const apiBaseUrl = '/pedapi';
// 获取token
const userToken = '65c76a8b38f350bd1849d41d3185c3eb';
const userInfo = localStorage.getItem('wechat_user')
const {extMap = {}} = JSON.parse(userInfo || '{}')
const userToken = extMap.sessionId;
// 添加APP_CODE配置
const appCode = 'ped.pc';
const appCode = 'ped.qywx';
const chatParams = {
appId: '83b2664019a945d0a438abe6339758d8',
stage: 'wechat-demo',
};
const dialogSessionId = '20251028143404893-00045166';
// const dialogSessionId = '';
// const dialogSessionId = '20251028143404893-00045166';
const dialogSessionId = '';
const detailData = ref({
title: '国械小智',
});
</script>
<style scoped>
......
......@@ -5,7 +5,6 @@
<div class="spinner"></div>
<p>正在静默登录中...</p>
</div>
<div v-else-if="error" class="error">
<p class="error-text">{{ error }}</p>
<button @click="retryLogin" class="retry-btn">重试登录</button>
......@@ -35,12 +34,9 @@ export default {
if (result.isLoggedIn) {
// 登录成功,跳转到首页
setTimeout(() => {
router.replace('/')
}, 500)
router.replace('/')
}
} catch (err) {
console.error('登录失败:', err)
error.value = err.message || '登录失败,请重试'
loading.value = false
}
......
......@@ -81,12 +81,13 @@
<script setup lang="ts">
import { EventSourcePolyfill } from 'event-source-polyfill';
import { ref, nextTick, onMounted, onBeforeUnmount } from 'vue';
import { SendOutlined, UserOutlined } from '@ant-design/icons-vue';
import { ref, reactive, computed, onMounted, onBeforeUnmount, nextTick, watch } from 'vue';
import dayjs from 'dayjs';
import { post } from '@/utils/axios.js'; // 导入axios的post方法
import tableTemplate from './tableTemplate';
import { SendOutlined, UserOutlined } from '@ant-design/icons-vue';
import defaultAvatar from '@/assets/logo.png';
import ChartComponent from './ChartComponent.vue'; // 导入独立的图表组件
import { tableTemplate } from './tableTemplate'; // 导入表格模板工具
// 组件属性
const props = withDefaults(
......@@ -303,20 +304,18 @@ const sendMessage = async () => {
} else {
// 默认的API调用逻辑
console.log('默认API调用逻辑', dialogSessionId);
const response = await fetch(`${props.apiBaseUrl}/aiService/ask/app/${props.params?.appId}`, {
method: 'POST',
const response = await post(`${props.apiBaseUrl}/aiService/ask/app/${props.params?.appId}`, {
question: message,
...props.params,
}, {
headers: {
'Content-Type': 'application/json',
Token: props.token || '',
'x-session-id': props.token || '',
'x-app-code': props.appCode || '',
},
body: JSON.stringify({
question: message,
...props.params,
}),
}
});
const data = await response.json();
const data = response.data;
if (data.code === 0) {
loading.value = false;
}
......@@ -365,19 +364,21 @@ const processSSEMessage = (
case 3: // 图表数据
if (updatedResponse) {
const { rows } = messageContent;
// 表格数据处理
updatedResponse.contentBlocks.push({
content: contentTemplates.table(rows),
hasThinkBox: false,
thinkContent: '',
thinkBoxExpanded: false,
});
// 图表数据处理
updatedResponse.contentBlocks.push({
content: '', // 图表内容由组件处理,这里留空
content: '',
hasThinkBox: false,
thinkContent: '',
thinkBoxExpanded: false,
chartData: messageContent, // 添加图表数据
chartType: 3, // 使用object类型
chartType: 3,
});
}
break;
......@@ -504,7 +505,7 @@ const reconnectSSE = (newDialogSessionId: string) => {
// 添加重连间隔控制,避免频繁重连
const reconnectTimeout = setTimeout(() => {
initSSE();
// 重连完成后重置标志
// 重连完成后重置标志
setTimeout(() => {
isReconnecting.value = false;
}, 2000); // 延长重连间隔
......@@ -755,14 +756,15 @@ const getChatRecord = async (dialogSessionId: string) => {
messages.value = [...recordList];
}
} else {
const response = await fetch(`${props.apiBaseUrl}/aiService/ask/list/chat/${dialogSessionId}`, {
const response = await post(`${props.apiBaseUrl}/aiService/ask/list/chat/${dialogSessionId}`, {}, {
headers: {
Token: props.token || '',
'x-session-id': props.token || '',
'x-app-code': props.appCode || '',
},
}
});
const data = await response.json();
const data = response.data;
if (data.code === 0) {
const recordList = processHistoryData(data.data || []);
messages.value = [...recordList];
......
// =============================================
// 全局样式和变量定义
// =============================================
// 颜色变量
@primary-color: #5B8AFE;
@primary-hover: #4a7df5;
@primary-light: #7BA6FF;
@blue-light-1: #f0f5ff;
@blue-light-2: #f8faff;
@blue-light-3: #e0e8ff;
@white: #ffffff;
@gray-1: #f8f9fa;
@gray-2: #f5f5f5;
@gray-3: #e0e0e0;
@gray-4: #cccccc;
@gray-5: #999999;
@gray-6: #666666;
@gray-7: #333333;
@success-color: #52c41a;
@error-color: #f5222d;
@warning-color: #faad14;
// 全局滚动条美化 - 悬浮式不占位滚动条
* {
padding: 0;
......@@ -11,317 +34,338 @@
}
}
p,h1,h2,h3,h4,h5,h6,ul,ol,li{
margin:0;
padding:0;
// 重置基础元素样式
p, h1, h2, h3, h4, h5, h6, ul, ol, li {
margin: 0;
padding: 0;
}
// =============================================
// 主容器和布局样式
// =============================================
.chat-container {
background-color: white;
border-radius: 8px;
box-shadow: 0 8px 30px rgba(91, 138, 254, 0.15); // 修改阴影颜色
overflow: hidden;
width: 100%;
background-color: @white;
border-radius: 8px;
box-shadow: 0 8px 30px rgba(91, 138, 254, 0.15);
overflow: hidden;
width: 100%;
display: flex;
flex-direction: column;
height: 100vh;
// 居中介绍页面样式
.chat-intro-center {
flex: 1;
display: flex;
flex-direction: column;
height: 100vh;
// 居中介绍页面样式
.chat-intro-center {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
padding: 40px 20px;
align-items: center;
justify-content: center;
padding: 40px 20px;
.intro-content {
text-align: center;
max-width: 400px;
width: 100%;
.avatar-image {
width: 180px;
height: 180px;
border-radius: 50%;
margin-bottom: 20px;
}
h3 {
font-size: 24px;
color: @gray-7;
margin-bottom: 12px;
font-weight: 600;
}
p {
font-size: 16px;
color: @gray-6;
line-height: 1.5;
margin-bottom: 30px;
}
.start-chat-btn {
background: linear-gradient(135deg, @primary-color 0%, @primary-light 100%);
color: @white;
border: none;
padding: 12px 30px;
border-radius: 25px;
font-size: 16px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(91, 138, 254, 0.3);
.intro-content {
text-align: center;
max-width: 400px;
width: 100%;
.avatar-image {
width: 180px;
height: 180px;
border-radius: 50%;
margin-bottom: 20px;
}
h3 {
font-size: 24px;
color: #333;
margin-bottom: 12px;
font-weight: 600;
}
p {
font-size: 16px;
color: #666;
line-height: 1.5;
margin-bottom: 30px;
}
.start-chat-btn {
background: linear-gradient(135deg, #5B8AFE 0%, #7BA6FF 100%);
color: white;
border: none;
padding: 12px 30px;
border-radius: 25px;
font-size: 16px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(91, 138, 254, 0.3);
&:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(91, 138, 254, 0.4);
}
&:active {
transform: translateY(0);
}
}
&:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(91, 138, 254, 0.4);
}
&:active {
transform: translateY(0);
}
}
}
// 聊天头部样式保持不变
.chat-header {
display: flex;
align-items: center;
}
// 消息区域样式保持不变
.chat-messages {
flex: 1;
overflow-y: auto;
padding: 12px;
}
// 输入容器保持在底部
.chat-input-container {
padding: 20px;
border-top: 1px solid #e8f2f1;
background: #FCFCFC;
// 确保输入容器始终在底部
flex-shrink: 0;
}
.header-avatar {
width: 45px;
height: 45px;
border-radius: 50%;
background-color: rgba(255, 255, 255, 0.2);
}
// 聊天头部样式
.chat-header {
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
margin-right: 15px;
border: 2px solid rgba(255, 255, 255, 0.3);
img{
width:100%;
height:auto;
.header-avatar {
width: 45px;
height: 45px;
border-radius: 50%;
background-color: rgba(255, 255, 255, 0.2);
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
margin-right: 15px;
border: 2px solid rgba(255, 255, 255, 0.3);
img {
width: 100%;
height: auto;
}
}
}
.header-info {
flex: 1;
h2 {
font-size: 18px;
.header-info {
flex: 1;
h2 {
font-size: 18px;
}
}
}
// 消息区域
.chat-messages {
flex: 1;
overflow-y: auto;
padding:12px;
padding: 12px;
}
.message-time {
color: #88a5d0; // 修改时间颜色为蓝色系
margin-bottom: 6px;
font-size: 14px;
// 输入容器
.chat-input-container {
padding: 20px;
border-top: 1px solid #e8f2f1;
background: #FCFCFC;
flex-shrink: 0;
}
}
.message {
display: flex;
margin-bottom: 20px;
flex-direction: column;
align-items: baseline;
}
// =============================================
// 消息样式
// =============================================
.message-time {
color: #88a5d0;
margin-bottom: 6px;
font-size: 14px;
}
.message.sent {
.message {
display: flex;
margin-bottom: 20px;
flex-direction: column;
align-items: baseline;
&.sent {
align-items: flex-end;
.message-time {
text-align: right;
}
.avatar-container {
flex-direction: row-reverse;
justify-content: flex-end;
}
}
.avatar-container {
display: flex;
align-items: center;
}
}
.avatar {
width: 42px;
height: 42px;
border-radius: 50%;
overflow: hidden;
flex-shrink: 0;
background-color: #e0e0e0;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
color: white;
border: 2px solid white;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
img{
width:100%;
height:auto;
}
}
.avatar-container {
display: flex;
align-items: center;
}
.message.received .avatar {
margin-right: 12px;
.avatar {
width: 42px;
height: 42px;
border-radius: 50%;
overflow: hidden;
flex-shrink: 0;
background-color: @gray-3;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
color: @white;
border: 2px solid @white;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
img {
width: 100%;
height: auto;
}
}
.message.sent .avatar {
background: linear-gradient(135deg, #A8C6FF 0%, #C2D6FF 100%); // 修改发送方头像背景为浅蓝色
margin-left: 12px;
}
.message.received .avatar {
margin-right: 12px;
}
.message.sent .avatar {
background: linear-gradient(135deg, #A8C6FF 0%, #C2D6FF 100%);
margin-left: 12px;
}
.message-content-wrapper {
.message-content-wrapper {
max-width: 100%;
margin-top: 8px;
min-width: 150px;
// 当包含图表、表格或iframe时,宽度为100%
&:has(.message-table),
&:has(.message-chart),
&:has(.message-iframe) {
width: 100%;
min-width: 100%;
max-width: 100%;
margin-top: 8px;
min-width: 150px;
// 当包含图表、表格或iframe时,宽度为100%
&:has(.message-table),
&:has(.message-chart),
&:has(.message-iframe){
width: 100%;
min-width: 100%;
max-width: 100%;
}
}
}
.message-content {
padding: 10px;
border-radius: 8px;
line-height: 1.5;
position: relative;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
white-space: pre-wrap;
.message-inner-box {
font-size: 0;
:deep(.message-text) {
font-size: 14px;
}
.message-content {
padding: 10px;
border-radius: 8px;
line-height: 1.5;
position: relative;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
white-space: pre-wrap;
.message-inner-box {
font-size: 0;
:deep(.message-text) {
font-size: 14px;
}
}
}
.message.received .message-content {
background-color: #f0f5ff; // 修改回复方消息背景为浅蓝色
border-top-left-radius: 5px;
color: #333;
border: 1px solid #e0e8ff; // 修改边框颜色
}
.message.received .message-content {
background-color: @blue-light-1;
border-top-left-radius: 5px;
color: @gray-7;
border: 1px solid @blue-light-3;
}
.message.sent .message-content {
background: linear-gradient(135deg, #5B8AFE 0%, #7BA6FF 100%); // 修改发送方消息背景为#5B8AFE
border-top-right-radius: 5px;
color: white; // 修改文字颜色为白色
border: 1px solid #4a7df5; // 修改边框颜色
}
.message.sent .message-content {
background: linear-gradient(135deg, @primary-color 0%, @primary-light 100%);
border-top-right-radius: 5px;
color: @white;
}
:deep(.message-error) {
line-height: 1.5;
color: #c33;
white-space: pre-wrap;
font-size: 14px;
}
// 错误消息样式
:deep(.message-error) {
line-height: 1.5;
color: @error-color;
white-space: pre-wrap;
font-size: 14px;
}
.think-box-wrapper {
margin: 12px 0;
padding: 10px 15px;
background-color: #f5f8f7;
border-radius: 12px;
border: 1px solid #e3ecea;
transition: all 0.3s ease;
}
// 思考框样式
.think-box-wrapper {
margin: 12px 0;
padding: 10px 15px;
background-color: #f5f8f7;
border-radius: 12px;
border: 1px solid #e3ecea;
transition: all 0.3s ease;
}
:deep(.think-box-toggle) {
color: #5B8AFE; // 修改思考框切换按钮颜色
cursor: pointer;
font-size: 12px;
text-decoration: none;
align-items: center;
gap: 4px;
font-weight: 500;
padding: 4px 8px;
border-radius: 4px;
transition: all 0.2s ease;
}
:deep(.think-box-toggle) {
color: @primary-color;
cursor: pointer;
font-size: 12px;
text-decoration: none;
align-items: center;
gap: 4px;
font-weight: 500;
padding: 4px 8px;
border-radius: 4px;
transition: all 0.2s ease;
}
:deep(.think-box-content) {
margin-top: 8px;
background-color: #ffffff;
padding: 12px 16px;
border-radius: 8px;
border: 1px solid #e9ecef;
font-size: 0px;
color: #495057;
white-space: pre-wrap;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
animation: fadeIn 0.3s ease-in-out;
.think-content {
font-size: 0;
.think-line {
font-size: 13px;
color: #999;
font-style: italic;
}
:deep(.think-box-content) {
margin-top: 8px;
background-color: @white;
padding: 12px 16px;
border-radius: 8px;
border: 1px solid #e9ecef;
font-size: 0px;
color: #495057;
white-space: pre-wrap;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
animation: fadeIn 0.3s ease-in-out;
.think-content {
font-size: 0;
.think-line {
font-size: 13px;
color: @gray-5;
font-style: italic;
}
}
}
.chat-input-container {
padding: 20px;
border-top: 1px solid #e8f2f1;
background: #FCFCFC;
}
.chat-input {
display: flex;
align-items: flex-end;
position: relative; // 添加相对定位
}
// =============================================
// 输入框样式
// =============================================
.chat-input textarea {
.chat-input {
display: flex;
align-items: flex-end;
position: relative;
textarea {
flex: 1;
padding: 14px 70px 14px 18px; // 增加右侧内边距为按钮留出更多空间
padding: 14px 70px 14px 18px;
border-radius: 12px;
outline: none;
resize: none;
height: 52px;
font-size: 15px;
transition: border-color 0.3s, box-shadow 0.3s;
background-color: #f8faff;
border: 1px solid #E0E0E0;
background-color: @blue-light-2;
border: 1px solid @gray-3;
overflow: hidden;
position: relative;
/* 投影/大投影 */
box-shadow: 0px 2px 8px 0px rgba(0, 0, 0, 0.12);
&:focus {
border-color: @primary-color;
box-shadow: 0 0 0 2px rgba(91, 138, 254, 0.1);
}
&:disabled {
background-color: @gray-2;
border-color: @gray-3;
color: @gray-5;
cursor: not-allowed;
}
}
.chat-input button {
button {
position: absolute;
right: 12px;
top: 50%;
color: #5B8AFE;
color: @primary-color;
background: none;
border: none;
width: 40px;
......@@ -334,73 +378,58 @@ p,h1,h2,h3,h4,h5,h6,ul,ol,li{
transition: color 0.2s, border-color 0.2s, background-color 0.2s;
z-index: 10;
transform: translateY(-50%);
}
.chat-input button:hover {
color: #4a7df5; // 悬停时颜色变深
border-color: #4a7df5; // 悬停时边框颜色变深
background-color: rgba(91, 138, 254, 0.05); // 悬停时添加轻微背景色
}
.chat-input button:active {
background-color: rgba(91, 138, 254, 0.1); // 点击时背景色加深
transform: translateY(-50%) scale(0.95); // 保持垂直居中并缩小
}
.chat-input button:disabled {
color: #cccccc; // 禁用状态颜色
border-color: #cccccc; // 禁用状态边框颜色
background-color: transparent; // 禁用状态背景透明
cursor: not-allowed;
transform: translateY(-50%); // 保持垂直居中,不移除transform
}
.chat-input textarea:focus {
border-color: #5B8AFE; // 修改输入框焦点边框颜色
box-shadow: 0 0 0 2px rgba(91, 138, 254, 0.1); // 修改输入框焦点阴影
}
.chat-input textarea:disabled {
background-color: #f5f5f5;
border-color: #e0e0e0;
color: #999;
cursor: not-allowed;
}
.operation-box {
margin-top: 6px;
p {
color: #999;
font-size: 12px;
span {
margin-right: 15px;
}
&:hover {
color: @primary-hover;
border-color: @primary-hover;
background-color: rgba(91, 138, 254, 0.05);
}
&:active {
background-color: rgba(91, 138, 254, 0.1);
transform: translateY(-50%) scale(0.95);
}
&:disabled {
color: @gray-4;
border-color: @gray-4;
background-color: transparent;
cursor: not-allowed;
transform: translateY(-50%);
}
}
}
}
@media (max-width: 600px) {
.header-avatar {
width: 40px;
height: 40px;
.operation-box {
margin-top: 6px;
p {
color: @gray-5;
font-size: 12px;
span {
margin-right: 15px;
}
}
}
// =============================================
// 表格消息样式
// =============================================
:deep(.message-table) {
width: 100%;
max-width: 100%;
margin: 8px 0;
// 表格容器,用于包裹表格和滚动条
// 表格容器
.table-container {
width: 100%;
overflow-x: auto; // 添加水平滚动条支持
-webkit-overflow-scrolling: touch; // iOS平滑滚动
overflow-x: auto;
-webkit-overflow-scrolling: touch;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
// 滚动条样式
&::-webkit-scrollbar {
height: 8px;
......@@ -420,31 +449,29 @@ p,h1,h2,h3,h4,h5,h6,ul,ol,li{
}
}
}
.data-table {
width: auto; // 改为自动宽度,允许表格超出容器
min-width: 100%; // 确保表格至少与容器一样宽
width: auto;
min-width: 100%;
border-collapse: collapse;
background-color: white;
table-layout: auto; // 改为自动布局,允许列宽自适应内容
background-color: @white;
table-layout: auto;
// 文字列样式 - 左对齐
// 列类型样式
.text-cell {
text-align: left;
padding-left: 12px;
padding-right: 8px;
}
// 数字列样式 - 右对齐
.numeric-cell {
text-align: right;
padding-left: 8px;
padding-right: 12px;
font-family: 'Courier New', monospace; // 使用等宽字体便于数字对齐
font-family: 'Courier New', monospace;
font-weight: 500;
}
// 趋势列样式 - 居中
.trend-cell {
text-align: center;
padding-left: 8px;
......@@ -452,8 +479,8 @@ p,h1,h2,h3,h4,h5,h6,ul,ol,li{
}
th {
background: linear-gradient(135deg, #5B8AFE 0%, #4a7df5 100%); // 修改表格表头背景
color: white;
background: linear-gradient(135deg, @primary-color 0%, @primary-hover 100%);
color: @white;
font-weight: 600;
padding: 12px 8px;
font-size: 14px;
......@@ -473,26 +500,26 @@ p,h1,h2,h3,h4,h5,h6,ul,ol,li{
padding: 10px 8px;
font-size: 14px;
border-bottom: 1px solid #f0f0f0;
color: #333;
height: 35px; // 固定单元格高度,替换line-height
color: @gray-7;
height: 35px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: middle; // 确保内容垂直居中
min-width: 80px; // 设置最小列宽,与表头保持一致
vertical-align: middle;
min-width: 80px;
}
// 奇偶行背景色设置移动到tr元素上
// 奇偶行样式
tr:nth-child(odd) td {
background-color: #f8faff; // 奇数行背景色为浅蓝色
background-color: @blue-light-2;
}
tr:nth-child(even) td {
background-color: white; // 偶数行背景色为白色
background-color: @white;
}
tr:hover td {
background-color: #f0f5ff; // 修改为蓝色系的悬停背景色
background-color: @blue-light-1;
}
tr:last-child td {
......@@ -502,13 +529,13 @@ p,h1,h2,h3,h4,h5,h6,ul,ol,li{
// 趋势箭头样式
.trend-up {
color: #52c41a;
color: @success-color;
font-weight: bold;
font-size: 16px;
}
.trend-down {
color: #f5222d;
color: @error-color;
font-weight: bold;
font-size: 16px;
}
......@@ -516,6 +543,7 @@ p,h1,h2,h3,h4,h5,h6,ul,ol,li{
.table-footer {
margin-top: 12px;
font-size: 14px;
span {
color: #2eb0a1;
font-weight: bold;
......@@ -523,41 +551,10 @@ p,h1,h2,h3,h4,h5,h6,ul,ol,li{
}
}
// 响应式表格样式
@media (max-width: 768px) {
:deep(.message-table) {
.data-table {
font-size: 12px;
th, td {
padding: 8px 4px;
height: 30px; // 移动端减小高度
min-width: 60px; // 移动端减小最小列宽
}
}
.table-title {
font-size: 14px;
}
.table-summary {
font-size: 12px;
padding: 8px 10px;
}
}
}
// =============================================
// iframe消息样式
// =============================================
@media (max-width: 480px) {
:deep(.message-table) {
.data-table {
th, td {
min-width: 50px; // 更小屏幕进一步减小最小列宽
height: 28px; // 更小屏幕进一步减小高度
}
}
}
}
// 表格消息样式
:deep(.message-iframe) {
width: 100%;
max-width: 100%;
......@@ -573,7 +570,7 @@ p,h1,h2,h3,h4,h5,h6,ul,ol,li{
min-height: 1800px;
border: none;
border-radius: 8px;
background-color: #f8f9fa;
background-color: @gray-1;
transition: height 0.5s ease-in-out, opacity 0.3s ease;
// 加载状态样式
......@@ -622,8 +619,8 @@ p,h1,h2,h3,h4,h5,h6,ul,ol,li{
.loading-spinner {
width: 40px;
height: 40px;
border: 4px solid #e0e0e0;
border-top: 4px solid #5B8AFE;
border: 4px solid @gray-3;
border-top: 4px solid @primary-color;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 16px;
......@@ -631,7 +628,7 @@ p,h1,h2,h3,h4,h5,h6,ul,ol,li{
.loading-text {
font-size: 16px;
color: #666;
color: @gray-6;
margin-bottom: 12px;
font-weight: 500;
}
......@@ -639,20 +636,23 @@ p,h1,h2,h3,h4,h5,h6,ul,ol,li{
.loading-progress {
width: 200px;
height: 4px;
background: #e0e0e0;
background: @gray-3;
border-radius: 2px;
overflow: hidden;
.progress-bar {
height: 100%;
background: linear-gradient(90deg, #5B8AFE, #7BA6FF);
background: linear-gradient(90deg, @primary-color, @primary-light);
width: 30%;
animation: progress 2s ease-in-out infinite;
}
}
}
// 加载动画
// =============================================
// 动画定义
// =============================================
@keyframes loading {
0% {
background-position: 200% 0;
......@@ -681,4 +681,49 @@ p,h1,h2,h3,h4,h5,h6,ul,ol,li{
100% {
transform: translateX(200%);
}
}
// =============================================
// 响应式样式
// =============================================
@media (max-width: 768px) {
:deep(.message-table) {
.data-table {
font-size: 12px;
th, td {
padding: 8px 4px;
height: 30px;
min-width: 60px;
}
}
.table-title {
font-size: 14px;
}
.table-summary {
font-size: 12px;
padding: 8px 10px;
}
}
}
@media (max-width: 480px) {
:deep(.message-table) {
.data-table {
th, td {
min-width: 50px;
height: 28px;
}
}
}
}
@media (max-width: 600px) {
.header-avatar {
width: 40px;
height: 40px;
}
}
\ No newline at end of file
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path';
export default defineConfig({
base: '/ai/', // 添加基础路径前缀
plugins: [vue()],
server: {
host: '0.0.0.0',
port: 3000,
proxy: {
// 添加history fallback配置
historyApiFallback: {
rewrites: [
{ from: /^\/ai\/.*$/, to: '/ai/index.html' }
]
},
proxy: {
'/pedapi': {
target: 'http://peddev.cmic.com.cn',
changeOrigin: true, // 解决跨域问题
......@@ -33,6 +40,24 @@ export default defineConfig({
console.log('发送请求到:', options.target);
});
}
},
// 修复pedService代理配置
'/pedService': {
target: 'http://10.17.86.37:8630',
changeOrigin: true, // 解决跨域问题
secure: false, // 允许不安全的SSL连接
rewrite: (path) => path.replace(/^\/pedService/, '/pedService'), // 保留前缀
configure: (proxy, options) => {
proxy.on('error', (err, req, res) => {
console.log('pedService代理错误:', err);
});
proxy.on('proxyReq', (proxyReq, req, res) => {
console.log('pedService发送请求到本地服务:', options.target + req.url);
});
proxy.on('proxyRes', (proxyRes, req, res) => {
console.log('pedService收到响应,状态码:', proxyRes.statusCode);
});
}
}
},
},
......@@ -44,7 +69,7 @@ export default defineConfig({
resolve: {
alias: {
'@': resolve(__dirname, 'src'),
'echarts': 'echarts/dist/echarts.esm.js' // 添加这一行
'echarts': 'echarts/dist/echarts.esm.js'
}
},
})
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment