Files
tra-app/src/pages/index/index.vue
T

891 lines
22 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="main_div max_page">
<nav-bar :is_seat="false" :backgroundColor="bgOpacity"></nav-bar>
<view class="bg_div">
<!-- 背景图 -->
<image src="@/static/images/index/bg.png" class="bg_img"></image>
<view class="fixed_search_div" v-show="opacity" :style="{ opacity: opacity }">
<view class="fixed_search_input_div" @click="goto_search_page">
<uv-input shape="circle" :customStyle="fixedCustomStyles"
placeholderStyle='color:#999999;font-size:26rpx' placeholder="请输入关键字" suffixIcon="search"
:suffixIconStyle="suffixIconStyle" :readonly="true">
</uv-input>
</view>
<view class="message_div">
<image src="@/static/images/index/message_b.png" class="message_img"></image>
<view class="message_text">消息</view>
<view class="message_num message_num_font">30</view>
</view>
</view>
<!-- 文字logo -->
<view class="title_logo">
<image src="@/static/images/index/logo_text.png" class="log_img"></image>
<view class="fl1"></view>
</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>
<view class="message_div">
<image src="@/static/images/index/message.png" class="message_img"></image>
<view class="message_text">消息</view>
<view class="message_num message_num_font">
30
</view>
</view>
</view>
<!-- 滚动通知 -->
<view class="notice_div">
<uv-notice-bar v-show="notice_text.length" :text="notice_text" :bgColor="null"
color="rgba(255,255,255,0.7)" :speed="40" direction="column"></uv-notice-bar>
</view>
<!-- 学习时长和飞天兔子为了挡住部分兔子只能多一个盒子 -->
<view class="study_duration_and_profile_div">
<!-- 飞天兔子 -->
<view class="profile_div">
<image :src="mascotInfo?.imgAddr ||''" alt="" class="profile"></image>
<!-- <image src="/static/images/index/fttz.png" class="profile"></image> -->
</view>
<!-- 学习时长 -->
<view class="study_duration_div">
<view class="item">
<view class="top">本年学习时长</view>
<view class="bottom">
<uv-count-to :startVal="statistics_data['startStdtTmLen']"
:endVal="statistics_data['stdtTmLen']" :useEasing="true" :decimals="1"
ref="stdtTmLenRef"></uv-count-to>h
</view>
</view>
<view class="item">
<view class="top">累计训练次数</view>
<view class="bottom">
<uv-count-to :startVal="statistics_data['startAccmExamCnt']"
:endVal="statistics_data['accmExamCnt']" :useEasing="true"
ref="accmExamCntRef"></uv-count-to><span class="number"></span>
</view>
</view>
<view class="item">
<view class="top">累计考试次数</view>
<view class="bottom"><uv-count-to :startVal="statistics_data['starAccmPracticeCnt']"
:endVal="statistics_data['accmPracticeCnt']" :useEasing="true"
ref="accmPracticeCntRef"></uv-count-to><span class="number"></span>
</view>
</view>
</view>
</view>
<!-- 8个导航 -->
<view class="navigation_div">
<view class="group">
<view class="item" @click="common.switchTab('/pages/course/index')">
<image class="icon" src="@/static/images/index/navigation_course.png"></image>
<view class="title">课程中心</view>
</view>
<view class="item"
@click="common.navigateTo('/pages/index/dialog',{ animationType: 'slide-in-bottom'})">
<image class="icon" src="@/static/images/index/navigation_question_answering.png"></image>
<view class="title">AI问答</view>
</view>
<view class="item">
<image class="icon" src="@/static/images/index/navigation_ai.png" @click="ai_test()"></image>
<view class="title">AI陪练</view>
</view>
<view class="item">
<image class="icon" src="@/static/images/index/navigation_learning_tasks.png"></image>
<view class="title">学习任务</view>
</view>
</view>
<view class="group">
<view class="item">
<image class="icon" src="@/static/images/index/navigation_examination.png"></image>
<view class="title">考试中心</view>
</view>
<view class="item">
<image class="icon" src="@/static/images/index/navigation_practice.png"></image>
<view class="title">竞赛练习</view>
</view>
<view class="item">
<image class="icon" src="@/static/images/index/navigation_wrong_question.png"></image>
<view class="title">错题本</view>
</view>
<view class="item">
<image class="icon" src="@/static/images/index/navigation_learning_analysis.png"></image>
<view class="title">学习分析</view>
</view>
</view>
</view>
<!-- 热门课程分模块标题 -->
<view class="module_title_div">
<view class="icon icon_1">
<image class="img" src="@/static/images/index/hot.png"></image>
</view>
<view class="text font_pf">热门课程</view>
</view>
<!-- 热门课程 -->
<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="item_div">
<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-preview class="img-box img" :imgId="item.imgId" mode="aspectFill"
:isCache="true" :width="240" :height="240"></image-preview>
</view>
<view class="right">
<view class="title ellipsis-text">{{item.crsName}}</view>
<view class="note ellipsis-text">
更新{{(item.mtTime||'').substr(0, 10)}} 丨已学{{item.accmStdyCnt}}
</view>
<view class="button_div">
<view class="button">去学习</view>
</view>
</view>
</view>
</uv-skeleton>
</view>
</view>
</scroll-view>
</view>
<!-- 推荐课程分模块标题 -->
<view class="module_title_div">
<view class="icon icon_2">
<image class="img" src="@/static/images/index/recommend.png"></image>
</view>
<view class="text font_pf">推荐课程</view>
</view>
<!-- 推荐课程 -->
<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 recommend_class_list" :key="index">
<view class="item_div">
<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-preview class="img-box img" :imgId="item.imgId" mode="aspectFill"
:isCache="true" :width="240" :height="240"></image-preview>
</view>
<view class="right">
<view class="title ellipsis-text">{{item.crsName}}</view>
<view class="note ellipsis-text">
更新{{(item.mtTime||'').substr(0, 10)}} 丨已学{{item.accmStdyCnt}}
</view>
<view class="button_div">
<view class="button">去学习</view>
</view>
</view>
</view>
</uv-skeleton>
</view>
</view>
</scroll-view>
</view>
<!-- 最新课程分模块标题 -->
<view class="module_title_div">
<view class="icon icon_3">
<image class="img" src="@/static/images/index/new.png"></image>
</view>
<view class="text font_pf">最新课程</view>
</view>
<!-- 最新课程 -->
<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 new_class_list" :key="index">
<view class="item_div">
<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-preview class="img-box img" :imgId="item.imgId" mode="aspectFill"
:isCache="true" :width="240" :height="240"></image-preview>
</view>
<view class="right">
<view class="title ellipsis-text">{{item.crsName}}</view>
<view class="note ellipsis-text">
更新{{(item.mtTime||'').substr(0, 10)}} 丨已学{{item.accmStdyCnt}}
</view>
<view class="button_div">
<view class="button">去学习</view>
</view>
</view>
</view>
</uv-skeleton>
</view>
</view>
</scroll-view>
</view>
<view class="bottom_line">
<uv-divider text='我是有底线的' lineColor="#9cB0DC" :hairline="true"></uv-divider>
</view>
</view>
<tabbar-shadow></tabbar-shadow>
</view>
</template>
<script setup>
import {
computed,
nextTick,
onBeforeMount,
onMounted,
reactive,
ref
} from 'vue'
import {
onShow,
onPageScroll,
onLoad,
onHide
} from '@dcloudio/uni-app'
import {
customStyles,
fixedCustomStyles,
placeholderStyle,
suffixIconStyle
} from './index.js'
import {
getUserInfo
} from '@/common/common';
import common from '@/common/common'
import {
setMascot
} from "@/common/mascot.js"
import {
getStatisticsData,
queryCrsInfoByLastnew,
queryCrsInfoByPopular,
queryCrsInfoByRecmd,
} from '@/api/index.js'
const scrollTop = ref(0);
const mascotShow = ref(false);
const stdtTmLenRef = ref(null);
const accmPracticeCntRef = ref(null);
const accmExamCntRef = ref(null);
const three_list_request_time = ref(0); // 三个列表更新时间
// 计算透明度
const opacity = computed(() => {
if (scrollTop.value <= 130) return 0;
return Math.min(3, (scrollTop.value - 130) / 30);
});
const bgOpacity = computed(() => {
return `rgba(246,248,255,${opacity.value})`;
});
// 首页滑动事件监听
onPageScroll((e) => {
scrollTop.value = e.scrollTop
})
// 滚动消息
const notice_text = ref(['绿色金融政策解析与商业银行绿色水水水水水水水水水水水水水', '绿色金融政策解析与商业银行红色'])
const init_class_data = [{
crsNum: '',
img: '',
crsName: '',
issuTm: '',
accmStdyCnt: ''
}, {
crsNum: '',
img: '',
crsName: '',
issuTm: '',
accmStdyCnt: ''
}]
// 热门课程
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 mascotInfo = ref({})
const statistics_data = reactive({
'stdtTmLen': 0, // 学习
'accmPracticeCnt': 0, // 训练
'accmExamCnt': 0, // 考试
'startStdtTmLen': 0, // 起始学习
'startAccmPracticeCnt': 0, // 起始训练
'startAccmExamCnt': 0, // 起始考试
'request_time': 0, // 上次请求时间
"init": function() { // 初始化统计数据
const index_statistics_data = common.getValue('index_statistics_data') // 获取缓存
if (index_statistics_data) {
this.stdtTmLen = index_statistics_data.stdtTmLen;
this.accmPracticeCnt = index_statistics_data.accmPracticeCnt;
this.accmExamCnt = index_statistics_data.accmExamCnt;
}
},
"get_statistics_data": async function() {
try {
const time_now = Date.now();
if (time_now - this.request_time > 300 * 1000) {
this.request_time = time_now;
// 获取最新数据
const res = await getStatisticsData();
common.setValue('index_statistics_data', res.body)
const stdtTmLen = res.body.stdtTmLen
const accmPracticeCnt = res.body.accmPracticeCnt
const accmExamCnt = res.body.accmExamCnt
if (stdtTmLen != this.stdtTmLen) {
this.startStdtTmLen = this.stdtTmLen
this.stdtTmLen = stdtTmLen
stdtTmLenRef.value.start()
}
if (accmPracticeCnt != this.accmPracticeCnt) {
this.startAccmPracticeCnt = this.accmPracticeCnt
this.accmPracticeCnt = accmPracticeCnt
accmPracticeCntRef.value.start()
}
if (accmExamCnt != this.accmExamCnt) {
this.startAccmExamCnt = this.accmExamCnt
this.accmExamCnt = accmExamCnt
accmExamCntRef.value.start()
}
console.log('统计数据已更新');
} else {
console.log('时间没到无需更新');
}
} catch (error) {
console.log('获取统计数据失败:', error);
}
}
});
const index = ref(0)
const ai_test = () => {
index.value++
if (index.value == 4) {
index.value = 1
}
uni.setTabBarStyle({
midButton: {
iconPath: "/static/images/icon/fawn-" + index.value + ".png",
width: "86px",
height: "86px",
iconWidth: "90px"
},
})
}
// 进入搜索页
const goto_search_page = () => {
common.navigateTo('/pages/search/search')
}
// 进入课程详情页
const goto_course_detail = (crsNum) => {
common.navigateTo('/pages/courseDetail/index?crsNum=' + crsNum)
}
const scrolltolower = () => {
common.navigateTo('/pages/index/dialog', {
animationType: 'slide-in-bottom'
})
}
onShow(() => {
if (!common.isLogin()) {
common.navigateTo('/pages/login/login')
return
}
setMascot()
const userInfo = getUserInfo()
if (userInfo) {
mascotInfo.value = userInfo?.mascotInfo
}
statistics_data['get_statistics_data']() // 获取统计数据
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
})
})
onHide(() => {
})
</script>
<style scoped lang="scss">
$bg-margin-left: 30rpx;
// :deep(.uni-scroll-view-content) {
// display: flex;
// }
// 设置骨架屏左侧图片框的大小,设置成和图片大小一致,否则横向滑动会串行(对不齐)
:deep(.uv-skeleton__wrapper__avatar) {
height: 146rpx !important;
width: 146rpx !important;
border-radius: 16rpx;
}
// 底线样式
.bottom_line {
margin: 0 auto;
width: 240rpx;
}
// 热门课程等三个横向滑动模块的样式
.hot_class_div {
margin-left: $bg-margin-left;
.scroll-view {
white-space: nowrap;
width: 100%;
}
.scroll-view-item {
display: inline-block;
margin-right: 30rpx;
background-color: #ffffff;
border-radius: 22rpx;
box-shadow: #eaeaea 0 0 6rpx;
padding: 32rpx 22rpx 36rpx 26rpx;
}
.item_div {
width: 562rpx;
display: block;
}
.item {
display: flex;
.left {
border-radius: 16rpx;
overflow: hidden;
width: 180rpx;
height: 146rpx;
.img {
width: 100%;
height: 100%;
}
}
.right {
width: calc(100% - 180rpx);
margin-left: 22rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
.title {
width: 100%;
font-weight: 500;
font-size: 30rpx;
color: #333333;
line-height: 40rpx;
text-align: left;
font-style: normal;
}
.note {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 23rpx;
color: #666666;
line-height: 33rpx;
text-align: left;
font-style: normal;
}
.button_div {
display: flex;
justify-content: flex-end;
.button {
text-align: center;
line-height: 62rpx;
width: 138rpx;
height: 62rpx;
background: #EBF1FF;
border-radius: 30rpx;
font-weight: 500;
font-size: 30rpx;
color: #0066FF;
font-style: normal;
margin-right: 10rpx;
}
}
}
}
}
.bg_div {
height: 100%;
padding-bottom: 30rpx;
display: flex;
flex-direction: column;
position: relative;
z-index: 0;
overflow-x: hidden;
// 背景图
.bg_img {
position: absolute;
top: 0;
left: 0;
width: calc(100% + 4rpx);
height: 870rpx;
z-index: -1;
}
// 文字图片
.title_logo {
display: flex;
margin-top: 106rpx;
margin-left: $bg-margin-left;
.log_img {
margin-left: 10rpx;
width: 300rpx;
height: 46rpx;
}
}
// 固定的搜索框
.fixed_search_div {
position: fixed;
background-color: #f6f8ff;
margin-top: var(--status-bar-height);
padding: 0 $bg-margin-left 20rpx $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;
}
.message_div {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
margin-left: 33rpx;
.message_img {
width: 32rpx;
height: 36rpx;
}
.message_text {
margin-top: 4rpx;
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 22rpx;
color: #333333;
line-height: 24rpx;
white-space: nowrap;
}
.message_num {
position: absolute;
top: 2rpx;
right: -4rpx;
padding: 2rpx 3rpx 2rpx 3rpx;
background-color: #ff1926;
border-radius: 10rpx;
// width: 22rpx;
// height: 20rpx;
// font-size: 10rpx;
// font-size: 30rpx;
color: #ffffff;
}
.message_num_font {
width: 22rpx;
height: 22rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 16rpx;
}
}
}
// 搜索框
.search_div {
margin-top: 26rpx;
margin-left: $bg-margin-left;
width: 390rpx;
height: 70rpx;
z-index: 20;
display: flex;
position: relative;
.message_div {
position: absolute;
top: 4rpx;
right: -56rpx;
display: flex;
flex-direction: column;
align-items: center;
.message_img {
width: 32rpx;
height: 36rpx;
}
.message_text {
margin-top: 4rpx;
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 22rpx;
color: #FFFFFF;
line-height: 24rpx;
white-space: nowrap;
}
.message_num {
position: absolute;
top: 2rpx;
right: -4rpx;
padding: 2rpx 3rpx 2rpx 3rpx;
background-color: #ff1926;
border-radius: 20rpx;
// width: 22rpx;
// height: 20rpx;
// font-size: 10rpx;
color: #ffffff;
}
.message_num_font {
width: 22rpx;
height: 22rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 16rpx;
}
}
}
//滚动消息
.notice_div {
// margin-top: 10rpx;
margin-left: $bg-margin-left;
width: 400rpx;
height: 74rpx;
font-weight: 500;
color: rgba(255, 255, 255, 0.7);
text-align: left;
font-style: normal;
display: flex;
align-items: center;
:deep(.uv-notice-bar) {
padding: 9px 2px;
}
:deep(.uv-notice__swiper__item__text) {
font-size: 20rpx !important;
}
: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;
// }
}
// 学习时长
.study_duration_and_profile_div {
margin: 0 $bg-margin-left;
position: relative;
//飞天兔子
.profile_div {
position: absolute;
top: -236rpx;
right: -20rpx;
z-index: -1;
.profile {
width: 278rpx;
height: 370rpx;
}
}
.study_duration_div {
height: 162rpx;
background: linear-gradient(180deg, rgba(238, 246, 255, 0.65) 0%, #C5DFFD 4%, #FFFFFF 100%);
border-radius: 23rpx;
display: flex;
justify-content: space-around;
z-index: 20;
opacity: .9;
.item {
flex: 1;
// background-color: red;
display: flex;
flex-direction: column;
justify-content: center;
.top {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 25rpx;
color: #666666;
line-height: 35rpx;
text-align: center;
font-style: normal;
}
.bottom {
margin-top: 5%;
font-weight: bold;
font-size: 50rpx;
color: #000000;
line-height: 58rpx;
text-align: left;
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;
}
}
}
}
}
// 快捷导航栏
.navigation_div {
margin: 16rpx $bg-margin-left 0 $bg-margin-left;
height: 338rpx;
background-color: #FFFFFF;
border-radius: 23rpx;
display: flex;
flex-direction: column;
justify-content: space-around;
box-shadow: #E6E8EF 0 5rpx 20rpx;
.group {
display: flex;
justify-content: space-around;
padding: 10rpx 10rpx;
// background-color: red;
}
.item {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
// background-color: red;
.icon {
width: 88rpx;
height: 86rpx;
}
.title {
margin-top: 10rpx;
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 25rpx;
// color: #323E57;
line-height: 35rpx;
text-align: left;
font-style: normal;
}
}
}
.module_title_div {
display: flex;
margin: 30rpx $bg-margin-left;
align-items: center;
.icon {
margin-right: 6rpx;
}
.icon_1 {
.img {
width: 31rpx;
height: 36rpx;
}
}
.icon_2 {
margin-top: 10rpx;
.img {
width: 38rpx;
height: 38rpx;
}
}
.icon_3 {
// margin-top: 10rpx;
.img {
width: 38rpx;
height: 31rpx;
}
}
.title {
font-size: 34rpx;
color: #323E57;
font-weight: 700;
line-height: 46rpx;
text-align: left;
}
}
}
.main_div {
display: flex;
flex-direction: column;
background-color: #F6F8FF;
}
</style>