wangxy há 2 meses atrás
pai
commit
d83d6af99c

+ 12 - 0
api/kecheng.js

@@ -58,4 +58,16 @@ export function getKechengGlTime(data = {}) {
     data,
     timeout: 20000
   })
+}
+
+export function getVideoAuth(data = {}) {
+  return request({
+    url: '/app/video/auth',
+    headers: {
+      isToken: false
+    },
+    method: 'post',
+    data,
+    timeout: 20000
+  })
 }

+ 25 - 0
api/lianxi.js

@@ -0,0 +1,25 @@
+import request from '@/utils/request'
+
+export function getLianxiList(data = {}) {
+  return request({
+    url: '/app/lianxi/guanliyuan/list',
+    headers: {
+      isToken: false
+    },
+    method: 'post',
+    data,
+    timeout: 20000
+  })
+}
+
+export function getLianxiInfo(data = {}) {
+  return request({
+    url: '/app/lianxi/guanliyuan/info',
+    headers: {
+      isToken: false
+    },
+    method: 'post',
+    data,
+    timeout: 20000
+  })
+}

+ 52 - 0
components/kecheng-mulu/kecheng-mulu.vue

@@ -0,0 +1,52 @@
+<template>
+	<view class="kecheng-mulu">
+	<!-- 章collapse -->
+		<uni-collapse v-model="collapse.chapterActiveName" accordion>
+				<!-- 章 -->
+			<uni-collapse-item v-for="(chapter,i) in chapterArr" :key="i"
+				:title="chapter.name" :name="chapter.i">
+				<scroll-view :scroll-y="true" :style="{ height: 100*5+'rpx' }">
+					<!-- 节collapse -->
+					<uni-collapse v-model="collapse.sectionActiveName" accordion>
+						<!-- 节 -->
+						<uni-collapse-item v-for="(section,j) in chapter.jieList" :key="j"
+							:title="section.name" :name="section.j">
+							<view>asdasd</view>
+							<text>123asdasd</text>
+						</uni-collapse-item>
+					</uni-collapse>
+				</scroll-view>
+			</uni-collapse-item>
+		</uni-collapse>
+	</view>
+</template>
+
+<script setup>
+	import {
+		reactive,
+		ref
+	} from 'vue';
+	defineProps({
+		chapterArr: {
+			type: Array,
+			default: () => ([])
+		}
+	})
+
+	const collapse = reactive({
+		chapterActiveName: '0',
+		sectionActiveName: '0',
+	})
+
+	const historyKjId = ref('')
+
+	function handleClick() {}
+
+	function getClassByType() {}
+
+	function shitiClick() {}
+</script>
+
+<style>
+
+</style>

+ 198 - 0
components/videoPlay/videoPlay.vue

@@ -0,0 +1,198 @@
+<template>
+	<view>
+		<view ref="videoContent" id="wgy-player-test" :playAuth="playAuth" :change:playAuth="renderScript.receiveMsg"
+			:videoId="videoId" :change:videoId="renderScript.videoIdFun" :status="hideFlag"
+			:change:hideFlag="renderScript.hideFlagFun" :seekTime="seekTime" :change:seekTime="renderScript.seekTimeFun"
+			class="kecheng-video">
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: "videoPlay",
+		data() {
+			return {
+				playAuth: "", //播放凭证
+				hideFlag: 'show',
+				videoId: "", //阿里云视频id
+				seekTime: '',
+			};
+		},
+		onUnload() {
+			// 切换
+			this.hideFlag = 'hide'
+		},
+		onHide() {
+			this.hideFlag = 'hide'
+		},
+		methods: {
+			init(options) {
+				this.playAuth = options.playAuth;
+				this.videoId = options.videoId;
+				this.seekTime = options.seekTime;
+			},
+			setSeekTime(seekTime) {
+				this.seekTime = '';
+				this.$nextTick(() => {
+					this.seekTime = seekTime;
+				})
+			},
+		}
+	}
+</script>
+
+<script module="renderScript" lang="renderjs">
+	export default {
+		data() {
+			return {
+				player: null,
+				playAuth: '',
+				videoId: '',
+			}
+		},
+		methods: {
+			receiveMsg(newValue, oldValue, ownerInstance, instance) {
+				if (newValue) {
+					this.playAuth = ''
+					this.playAuth = newValue
+					this.loadWebPlayerSDK()
+				}
+			},
+			videoIdFun(newValue, oldValue, ownerInstance, instance) {
+				if (newValue) {
+					this.videoId = ''
+					this.videoId = newValue
+				}
+			},
+			hideFlagFun(newValue, oldValue, ownerInstance, instance) {
+				if (this.player) {
+					this.player.pause()
+				}
+			},
+			seekTimeFun(newValue, oldValue, ownerInstance, instance) {
+				if (newValue) {
+					this.player.seek(newValue)
+				}
+			},
+			playAli() {
+				let that = this
+				//配置播放器
+				if (!this.playAuth) {
+					return false;
+				}
+				let player = new Aliplayer({
+					id: "wgy-player-test",
+					vid: this.videoId,
+					playauth: this.playAuth,
+					extraInfo: {
+						poster: 'noposter'
+					},
+					skinLayout: [{
+							name: "bigPlayButton",
+							align: "blabs",
+							x: 30,
+							y: 80
+						},
+						{
+							name: "H5Loading",
+							align: "cc"
+						},
+						{
+							name: "controlBar",
+							align: "blabs",
+							x: 0,
+							y: 0,
+							children: [{
+									name: "progress",
+									align: "blabs",
+									x: 0,
+									y: 44
+								},
+								{
+									name: "playButton",
+									align: "tl",
+									x: 15,
+									y: 12
+								},
+								{
+									name: "fullScreenButton",
+									align: "tr",
+									x: 10,
+									y: 12
+								},
+								{
+									name: "timeDisplay",
+									align: "tr",
+									x: 10,
+									y: 5
+								}
+							]
+						}
+					],
+					qualitySort: "asc",
+					format: "mp4",
+					mediaType: "video",
+					encryptType: 1,
+					autoplay: false,
+					isLive: false,
+					rePlay: false,
+					playsinline: true,
+					preload: false,
+					controlBarVisibility: "hover",
+					useH5Prism: true
+
+				}, function(player) {});
+				this.player = player;
+				player.on('canplay', function() {
+					player.tag.play();
+				});
+				player.on('ended', function() {
+					that.$ownerInstance.callMethod('playEnd', {
+						data: 'end'
+					})
+				});
+			},
+			isHasScript() {
+				let scriptExists = false;
+				for (let script of document.scripts) {
+					if (script.src === 'https://g.alicdn.com/de/prismplayer/2.9.6/aliplayer-min.js') {
+						scriptExists = true;
+						break;
+					}
+				}
+				return scriptExists
+			},
+			loadWebPlayerSDK() {
+				if (this.player) {
+					this.player.dispose();
+				}
+				if (this.isHasScript()) {
+					this.playAli()
+					return;
+				}
+				return new Promise((resolve, reject) => {
+					const s_tag = document.createElement('script'); // 引入播放器js
+					s_tag.type = 'text/javascript';
+					s_tag.src = 'https://g.alicdn.com/de/prismplayer/2.9.6/aliplayer-min.js';
+					s_tag.charset = 'utf-8';
+					s_tag.onload = () => {
+						//	console.log(this.playAuth);
+						this.playAli()
+						resolve();
+					}
+					document.body.appendChild(s_tag);
+					const l_tag = document.createElement('link'); // 引入播放器css
+					l_tag.rel = 'stylesheet';
+					l_tag.href =
+						'https://g.alicdn.com/de/prismplayer/2.9.6/skins/default/aliplayer-min.css';
+					document.body.appendChild(l_tag);
+				});
+			},
+		}
+	}
+</script>
+
+<style lang="scss">
+
+</style>

+ 15 - 1
pages.json

@@ -56,7 +56,7 @@
 			"path" : "pages/admin/Kecheng/list",
 			"style" : 
 			{
-				"navigationBarTitleText" : ""
+				"navigationStyle": "custom"
 			}
 		},
 		{
@@ -66,6 +66,20 @@
 				"navigationBarTitleText" : "demo1",
 				"navigationStyle": "custom"
 			}
+		},
+		{
+			"path" : "pages/admin/Kecheng/study",
+			"style" : 
+			{
+				"navigationStyle": "custom"
+			}
+		},
+		{
+			"path" : "pages/admin/Lianxi/list",
+			"style" : 
+			{
+				"navigationStyle": "custom"
+			}
 		}
 	],
 	 "tabBar": {

+ 4 - 2
pages/admin/Kaoshi/list.vue

@@ -80,8 +80,10 @@
 		}
 	})
 	
-	function goUpPage(){
-		
+	function goUpPage() {
+		uni.redirectTo({
+			url: '/pages/admin/ShouYe/shouye'
+		})
 	}
 	
 	function handleConfirmKs(ksId) {

+ 56 - 42
pages/admin/Kecheng/list.vue

@@ -1,31 +1,35 @@
 <template>
-	<view class="phone-kecheng-page">
+	<view class="admin-kaoshi-page">
+		<view class="icon-title-navBar-box">
+			<view @click="goUpPage" class="nav-bar-icon"></view>
+			<text class="nav-bar-title">课程管理</text>
+		</view>
 		<!-- 查询职业 -->
-		<view style="padding: 10px">
-			<view class="phone-search-content">
-				<input class="search-input" placeholder="请输入职业名称" v-model="data.zyName" />
-				<view class="search-icon" @click="handleSearch">
-					<uni-icons type="search" size="20"></uni-icons>
-				</view>
+		<view class="phone-search-box">
+			<input class="search-input" placeholder="请输入职业名称" v-model="data.zyName" />
+			<view class="search-icon" @click="handleSearch">
+				<uni-icons type="search" size="24" color="#fff"></uni-icons>
 			</view>
 		</view>
-		<!-- 考试列表 -->
-		<view class="cuoti-content-box">
-			<scroll-view scroll-y="true" refresher-enabled="true" :refresher-triggered="data.loading" 
+		<!-- 课程列表 -->
+		<view class="kaoshi-content-box">
+			<scroll-view scroll-y="true" refresher-enabled="true" :refresher-triggered="data.loading"
 				:refresher-threshold="50" refresher-background="transparent" @refresherrefresh="onRefresh"
-				class="cuoti-scroll-view">
-				<uni-list>
-					<uni-list-item v-for="item in data.list" class="list-item-box">
+				class="kaoshi-scroll-view">
+				<uni-list class="admin-list-box">
+					<uni-list-item v-for="item in data.list" class="admin-list-item-box">
 						<template v-slot:body>
-							<!-- 数量 -->
-							<view class="item-cuoti-row">
-								<view>{{item.ksName}}</view>
-								<view>时间:{{item.totalTm}} 分钟</view>
-								<view>次数: {{item.maxTimes}}</view>
-								<view>总分: {{item.ksScore}}</view>
-								<view>及格分: {{item.okScore}}</view>
+							<view class="item-kaoshi-row">
+								<!-- 数量 -->
+								<view class="ks-item-top">
+									<view>{{item.name}}</view>
+									<view class="ks-zyLevelName">{{item.zyLevelName}}</view>
+								</view>
+								<view class="ks-totalTm">
+									<icon class="phone-time-icon" />时间:{{formatDuration(item.period)}}分钟
+								</view>
+								<button @click="checkKecheng(item)" type="primary" size="mini"  class="kaoshi-btn">查看内容</button>
 							</view>
-							<view @click="checkKaoshi(item)" class="cuoti-btn">查看内容</view>
 						</template>
 					</uni-list-item>
 					<uni-load-more :status="data.state" @click="getMore(0)"
@@ -33,21 +37,27 @@
 				</uni-list>
 			</scroll-view>
 		</view>
+
+		<!-- 页面底端 -->
+		<customTabbarAdminVue></customTabbarAdminVue>
 	</view>
 </template>
 
 <script setup>
+	import customTabbarAdminVue from "@/components/custom-tabbar/custom-tabbar-admin.vue";
 	import {
-		ref,reactive
+		ref,
+		reactive
 	} from "vue";
 	import {
 		onLoad
 	} from "@dcloudio/uni-app";
 	import * as kechengApi from "@/api/kecheng.js"
+	import {formatDuration} from "@/utils/common.js"
 
 	const data = reactive({
 		zyName: '', // 职业名称
-		list: [],  // 考试列表
+		list: [], // 考试列表
 		loading: false,
 		page: 0,
 		size: 10,
@@ -58,25 +68,31 @@
 			contentnomore: '没有更多'
 		}
 	})
-	
+
+	function goUpPage() {
+		uni.redirectTo({
+			url: '/pages/admin/ShouYe/shouye'
+		})
+	}
+
 	function handleSearch() {
 		data.page = 0;
 		refreshData();
 	}
 
-	function checkKaoshi(item) {
+	function checkKecheng(item) {
 		uni.navigateTo({
-			url: `/pages/admin/Kecheng/exam?ksId=${item.ksId}`
+			url: `/pages/admin/Kecheng/study?kcId=${item.kcId}`
 		})
 	}
-	
+
 	function onRefresh() {
 		data.page = 0;
 		data.list = [];
 		data.loading = true;
 		refreshData();
 	}
-	
+
 	function refreshData() {
 		const opt = {
 			page: 1,
@@ -88,16 +104,16 @@
 		data.state = 'loading';
 		data.page++;
 		opt.page = data.page;
-		
-		kechengApi.getKechengGlList(opt).then(res =>{
+
+		kechengApi.getKechengGlList(opt).then(res => {
 			data.list = data.list.concat(res.data.data);
 			data.loading = false;
-			
-			if (res.data.total >= data.list.length) {
-				data.state = 'no-more';
+
+			if (res.data.total > data.list.length) {
+				data.state = 'more';
 				data.loading = false;
 			} else {
-				data.state = 'more';
+				data.state = 'no-more';
 				data.loading = false;
 			}
 		}).catch(err => {
@@ -116,22 +132,20 @@
 		data.state = 'loading';
 		data.page++;
 		opt.page = data.page;
-		kechengApi.getKechengGlList(opt).then(res =>{
+		kechengApi.getKechengGlList(opt).then(res => {
 			data.list = data.list.concat(res.data.data);
 			data.loading = false;
-			
-			if (res.data.total >= data.list.length) {
-				// 数学
-				data.state = 'no-more';
+
+			if (res.data.total > data.list.length) {
+				data.state = 'more';
 				data.loading = false;
 			} else {
-				// 数学
-				data.state = 'more';
+				data.state = 'no-more';
 				data.loading = false;
 			}
 		})
 	}
-	
+
 	onLoad(() => {
 		getMore()
 	})

+ 99 - 0
pages/admin/Kecheng/study.vue

@@ -0,0 +1,99 @@
+<template>
+	<view class="kecheng-study-page">
+		<view class="icon-title-navBar-box">
+			<view @click="goUpPage" class="nav-bar-icon"></view>
+			<text class="nav-bar-title">{{title}}</text>
+		</view>
+		<!-- 播放器 -->
+		<videoPlayVue ref="videoRef"></videoPlayVue>
+		<!-- 中间区域 -->
+		<view>
+			<view>{{period}}分钟</view>
+			<view>{{userCount}}人学习</view>
+		</view>
+		<!-- 大纲 -->
+		<view class="uni-padding-wrap uni-common-mt">
+			<uni-segmented-control :current="current" :values="items" style-type="text"
+				:active-color="activeColor" @clickItem="onClickItem" />
+		</view>
+		<view class="content">
+			<!-- 目录 -->
+			<view v-if="current === 0">
+				<kechengMuluVue :chapterArr="list"></kechengMuluVue>
+			</view>
+			<!-- 介绍 -->
+			<view v-if="current === 1"><text class="content-text">选项卡2的内容</text></view>
+		</view>
+
+
+	</view>
+</template>
+
+<script>
+	import * as kechengApi from "@/api/kecheng.js";
+	import videoPlayVue from "@/components/videoPlay/videoPlay.vue";
+	import kechengMuluVue from "@/components/kecheng-mulu/kecheng-mulu.vue";
+	import {
+		formatDuration
+	} from "@/utils/common.js"
+
+	export default {
+		components: {
+			videoPlayVue,kechengMuluVue
+		},
+		data() {
+			return {
+				items: ['目录', '介绍'],
+				colors: ['#007aff', '#4cd964', '#dd524d'],
+				activeColor: '#007aff',
+				current: 0, // 激活的选项卡
+				kcId: '', // 课程
+				title: '',
+				period: 0, // 时长
+				userCount: 0, // 学习人数
+				list: [],
+			}
+		},
+		onLoad(options) {
+			this.kcId = options.kcId;
+			this.init();
+		},
+		methods: {
+			goUpPage() {
+				uni.redirectTo({
+					url: '/pages/admin/Kecheng/list'
+				})
+			},
+			onClickItem(e) {
+				if (this.current !== e.currentIndex) {
+					this.current = e.currentIndex
+				}
+			},
+	
+			init() {
+				kechengApi.getKechengGlStart({
+					kcId: this.kcId
+				}).then(res => {
+					console.log('rrr', res.data)
+					const {
+						userCount,
+						period,
+						name,
+						kejianUserVo,
+						intro
+					} = res.data;
+					this.userCount = userCount;
+					this.period = formatDuration(period);
+					this.name = name;
+					this.list = kejianUserVo.zhangList;
+					this.intro = intro;
+				})
+			}
+		}
+	}
+</script>
+
+
+<style>
+
+</style>

+ 175 - 0
pages/admin/Lianxi/list.vue

@@ -0,0 +1,175 @@
+<template>
+	<view class="admin-kaoshi-page">
+		<view class="icon-title-navBar-box">
+			<view @click="goUpPage" class="nav-bar-icon"></view>
+			<text class="nav-bar-title">练习管理</text>
+		</view>
+		<!-- 查询职业 -->
+		<view class="phone-search-box">
+			<input class="search-input" placeholder="请输入职业名称" v-model="data.zyName" />
+			<view class="search-icon" @click="handleSearch">
+				<uni-icons type="search" size="24" color="#fff"></uni-icons>
+			</view>
+		</view>
+		<!-- 考试列表 -->
+		<view class="kaoshi-content-box">
+			<scroll-view scroll-y="true" refresher-enabled="true" :refresher-triggered="data.loading"
+				:refresher-threshold="50" refresher-background="transparent" @refresherrefresh="onRefresh"
+				class="kaoshi-scroll-view">
+				<uni-list class="admin-list-box">
+					<uni-list-item v-for="item in data.list" class="admin-list-item-box">
+						<template v-slot:body>
+							<!-- 考试项 -->
+							<view class="item-kaoshi-row">
+								<!-- 考试名 + 等级 -->
+								<view class="ks-item-top">
+									<view class="ks-name">{{item.lxName}}</view>
+									<view class="ks-zyLevelName">{{item.zyLevelName}}</view>
+								</view>
+								<!-- 时间 -->
+								<view class="ks-totalTm">
+									<icon class="phone-time-icon" />时间:{{item.totalTm}}分钟
+								</view>
+								<view class="ks-totalTm">
+									<icon class="phone-cishu-icon" />次数:{{item.maxTimes}}次
+								</view>
+								<!-- 分数 -->
+								<view class="ks-score-content">
+									<view class="ks-score">
+										<icon class="phone-zongfen-icon" />总分:<text>{{item.ksScore}}</text>
+									</view>
+									<view class="ks-okScore">
+										<icon class="phone-jigefen-icon" />及格分:<text>{{item.okScore}}</text>
+									</view>
+								</view>
+								<button type="primary" size="mini" @click="checkKsXz(item)"
+									class="kaoshi-btn">查看内容</button>
+							</view>
+						</template>
+					</uni-list-item>
+					<uni-load-more :status="data.state" @click="getMore(0)"
+						:contentText="data.contentText"></uni-load-more>
+				</uni-list>
+			</scroll-view>
+		</view>
+		<!-- 页面底端 -->
+		<customTabbarAdminVue></customTabbarAdminVue>
+		<!-- 考试须知 -->
+		<!-- <kaoshixuzhiVue ref="ksxzRef" @confirm="handleConfirmKs"></kaoshixuzhiVue> -->
+	</view>
+</template>
+
+<script setup>
+	import * as lianxiApi from "@/api/lianxi.js";
+	import customTabbarAdminVue from "@/components/custom-tabbar/custom-tabbar-admin.vue";
+	import {
+		ref,
+		reactive
+	} from "vue";
+	import {
+		onLoad
+	} from "@dcloudio/uni-app";
+	
+	const ksxzRef = ref(null);
+	
+	const data = reactive({
+		zyName: '', // 职业名称
+		list: [], // 考试列表
+		loading: false,
+		page: 0,
+		size: 8,
+		state: 'more',
+		contentText: {
+			contentdown: '查看更多',
+			contentrefresh: '加载中',
+			contentnomore: '没有更多'
+		}
+	})
+	
+	function goUpPage() {
+		uni.redirectTo({
+			url: '/pages/admin/ShouYe/shouye'
+		})
+	}
+	
+	function handleSearch() {
+		data.page = 0;
+		refreshData();
+	}
+	
+	function checkKaoshi(item) {
+		uni.navigateTo({
+			url: `/pages/admin/Lianxi/info?lxId=${item.lxId}`
+		})
+	}
+	
+	function onRefresh() {
+		data.page = 0;
+		data.list = [];
+		data.loading = true;
+		refreshData();
+	}
+	
+	function refreshData() {
+		const opt = {
+			page: 1,
+			size: data.size, // 固定查询10条
+			zyName: data.zyName
+		}
+		data.list = [];
+		// 数学
+		data.state = 'loading';
+		data.page++;
+		opt.page = data.page;
+	
+		lianxiApi.getLianxiList(opt).then(res => {
+			data.list = data.list.concat(res.data.data);
+			data.loading = false;
+	
+			if (res.data.total > data.list.length) {
+				data.state = 'more';
+				data.loading = false;
+			} else {
+				data.state = 'no-more';
+				data.loading = false;
+		
+			}
+		}).catch(err => {
+			data.state = 'more';
+			data.loading = false;
+		})
+	}
+	
+	function getMore() {
+		const opt = {
+			page: 1,
+			size: data.size, // 固定查询10条
+			zyName: data.zyName
+		}
+		if (data.state == 'no-more') return;
+		data.state = 'loading';
+		data.page++;
+		opt.page = data.page;
+		lianxiApi.getLianxiList(opt).then(res => {
+			data.list = data.list.concat(res.data.data);
+			data.loading = false;
+	
+			if (res.data.total > data.list.length) {
+				data.state = 'more';
+				data.loading = false;
+			} else {
+				data.state = 'no-more';
+				data.loading = false;
+			}
+		})
+	}
+	
+	onLoad(() => {
+		getMore()
+	})
+	
+</script>
+
+<style>
+
+</style>

+ 5 - 1
utils/common.js

@@ -65,4 +65,8 @@ export function debounce(func, wait) {
       func.apply(this, args);
     }, wait);
   };
-}
+}
+
+export  function formatDuration(duration = 0) {
+      return Math.round(duration / 60);
+    }