接完首页和我的页接口

This commit is contained in:
田岩
2025-06-20 18:28:41 +08:00
parent 68bf17b7e2
commit c477090aea
14 changed files with 648 additions and 124 deletions
+10 -2
View File
@@ -3,6 +3,14 @@ ENV = 'development'
# 'development'
# base api
#VITE_APP_BASE_API_Url = 'http://25.18.122.66:9786'
# 苗扬
VITE_APP_BASE_API_Url = 'http://25.64.16.133:9786'
#VITE_APP_BASE_API_Url = 'http://25.64.16.133:9786'
#VITE_APP_BASE_API_Url = 'http://aitstest.jlbank.com.cn:7002'
# app入口
VITE_APP_BASE_API_Url = 'http://25.18.122.65:7001'
#VITE_APP_BASE_API_Url = 'http://25.18.122.66:9786'
+83 -3
View File
@@ -1,12 +1,92 @@
import request from '@/api/request'
// 获取首页统计数据方法
// 获取首页统计数据方法(查询个人学习统计信息
export const getStatisticsData = (data) => {
/**
userId 学员ID String
stdtTmLen 本年学习时长 double
accmPracticeCnt 累计训练次数 int
accmExamCnt 累计考试次数 int
**/
return request({
url: '/plappro/process/queryProcessList',
url: '/traapp/traStdyInfo/queryTraStdyStatisticsPerson',
method: 'post',
data,
suppressErrors:true
suppressErrors: true
});
};
// 最新课程查询接口
export const queryCrsInfoByLastnew = (data) => {
/**
crsNum 课程编号 String
crsName 课程名称 String
tagId 课程分类 String
prdLineId 生产线分类 String
issuTm 发布日期 String
imgId 课程封面ID String
accmStdyCnt 累计学习次数 int
evalGrade 课程评分 Bigdecimal
tagCataList 课程标签集 List<Object>
tagId 标签ID String
tagName 标签名称 String
**/
return request({
url: '/traapp/mycrs/queryCrsInfoByLastnew',
method: 'post',
data,
suppressErrors: true
});
};
// 热门课程查询接口
export const queryCrsInfoByPopular = (data) => {
/**
tagId 标签ID(可选填),为空时查全部 必输项:false 类型:String
出参:
tagId 标签ID(可选填),为空时查全部 必输项:false 类型:String
出参:
crsId 课程ID StringcrsNum 课程编号 String
crsName 课程名称 String
tagId 课程分类 String
prdLineId 生产线分类 String
issuTm 发布日期 String
imgId 课程封面ID String
accmStdyCnt 累计学习次数 int
evalGrade 课程评分 Bigdecimal
tagCataList 课程标签集 List<Object>
tagId 标签ID String
tagName 标签名称 String
**/
return request({
url: '/traapp/mycrs/queryCrsInfoByPopular',
method: 'post',
data,
suppressErrors: true
});
};
// 推荐课程查询接口
export const queryCrsInfoByRecmd = (data) => {
/**
crsNum 课程编号 String
crsName 课程名称 String
tagId 课程分类 String
prdLineId 生产线分类 String
issuTm 发布日期 String
imgId 课程封面ID String
accmStdyCnt 累计学习次数 int
evalGrade 课程评分 Bigdecimal
tagCataList 课程标签集 List<Object>
tagId 标签ID String
tagName 标签名称 String
**/
return request({
url: '/traapp/mycrs/queryCrsInfoByRecmd',
method: 'post',
data,
suppressErrors: true
});
};
+18 -1
View File
@@ -25,9 +25,19 @@ export const useAccountLoginApp = (data) => request({
return user_data.body
}
return Promise.reject({ rtnCode, body })
}).catch(res => {
console.log('报错s');
console.log(res);
})
// 获取个人信息
/**
* 获取个人信息
* 入参
gender F是女 M男
imageAddr 图片
loginName ID
userName 姓名
*/
export const queryCurrentUser = (data) => request({
url: '/traapp/access/queryCurrentUser',
method: 'post',
@@ -46,4 +56,11 @@ export const getLoginAppCheckCode = (data) => request({
url: '/traapp/access/checkCode',
method: 'get',
data
})
// 退出登录
export const loginOut = (data) => request({
url: '/traapp/access/loginOut',
method: 'post',
data
})
+27 -11
View File
@@ -15,6 +15,26 @@ export const get_base_url = url => {
}
}
// 请求错误码
export const REQUES_ERROR_CODES = {
NO_LOGIN: ['QQ0005', '0005'] //登录
};
// 去登录弹窗状态
let no_login_show_modal_state = false
// 去登录方法
export const goto_login_fun = () => {
// if (no_login_show_modal_state) return;
no_login_show_modal_state = true
common.hideLoading()
common.show('未登录','现在去登录').then(() => {
common.navigateTo('/pages/login/login')
}).finally(() => {
no_login_show_modal_state = false
})
}
export default function request({
url,
method,
@@ -46,16 +66,13 @@ export default function request({
if (isStream) { // 流式传输,直接返回
return resolve(response);
}
// 0005 QQ0005 登录已过期
// suppressErrors
// 模拟拦截器功能
const res = response.data
if (res?.rtnCode === '0000'){
return resolve(res)
}
//到这里全是异常情况
//到这里下面全是异常的处理
if(suppressErrors){ // 静默的接口,报错也不处理,因为下面有公共处理
return reject()
}
@@ -63,16 +80,15 @@ export default function request({
common.msg("系统异常.")
return reject()
}
if (res.rtnCode === '0005' || res.rtnCode === 'QQ0005'){
common.hideLoading()
common.show('未登录','现在去登录').then(() => {
common.navigateTo('/pages/login/login')
})
// 0005 QQ0005 登录已过期
if(REQUES_ERROR_CODES['NO_LOGIN'].includes(res.rtnCode)) {
goto_login_fun()
}
return reject(res)
},
fail() {
console.log('131231');
fail(res) {
console.log('131231', res, url);
}
});
})
+214
View File
@@ -0,0 +1,214 @@
export default class WebSocketUtil {
/**
* WebSocket工具类,用于管理WebSocket连接
* @param {string} url - WebSocket服务器地址
* @param {Object} options - 配置选项
* @param {number} [options.maxReconnectCount=5] - 最大重连次数
* @param {number} [options.reconnectInterval=3000] - 重连间隔时间(ms)
* @param {number} [options.heartbeatInterval=30000] - 心跳间隔时间(ms)
* @param {string|Object} [options.heartbeatMsg='ping'] - 心跳消息
*/
constructor(url, options = {}) {
this.url = url;
this.options = options;
this.socketTask = null; // WebSocket任务实例
this.reconnectTimer = null; // 重连计时器
this.reconnectCount = 0; // 当前重连次数
this.maxReconnectCount = options.maxReconnectCount || 5; // 最大重连次数
this.reconnectInterval = options.reconnectInterval || 3000; // 重连间隔(ms)
this.heartbeatTimer = null; // 心跳计时器
this.heartbeatInterval = options.heartbeatInterval || 30000; // 心跳间隔(ms)
this.heartbeatMsg = options.heartbeatMsg || 'ping'; // 心跳消息
this.callbacks = {
open: [], // 连接打开回调
message: [], // 消息接收回调
close: [], // 连接关闭回调
error: [] // 错误处理回调
};
this.init(); // 初始化WebSocket连接
}
/**
* 初始化WebSocket连接
*/
init() {
// 创建WebSocket连接
this.socketTask = uni.connectSocket({
url: this.url,
header: this.options.header || {},
protocols: this.options.protocols || [],
success: () => {
console.log('WebSocket连接创建成功');
},
fail: (err) => {
console.error('WebSocket连接创建失败', err);
this.triggerEvent('error', err);
this.tryReconnect(); // 连接失败时尝试重连
}
});
// 监听WebSocket连接打开事件
this.socketTask.onOpen(() => {
console.log('WebSocket连接已打开');
this.reconnectCount = 0; // 重置重连计数
clearInterval(this.reconnectTimer); // 清除重连计时器
this.startHeartbeat(); // 启动心跳机制
this.triggerEvent('open'); // 触发连接打开事件
});
// 监听WebSocket消息接收事件
this.socketTask.onMessage((res) => {
console.log('收到WebSocket消息', res);
this.triggerEvent('message', res); // 触发消息接收事件
});
// 监听WebSocket连接关闭事件
this.socketTask.onClose((res) => {
console.log('WebSocket连接已关闭', res);
clearInterval(this.heartbeatTimer); // 清除心跳计时器
this.triggerEvent('close', res); // 触发连接关闭事件
this.tryReconnect(); // 尝试重连
});
// 监听WebSocket错误事件
this.socketTask.onError((err) => {
console.error('WebSocket发生错误', err);
clearInterval(this.heartbeatTimer); // 清除心跳计时器
this.triggerEvent('error', err); // 触发错误事件
this.tryReconnect(); // 尝试重连
});
}
/**
* 注册事件回调
* @param {string} event - 事件名称(open/message/close/error)
* @param {Function} callback - 回调函数
* @returns {WebSocketUtil} - 返回当前实例,支持链式调用
*/
on(event, callback) {
if (this.callbacks[event]) {
this.callbacks[event].push(callback);
}
return this;
}
/**
* 移除事件回调
* @param {string} event - 事件名称(open/message/close/error)
* @param {Function} callback - 要移除的回调函数
* @returns {WebSocketUtil} - 返回当前实例,支持链式调用
*/
off(event, callback) {
if (this.callbacks[event]) {
this.callbacks[event] = this.callbacks[event].filter(cb => cb !== callback);
}
return this;
}
/**
* 触发事件回调
* @param {string} event - 事件名称
* @param {any} [data] - 传递给回调函数的数据
*/
triggerEvent(event, data) {
if (this.callbacks[event]) {
this.callbacks[event].forEach(callback => callback(data));
}
}
/**
* 通过WebSocket发送消息
* @param {string|Object} message - 要发送的消息,可以是字符串或对象
* @returns {WebSocketUtil} - 返回当前实例,支持链式调用
*/
send(message) {
if (this.socketTask && this.getStatus() === 1) {
// 发送消息,对象会自动转换为JSON字符串
this.socketTask.send({
data: typeof message === 'string' ? message : JSON.stringify(message),
success: () => {
console.log('WebSocket消息发送成功');
},
fail: (err) => {
console.error('WebSocket消息发送失败', err);
this.triggerEvent('error', err);
}
});
} else {
console.error('WebSocket连接未打开,无法发送消息');
this.triggerEvent('error', new Error('WebSocket连接未打开'));
}
return this;
}
/**
* 关闭WebSocket连接
* @param {number} [code=1000] - 关闭码
* @param {string} [reason=''] - 关闭原因
* @returns {WebSocketUtil} - 返回当前实例,支持链式调用
*/
close(code = 1000, reason = '') {
if (this.socketTask) {
clearInterval(this.heartbeatTimer); // 清除心跳计时器
clearInterval(this.reconnectTimer); // 清除重连计时器
// 关闭WebSocket连接
this.socketTask.close({
code,
reason,
success: () => {
console.log('WebSocket连接正在关闭');
},
fail: (err) => {
console.error('WebSocket关闭失败', err);
this.triggerEvent('error', err);
}
});
}
return this;
}
/**
* 获取WebSocket连接状态
* @returns {number} - 连接状态:0-连接中,1-已连接,2-连接关闭中,3-已关闭,-1-未知
*/
getStatus() {
if (this.socketTask) {
try {
return this.socketTask.readyState;
} catch (e) {
console.error('获取WebSocket状态失败', e);
return -1;
}
}
return -1;
}
/**
* 尝试重新连接WebSocket
*/
tryReconnect() {
if (this.reconnectCount < this.maxReconnectCount) {
clearInterval(this.reconnectTimer);
this.reconnectTimer = setTimeout(() => {
this.reconnectCount++;
console.log(`尝试重新连接WebSocket (${this.reconnectCount}/${this.maxReconnectCount})`);
this.init(); // 重新初始化WebSocket连接
}, this.reconnectInterval);
} else {
console.error('达到最大重连次数,停止尝试');
this.triggerEvent('error', new Error('达到最大重连次数'));
}
}
/**
* 启动心跳机制
*/
startHeartbeat() {
clearInterval(this.heartbeatTimer);
this.heartbeatTimer = setInterval(() => {
if (this.getStatus() === 1) {
this.send(this.heartbeatMsg); // 发送心跳消息
}
}, this.heartbeatInterval);
}
}
+11 -4
View File
@@ -1,11 +1,18 @@
import request from '@/api/request'
// 获取列表接口
export const process_listPage = (data) => {
// 我的-统计信息
export const queryTraStdyStatisticsSelf = (data) => {
/**
userId 学员ID String
stdtTmLen 累计学习时长 double
accmTaskCnt 累计完成任务 int
accmPoint 累计获得积分 int
**/
return request({
url: '/plappro/process/queryProcessList',
url: '/traapp/traStdyInfo/queryTraStdyStatisticsSelf',
method: 'post',
data
data,
suppressErrors: true
});
};
+2 -3
View File
@@ -9,7 +9,7 @@ function msg(title, duration = 1000) {
}
function show(title, msg, showCancel = true) {
let res = new Promise((resolve, reject) => {
return new Promise((resolve, reject) => {
uni.showModal({
title: title,
content: msg,
@@ -18,11 +18,10 @@ function show(title, msg, showCancel = true) {
resolve(res.confirm)
},
fail: function(res) {
reject(false)
reject(res)
},
});
})
return res;
}
const loading = (title = '加载中', mask = true) => uni.showLoading({
-6
View File
@@ -10,7 +10,6 @@
}
},
{
<<<<<<< HEAD
"path": "pages/courseDetail/index",
"style": {
"navigationBarTitleText": "课程详情",
@@ -20,8 +19,6 @@
}
},
{
=======
>>>>>>> f0015d5ea46c4904ce35c5ec4a03028d9ec6d5b4
"path": "pages/study/index",
"style": {
"navigationBarTitleText": "学习",
@@ -93,8 +90,6 @@
"titleNView": false
}
}
<<<<<<< HEAD
=======
},
{
"path": "pages/course/index",
@@ -104,7 +99,6 @@
"titleNView": false
}
}
>>>>>>> f0015d5ea46c4904ce35c5ec4a03028d9ec6d5b4
}
],
"tabBar": {
+107 -73
View File
@@ -27,8 +27,9 @@
</view>
<!-- 搜索框 -->
<view class="search_div">
<uv-input shape="circle" @click="goto_search_page" :customStyle="customStyles" :placeholderStyle="placeholderStyle"
placeholder="请输入关键字" suffixIcon="search" :suffixIconStyle="suffixIconStyle" :readonly="true">
<uv-input shape="circle" @click="goto_search_page" :customStyle="customStyles"
:placeholderStyle="placeholderStyle" placeholder="请输入关键字" suffixIcon="search"
:suffixIconStyle="suffixIconStyle" :readonly="true">
</uv-input>
<view class="message_div">
<image src="@/static/images/index/message.png" class="message_img"></image>
@@ -52,20 +53,22 @@
<!-- 学习时长 -->
<view class="study_duration_div">
<view class="item">
<view class="top">学习时长</view>
<view class="top">年学习时长</view>
<view class="bottom">
<uv-count-to :startVal="150" :endVal="256.2" :useEasing="true" :decimals="1"></uv-count-to>h
<uv-count-to :startVal="statistics_data['stdtTmLen']" :endVal="statistics_data['stdtTmLen']" :useEasing="true" :decimals="1"></uv-count-to>h
</view>
</view>
<view class="item">
<view class="top">累计训练时长</view>
<view class="top">累计训练次数</view>
<view class="bottom">
<uv-count-to :startVal="100" :endVal="224.5" :useEasing="true" :decimals="1"></uv-count-to>h
<uv-count-to :startVal="statistics_data['accmExamCnt']" :endVal="statistics_data['accmExamCnt']" :useEasing="true"></uv-count-to><span
class="number"></span>
</view>
</view>
<view class="item">
<view class="top">累计考试次数</view>
<view class="bottom"><uv-count-to :startVal="0" :endVal="25" :useEasing="true"></uv-count-to>
<view class="bottom"><uv-count-to :startVal="statistics_data['accmPracticeCnt']" :endVal="statistics_data['accmPracticeCnt']"
:useEasing="true"></uv-count-to><span class="number"></span>
</view>
</view>
</view>
@@ -121,15 +124,15 @@
<scroll-view class="scroll-view" :scroll-x="true" :show-scrollbar="false">
<view class="scroll-view-item" v-for="(item,index) in hot_class_list" :key="index">
<view class="item_div">
<uv-skeleton :loading="!item.title" :rows="3" avatar avatar-shape="square" :title="false">
<view class="item">
<uv-skeleton :loading="!item.crsNum" :rows="3" avatar avatar-shape="square" :title="false">
<view class="item" @click="goto_course_detail(item.crsNum)">
<view class="left">
<image class="img" src="@/static/images/test/1.png"></image>
<image-preview class="img-box img" :imgId="item.imgId"></image-preview>
</view>
<view class="right">
<view class="title ellipsis-text">{{item.title}}</view>
<view class="title ellipsis-text">{{item.crsName}}</view>
<view class="note ellipsis-text">
发布{{item.date}} 丨已学{{item.num}}
发布{{item.issuTm.substr(0, 10)}} 丨已学{{item.accmStdyCnt}}
</view>
<view class="button_div">
<view class="button">去学习</view>
@@ -152,17 +155,17 @@
<!-- 推荐课程 -->
<view class="hot_class_div">
<scroll-view class="scroll-view" :scroll-x="true" :show-scrollbar="false">
<view class="scroll-view-item" v-for="(item,index) in hot_class_list" :key="index">
<view class="scroll-view-item" v-for="(item,index) in recommend_class_list" :key="index">
<view class="item_div">
<uv-skeleton :loading="!item.title" :rows="3" avatar avatar-shape="square" :title="false">
<view class="item">
<uv-skeleton :loading="!item.crsNum" :rows="3" avatar avatar-shape="square" :title="false">
<view class="item" @click="goto_course_detail(item.crsNum)">
<view class="left">
<image class="img" src="@/static/images/test/1.png"></image>
<image-preview class="img-box img" :imgId="item.imgId"></image-preview>
</view>
<view class="right">
<view class="title ellipsis-text">{{item.title}}</view>
<view class="title ellipsis-text">{{item.crsName}}</view>
<view class="note ellipsis-text">
发布{{item.date}} 丨已学{{item.num}}
发布{{item.issuTm.substr(0, 10)}} 丨已学{{item.accmStdyCnt}}
</view>
<view class="button_div">
<view class="button">去学习</view>
@@ -184,17 +187,17 @@
<!-- 最新课程 -->
<view class="hot_class_div">
<scroll-view class="scroll-view" :scroll-x="true" :show-scrollbar="false">
<view class="scroll-view-item" v-for="(item,index) in hot_class_list" :key="index">
<view class="scroll-view-item" v-for="(item,index) in new_class_list" :key="index">
<view class="item_div">
<uv-skeleton :loading="!item.title" :rows="3" avatar avatar-shape="square" :title="false">
<view class="item">
<uv-skeleton :loading="!item.crsNum" :rows="3" avatar avatar-shape="square" :title="false">
<view class="item" @click="goto_course_detail(item.crsNum)">
<view class="left">
<image class="img" src="@/static/images/test/1.png"></image>
<image-preview class="img-box img" :imgId="item.imgId"></image-preview>
</view>
<view class="right">
<view class="title ellipsis-text">{{item.title}}</view>
<view class="title ellipsis-text">{{item.crsName}}</view>
<view class="note ellipsis-text">
发布{{item.date}} 丨已学{{item.num}}
发布{{item.issuTm.substr(0, 10)}} 丨已学{{item.accmStdyCnt}}
</view>
<view class="button_div">
<view class="button">去学习</view>
@@ -210,15 +213,17 @@
<uv-divider text='我是有底线的' lineColor="#9cB0DC" :hairline="true"></uv-divider>
</view>
</view>
<tabbar-shadow></tabbar-shadow>
</view>
</template>
<script setup>
import {
computed,
onMounted,
reactive,
ref
} from 'vue'
import {
@@ -233,7 +238,10 @@
} from './index.js'
import common from '@/common/common'
import {
getStatisticsData
getStatisticsData,
queryCrsInfoByLastnew,
queryCrsInfoByPopular,
queryCrsInfoByRecmd,
} from '@/api/index.js'
const scrollTop = ref(0);
// 计算透明度
@@ -250,64 +258,81 @@
})
// 滚动消息
const notice_text = ref(['绿色金融政策解析与商业银行绿色水水水水水水水水水水水水水', '绿色金融政策解析与商业银行红色'])
const init_class_data = [
{
crsNum: '',
img: '',
crsName: '',
issuTm: '',
accmStdyCnt: ''
}, {
crsNum: '',
img: '',
crsName: '',
issuTm: '',
accmStdyCnt: ''
}
]
// 热门课程
const hot_class_list = ref([{
img: '',
title: '',
date: '',
num: ''
}, {
img: '',
title: '',
date: '',
num: ''
}])
const statistics_data = {
'study': 0, // 学习
'train': 0, // 训练
'exam': 0, //考试
const hot_class_list = ref([...init_class_data])
const new_class_list = ref([...init_class_data])
const recommend_class_list = ref([...init_class_data])
const statistics_data = reactive({
'stdtTmLen': 0, // 学习
'accmPracticeCnt': 0, // 训练
'accmExamCnt': 0, //考试
'start_tudy': 0, // 起始学习
'start_train': 0, // 起始训练
'start_exam': 0, //起始考试
'request_time': 0, //上次请求时间
}
})
// 获取首页统计数据方法
const get_statistics_data = async () => {
if (!common.isLogin()) return
const time_now = Date.now()
// 暂时设置10分钟
if (time_now - statistics_data['request_time'] > 600 * 1000) {
statistics_data['request_time'] = time_now
// const data = await getStatisticsData()
// console.log(data);
}
const data = await getStatisticsData()
statistics_data['accmExamCnt'] = data['accmExamCnt']
statistics_data['accmPracticeCnt'] = data['accmPracticeCnt']
statistics_data['stdtTmLen'] = data['stdtTmLen']
// const time_now = Date.now()
// // 暂时设置10分钟
// if (time_now - statistics_data['request_time'] > 600 * 1000) {
// statistics_data['request_time'] = time_now
// const data = await getStatisticsData()
// console.log(data);
// }
}
// 进入搜索页
const goto_search_page = () => {
common.navigateTo('/pages/search/search')
}
// 进入课程详情页
const goto_course_detail = (crsNum) => {
common.navigateTo('/pages/courseDetail/index?crsNum='+crsNum)
}
onShow(() => {
get_statistics_data() // 获取首页统计数据
})
onMounted(() => {
setTimeout(() => {
hot_class_list.value = [{
img: '11',
title: '最新课程最新课程最新课程程最新课程程最新课程程最新课程',
date: '2025/4/21',
num: '44'
}, {
img: '',
title: '',
date: '',
num: ''
}]
}, 100)
onMounted(async () => {
queryCrsInfoByLastnew().then(res => {
new_class_list.value = res.body
})
queryCrsInfoByPopular().then(res => {
hot_class_list.value = res.body
})
queryCrsInfoByRecmd().then(res => {
recommend_class_list.value = res.body
})
})
</script>
<style lang="scss" scoped>
<style scoped lang="scss">
$bg-margin-left: 50rpx;
// :deep(.uni-scroll-view-content) {
@@ -319,12 +344,13 @@
width: 146rpx !important;
border-radius: 16rpx;
}
// 底线样式
.bottom_line {
margin: 0 auto;
width: 240rpx;
}
// 热门课程等三个横向滑动模块的样式
.hot_class_div {
margin-left: $bg-margin-left;
@@ -416,7 +442,7 @@
}
}
.bg_div {
height: 100%;
padding-bottom: 30rpx;
@@ -455,13 +481,12 @@
background-color: #f6f8ff;
margin-top: var(--status-bar-height);
padding: 0 $bg-margin-left 20rpx $bg-margin-left;
height: 70rpx;
width: calc(100% - 2* $bg-margin-left);
height: 90rpx;
width: 100%;
z-index: 100;
display: flex;
align-items: center;
border-bottom: 4rpx solid #efefef;
.fixed_search_input_div {
flex: 1;
}
@@ -578,16 +603,16 @@
:deep(.uv-notice__left-icon) .uv-icon__icon {
font-size: 24rpx !important;
}
// ::v-deep .u-notice-bar {
// padding: 14rpx 0;
// font-size: 22rpx;
// }
// :deep(.u-notice__left-icon) {
// margin-right: 5rpx;
// }
}
// 学习时长
@@ -643,12 +668,21 @@
font-style: normal;
text-align: center;
// 数字滚动组件
:deep(.uv-count-num) {
font-weight: bold !important;
font-size: 50rpx !important;
color: #000000 !important;
}
.number {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 30rpx;
color: #000000;
}
}
}
}
+1 -1
View File
@@ -186,7 +186,7 @@
}
.account_input {
height: 76rpx;
height: 100rpx;
background-color: #F4F8FF;
border: none;
border-radius: 16rpx;
+129 -11
View File
@@ -8,20 +8,25 @@
<!-- 用户个人信息 -->
<view class="personal_information">
<view class="profile">
<image class="img_100" src="/static/images/test/touxiang.png"></image>
<image v-if="user_info.imageAddr" class="img_100" src="/static/images/test/touxiang.png">
</image>
<image v-else class="img_100" src="/static/images/me/default_user_avatar.png"></image>
</view>
<view class="personal_information_data">
<view class="name_sex_div">
<view class="name">
顾青裴
{{user_info.userName}}
</view>
<view class="sex">
<!-- <image class="img_100" src="/static/images/me/man.png"></image> -->
<image class="img_100" src="/static/images/me/wuman.png"></image>
<image v-if="user_info.gender === 'F'" class="img_100"
src="/static/images/me/wuman.png">
</image>
<image v-if="user_info.gender === 'M'" class="img_100" src="/static/images/me/man.png">
</image>
</view>
</view>
<view class="work_number_div">
工号15688749934
工号{{user_info.userId}}
</view>
<view class="fl1"></view>
</view>
@@ -31,19 +36,19 @@
<view class="item">
<view class="top">累计学习时长</view>
<view class="bottom">
<uv-count-to :startVal="15" :endVal="15" :useEasing="true" :decimals="1"></uv-count-to>h
<uv-count-to :startVal="statistics_data['accmPoint']" :endVal="statistics_data['accmPoint']" :useEasing="true" :decimals="1"></uv-count-to>h
</view>
</view>
<view class="item">
<view class="top">累计完成任务</view>
<view class="bottom">
<uv-count-to :startVal="24" :endVal="24" :useEasing="true"></uv-count-to>
<uv-count-to :startVal="statistics_data['accmTaskCnt']" :endVal="statistics_data['accmTaskCnt']" :useEasing="true"></uv-count-to>
</view>
</view>
<view class="item">
<view class="top">累计获得积分</view>
<view class="bottom">
<uv-count-to :startVal="125" :endVal="125" :useEasing="true"></uv-count-to>
<uv-count-to :startVal="statistics_data['stdtTmLen']" :endVal="statistics_data['stdtTmLen']" :useEasing="true"></uv-count-to>
</view>
</view>
</view>
@@ -82,7 +87,8 @@
<uv-cell-group :border="false">
<uv-cell title='设置' :isLink="true"></uv-cell>
<uv-cell title='客服' :isLink="true"></uv-cell>
<uv-cell title='退出登录' :isLink="true" :clickable="false" :border="false"></uv-cell>
<uv-cell title='退出登录' :isLink="true" :clickable="false" :border="false"
@click="click_loginout()"></uv-cell>
</uv-cell-group>
</view>
<tabbar-shadow></tabbar-shadow>
@@ -92,14 +98,126 @@
<script setup>
import {
ref,
computed
computed,
reactive
} from 'vue';
import {
onShow
} from '@dcloudio/uni-app'
import common from '@/common/common'
import {
getUserInfo
} from '@/common/common'
import {
onPullDownRefresh
} from '@dcloudio/uni-app'
import {
loginOut
} from '@/api/login.js'
import {
queryTraStdyStatisticsSelf
} from '@/api/user.js'
const statistics_data = reactive({
'study': 0, // 学习
'train': 0, // 训练
'exam': 0, // 考试
'start_study': 0, // 起始学习
'start_train': 0, // 起始训练
'start_exam': 0, // 起始考试
'request_time': 0, // 上次请求时间
/**
* 初始化统计数据
*/
"init": function() {
// 初始化起始数据
this.start_study = this.study;
this.start_train = this.train;
this.start_exam = this.exam;
},
/**
* 获取统计数据(带缓存机制)
* @returns {Promise<void>}
*/
"get_statistics_data": async function() {
try {
const time_now = Date.now();
// 检查缓存是否过期(10分钟)
if (time_now - this.request_time > 600 * 1000) {
this.request_time = time_now;
// 获取最新数据
const {
study,
train,
exam
} = await getStatisticsData();
// 保存起始值(如果是首次获取)
if (this.request_time === 0) {
this.start_study = study;
this.start_train = train;
this.start_exam = exam;
}
// 更新当前值
this.study = study;
this.train = train; // 修正:之前漏写这一行
this.exam = exam;
console.log('统计数据已更新');
} else {
console.log('使用缓存的统计数据');
}
} catch (error) {
console.error('获取统计数据失败:', error);
// 可以在这里添加重试逻辑或使用默认值
}
}
});
const user_info = reactive({
userName: '',
userId: ''
});
onShow(() => {
const user_info_cache = getUserInfo()
Object.assign(user_info, user_info_cache)
queryTraStdyStatisticsSelf().then(res => {
statistics_data['accmPoint'] = res['accmPoint']
statistics_data['accmTaskCnt'] = res['accmTaskCnt']
statistics_data['stdtTmLen'] = res['stdtTmLen']
console.log('res', res);
console.log('res', res);
console.log('res', res);
})
// statistics_data['get_statistics_data']() // 获取首页统计数据
})
const click_loginout = () => {
common.show('确定退出登录?').then(async (res) => {
console.log(res);
if (!res) return;
try {
common.loading('正在退出登录')
await loginOut()
} catch (e) {
}
common.hideLoading()
// 主动退出登录后,再次登录应该进首页
common.reLaunch('/pages/login/login')
})
}
onPullDownRefresh(() => {
console.log('下拉刷新');
// uni.stopPullDownRefresh();
uni.stopPullDownRefresh();
})
</script>
+45 -7
View File
@@ -8,10 +8,45 @@
</view>
</view>
</template>
<script>
<script setup>
import WebSocketUtil from '@/api/socket.js';
const ws = new WebSocketUtil('ws://127.0.0.1', {
maxReconnectCount: 10,
reconnectInterval: 5000,
heartbeatInterval: 30000,
heartbeatMsg: 'ping'
});
ws.on('open', () => {
console.log('WebSocket连接已打开');
ws.send({
type: 'init',
data: {
userId: 123
}
});
});
ws.on('message', (res) => {
console.log('收到消息:', res);
});
ws.on('close', (res) => {
console.log('WebSocket连接已关闭:', res);
});
ws.on('error', (err) => {
console.error('WebSocket错误:', err);
});
// 一段时间后关闭连接
setTimeout(() => {
ws.close(1000, '正常关闭');
}, 60000);
</script>
<style scoped lang="scss">
.main_div{
.main_div {
background-color: #f9faff;
// background-color: red;
display: flex;
@@ -19,21 +54,24 @@
align-items: center;
justify-content: space-around;
}
.empty_div{
.empty_div {
// margin-top: 40%;
display: flex;
flex-direction: column;
align-items: center;
//
.img{
.img {
width: 388rpx;
height: 335rpx;
}
.text{
.text {
margin-top: 20rpx;
height: 40rpx;
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 29rpx;
+1 -2
View File
@@ -33,8 +33,7 @@
"navigationBarTitleText": "我的",
"app-plus": {
"titleNView": false
},
"enablePullDownRefresh": true
}
}
},
{
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB