|
@@ -1,82 +1,347 @@
|
|
|
<template>
|
|
<template>
|
|
|
<!-- 头部 -->
|
|
<!-- 头部 -->
|
|
|
- <nav-bar height="312" backPath="workspace" title="教师研修" :filterPickerData="state.filterPickerData" :tabList="state.tabList" :onlyTitle="false" :showFilterPicker="true" :showTabs="true" rightWidth="0rpx" @GoBack="GoBack"></nav-bar>
|
|
|
|
|
- <view class="page_content">
|
|
|
|
|
- <view class="list_item">
|
|
|
|
|
- <image class="item_img" mode="aspectFill" src="https://jtzx001.oss-accelerate.aliyuncs.com/huijiaoyan_test/20260609_255638/09101629_53c71c9b-3072-4fa5-9944-3598c9650666.jpg"></image>
|
|
|
|
|
- <view class="item_title">2025学年高一化学公开课全国评比大赛赛赛赛赛赛赛赛赛赛学公开课全国评比大赛赛赛赛赛赛赛赛赛赛</view>
|
|
|
|
|
- <view class="item_time"><text class="time">2025-11-12</text></view>
|
|
|
|
|
- </view>
|
|
|
|
|
|
|
+ <nav-bar :height="state.courseType == '0'?'312':'224'" backPath="workspace" title="教师研修" :filterPickerData="state.filterPickerData" :tabList="state.tabList" :onlyTitle="false" :showFilterPicker="true" :showTabs="true" rightWidth="0rpx" @CommonFilterData="CommonFilterData"></nav-bar>
|
|
|
|
|
+ <view :class="['page_content',{'self_content_height':state.courseType == '1'}]">
|
|
|
|
|
+ <scroll-view
|
|
|
|
|
+ class="scroll_view_y"
|
|
|
|
|
+ :scroll-top="state.scrollTop"
|
|
|
|
|
+ scroll-y="true"
|
|
|
|
|
+ :refresher-enabled="false"
|
|
|
|
|
+ :enable-back-to-top="true"
|
|
|
|
|
+ :show-scrollbar="false"
|
|
|
|
|
+ :scroll-with-animation="true"
|
|
|
|
|
+ refresher-default-style="none"
|
|
|
|
|
+ refresher-background="#F8F9FD"
|
|
|
|
|
+ :refresher-triggered="state.isRefreshing"
|
|
|
|
|
+ @scrolltolower="OnLoadMore"
|
|
|
|
|
+ @refresherrefresh="OnRefresh"
|
|
|
|
|
+ @scroll="OnScroll">
|
|
|
|
|
+ <view class="refresh_loading" v-if="state.isRefreshing"><uni-load-more status="loading" /></view>
|
|
|
|
|
+ <view class="page_list">
|
|
|
|
|
+ <view class="list_item" v-for="item in state.pageList" :key="item.id">
|
|
|
|
|
+ <view class="item_title">
|
|
|
|
|
+ <image class="img" src="@/static/image/icon/video.png"></image>
|
|
|
|
|
+ <view class="title">{{item.courseName}}</view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="item_status">
|
|
|
|
|
+ <view v-if="state.courseType == '0'" :class="['status',{going:item.courseStatus === 0,finished:item.courseStatus === 2}]">{{item.courseStatus === 0?'进行中':'已结束'}}</view>
|
|
|
|
|
+ <view class="item_field" v-if="state.courseType == '0' && item.courseType">{{item.courseType}}</view>
|
|
|
|
|
+ <view class="item_field" v-if="state.courseType == '1' && item.teachCourseTypeName">{{item.teachCourseTypeName}}</view>
|
|
|
|
|
+ <view class="item_field" v-if="item.teachCourseTypeClassName">{{item.teachCourseTypeClassName}}</view>
|
|
|
|
|
+ <view class="item_field" v-if="item.teacherName">{{item.teacherName}}</view>
|
|
|
|
|
+ <view class="item_field" v-if="state.courseType == '0' && item.remainingTime && item.remainingTime!='-'">剩余{{item.remainingTime}}</view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="item_complete_status">
|
|
|
|
|
+ <text class="complete_status">完成情况:{{item.learnOver ?? '-'}}/{{item.learnCount ?? '-'}}</text>
|
|
|
|
|
+ <text class="btn_detail">查看详情</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="no_data" v-if="!state.isLoading && state.pageList.length == 0">
|
|
|
|
|
+ <image class="no_data_img" src="@/static/image/bg/no_data.png"></image>
|
|
|
|
|
+ <text class="no_data_text">暂无数据</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <uni-load-more v-if="state.pageList.length > 0" :status="state.loadStatus" />
|
|
|
|
|
+ </scroll-view>
|
|
|
</view>
|
|
</view>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup>
|
|
<script setup>
|
|
|
import navBar from '@/components/nav-bar.vue';
|
|
import navBar from '@/components/nav-bar.vue';
|
|
|
|
|
+ import {queryCourseTypeDataList,minitorPageListData} from '@/reqApi/teacherStudy.js';
|
|
|
import {
|
|
import {
|
|
|
reactive,
|
|
reactive,
|
|
|
- ref
|
|
|
|
|
|
|
+ ref,
|
|
|
|
|
+ onMounted,
|
|
|
|
|
+ nextTick
|
|
|
} from 'vue';
|
|
} from 'vue';
|
|
|
const state = reactive({
|
|
const state = reactive({
|
|
|
- filterPickerData: [
|
|
|
|
|
- ['全部类型', '全部类型1'],
|
|
|
|
|
- ['全部类型', '全部类型2'],
|
|
|
|
|
- ['全部类型', '全部类型2']
|
|
|
|
|
- ],
|
|
|
|
|
- tabList: [{
|
|
|
|
|
- name: '最新发布',
|
|
|
|
|
- sortType: '0'
|
|
|
|
|
|
|
+ courseTypeData:[],//顶部查询数据
|
|
|
|
|
+ filterPickerData: [{
|
|
|
|
|
+ valueIndex:0,//默认值索引
|
|
|
|
|
+ defaultValue:'0',//默认值
|
|
|
|
|
+ list:[{
|
|
|
|
|
+ label:'必修任务',
|
|
|
|
|
+ value:'0',
|
|
|
|
|
+ },{
|
|
|
|
|
+ label:'自主研修',
|
|
|
|
|
+ value:'1',
|
|
|
|
|
+ }]
|
|
|
|
|
+ },{
|
|
|
|
|
+ valueIndex:0,//默认值索引
|
|
|
|
|
+ defaultValue:'',//默认值
|
|
|
|
|
+ list:[]
|
|
|
|
|
+ },{
|
|
|
|
|
+ valueIndex:0,//默认值索引
|
|
|
|
|
+ defaultValue:'',//默认值
|
|
|
|
|
+ list:[]
|
|
|
|
|
+ }],//必修任务tab
|
|
|
|
|
+ tabList:[],
|
|
|
|
|
+ mustTabList: [{
|
|
|
|
|
+ label: '全部',
|
|
|
|
|
+ value: ''
|
|
|
}, {
|
|
}, {
|
|
|
- name: '播放最多',
|
|
|
|
|
- sortType: '1'
|
|
|
|
|
|
|
+ label: '进行中',
|
|
|
|
|
+ value: '0'
|
|
|
}, {
|
|
}, {
|
|
|
- name: '关注最多',
|
|
|
|
|
- sortType: '2'
|
|
|
|
|
- }]
|
|
|
|
|
|
|
+ label: '已结束',
|
|
|
|
|
+ value: '2'
|
|
|
|
|
+ }],
|
|
|
|
|
+ pageList:[],//列表数据
|
|
|
|
|
+ queryStr: '',
|
|
|
|
|
+ courseType:'0',//默认必修任务
|
|
|
|
|
+ teachCourseTypeId: '',//内容领域
|
|
|
|
|
+ teachCourseTypeClassId: '',//研修专题
|
|
|
|
|
+ courseStatus: '',//tab选中值
|
|
|
|
|
+ pageSize: 10,
|
|
|
|
|
+ pageNum: 1,
|
|
|
|
|
+ scrollTop:0,
|
|
|
|
|
+ oldScrollTop:0,
|
|
|
|
|
+ isRefreshing:false,//设置当前下拉刷新状态,true 表示下拉刷新已经被触发,false 表示下拉刷新未被触发
|
|
|
|
|
+ isLoading:true,//加载中
|
|
|
|
|
+ noMoreData:false,//没有更多数据了
|
|
|
|
|
+ loadStatus:'more',//loading状态
|
|
|
})
|
|
})
|
|
|
|
|
+ onMounted(() => {
|
|
|
|
|
+ state.tabList = [...state.mustTabList];
|
|
|
|
|
+ getCourseTypeDataList();
|
|
|
|
|
+ OnLoadData(true);
|
|
|
|
|
+ });
|
|
|
|
|
+ //获取顶部查询项
|
|
|
|
|
+ const getCourseTypeDataList = () => {
|
|
|
|
|
+ queryCourseTypeDataList().then(res => {
|
|
|
|
|
+ if(res.code == 200){
|
|
|
|
|
+ const defaultData = [{
|
|
|
|
|
+ label:'内容领域',
|
|
|
|
|
+ id:'',
|
|
|
|
|
+ value:''
|
|
|
|
|
+ }];
|
|
|
|
|
+ const resData = res?.data || [];
|
|
|
|
|
+ state.courseTypeData = defaultData.concat(resData);
|
|
|
|
|
+ //内容领域
|
|
|
|
|
+ state.filterPickerData[1].list = state.courseTypeData.map(item=>({
|
|
|
|
|
+ ...item,
|
|
|
|
|
+ value:item.id
|
|
|
|
|
+ }))
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ //切换条件选择器
|
|
|
|
|
+ const CommonFilterData = (searchWord,filterPicker,tabsSelected,type) => {
|
|
|
|
|
+ const {valueIndex, index,filterPickerValue} = filterPicker;
|
|
|
|
|
+ state.queryStr = searchWord;
|
|
|
|
|
+ state.courseType = filterPickerValue[0];
|
|
|
|
|
+ state.teachCourseTypeId = filterPickerValue[1];
|
|
|
|
|
+ state.teachCourseTypeClassId = filterPickerValue[2];
|
|
|
|
|
+ state.courseStatus = tabsSelected;
|
|
|
|
|
+ if(type == 'filterPicker'){
|
|
|
|
|
+ state.filterPickerData[index].valueIndex = valueIndex;//研修场景、内容领域、研修专题选中项的索引
|
|
|
|
|
+ if(index==1){//切换内容领域选中项
|
|
|
|
|
+ //研修专题默认切换到全部 同时获取研修专题所有选项
|
|
|
|
|
+ state.filterPickerData[2].valueIndex = 0;
|
|
|
|
|
+ const childrenData = state.courseTypeData?.[valueIndex]?.children || [];
|
|
|
|
|
+ const childrenList = childrenData.map(item=>({
|
|
|
|
|
+ ...item,
|
|
|
|
|
+ value:item?.id ?? ''
|
|
|
|
|
+ }))
|
|
|
|
|
+ if(childrenList.length){
|
|
|
|
|
+ childrenList.unshift({
|
|
|
|
|
+ label:'研修专题',
|
|
|
|
|
+ id:'',
|
|
|
|
|
+ value:''
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ state.filterPickerData[2].list = childrenList;
|
|
|
|
|
+ }else{
|
|
|
|
|
+ if(index == 0){
|
|
|
|
|
+ state.filterPickerData[1].valueIndex = 0;//内容领域
|
|
|
|
|
+ state.filterPickerData[2].valueIndex = 0;//研修专题
|
|
|
|
|
+ state.filterPickerData[2].list = [];//研修专题选项
|
|
|
|
|
+ state.tabList = valueIndex == 0 ? [...state.mustTabList] : [];
|
|
|
|
|
+ state.courseStatus = '';
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ OnLoadData(true)
|
|
|
|
|
+ }
|
|
|
|
|
+ /*
|
|
|
|
|
+ *获取数据
|
|
|
|
|
+ * initPage:初始分页 从第一开始
|
|
|
|
|
+ */
|
|
|
|
|
+ const OnLoadData = (initPage) => {
|
|
|
|
|
+ // uni.showLoading({
|
|
|
|
|
+ // title: '加载中'
|
|
|
|
|
+ // });
|
|
|
|
|
+ if (initPage) state.pageNum = 1;//如果是下拉刷新、重新查询 默认加载第一页
|
|
|
|
|
+ state.isLoading = true;
|
|
|
|
|
+ state.loadStatus = 'loading';
|
|
|
|
|
+ minitorPageListData({
|
|
|
|
|
+ queryStr:state.queryStr,
|
|
|
|
|
+ courseType:state.courseType,
|
|
|
|
|
+ teachCourseTypeId:state.teachCourseTypeId,
|
|
|
|
|
+ teachCourseTypeClassId:state.teachCourseTypeClassId,
|
|
|
|
|
+ courseStatus:state.courseStatus,
|
|
|
|
|
+ pageSize:state.pageSize,
|
|
|
|
|
+ pageNum:state.pageNum
|
|
|
|
|
+ }).then(res=>{
|
|
|
|
|
+ if(res.code == 200){
|
|
|
|
|
+ const total = Number(res?.data?.dateList?.total) || 0;//总数
|
|
|
|
|
+ const pages = Math.ceil(total / state.pageSize);//总页数
|
|
|
|
|
+ const recordsData = res?.data?.dateList?.records || [];
|
|
|
|
|
+ state.pageList = initPage ? recordsData : [...state.pageList,...recordsData];
|
|
|
|
|
+ state.noMoreData = state.pageNum == pages;
|
|
|
|
|
+ state.pageNum++;
|
|
|
|
|
+ }
|
|
|
|
|
+ }).finally(()=>{
|
|
|
|
|
+ // uni.hideLoading();
|
|
|
|
|
+ state.isLoading = false;
|
|
|
|
|
+ state.isRefreshing = false;//下拉刷新未被触发
|
|
|
|
|
+ if(state.noMoreData){
|
|
|
|
|
+ state.loadStatus = 'no-more';
|
|
|
|
|
+ }else{
|
|
|
|
|
+ state.loadStatus = 'more';
|
|
|
|
|
+ }
|
|
|
|
|
+ //返回到页面顶部
|
|
|
|
|
+ if(initPage){
|
|
|
|
|
+ GoTop();
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ // 自定义下拉刷新被触发 下拉刷新
|
|
|
|
|
+ const OnRefresh = () =>{
|
|
|
|
|
+ state.isRefreshing = true;//下拉刷新已经被触发
|
|
|
|
|
+ OnLoadData(true);
|
|
|
|
|
+ }
|
|
|
|
|
+ //滚动到底部/右边 触发上拉刷新
|
|
|
|
|
+ const OnLoadMore = () => {
|
|
|
|
|
+ if (state.isLoading || state.noMoreData) return;
|
|
|
|
|
+ OnLoadData(false);
|
|
|
|
|
+ }
|
|
|
|
|
+ // 滚动时触发
|
|
|
|
|
+ const OnScroll = (e) => {
|
|
|
|
|
+ state.oldScrollTop = e.detail.scrollTop;
|
|
|
|
|
+ }
|
|
|
|
|
+ //返回到顶部
|
|
|
|
|
+ const GoTop = () => {
|
|
|
|
|
+ // 解决view层不同步的问题
|
|
|
|
|
+ state.scrollTop = state.oldScrollTop;
|
|
|
|
|
+ nextTick(() => {
|
|
|
|
|
+ state.scrollTop = 0
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
<style lang="scss" scoped>
|
|
|
.page_content{
|
|
.page_content{
|
|
|
- gap:32rpx;
|
|
|
|
|
- height: 100%;
|
|
|
|
|
- .list_item{
|
|
|
|
|
- &:nth-child(1){
|
|
|
|
|
- margin-top: 16rpx;
|
|
|
|
|
- }
|
|
|
|
|
- &:nth-child(2){
|
|
|
|
|
- margin-top: 16rpx;
|
|
|
|
|
|
|
+ height: calc(100% - 448rpx);
|
|
|
|
|
+ &.self_content_height{
|
|
|
|
|
+ height: calc(100% - 360rpx);
|
|
|
|
|
+ }
|
|
|
|
|
+ .scroll_view_y{
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+ .refresh_loading{
|
|
|
|
|
+ padding: 10rpx 0;
|
|
|
}
|
|
}
|
|
|
- width: calc((100% - 32rpx) / 2);
|
|
|
|
|
- overflow: hidden;
|
|
|
|
|
|
|
+ }
|
|
|
|
|
+ .page_list{
|
|
|
display: flex;
|
|
display: flex;
|
|
|
- flex-direction: column;
|
|
|
|
|
- .item_img{
|
|
|
|
|
- width: 100%;
|
|
|
|
|
- height: 220rpx;
|
|
|
|
|
- border-radius: 8rpx;
|
|
|
|
|
- }
|
|
|
|
|
- .item_title{
|
|
|
|
|
- display: flex;
|
|
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
|
+ gap:32rpx;
|
|
|
|
|
+ .list_item{
|
|
|
|
|
+ &:nth-child(1){
|
|
|
|
|
+ margin-top: 16rpx;
|
|
|
|
|
+ }
|
|
|
width: 100%;
|
|
width: 100%;
|
|
|
- margin:8rpx 0;
|
|
|
|
|
- font-weight: 400;
|
|
|
|
|
- font-size: 24rpx;
|
|
|
|
|
- color: #333333;
|
|
|
|
|
- display: -webkit-box;
|
|
|
|
|
- -webkit-line-clamp: 2;
|
|
|
|
|
- -webkit-box-orient: vertical;
|
|
|
|
|
overflow: hidden;
|
|
overflow: hidden;
|
|
|
- text-overflow: ellipsis;
|
|
|
|
|
- }
|
|
|
|
|
- .item_time{
|
|
|
|
|
display: flex;
|
|
display: flex;
|
|
|
- width: 100%;
|
|
|
|
|
- .time{
|
|
|
|
|
- font-weight: 400;
|
|
|
|
|
- font-size: 24rpx;
|
|
|
|
|
- color: #999999;
|
|
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ background: #F9FAFF;
|
|
|
|
|
+ border-radius: 20rpx;
|
|
|
|
|
+ border: 2rpx solid #E4E7ED;
|
|
|
|
|
+
|
|
|
|
|
+ .item_title{
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ padding:24rpx 16rpx 16rpx;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+ .img{
|
|
|
|
|
+ width: 32rpx;
|
|
|
|
|
+ height: 32rpx;
|
|
|
|
|
+ margin-right: 16rpx;
|
|
|
|
|
+ }
|
|
|
|
|
+ .title{
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ white-space: nowrap;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ text-overflow: ellipsis;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+ font-size: 28rpx;
|
|
|
|
|
+ color: #333333;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ .item_status{
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
|
+ gap: 16rpx;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ padding: 0 16rpx 24rpx;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+ .status{
|
|
|
|
|
+ height: 48rpx;
|
|
|
|
|
+ display: inline-flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ padding: 0 12rpx;
|
|
|
|
|
+ border-radius: 8rpx;
|
|
|
|
|
+ font-weight: 400;
|
|
|
|
|
+ font-size: 24rpx;
|
|
|
|
|
+ &.going{
|
|
|
|
|
+ background-color: rgba(43,198,68,0.1);
|
|
|
|
|
+ color: #2BC644;
|
|
|
|
|
+ }
|
|
|
|
|
+ &.finished{
|
|
|
|
|
+ background-color: rgba(245,108,108,0.1);
|
|
|
|
|
+ color: #F56C6C;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ .item_field{
|
|
|
|
|
+ font-weight: 400;
|
|
|
|
|
+ font-size: 24rpx;
|
|
|
|
|
+ color: #999999;
|
|
|
|
|
+ word-break: break-all;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ .item_complete_status{
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ padding: 24rpx 16rpx;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+ border-top: 2rpx solid #E4E7ED;
|
|
|
|
|
+ .complete_status{
|
|
|
|
|
+ font-weight: 400;
|
|
|
|
|
+ font-size: 24rpx;
|
|
|
|
|
+ color: #999999;
|
|
|
|
|
+ }
|
|
|
|
|
+ .btn_detail{
|
|
|
|
|
+ width: 160rpx;
|
|
|
|
|
+ height: 64rpx;
|
|
|
|
|
+ background-color: #2E64FA;
|
|
|
|
|
+ border-radius: 8rpx;
|
|
|
|
|
+ border: 2rpx solid #2E64FA;
|
|
|
|
|
+ display: inline-flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ font-weight: 400;
|
|
|
|
|
+ font-size: 28rpx;
|
|
|
|
|
+ color: #FFFFFF;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
}
|
|
}
|
|
|
</style>
|
|
</style>
|