mirror of
https://codeup.aliyun.com/67762337eccfc218f6110e0e/vue/learning-system-portal.git
synced 2025-12-09 10:56:44 +08:00
Compare commits
154 Commits
20250922-d
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
738add6f18 | ||
|
|
a7763057c4 | ||
|
|
421e2b2c51 | ||
|
|
12e91854fe | ||
|
|
3852a92ab3 | ||
|
|
56103bbdf6 | ||
|
|
d2f3b2d79c | ||
|
|
4e1940b36f | ||
|
|
3e344a8374 | ||
|
|
82598dd5e0 | ||
|
|
da72c156e9 | ||
|
|
f731bb425f | ||
|
|
8c2f128578 | ||
|
|
f16c6eb157 | ||
|
|
6016e00ae8 | ||
|
|
7155976f31 | ||
|
|
4ca01ba233 | ||
|
|
7368fa7a8c | ||
|
|
d09cbfac5f | ||
|
|
fd903d0974 | ||
|
|
42885e0d61 | ||
|
|
0b3b9ad082 | ||
|
|
38fe538e4e | ||
|
|
052ab0be6f | ||
|
|
4c453e3974 | ||
|
|
47dde458de | ||
|
|
3701605f7a | ||
|
|
b021be2f6f | ||
|
|
11e34ca335 | ||
|
|
bf20eced9b | ||
|
|
8f2da1c736 | ||
|
|
322172edec | ||
|
|
c801dc8a3d | ||
|
|
838e704ab0 | ||
|
|
d3e891e5cc | ||
|
|
40ac85f1fe | ||
|
|
6ee8eaca00 | ||
|
|
d78cc1f97c | ||
|
|
2576174e95 | ||
|
|
7316215809 | ||
|
|
c5e794ef45 | ||
|
|
720cff1d1e | ||
| f3cc59d313 | |||
|
|
dc57becb0d | ||
|
|
a94d101853 | ||
|
|
426ed75bc3 | ||
|
|
7e8b807825 | ||
|
|
bf13c953be | ||
|
|
8d07122420 | ||
|
|
471a790010 | ||
|
|
d39e1e98ef | ||
|
|
a82a65da8e | ||
|
|
2070466786 | ||
|
|
57d9f9b483 | ||
|
|
1710e34f89 | ||
|
|
e292a57b20 | ||
|
|
88c83af460 | ||
|
|
a78bac9368 | ||
|
|
f121a2aaf9 | ||
|
|
8228b33cb0 | ||
|
|
702255d9d0 | ||
|
|
df3e246d25 | ||
|
|
1d20f11861 | ||
|
|
d5ec4c1833 | ||
|
|
89a9be76d4 | ||
|
|
73026b0ab5 | ||
|
|
9b11cc3f92 | ||
|
|
372a7c22ed | ||
|
|
2678d22302 | ||
| 914b80c374 | |||
|
|
5d81f72f5f | ||
|
|
c9c34501ce | ||
|
|
1812c0901c | ||
|
|
13281d8a7d | ||
|
|
5fdf8efedb | ||
| 58f517d2fb | |||
|
|
ef9e4a0f68 | ||
|
|
a2640771fb | ||
|
|
25cb97f462 | ||
|
|
51c3d29854 | ||
|
|
c49d69dede | ||
|
|
6a764dd698 | ||
|
|
af10b1fa32 | ||
|
|
1a475c8612 | ||
|
|
782bcc31e5 | ||
|
|
7be0bdee6c | ||
|
|
f88a3a0b53 | ||
|
|
1a95852912 | ||
|
|
01e4c676fc | ||
|
|
48ec56dcbc | ||
|
|
f5d865ccc3 | ||
|
|
25c2e673dc | ||
|
|
78cc822464 | ||
|
|
366f1dc45b | ||
|
|
4ee6697166 | ||
|
|
a54c642f4b | ||
|
|
6a77bd9dc4 | ||
|
|
8e51663b86 | ||
|
|
cbe7981abd | ||
|
|
1ad2816622 | ||
|
|
03b3c61c6b | ||
|
|
b3756280cf | ||
|
|
f34d2a6e94 | ||
|
|
65673561d8 | ||
|
|
4d5b462b61 | ||
|
|
055476c583 | ||
|
|
78f681b4cb | ||
|
|
520fb4ee5e | ||
|
|
ba7bfe5f11 | ||
|
|
86bcf06d87 | ||
|
|
3e1b545d2a | ||
|
|
3f028e5cd8 | ||
|
|
d94bcf96a1 | ||
|
|
36b739d139 | ||
|
|
2cbb379fa6 | ||
|
|
8bf7a8e8e7 | ||
|
|
4b92308d1d | ||
|
|
a25ea0c4ba | ||
|
|
e55aa09409 | ||
|
|
5a3b57bd1c | ||
|
|
6d4af3aa2d | ||
|
|
b8ba52731f | ||
|
|
86e25f69f9 | ||
|
|
b8daef0983 | ||
|
|
df45c9d896 | ||
|
|
b9caf2c4ad | ||
|
|
0afd733f47 | ||
|
|
3720b5667d | ||
|
|
72472979bd | ||
| 70000e2e10 | |||
|
|
5ebee96ce4 | ||
| 408d6a1612 | |||
|
|
969c9f6797 | ||
|
|
33406f6964 | ||
|
|
e1f2e91648 | ||
|
|
8c023d459f | ||
|
|
47c1d29ef2 | ||
|
|
a3dab45af0 | ||
|
|
e3422d15ee | ||
|
|
581be5567f | ||
|
|
c9465492f4 | ||
|
|
3cef730e61 | ||
|
|
b18500bad7 | ||
|
|
5536fc06e1 | ||
|
|
18f3804536 | ||
|
|
7230bd18e8 | ||
| b1508ad226 | |||
| a9764bf2f8 | |||
|
|
fd10d99454 | ||
|
|
a51d87fbe8 | ||
|
|
2aa36c82ab | ||
|
|
0bba87cb3d | ||
|
|
98ba239494 | ||
|
|
df3b1d7162 |
22046
package-lock.json
generated
22046
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -15,6 +15,7 @@
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@mermaid-js/parser": "^0.6.3",
|
||||
"axios": "^0.21.4",
|
||||
"core-js": "^3.6.5",
|
||||
"driver.js": "^0.9.8",
|
||||
@@ -23,9 +24,15 @@
|
||||
"element-ui": "^2.15.7",
|
||||
"file-saver": "^2.0.5",
|
||||
"fuse.js": "^6.4.6",
|
||||
"highlight.js": "^11.11.1",
|
||||
"image-conversion": "^2.1.1",
|
||||
"jsencrypt": "^3.2.1",
|
||||
"json-bigint": "^1.0.0",
|
||||
"katex": "^0.16.25",
|
||||
"markdown-it": "^14.1.0",
|
||||
"markdown-it-highlightjs": "^4.2.0",
|
||||
"markdown-it-mermaid": "^0.2.5",
|
||||
"mermaid": "^8.13.10",
|
||||
"mockjs": "^1.1.0",
|
||||
"moment": "^2.29.1",
|
||||
"nprogress": "^0.2.0",
|
||||
@@ -43,6 +50,7 @@
|
||||
"vue": "^2.6.11",
|
||||
"vue-awesome-swiper": "^3.1.3",
|
||||
"vue-cookies": "^1.7.4",
|
||||
"vue-katex": "^0.5.0",
|
||||
"vue-pdf": "^4.2.0",
|
||||
"vue-quill-editor": "^3.0.6",
|
||||
"vue-router": "^3.5.2",
|
||||
@@ -60,6 +68,7 @@
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"less": "^4.1.1",
|
||||
"less-loader": "^6.2.0",
|
||||
"null-loader": "^4.0.1",
|
||||
"sass": "^1.32.13",
|
||||
"sass-loader": "^10.1.0",
|
||||
"vue-template-compiler": "^2.6.11"
|
||||
|
||||
72
src/App.vue
72
src/App.vue
@@ -1,25 +1,74 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<div id="app" style="width: 100vw">
|
||||
<keep-alive :include="['case']">
|
||||
<router-view />
|
||||
12312
|
||||
</keep-alive>
|
||||
<!-- 添加AI Call组件 -->
|
||||
<AICall
|
||||
:dialogVisible="showAICall"
|
||||
@close="onCloseAICall"
|
||||
@restore="onRestoreAICall"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import { mapGetters, mapState } from 'vuex';
|
||||
import AICall from '@/views/portal/case/AICall.vue';
|
||||
|
||||
export default{
|
||||
name: 'App',
|
||||
computed: {
|
||||
...mapGetters(['userInfo'])
|
||||
components: {
|
||||
AICall
|
||||
},
|
||||
mounted() {
|
||||
computed: {
|
||||
...mapGetters(['userInfo']),
|
||||
...mapState('app', ['showAICall', 'showAICallMinimized'])
|
||||
},
|
||||
methods: {
|
||||
onCloseAICall() {
|
||||
// 通过Vuex关闭AI Call组件
|
||||
this.$store.dispatch('app/setShowAICall', false);
|
||||
},
|
||||
|
||||
onRestoreAICall() {
|
||||
// 通过Vuex显示AI Call组件
|
||||
this.$store.dispatch('app/setShowAICall', true);
|
||||
},
|
||||
|
||||
// 检查当前路由是否应该显示AI弹窗
|
||||
checkRouteForAICall() {
|
||||
const currentRoute = this.$route.name;
|
||||
// 只在case或caseDetail路由显示弹窗
|
||||
if (currentRoute === 'case' || currentRoute === 'caseDetail') {
|
||||
// 设置最小化窗口显示状态为true
|
||||
this.$store.dispatch('app/setShowAICallMinimized', true);
|
||||
// 注意:这里不再强制设置showAICall为true,保留用户之前的操作状态
|
||||
} else {
|
||||
// 其他路由关闭弹窗
|
||||
this.$store.dispatch('app/setShowAICall', false);
|
||||
// 设置最小化窗口显示状态为false
|
||||
this.$store.dispatch('app/setShowAICallMinimized', false);
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
//从状态值中取,因为登录处理,所以移动watch中
|
||||
// console.log(this.userInfo);
|
||||
// if(this.userInfo && this.userInfo.name!=''){
|
||||
// this.$watermark.set(this.userInfo.name+this.userInfo.loginName);
|
||||
// }
|
||||
|
||||
// 初始化检查路由
|
||||
this.checkRouteForAICall();
|
||||
},
|
||||
watch: {
|
||||
// 监听路由变化
|
||||
$route(to, from) {
|
||||
this.checkRouteForAICall();
|
||||
}
|
||||
}
|
||||
// watch:{
|
||||
// userInfo(newVal,oldVal){
|
||||
// if(newVal && newVal.name!=''){
|
||||
@@ -38,5 +87,16 @@
|
||||
border: 1px solid #e7e7e7 !important;
|
||||
box-shadow: 0px 1px 5px 1px rgba(92,98,111,.3);
|
||||
}
|
||||
</style>
|
||||
|
||||
#app {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#app > *:not(.case-expert-dialog) {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.case-expert-dialog {
|
||||
pointer-events: auto;
|
||||
}
|
||||
</style>
|
||||
241
src/api/ajax.js
241
src/api/ajax.js
@@ -19,88 +19,93 @@ import errorCode from '@/utils/errorCode'
|
||||
|
||||
|
||||
// const ReLoginUrl=process.env.VUE_APP_LOGIN_URL;
|
||||
const TokenName='XBOE-Access-Token';
|
||||
const TokenName = 'XBOE-Access-Token';
|
||||
/**axios.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded'**/
|
||||
//只是用于发送json对象数据时使用post,put,patch
|
||||
/**axios.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded'**/
|
||||
//只是用于发送json对象数据时使用post,put,patch
|
||||
//用于普通的发送请求
|
||||
const formRequest=axios.create({
|
||||
// headers:{'Content-Type':'application/x-www-form-urlencoded'},
|
||||
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
||||
// baseURL: process.env.VUE_APP_CESOURCE_BASE_API,
|
||||
//超时
|
||||
timeout: 60000,
|
||||
})
|
||||
//发送json对象的拦截器
|
||||
formRequest.interceptors.request.use(config => {
|
||||
//是否需要设置 token
|
||||
const isToken = (config.headers || {}).isToken === false
|
||||
if (getToken() && !isToken) {
|
||||
config.headers[TokenName] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
}
|
||||
return config
|
||||
}, error => {
|
||||
console.log(error)
|
||||
Promise.reject(error)
|
||||
});
|
||||
formRequest.interceptors.response.use(res => {
|
||||
const code = res.data.status || 200;
|
||||
if(code===200){
|
||||
return res.data
|
||||
}else{
|
||||
if(code === 401){
|
||||
//Message({message: msg, type: 'error'});
|
||||
store.dispatch('LogOut').then(() => {
|
||||
location.href = this.webBaseUrl + ReLoginUrl;
|
||||
})
|
||||
}else if(code===403){
|
||||
var msg='当前操作没有权限';
|
||||
Message({message: msg, type: 'error'});
|
||||
return Promise.reject(new Error(msg))
|
||||
}else{
|
||||
//Message({message: res.data.message, type: 'error'});
|
||||
//console.log('err' + res.data.error);
|
||||
return res.data
|
||||
}
|
||||
}
|
||||
},
|
||||
error => {
|
||||
const formRequest = axios.create({
|
||||
// headers:{'Content-Type':'application/x-www-form-urlencoded'},
|
||||
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
||||
// baseURL: process.env.VUE_APP_CESOURCE_BASE_API,
|
||||
//超时
|
||||
timeout: 60000,
|
||||
})
|
||||
//发送json对象的拦截器
|
||||
formRequest.interceptors.request.use(config => {
|
||||
//是否需要设置 token
|
||||
const isToken = (config.headers || {}).isToken === false
|
||||
if (getToken() && !isToken) {
|
||||
config.headers[TokenName] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
}
|
||||
return config
|
||||
}, error => {
|
||||
console.log(error)
|
||||
Promise.reject(error)
|
||||
});
|
||||
formRequest.interceptors.response.use(res => {
|
||||
const code = res.data.status || 200;
|
||||
if (code === 200) {
|
||||
return res.data
|
||||
} else {
|
||||
if (code === 401) {
|
||||
//Message({message: msg, type: 'error'});
|
||||
store.dispatch('LogOut').then(() => {
|
||||
if (top !== window) { // 判断当前是否在iframe内
|
||||
top.location.href = this.webBaseUrl + ReLoginUrl;
|
||||
} else {
|
||||
window.location.href = this.webBaseUrl + ReLoginUrl;
|
||||
}
|
||||
// location.href = this.webBaseUrl + ReLoginUrl;
|
||||
})
|
||||
} else if (code === 403) {
|
||||
var msg = '当前操作没有权限';
|
||||
Message({ message: msg, type: 'error' });
|
||||
return Promise.reject(new Error(msg))
|
||||
} else {
|
||||
//Message({message: res.data.message, type: 'error'});
|
||||
//console.log('err' + res.data.error);
|
||||
return res.data
|
||||
}
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log('err' + error)
|
||||
let { message } = error;
|
||||
if (message == "Network Error") {
|
||||
message = "网络异常,请稍后重试";
|
||||
message = "网络异常,请稍后重试";
|
||||
}
|
||||
else if (message.includes("timeout")) {
|
||||
message = "网络异常或接口错误,请求超时";
|
||||
message = "网络异常或接口错误,请求超时";
|
||||
}
|
||||
else if (message.includes("Request failed with status code")) {
|
||||
message = "系统接口" + message.substr(message.length - 3) + "异常";
|
||||
message = "系统接口" + message.substr(message.length - 3) + "异常";
|
||||
}
|
||||
Message({
|
||||
message: message,
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
message: message,
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
})
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* request请求,可以自定义参数
|
||||
*/
|
||||
const request=formRequest.request;
|
||||
const request = formRequest.request;
|
||||
|
||||
/**
|
||||
* get请求 ,只有url
|
||||
*/
|
||||
const get = function(baseURL,url){
|
||||
return request({
|
||||
baseURL,
|
||||
url: url,
|
||||
method: 'get',
|
||||
headers:{'Content-Type':'application/x-www-form-urlencoded'}
|
||||
})
|
||||
const get = function (baseURL, url) {
|
||||
return request({
|
||||
baseURL,
|
||||
url: url,
|
||||
method: 'get',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,61 +113,61 @@ const get = function(baseURL,url){
|
||||
* @param {Object} url
|
||||
* @param {Object} postData
|
||||
*/
|
||||
const post=function(baseURL,url,postData){
|
||||
if(postData){
|
||||
postData=qs.stringify(postData);
|
||||
const post = function (baseURL, url, postData) {
|
||||
if (postData) {
|
||||
postData = qs.stringify(postData);
|
||||
}
|
||||
return request({
|
||||
baseURL,
|
||||
url: url,
|
||||
method: 'post',
|
||||
data:postData,
|
||||
headers:{'Content-Type':'application/x-www-form-urlencoded'}
|
||||
baseURL,
|
||||
url: url,
|
||||
method: 'post',
|
||||
data: postData,
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
|
||||
})
|
||||
}
|
||||
//post请求
|
||||
const postForm=function(baseURL,url,data){
|
||||
return request({
|
||||
baseURL,
|
||||
url,
|
||||
data,
|
||||
method: 'post',
|
||||
headers:{'Content-Type':'application/x-www-form-urlencoded'}
|
||||
});
|
||||
}
|
||||
const postForm = function (baseURL, url, data) {
|
||||
return request({
|
||||
baseURL,
|
||||
url,
|
||||
data,
|
||||
method: 'post',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
|
||||
});
|
||||
}
|
||||
// const postJson=jsonRequest.post;
|
||||
|
||||
const postJson=function(baseURL,url,postData){
|
||||
const postJson = function (baseURL, url, postData) {
|
||||
return request({
|
||||
baseURL,
|
||||
url: url,
|
||||
method: 'post',
|
||||
data:postData,
|
||||
headers:{'Content-Type':'application/json;charset=utf-8'},
|
||||
baseURL,
|
||||
url: url,
|
||||
method: 'post',
|
||||
data: postData,
|
||||
headers: { 'Content-Type': 'application/json;charset=utf-8' },
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
const postPdf=function(baseURL,url,postData){
|
||||
const postPdf = function (baseURL, url, postData) {
|
||||
return request({
|
||||
baseURL,
|
||||
url: url,
|
||||
responseType: 'blob',
|
||||
method: 'post',
|
||||
data:postData,
|
||||
headers:{'Content-Type':'application/pdf'},
|
||||
baseURL,
|
||||
url: url,
|
||||
responseType: 'blob',
|
||||
method: 'post',
|
||||
data: postData,
|
||||
headers: { 'Content-Type': 'application/pdf' },
|
||||
})
|
||||
}
|
||||
|
||||
// 导出文件请求定义
|
||||
const postJsonToFile=function(baseURL,url,postData){
|
||||
const postJsonToFile = function (baseURL, url, postData) {
|
||||
return request({
|
||||
baseURL,
|
||||
url: url,
|
||||
method: 'post',
|
||||
data:postData,
|
||||
headers:{'Content-Type':'application/json;charset=utf-8'},
|
||||
responseType: 'blob'
|
||||
baseURL,
|
||||
url: url,
|
||||
method: 'post',
|
||||
data: postData,
|
||||
headers: { 'Content-Type': 'application/json;charset=utf-8' },
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -170,39 +175,39 @@ const postJsonToFile=function(baseURL,url,postData){
|
||||
/**
|
||||
* put请求
|
||||
*/
|
||||
const put=function(baseURL,url,data){
|
||||
if(data){
|
||||
data=qs.stringify(data);
|
||||
const put = function (baseURL, url, data) {
|
||||
if (data) {
|
||||
data = qs.stringify(data);
|
||||
}
|
||||
return request({
|
||||
baseURL,
|
||||
url: url,
|
||||
method: 'put',
|
||||
data:data,
|
||||
headers:{'Content-Type':'application/x-www-form-urlencoded'}
|
||||
baseURL,
|
||||
url: url,
|
||||
method: 'put',
|
||||
data: data,
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
|
||||
})
|
||||
}
|
||||
|
||||
const putJson=function(baseURL,url,data){
|
||||
const putJson = function (baseURL, url, data) {
|
||||
return request({
|
||||
baseURL,
|
||||
url: url,
|
||||
method: 'put',
|
||||
data:data,
|
||||
headers:{'Content-Type':'application/json;charset=utf-8'},
|
||||
baseURL,
|
||||
url: url,
|
||||
method: 'put',
|
||||
data: data,
|
||||
headers: { 'Content-Type': 'application/json;charset=utf-8' },
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
export default {
|
||||
tokenName:TokenName,
|
||||
request,
|
||||
get,
|
||||
post,
|
||||
postJson,
|
||||
postJsonToFile,
|
||||
put,
|
||||
putJson,
|
||||
postPdf,
|
||||
tokenName: TokenName,
|
||||
request,
|
||||
get,
|
||||
post,
|
||||
postJson,
|
||||
postJsonToFile,
|
||||
put,
|
||||
putJson,
|
||||
postPdf,
|
||||
}
|
||||
|
||||
@@ -19,90 +19,95 @@ import errorCode from '@/utils/errorCode'
|
||||
|
||||
|
||||
// const ReLoginUrl=process.env.VUE_APP_LOGIN_URL;
|
||||
const TokenName='token';
|
||||
const TokenName = 'token';
|
||||
/**axios.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded'**/
|
||||
//只是用于发送json对象数据时使用post,put,patch
|
||||
/**axios.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded'**/
|
||||
//只是用于发送json对象数据时使用post,put,patch
|
||||
//用于普通的发送请求
|
||||
const formRequest=axios.create({
|
||||
// headers:{'Content-Type':'application/x-www-form-urlencoded'},
|
||||
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
||||
// baseURL: process.env.VUE_APP_CESOURCE_BASE_API,
|
||||
//超时
|
||||
timeout: 10000,
|
||||
})
|
||||
//发送json对象的拦截器
|
||||
formRequest.interceptors.request.use(config => {
|
||||
//是否需要设置 token
|
||||
const isToken = (config.headers || {}).isToken === false
|
||||
let curToken=getToken();
|
||||
//curToken='eyJ0eXBlIjoidG9rZW4iLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC91LmJvZS5jb20iLCJpYXQiOjE2NzIzMTE2MTIsImV4cCI6MTY3MjMxODgxMiwiR2l2ZW5OYW1lIjoiYm9ldSIsInVzZXJJZCI6IjZCMDQ5RkFGLUMzMTQtN0NDRi0wRDI4LTBEMjNGNEM0MjUzMSIsInVJZCI6Ijk2NTM0MjAyNzQ5NzYwNzE2OCIsInBlcm1pc3Npb24iOiIifQ==.a4f41376e994c5fcd3ab537ce17572ef4c633863f87785cf7b6ffa353e2ed51c';
|
||||
if (curToken && !isToken) {
|
||||
config.headers[TokenName] = curToken // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
}
|
||||
return config
|
||||
}, error => {
|
||||
console.log(error)
|
||||
Promise.reject(error)
|
||||
});
|
||||
formRequest.interceptors.response.use(res => {
|
||||
//console.log(res);
|
||||
const code = res.data.status || 200;
|
||||
if(code===200){
|
||||
return res.data
|
||||
}else{
|
||||
if(code === 401){
|
||||
store.dispatch('LogOut').then(() => {
|
||||
location.href = this.webBaseUrl + ReLoginUrl;
|
||||
})
|
||||
}else if(code===403){
|
||||
var msg='当前操作没有权限';
|
||||
Message({message: msg, type: 'error'});
|
||||
return Promise.reject(new Error(msg))
|
||||
}else{
|
||||
//Message({message: res.data.message, type: 'error'});
|
||||
//console.log('err' + res.data.error);
|
||||
return res.data
|
||||
}
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log('err',error)
|
||||
const formRequest = axios.create({
|
||||
// headers:{'Content-Type':'application/x-www-form-urlencoded'},
|
||||
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
||||
// baseURL: process.env.VUE_APP_CESOURCE_BASE_API,
|
||||
//超时
|
||||
timeout: 10000,
|
||||
})
|
||||
//发送json对象的拦截器
|
||||
formRequest.interceptors.request.use(config => {
|
||||
//是否需要设置 token
|
||||
const isToken = (config.headers || {}).isToken === false
|
||||
let curToken = getToken();
|
||||
//curToken='eyJ0eXBlIjoidG9rZW4iLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC91LmJvZS5jb20iLCJpYXQiOjE2NzIzMTE2MTIsImV4cCI6MTY3MjMxODgxMiwiR2l2ZW5OYW1lIjoiYm9ldSIsInVzZXJJZCI6IjZCMDQ5RkFGLUMzMTQtN0NDRi0wRDI4LTBEMjNGNEM0MjUzMSIsInVJZCI6Ijk2NTM0MjAyNzQ5NzYwNzE2OCIsInBlcm1pc3Npb24iOiIifQ==.a4f41376e994c5fcd3ab537ce17572ef4c633863f87785cf7b6ffa353e2ed51c';
|
||||
if (curToken && !isToken) {
|
||||
config.headers[TokenName] = curToken // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
}
|
||||
return config
|
||||
}, error => {
|
||||
console.log(error)
|
||||
Promise.reject(error)
|
||||
});
|
||||
formRequest.interceptors.response.use(res => {
|
||||
//console.log(res);
|
||||
const code = res.data.status || 200;
|
||||
if (code === 200) {
|
||||
return res.data
|
||||
} else {
|
||||
if (code === 401) {
|
||||
store.dispatch('LogOut').then(() => {
|
||||
if (top !== window) { // 判断当前是否在iframe内
|
||||
top.location.href = this.webBaseUrl + ReLoginUrl;
|
||||
} else {
|
||||
window.location.href = this.webBaseUrl + ReLoginUrl;
|
||||
}
|
||||
// location.href = this.webBaseUrl + ReLoginUrl;
|
||||
})
|
||||
} else if (code === 403) {
|
||||
var msg = '当前操作没有权限';
|
||||
Message({ message: msg, type: 'error' });
|
||||
return Promise.reject(new Error(msg))
|
||||
} else {
|
||||
//Message({message: res.data.message, type: 'error'});
|
||||
//console.log('err' + res.data.error);
|
||||
return res.data
|
||||
}
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log('err', error)
|
||||
let { message } = error;
|
||||
if (message == "Network Error") {
|
||||
message = "网络异常,请稍后重试";
|
||||
message = "网络异常,请稍后重试";
|
||||
}
|
||||
else if (message.includes("timeout")) {
|
||||
message = "网络异常或接口错误,请求超时";
|
||||
message = "网络异常或接口错误,请求超时";
|
||||
}
|
||||
else if (message.includes("Request failed with status code")) {
|
||||
message = "系统接口" + message.substr(message.length - 3) + "异常";
|
||||
message = "系统接口" + message.substr(message.length - 3) + "异常";
|
||||
}
|
||||
Message({
|
||||
message: message,
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
message: message,
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
})
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* request请求,可以自定义参数
|
||||
*/
|
||||
const request=formRequest.request;
|
||||
const request = formRequest.request;
|
||||
|
||||
/**
|
||||
* get请求 ,只有url
|
||||
*/
|
||||
const get = function(baseURL,url){
|
||||
return request({
|
||||
baseURL,
|
||||
url: url,
|
||||
method: 'get',
|
||||
headers:{'Content-Type':'application/x-www-form-urlencoded'}
|
||||
})
|
||||
const get = function (baseURL, url) {
|
||||
return request({
|
||||
baseURL,
|
||||
url: url,
|
||||
method: 'get',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,49 +115,49 @@ const get = function(baseURL,url){
|
||||
* @param {Object} url
|
||||
* @param {Object} postData
|
||||
*/
|
||||
const post=function(baseURL,url,postData){
|
||||
if(postData){
|
||||
postData=qs.stringify(postData);
|
||||
const post = function (baseURL, url, postData) {
|
||||
if (postData) {
|
||||
postData = qs.stringify(postData);
|
||||
}
|
||||
return request({
|
||||
baseURL,
|
||||
url: url,
|
||||
method: 'post',
|
||||
data:postData,
|
||||
headers:{'Content-Type':'application/x-www-form-urlencoded'}
|
||||
baseURL,
|
||||
url: url,
|
||||
method: 'post',
|
||||
data: postData,
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
|
||||
})
|
||||
}
|
||||
//post请求
|
||||
const postForm=function(baseURL,url,data){
|
||||
return request({
|
||||
baseURL,
|
||||
url,
|
||||
data,
|
||||
method: 'post',
|
||||
headers:{'Content-Type':'application/x-www-form-urlencoded'}
|
||||
});
|
||||
}
|
||||
const postForm = function (baseURL, url, data) {
|
||||
return request({
|
||||
baseURL,
|
||||
url,
|
||||
data,
|
||||
method: 'post',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
|
||||
});
|
||||
}
|
||||
// const postJson=jsonRequest.post;
|
||||
|
||||
const postJson=function(baseURL,url,postData){
|
||||
const postJson = function (baseURL, url, postData) {
|
||||
return request({
|
||||
baseURL,
|
||||
url: url,
|
||||
method: 'post',
|
||||
data:postData,
|
||||
headers:{'Content-Type':'application/json'},
|
||||
baseURL,
|
||||
url: url,
|
||||
method: 'post',
|
||||
data: postData,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
})
|
||||
}
|
||||
|
||||
// 导出文件请求定义
|
||||
const postJsonToFile=function(baseURL,url,postData){
|
||||
const postJsonToFile = function (baseURL, url, postData) {
|
||||
return request({
|
||||
baseURL,
|
||||
url: url,
|
||||
method: 'post',
|
||||
data:postData,
|
||||
headers:{'Content-Type':'application/json;charset=utf-8'},
|
||||
responseType: 'blob'
|
||||
baseURL,
|
||||
url: url,
|
||||
method: 'post',
|
||||
data: postData,
|
||||
headers: { 'Content-Type': 'application/json;charset=utf-8' },
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -160,38 +165,38 @@ const postJsonToFile=function(baseURL,url,postData){
|
||||
/**
|
||||
* put请求
|
||||
*/
|
||||
const put=function(baseURL,url,data){
|
||||
if(data){
|
||||
data=qs.stringify(data);
|
||||
const put = function (baseURL, url, data) {
|
||||
if (data) {
|
||||
data = qs.stringify(data);
|
||||
}
|
||||
return request({
|
||||
baseURL,
|
||||
url: url,
|
||||
method: 'put',
|
||||
data:data,
|
||||
headers:{'Content-Type':'application/x-www-form-urlencoded'}
|
||||
baseURL,
|
||||
url: url,
|
||||
method: 'put',
|
||||
data: data,
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
|
||||
})
|
||||
}
|
||||
|
||||
const putJson=function(baseURL,url,data){
|
||||
const putJson = function (baseURL, url, data) {
|
||||
return request({
|
||||
baseURL,
|
||||
url: url,
|
||||
method: 'put',
|
||||
data:data,
|
||||
headers:{'Content-Type':'application/json;charset=utf-8'},
|
||||
baseURL,
|
||||
url: url,
|
||||
method: 'put',
|
||||
data: data,
|
||||
headers: { 'Content-Type': 'application/json;charset=utf-8' },
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
export default {
|
||||
tokenName:TokenName,
|
||||
request,
|
||||
get,
|
||||
post,
|
||||
postJson,
|
||||
postJsonToFile,
|
||||
put,
|
||||
putJson,
|
||||
tokenName: TokenName,
|
||||
request,
|
||||
get,
|
||||
post,
|
||||
postJson,
|
||||
postJsonToFile,
|
||||
put,
|
||||
putJson,
|
||||
}
|
||||
|
||||
@@ -18,191 +18,201 @@ import errorCode from '@/utils/errorCode'
|
||||
*delete请求 axios.delete(url[, config])
|
||||
*/
|
||||
|
||||
const ReLoginUrl=process.env.VUE_APP_LOGIN_URL;
|
||||
const TokenName='token';
|
||||
const ReLoginUrl = process.env.VUE_APP_LOGIN_URL;
|
||||
const TokenName = 'token';
|
||||
|
||||
/**axios.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded'**/
|
||||
//只是用于发送json对象数据时使用post,put,patch
|
||||
const jsonRequest=axios.create({
|
||||
headers:{'Content-Type':'application/json;charset=utf-8'},
|
||||
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
||||
baseURL: process.env.VUE_APP_BOE_BASE_API,
|
||||
//超时
|
||||
timeout: 10000,
|
||||
const jsonRequest = axios.create({
|
||||
headers: { 'Content-Type': 'application/json;charset=utf-8' },
|
||||
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
||||
baseURL: process.env.VUE_APP_BOE_BASE_API,
|
||||
//超时
|
||||
timeout: 10000,
|
||||
});
|
||||
//发送json对象的拦截器
|
||||
jsonRequest.interceptors.request.use(config => {
|
||||
//是否需要设置 token
|
||||
const isToken = (config.headers || {}).isToken === false
|
||||
if (getToken() && !isToken) {
|
||||
config.headers[TokenName] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
}
|
||||
return config
|
||||
//是否需要设置 token
|
||||
const isToken = (config.headers || {}).isToken === false
|
||||
if (getToken() && !isToken) {
|
||||
config.headers[TokenName] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
}
|
||||
return config
|
||||
}, error => {
|
||||
console.log(error)
|
||||
Promise.reject(error)
|
||||
console.log(error)
|
||||
Promise.reject(error)
|
||||
})
|
||||
|
||||
// 响应拦截器
|
||||
jsonRequest.interceptors.response.use(res => {
|
||||
|
||||
const code1 = res.data.status || 200;
|
||||
const code=parseInt(code1);
|
||||
if(code===200){
|
||||
return res.data
|
||||
}else{
|
||||
if(code == 6001){ //对方是字符串,所以这里不要使用三个等号
|
||||
store.dispatch('LogOut').then(() => {
|
||||
location.href = ReLoginUrl;
|
||||
})
|
||||
}else if(code===403){
|
||||
var msg='当前操作没有权限';
|
||||
Message({message: msg, type: 'error'});
|
||||
return Promise.reject(new Error(msg))
|
||||
//return res.data;
|
||||
}else{
|
||||
//Message({message: res.data.message, type: 'error'});
|
||||
//console.log('err:' + res.data.error);
|
||||
//return Promise.reject(new Error(res.data.message))
|
||||
return res.data;
|
||||
}
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log('err' + error)
|
||||
let { message } = error;
|
||||
if (message == "Network Error") {
|
||||
message = "网络异常,请稍后重试";
|
||||
}
|
||||
else if (message.includes("timeout")) {
|
||||
message = "系统接口请求超时";
|
||||
//location.href = this.webBaseUrl + ReLoginUrl;
|
||||
}
|
||||
else if (message.includes("Request failed with status code")) {
|
||||
message = "系统接口" + message.substr(message.length - 3) + "异常";
|
||||
}
|
||||
Message({
|
||||
message: message,
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
})
|
||||
return Promise.reject(error)
|
||||
}
|
||||
const code1 = res.data.status || 200;
|
||||
const code = parseInt(code1);
|
||||
if (code === 200) {
|
||||
return res.data
|
||||
} else {
|
||||
if (code == 6001) { //对方是字符串,所以这里不要使用三个等号
|
||||
store.dispatch('LogOut').then(() => {
|
||||
if (top !== window) { // 判断当前是否在iframe内
|
||||
top.location.href = ReLoginUrl;
|
||||
} else {
|
||||
window.location.href = ReLoginUrl;
|
||||
}
|
||||
// location.href = ReLoginUrl;
|
||||
})
|
||||
} else if (code === 403) {
|
||||
var msg = '当前操作没有权限';
|
||||
Message({ message: msg, type: 'error' });
|
||||
return Promise.reject(new Error(msg))
|
||||
//return res.data;
|
||||
} else {
|
||||
//Message({message: res.data.message, type: 'error'});
|
||||
//console.log('err:' + res.data.error);
|
||||
//return Promise.reject(new Error(res.data.message))
|
||||
return res.data;
|
||||
}
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log('err' + error)
|
||||
let { message } = error;
|
||||
if (message == "Network Error") {
|
||||
message = "网络异常,请稍后重试";
|
||||
}
|
||||
else if (message.includes("timeout")) {
|
||||
message = "系统接口请求超时";
|
||||
//location.href = this.webBaseUrl + ReLoginUrl;
|
||||
}
|
||||
else if (message.includes("Request failed with status code")) {
|
||||
message = "系统接口" + message.substr(message.length - 3) + "异常";
|
||||
}
|
||||
Message({
|
||||
message: message,
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
})
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
//用于普通的发送请求
|
||||
const formRequest=axios.create({
|
||||
headers:{'Content-Type':'application/x-www-form-urlencoded'},
|
||||
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
||||
baseURL: process.env.VUE_APP_BOE_BASE_API,
|
||||
//超时
|
||||
timeout: 10000,
|
||||
const formRequest = axios.create({
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
||||
baseURL: process.env.VUE_APP_BOE_BASE_API,
|
||||
//超时
|
||||
timeout: 10000,
|
||||
})
|
||||
//发送json对象的拦截器
|
||||
formRequest.interceptors.request.use(config => {
|
||||
//是否需要设置 token
|
||||
const isToken = (config.headers || {}).isToken === false
|
||||
if (getToken() && !isToken) {
|
||||
config.headers[TokenName] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
}
|
||||
return config
|
||||
//是否需要设置 token
|
||||
const isToken = (config.headers || {}).isToken === false
|
||||
if (getToken() && !isToken) {
|
||||
config.headers[TokenName] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
}
|
||||
return config
|
||||
}, error => {
|
||||
console.log(error)
|
||||
Promise.reject(error)
|
||||
console.log(error)
|
||||
Promise.reject(error)
|
||||
});
|
||||
formRequest.interceptors.response.use(res => {
|
||||
const code = res.data.status || 200;
|
||||
if(code===200){
|
||||
return res.data
|
||||
}else{
|
||||
if(code == 6001){ //对方是字符串,所以这里不要使用三个等号
|
||||
store.dispatch('LogOut').then(() => {
|
||||
location.href = ReLoginUrl;
|
||||
})
|
||||
}else if(code===403){
|
||||
var msg='当前操作没有权限';
|
||||
Message({message: msg, type: 'error'});
|
||||
return Promise.reject(new Error(msg))
|
||||
}else{
|
||||
//Message({message: res.data.message, type: 'error'});
|
||||
//console.log('err' + res.data.error);
|
||||
//return Promise.reject(new Error(res.data.message))
|
||||
return res.data;//返回给用户做业务处理
|
||||
}
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log('err' + error)
|
||||
let { message } = error;
|
||||
if (message == "Network Error") {
|
||||
message = "网络异常,请稍后重试";
|
||||
}
|
||||
else if (message.includes("timeout")) {
|
||||
message = "系统接口请求超时";
|
||||
//location.href = this.webBaseUrl + ReLoginUrl;
|
||||
}
|
||||
else if (message.includes("Request failed with status code")) {
|
||||
message = "系统接口" + message.substr(message.length - 3) + "异常";
|
||||
}
|
||||
Message({
|
||||
message: message,
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
})
|
||||
return Promise.reject(error)
|
||||
}
|
||||
const code = res.data.status || 200;
|
||||
if (code === 200) {
|
||||
return res.data
|
||||
} else {
|
||||
if (code == 6001) { //对方是字符串,所以这里不要使用三个等号
|
||||
store.dispatch('LogOut').then(() => {
|
||||
if (top !== window) { // 判断当前是否在iframe内
|
||||
top.location.href = ReLoginUrl;
|
||||
} else {
|
||||
window.location.href = ReLoginUrl;
|
||||
}
|
||||
// location.href = ReLoginUrl;
|
||||
})
|
||||
} else if (code === 403) {
|
||||
var msg = '当前操作没有权限';
|
||||
Message({ message: msg, type: 'error' });
|
||||
return Promise.reject(new Error(msg))
|
||||
} else {
|
||||
//Message({message: res.data.message, type: 'error'});
|
||||
//console.log('err' + res.data.error);
|
||||
//return Promise.reject(new Error(res.data.message))
|
||||
return res.data;//返回给用户做业务处理
|
||||
}
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log('err' + error)
|
||||
let { message } = error;
|
||||
if (message == "Network Error") {
|
||||
message = "网络异常,请稍后重试";
|
||||
}
|
||||
else if (message.includes("timeout")) {
|
||||
message = "系统接口请求超时";
|
||||
//location.href = this.webBaseUrl + ReLoginUrl;
|
||||
}
|
||||
else if (message.includes("Request failed with status code")) {
|
||||
message = "系统接口" + message.substr(message.length - 3) + "异常";
|
||||
}
|
||||
Message({
|
||||
message: message,
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
})
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
//request请求
|
||||
const request=function(cfg){
|
||||
if(cfg.data){
|
||||
cfg.data=qs.stringify(cfg.data);
|
||||
const request = function (cfg) {
|
||||
if (cfg.data) {
|
||||
cfg.data = qs.stringify(cfg.data);
|
||||
}
|
||||
};
|
||||
//requestJson请求
|
||||
const requestJson=jsonRequest.request;
|
||||
const requestJson = jsonRequest.request;
|
||||
//get请求
|
||||
const get=formRequest.request;
|
||||
const get = formRequest.request;
|
||||
//post请求
|
||||
const post=function(url,data,config){
|
||||
if(data){
|
||||
data=qs.stringify(data);
|
||||
const post = function (url, data, config) {
|
||||
if (data) {
|
||||
data = qs.stringify(data);
|
||||
}
|
||||
return formRequest.post(url,data,config);
|
||||
return formRequest.post(url, data, config);
|
||||
}
|
||||
//postJson请求
|
||||
const postJson=jsonRequest.post;
|
||||
const postJson = jsonRequest.post;
|
||||
//put请求
|
||||
const put=function(url,data,config){
|
||||
if(data){
|
||||
data=qs.stringify(data);
|
||||
const put = function (url, data, config) {
|
||||
if (data) {
|
||||
data = qs.stringify(data);
|
||||
}
|
||||
return formRequest.put(url,data,config);
|
||||
return formRequest.put(url, data, config);
|
||||
}
|
||||
//putJson请求
|
||||
const putJson=jsonRequest.put;
|
||||
const putJson = jsonRequest.put;
|
||||
//patch请求
|
||||
const patch=function(url,data,config){
|
||||
if(data){
|
||||
data=qs.stringify(data);
|
||||
const patch = function (url, data, config) {
|
||||
if (data) {
|
||||
data = qs.stringify(data);
|
||||
}
|
||||
return formRequest.patch(url,data,config);
|
||||
return formRequest.patch(url, data, config);
|
||||
}
|
||||
//patchJson请求
|
||||
const patchJson=jsonRequest.patch;
|
||||
const patchJson = jsonRequest.patch;
|
||||
//delete请求
|
||||
const del=formRequest.delete;
|
||||
const del = formRequest.delete;
|
||||
|
||||
|
||||
export default {
|
||||
request,
|
||||
requestJson,
|
||||
get,
|
||||
post,
|
||||
postJson,
|
||||
put,
|
||||
putJson,
|
||||
patch,
|
||||
patchJson,
|
||||
del
|
||||
request,
|
||||
requestJson,
|
||||
get,
|
||||
post,
|
||||
postJson,
|
||||
put,
|
||||
putJson,
|
||||
patch,
|
||||
patchJson,
|
||||
del
|
||||
}
|
||||
|
||||
@@ -16,186 +16,196 @@ import errorCode from '@/utils/errorCode'
|
||||
*patchJson请求 axios.patch(url[, data[, config]])
|
||||
*delete请求 axios.delete(url[, config])
|
||||
*/
|
||||
|
||||
const ReLoginUrl="/login";
|
||||
const TokenName='XBOE-Access-Token';
|
||||
|
||||
const ReLoginUrl = "/login";
|
||||
const TokenName = 'XBOE-Access-Token';
|
||||
/**axios.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded'**/
|
||||
//只是用于发送json对象数据时使用post,put,patch
|
||||
const jsonRequest=axios.create({
|
||||
headers:{'Content-Type':'application/json;charset=utf-8'},
|
||||
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
||||
baseURL: process.env.VUE_APP_CESOURCE_BASE_API,
|
||||
//超时
|
||||
timeout: 10000,
|
||||
const jsonRequest = axios.create({
|
||||
headers: { 'Content-Type': 'application/json;charset=utf-8' },
|
||||
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
||||
baseURL: process.env.VUE_APP_CESOURCE_BASE_API,
|
||||
//超时
|
||||
timeout: 10000,
|
||||
});
|
||||
//发送json对象的拦截器
|
||||
jsonRequest.interceptors.request.use(config => {
|
||||
//是否需要设置 token
|
||||
const isToken = (config.headers || {}).isToken === false
|
||||
if (getToken() && !isToken) {
|
||||
config.headers[TokenName] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
}
|
||||
return config
|
||||
//是否需要设置 token
|
||||
const isToken = (config.headers || {}).isToken === false
|
||||
if (getToken() && !isToken) {
|
||||
config.headers[TokenName] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
}
|
||||
return config
|
||||
}, error => {
|
||||
console.log(error)
|
||||
Promise.reject(error)
|
||||
console.log(error)
|
||||
Promise.reject(error)
|
||||
})
|
||||
|
||||
// 响应拦截器
|
||||
jsonRequest.interceptors.response.use(res => {
|
||||
|
||||
const code = res.data.status || 200;
|
||||
if(code===200){
|
||||
return res.data
|
||||
}else{
|
||||
if(code === 401){
|
||||
store.dispatch('LogOut').then(() => {
|
||||
location.href = this.webBaseUrl + ReLoginUrl;
|
||||
})
|
||||
}else if(code===403){
|
||||
var msg='当前操作没有权限';
|
||||
Message({message: msg, type: 'error'});
|
||||
return Promise.reject(new Error(msg))
|
||||
}else{
|
||||
//Message({message: res.data.message, type: 'error'});
|
||||
//console.log('err:' + res.data.error);
|
||||
return res.data;
|
||||
//return Promise.reject(new Error(res.data.message))
|
||||
}
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log('err' + error)
|
||||
let { message } = error;
|
||||
if (message == "Network Error") {
|
||||
message = "网络异常,请稍后重试";
|
||||
}
|
||||
else if (message.includes("timeout")) {
|
||||
message = "系统接口请求超时";
|
||||
}
|
||||
else if (message.includes("Request failed with status code")) {
|
||||
message = "系统接口" + message.substr(message.length - 3) + "异常";
|
||||
}
|
||||
Message({
|
||||
message: message,
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
})
|
||||
return Promise.reject(error)
|
||||
}
|
||||
const code = res.data.status || 200;
|
||||
if (code === 200) {
|
||||
return res.data
|
||||
} else {
|
||||
if (code === 401) {
|
||||
store.dispatch('LogOut').then(() => {
|
||||
if (top !== window) { // 判断当前是否在iframe内
|
||||
top.location.href = this.webBaseUrl + ReLoginUrl;
|
||||
} else {
|
||||
window.location.href = this.webBaseUrl + ReLoginUrl;
|
||||
}
|
||||
// location.href = this.webBaseUrl + ReLoginUrl;
|
||||
})
|
||||
} else if (code === 403) {
|
||||
var msg = '当前操作没有权限';
|
||||
Message({ message: msg, type: 'error' });
|
||||
return Promise.reject(new Error(msg))
|
||||
} else {
|
||||
//Message({message: res.data.message, type: 'error'});
|
||||
//console.log('err:' + res.data.error);
|
||||
return res.data;
|
||||
//return Promise.reject(new Error(res.data.message))
|
||||
}
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log('err' + error)
|
||||
let { message } = error;
|
||||
if (message == "Network Error") {
|
||||
message = "网络异常,请稍后重试";
|
||||
}
|
||||
else if (message.includes("timeout")) {
|
||||
message = "系统接口请求超时";
|
||||
}
|
||||
else if (message.includes("Request failed with status code")) {
|
||||
message = "系统接口" + message.substr(message.length - 3) + "异常";
|
||||
}
|
||||
Message({
|
||||
message: message,
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
})
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
//用于普通的发送请求
|
||||
const formRequest=axios.create({
|
||||
headers:{'Content-Type':'application/x-www-form-urlencoded'},
|
||||
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
||||
baseURL: process.env.VUE_APP_CESOURCE_BASE_API,
|
||||
//超时
|
||||
timeout: 10000,
|
||||
const formRequest = axios.create({
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
||||
baseURL: process.env.VUE_APP_CESOURCE_BASE_API,
|
||||
//超时
|
||||
timeout: 10000,
|
||||
})
|
||||
//发送json对象的拦截器
|
||||
formRequest.interceptors.request.use(config => {
|
||||
//是否需要设置 token
|
||||
const isToken = (config.headers || {}).isToken === false
|
||||
if (getToken() && !isToken) {
|
||||
config.headers[TokenName] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
}
|
||||
return config
|
||||
//是否需要设置 token
|
||||
const isToken = (config.headers || {}).isToken === false
|
||||
if (getToken() && !isToken) {
|
||||
config.headers[TokenName] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
}
|
||||
return config
|
||||
}, error => {
|
||||
console.log(error)
|
||||
Promise.reject(error)
|
||||
console.log(error)
|
||||
Promise.reject(error)
|
||||
});
|
||||
formRequest.interceptors.response.use(res => {
|
||||
const code = res.data.status || 200;
|
||||
if(code===200){
|
||||
const code = res.data.status || 200;
|
||||
if (code === 200) {
|
||||
return res.data
|
||||
} else {
|
||||
if (code === 401) {
|
||||
store.dispatch('LogOut').then(() => {
|
||||
if (top !== window) { // 判断当前是否在iframe内
|
||||
top.location.href = this.webBaseUrl + ReLoginUrl;
|
||||
} else {
|
||||
window.location.href = this.webBaseUrl + ReLoginUrl;
|
||||
}
|
||||
// location.href = this.webBaseUrl + ReLoginUrl;
|
||||
})
|
||||
} else if (code === 403) {
|
||||
var msg = '当前操作没有权限';
|
||||
Message({ message: msg, type: 'error' });
|
||||
return Promise.reject(new Error(msg))
|
||||
} else {
|
||||
//Message({message: res.data.message, type: 'error'});
|
||||
//console.log('err' + res.data.error);
|
||||
return res.data
|
||||
}else{
|
||||
if(code === 401){
|
||||
store.dispatch('LogOut').then(() => {
|
||||
location.href = this.webBaseUrl + ReLoginUrl;
|
||||
})
|
||||
}else if(code===403){
|
||||
var msg='当前操作没有权限';
|
||||
Message({message: msg, type: 'error'});
|
||||
return Promise.reject(new Error(msg))
|
||||
}else{
|
||||
//Message({message: res.data.message, type: 'error'});
|
||||
//console.log('err' + res.data.error);
|
||||
return res.data
|
||||
}
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log('err' + error)
|
||||
let { message } = error;
|
||||
if (message == "Network Error") {
|
||||
message = "网络异常,请稍后重试";
|
||||
}
|
||||
else if (message.includes("timeout")) {
|
||||
message = "系统接口请求超时";
|
||||
}
|
||||
else if (message.includes("Request failed with status code")) {
|
||||
message = "系统接口" + message.substr(message.length - 3) + "异常";
|
||||
}
|
||||
Message({
|
||||
message: message,
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
})
|
||||
return Promise.reject(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log('err' + error)
|
||||
let { message } = error;
|
||||
if (message == "Network Error") {
|
||||
message = "网络异常,请稍后重试";
|
||||
}
|
||||
else if (message.includes("timeout")) {
|
||||
message = "系统接口请求超时";
|
||||
}
|
||||
else if (message.includes("Request failed with status code")) {
|
||||
message = "系统接口" + message.substr(message.length - 3) + "异常";
|
||||
}
|
||||
Message({
|
||||
message: message,
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
})
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
//request请求
|
||||
const request=function(cfg){
|
||||
if(cfg.data){
|
||||
cfg.data=qs.stringify(cfg.data);
|
||||
const request = function (cfg) {
|
||||
if (cfg.data) {
|
||||
cfg.data = qs.stringify(cfg.data);
|
||||
}
|
||||
};
|
||||
//requestJson请求
|
||||
const requestJson=jsonRequest.request;
|
||||
const requestJson = jsonRequest.request;
|
||||
//get请求
|
||||
const get=formRequest.request;
|
||||
const get = formRequest.request;
|
||||
//post请求
|
||||
const post=function(url,data,config){
|
||||
if(data){
|
||||
data=qs.stringify(data);
|
||||
const post = function (url, data, config) {
|
||||
if (data) {
|
||||
data = qs.stringify(data);
|
||||
}
|
||||
return formRequest.post(url,data,config);
|
||||
return formRequest.post(url, data, config);
|
||||
}
|
||||
//postJson请求
|
||||
const postJson=jsonRequest.post;
|
||||
const postJson = jsonRequest.post;
|
||||
//put请求
|
||||
const put=function(url,data,config){
|
||||
if(data){
|
||||
data=qs.stringify(data);
|
||||
const put = function (url, data, config) {
|
||||
if (data) {
|
||||
data = qs.stringify(data);
|
||||
}
|
||||
return formRequest.put(url,data,config);
|
||||
return formRequest.put(url, data, config);
|
||||
}
|
||||
//putJson请求
|
||||
const putJson=jsonRequest.put;
|
||||
const putJson = jsonRequest.put;
|
||||
//patch请求
|
||||
const patch=function(url,data,config){
|
||||
if(data){
|
||||
data=qs.stringify(data);
|
||||
const patch = function (url, data, config) {
|
||||
if (data) {
|
||||
data = qs.stringify(data);
|
||||
}
|
||||
return formRequest.patch(url,data,config);
|
||||
return formRequest.patch(url, data, config);
|
||||
}
|
||||
//patchJson请求
|
||||
const patchJson=jsonRequest.patch;
|
||||
const patchJson = jsonRequest.patch;
|
||||
//delete请求
|
||||
const del=formRequest.delete;
|
||||
const del = formRequest.delete;
|
||||
|
||||
|
||||
export default {
|
||||
request,
|
||||
requestJson,
|
||||
get,
|
||||
post,
|
||||
postJson,
|
||||
put,
|
||||
putJson,
|
||||
patch,
|
||||
patchJson,
|
||||
del
|
||||
request,
|
||||
requestJson,
|
||||
get,
|
||||
post,
|
||||
postJson,
|
||||
put,
|
||||
putJson,
|
||||
patch,
|
||||
patchJson,
|
||||
del
|
||||
}
|
||||
|
||||
@@ -17,185 +17,195 @@ import errorCode from '@/utils/errorCode'
|
||||
*delete请求 axios.delete(url[, config])
|
||||
*/
|
||||
|
||||
const ReLoginUrl="/login";
|
||||
const TokenName='XBOE-Access-Token';
|
||||
const ReLoginUrl = "/login";
|
||||
const TokenName = 'XBOE-Access-Token';
|
||||
/**axios.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded'**/
|
||||
//只是用于发送json对象数据时使用post,put,patch
|
||||
const jsonRequest=axios.create({
|
||||
headers:{'Content-Type':'application/json;charset=utf-8'},
|
||||
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
||||
baseURL: process.env.VUE_APP_STAT_BASE_API,
|
||||
//超时
|
||||
timeout: 10000,
|
||||
const jsonRequest = axios.create({
|
||||
headers: { 'Content-Type': 'application/json;charset=utf-8' },
|
||||
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
||||
baseURL: process.env.VUE_APP_STAT_BASE_API,
|
||||
//超时
|
||||
timeout: 10000,
|
||||
});
|
||||
//发送json对象的拦截器
|
||||
jsonRequest.interceptors.request.use(config => {
|
||||
//是否需要设置 token
|
||||
const isToken = (config.headers || {}).isToken === false
|
||||
if (getToken() && !isToken) {
|
||||
config.headers[TokenName] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
}
|
||||
return config
|
||||
//是否需要设置 token
|
||||
const isToken = (config.headers || {}).isToken === false
|
||||
if (getToken() && !isToken) {
|
||||
config.headers[TokenName] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
}
|
||||
return config
|
||||
}, error => {
|
||||
console.log(error)
|
||||
Promise.reject(error)
|
||||
console.log(error)
|
||||
Promise.reject(error)
|
||||
})
|
||||
|
||||
// 响应拦截器
|
||||
jsonRequest.interceptors.response.use(res => {
|
||||
|
||||
const code = res.data.status || 200;
|
||||
if(code===200){
|
||||
return res.data
|
||||
}else{
|
||||
if(code === 401){
|
||||
store.dispatch('LogOut').then(() => {
|
||||
location.href = this.webBaseUrl + ReLoginUrl;
|
||||
})
|
||||
}else if(code===403){
|
||||
var msg='当前操作没有权限';
|
||||
Message({message: msg, type: 'error'});
|
||||
return Promise.reject(new Error(msg))
|
||||
}else{
|
||||
//Message({message: res.data.message, type: 'error'});
|
||||
//console.log('err:' + res.data.error);
|
||||
return res.data;
|
||||
//return Promise.reject(new Error(res.data.message))
|
||||
}
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log('err' + error)
|
||||
let { message } = error;
|
||||
if (message == "Network Error") {
|
||||
message = "网络异常,请稍后重试";
|
||||
}
|
||||
else if (message.includes("timeout")) {
|
||||
message = "系统接口请求超时";
|
||||
}
|
||||
else if (message.includes("Request failed with status code")) {
|
||||
message = "系统接口" + message.substr(message.length - 3) + "异常";
|
||||
}
|
||||
Message({
|
||||
message: message,
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
})
|
||||
return Promise.reject(error)
|
||||
}
|
||||
const code = res.data.status || 200;
|
||||
if (code === 200) {
|
||||
return res.data
|
||||
} else {
|
||||
if (code === 401) {
|
||||
store.dispatch('LogOut').then(() => {
|
||||
if (top !== window) { // 判断当前是否在iframe内
|
||||
top.location.href = this.webBaseUrl + ReLoginUrl;
|
||||
} else {
|
||||
window.location.href = this.webBaseUrl + ReLoginUrl;
|
||||
}
|
||||
// location.href = this.webBaseUrl + ReLoginUrl;
|
||||
})
|
||||
} else if (code === 403) {
|
||||
var msg = '当前操作没有权限';
|
||||
Message({ message: msg, type: 'error' });
|
||||
return Promise.reject(new Error(msg))
|
||||
} else {
|
||||
//Message({message: res.data.message, type: 'error'});
|
||||
//console.log('err:' + res.data.error);
|
||||
return res.data;
|
||||
//return Promise.reject(new Error(res.data.message))
|
||||
}
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log('err' + error)
|
||||
let { message } = error;
|
||||
if (message == "Network Error") {
|
||||
message = "网络异常,请稍后重试";
|
||||
}
|
||||
else if (message.includes("timeout")) {
|
||||
message = "系统接口请求超时";
|
||||
}
|
||||
else if (message.includes("Request failed with status code")) {
|
||||
message = "系统接口" + message.substr(message.length - 3) + "异常";
|
||||
}
|
||||
Message({
|
||||
message: message,
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
})
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
//用于普通的发送请求
|
||||
const formRequest=axios.create({
|
||||
headers:{'Content-Type':'application/x-www-form-urlencoded'},
|
||||
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
||||
baseURL: process.env.VUE_APP_STAT_BASE_API,
|
||||
//超时
|
||||
timeout: 10000,
|
||||
const formRequest = axios.create({
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
||||
baseURL: process.env.VUE_APP_STAT_BASE_API,
|
||||
//超时
|
||||
timeout: 10000,
|
||||
})
|
||||
//发送json对象的拦截器
|
||||
formRequest.interceptors.request.use(config => {
|
||||
//是否需要设置 token
|
||||
const isToken = (config.headers || {}).isToken === false
|
||||
if (getToken() && !isToken) {
|
||||
config.headers[TokenName] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
}
|
||||
return config
|
||||
//是否需要设置 token
|
||||
const isToken = (config.headers || {}).isToken === false
|
||||
if (getToken() && !isToken) {
|
||||
config.headers[TokenName] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
}
|
||||
return config
|
||||
}, error => {
|
||||
console.log(error)
|
||||
Promise.reject(error)
|
||||
console.log(error)
|
||||
Promise.reject(error)
|
||||
});
|
||||
formRequest.interceptors.response.use(res => {
|
||||
const code = res.data.status || 200;
|
||||
if(code===200){
|
||||
const code = res.data.status || 200;
|
||||
if (code === 200) {
|
||||
return res.data
|
||||
} else {
|
||||
if (code === 401) {
|
||||
store.dispatch('LogOut').then(() => {
|
||||
if (top !== window) { // 判断当前是否在iframe内
|
||||
top.location.href = this.webBaseUrl + ReLoginUrl;
|
||||
} else {
|
||||
window.location.href = this.webBaseUrl + ReLoginUrl;
|
||||
}
|
||||
// location.href = this.webBaseUrl + ReLoginUrl;
|
||||
})
|
||||
} else if (code === 403) {
|
||||
var msg = '当前操作没有权限';
|
||||
Message({ message: msg, type: 'error' });
|
||||
return Promise.reject(new Error(msg))
|
||||
} else {
|
||||
//Message({message: res.data.message, type: 'error'});
|
||||
//console.log('err' + res.data.error);
|
||||
return res.data
|
||||
}else{
|
||||
if(code === 401){
|
||||
store.dispatch('LogOut').then(() => {
|
||||
location.href = this.webBaseUrl + ReLoginUrl;
|
||||
})
|
||||
}else if(code===403){
|
||||
var msg='当前操作没有权限';
|
||||
Message({message: msg, type: 'error'});
|
||||
return Promise.reject(new Error(msg))
|
||||
}else{
|
||||
//Message({message: res.data.message, type: 'error'});
|
||||
//console.log('err' + res.data.error);
|
||||
return res.data
|
||||
}
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log('err' + error)
|
||||
let { message } = error;
|
||||
if (message == "Network Error") {
|
||||
message = "网络异常,请稍后重试";
|
||||
}
|
||||
else if (message.includes("timeout")) {
|
||||
message = "系统接口请求超时";
|
||||
}
|
||||
else if (message.includes("Request failed with status code")) {
|
||||
message = "系统接口" + message.substr(message.length - 3) + "异常";
|
||||
}
|
||||
Message({
|
||||
message: message,
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
})
|
||||
return Promise.reject(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log('err' + error)
|
||||
let { message } = error;
|
||||
if (message == "Network Error") {
|
||||
message = "网络异常,请稍后重试";
|
||||
}
|
||||
else if (message.includes("timeout")) {
|
||||
message = "系统接口请求超时";
|
||||
}
|
||||
else if (message.includes("Request failed with status code")) {
|
||||
message = "系统接口" + message.substr(message.length - 3) + "异常";
|
||||
}
|
||||
Message({
|
||||
message: message,
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
})
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
//request请求
|
||||
const request=function(cfg){
|
||||
if(cfg.data){
|
||||
cfg.data=qs.stringify(cfg.data);
|
||||
const request = function (cfg) {
|
||||
if (cfg.data) {
|
||||
cfg.data = qs.stringify(cfg.data);
|
||||
}
|
||||
};
|
||||
//requestJson请求
|
||||
const requestJson=jsonRequest.request;
|
||||
const requestJson = jsonRequest.request;
|
||||
//get请求
|
||||
const get=formRequest.request;
|
||||
const get = formRequest.request;
|
||||
//post请求
|
||||
const post=function(url,data,config){
|
||||
if(data){
|
||||
data=qs.stringify(data);
|
||||
const post = function (url, data, config) {
|
||||
if (data) {
|
||||
data = qs.stringify(data);
|
||||
}
|
||||
return formRequest.post(url,data,config);
|
||||
return formRequest.post(url, data, config);
|
||||
}
|
||||
//postJson请求
|
||||
const postJson=jsonRequest.post;
|
||||
const postJson = jsonRequest.post;
|
||||
//put请求
|
||||
const put=function(url,data,config){
|
||||
if(data){
|
||||
data=qs.stringify(data);
|
||||
const put = function (url, data, config) {
|
||||
if (data) {
|
||||
data = qs.stringify(data);
|
||||
}
|
||||
return formRequest.put(url,data,config);
|
||||
return formRequest.put(url, data, config);
|
||||
}
|
||||
//putJson请求
|
||||
const putJson=jsonRequest.put;
|
||||
const putJson = jsonRequest.put;
|
||||
//patch请求
|
||||
const patch=function(url,data,config){
|
||||
if(data){
|
||||
data=qs.stringify(data);
|
||||
const patch = function (url, data, config) {
|
||||
if (data) {
|
||||
data = qs.stringify(data);
|
||||
}
|
||||
return formRequest.patch(url,data,config);
|
||||
return formRequest.patch(url, data, config);
|
||||
}
|
||||
//patchJson请求
|
||||
const patchJson=jsonRequest.patch;
|
||||
const patchJson = jsonRequest.patch;
|
||||
//delete请求
|
||||
const del=formRequest.delete;
|
||||
const del = formRequest.delete;
|
||||
|
||||
|
||||
export default {
|
||||
request,
|
||||
requestJson,
|
||||
get,
|
||||
post,
|
||||
postJson,
|
||||
put,
|
||||
putJson,
|
||||
patch,
|
||||
patchJson,
|
||||
del
|
||||
request,
|
||||
requestJson,
|
||||
get,
|
||||
post,
|
||||
postJson,
|
||||
put,
|
||||
putJson,
|
||||
patch,
|
||||
patchJson,
|
||||
del
|
||||
}
|
||||
|
||||
@@ -440,6 +440,12 @@ const queryCrowd=function(query){
|
||||
const ids=function (data){
|
||||
return ajax.postJson('/xboe/m/course/manage/ids',data);
|
||||
}
|
||||
|
||||
const saveTip = function() {
|
||||
return ajax.postJson('/xboe/m/course/manage/saveTip');
|
||||
}
|
||||
|
||||
|
||||
export default {
|
||||
saveBase,
|
||||
submitCourse,
|
||||
@@ -482,6 +488,7 @@ export default {
|
||||
exportCourseAudit,
|
||||
exportCourse,
|
||||
queryCrowd,
|
||||
ids
|
||||
ids,
|
||||
saveTip
|
||||
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ const pageList = function(data) {
|
||||
|
||||
/**
|
||||
* 选择课件的查询,这里也是分页查询,只是返回的内容,字段会很少,用于课件制作那选择已有课件内容。
|
||||
*
|
||||
*
|
||||
* @param {Object} data
|
||||
* 查询参数如上面pageList方法
|
||||
*/
|
||||
@@ -47,7 +47,9 @@ const findList = function(data) {
|
||||
}
|
||||
*/
|
||||
const saveUpload = function(data) {
|
||||
return ajax.post('/xboe/m/course/file/upload/save', data);
|
||||
return ajax.post('/xboe/m/course/file/upload/save', data, {
|
||||
timeout: 60000
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,4 +90,4 @@ export default {
|
||||
batchUpdate,
|
||||
detail,
|
||||
delFile
|
||||
}
|
||||
}
|
||||
|
||||
64
src/api/modules/courseTag.js
Normal file
64
src/api/modules/courseTag.js
Normal file
@@ -0,0 +1,64 @@
|
||||
/**课程标签模块的相关处理*/
|
||||
import ajax from '@/utils/xajax.js'
|
||||
|
||||
/**
|
||||
* 分页查询:标签列表
|
||||
* @param {Object} query
|
||||
*/
|
||||
const portalPageList = function(query) {
|
||||
return ajax.post('/xboe/m/coursetag/page', query);
|
||||
}
|
||||
|
||||
//改变标签的公共属性
|
||||
const changeTagPublic = function (row){
|
||||
// 返回 Promise 的 API 调用
|
||||
return ajax.post('/xboe/m/coursetag/changePublicStatus', {
|
||||
id: row.id,
|
||||
isPublic: row.isPublic
|
||||
});
|
||||
}
|
||||
|
||||
//改变标签的热点属性
|
||||
const changeTagHot = function (row){
|
||||
// 返回 Promise 的 API 调用
|
||||
return ajax.post('/xboe/m/coursetag/changeHotStatus', {
|
||||
id: row.id,
|
||||
isHot: row.isHot
|
||||
});
|
||||
}
|
||||
|
||||
//查询指定id的标签关联的所有课程
|
||||
const showCourseByTag = function (query){
|
||||
return ajax.post('/xboe/m/coursetag/showCourseByTag', query);
|
||||
}
|
||||
|
||||
//解除指定id的课程和某个标签之间的关联关系
|
||||
const unbindCourseTagRelation = function (params){
|
||||
return ajax.post('/xboe/m/coursetag/unbind', params);
|
||||
}
|
||||
|
||||
//编辑课程:标签模糊查询
|
||||
const searchTags = function (params){
|
||||
return ajax.post('/xboe/m/coursetag/searchTags', params);
|
||||
}
|
||||
|
||||
//编辑课程:创建标签(与当前课程关联)
|
||||
const createTag = function (params){
|
||||
return ajax.post('/xboe/m/coursetag/createTag', params);
|
||||
}
|
||||
|
||||
//获取最新前10个热点标签
|
||||
const getHotTagList = function (params){
|
||||
return ajax.post('/xboe/m/coursetag/getHotTagList', params);
|
||||
}
|
||||
|
||||
export default {
|
||||
portalPageList,
|
||||
changeTagPublic,
|
||||
changeTagHot,
|
||||
showCourseByTag,
|
||||
unbindCourseTagRelation,
|
||||
searchTags,
|
||||
createTag,
|
||||
getHotTagList
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 46 KiB |
BIN
src/assets/images/project/title-bg.png
Normal file
BIN
src/assets/images/project/title-bg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
@@ -50,7 +50,7 @@
|
||||
<el-input-number v-model="duration" size="mini" :min="1" :max="100"></el-input-number>
|
||||
</span>
|
||||
</div>
|
||||
<el-upload class="upload-demo" :headers="headers" :data="data" drag :action="uploadFileUrl" :on-success="handleUploadSuccess" :before-upload="handleBeforeUpload">
|
||||
<el-upload ref="uploadRef" class="upload-demo" :headers="headers" :data="data" drag :action="uploadFileUrl" :on-success="handleUploadSuccess" :before-upload="handleBeforeUpload">
|
||||
<i class="el-icon-upload"></i>
|
||||
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
|
||||
<div class="el-upload__tip" slot="tip">文件大小限制:{{curComType.maxSizeName}},支持的文件类型:{{curComType.fileTypes.join(',')}}</div>
|
||||
@@ -195,6 +195,7 @@
|
||||
// this.cware.content.content=result.filePath;
|
||||
}else{
|
||||
this.$message.error(rs.message);
|
||||
this.$refs.uploadRef.clearFiles();
|
||||
}
|
||||
});
|
||||
}else{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
400
src/components/Course/courseTag.vue
Normal file
400
src/components/Course/courseTag.vue
Normal file
@@ -0,0 +1,400 @@
|
||||
<template>
|
||||
<div class="tag-container" @click="handleContainerClick">
|
||||
<el-select style="width: 100%;"
|
||||
v-model="selectedTags"
|
||||
multiple
|
||||
filterable
|
||||
value-key="id"
|
||||
remote
|
||||
reserve-keyword
|
||||
:remote-method="debouncedSearch"
|
||||
:loading="loading"
|
||||
:placeholder="'回车创建新标签'"
|
||||
:no-data-text="'无此标签,按回车键创建'"
|
||||
@remove-tag="handleTagRemove"
|
||||
@change="handleSelectionChange"
|
||||
@keyup.enter.native="handleEnterKey"
|
||||
@keyup.delete.native="handleDeleteKey"
|
||||
@focus="handleFocus"
|
||||
ref="tagSelect"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in searchResults"
|
||||
:key="item.id"
|
||||
:label="item.tagName"
|
||||
:value="item"
|
||||
:disabled="isTagDisabled(item)"
|
||||
/>
|
||||
</el-select>
|
||||
<!-- 添加标签计数显示 -->
|
||||
<div class="tag-count">
|
||||
{{ selectedTags.length }}/5
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { debounce } from 'lodash'
|
||||
import apiCourseTag from '@/api/modules/courseTag.js'
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
courseId:{
|
||||
type:String,
|
||||
require:true,
|
||||
},
|
||||
sysTypeList:{
|
||||
type:Array,
|
||||
require:true,
|
||||
default: []
|
||||
},
|
||||
maxTags: {
|
||||
type: Number,
|
||||
default: 5
|
||||
},
|
||||
// 添加:接收初始标签数据的props
|
||||
initialTags: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectedTags: [],
|
||||
searchResults: [],
|
||||
loading: false,
|
||||
tagMap: new Map(),
|
||||
inputBuffer: '',
|
||||
params: {},
|
||||
tag: {},
|
||||
// 添加临时存储用于回滚
|
||||
previousTags: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['userInfo']),
|
||||
displayTags() {
|
||||
return this.selectedTags.map(tag =>
|
||||
typeof tag === 'object' ? tag : this.tagMap.get(tag)
|
||||
).filter(Boolean)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.debouncedSearch = debounce(this.doSearch, 500)
|
||||
console.log("----------sysTypeList.length---------->"+this.sysTypeList.length)
|
||||
console.log("----------sysTypeList.length---------->"+(this.sysTypeList.length===0))
|
||||
},
|
||||
// 添加:挂载时初始化标签数据
|
||||
mounted() {
|
||||
if (this.initialTags && this.initialTags.length > 0) {
|
||||
this.selectedTags = this.initialTags;
|
||||
this.searchResults = this.initialTags;
|
||||
// 将初始标签添加到tagMap中,确保删除功能正常
|
||||
this.initialTags.forEach(tag => {
|
||||
if (tag.id) {
|
||||
this.tagMap.set(tag.id, tag);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// 监听课程ID变化,重置所有状态
|
||||
courseId(newVal) {
|
||||
this.resetTagState();
|
||||
},
|
||||
// 监听初始标签变化,重新加载
|
||||
initialTags(newVal) {
|
||||
this.selectedTags = newVal || [];
|
||||
this.searchResults = newVal || [];
|
||||
this.tagMap.clear(); // 清空旧缓存
|
||||
newVal.forEach(tag => {
|
||||
if (tag.id) this.tagMap.set(tag.id, tag);
|
||||
});
|
||||
},
|
||||
// 监听分类变化,重新加载搜索结果
|
||||
sysTypeList: {
|
||||
handler() {
|
||||
// 只有在已选择分类且有焦点时才重新加载
|
||||
if (this.sysTypeList.length > 0 && this.$refs.tagSelect && this.$refs.tagSelect.visible) {
|
||||
this.doSearch('');
|
||||
}
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 新增:检查标签是否应该被禁用
|
||||
isTagDisabled(tag) {
|
||||
// 如果标签已经被选中,不应该禁用(允许取消选择)
|
||||
const isSelected = this.selectedTags.some(selectedTag => selectedTag.id === tag.id);
|
||||
if (isSelected) {
|
||||
return false;
|
||||
}
|
||||
// 如果标签未被选中且已达到最大数量,则禁用
|
||||
return this.selectedTags.length >= this.maxTags;
|
||||
},
|
||||
// 新增:处理输入框获得焦点事件
|
||||
async handleFocus() {
|
||||
this.previousTags = [...this.selectedTags];
|
||||
// 当输入框获得焦点时,加载默认的搜索结果
|
||||
if (this.sysTypeList.length > 0) {
|
||||
await this.doSearch('');
|
||||
}
|
||||
this.$emit('focus');
|
||||
},
|
||||
handleContainerClick() {
|
||||
// 容器点击时也触发焦点事件
|
||||
this.$emit('focus');
|
||||
},
|
||||
// 新增:重置标签状态的方法
|
||||
resetTagState() {
|
||||
this.selectedTags = [];
|
||||
this.searchResults = [];
|
||||
this.tagMap.clear();
|
||||
this.loading = false;
|
||||
this.params = {};
|
||||
},
|
||||
handleTagRemove(tagId) {
|
||||
this.selectedTags = this.selectedTags.filter(id => id !== tagId)
|
||||
this.$emit('change', this.displayTags)
|
||||
this.clearInput();
|
||||
},
|
||||
removeTag(tagId) {
|
||||
this.handleTagRemove(tagId)
|
||||
},
|
||||
|
||||
// 新增:处理删除键事件
|
||||
handleDeleteKey(event) {
|
||||
// 如果输入框内容为空,不执行任何搜索
|
||||
if (!event.target.value.trim()) {
|
||||
this.searchResults = []
|
||||
}
|
||||
},
|
||||
|
||||
//按回车键,创建新标签
|
||||
handleEnterKey(event) {
|
||||
const inputVal = event.target.value?.trim()
|
||||
if (!inputVal) return;
|
||||
// 检查是否与已选择的标签重复
|
||||
const isDuplicate = this.selectedTags.some(tag => tag.tagName === inputVal);
|
||||
if (isDuplicate) {
|
||||
this.$message.warning('该标签已存在,无需重复创建');
|
||||
event.target.value = '';
|
||||
return;
|
||||
}
|
||||
if (!isDuplicate && inputVal && this.selectedTags.length < this.maxTags) {
|
||||
this.createNewTag(event.target.value.trim())
|
||||
this.clearInput();
|
||||
} else if (this.selectedTags.length >= this.maxTags) {
|
||||
this.$message.warning('最多只能添加5个标签')
|
||||
this.clearInput();
|
||||
} else {
|
||||
this.clearInput();
|
||||
}
|
||||
},
|
||||
|
||||
// 新增:处理选择变化事件
|
||||
handleSelectionChange(newValues) {
|
||||
|
||||
// 检查每个标签对象是否完整
|
||||
newValues.forEach((tag, index) => {
|
||||
if (!tag.tagName) {
|
||||
console.error(`第${index}个标签缺少tagName:`, tag);
|
||||
}
|
||||
});
|
||||
|
||||
// 检查数量限制
|
||||
if (newValues.length > this.maxTags) {
|
||||
this.$message.warning(`最多只能选择${this.maxTags}个标签`);
|
||||
// 回滚到之前的状态
|
||||
this.selectedTags = [...this.previousTags];
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新前保存当前状态
|
||||
this.previousTags = [...newValues];
|
||||
this.$emit('change', this.displayTags);
|
||||
|
||||
this.clearInput();
|
||||
this.$nextTick(() => {
|
||||
this.$refs.tagSelect.visible = false;
|
||||
});
|
||||
},
|
||||
|
||||
clearInput() {
|
||||
if (this.$refs.tagSelect) {
|
||||
const input = this.$refs.tagSelect.$refs.input;
|
||||
if (input) {
|
||||
input.value = '';
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
//创建新标签
|
||||
async createNewTag(tagName) {
|
||||
// 标签不能超过八个字
|
||||
if (tagName.length > 8) {
|
||||
this.$message.error('标签不能超过8个字')
|
||||
return;
|
||||
}
|
||||
// 检查标签是否在下拉框中已存在
|
||||
const isExistInSearch = this.searchResults.some(tag => tag.tagName === tagName);
|
||||
if (isExistInSearch) {
|
||||
this.$message.warning('已存在此标签,请选择');
|
||||
return;
|
||||
}
|
||||
// 首先检查是否与已选择的标签重复
|
||||
const isDuplicate = this.selectedTags.some(tag => tag.tagName === tagName);
|
||||
if (isDuplicate) {
|
||||
this.$message.warning('该标签已存在,无需重复创建');
|
||||
return;
|
||||
}
|
||||
// 标签格式验证:仅支持中文、英文、数字、下划线、中横线
|
||||
const tagPattern = /^[\u4e00-\u9fa5a-zA-Z0-9_-]+$/;
|
||||
if (!tagPattern.test(tagName)) {
|
||||
this.$message.error('标签名称仅支持中文、英文、数字、下划线(_)和中横线(-),不支持空格、点和特殊字符');
|
||||
return;
|
||||
}
|
||||
// 添加标签数量限制检查
|
||||
if (this.selectedTags.length >= this.maxTags) {
|
||||
this.$message.warning('最多只能添加5个标签')
|
||||
return;
|
||||
}
|
||||
this.loading = true
|
||||
try {
|
||||
this.params.courseId = this.courseId;
|
||||
this.params.tagName = tagName;
|
||||
// 分类
|
||||
if (this.sysTypeList.length > 0) {
|
||||
this.params.sysType1 = this.sysTypeList[0]; //一级的id
|
||||
}
|
||||
if (this.sysTypeList.length > 1) {
|
||||
this.params.sysType2 = this.sysTypeList[1]; //二级的id
|
||||
}
|
||||
if (this.sysTypeList.length > 2) {
|
||||
this.params.sysType3 = this.sysTypeList[2]; //三级的id
|
||||
}
|
||||
const {result:newTag} = await apiCourseTag.createTag(this.params)
|
||||
this.$message.success('标签创建成功',newTag);
|
||||
|
||||
this.selectedTags = [...this.selectedTags, newTag];
|
||||
// 更新搜索结果的逻辑保持不变
|
||||
this.searchResults = [newTag, ...this.searchResults];
|
||||
this.tagMap.set(newTag.id, newTag)
|
||||
this.$emit('change', this.displayTags)
|
||||
|
||||
this.$nextTick(() => {
|
||||
// 强制重新设置selectedTags来触发更新
|
||||
const tempTags = [...this.selectedTags];
|
||||
this.selectedTags = [];
|
||||
this.$nextTick(() => {
|
||||
this.selectedTags = tempTags;
|
||||
});
|
||||
this.$refs.tagSelect.visible = false;
|
||||
});
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
// 修改doSearch方法,添加搜索结果为空时的提示
|
||||
async doSearch(query) {
|
||||
// 不再在空查询时清空搜索结果
|
||||
// if (!query.trim()) {
|
||||
// this.searchResults = []
|
||||
// return
|
||||
// }
|
||||
console.log("---- doSearch ------ query = " + query )
|
||||
this.loading = true
|
||||
try {
|
||||
// 获取 typeId:取 sysTypeList 最后一个有效的值
|
||||
const typeId = this.sysTypeList.length > 2 ? this.sysTypeList[2] :
|
||||
this.sysTypeList.length > 1 ? this.sysTypeList[1] :
|
||||
this.sysTypeList.length > 0 ? this.sysTypeList[0] : null;
|
||||
console.log("---- doSearch searchTags ------ query = " + query + " , typeId = " + typeId )
|
||||
const {result:tags} = await apiCourseTag.searchTags({tagName:query,typeId:typeId})
|
||||
console.log("-- searchTags 查询结果 tags = " + tags )
|
||||
|
||||
tags.forEach(item => {
|
||||
this.tagMap.set(item.id, item)
|
||||
})
|
||||
this.searchResults = tags
|
||||
// 当搜索结果为空时,提示用户可以按回车键创建标签
|
||||
if (tags.length === 0) {
|
||||
// this.$message.info('无此标签,按回车键创建')
|
||||
}
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tag-container {
|
||||
position: relative;
|
||||
}
|
||||
.tag-preview {
|
||||
margin-top: 8px;
|
||||
}
|
||||
.el-tag {
|
||||
margin-right: 6px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
/* 添加标签计数样式 */
|
||||
.tag-count {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 47%;
|
||||
transform: translateY(-40%);
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
background: white;
|
||||
padding: 0 5px;
|
||||
pointer-events: none;
|
||||
/* 添加高度限制 */
|
||||
height: 25px;
|
||||
line-height: 25px; /* 垂直居中文字 */
|
||||
box-sizing: border-box; /* 确保padding包含在height内 */
|
||||
}
|
||||
|
||||
|
||||
|
||||
::v-deep(.el-select__tags) {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
/*
|
||||
::v-deep(.el-tag) {
|
||||
flex: 0 0 calc(50% - 8px);
|
||||
max-width: calc(50% - 8px);
|
||||
box-sizing: border-box;
|
||||
margin-right: 8px;
|
||||
margin-bottom: 4px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}*/
|
||||
|
||||
::v-deep(.el-tag) {
|
||||
flex: 1 1 auto; /* 自动调整宽度 */
|
||||
min-width: 30%; /* 设置最小宽度 */
|
||||
max-width: 48%; /* 设置最大宽度,留出边距 */
|
||||
box-sizing: border-box;
|
||||
margin-right: 8px;
|
||||
margin-bottom: 4px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
::v-deep(.el-select__input) {
|
||||
flex: 1;
|
||||
min-width: 60px;
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
<script setup>
|
||||
<script>
|
||||
import {getCertificationProcess} from "@/api/modules/lecturer";
|
||||
|
||||
export default {
|
||||
|
||||
@@ -128,7 +128,8 @@ export const iframes=[
|
||||
{title:'查看受众', path:'/iframe/ugroup/view',hidden:false,component:'manage/AudienceView'},
|
||||
{title:'问答管理', path:'/iframe/qa/manages',hidden:false,component:'qa/ManageList'},
|
||||
{title:'待审核课程', path:'/iframe/course/noapproved',hidden:false,component:'examine/NotApproved'},
|
||||
{title:'已审核课程', path:'/iframe/course/reviewed',hidden:false,component:'examine/Reviewed'}
|
||||
{title:'已审核课程', path:'/iframe/course/reviewed',hidden:false,component:'examine/Reviewed'},
|
||||
{title:'标签管理', path:'/iframe/tag/manages',hidden:false,component:'tag/TagManageList'},
|
||||
|
||||
]
|
||||
|
||||
|
||||
16
src/main.js
16
src/main.js
@@ -3,6 +3,22 @@ import App from './App.vue'
|
||||
import router from './router'
|
||||
import store from './store'
|
||||
|
||||
import vueKatexEs from "vue-katex";
|
||||
import "katex/dist/katex.min.css"
|
||||
|
||||
|
||||
Vue.use(vueKatexEs,{
|
||||
globalOptions:{
|
||||
delimiters:[
|
||||
{left:"$$",right:"$$",display:true},
|
||||
{left:"$",right:"$",display:false},
|
||||
{left:"\\[",right:"\\]",display:true},
|
||||
{left:"\\(",right:"\\)",display:false}
|
||||
],
|
||||
throwOnError:true
|
||||
}
|
||||
})
|
||||
|
||||
//import './mock/index'
|
||||
|
||||
import xpage from '@/utils/xpage'
|
||||
|
||||
109
src/security.js
109
src/security.js
@@ -11,16 +11,16 @@ import xpage from '@/utils/xpage'
|
||||
|
||||
NProgress.configure({ showSpinner: false })
|
||||
|
||||
const whiteList = ['/login','/logout','/loading','/pc/loading','/500','/auth-redirect','/forget','/reset/password']
|
||||
const whiteList = ['/login', '/logout', '/loading', '/pc/loading', '/500', '/auth-redirect', '/forget', '/reset/password']
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
watermark.set("");
|
||||
//动态计算文件的路径
|
||||
let configPath=process.env.VUE_APP_FILE_RELATIVE_PATH;
|
||||
if(configPath.startsWith('http')){
|
||||
xpage.constants.fileBaseUrl=configPath;
|
||||
}else{
|
||||
xpage.constants.fileBaseUrl=window.location.protocol+'//'+window.location.host+configPath;
|
||||
let configPath = process.env.VUE_APP_FILE_RELATIVE_PATH;
|
||||
if (configPath.startsWith('http')) {
|
||||
xpage.constants.fileBaseUrl = configPath;
|
||||
} else {
|
||||
xpage.constants.fileBaseUrl = window.location.protocol + '//' + window.location.host + configPath;
|
||||
}
|
||||
|
||||
NProgress.start();
|
||||
@@ -28,66 +28,71 @@ router.beforeEach((to, from, next) => {
|
||||
if (whiteList.indexOf(to.path) !== -1) {
|
||||
// 在免登录白名单,直接进入
|
||||
next()
|
||||
}else{
|
||||
if(getToken()){
|
||||
if(to.path === '/login'){
|
||||
} else {
|
||||
if (getToken()) {
|
||||
if (to.path === '/login') {
|
||||
// 如果是外部用户,把配置的路由跳转到个人中心
|
||||
if(store.getters.userInfo.role === 2){
|
||||
next({ path: process.env.VUE_APP_PUBLIC_PATH+'/uc/study/courses' })
|
||||
}else{
|
||||
next({ path: process.env.VUE_APP_PUBLIC_PATH+'/index' })
|
||||
if (store.getters.userInfo.role === 2) {
|
||||
next({ path: process.env.VUE_APP_PUBLIC_PATH + '/uc/study/courses' })
|
||||
} else {
|
||||
next({ path: process.env.VUE_APP_PUBLIC_PATH + '/index' })
|
||||
}
|
||||
NProgress.done();
|
||||
} else {
|
||||
//console.log('store.getters.userInfo:',store.getters.userInfo.role)
|
||||
// 如果是外部用户,把配置的路由跳转到个人中心
|
||||
if(store.getters.userInfo.role === 2){
|
||||
if(to.path === '/index' || to.path === '/course' || to.path === '/case' || to.path === '/article' ) location.href = '/pc/uc/study/task'
|
||||
if (store.getters.userInfo.role === 2) {
|
||||
if (to.path === '/index' || to.path === '/course' || to.path === '/case' || to.path === '/article') location.href = '/pc/uc/study/task'
|
||||
}
|
||||
//后续这里需要增加一定的控制
|
||||
if (!store.getters.init) {
|
||||
sessionStorage.removeItem(xpage.constants.localCaseFiltersKey);
|
||||
sessionStorage.removeItem(xpage.constants.localCourseFiltersKey);
|
||||
// 判断当前控制台是否已拉取完数据
|
||||
store.dispatch('InitData').then(res => {
|
||||
//加载白名单信息
|
||||
//testUser.init();
|
||||
//加载信息资源归属,系统分类信息
|
||||
store.dispatch('resOwner/loadResOwners');
|
||||
store.dispatch('sysType/loadSysTypes');
|
||||
if (!store.getters.init) {
|
||||
sessionStorage.removeItem(xpage.constants.localCaseFiltersKey);
|
||||
sessionStorage.removeItem(xpage.constants.localCourseFiltersKey);
|
||||
// 判断当前控制台是否已拉取完数据
|
||||
store.dispatch('InitData').then(res => {
|
||||
//加载白名单信息
|
||||
//testUser.init();
|
||||
//加载信息资源归属,系统分类信息
|
||||
store.dispatch('resOwner/loadResOwners');
|
||||
store.dispatch('sysType/loadSysTypes');
|
||||
|
||||
store.commit('app/SET_INITDATA',true);
|
||||
//routers数据先使用固定的,以后在初始化接口中返回
|
||||
let myRouters=routers();
|
||||
store.dispatch('GenerateRoutes',{routers:myRouters}).then(accessRoutes=>{
|
||||
router.addRoutes(accessRoutes) // 动态添加可访问路由表
|
||||
next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
|
||||
});
|
||||
store.commit('app/SET_INITDATA', true);
|
||||
//routers数据先使用固定的,以后在初始化接口中返回
|
||||
let myRouters = routers();
|
||||
store.dispatch('GenerateRoutes', { routers: myRouters }).then(accessRoutes => {
|
||||
router.addRoutes(accessRoutes) // 动态添加可访问路由表
|
||||
next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
|
||||
});
|
||||
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
store.commit('app/SET_INITDATA',false);
|
||||
//如果初始化错误,就不再执行了,不然会一直循环下去
|
||||
next({ path: '/500' })
|
||||
//NProgress.done();
|
||||
})
|
||||
} else {
|
||||
to.meta.keepAlive = true
|
||||
next();
|
||||
}
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
store.commit('app/SET_INITDATA', false);
|
||||
//如果初始化错误,就不再执行了,不然会一直循环下去
|
||||
next({ path: '/500' })
|
||||
//NProgress.done();
|
||||
})
|
||||
} else {
|
||||
to.meta.keepAlive = true
|
||||
next();
|
||||
}
|
||||
|
||||
}
|
||||
//next();
|
||||
}else{
|
||||
} else {
|
||||
|
||||
//next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页
|
||||
//设置之前的路径
|
||||
//store.commit('portal/SetBackUrl',location.href);
|
||||
//console.log(location.href,'location.href');
|
||||
//let urlPre=window.location.protocol+'//'+window.location.host;
|
||||
//let backUrl=location.href.substring(urlPre.length); encodeURIComponent()
|
||||
location.href=process.env.VUE_APP_LOGIN_URL+"?returnUrl="+encodeURIComponent(location.href);
|
||||
NProgress.done()
|
||||
//next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页
|
||||
//设置之前的路径
|
||||
//store.commit('portal/SetBackUrl',location.href);
|
||||
//console.log(location.href,'location.href');
|
||||
//let urlPre=window.location.protocol+'//'+window.location.host;
|
||||
//let backUrl=location.href.substring(urlPre.length); encodeURIComponent()
|
||||
if (top !== window) { // 判断当前是否在iframe内
|
||||
top.location.href = process.env.VUE_APP_LOGIN_URL + "?returnUrl=" + encodeURIComponent(location.href);
|
||||
} else {
|
||||
window.location.href = process.env.VUE_APP_LOGIN_URL + "?returnUrl=" + encodeURIComponent(location.href);
|
||||
}
|
||||
// location.href=process.env.VUE_APP_LOGIN_URL+"?returnUrl="+encodeURIComponent(location.href);
|
||||
NProgress.done()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,11 @@ const state = {
|
||||
withoutAnimation: false
|
||||
},
|
||||
device: 'desktop',//默认是桌面,以后会有android,ios,minapp
|
||||
size: Cookies.get('size') || 'medium' //字段大小
|
||||
size: Cookies.get('size') || 'medium', //字段大小
|
||||
// 添加AI Call组件显示控制状态
|
||||
showAICall: false,
|
||||
// 控制AI Call最小化窗口在特定路由下显示的状态
|
||||
showAICallMinimized: false
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
@@ -34,6 +38,14 @@ const mutations = {
|
||||
SET_SIZE: (state, size) => {
|
||||
state.size = size
|
||||
Cookies.set('size', size)
|
||||
},
|
||||
// 添加控制AI Call组件显示的mutation
|
||||
SET_SHOW_AI_CALL: (state, show) => {
|
||||
state.showAICall = show
|
||||
},
|
||||
// 控制AI Call最小化窗口显示的mutation
|
||||
SET_SHOW_AI_CALL_MINIMIZED: (state, show) => {
|
||||
state.showAICallMinimized = show
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +61,14 @@ const actions = {
|
||||
},
|
||||
setSize({ commit }, size) {
|
||||
commit('SET_SIZE', size)
|
||||
},
|
||||
// 添加控制AI Call组件显示的action
|
||||
setShowAICall({ commit }, show) {
|
||||
commit('SET_SHOW_AI_CALL', show)
|
||||
},
|
||||
// 控制AI Call最小化窗口显示的action
|
||||
setShowAICallMinimized({ commit }, show) {
|
||||
commit('SET_SHOW_AI_CALL_MINIMIZED', show)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,4 +77,4 @@ export default {
|
||||
state,
|
||||
mutations,
|
||||
actions
|
||||
}
|
||||
}
|
||||
@@ -19,215 +19,255 @@ import errorCode from '@/utils/errorCode'
|
||||
|
||||
//const ReLoginUrl="/login";
|
||||
|
||||
const ReLoginUrl=process.env.VUE_APP_LOGIN_URL;
|
||||
const ReLoginUrl = process.env.VUE_APP_LOGIN_URL;
|
||||
|
||||
const TokenName='XBOE-Access-Token';
|
||||
const TokenName = 'XBOE-Access-Token';
|
||||
/**axios.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded'**/
|
||||
//只是用于发送json对象数据时使用post,put,patch
|
||||
const jsonRequest=axios.create({
|
||||
headers:{'Content-Type':'application/json;charset=utf-8'},
|
||||
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
||||
baseURL: process.env.VUE_APP_BASE_API,
|
||||
//超时
|
||||
timeout: 60000,
|
||||
const jsonRequest = axios.create({
|
||||
headers: { 'Content-Type': 'application/json;charset=utf-8' },
|
||||
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
||||
baseURL: process.env.VUE_APP_BASE_API,
|
||||
//超时
|
||||
timeout: 60000,
|
||||
});
|
||||
//发送json对象的拦截器
|
||||
jsonRequest.interceptors.request.use(config => {
|
||||
//是否需要设置 token
|
||||
const isToken = (config.headers || {}).isToken === false
|
||||
if (getToken() && !isToken) {
|
||||
config.headers[TokenName] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
}
|
||||
return config
|
||||
//是否需要设置 token
|
||||
const isToken = (config.headers || {}).isToken === false
|
||||
if (getToken() && !isToken) {
|
||||
config.headers[TokenName] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
}
|
||||
return config
|
||||
}, error => {
|
||||
console.log(error)
|
||||
Promise.reject(error)
|
||||
console.log(error)
|
||||
Promise.reject(error)
|
||||
})
|
||||
|
||||
// 响应拦截器
|
||||
jsonRequest.interceptors.response.use(res => {
|
||||
|
||||
const code = res.data.status || 200;
|
||||
if(code===200){
|
||||
return res.data
|
||||
}else{
|
||||
if(code == 6001){ //针对于老系统的处理
|
||||
store.dispatch('LogOut').then(() => {
|
||||
location.href = ReLoginUrl;
|
||||
})
|
||||
}else if(code === 401){
|
||||
store.dispatch('LogOut').then(() => {
|
||||
location.href = ReLoginUrl;
|
||||
})
|
||||
}else if(code === 402){
|
||||
store.dispatch('LogOut').then(() => {
|
||||
location.href = ReLoginUrl;
|
||||
})
|
||||
}else if(code===403){
|
||||
var msg='当前操作没有权限';
|
||||
Message({message: msg, type: 'error'});
|
||||
return Promise.reject(new Error(msg))
|
||||
//return res.data;
|
||||
}else if(code===302){
|
||||
location.href = ReLoginUrl;
|
||||
}else{
|
||||
//Message({message: res.data.message, type: 'error'});
|
||||
//console.log('err:' + res.data.error);
|
||||
//return Promise.reject(new Error(res.data.message))
|
||||
return res.data;
|
||||
const code = res.data.status || 200;
|
||||
if (code === 200) {
|
||||
return res.data
|
||||
} else {
|
||||
if (code == 6001) { //针对于老系统的处理
|
||||
store.dispatch('LogOut').then(() => {
|
||||
if (top !== window) { // 判断当前是否在iframe内
|
||||
top.location.href = ReLoginUrl;
|
||||
} else {
|
||||
window.location.href = ReLoginUrl;
|
||||
}
|
||||
// location.href = ReLoginUrl;
|
||||
})
|
||||
} else if (code === 401) {
|
||||
store.dispatch('LogOut').then(() => {
|
||||
if (top !== window) { // 判断当前是否在iframe内
|
||||
top.location.href = ReLoginUrl;
|
||||
} else {
|
||||
window.location.href = ReLoginUrl;
|
||||
}
|
||||
// location.href = ReLoginUrl;
|
||||
})
|
||||
} else if (code === 402) {
|
||||
store.dispatch('LogOut').then(() => {
|
||||
if (top !== window) { // 判断当前是否在iframe内
|
||||
top.location.href = ReLoginUrl;
|
||||
} else {
|
||||
window.location.href = ReLoginUrl;
|
||||
}
|
||||
// location.href = ReLoginUrl;
|
||||
})
|
||||
} else if (code === 403) {
|
||||
var msg = '当前操作没有权限';
|
||||
Message({ message: msg, type: 'error' });
|
||||
return Promise.reject(new Error(msg))
|
||||
//return res.data;
|
||||
} else if (code === 302) {
|
||||
if (top !== window) { // 判断当前是否在iframe内
|
||||
top.location.href = ReLoginUrl;
|
||||
} else {
|
||||
window.location.href = ReLoginUrl;
|
||||
}
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log('err' + error)
|
||||
let { message } = error;
|
||||
if (message == "Network Error") {
|
||||
message = "网络异常,请稍后重试";
|
||||
}
|
||||
else if (message.includes("timeout")) {
|
||||
message = "系统接口请求超时";
|
||||
//location.href = this.webBaseUrl + ReLoginUrl;
|
||||
}
|
||||
else if (message.includes("Request failed with status code")) {
|
||||
message = "系统接口" + message.substr(message.length - 3) + "异常";
|
||||
}
|
||||
Message({
|
||||
message: message,
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
})
|
||||
return Promise.reject(error)
|
||||
}
|
||||
// location.href = ReLoginUrl;
|
||||
} else {
|
||||
//Message({message: res.data.message, type: 'error'});
|
||||
//console.log('err:' + res.data.error);
|
||||
//return Promise.reject(new Error(res.data.message))
|
||||
return res.data;
|
||||
}
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log('err' + error)
|
||||
let { message } = error;
|
||||
if (message == "Network Error") {
|
||||
message = "网络异常,请稍后重试";
|
||||
}
|
||||
else if (message.includes("timeout")) {
|
||||
message = "系统接口请求超时";
|
||||
//location.href = this.webBaseUrl + ReLoginUrl;
|
||||
}
|
||||
else if (message.includes("Request failed with status code")) {
|
||||
message = "系统接口" + message.substr(message.length - 3) + "异常";
|
||||
}
|
||||
Message({
|
||||
message: message,
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
})
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
//用于普通的发送请求
|
||||
const formRequest=axios.create({
|
||||
headers:{'Content-Type':'application/x-www-form-urlencoded'},
|
||||
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
||||
baseURL: process.env.VUE_APP_BASE_API,
|
||||
//超时
|
||||
timeout: 10000,
|
||||
const formRequest = axios.create({
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
||||
baseURL: process.env.VUE_APP_BASE_API,
|
||||
//超时
|
||||
timeout: 10000,
|
||||
})
|
||||
//发送json对象的拦截器
|
||||
formRequest.interceptors.request.use(config => {
|
||||
//是否需要设置 token
|
||||
const isToken = (config.headers || {}).isToken === false
|
||||
if (getToken() && !isToken) {
|
||||
config.headers[TokenName] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
}
|
||||
return config
|
||||
//是否需要设置 token
|
||||
const isToken = (config.headers || {}).isToken === false
|
||||
if (getToken() && !isToken) {
|
||||
config.headers[TokenName] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
}
|
||||
return config
|
||||
}, error => {
|
||||
console.log(error)
|
||||
Promise.reject(error)
|
||||
console.log(error)
|
||||
Promise.reject(error)
|
||||
});
|
||||
formRequest.interceptors.response.use(res => {
|
||||
const code = res.data.status || 200;
|
||||
if(code===200){
|
||||
return res.data
|
||||
}else{
|
||||
if(code == 6001){ //针对于老系统的处理,因为老系统是字符串,所以这里不使用三等于号
|
||||
store.dispatch('LogOut').then(() => {
|
||||
location.href = ReLoginUrl;
|
||||
})
|
||||
}else if(code === 401){
|
||||
store.dispatch('LogOut').then(() => {
|
||||
location.href = ReLoginUrl;
|
||||
})
|
||||
}else if(code === 402){
|
||||
store.dispatch('LogOut').then(() => {
|
||||
location.href = ReLoginUrl;
|
||||
})
|
||||
}else if(code===403){
|
||||
var msg='当前操作没有权限';
|
||||
Message({message: msg, type: 'error'});
|
||||
return Promise.reject(new Error(msg))
|
||||
}else if(code===302){
|
||||
location.href = ReLoginUrl;
|
||||
}else{
|
||||
//Message({message: res.data.message, type: 'error'});
|
||||
//console.log('err' + res.data.error);
|
||||
//return Promise.reject(new Error(res.data.message))
|
||||
return res.data;//返回给用户做业务处理
|
||||
const code = res.data.status || 200;
|
||||
if (code === 200) {
|
||||
return res.data
|
||||
} else {
|
||||
if (code == 6001) { //针对于老系统的处理,因为老系统是字符串,所以这里不使用三等于号
|
||||
store.dispatch('LogOut').then(() => {
|
||||
if (top !== window) { // 判断当前是否在iframe内
|
||||
top.location.href = ReLoginUrl;
|
||||
} else {
|
||||
window.location.href = ReLoginUrl;
|
||||
}
|
||||
// location.href = ReLoginUrl;
|
||||
})
|
||||
} else if (code === 401) {
|
||||
store.dispatch('LogOut').then(() => {
|
||||
if (top !== window) { // 判断当前是否在iframe内
|
||||
top.location.href = ReLoginUrl;
|
||||
} else {
|
||||
window.location.href = ReLoginUrl;
|
||||
}
|
||||
// location.href = ReLoginUrl;
|
||||
})
|
||||
} else if (code === 402) {
|
||||
store.dispatch('LogOut').then(() => {
|
||||
if (top !== window) { // 判断当前是否在iframe内
|
||||
top.location.href = ReLoginUrl;
|
||||
} else {
|
||||
window.location.href = ReLoginUrl;
|
||||
}
|
||||
// location.href = ReLoginUrl;
|
||||
})
|
||||
} else if (code === 403) {
|
||||
var msg = '当前操作没有权限';
|
||||
Message({ message: msg, type: 'error' });
|
||||
return Promise.reject(new Error(msg))
|
||||
} else if (code === 302) {
|
||||
if (top !== window) { // 判断当前是否在iframe内
|
||||
top.location.href = ReLoginUrl;
|
||||
} else {
|
||||
window.location.href = ReLoginUrl;
|
||||
}
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log('err' + error)
|
||||
let { message } = error;
|
||||
if (message == "Network Error") {
|
||||
message = "网络异常,请稍后重试";
|
||||
}
|
||||
else if (message.includes("timeout")) {
|
||||
message = "系统接口请求超时";
|
||||
//location.href = this.webBaseUrl + ReLoginUrl;
|
||||
}
|
||||
else if (message.includes("Request failed with status code")) {
|
||||
message = "系统接口" + message.substr(message.length - 3) + "异常";
|
||||
}
|
||||
Message({
|
||||
message: message,
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
})
|
||||
return Promise.reject(error)
|
||||
}
|
||||
// location.href = ReLoginUrl;
|
||||
} else {
|
||||
//Message({message: res.data.message, type: 'error'});
|
||||
//console.log('err' + res.data.error);
|
||||
//return Promise.reject(new Error(res.data.message))
|
||||
return res.data;//返回给用户做业务处理
|
||||
}
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log('err' + error)
|
||||
let { message } = error;
|
||||
if (message == "Network Error") {
|
||||
message = "网络异常,请稍后重试";
|
||||
}
|
||||
else if (message.includes("timeout")) {
|
||||
message = "系统接口请求超时";
|
||||
//location.href = this.webBaseUrl + ReLoginUrl;
|
||||
}
|
||||
else if (message.includes("Request failed with status code")) {
|
||||
message = "系统接口" + message.substr(message.length - 3) + "异常";
|
||||
}
|
||||
Message({
|
||||
message: message,
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
})
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
//request请求
|
||||
const request=function(cfg){
|
||||
if(cfg.data){
|
||||
cfg.data=qs.stringify(cfg.data);
|
||||
const request = function (cfg) {
|
||||
if (cfg.data) {
|
||||
cfg.data = qs.stringify(cfg.data);
|
||||
}
|
||||
};
|
||||
//requestJson请求
|
||||
const requestJson=jsonRequest.request;
|
||||
const requestJson = jsonRequest.request;
|
||||
//get请求
|
||||
const get=formRequest.request;
|
||||
const get = formRequest.request;
|
||||
//post请求
|
||||
const post=function(url,data,config){
|
||||
if(data){
|
||||
data=qs.stringify(data);
|
||||
const post = function (url, data, config) {
|
||||
if (data) {
|
||||
data = qs.stringify(data);
|
||||
}
|
||||
return formRequest.post(url,data,config);
|
||||
return formRequest.post(url, data, config);
|
||||
}
|
||||
//post请求
|
||||
const postForm=function(url,data,config){
|
||||
return formRequest.post(url,data,config);
|
||||
const postForm = function (url, data, config) {
|
||||
return formRequest.post(url, data, config);
|
||||
}
|
||||
//postJson请求
|
||||
const postJson=jsonRequest.post;
|
||||
const postJson = jsonRequest.post;
|
||||
//put请求
|
||||
const put=function(url,data,config){
|
||||
if(data){
|
||||
data=qs.stringify(data);
|
||||
const put = function (url, data, config) {
|
||||
if (data) {
|
||||
data = qs.stringify(data);
|
||||
}
|
||||
return formRequest.put(url,data,config);
|
||||
return formRequest.put(url, data, config);
|
||||
}
|
||||
//putJson请求
|
||||
const putJson=jsonRequest.put;
|
||||
const putJson = jsonRequest.put;
|
||||
//patch请求
|
||||
const patch=function(url,data,config){
|
||||
if(data){
|
||||
data=qs.stringify(data);
|
||||
const patch = function (url, data, config) {
|
||||
if (data) {
|
||||
data = qs.stringify(data);
|
||||
}
|
||||
return formRequest.patch(url,data,config);
|
||||
return formRequest.patch(url, data, config);
|
||||
}
|
||||
//patchJson请求
|
||||
const patchJson=jsonRequest.patch;
|
||||
const patchJson = jsonRequest.patch;
|
||||
//delete请求
|
||||
const del=formRequest.delete;
|
||||
const del = formRequest.delete;
|
||||
|
||||
|
||||
export default {
|
||||
request,
|
||||
requestJson,
|
||||
get,
|
||||
post,
|
||||
postJson,
|
||||
put,
|
||||
putJson,
|
||||
patch,
|
||||
patchJson,
|
||||
del,
|
||||
postForm
|
||||
request,
|
||||
requestJson,
|
||||
get,
|
||||
post,
|
||||
postJson,
|
||||
put,
|
||||
putJson,
|
||||
patch,
|
||||
patchJson,
|
||||
del,
|
||||
postForm
|
||||
}
|
||||
|
||||
@@ -153,28 +153,29 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="xindex-content">
|
||||
|
||||
|
||||
<!-- 推荐课程 -->
|
||||
<div class="modules xcontent2">
|
||||
<!-- <div class="xcontent2-main"> -->
|
||||
<!--内容块-->
|
||||
|
||||
|
||||
<!-- </div> -->
|
||||
<!-- 精品课模块 -->
|
||||
<div class="xcontent2-main">
|
||||
<div class="modules-title xindex-main" v-if="this.qusisityList.list.length > 0">
|
||||
<!-- <span class="modules-text" style="color: #3D86F4;">精品课</span> -->
|
||||
<!-- <span class="jin-text">精品课</span> -->
|
||||
<div class="jin-zhe"></div>
|
||||
<span class="quyer-tag" style="margin-left: 0px;">
|
||||
<!-- <img src="../assets/images/tutoring1.pn" alt=""> -->
|
||||
<img class="modules-text" style="height: 28px;" src="../assets/images/course/courseTitle.png" alt="">
|
||||
</span>
|
||||
|
||||
<span class="more">
|
||||
<router-link to="/qualityCourse">查看更多>></router-link>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<div
|
||||
v-for="(course, eIndex) in exquisiteList"
|
||||
:key="'cc' + eIndex"
|
||||
@@ -231,7 +232,7 @@
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<!--内容块-->
|
||||
<div class="modules-title xindex-main">
|
||||
<span class="modules-text">推荐课程</span>
|
||||
@@ -1308,7 +1309,7 @@ export default {
|
||||
return this.courseList.list.slice(3)
|
||||
},
|
||||
// 精品课展示
|
||||
exquisiteList() {
|
||||
exquisiteList() {
|
||||
return this.qusisityList.list.slice(0,3)
|
||||
},
|
||||
},
|
||||
@@ -1567,7 +1568,7 @@ export default {
|
||||
let course = {
|
||||
aid: this.userInfo.aid,
|
||||
}
|
||||
apiIndex.qualitylist(course).then((res) => {
|
||||
apiIndex.qualitylist(course).then((res) => {
|
||||
let courseIds = [];
|
||||
res.data.result.forEach((item) => {
|
||||
item.authorInfo = {
|
||||
@@ -2826,6 +2827,15 @@ export default {
|
||||
display: flex;
|
||||
|
||||
.modules-title {
|
||||
position: relative;
|
||||
.jin-zhe{
|
||||
width: 410px;
|
||||
height: 30px;
|
||||
background: #f7f7f9;
|
||||
position: absolute;
|
||||
left: 86px;
|
||||
|
||||
}
|
||||
.modules-text {
|
||||
height: 28px;
|
||||
font-size: 20px;
|
||||
@@ -3136,4 +3146,13 @@ export default {
|
||||
border: 1px solid #d9edf7;
|
||||
//overflow: hidden;
|
||||
}
|
||||
.jin-text{
|
||||
font-family: "Source Han Sans CN", "SourceHanSansCN", sans-serif !important;
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
color: #3E87F5;
|
||||
// line-height: 29px;/
|
||||
text-align: justify;
|
||||
font-style: normal;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -5,56 +5,61 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Cookies from 'vue-cookies'
|
||||
import apiLogin from '@/api/login.js'
|
||||
import { getToken,setToken } from '@/utils/token'
|
||||
export default{
|
||||
mounted(){
|
||||
this.toUrl=this.$route.query.returnUrl;
|
||||
let token=getToken();
|
||||
let $this=this;
|
||||
if(!token){
|
||||
//console.log(token,'未获取token');
|
||||
setTimeout(function(){
|
||||
$this.curToken=getToken();
|
||||
if(!$this.curToken){
|
||||
//console.log(token,'第二次未获取token');
|
||||
location.href = process.env.VUE_APP_LOGIN_URL;
|
||||
}else{
|
||||
$this.boeLogin();
|
||||
import Cookies from "vue-cookies";
|
||||
import apiLogin from "@/api/login.js";
|
||||
import { getToken, setToken } from "@/utils/token";
|
||||
export default {
|
||||
mounted() {
|
||||
this.toUrl = this.$route.query.returnUrl;
|
||||
let token = getToken();
|
||||
let $this = this;
|
||||
if (!token) {
|
||||
//console.log(token,'未获取token');
|
||||
setTimeout(function () {
|
||||
$this.curToken = getToken();
|
||||
if (!$this.curToken) {
|
||||
//console.log(token,'第二次未获取token');
|
||||
if (top !== window) {
|
||||
// 判断当前是否在iframe内
|
||||
top.location.href = process.env.VUE_APP_LOGIN_URL;
|
||||
} else {
|
||||
window.location.href = process.env.VUE_APP_LOGIN_URL;
|
||||
}
|
||||
|
||||
},500);
|
||||
}else{
|
||||
this.curToken=token;
|
||||
this.boeLogin();
|
||||
}
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
curToken:'',
|
||||
toUrl:''
|
||||
}
|
||||
},
|
||||
methods:{
|
||||
boeLogin(){
|
||||
apiLogin.boeLogin(this.curToken).then(rs=>{
|
||||
if(rs.status==200){
|
||||
//setToken(rs.result.access_token);
|
||||
localStorage.setItem(this.$xpage.constants.newLoginKey,1);
|
||||
if(this.toUrl){
|
||||
location.href=this.toUrl;
|
||||
}else{
|
||||
this.$router.push({ path: "/index" })
|
||||
}
|
||||
//this.$router.push({ path: "/index" })
|
||||
}else{
|
||||
this.$message.error("登录失败:"+rs.message);
|
||||
}
|
||||
})
|
||||
}
|
||||
// location.href = process.env.VUE_APP_LOGIN_URL;
|
||||
} else {
|
||||
$this.boeLogin();
|
||||
}
|
||||
}, 500);
|
||||
} else {
|
||||
this.curToken = token;
|
||||
this.boeLogin();
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
curToken: "",
|
||||
toUrl: "",
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
boeLogin() {
|
||||
apiLogin.boeLogin(this.curToken).then((rs) => {
|
||||
if (rs.status == 200) {
|
||||
//setToken(rs.result.access_token);
|
||||
localStorage.setItem(this.$xpage.constants.newLoginKey, 1);
|
||||
if (this.toUrl) {
|
||||
location.href = this.toUrl;
|
||||
} else {
|
||||
this.$router.push({ path: "/index" });
|
||||
}
|
||||
//this.$router.push({ path: "/index" })
|
||||
} else {
|
||||
this.$message.error("登录失败:" + rs.message);
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -483,8 +483,11 @@ export default {
|
||||
} else if (this.form.device2 === true) {
|
||||
this.form.device = 2;
|
||||
}
|
||||
//时长,秒与分钟的转化
|
||||
//if(this.form.)
|
||||
// 时长,秒与分钟的转化
|
||||
if (this.form.minute) {
|
||||
this.form.duration = this.form.minute * 60;
|
||||
}
|
||||
|
||||
try {
|
||||
const { status,message} = await coueseFile.batchUpdate([this.form]);
|
||||
if (status === 200) {
|
||||
|
||||
@@ -1,66 +1,117 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:visible="dialogVisible"
|
||||
width="600px"
|
||||
:close-on-click-modal="false"
|
||||
:show-close="true"
|
||||
@close="onClose"
|
||||
class="case-expert-dialog"
|
||||
>
|
||||
<!-- 标题 -->
|
||||
<div slot="title" class="dialog-title">
|
||||
<!-- <img src="@/assets/images/case-expert-icon.png" alt="案例专家" class="icon" /> -->
|
||||
<span>案例专家</span>
|
||||
</div>
|
||||
|
||||
<!-- 内容区域 -->
|
||||
<div class="content-wrapper">
|
||||
<div
|
||||
class="welcome-message"
|
||||
ref="messageContainer"
|
||||
@scroll="handleScroll"
|
||||
>
|
||||
<div class="message-text" v-for="(item, index) in messageList" :key="index">
|
||||
<messages :messageData="item" :suggestions="suggestions"></messages>
|
||||
|
||||
</div>
|
||||
<div class="message-suggestions" v-if="messageList[messageList.length-1].textCompleted">
|
||||
<div class="suggestion-item" v-for="(item, index) in suggestions" :key="index">
|
||||
<a @click="sendSuggestions(item)"> {{ item }} →</a>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isLoading" class="loading-message">
|
||||
<div class="loading-dots">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<!-- 最大化状态的弹窗 -->
|
||||
<el-dialog
|
||||
v-if="dialogVisible && windowState === 'maximized'"
|
||||
:visible="true"
|
||||
:close-on-click-modal="false"
|
||||
:show-close="true"
|
||||
@close="onClose"
|
||||
class="case-expert-dialog"
|
||||
:modal="false"
|
||||
:fullscreen="false"
|
||||
top="0"
|
||||
v-resizeable
|
||||
v-draggable
|
||||
>
|
||||
<!-- 标题 -->
|
||||
<div slot="title" class="dialog-title">
|
||||
<span>案例专家</span>
|
||||
<el-button
|
||||
style="color:#96999f"
|
||||
type="text"
|
||||
class="window-control-btn"
|
||||
@click="minimizeWindow"
|
||||
>
|
||||
<i class="el-icon-minus"></i>
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 输入框区域 -->
|
||||
<send-message
|
||||
v-model="AIContent"
|
||||
:message-list="messageList"
|
||||
:suggestions="suggestions"
|
||||
@loading="handleLoading"
|
||||
@update-message="updateMessage"
|
||||
@update-suggestions="updateSuggestions"
|
||||
@new-conversation="startNewConversation"
|
||||
:disabled="isLoading"
|
||||
class="input-area-wrapper"
|
||||
ref="sendMessage"
|
||||
/>
|
||||
</div>
|
||||
<!-- 内容区域 -->
|
||||
<div class="content-wrapper">
|
||||
<div
|
||||
class="welcome-message"
|
||||
ref="messageContainer"
|
||||
@scroll="handleScroll"
|
||||
@wheel="handleWheel"
|
||||
>
|
||||
<div class="message-text" v-for="(item, index) in messageList" :key="index">
|
||||
<messages :messageData="item" :suggestions="suggestions" @getMinWindow="minimizeWindow"></messages>
|
||||
</div>
|
||||
<div class="message-suggestions" v-if="messageList.length > 0 && messageList[messageList.length-1].textCompleted">
|
||||
<div class="suggestion-item" v-for="(item, index) in suggestions" :key="index">
|
||||
<a @click="sendSuggestions(item)"> {{ item }} →</a>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isLoading" class="loading-message">
|
||||
<div class="loading-dots">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 关闭按钮在右上角,由 el-dialog 自动处理 -->
|
||||
</el-dialog>
|
||||
<!-- 输入框区域 -->
|
||||
<send-message
|
||||
v-model="AIContent"
|
||||
:message-list="messageList"
|
||||
:suggestions="suggestions"
|
||||
@loading="handleLoading"
|
||||
@update-message="updateMessage"
|
||||
@update-suggestions="updateSuggestions"
|
||||
@new-conversation="startNewConversation"
|
||||
:disabled="isLoading"
|
||||
class="input-area-wrapper"
|
||||
ref="sendMessage"
|
||||
/>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 最小化状态的弹窗 -->
|
||||
<div
|
||||
class="minimized-window"
|
||||
v-show="windowState === 'minimized' && showMinimizedWindow"
|
||||
@click="onMinimizedWindowClick"
|
||||
>
|
||||
<div class="minimized-content">
|
||||
<span class="window-title">案例专家</span>
|
||||
<div style="display: flex;align-items: center">
|
||||
<el-button
|
||||
type="text"
|
||||
class="window-control-btn"
|
||||
@click.stop="onMinimizedWindowClick"
|
||||
>
|
||||
<img :src="openImg" alt="" style="width: 17px">
|
||||
</el-button>
|
||||
|
||||
<el-button
|
||||
style="margin-left: 1px;color:#96999f"
|
||||
type="text"
|
||||
class="window-control-btn"
|
||||
@click.stop="closeMinimizedWindow"
|
||||
>
|
||||
<i class="el-icon-close"></i>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="minimized-message">
|
||||
<div v-if="messageList.length <= 1 && messageList[0].isBot">
|
||||
当前暂无对话内容,去创建对话吧
|
||||
</div>
|
||||
<div v-else>
|
||||
{{ getLastUserMessage() }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import messages from './components/messages.vue'
|
||||
import sendMessage from './components/sendMessage.vue'
|
||||
|
||||
import openImg from './components/open.png'
|
||||
export default {
|
||||
name: 'CaseExpertDialog',
|
||||
props: {
|
||||
@@ -73,43 +124,480 @@ export default {
|
||||
messages,
|
||||
sendMessage
|
||||
},
|
||||
directives: {
|
||||
draggable: {
|
||||
bind(el, binding, vnode) {
|
||||
vnode.context.$nextTick(() => {
|
||||
const dialogEl = el.querySelector('.el-dialog');
|
||||
if (!dialogEl) return;
|
||||
|
||||
const headerEl = dialogEl.querySelector('.dialog-title');
|
||||
if (!headerEl) return;
|
||||
|
||||
// 检查是否有保存的位置状态
|
||||
const savedPosition = sessionStorage.getItem('aiCallDialogPosition');
|
||||
if (savedPosition) {
|
||||
const { left, top } = JSON.parse(savedPosition);
|
||||
dialogEl.style.left = left + 'px';
|
||||
dialogEl.style.top = top + 'px';
|
||||
} else {
|
||||
// 设置初始样式
|
||||
dialogEl.style.position = 'fixed';
|
||||
dialogEl.style.top = '100px';
|
||||
dialogEl.style.left = (window.innerWidth - dialogEl.offsetWidth) / 2 + 'px';
|
||||
}
|
||||
dialogEl.style.margin = '0';
|
||||
|
||||
let isDragging = false;
|
||||
let startX = 0;
|
||||
let startY = 0;
|
||||
let startLeft = 0;
|
||||
let startTop = 0;
|
||||
|
||||
const startDrag = (event) => {
|
||||
// 只有在标题栏上按下鼠标才开始拖动
|
||||
if (event.target.closest('.resize-handle')) {
|
||||
return; // 如果点击的是resize-handle,则不触发拖动
|
||||
}
|
||||
|
||||
isDragging = true;
|
||||
startX = event.clientX;
|
||||
startY = event.clientY;
|
||||
startLeft = parseInt(dialogEl.style.left) || dialogEl.offsetLeft;
|
||||
startTop = parseInt(dialogEl.style.top) || dialogEl.offsetTop;
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
// 添加全局事件监听
|
||||
document.addEventListener('mousemove', handleMouseMove);
|
||||
document.addEventListener('mouseup', stopDrag);
|
||||
};
|
||||
|
||||
const handleMouseMove = (event) => {
|
||||
if (!isDragging) return;
|
||||
|
||||
const deltaX = event.clientX - startX;
|
||||
const deltaY = event.clientY - startY;
|
||||
|
||||
dialogEl.style.left = (startLeft + deltaX) + 'px';
|
||||
dialogEl.style.top = (startTop + deltaY) + 'px';
|
||||
};
|
||||
|
||||
const stopDrag = () => {
|
||||
isDragging = false;
|
||||
|
||||
// 保存当前位置到 sessionStorage
|
||||
const currentPosition = {
|
||||
left: parseInt(dialogEl.style.left),
|
||||
top: parseInt(dialogEl.style.top)
|
||||
};
|
||||
// sessionStorage.setItem('aiCallDialogPosition', JSON.stringify(currentPosition));
|
||||
|
||||
// 移除全局事件监听
|
||||
document.removeEventListener('mousemove', handleMouseMove);
|
||||
document.removeEventListener('mouseup', stopDrag);
|
||||
};
|
||||
|
||||
// 为标题栏绑定拖动事件
|
||||
headerEl.addEventListener('mousedown', startDrag);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
resizeable: {
|
||||
bind(el, binding, vnode) {
|
||||
// 确保元素已插入DOM
|
||||
vnode.context.$nextTick(() => {
|
||||
const dialogEl = el.querySelector('.el-dialog');
|
||||
if (!dialogEl) return;
|
||||
|
||||
// 检查是否有保存的尺寸状态
|
||||
const savedSize = sessionStorage.getItem('aiCallDialogSize');
|
||||
if (savedSize) {
|
||||
const { width, height, left, top } = JSON.parse(savedSize);
|
||||
dialogEl.style.width = width + 'px';
|
||||
dialogEl.style.height = height + 'px';
|
||||
dialogEl.style.left = left + 'px';
|
||||
dialogEl.style.top = top + 'px';
|
||||
} else {
|
||||
// 设置初始样式
|
||||
dialogEl.style.position = 'fixed';
|
||||
dialogEl.style.top = '100px';
|
||||
dialogEl.style.left = (window.innerWidth - dialogEl.offsetWidth) / 2 + 'px';
|
||||
}
|
||||
|
||||
// 创建拖拽手柄
|
||||
const createHandle = (direction) => {
|
||||
const handle = document.createElement('div');
|
||||
handle.className = `resize-handle ${direction}`;
|
||||
handle.style.position = 'absolute';
|
||||
handle.style.zIndex = '10';
|
||||
|
||||
switch (direction) {
|
||||
case 'left':
|
||||
case 'right':
|
||||
handle.style.width = '6px';
|
||||
handle.style.height = '100%';
|
||||
handle.style.top = '0';
|
||||
handle.style.cursor = 'ew-resize';
|
||||
break;
|
||||
case 'top':
|
||||
case 'bottom':
|
||||
handle.style.width = '100%';
|
||||
handle.style.height = '6px';
|
||||
handle.style.left = '0';
|
||||
handle.style.cursor = 'ns-resize';
|
||||
break;
|
||||
case 'top-left':
|
||||
case 'top-right':
|
||||
case 'bottom-left':
|
||||
case 'bottom-right':
|
||||
handle.style.width = '10px';
|
||||
handle.style.height = '10px';
|
||||
handle.style.zIndex = '20';
|
||||
break;
|
||||
}
|
||||
|
||||
switch (direction) {
|
||||
case 'left':
|
||||
handle.style.left = '0';
|
||||
break;
|
||||
case 'right':
|
||||
handle.style.right = '0';
|
||||
break;
|
||||
case 'top':
|
||||
handle.style.top = '0';
|
||||
break;
|
||||
case 'bottom':
|
||||
handle.style.bottom = '0';
|
||||
break;
|
||||
case 'top-left':
|
||||
handle.style.top = '0';
|
||||
handle.style.left = '0';
|
||||
handle.style.cursor = 'nw-resize';
|
||||
break;
|
||||
case 'top-right':
|
||||
handle.style.top = '0';
|
||||
handle.style.right = '0';
|
||||
handle.style.cursor = 'ne-resize';
|
||||
break;
|
||||
case 'bottom-left':
|
||||
handle.style.bottom = '0';
|
||||
handle.style.left = '0';
|
||||
handle.style.cursor = 'sw-resize';
|
||||
break;
|
||||
case 'bottom-right':
|
||||
handle.style.bottom = '0';
|
||||
handle.style.right = '0';
|
||||
handle.style.cursor = 'se-resize';
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// 防止拖拽手柄的事件冒泡到标题栏
|
||||
handle.addEventListener('mousedown', (e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
});
|
||||
|
||||
dialogEl.appendChild(handle);
|
||||
return handle;
|
||||
};
|
||||
|
||||
// 创建8个拖拽手柄
|
||||
const handles = {
|
||||
left: createHandle('left'),
|
||||
right: createHandle('right'),
|
||||
top: createHandle('top'),
|
||||
bottom: createHandle('bottom'),
|
||||
topLeft: createHandle('top-left'),
|
||||
topRight: createHandle('top-right'),
|
||||
bottomLeft: createHandle('bottom-left'),
|
||||
bottomRight: createHandle('bottom-right')
|
||||
};
|
||||
|
||||
// 添加拖拽事件处理
|
||||
let isResizing = false;
|
||||
let resizeDirection = '';
|
||||
let startX = 0;
|
||||
let startY = 0;
|
||||
let startWidth = 0;
|
||||
let startHeight = 0;
|
||||
let startLeft = 0;
|
||||
let startTop = 0;
|
||||
|
||||
const startResize = (direction, event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
isResizing = true;
|
||||
resizeDirection = direction;
|
||||
|
||||
startX = event.clientX;
|
||||
startY = event.clientY;
|
||||
startWidth = dialogEl.offsetWidth;
|
||||
startHeight = dialogEl.offsetHeight;
|
||||
|
||||
// 统一使用计算后的样式值
|
||||
startLeft = parseInt(dialogEl.style.left) || 0;
|
||||
startTop = parseInt(dialogEl.style.top) || 0;
|
||||
|
||||
// 添加全局事件监听
|
||||
document.addEventListener('mousemove', handleMouseMove);
|
||||
document.addEventListener('mouseup', stopResize);
|
||||
};
|
||||
|
||||
const handleMouseMove = (event) => {
|
||||
if (!isResizing) return;
|
||||
|
||||
const deltaX = event.clientX - startX;
|
||||
const deltaY = event.clientY - startY;
|
||||
|
||||
let newWidth, newHeight, newLeft, newTop;
|
||||
|
||||
switch (resizeDirection) {
|
||||
case 'right':
|
||||
newWidth = Math.max(400, startWidth + deltaX);
|
||||
dialogEl.style.width = newWidth + 'px';
|
||||
break;
|
||||
case 'left':
|
||||
newWidth = Math.max(400, startWidth - deltaX);
|
||||
newLeft = startLeft + startWidth - newWidth;
|
||||
dialogEl.style.width = newWidth + 'px';
|
||||
dialogEl.style.left = newLeft + 'px';
|
||||
break;
|
||||
case 'bottom':
|
||||
newHeight = Math.max(600, startHeight + deltaY);
|
||||
dialogEl.style.height = newHeight + 'px';
|
||||
break;
|
||||
case 'top':
|
||||
// 当窗口高度达到最小值时,不再调整高度和位置
|
||||
if (startHeight - deltaY >= 600) {
|
||||
newHeight = startHeight - deltaY;
|
||||
newTop = startTop + deltaY;
|
||||
dialogEl.style.height = newHeight + 'px';
|
||||
dialogEl.style.top = newTop + 'px';
|
||||
}
|
||||
break;
|
||||
case 'bottom-right':
|
||||
newWidth = Math.max(400, startWidth + deltaX);
|
||||
newHeight = Math.max(600, startHeight + deltaY);
|
||||
dialogEl.style.width = newWidth + 'px';
|
||||
dialogEl.style.height = newHeight + 'px';
|
||||
break;
|
||||
case 'bottom-left':
|
||||
newWidth = Math.max(400, startWidth - deltaX);
|
||||
newHeight = Math.max(600, startHeight + deltaY);
|
||||
newLeft = startLeft + startWidth - newWidth;
|
||||
dialogEl.style.width = newWidth + 'px';
|
||||
dialogEl.style.left = newLeft + 'px';
|
||||
dialogEl.style.height = newHeight + 'px';
|
||||
break;
|
||||
case 'top-right':
|
||||
// 当窗口高度达到最小值时,不再调整高度和位置
|
||||
if (startHeight - deltaY >= 600) {
|
||||
newHeight = startHeight - deltaY;
|
||||
newTop = startTop + deltaY;
|
||||
newWidth = Math.max(400, startWidth + deltaX);
|
||||
dialogEl.style.height = newHeight + 'px';
|
||||
dialogEl.style.top = newTop + 'px';
|
||||
dialogEl.style.width = newWidth + 'px';
|
||||
}
|
||||
break;
|
||||
case 'top-left':
|
||||
// 当窗口高度达到最小值时,不再调整高度和位置
|
||||
if (startHeight - deltaY >= 600) {
|
||||
newHeight = startHeight - deltaY;
|
||||
newTop = startTop + deltaY;
|
||||
newWidth = Math.max(400, startWidth - deltaX);
|
||||
newLeft = startLeft + startWidth - newWidth;
|
||||
dialogEl.style.height = newHeight + 'px';
|
||||
dialogEl.style.top = newTop + 'px';
|
||||
dialogEl.style.width = newWidth + 'px';
|
||||
dialogEl.style.left = newLeft + 'px';
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
let doc = document.querySelector('.welcome-message')
|
||||
let sendBox = document.querySelector('.input-area-wrapper');
|
||||
// sendBox 的高度
|
||||
if (doc && sendBox) {
|
||||
doc.style.height = `calc(${dialogEl.style.height} - ${sendBox.offsetHeight}px - 120px)`;
|
||||
}
|
||||
};
|
||||
|
||||
const stopResize = () => {
|
||||
isResizing = false;
|
||||
resizeDirection = '';
|
||||
|
||||
// 保存当前尺寸和位置到 sessionStorage
|
||||
const currentSize = {
|
||||
width: parseInt(dialogEl.style.width),
|
||||
height: parseInt(dialogEl.style.height),
|
||||
left: parseInt(dialogEl.style.left),
|
||||
top: parseInt(dialogEl.style.top)
|
||||
};
|
||||
sessionStorage.setItem('aiCallDialogSize', JSON.stringify(currentSize));
|
||||
|
||||
// 移除全局事件监听
|
||||
document.removeEventListener('mousemove', handleMouseMove);
|
||||
document.removeEventListener('mouseup', stopResize);
|
||||
};
|
||||
|
||||
// 为每个手柄绑定事件
|
||||
handles.left.addEventListener('mousedown', (e) => startResize('left', e));
|
||||
handles.right.addEventListener('mousedown', (e) => startResize('right', e));
|
||||
handles.top.addEventListener('mousedown', (e) => startResize('top', e));
|
||||
handles.bottom.addEventListener('mousedown', (e) => startResize('bottom', e));
|
||||
handles.topLeft.addEventListener('mousedown', (e) => startResize('top-left', e));
|
||||
handles.topRight.addEventListener('mousedown', (e) => startResize('top-right', e));
|
||||
handles.bottomLeft.addEventListener('mousedown', (e) => startResize('bottom-left', e));
|
||||
handles.bottomRight.addEventListener('mousedown', (e) => startResize('bottom-right', e));
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState('app', ['showAICallMinimized']),
|
||||
showMinimizedWindow() {
|
||||
// 只有在Vuex状态为true时才显示最小化窗口
|
||||
return this.showAICallMinimized;
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
openImg,
|
||||
AIContent: '',
|
||||
isLoading: false,
|
||||
windowState: 'maximized', // 'maximized' 或 'minimized'
|
||||
messageList: [
|
||||
{
|
||||
typing:true,
|
||||
isBot: true, // 是否为机器人
|
||||
text: `<p><b>您好!我是京东方案侧智能问答助手,随时为您服务。</b></p>
|
||||
text: `<p><b>您好!我是京东方案例智能问答助手,随时为您服务。</b></p>
|
||||
<p>我可以帮您快速查找和解读平台内的各类案例内容。只需输入您想了解的问题或关键词,我会从案例库中精准匹配相关信息,并提供清晰的解答。每条回答都会附上来源链接,方便您随时查阅原始案例全文。</p>
|
||||
<p>我还会根据您的提问,智能推荐相关延伸问题,助您更高效地探索知识、解决问题。</p>
|
||||
<p>现在,欢迎随时向我提问,开启高效的知识查询体验吧!</p>`
|
||||
}
|
||||
],
|
||||
suggestions:[],
|
||||
isAutoScroll: true // 是否自动滚动
|
||||
isAutoScroll: true, // 是否自动滚动
|
||||
// 添加一个标志位,用于标识组件是否已经初始化完成
|
||||
isComponentReady: false
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// 组件挂载完成后,标记为已准备就绪
|
||||
this.$nextTick(() => {
|
||||
this.isComponentReady = true;
|
||||
});
|
||||
},
|
||||
watch: {
|
||||
dialogVisible: {
|
||||
handler(newVal) {
|
||||
console.log('dialogVisible发生变化');
|
||||
console.log(newVal);
|
||||
console.log(this.windowState);
|
||||
if (newVal) {
|
||||
this.$nextTick(() => {
|
||||
// 获取对话框元素
|
||||
const dialogEl = document.querySelector('.case-expert-dialog .el-dialog');
|
||||
if (dialogEl) {
|
||||
// 检查是否有保存的尺寸状态
|
||||
const savedSize = sessionStorage.getItem('aiCallDialogSize');
|
||||
if (savedSize) {
|
||||
const { width, height, left, top } = JSON.parse(savedSize);
|
||||
dialogEl.style.width = width + 'px';
|
||||
dialogEl.style.height = height + 'px';
|
||||
dialogEl.style.left = left + 'px';
|
||||
dialogEl.style.top = top + 'px';
|
||||
}
|
||||
|
||||
// 检查是否有保存的位置状态
|
||||
// const savedPosition = sessionStorage.getItem('aiCallDialogPosition');
|
||||
// if (savedPosition) {
|
||||
// const { left, top } = JSON.parse(savedPosition);
|
||||
// dialogEl.style.left = left + 'px';
|
||||
// dialogEl.style.top = top + 'px';
|
||||
// }
|
||||
}
|
||||
|
||||
let doc = document.querySelector('.welcome-message')
|
||||
let sendBox = document.querySelector('.input-area-wrapper');
|
||||
// 只有在没有保存的尺寸状态时才使用默认值
|
||||
if (doc && sendBox) {
|
||||
const savedSize = sessionStorage.getItem('aiCallDialogSize');
|
||||
if (!savedSize) {
|
||||
doc.style.height = `calc(600px - ${sendBox.offsetHeight}px - 120px)`;
|
||||
} else {
|
||||
const { height } = JSON.parse(savedSize);
|
||||
doc.style.height = `calc(${height}px - ${sendBox.offsetHeight}px - 120px)`;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
messageList: {
|
||||
handler() {
|
||||
this.$nextTick(() => {
|
||||
this.scrollToBottom();
|
||||
});
|
||||
// 只有在组件准备就绪后才执行滚动操作
|
||||
if (this.isComponentReady) {
|
||||
this.$nextTick(() => {
|
||||
this.scrollToBottom();
|
||||
});
|
||||
}
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// / 关闭最小化窗口
|
||||
closeMinimizedWindow() {
|
||||
this.$store.commit('app/SET_SHOW_AI_CALL_MINIMIZED', false);
|
||||
this.$store.commit('app/SET_SHOW_AI_CALL', false);
|
||||
this.windowState = 'maximized';
|
||||
},
|
||||
getMinWidow(vis){
|
||||
// this.showAICallMinimized = vis
|
||||
this.windowState = 'minimized';
|
||||
},
|
||||
onClose() {
|
||||
console.log('关闭弹窗')
|
||||
// 清除保存的状态
|
||||
sessionStorage.removeItem('aiCallDialogSize');
|
||||
// sessionStorage.removeItem('aiCallDialogPosition');
|
||||
this.$emit('close')
|
||||
// 可以在这里执行其他逻辑
|
||||
},
|
||||
|
||||
minimizeWindow() {
|
||||
this.windowState = 'minimized';
|
||||
this.$store.commit('app/SET_SHOW_AI_CALL_MINIMIZED', true);
|
||||
},
|
||||
|
||||
maximizeWindow() {
|
||||
this.windowState = 'maximized';
|
||||
},
|
||||
|
||||
getLastUserMessage() {
|
||||
// 从后往前找用户消息
|
||||
for (let i = this.messageList.length - 1; i >= 0; i--) {
|
||||
if (!this.messageList[i].isBot) {
|
||||
// 移除HTML标签只返回纯文本
|
||||
const tempDiv = document.createElement('div');
|
||||
tempDiv.innerHTML = this.messageList[i].text;
|
||||
return tempDiv.textContent || tempDiv.innerText || '';
|
||||
}
|
||||
}
|
||||
return '';
|
||||
},
|
||||
|
||||
// 处理加载状态
|
||||
handleLoading(status) {
|
||||
console.log('handleLoading---'+status);
|
||||
this.isLoading = status;
|
||||
},
|
||||
|
||||
@@ -131,10 +619,13 @@ export default {
|
||||
},500)
|
||||
},
|
||||
startNewConversation() {
|
||||
// 重置对话时,先标记组件为未准备就绪状态
|
||||
this.isComponentReady = false;
|
||||
|
||||
this.messageList = [
|
||||
{
|
||||
isBot: true,
|
||||
text: `<p><b>您好!我是京东方案侧智能问答助手,随时为您服务。</b></p>
|
||||
text: `<p><b>您好!我是京东方案例智能问答助手,随时为您服务。</b></p>
|
||||
<p>我可以帮您快速查找和解读平台内的各类案例内容。只需输入您想了解的问题或关键词,我会从案例库中精准匹配相关信息,并提供清晰的解答。每条回答都会附上来源链接,方便您随时查阅原始案例全文。</p>
|
||||
<p>我还会根据您的提问,智能推荐相关延伸问题,助您更高效地探索知识、解决问题。</p>
|
||||
<p>现在,欢迎随时向我提问,开启高效的知识查询体验吧!</p>`
|
||||
@@ -142,6 +633,11 @@ export default {
|
||||
];
|
||||
this.AIContent = '';
|
||||
this.isLoading = false;
|
||||
|
||||
// 在下一个 tick 中重新标记为准备就绪
|
||||
this.$nextTick(() => {
|
||||
this.isComponentReady = true;
|
||||
});
|
||||
},
|
||||
|
||||
// 处理滚动事件
|
||||
@@ -160,21 +656,66 @@ export default {
|
||||
if (this.isAutoScroll && this.$refs.messageContainer) {
|
||||
this.$refs.messageContainer.scrollTop = this.$refs.messageContainer.scrollHeight;
|
||||
}
|
||||
},
|
||||
|
||||
// 处理鼠标滚轮事件
|
||||
handleWheel(event) {
|
||||
const element = this.$refs.messageContainer;
|
||||
if (!element) return;
|
||||
|
||||
// 阻止事件冒泡,防止滚动底层页面
|
||||
event.stopPropagation();
|
||||
|
||||
// 计算滚动方向和距离
|
||||
const delta = event.deltaY || event.detail || event.wheelDelta;
|
||||
|
||||
// 检查是否可以继续滚动
|
||||
if (delta < 0 && element.scrollTop === 0) {
|
||||
// 向上滚动且已在顶部,阻止默认行为
|
||||
event.preventDefault();
|
||||
} else if (delta > 0 && element.scrollHeight - element.scrollTop <= element.clientHeight) {
|
||||
// 向下滚动且已在底部,阻止默认行为
|
||||
event.preventDefault();
|
||||
} else {
|
||||
// 允许在容器内滚动
|
||||
element.scrollTop += delta;
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
|
||||
// 最小化窗口的点击事件处理方法
|
||||
onMinimizedWindowClick() {
|
||||
// 当点击最小化窗口时,如果dialogVisible为false,则通过事件通知父组件显示对话框
|
||||
if (!this.dialogVisible) {
|
||||
this.$emit('restore');
|
||||
}
|
||||
// 然后将窗口状态设置为最大化
|
||||
this.windowState = 'maximized';
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
::v-deep .el-dialog__wrapper{
|
||||
position: unset!important;
|
||||
}
|
||||
.case-expert-dialog {
|
||||
::v-deep .el-dialog{
|
||||
background: url("./components/u762.svg") no-repeat ;
|
||||
background-size: cover;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
pointer-events: auto;
|
||||
z-index: 2000;
|
||||
|
||||
//background-color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
::v-deep .el-dialog__body{
|
||||
padding: 10px;
|
||||
flex:1;
|
||||
//font-size: 12px;
|
||||
*{
|
||||
font-size:unset ;
|
||||
@@ -185,15 +726,24 @@ export default {
|
||||
background: transparent;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
padding-right: 20px;
|
||||
cursor: move; /* 添加拖动样式 */
|
||||
|
||||
.icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.window-control-btn {
|
||||
font-size: 18px;
|
||||
padding: 5px 10px;
|
||||
color: #333; /* 黑色图标 */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -214,7 +764,8 @@ export default {
|
||||
padding: 20px;
|
||||
background-color: transparent;
|
||||
border-radius: 8px;
|
||||
height: 550px;
|
||||
min-height: 500px;
|
||||
height:100%;
|
||||
position: relative;
|
||||
//margin-bottom: 20px;
|
||||
display: flex;
|
||||
@@ -225,7 +776,8 @@ export default {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 10px;
|
||||
flex:1;
|
||||
height: 400px;
|
||||
//flex:1;
|
||||
overflow-y: auto;
|
||||
|
||||
.avatar {
|
||||
@@ -310,4 +862,45 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.minimized-window {
|
||||
position: fixed;
|
||||
right: 20px;
|
||||
bottom: 20px;
|
||||
width: 300px;
|
||||
background: url("./components/u762.svg") no-repeat;
|
||||
background-size: cover;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
z-index: 2000;
|
||||
cursor: pointer;
|
||||
|
||||
.minimized-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10px 15px;
|
||||
border-bottom: 1px solid #eee;
|
||||
|
||||
.window-title {
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.window-control-btn {
|
||||
font-size: 16px;
|
||||
padding: 3px 8px;
|
||||
color: #000000; /* 黑色图标 */
|
||||
}
|
||||
}
|
||||
|
||||
.minimized-message {
|
||||
padding: 15px;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
min-height: 60px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
63
src/views/portal/case/components/AICaseConsult.vue
Normal file
63
src/views/portal/case/components/AICaseConsult.vue
Normal file
@@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="AI-case" style="position: relative; margin-bottom: 10px;" v-if="showAiCase" @click.stop="getAICase()">
|
||||
<img src="../../../../../public/images/case-logo.png" alt="">
|
||||
<span @click="getAICase()" style="position: absolute; bottom: 65px;left: 15px;z-index: 1;width: 40%;height: 30px;"></span>
|
||||
</div>
|
||||
<!-- 移除直接使用的AICall组件 -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { showCaseAiEntrance } from '@/api/boe/aiChat.js'
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'AICaseConsult',
|
||||
data() {
|
||||
return {
|
||||
showAiCase: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 从Vuex中获取showAICall状态(虽然当前组件不使用,但保持连接)
|
||||
...mapState('app', ['showAICall'])
|
||||
},
|
||||
mounted() {
|
||||
this.getShowAiCase()
|
||||
},
|
||||
methods: {
|
||||
// 是否展示入口
|
||||
getShowAiCase() {
|
||||
showCaseAiEntrance().then(res => {
|
||||
this.showAiCase = res.result
|
||||
})
|
||||
},
|
||||
// 案例立即咨询
|
||||
getAICase() {
|
||||
// 通过Vuex控制AICall组件显示
|
||||
this.$store.dispatch('app/setShowAICall', true)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.AI-case {
|
||||
margin-bottom: 10px;
|
||||
position: relative;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
span {
|
||||
width: 160px;
|
||||
height: 40px;
|
||||
position: absolute;
|
||||
left: 20px;
|
||||
top: 105px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,160 +1,223 @@
|
||||
<!--消息渲染-->
|
||||
<template>
|
||||
<div class="messages">
|
||||
<!-- 机器人消息 -->
|
||||
<div v-if="messageData.isBot" class="bot-message">
|
||||
<!-- 思考中提示 -->
|
||||
<div v-if="messageData.thinkText" class="bot-think" v-katex:auto v-html="md.render(messageData.thinkText)"></div>
|
||||
|
||||
<!-- 主要回复内容 -->
|
||||
<div
|
||||
ref="contentContainer"
|
||||
class="message-content"
|
||||
v-katex:auto
|
||||
v-html="md.render(displayText)"
|
||||
></div>
|
||||
|
||||
<!-- 引用案例 -->
|
||||
<div v-if="messageData.caseRefers && messageData.caseRefers.length > 0 && messageData.textCompleted" class="case-refers">
|
||||
<div class="case-refers-title">
|
||||
<span><i class="iconfont icon-think"></i> 引用案例</span>
|
||||
<span v-if="shouldShowMoreButton" class="more" @click="toggleShowAllCaseRefers">
|
||||
{{ showAllCaseRefers ? '收起' : '查看更多' }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="case-refers-list">
|
||||
<div
|
||||
v-for="item in displayedCaseRefers"
|
||||
:key="item.caseId"
|
||||
class="case-refers-item"
|
||||
>
|
||||
<div class="case-refers-item-title">
|
||||
<a @click="toUrl(item)" class="title">{{ item.title }}</a>
|
||||
<span class="case-refers-item-timer">{{ item.uploadTime }}</span>
|
||||
</div>
|
||||
<div class="case-refers-item-author">
|
||||
<span class="user"></span>
|
||||
<span>{{ item.authorName }}</span>
|
||||
<span class="case-inter-orginInfo">{{ item.orgInfo }}</span>
|
||||
</div>
|
||||
<div class="case-refers-item-keywords">
|
||||
<span v-for="keyword in item.keywords" :key="keyword">{{ keyword }}</span>
|
||||
</div>
|
||||
<div class="message-content case-content" v-html="md.render(item.content)"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 用户消息 -->
|
||||
<div v-else class="user-message">
|
||||
<div class="message-text" v-html="messageData.text"></div>
|
||||
</div>
|
||||
|
||||
<!-- 推荐问题 -->
|
||||
<!-- <div v-if="suggestions && suggestions.length > 0" class="suggestions">-->
|
||||
<!-- <div class="suggestions-title">💡 推荐问题</div>-->
|
||||
<!-- <div class="suggestions-list">-->
|
||||
<!-- <button-->
|
||||
<!-- v-for="(item, index) in suggestions"-->
|
||||
<!-- :key="index"-->
|
||||
<!-- class="suggestions-item"-->
|
||||
<!-- @click="$emit('suggestion-click', item)"-->
|
||||
<!-- >-->
|
||||
<!-- {{ item }}-->
|
||||
<!-- </button>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MarkdownIt from 'markdown-it';
|
||||
import highlight from 'markdown-it-highlightjs';
|
||||
import 'highlight.js/styles/a11y-dark.css';
|
||||
import markdownItMermaid from 'markdown-it-mermaid';
|
||||
import mermaid from 'mermaid';
|
||||
|
||||
// 初始化 Mermaid
|
||||
mermaid.initialize({ startOnLoad: false });
|
||||
|
||||
const md = new MarkdownIt({
|
||||
html: true,
|
||||
linkify: true,
|
||||
typographer: true,
|
||||
});
|
||||
|
||||
md.use(highlight).use(markdownItMermaid);
|
||||
|
||||
export default {
|
||||
name: "message",
|
||||
name: 'Message',
|
||||
props: {
|
||||
messageData: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {}
|
||||
}
|
||||
required: true,
|
||||
default: () => ({}),
|
||||
},
|
||||
suggestions: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
md,
|
||||
displayText: '',
|
||||
typingTimer: null,
|
||||
typingSpeed: 30, // 打字机速度(毫秒/字符)
|
||||
showAllCaseRefers: false // 控制是否显示所有案例引用
|
||||
}
|
||||
typingSpeed: 30, // 毫秒/字符
|
||||
showAllCaseRefers: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
// 计算需要显示的案例引用
|
||||
displayedCaseRefers() {
|
||||
if (this.showAllCaseRefers || !this.messageData.caseRefers) {
|
||||
return this.messageData.caseRefers || [];
|
||||
}
|
||||
return this.messageData.caseRefers.slice(0, 3);
|
||||
},
|
||||
// 判断是否需要显示"查看更多"按钮
|
||||
shouldShowMoreButton() {
|
||||
return this.messageData.caseRefers && this.messageData.caseRefers.length > 3;
|
||||
}
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
'messageData.text': {
|
||||
handler(newVal) {
|
||||
if (newVal && this.messageData.isBot && !this.messageData.typing) {
|
||||
// this.startTyping(newVal)
|
||||
if (!newVal) {
|
||||
this.displayText = '';
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.messageData.isBot && !this.messageData.typing) {
|
||||
// this.startTyping(newVal); // 启动打字机效果/**/
|
||||
|
||||
this.displayText = newVal || ''
|
||||
} else {
|
||||
this.displayText = newVal || ''
|
||||
this.displayText = this.md.render(newVal);
|
||||
this.$nextTick(this.renderMermaid); // 直接渲染 Mermaid
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
immediate: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
startTyping(text) {
|
||||
// 清除之前的定时器
|
||||
toUrl(item) {
|
||||
this.$router.push({
|
||||
path: '/case/detail',
|
||||
query: { id: item.caseId },
|
||||
});
|
||||
|
||||
|
||||
this.$emit('getMinWindow')
|
||||
},
|
||||
|
||||
// 正确的打字机效果:先整体渲染 Markdown,再逐字显示 HTML
|
||||
startTyping(fullText) {
|
||||
const renderedText = this.md.render(fullText);
|
||||
this.displayText = '';
|
||||
let index = 0;
|
||||
|
||||
if (this.typingTimer) {
|
||||
clearInterval(this.typingTimer)
|
||||
this.typingTimer = null
|
||||
clearInterval(this.typingTimer);
|
||||
}
|
||||
|
||||
// 初始化
|
||||
// this.displayText = ''
|
||||
let index = 0
|
||||
|
||||
// 开始打字机效果
|
||||
this.typingTimer = setInterval(() => {
|
||||
if (index < text.length) {
|
||||
this.displayText += text.charAt(index)
|
||||
index++
|
||||
if (index < renderedText.length) {
|
||||
this.displayText += renderedText[index];
|
||||
index++;
|
||||
} else {
|
||||
// 打字完成,清除定时器
|
||||
clearInterval(this.typingTimer)
|
||||
this.typingTimer = null
|
||||
clearInterval(this.typingTimer);
|
||||
this.typingTimer = null;
|
||||
this.$nextTick(this.renderMermaid); // 渲染 Mermaid 图表
|
||||
}
|
||||
}, this.typingSpeed)
|
||||
}, this.typingSpeed);
|
||||
},
|
||||
// 切换显示所有案例引用
|
||||
|
||||
// 触发 Mermaid 渲染
|
||||
renderMermaid() {
|
||||
this.$nextTick(() => {
|
||||
const mermaidEls = this.$el.querySelectorAll('.mermaid');
|
||||
if (mermaidEls.length > 0) {
|
||||
try {
|
||||
// mermaid 8.x 版本使用 init 方法而不是 run
|
||||
if (typeof mermaid.init === 'function') {
|
||||
mermaid.init(undefined, '.mermaid');
|
||||
} else if (mermaid.default && typeof mermaid.default.init === 'function') {
|
||||
mermaid.default.init(undefined, '.mermaid');
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Mermaid 渲染失败:', e);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 切换案例引用显示数量
|
||||
toggleShowAllCaseRefers() {
|
||||
this.showAllCaseRefers = !this.showAllCaseRefers;
|
||||
}
|
||||
// 切换后重新渲染 Mermaid(如果内容中有图表)
|
||||
this.$nextTick(this.renderMermaid);
|
||||
},
|
||||
},
|
||||
beforeDestroy() {
|
||||
// 组件销毁前清除定时器
|
||||
if (this.typingTimer) {
|
||||
clearInterval(this.typingTimer)
|
||||
this.typingTimer = null
|
||||
clearInterval(this.typingTimer);
|
||||
this.typingTimer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="messages">
|
||||
{{messageData}}
|
||||
<!-- 机器人消息-->
|
||||
<div v-if="messageData.isBot" class="bot-message">
|
||||
<div class="bot-think" v-if="messageData.thinkText" v-html="messageData.thinkText"></div>
|
||||
<div v-html="displayText" ></div>
|
||||
<div v-if="messageData.caseRefers && messageData.caseRefers.length > 0 && messageData.textCompleted">
|
||||
<div class="case-refers">
|
||||
<div class="case-refers-title">
|
||||
<span> <i class="iconfont icon-think"></i> 引用案例</span>
|
||||
<span v-if="shouldShowMoreButton" class="more" @click="toggleShowAllCaseRefers">
|
||||
{{ showAllCaseRefers ? '收起' : '查看更多' }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="case-refers-list">
|
||||
<div class="case-refers-item" v-for="item in displayedCaseRefers" :key="item.caseId">
|
||||
<div class="case-refers-item-title">
|
||||
<a :href="'#case-' + item.caseId" class="title">{{ item.title }}</a>
|
||||
<span class="case-refers-item-timer">{{item.uploadTime}}</span>
|
||||
</div>
|
||||
<div class="case-refers-item-author">
|
||||
<span class="user"></span>
|
||||
<span>{{ item.authorName }}</span>
|
||||
<span class="case-inter-orginInfo">{{ item.orgInfo }}</span>
|
||||
</div>
|
||||
<div class="case-refers-item-keywords">
|
||||
<span v-for="keyword in item.keywords" :key="keyword">{{ keyword }}</span>
|
||||
</div>
|
||||
|
||||
<div class="message-content">{{item.content}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 非机器人消息-->
|
||||
<div v-else class="user-message">
|
||||
<div class="message-text">
|
||||
<div v-html="messageData.text"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 推荐问题-->
|
||||
|
||||
<!-- <div v-if="suggestions && suggestions.length > 0">-->
|
||||
<!-- <div class="suggestions">-->
|
||||
<!-- <div class="suggestions-title">-->
|
||||
<!-- <span>推荐问题</span>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="suggestions-list">-->
|
||||
<!-- <div class="suggestions-item" v-for="item in suggestions">-->
|
||||
<!-- <div class="suggestions-item-title">-->
|
||||
<!-- {{item}}-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
::v-deep .mermaid{
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
::v-deep svg[id^="mermaid-"]{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.messages {
|
||||
width: 100%;
|
||||
word-wrap: break-word;
|
||||
|
||||
.bot-message {
|
||||
background-color: #fff;
|
||||
@@ -176,125 +239,185 @@ export default {
|
||||
left: 0;
|
||||
top: -3px;
|
||||
transform: scaleX(0.5);
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.case-refers {
|
||||
margin-top: 10px;
|
||||
.message-content {
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.case-refers-title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
.icon-think {
|
||||
background-image: url("./map.svg") ;
|
||||
width: 15px;
|
||||
height: 13px;
|
||||
display: inline-block;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
.more{
|
||||
font-size: 10px;
|
||||
padding: 2px 6px;
|
||||
background-color: #F4F7FD;
|
||||
border-radius: 5px;
|
||||
color:#577EE1;font-weight: unset;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.case-refers-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
|
||||
.case-refers-item {
|
||||
//margin-right: 10px;
|
||||
margin-bottom: 5px;
|
||||
border: 1px solid rgba(144, 147, 153, 0.44);
|
||||
padding: 5px;
|
||||
border-radius: 5px;
|
||||
|
||||
.case-refers-item-title {
|
||||
font-size: 14px;
|
||||
margin-bottom: 5px;
|
||||
font-weight: 600;
|
||||
color: #000;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
.title{
|
||||
max-width: 70% ;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
|
||||
|
||||
}
|
||||
.case-refers-item-timer{
|
||||
font-size: 10px;
|
||||
margin-right: 20px;
|
||||
color:#cecece;
|
||||
font-weight: unset!important;
|
||||
}
|
||||
}
|
||||
.case-refers-item-author{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.user{
|
||||
background-image: url("./user.svg");
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
display: inline-block;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.case-inter-orginInfo{
|
||||
font-size: 10px;
|
||||
color: rgba(144, 147, 153, 0.44);margin-left: 5px;
|
||||
|
||||
}
|
||||
}
|
||||
.case-refers-item-author,
|
||||
.case-refers-item-keywords {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
}
|
||||
.case-content {
|
||||
font-size: 12px !important;
|
||||
margin-top: 8px;
|
||||
padding: 6px 10px;
|
||||
//background-color: #f9f9f9;
|
||||
border-radius: 4px;
|
||||
//border: 1px solid #eee;
|
||||
}
|
||||
}
|
||||
|
||||
.user-message {
|
||||
float: right;
|
||||
padding: 5px 15px;
|
||||
box-sizing: border-box;
|
||||
background-color: rgba(228, 231, 237, 1);
|
||||
padding: 8px 15px;
|
||||
max-width: 80%;
|
||||
background-color: #e4e7ed;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 10px;
|
||||
font-size: 14px;
|
||||
word-break: break-word;
|
||||
}
|
||||
.case-refers-item-keywords{
|
||||
margin-top: 5px;
|
||||
span{
|
||||
padding: 1px 4px;
|
||||
background-color: #F4F7FD;
|
||||
border-radius: 5px;
|
||||
font-size: 10px!important;
|
||||
color:#577EE1
|
||||
|
||||
/* ========== 案例引用样式 ========== */
|
||||
.case-refers {
|
||||
margin-top: 12px;
|
||||
|
||||
.case-refers-title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
color: #333;
|
||||
|
||||
.icon-think {
|
||||
background-image: url('./map.svg');
|
||||
width: 15px;
|
||||
height: 13px;
|
||||
display: inline-block;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.more {
|
||||
font-size: 12px;
|
||||
padding: 2px 8px;
|
||||
background-color: #f4f7fd;
|
||||
border-radius: 5px;
|
||||
color: #577ee1;
|
||||
font-weight: normal;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
span + span{
|
||||
margin-left: 8px;
|
||||
|
||||
.case-refers-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
|
||||
.case-refers-item {
|
||||
border: 1px solid rgba(144, 147, 153, 0.44);
|
||||
padding: 8px;
|
||||
border-radius: 6px;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
|
||||
.case-refers-item-title {
|
||||
font-size: 14px;
|
||||
margin-bottom: 6px;
|
||||
font-weight: 600;
|
||||
color: #000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.title {
|
||||
max-width: 70%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
color: #000;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.case-refers-item-timer {
|
||||
font-size: 11px;
|
||||
color: #aaa;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.case-refers-item-author {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
color: #555;
|
||||
margin-bottom: 5px;
|
||||
|
||||
.user {
|
||||
background-image: url('./user.svg');
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
display: inline-block;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.case-inter-orginInfo {
|
||||
font-size: 11px;
|
||||
color: #999;
|
||||
margin-left: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.case-refers-item-keywords {
|
||||
margin-top: 4px;
|
||||
font-size: 12px;
|
||||
|
||||
span {
|
||||
padding: 2px 6px;
|
||||
background-color: #f4f7fd;
|
||||
border-radius: 5px;
|
||||
font-size: 11px !important;
|
||||
color: #577ee1;
|
||||
}
|
||||
|
||||
span + span {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.message-content{
|
||||
font-size: 12px!important;
|
||||
margin-top: 5px;
|
||||
|
||||
/* ========== 推荐问题 ========== */
|
||||
.suggestions {
|
||||
margin-top: 10px;
|
||||
font-size: 14px;
|
||||
|
||||
.suggestions-title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 6px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.suggestions-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
|
||||
.suggestions-item {
|
||||
padding: 6px 10px;
|
||||
background-color: #f0f4fc;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
text-align: left;
|
||||
color: #1a73e8;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
transition: background-color 0.2s;
|
||||
|
||||
&:hover {
|
||||
background-color: #e1e8f5;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
BIN
src/views/portal/case/components/open.png
Normal file
BIN
src/views/portal/case/components/open.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 283 B |
@@ -2,10 +2,13 @@
|
||||
<div class="input-area">
|
||||
<el-input
|
||||
v-model="inputContent"
|
||||
type="textarea"
|
||||
class="input-placeholder"
|
||||
placeholder="有问题,尽管问"
|
||||
@keyup.enter.native="handleSend"
|
||||
@keyup.enter.native.prevent="handleSend"
|
||||
:disabled="disabled"
|
||||
:autosize="{ minRows: 2, maxRows: 4}"
|
||||
resize="none"
|
||||
></el-input>
|
||||
<div class="action-buttons">
|
||||
<el-button type="primary" size="small" class="start-btn" @click="handleNewConversation">
|
||||
@@ -53,7 +56,14 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleSend() {
|
||||
handleSend(event) {
|
||||
// 阻止事件的默认行为和冒泡
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
console.log('preventDefault');
|
||||
}
|
||||
console.log('handleSend');
|
||||
if (!this.inputContent.trim() || this.disabled) return
|
||||
// 添加用户消息到列表
|
||||
const userMessage = {
|
||||
@@ -91,12 +101,12 @@ export default {
|
||||
conversationId: this.conversationId,
|
||||
query: question
|
||||
};
|
||||
|
||||
// 创建POST请求
|
||||
fetch('/systemapi/xboe/m/boe/case/ai/chat',{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
"accept": "text/event-stream",
|
||||
},
|
||||
body: JSON.stringify(requestData)
|
||||
}).then(r=>{
|
||||
@@ -129,7 +139,7 @@ export default {
|
||||
return;
|
||||
}
|
||||
|
||||
const typingSpeed = 50; // 每个字符的间隔时间(毫秒)
|
||||
const typingSpeed = 30; // 每个字符的间隔时间(毫秒)
|
||||
|
||||
typingTimer = setInterval(() => {
|
||||
// 计算下一个要显示的字符索引
|
||||
@@ -230,6 +240,7 @@ export default {
|
||||
// 从响应中获取并保存conversationId
|
||||
if (jsonData.conversationId) {
|
||||
this.conversationId = jsonData.conversationId;
|
||||
sessionStorage.setItem('conversationId', jsonData.conversationId);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -310,7 +321,7 @@ export default {
|
||||
}
|
||||
aiMessage.textCompleted = true;
|
||||
this.$emit('loading', false);
|
||||
aiMessage.text = '抱歉,网络连接出现问题,请稍后重试。';
|
||||
aiMessage.text = '当前无法获取回答,请稍后重试';
|
||||
// 更新父组件的messageList
|
||||
this.$emit('update-message', aiMessage);
|
||||
});
|
||||
@@ -323,12 +334,13 @@ export default {
|
||||
// 出错时也设置文字处理完成状态
|
||||
aiMessage.textCompleted = true;
|
||||
this.$emit('loading', false);
|
||||
aiMessage.text = '抱歉,网络连接出现问题,请稍后重试。';
|
||||
aiMessage.text = '当前无法获取回答,请稍后重试';
|
||||
// 更新父组件的messageList
|
||||
this.$emit('update-message', aiMessage);
|
||||
});
|
||||
},
|
||||
handleNewConversation() {
|
||||
this.conversationId = ''
|
||||
this.$emit('new-conversation')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,13 +30,19 @@
|
||||
<!-- <div class="course-title-right"> -->
|
||||
<!-- <interactBar :readonly="!stuStusts || stuStusts==0" :type="1" :data="courseInfo" :comments="false" :views="false"></interactBar> -->
|
||||
<!-- </div> -->
|
||||
<!-- <div class="label-div">
|
||||
<el-tag class="label-item" effect="plain" v-for="(item,tagIdx) in tagArray" :key="tagIdx">{{item}}</el-tag>
|
||||
</div>-->
|
||||
<div class="label-div">
|
||||
<div v-for="(item, tagIdx) in tagArray" :key="tagIdx" class="keyword-tag">
|
||||
{{ item }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="study-count">{{courseInfo.studys}}人学习</div>
|
||||
<!-- <div><span style="font-size:20px;color:#ff8e00">{{courseInfo.score ? courseInfo.score.toFixed(1) : 0}}</span><span style="font-size:12px;color:#ff8e00">分</span></div> -->
|
||||
</div>
|
||||
<div class="label-div">
|
||||
<el-tag class="label-item" effect="plain" v-for="(item,tagIdx) in tagArray" :key="tagIdx">{{item}}</el-tag>
|
||||
</div>
|
||||
|
||||
<!-- <div style="width:160px;height:50px"> -->
|
||||
<!-- </div> -->
|
||||
<!-- <div class="label-div">
|
||||
@@ -419,7 +425,7 @@ export default {
|
||||
|
||||
.course-title{
|
||||
position: relative;
|
||||
height: 90px;
|
||||
height: auto;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.title {
|
||||
@@ -452,18 +458,43 @@ export default {
|
||||
padding: 24px 24px 5px 24px;
|
||||
// margin-right: 361px;
|
||||
.study-count {
|
||||
margin-top: 10px;
|
||||
margin-top: 30px;
|
||||
font-size: 16px;
|
||||
color: #444444;
|
||||
}
|
||||
|
||||
.label-div {
|
||||
/*.label-div {
|
||||
margin: 5px 0;
|
||||
min-height: 20px;
|
||||
.label-item {
|
||||
padding: 0 7px;
|
||||
padding: 0px 8px;
|
||||
margin-top: 5px;
|
||||
float: left;
|
||||
line-height: 24px;
|
||||
font-size: 12px;
|
||||
border-radius: 2px;
|
||||
margin-right: 8px;
|
||||
margin-bottom: 0px;
|
||||
color: #2C68FF;
|
||||
height: 24px;
|
||||
background: rgba(44, 104, 255, 0.06);
|
||||
border: none; // 或者使用 border-color: transparent;
|
||||
}
|
||||
}*/
|
||||
.label-div {
|
||||
margin: 5px 0;
|
||||
min-height: 20px;
|
||||
|
||||
.keyword-tag {
|
||||
padding: 0px 10px;
|
||||
margin-top: 7px;
|
||||
float: left;
|
||||
line-height: 24px;
|
||||
font-size: 12px;
|
||||
border-radius: 2px;
|
||||
margin-right: 10px;
|
||||
color: #2C68FF;
|
||||
height: 24px;
|
||||
background: rgba(44, 104, 255, 0.06);
|
||||
}
|
||||
}
|
||||
::v-deep .el-rate__icon {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
389
src/views/tag/TagManageList.vue
Normal file
389
src/views/tag/TagManageList.vue
Normal file
@@ -0,0 +1,389 @@
|
||||
<template>
|
||||
<div class="u-page" style="padding-right:32px">
|
||||
<div style="width: 100%; margin-left: 12px;padding: 2px 0px 10px 12px;background-color: white">
|
||||
<el-form :inline="true" style="margin-left: 12px;" :model="pageData" class="demo-form-inline">
|
||||
<el-form-item label="标签ID:" label-width="60px">
|
||||
<el-input id="tag-id" placeholder="请输入标签ID" v-model="pageData.id" clearable />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="标签名称:" label-width="80px">
|
||||
<el-input id="tag-id" placeholder="请输入标签名称" v-model="pageData.tagName" clearable />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="热点标签:" label-width="80px">
|
||||
<el-select v-model="pageData.isHot" style="width: 120px;" clearable placeholder="请选择状态">
|
||||
<el-option label="开启" value="true"></el-option>
|
||||
<el-option label="关闭" value="false"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button @click="getsearch" icon="el-icon-search" type="primary">查询</el-button>
|
||||
<!-- 添加重置按钮 -->
|
||||
<el-button @click="resetSearch" icon="el-icon-refresh">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div style="padding: 5px 0px 2px 12px;">
|
||||
<!-- <el-checkbox label="前台公共显示"></el-checkbox>-->
|
||||
<!-- <el-checkbox label="热点标签展示"></el-checkbox>-->
|
||||
</div>
|
||||
|
||||
<div style="width: 100%; margin-left: 12px;padding: 2px 0px 10px 12px;background-color: white">
|
||||
<el-table style="width: 96%; margin:2px 32px 10px 12px;" :data="pageData.list" border stripe
|
||||
:header-cell-style="{ background: '#E9F0FF' }"
|
||||
@selection-change="handleSelectionChange"
|
||||
@sort-change="handleSortChange">
|
||||
<el-table-column type="selection" width="80px"></el-table-column>
|
||||
<el-table-column label="标签ID" width="200px" prop="id"></el-table-column>
|
||||
<el-table-column label="标签名称" width="235px" prop="tagName"></el-table-column>
|
||||
<el-table-column label="已关联课程" width="220px"
|
||||
prop="useCount"
|
||||
sortable="custom"
|
||||
:sort-orders="['descending', 'ascending']"
|
||||
>
|
||||
<template #default="scope">
|
||||
<a v-if="scope.row.useCount > 0"
|
||||
@click="showCourseByTag(`${scope.row.id}`)"
|
||||
style="font-weight:bold; color: #409EFF; text-decoration: underline;">
|
||||
{{ scope.row.useCount }}
|
||||
</a>
|
||||
<span style="font-weight:bold; color: #409EFF; text-decoration: underline;" v-else>0</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="前台公共显示" width="220px" prop="isPublic">
|
||||
<template #default="scope"><!-- 开关状态会直接修改 pageData.list 中的数据 -->
|
||||
<el-switch
|
||||
v-model="scope.row.isPublic"
|
||||
:disabled="scope.row.isHot==1?true:false"
|
||||
@change="handlePublicChange(scope.row)"
|
||||
>
|
||||
</el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="热点标签展示" width="220px" prop="isHot">
|
||||
<template #default="scope">
|
||||
<el-switch
|
||||
v-model="scope.row.isHot"
|
||||
:disabled="scope.row.isPublic==0?true:false"
|
||||
@change="handleHotChange(scope.row)"
|
||||
>
|
||||
</el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div v-if="pageData.list.length > 0" style="text-align: center;margin-top: 50px;">
|
||||
<el-pagination
|
||||
background
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="pageData.pageIndex"
|
||||
:page-sizes="[10, 20, 30, 40]"
|
||||
:page-size="pageData.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
></el-pagination>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 标签关联课程弹窗 -->
|
||||
<el-dialog custom-class="g-dialog" title="关联课程"
|
||||
width="850px" top="20px"
|
||||
:visible.sync="dialogVisible"
|
||||
:modal-append-to-body="true"
|
||||
:append-to-body="true">
|
||||
<div class="dialog-content-container">
|
||||
<el-table
|
||||
:data="pageData.list2"
|
||||
border stripe style="width: 100%"
|
||||
:header-cell-style="{ background: '#E9F0FF' }"
|
||||
@sort-change="handleSortChange2">
|
||||
<el-table-column label="序号" width="60px" align="center">
|
||||
<template #default="scope">
|
||||
{{ scope.$index + 1 }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="关联课程名称" width="200px" prop="courseName"></el-table-column>
|
||||
<el-table-column label="关联课程ID" width="100px" prop="courseId"></el-table-column>
|
||||
<el-table-column label="关联人" width="80px" prop="sysCreateBy"></el-table-column>
|
||||
<el-table-column label="关联时间" width="110px" prop="sysCreateTime"
|
||||
:formatter="dateFormat" sortable="custom"
|
||||
:sort-orders="['descending', 'ascending']"></el-table-column>
|
||||
<el-table-column label="本课程绑定的其他标签" width="200px" prop="otherTags"></el-table-column>
|
||||
<el-table-column label="操作" width="60px">
|
||||
<template #default="scope">
|
||||
<a @click="unbindCurrentTag(scope.row)"
|
||||
style="font-weight:bold; color: #409EFF;">
|
||||
解绑
|
||||
</a>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页 -->
|
||||
<div v-if="pageData.list2.length > 0" class="pagination-container">
|
||||
<el-pagination
|
||||
background
|
||||
@size-change="handleSizeChange2"
|
||||
@current-change="handleCurrentChange2"
|
||||
:current-page="pageData.pageIndex2"
|
||||
:page-sizes="[10, 20, 30, 40]"
|
||||
:page-size="pageData.pageSize2"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total2">
|
||||
</el-pagination>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'moment';
|
||||
import apiCourseTag from '@/api/modules/courseTag.js'
|
||||
import { mapGetters } from 'vuex';
|
||||
export default {
|
||||
name: 'courseTagItems',
|
||||
computed: {
|
||||
...mapGetters(['userInfo'])
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pageData: {
|
||||
pageIndex: 1,
|
||||
pageIndex2: 1,
|
||||
pageSize: 10,
|
||||
pageSize2: 10,
|
||||
list:[],
|
||||
list2:[],
|
||||
orderField: null,
|
||||
orderAsc: null,
|
||||
orderField2: null,
|
||||
orderAsc2: null,
|
||||
},
|
||||
total: 0,
|
||||
total2: 0,
|
||||
dialogVisible: false,
|
||||
tagId: null,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getCourseTagList()
|
||||
},
|
||||
methods: {
|
||||
|
||||
//重置搜索条件
|
||||
resetSearch() {
|
||||
this.pageData.id = '';
|
||||
this.pageData.tagName = '';
|
||||
this.pageData.isHot = '';
|
||||
this.pageData.pageIndex = 1;
|
||||
this.getCourseTagList(); // 重置后重新加载列表
|
||||
},
|
||||
|
||||
//初始化:课程标签列表
|
||||
getsearch(){
|
||||
this.pageData.pageIndex = 1;
|
||||
this.getCourseTagList()
|
||||
},
|
||||
|
||||
//课程标签列表:排序
|
||||
handleSortChange({ prop, order }) {
|
||||
this.pageData.orderField = prop; // 当前排序字段
|
||||
this.pageData.orderAsc = order === 'ascending'; // 排序方向
|
||||
this.getCourseTagList(); // 重新获取数据
|
||||
},
|
||||
|
||||
//TODO:课程标签列表:监听选中项变化(批量的设置标签公共显示|热点标签)
|
||||
handleSelectionChange(selection) {
|
||||
this.selectedRows = selection; // 更新选中的行数据
|
||||
},
|
||||
|
||||
//课程标签列表:获取课程标签列表数据
|
||||
getCourseTagList() {
|
||||
const { pageIndex, pageSize, orderField, orderAsc } = this.pageData
|
||||
let query = { pageIndex, pageSize, orderField, orderAsc}
|
||||
//拼接查询条件
|
||||
if (this.pageData.id) {
|
||||
const { id } = this.pageData
|
||||
query.id = id
|
||||
}
|
||||
if (this.pageData.tagName) {
|
||||
const { tagName } = this.pageData
|
||||
query.tagName = tagName
|
||||
}
|
||||
if (this.pageData.isHot) {
|
||||
const { isHot } = this.pageData
|
||||
query.isHot = isHot
|
||||
}
|
||||
apiCourseTag.portalPageList(query).then((res) => {
|
||||
if (res.status == 200) {
|
||||
this.total = res.result.count
|
||||
this.pageData.list = res.result.list
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
this.$message.error('获取数据失败')
|
||||
})
|
||||
},
|
||||
|
||||
//课程标签列表:改变标签的公共属性
|
||||
async handlePublicChange(row) {
|
||||
// 保存原始状态用于回滚
|
||||
const originalStatus = row.isPublic;
|
||||
try {
|
||||
// 调用 API 更新状态
|
||||
await apiCourseTag.changeTagPublic(row);
|
||||
this.$message.success('更新成功');
|
||||
} catch (error) {
|
||||
// 发生错误时回滚状态
|
||||
row.isPublic = originalStatus;
|
||||
this.$message.error('更新失败:' + error.message);
|
||||
}
|
||||
},
|
||||
|
||||
//课程标签列表:改变标签的热点属性
|
||||
async handleHotChange(row) {
|
||||
const isPublic=row.isPublic;
|
||||
// 保存原始状态用于回滚
|
||||
const originalStatus = row.isHot;
|
||||
try {
|
||||
// 调用 API 更新状态
|
||||
await apiCourseTag.changeTagHot(row).then((res)=>{
|
||||
if (res.status == 200){
|
||||
this.$message.success(res.message);
|
||||
}else {
|
||||
row.isHot=false;
|
||||
this.$message.warning(res.message);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
// 发生错误时回滚状态
|
||||
row.isHot = originalStatus;
|
||||
this.$message.error('更新失败:' + error.message);
|
||||
}
|
||||
},
|
||||
|
||||
//课程标签列表:改变条数的回调
|
||||
handleSizeChange(value) {
|
||||
this.pageData.pageIndex = 1;
|
||||
this.pageData.pageSize = value;
|
||||
this.getCourseTagList();
|
||||
},
|
||||
//课程标签列表:改变页数的回调
|
||||
handleCurrentChange(value) {
|
||||
this.pageData.pageIndex = value;
|
||||
this.getCourseTagList();
|
||||
},
|
||||
|
||||
//标签关联的所有课程弹出框:显示指定标签id关联的课程列表
|
||||
showCourseByTag(tagId) {
|
||||
this.tagId=tagId;
|
||||
this.getCourseOfTagList(tagId);
|
||||
this.dialogVisible=true;
|
||||
},
|
||||
|
||||
//分页查询指定标签关联的所有课程
|
||||
getCourseOfTagList(){
|
||||
const { pageIndex2:pageIndex, pageSize2:pageSize, orderField2:orderField, orderAsc2:orderAsc } = this.pageData
|
||||
let query = { pageIndex, pageSize, orderField, orderAsc }
|
||||
//拼接查询条件
|
||||
if (this.tagId) {
|
||||
query.id = this.tagId
|
||||
apiCourseTag.showCourseByTag(query).then((res) => {
|
||||
if (res.status == 200) {
|
||||
this.total2 = res.result.count
|
||||
this.pageData.list2 = res.result.list
|
||||
if (this.total2==0){
|
||||
this.dialogVisible=false
|
||||
this.getCourseTagList(); // 重新获取课程标签列表数据
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
this.$message.error('获取数据失败')
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
//标签关联课程列表:排序
|
||||
handleSortChange2({ prop, order }) {
|
||||
this.pageData.orderField2 = prop; // 当前排序字段
|
||||
this.pageData.orderAsc2 = order === 'ascending'; // 排序方向
|
||||
this.getCourseOfTagList(); // 重新获取数据
|
||||
},
|
||||
|
||||
//标签关联的所有课程列表:改变条数的回调
|
||||
handleSizeChange2(value) {
|
||||
this.pageData.pageIndex2= 1;
|
||||
this.pageData.pageSize2 = value;
|
||||
this.getCourseOfTagList();
|
||||
},
|
||||
//标签关联的所有课程列表:改变页数的回调
|
||||
handleCurrentChange2(value) {
|
||||
this.pageData.pageIndex2 = value;
|
||||
this.getCourseOfTagList();
|
||||
},
|
||||
//关联时间格式化
|
||||
dateFormat(row, column) {
|
||||
return row[column.property] ?
|
||||
moment(row[column.property]).format('YYYY-MM-DD') : '';
|
||||
},
|
||||
|
||||
//解除指定课程和当前标签的关联关系
|
||||
unbindCurrentTag (row) {
|
||||
let id = row.id;
|
||||
let tagId = this.tagId;
|
||||
let courseId = row.courseId;
|
||||
//拼接查询条件
|
||||
if (tagId && courseId) {
|
||||
let params = { id, tagId, courseId }
|
||||
apiCourseTag.unbindCourseTagRelation(params).then((res) => {
|
||||
if (res.status == 200) {
|
||||
//刷新列表
|
||||
this.getCourseOfTagList(this.tagId);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
this.$message.error('解绑失败!')
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.demo-form-inline {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px; /* 间距 */
|
||||
}
|
||||
|
||||
.demo-form-inline .el-form-item {
|
||||
margin-bottom: 0; /* 消除默认底部间距 */
|
||||
}
|
||||
|
||||
.dialog-content-container {
|
||||
padding: 10px;
|
||||
border: 1px solid #d9d9d9;
|
||||
}
|
||||
|
||||
.pagination-container {
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.g-dialog .el-dialog__header {
|
||||
background-color: #409EFF;
|
||||
padding: 15px 20px;
|
||||
}
|
||||
|
||||
.g-dialog .el-dialog__title {
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.g-dialog .el-dialog__headerbtn .el-dialog__close {
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
@@ -57,6 +57,13 @@ module.exports = {
|
||||
// set svg-sprite-loader
|
||||
config.plugins.delete('preload')
|
||||
config.plugins.delete('prefetch')
|
||||
// 添加对 mathxyjax3 的处理规则
|
||||
config.module
|
||||
.rule('mathxyjax3')
|
||||
.test(/node_modules[\/\\]mathxyjax3[\/\\].*\.js$/)
|
||||
.use('null-loader')
|
||||
.loader('null-loader')
|
||||
.end()
|
||||
config.module
|
||||
.rule('svg')
|
||||
.exclude.add(resolve('src/icons'))
|
||||
|
||||
Reference in New Issue
Block a user