Browse Source

修改详情页面

wangxy 3 weeks ago
parent
commit
4bea7b4fd1

+ 122 - 0
api/chanpinZiRanPinDu.js

@@ -0,0 +1,122 @@
+import request from '@/utils/request'
+
+export function getPinduChanpinBanbenSave(data = {}) {
+    return request({
+        'url': '/app/pindu/chanpin/banben/save',
+        headers: {
+            isToken: true
+        },
+        method: 'post',
+        data,
+        timeout: 20000
+    })
+}
+
+
+export function getPinduChanpinBanbenList(data = {}) {
+    return request({
+        'url': '/app/pindu/chanpin/banben/list',
+        headers: {
+            isToken: true
+        },
+        method: 'post',
+        data,
+        timeout: 20000
+    })
+}
+export function getPinduChanpinBanbenInfo(data = {}) {
+    return request({
+        'url': '/app/pindu/chanpin/banben/info',
+        headers: {
+            isToken: true
+        },
+        method: 'post',
+        data,
+        timeout: 20000
+    })
+}
+
+export function getPinduChanpinShitiList(data = {}) {
+    return request({
+        'url': '/app/pindu/chanpin/shiti/list',
+        headers: {
+            isToken: true
+        },
+        method: 'post',
+        data,
+        timeout: 20000
+    })
+}
+
+export function getPinduChanpinShitiSave(data = {}) {
+    return request({
+        'url': '/app/pindu/chanpin/shiti/save',
+        headers: {
+            isToken: true
+        },
+        method: 'post',
+        data,
+        timeout: 20000
+    })
+}
+
+
+export function getPinduChanpinDanyuanInfo(data = {}) {
+    return request({
+        'url': '/app/pindu/chanpin/danyuan/dagang/info',
+        headers: {
+            isToken: true
+        },
+        method: 'post',
+        data,
+        timeout: 20000
+    })
+}
+
+export function getPinduChanpinJieInfo(data = {}) {
+    return request({
+        'url': '/app/pindu/chanpin/jie/info',
+        headers: {
+            isToken: true
+        },
+        method: 'post',
+        data,
+        timeout: 20000
+    })
+}
+
+export function getPinduChanpinSave(data = {}) {
+    return request({
+        'url': '/app/pindu/chanpin/save',
+        headers: {
+            isToken: true
+        },
+        method: 'post',
+        data,
+        timeout: 20000
+    })
+}
+
+export function getPinduChanpinWancheng(data = {}) {
+    return request({
+        'url': '/app/pindu/chanpin/wancheng',
+        headers: {
+            isToken: true
+        },
+        method: 'post',
+        data,
+        timeout: 20000
+    })
+}
+
+export function getPinduChanpinDanyuanMulu(data = {}) {
+    return request({
+        'url': '/app/pindu/chanpin/danyuan/list',
+        headers: {
+            isToken: true
+        },
+        method: 'post',
+        data,
+        timeout: 20000
+    })
+}

+ 24 - 0
api/shop.js

@@ -60,6 +60,30 @@ export function getAppCp2Info(data = {}) {
 	})
 }
 
+export function getAppCp3Buy(data = {}) {
+	return request({
+		url: "/app/shop/pindu/buy",
+		headers: {
+			isToken: true
+		},
+		method: 'post',
+		data,
+		timeout: 20000
+	})
+}
+
+export function getAppCp3Info(data = {}) {
+	return request({
+		url: "/app/shop/pindu/info",
+		headers: {
+			isToken: true
+		},
+		method: 'post',
+		data,
+		timeout: 20000
+	})
+}
+
 
 export function orderPayAli(data = {}) {
 	return request({

+ 32 - 1
pages.json

@@ -72,12 +72,23 @@
 			}
 		},
 		{
+			"path": "pages/chanpinXuanze/cp3/banben",
+			"style": {
+				"navigationStyle": "custom"
+			}
+		},
+		{
 			"path": "pages/xinshuxue/unitTest",
 			"style": {
 				"navigationStyle": "custom"
 			}
 		},
-
+		{
+			"path": "pages/ziranpindu/unitTest",
+			"style": {
+				"navigationStyle": "custom"
+			}
+		},
 		{
 			"path": "pages/chanpinMy/myInfo",
 			"style": {
@@ -103,6 +114,12 @@
 			}
 		},
 		{
+			"path": "pages/ziranpindu/lookShipin",
+			"style": {
+				"navigationStyle": "custom"
+			}
+		},
+		{
 			"path" : "pages/chanpinMy/yinsizhengce",
 			"style" :
 			{
@@ -138,6 +155,20 @@
 			}
 		},
 		{
+			"path" : "pages/chanpinShop/cp3/intro",
+			"style" :
+			{
+				"navigationStyle": "custom"
+			}
+		},
+		{
+			"path" : "pages/chanpinShop/cp3/dingdan",
+			"style" :
+			{
+				"navigationStyle": "custom"
+			}
+		},
+		{
 			"path" : "pages/chanpinMy/duihuanma",
 			"style" :
 			{

+ 3 - 3
pages/chanpinShop/components/yingyuList.vue

@@ -1,7 +1,7 @@
 <template>
 	<view class="shop-card-list" v-if="list.length">
-    <template  v-for="{chanpin,value:item} in list" :item="item">
-      <cardVue v-if="chanpin == 'xxx'" :item="item" :key="item.chanpinId" class="sx-card-box"></cardVue>
+    <template  v-for="{chanpin,value:item} in list">
+      <cardVue v-if="chanpin == 'ziranpindu'" :item="item" :key="item.chanpinId"></cardVue>
     </template>
 
 	</view>
@@ -12,7 +12,7 @@
 </template>
 
 <script setup>
-  import cardVue from '../cp1/card.vue';
+  import cardVue from '../cp3/card.vue';
 
 	const props = defineProps({
 		list: {

+ 35 - 0
pages/chanpinShop/cp3/card.vue

@@ -0,0 +1,35 @@
+<template>
+  <view class="shop-card-box" @click="handleClick">
+      <!-- 封面 -->
+      <image :src="item.cover" class="shop-img"></image>
+      <view class="card-right-box">
+        <!-- 名称 -->
+        <view class="card-title">{{item.name}}</view>
+        <!-- 简介 -->
+        <view class="card-content">{{item.intro}}</view>
+        <!-- 共计 -->
+        <view class="card-price">¥{{item.price}}</view>
+      </view>
+  </view>
+</template>
+
+<script setup>
+import ezyActiveVue from "@/components/ezyActive/ezyActive.vue";
+const props = defineProps({
+  item: {
+    type: Object
+  }
+})
+
+	// 选择产品等级
+function handleClick() {
+	uni.navigateTo({
+		url: '/pages/chanpinShop/cp3/intro'
+	})
+}
+
+</script>
+
+<style scoped>
+
+</style>

+ 275 - 0
pages/chanpinShop/cp3/dingdan.vue

@@ -0,0 +1,275 @@
+<template>
+	<view class="ezy-qrdd-page">
+		<view class="icon-title-navBar-box">
+			<view class="nav-bar-icon" @click="handleBack"></view>
+			<text class="nav-bar-title">确认订单</text>
+		</view>
+		<view class="qrdd-body-box">
+			<!-- 卡片 -->
+			<view class="dd-item-box">
+				<!-- 封面 -->
+				<image class="item-img-box" :src="data.cover" mode=""></image>
+				<view class="item-content-box">
+					<!-- 名称 -->
+					<view class="item-name">{{data.name}}</view>
+					<!-- 简介 -->
+					<view class="item-intro">{{data.intro}}</view>
+					<!-- 价格 -->
+					<view class="item-xianjia">¥{{xianjia}}</view>
+				</view>
+				<view class="item-play-btn"></view>
+			</view>
+			<!-- 等级 -->
+			<view class="qrdd-border-box">
+				<view class="kcxxdj-title">课程学习等级</view>
+				<view class="kcxxdj-tc-box">
+					<!-- 套餐 -->
+					<ezyActiveVue class="ezy-btn-active tc-item" v-for="item in data.taocanList"
+						@click="handleSelectTaoCan(item)" :class="{active: item.taocanId == activeTaocan.taocanId}">
+						{{item.name}}
+					</ezyActiveVue>
+				</view>
+			</view>
+
+			<!-- 商品总价 -->
+			<view class="qrdd-border-box">
+				<view class="border-row">
+					<view>商品总价</view>
+					<view>¥{{yuanjia}}</view>
+				</view>
+				<view class="border-row">
+					<view>优惠券</view>
+					<view class="jg-text">-¥{{youhui}}</view>
+				</view>
+				<view class="border-row sum-row">
+					<view class="sum-text">合计</view>
+					<view class="jg-text">¥{{xianjia}}</view>
+				</view>
+			</view>
+			<!-- 支付模式 -->
+			<template v-if="currentPlatform != 'ios'">
+				<radio-group @change="radioChange" class="qrdd-border-box">
+					<label class="border-row" v-for="(item, index) in items" :key="item.value">
+						<view class="zzfs-name-box">
+							<icon :class="{
+							  'wechat-icon': item.name === '微信',
+							  'alipay-icon': item.name === '支付宝'
+							}"></icon>
+							<text>{{item.name}}</text>
+						</view>
+						<radio :value="item.value" :checked="index === current" style="transform:scale(0.7)" />
+					</label>
+				</radio-group>
+			</template>
+		</view>
+
+		<!-- 支付区 -->
+		<view class="qrdd-footer-box">
+			<view class="jg-box">
+				<view class="sum-row">
+					<text class="sum-text">合计:</text>
+					<text class="xj-text-text">¥{{xianjia}}</text>
+				</view>
+				<view class="yh-text">共优惠¥{{youhui}}</view>
+			</view>
+			<view @click="handlePay" class="ljzf-btn">立即支付</view>
+		</view>
+		<!-- <view class="shop-mask">遮盖层</view> -->
+	</view>
+	
+	<kaiTongFongShiVue ref="kaiRef" @ykIoszhifu="ykIoszhifu" @success="handlePay"></kaiTongFongShiVue>
+</template>
+
+<script setup>
+	import {
+		reactive,
+		ref,
+		computed,
+	} from "vue";
+	import {
+		onLoad,
+		onShow
+	} from "@dcloudio/uni-app"
+	import * as shopHttp from "@/api/shop.js"
+	import kaiTongFongShiVue from "../components/kaiTongFongShi.vue";
+	import {
+		usePay
+	} from "../usePay.js";
+	import {
+		getUserIsYouke
+	} from "@/utils/common.js"
+	import cacheManager from "@/utils/cacheManager.js";
+	import ezyActiveVue from "@/components/ezyActive/ezyActive.vue";
+	
+	
+	const currentPlatform = ref(null);
+
+	function isIOSorAndroid() {
+		const systemInfo = uni.getSystemInfoSync();
+
+		if (systemInfo.platform == 'ios') {
+			currentPlatform.value = 'ios'
+		} else {
+			currentPlatform.value = 'android'
+		}
+	}
+
+	const data = reactive({
+		chanpinId: null,
+		cover: null,
+		intro: null,
+		name: null,
+		taocanList: []
+	})
+
+	const activeTaocan = ref(null)
+	const kaiRef = ref(null)
+
+	const current = ref(0)
+	const items = ref([{
+		name: '微信',
+		value: '0'
+	}, {
+		name: '支付宝',
+		value: '1'
+	}])
+
+
+
+	const youhui = computed(() => {
+		if (!activeTaocan.value) {
+			return '0.00'
+		} else {
+			return activeTaocan.value.youhui
+		}
+	})
+
+	const xianjia = computed(() => {
+		if (!activeTaocan.value) {
+			return '0.00'
+		} else {
+			return activeTaocan.value.xianjia
+		}
+	})
+
+	const yuanjia = computed(() => {
+		if (!activeTaocan.value) {
+			return '0.00'
+		} else {
+			return activeTaocan.value.yuanjia
+		}
+	})
+
+	const {
+		OrderPay
+	} = usePay({
+		createOrderError: () => {}, // 创建订单失败
+		checkError: () => {}, // 校验失败
+		payError: () => {}, // 支付失败
+		paySuccess: () => {
+			// 支付成功删除contentInfo 缓存
+			cacheManager.remove("contentInfo");
+			// zhifu='success' 用于判断在订单页 游客模式ios支付成功情况,要去弹出弹窗
+			uni.navigateTo({
+				url: "/pages/chanpinMy/order?zhifu=success"
+			})
+			// uni.showLoading({
+			// 	title: '跳转中...',
+			// 	mask: true
+			// });
+			// uni.switchTab({
+			// 	url: "/pages/chanpinMy/my" // 你的F页面实际路径(不变)
+			// });
+			// setTimeout(() => {
+			// 	uni.navigateTo({
+			// 		url: "/pages/chanpinMy/order?zhifu=success", // 你的D页面路径+保留zhifu=success传参
+			// 		success: () => {
+			// 			uni.hideLoading();
+			// 		},
+			// 		fail: () => {
+			// 			uni.hideLoading();
+			// 			toast("跳转失败,请重试");
+			// 		}
+			// 	});
+			// }, 300);
+
+
+
+		}, //支付成功
+		applePayError: () => {}, // 苹果内购失败
+	});
+
+	onLoad(() => {
+		isIOSorAndroid();
+		initPage();
+		if (currentPlatform.value == 'ios') {
+			// ios 无微信与支付宝
+			current.value = -1;
+		}
+	})
+
+	function ykIoszhifu() {
+		console.log('12311');
+		const options = {
+			chanpinId: data.chanpinId,
+			taocanId: activeTaocan.value.taocanId
+		};
+		options.applePid = activeTaocan.value.applePid;
+		console.log('options', options);
+		console.log('activeTaocan.value.applePid', activeTaocan.value.applePid);
+		OrderPay('apple', options)
+	}
+
+
+	function radioChange(d) {
+		current.value = d.detail.value;
+	}
+
+	function handleSelectTaoCan(item) {
+		activeTaocan.value = item;
+	}
+
+	function initPage() {
+		shopHttp.getAppCp3Buy().then(res => {
+			Object.assign(data, res.data)
+
+			activeTaocan.value = res.data.taocanList[0]
+		})
+	}
+
+	function handlePay() {
+		if (getUserIsYouke()) {
+			// 游客
+			kaiRef.value.handleShow();
+		} else {
+			// 非游客
+			const options = {
+				chanpinId: data.chanpinId,
+				taocanId: activeTaocan.value.taocanId
+			};
+
+			if (currentPlatform.value == 'ios') {
+				options.applePid = activeTaocan.value.applePid;
+				console.log('apple支付入参', options)
+				// 苹果
+				OrderPay('apple', options)
+			} else if (currentPlatform.value != 'ios' && current.value == '0') {
+				console.log('wx支付入参', options)
+				// 微信
+				OrderPay('wx', options)
+			} else if (currentPlatform.value != 'ios' && current.value == '1') {
+				console.log('ali支付入参', options)
+				// 支付宝
+				OrderPay('ali', options)
+			}
+		}
+	}
+
+	function handleBack() {
+		uni.navigateBack()
+	}
+</script>
+
+<style>
+
+</style>

+ 80 - 0
pages/chanpinShop/cp3/intro.vue

@@ -0,0 +1,80 @@
+<template>
+	<view class="ezy-shop-info-page">
+		<view class="icon-title-navBar-box">
+			<view class="nav-bar-icon" @click="handleBack"></view>
+			<text class="nav-bar-title">商品详情</text>
+		</view>
+		<view class="shop-info-body">
+			<view class="img-content-box">
+				<img :src="imageUrl" alt="" />
+			</view>
+			<view class="fx-btn-row">
+				<view @click="fenxiang" class="fx-btn">
+					<icon class="fx-icon"></icon>
+					<view>分享</view>
+				</view>
+				<ezyActiveVue @click="handleStudy" class="ezy-btn-active bmxx-btn">立即报名学习</ezyActiveVue>
+			</view>
+		</view>
+		
+
+<!--  分享  -->
+    <SharePopup ref="sharePopup" :type="2" title="商品详情" desc="商品详情"
+                :image="imageUrl" currentPage="tupian"
+                @success="handleShareSuccess" @error="handleShareError" />
+	</view>
+</template>
+
+<script setup>
+	import {
+		reactive,
+		ref
+	} from "vue";
+	import {
+		onLoad,
+		onShow
+	} from "@dcloudio/uni-app"
+	import * as shopHttp from "@/api/shop.js"
+  import {getAppCp1Info} from "@/api/shop";
+  import ezyActiveVue from "@/components/ezyActive/ezyActive.vue";
+  import SharePopup from "@/components/sharePopUp/index.vue"
+  import {toast} from "uview-plus";
+	
+	const imageUrl = ref(null);
+  const sharePopup = ref(null);
+
+	onLoad(() => {
+		initPage()
+	})
+
+	function initPage() {
+		shopHttp.getAppCp3Info().then(res => {
+			imageUrl.value = res.data.image;
+		})
+	}
+
+  function handleShareError() {
+    toast('分享失败')
+  }
+
+  function handleShareSuccess() {
+    toast('分享成功')
+  }
+	
+	function fenxiang() {
+    sharePopup.value.open();
+  }
+	function handleStudy() {
+		uni.navigateTo({
+			url: '/pages/chanpinShop/cp2/dingdan'
+		})
+	}
+	
+	function handleBack() {
+		uni.navigateBack()
+	}
+</script>
+
+<style>
+
+</style>

+ 84 - 0
pages/chanpinXuanze/cp3/banben.vue

@@ -0,0 +1,84 @@
+<template>
+  <view class="ezy-xbb-page">
+    <view class="icon-title-navBar-box">
+      <view class="nav-bar-icon" @click="handleBack"></view>
+      <view class="nav-bar-title">选择版本</view>
+    </view>
+
+    <view class="xbb-list-box">
+      <template v-if="data.banbenList.length">
+        <ezyActiveVue class="ezy-list-item-active xbb-item-box" v-for="item in data.banbenList" :key="item.id"
+                      @aclick="handleSelect(item)">
+          <!-- 封面 -->
+          <image class="item-img-box" :src="item.cover" mode=""></image>
+          <view class="item-content-box">
+            <!-- 名称+等级 -->
+            <view class="item-name">{{ item.chanpinName }} {{ item.dengjiName }}</view>
+            <!-- 版本名称 -->
+            <view class="item-bb">{{ item.name }}</view>
+          </view>
+          <view class="item-play-btn"></view>
+        </ezyActiveVue>
+		<view class="ezy-no-more">没有更多</view>
+      </template>
+      <template v-else>
+        <view class="shiti-frame-box">
+          <view class="ezy-no-sj">
+            <icon></icon>
+            <text>暂无数据</text>
+          </view>
+        </view>
+      </template>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import {reactive} from "vue";
+import {onLoad} from "@dcloudio/uni-app"
+import * as pinduHttp from "@/api/chanpinZiRanPinDu.js"
+import cacheManager from "@/utils/cacheManager.js";
+import ezyActiveVue from "@/components/ezyActive/ezyActive.vue";
+
+const data = reactive({
+  dengjiId: null,
+  banbenList: []
+})
+
+function getBanbenList() {
+  pinduHttp.getPinduChanpinBanbenList({dengjiId: data.dengjiId}).then(res => {
+    data.banbenList = res.data;
+  })
+}
+
+function handleBack() {
+  uni.switchTab({
+    url: `/pages/chanpinXuanze/index`
+  })
+}
+
+function handleSelect(item) {
+  const opt = {
+    banbenId: item.id,
+  }
+  pinduHttp.getPinduChanpinBanbenSave(opt).then(res => {
+    if (!res.data) { return;}
+    cacheManager.get('contentInfo') && cacheManager.remove('contentInfo');
+    // 跳转
+    uni.switchTab({
+      url: "/pages/chanpinneirong/index"
+    })
+  })
+}
+
+onLoad((options) => {
+  data.dengjiId = options.dengjiId;
+  getBanbenList();
+})
+
+
+</script>
+
+<style>
+
+</style>

+ 43 - 0
pages/chanpinXuanze/cp3/card.vue

@@ -0,0 +1,43 @@
+<template>
+  <view class="sx-card-box">
+    <view class="card-head-box">
+      <!-- 封面 -->
+      <image :src="item.cover" class="head-img"></image>
+      <view class="head-right-box">
+        <!-- 名称 -->
+        <view class="head-title">{{item.name}}</view>
+        <!-- 简介 -->
+        <view class="head-content">{{item.intro}}</view>
+        <!-- 共计 -->
+        <view class="head-content">{{item.gongji}}</view>
+      </view>
+    </view>
+    <view class="card-body-box">
+      <view class="body-title">请选择学习等级</view>
+      <view class="dj-item-row">
+        <ezyActiveVue v-for="cItem in item.levelList" class="ezy-btn-active dj-item" @aclick="handleSelect(cItem)" :class="{active: cItem.active}">{{cItem.levelName}}</ezyActiveVue>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import ezyActiveVue from "@/components/ezyActive/ezyActive.vue";
+const porps = defineProps({
+  item: {
+    type: Object
+  }
+})
+
+	// 选择产品等级
+function handleSelect(item) {
+  uni.navigateTo({
+    url: `/pages/chanpinXuanze/cp3/banben?dengjiId=${item.dengjiId}`
+  })
+}
+
+</script>
+
+<style scoped>
+
+</style>

+ 43 - 0
pages/ziranpindu/card.vue

@@ -0,0 +1,43 @@
+<template>
+  <view class="sx-card-box">
+    <view class="card-head-box">
+      <!-- 封面 -->
+      <image :src="item.cover" class="head-img"></image>
+      <view class="head-right-box">
+        <!-- 名称 -->
+        <view class="head-title">{{item.name}}</view>
+        <!-- 简介 -->
+        <view class="head-content">{{item.intro}}</view>
+        <!-- 共计 -->
+        <view class="head-content">{{item.gongji}}</view>
+      </view>
+    </view>
+    <view class="card-body-box">
+      <view class="body-title">请选择学习等级</view>
+      <view class="dj-item-row">
+        <ezyActiveVue v-for="cItem in item.levelList" class="ezy-btn-active dj-item" @aclick="handleSelect(cItem)" :class="{active: cItem.active}">{{cItem.levelName}}</ezyActiveVue>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import ezyActiveVue from "@/components/ezyActive/ezyActive.vue";
+const porps = defineProps({
+  item: {
+    type: Object
+  }
+})
+
+	// 选择产品等级
+function handleSelect(item) {
+  uni.navigateTo({
+    url: `/pages/chanpinXuanze/cp3/banben?dengjiId=${item.dengjiId}`
+  })
+}
+
+</script>
+
+<style scoped>
+
+</style>

+ 391 - 0
pages/ziranpindu/components/danyuanInfo.vue

@@ -0,0 +1,391 @@
+<template>
+	<view>
+		<uni-popup ref="popupRef" :animation="true" :is-mask-click="false"
+			mask-background-color="rgba(255, 255, 255, 0.1);" type="bottom">
+			<view class="xuexi-dagang-page">
+				<view class="dagang-title">
+					<text>{{danyuanInfo.danyuanIntro}}</text>
+					<icon @click="goUpPage"></icon>
+				</view>
+				<view class="xuexi-dagang-body">
+					<view class="ezy-video-box course-video-box">
+						<view ref="videoContent" id="wgy-player-test" :playAuth="playAuth"
+							:change:playAuth="renderScript.receiveMsg" :videoId="videoId"
+							:change:videoId="renderScript.videoIdFun" :hideFlag="hideFlag"
+							:change:hideFlag="renderScript.hideFlagFun" :progressMarkers="progressMarkers"
+							:change:progressMarkers="renderScript.progressMarkersMsg" :seekTime="seekTime"
+							:change:seekTime="renderScript.seekTimeFun" class="ezy-video">
+						</view>
+					</view>
+
+					<!-- 您将学会 -->
+					<view class="dagang-xh-box">
+						<view class="xh-title">您将学会</view>
+						<view class="xh-content-box">
+							<view class="text-row" v-for="(item,index) in danyuanInfo.xuehui" :key="index">
+								<icon></icon>
+								<view class="text-content">{{item}}</view>
+							</view>
+						</view>
+					</view>
+					<!-- 学习大纲 -->
+					<view class="dagang-content-box">
+						<view class="dagang-content-title">学习大纲</view>
+						<view class="dagang-item-list">
+							<view class="dagang-content-item" v-for="(item,index) in danyuanInfo.dagangList"
+								:key="index">
+								<!-- 封面 -->
+								<!-- <img :src="item.cover" /> -->
+								<view>
+									<view class="content-title">{{item.jieName}}</view>
+									<view class="content-title">{{item.jieIntro}}</view>
+								</view>
+							</view>
+						</view>
+					</view>
+				</view>
+			</view>
+		</uni-popup>
+	</view>
+</template>
+
+<script>
+	import {
+		nextTick,
+		ref
+	} from 'vue';
+	import {
+		onLoad,
+		onReady
+	} from '@dcloudio/uni-app';
+	import {
+		getVideoAuth,
+		getVideoAuthYk,
+		videoWancheng
+	} from "@/api/shipin.js"
+	import {
+		toast,
+		convertTimeToSeconds
+	} from "@/utils/common";
+	import cacheManager from "@/utils/cacheManager.js";
+	import * as httpApi from "@/api/chanpinShuxue.js";
+	export default {
+		data() {
+			return {
+				danyuanId: null,
+				danyuanInfo: {
+					danyuanId: '',
+					dagangList: [],
+					danyuanIntro: '',
+					number: '',
+					video: '',
+					xuehui: [],
+				},
+
+				pageData: null, //上个页面获取的视频参数(视频id)
+				playAuth: "", //播放凭证
+				progressMarkers: [],
+				hideFlag: 'show',
+				videoId: "", //阿里云视频id
+				seekTime: '',
+				danyuanId: '',
+				shipinTitle: '',
+			}
+		},
+		onLoad(options) {
+			this.init(options)
+		},
+		onHide() {
+			this.hideFlag = 'hide'
+		},
+		onUnload() {
+			this.hideFlag = 'hide'
+		},
+		methods: {
+			goUpPage() {
+				this.$refs.popupRef.close();
+				this.$emit('close')
+			},
+			// 打开弹窗
+			handleShow(danyuanId) {
+				this.danyuanId = danyuanId;
+				this.getDataInfo()
+			},
+			handleClose() {
+				this.$refs.popupRef.close();
+			},
+			courseBjFun() {
+				return 'static/images/course/couse-shuxue-bj.png'
+			},
+			courseIconFun() {
+				return 'static/images/course/shuxue-icon.png'
+			},
+			getDataInfo() {
+				httpApi.getShuxueChanpinDanyuanInfo({
+					danyuanId: this.danyuanId
+				}).then(res => {
+					// 重新赋值
+					Object.assign(this.danyuanInfo, res.data)
+					this.$refs.popupRef.open();
+					nextTick(() => {
+						// 	针对视频进行赋值
+						this.videoId = this.danyuanInfo.video;
+						// 执行方法
+						this.getLive(); //获取播放凭证
+					})
+				})
+			},
+			init(options) {
+				this.danyuanId = options.danyuanId;
+				this.getDataInfo()
+			},
+			playEnd(data) {
+				// #ifdef APP-PLUS
+				plus.screen.lockOrientation('portrait-primary');
+				// #endif
+			},
+			getLive() {
+				if (!this.videoId) {
+					toast("video缺失!")
+					return false
+				}
+				let req = {
+					videoId: this.videoId
+				}
+				getVideoAuth(req).then(res => {
+					this.playAuth = res.data
+				})
+			},
+			markersClick(data) {
+				this.seekTime = ""
+				this.$nextTick(() => {
+					this.seekTime = data.offset
+				});
+			},
+
+		},
+	}
+</script>
+
+
+
+<script module="renderScript" lang="renderjs">
+	export default {
+		mounted() {
+			console.log("renderScript1")
+			// 在适合的生命周期,通过script和link标签引入播放器sdk、css
+			//	this.loadWebPlayerSDK()
+		},
+		data() {
+			return {
+				player: null,
+				playAuth: '',
+				videoId: '',
+				progressMarkers: [],
+				isFullScreen: false,
+				seekTime: ''
+
+			}
+		},
+		methods: {
+
+			receiveMsg(newValue, oldValue, ownerInstance, instance) {
+				// console.log('service层中的options发生变化')
+				// console.log('新值', newValue)
+				// console.log('旧值', oldValue)
+				// ownerInstance和this.$ownerInstance一样,可用来向service层通信
+				// instance和ownerInstance的区别是:
+				// instance.$el指向的是触发事件的那个节点;ownerInstance.$el指向当前vue文件中的根节点;
+				// 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()
+				}
+			},
+			progressMarkersMsg(newValue, oldValue, ownerInstance, instance) {
+
+				if (newValue) {
+					this.progressMarkers = newValue
+				}
+			},
+			seekTimeFun(newValue, oldValue, ownerInstance, instance) {
+				if (newValue) {
+					this.player.play()
+					this.player.seek(newValue)
+					// switch (this.player.getStatus()) {
+					// 	case 'init':
+					// 		break;
+					// 	case 'ready':
+					// 		break;
+					// 	case 'loading':
+					// 	this.player.play()
+					// 	this.player.seek(newValue)
+					// 		break;
+					// 	case 'play':
+					// 		this.player.seek(newValue)
+					// 		break;
+					// 	case 'pause':
+					// 	this.player.play()
+					// 	this.player.seek(newValue)
+					// 		break;
+					// 	case 'playing':
+					// 	this.player.seek(newValue)
+					// 		break;
+					// 	case 'waiting':
+					// 		break;
+					// 	case 'error':
+					// 		break;
+					// 	case 'ended':
+					// 		break;
+					// 	default:
+					// 		break;
+					// }
+					//	this.player.seek(newValue)
+				}
+			},
+			playAli() {
+				let that = this
+				// console.log(this.videoId);
+				// console.log(this.playAuth);
+				//配置播放器
+				if (!this.playAuth) {
+					return false;
+				}
+				var player = new Aliplayer({
+					id: "wgy-player-test",
+					"vid": this.videoId,
+					"playauth": this.playAuth,
+					extraInfo: {
+						poster: 'noposter'
+					},
+					fullscreenEvents: {
+						fullscreenChange: (isFull) => {
+							this.isFullScreen = isFull
+						}
+					},
+					//cover: 'https://img.alicdn.com/tps/TB1EXIhOFXXXXcIaXXXXXXXXXXX-760-340.jpg',
+					// "vid": '',
+					// "playauth": '',
+					// "playConfig": {
+					// 	"EncryptType": 'AliyunVoDEncryption'
+					// },
+					"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,
+					"progressMarkers": this.progressMarkers,
+					"autoplay": false,
+					"isLive": false,
+					"rePlay": false,
+					"playsinline": true,
+					"preload": false,
+					"controlBarVisibility": "hover",
+					"useH5Prism": true
+
+				}, function(player) {});
+				this.player = player;
+				player.on('canplay', function() {
+					console.log('canplay', this.player.tag);
+					player.tag.play();
+
+				});
+
+				player.on('ended', function(data) {
+					that.exitFullScreen();
+					that.$ownerInstance.callMethod('playEnd', {
+						data: 'end'
+					})
+					// uni.$emit('playEnd', {
+					// 	data: 'end'
+					// });
+				});
+			},
+			exitFullScreen() {
+				if (document.exitFullscreen) {
+					document.exitFullscreen(); // 标准方法
+				} else if (document.mozCancelFullScreen) { // Firefox
+					document.mozCancelFullScreen();
+				} else if (document.webkitExitFullscreen) { // Chrome, Safari & Opera
+					document.webkitExitFullscreen();
+				} else if (document.msExitFullscreen) { // IE/Edge
+					document.msExitFullscreen();
+				}
+			},
+
+			loadWebPlayerSDK() {
+				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>

+ 298 - 0
pages/ziranpindu/components/questionJiexi.vue

@@ -0,0 +1,298 @@
+<template>
+	<view>
+		<uni-popup ref="popupRef" :animation="false" :is-mask-click="false" type="top"
+			mask-background-color="rgba(255, 255, 255, 0.6);" class="ezy-popup-width-all">
+			<view class="ezy-dajx-page">
+				<view class="icon-title-navBar-box">
+					<view @click="handleBack" class="nav-bar-icon"></view>
+					<view class="nav-bar-title">单元测试</view>
+				</view>
+				<view class="shiti-frame-box">
+					<!-- 思路分析 -->
+					<!-- <view class="slfx-title"></view> -->
+					<!-- <view class="slfx-content"> {{data.answer}}</view> -->
+					<!-- <rich-text class="slfx-content" :nodes="data.answer"></rich-text> -->
+					<!-- 视频讲解 -->
+					<view class="spjj-title"></view>
+					<view class="ezy-video-box dajx-video-box">
+						<!-- 这里放视频 ↓ -->
+						<view class="ezy-video" ref="videoContent" id="wgy-player-test" :playAuth="playAuth"
+							:change:playAuth="renderScript.receiveMsg" :videoId="videoId"
+							:change:videoId="renderScript.videoIdFun" :hideFlag="hideFlag"
+							:change:hideFlag="renderScript.hideFlagFun" :seekTime="seekTime"
+							:change:seekTime="renderScript.seekTimeFun">
+						</view>
+					</view>
+				</view>
+			</view>
+		</uni-popup>
+		<uni-popup ref="popupRef2" :animation="true" :is-mask-click="false"
+			mask-background-color="rgba(51, 137, 217, 0.65);">
+			<view class="course-finish-dialog">
+				<view class="text-score">{{credit}}</view>
+				<view class="course-btn-box">
+					<view @click="goBack" class="return-btn"></view>
+					<view @click="goNext" class="continue-btn"></view>
+				</view>
+			</view>
+		</uni-popup>
+	</view>
+</template>
+<script>
+	import {
+		onLoad,
+		onReady
+	} from '@dcloudio/uni-app';
+	import {
+		getVideoAuth,
+	} from "@/api/shipin.js"
+	export default {
+		props: {
+			cardId: {
+				type: [String, Number],
+				default: 1
+			}
+		},
+		data() {
+			return {
+				pageData: null, //上个页面获取的视频参数(视频id)
+				playAuth: "", //播放凭证
+				progressMarkers: [],
+				videoId: "", //阿里云视频id
+				seekTime: '',
+				hideFlag: 'show',
+				data: {},
+			}
+		},
+		onHide() {
+			this.hideFlag = 'hide'
+		},
+		onUnload() {
+			this.hideFlag = 'hide'
+		},
+		methods: {
+			playEnd(data) {
+				plus.screen.lockOrientation('portrait-primary');
+				this.$refs.popupRef2.open();
+			},
+			goBack() {
+				plus.screen.unlockOrientation();
+				this.$refs.popupRef2.close();
+				this.$refs.popupRef.close()
+			},
+			goNext() {
+				plus.screen.unlockOrientation();
+				this.$refs.popupRef2.close();
+			},
+			showPopup(item) {
+				this.data = item;
+				this.videoId = item.jiangjie
+				//this.videoId = 'b997f16cb9cb474cb93526cff77d8801'
+				//	this.progressMarkers = item.progressMarkers
+				this.getLive(); //获取播放凭证
+				this.$refs.popupRef.open()
+			},
+			handleBack(item) {
+				this.$refs.popupRef.close()
+			},
+			getLive() {
+				let req = {
+					videoId: this.videoId
+				}
+				getVideoAuth(req).then(res => {
+					this.playAuth = res.data
+				})
+			},
+			markersClick(data) {
+				this.seekTime = ""
+				this.$nextTick(() => {
+					this.seekTime = data.offset
+				});
+			},
+		},
+		created() {
+			// console.log("getLive")
+			// this.getLive(); //获取播放凭证
+
+		},
+
+	}
+</script>
+
+
+
+<script module="renderScript" lang="renderjs">
+	export default {
+		mounted() {
+			console.log("renderScript1")
+			// 在适合的生命周期,通过script和link标签引入播放器sdk、css
+		},
+		data() {
+			return {
+				player: null,
+				playAuth: '',
+				videoId: '',
+				progressMarkers: [],
+				isFullScreen: false,
+				seekTime: '',
+				isFirst: -1,
+			}
+		},
+		methods: {
+			receiveMsg(newValue, oldValue, ownerInstance, instance) {
+				if (newValue) {
+					this.playAuth = newValue
+					this.loadWebPlayerSDK()
+				}
+			},
+			videoIdFun(newValue, oldValue, ownerInstance, instance) {
+				if (newValue) {
+					this.videoId = newValue
+				}
+			},
+			hideFlagFun(newValue, oldValue, ownerInstance, instance) {
+				if (this.player) {
+					this.player.pause()
+				}
+
+			},
+			progressMarkersMsg(newValue, oldValue, ownerInstance, instance) {
+				if (newValue) {
+					this.progressMarkers = newValue
+				}
+			},
+			seekTimeFun(newValue, oldValue, ownerInstance, instance) {
+				if (newValue) {
+					console.log(newValue, 'newValuenewValuenewValuenewValuenewValue')
+					console.log(this.player.getStatus(), 'newValuenewValuenewValuenewValuenewValue')
+					this.player.play()
+					this.player.seek(newValue)
+					//	this.player.seek(newValue)
+				}
+			},
+			playAli() {
+				if (this.isFirst == 0) {
+					this.isFirst = -1
+					return;
+				}
+				this.player = null;
+				let that = this
+				//配置播放器
+				var player = new Aliplayer({
+					id: "wgy-player-test",
+					"vid": this.videoId,
+					"playauth": this.playAuth,
+					extraInfo: {
+						poster: 'noposter'
+					},
+					fullscreenEvents: {
+						fullscreenChange: (isFull) => {
+							this.isFullScreen = isFull
+						}
+					},
+					// "playConfig": {
+					// 	"EncryptType": 'AliyunVoDEncryption'
+					// },
+					"skinLayout": [{
+							"name": "bigPlayButton",
+							"align": "blabs",
+							"x": 30,
+							"y": 80
+						},
+						{
+							"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,
+					"progressMarkers": this.progressMarkers,
+					"width": '100%',
+					"height": '500px',
+					"autoplay": false,
+					"isLive": false,
+					"rePlay": false,
+					"playsinline": true,
+					"preload": false,
+					"controlBarVisibility": "hover",
+					"useH5Prism": true
+
+				}, function(player) {});
+				this.player = player;
+				player.one('canplay', function() {
+					console.log('canplay', this.player.tag);
+
+					player.tag.play();
+
+				});
+				player.on('ended', function(data) {
+					that.exitFullScreen();
+					that.$ownerInstance.callMethod('playEnd', {
+						data: 'end'
+					})
+
+				});
+				this.isFirst++;
+			},
+			exitFullScreen() {
+				if (document.exitFullscreen) {
+					document.exitFullscreen(); // 标准方法
+				} else if (document.mozCancelFullScreen) { // Firefox
+					document.mozCancelFullScreen();
+				} else if (document.webkitExitFullscreen) { // Chrome, Safari & Opera
+					document.webkitExitFullscreen();
+				} else if (document.msExitFullscreen) { // IE/Edge
+					document.msExitFullscreen();
+				}
+			},
+
+			loadWebPlayerSDK() {
+				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 = () => {
+						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>

+ 59 - 0
pages/ziranpindu/components/tishiDl.vue

@@ -0,0 +1,59 @@
+<template>
+	<!-- 弹窗 -->
+	<view>
+		<uni-popup ref="popupRef" :animation="false" :is-mask-click="false" mask-background-color="rgba(0,0,0, 0.76);">
+			<view class="ezy-tip-dialog tip-e-dialog ">
+				<view class="close-btn" @click="handleClose"></view>
+				<view class="e-img kx-e-img"></view>
+				<view class="text-score">完成了本节基础课程的学习</view>
+				<view class="time-tip-box" v-if="times">({{count}}S)</view>
+			</view>
+		</uni-popup>
+	</view>
+</template>
+
+<script setup>
+	import {
+		nextTick,
+		ref
+	} from "vue"
+
+	const times = ref(null)
+	const count = ref(5);
+	const popupRef = ref(null);
+
+
+	function initTime() {
+		times.value = setTimeout(() => {
+			if (count.value == 0) {
+				handleClose();
+				return;
+			}
+			count.value--;
+			initTime()
+		}, 1000)
+	}
+
+	function clearTime() {
+		clearTimeout(times.value);
+		times.value = null;
+		count.value = 5;
+	}
+
+	function handleClose() {
+		clearTime();
+		popupRef.value.close();
+	}
+
+	function open() {
+		popupRef.value.open();
+		nextTick(() => initTime())
+	}
+
+	defineExpose({
+		open
+	})
+</script>
+
+<style>
+</style>

+ 59 - 0
pages/ziranpindu/components/tishiDl2.vue

@@ -0,0 +1,59 @@
+<template>
+	<!-- 弹窗 -->
+	<view>
+		<uni-popup ref="popupRef" :animation="false" :is-mask-click="false" mask-background-color="rgba(0,0,0, 0.76);">
+			<view class="ezy-tip-dialog tip-e-dialog ">
+				<view class="close-btn" @click="handleClose"></view>
+				<view class="e-img kx-e-img"></view>
+				<view class="text-score">完成了本节能力提升题的学习</view>
+				<view class="time-tip-box" v-if="times">({{count}}S)</view>
+			</view>
+		</uni-popup>
+	</view>
+</template>
+
+<script setup>
+	import {
+		nextTick,
+		ref
+	} from "vue"
+
+	const times = ref(null)
+	const count = ref(5);
+	const popupRef = ref(null);
+
+
+	function initTime() {
+		times.value = setTimeout(() => {
+			if (count.value == 0) {
+				handleClose();
+				return;
+			}
+			count.value--;
+			initTime()
+		}, 1000)
+	}
+
+	function clearTime() {
+		clearTimeout(times.value);
+		times.value = null;
+		count.value = 5;
+	}
+
+	function handleClose() {
+		clearTime();
+		popupRef.value.close();
+	}
+
+	function open() {
+		popupRef.value.open();
+		nextTick(() => initTime())
+	}
+
+	defineExpose({
+		open
+	})
+</script>
+
+<style>
+</style>

+ 209 - 0
pages/ziranpindu/components/unitAnswer.vue

@@ -0,0 +1,209 @@
+<template>
+	<view>
+		<uni-popup ref="popupRef" :animation="false" :is-mask-click="false" type="top"
+			mask-background-color="rgba(255, 255, 255, 0.6);" class="ezy-popup-width-all">
+			<view class="ezy-result-page">
+				<view class="icon-title-navBar-box">
+					<view @click="handleBack" class="nav-bar-icon"></view>
+					<view class="nav-bar-title">答案</view>
+				</view>
+				<view class="exam-body">
+					<view class="xx-jd-box">
+						<view class="xx-row">
+							<view>当前学习进度</view>
+							<view class="text-row">
+								<text class="dq-jd-text">{{current+1}}</text>
+								<text class="dq-jd-line">/</text>{{myList.length}}
+							</view>
+						</view>
+						<progress :percent="(current+1)/myList.length * 100" class="exam-progress-box" stroke-width="10"
+							backgroundColor="#3c7dfd" activeColor="#ffd11c" />
+					</view>
+					<view class="shiti-frame-box">
+						<w-swiper :list="myList" :positionIndex="current" class="result-exam-swiper"
+							@change="onSwiperChange">
+							<template v-slot:default="{item,index}">
+								<view class="body" v-if="item.mta_show">
+									<danxuan :question="item" showError v-if="item.type == '1'"></danxuan>
+									<panduan :question="item" showError v-if="item.type == '2'"></panduan>
+									<tiankong :question="item" showError v-if="item.type == '3'"
+										:placeholders="item.placeholders"></tiankong>
+									<view class="answer-content-box">
+										<view class="answer-title">答案</view>
+										<view class="answer-content-border answer-btn-box" v-if="item.type!=3">
+											<!-- 你的答案 -->
+											<view class="answer-item-left">
+												<text class="answer-item-title">您的答案</text>
+												<text class="answer-item-error">{{showAnswerReply(item)}}</text>
+												<view class="answer-line"></view>
+											</view>
+											<!-- 答案 -->
+											<view class="answer-item-right">
+												<text class="answer-item-title">正确答案</text>
+												<text class="answer-item-correct">{{showAnswerResult(item)}}</text>
+											</view>
+										</view>
+										<!-- 填空题答案 -->
+										<view class="answer-content-border tiankong-answer-content-box" v-else>
+											<view class="tiankong-answer-title">正确答案</view>
+											<view v-for="(ict,cindex) in showAnswerResult(item)" :key="cindex"
+												class="tiankong-answer-row">
+												<text class="answer-index-box">{{cindex+1}}</text>
+												<text v-for="(xItem,xindex) in ict" :key="xindex">
+													<text> {{xItem}} </text>
+													<text v-if="xindex != ict.length-1">/</text>
+												</text>
+											</view>
+										</view>
+
+										<!-- 试题解析 -->
+										<view class="answer-stjx-box">
+											<view class="answer-text-title">试题解析:</view>
+											<rich-text :nodes="item.answer" class="answer-rich-text"></rich-text>
+
+											<!-- 试题视频 -->
+											<view class="answer-text-title">视频讲解:</view>
+											<view class="answer-video-box" @click="handleCheckVideo(item)">
+												<img :src="item.cover" />
+											</view>
+										</view>
+									</view>
+								</view>
+							</template>
+						</w-swiper>
+						<!--  左右滑动提示  -->
+						<view class="swiper-tip-box">
+							左右滑动查看更多题目
+						</view>
+					</view>
+				</view>
+			</view>
+			<!-- 解析浮层数据 -->
+			<questionJiexi ref="jiexiRef"></questionJiexi>
+		</uni-popup>
+	</view>
+</template>
+
+<script setup>
+	import questionJiexi from './questionJiexi.vue';
+	import wSwiper from '@/components/wSwiper/wSwiper.vue';
+	import danxuan from "@/components/question/danxuan.vue";
+	import panduan from "@/components/question/panduan.vue";
+	import tiankong from "@/components/question/tiankong.vue";
+	import {
+		useQuestionTools
+	} from "@/components/question/useQuestionTools.js";
+	import {
+		computed
+	} from "vue";
+	const {
+		getLetterByIndex
+	} = useQuestionTools();
+
+	import {
+		ref
+	} from "vue";
+
+	const props = defineProps({
+		list: {
+			type: Array,
+		},
+		code: {
+			type: String,
+			default: 'cj'
+		}
+	})
+
+	const myList = computed(() => {
+		return props.list.map(item => {
+			return {
+				...item,
+				code: 'cj'
+			}
+		})
+	})
+
+	const emits = defineEmits(['back'])
+
+	const current = ref(0)
+	const popupRef = ref(null)
+	const jiexiRef = ref(null);
+	
+	function handleCheckVideo(item) {
+		showJiexiPopup(item)
+	}
+
+	function onSwiperChange(index) {
+		current.value = index;
+		uni.$emit('swiper-change', index)
+	}
+
+	// 切换成绩
+	function showPopup() {
+		popupRef.value.open()
+	}
+
+	function closePopup() {
+		popupRef.value.close()
+	}
+
+	// 展示
+	function showJiexiPopup(data) {
+		jiexiRef.value.showPopup(data);
+	}
+
+	function handleBack() {
+		// 从 单元测试 到 岛 的路由参数
+		emits('back')
+	}
+
+	function showAnswerResult(item) {
+		if (item.type == 1) {
+			// 单选题
+			return getLetterByIndex(item.result)
+		} else if (item.type == 2) {
+			if (item.result == 1) {
+				return '正确'
+			} else {
+				return '错误'
+			}
+		} else if (item.type == 4) {
+			return getLetterByIndex(item.result)
+		} else {
+			return item.result
+		}
+	}
+
+
+	function showAnswerReply(item) {
+		if (item.type == 1) {
+			if (item.reply == null) {
+				return '未答'
+			}
+			// 单选题
+			return getLetterByIndex(item.reply)
+		} else if (item.type == 2) {
+			if (item.reply == null) {
+				return '未答'
+			}
+			if (item.reply == 1) {
+				return '正确'
+			} else {
+				return '错误'
+			}
+		} else if (item.type == 4) {
+			if (item.reply == null) {
+				return '未答'
+			}
+			// 单选题
+			return getLetterByIndex(item.reply)
+		} else {
+			return item.reply
+		}
+	}
+
+	defineExpose({
+		showPopup,
+		closePopup
+	})
+</script>

+ 82 - 0
pages/ziranpindu/components/unitResult.vue

@@ -0,0 +1,82 @@
+<template>
+	<view>
+	<uni-popup ref="popupRef" :animation="false" :is-mask-click="false" type="top"
+		mask-background-color="rgba(0,0,0, 0.76);" class="ezy-popup-width-all">
+		<view class="dycs-dialog">
+			<!-- 返回区域 -->
+			<view class="icon-title-navBar-box">
+				<view @click="handleBack" class="nav-bar-icon"></view>
+				<text class="nav-bar-title">单元测试</text>
+			</view>
+			<view class="ezy-page-body dycs-body">
+				<view class="dycs-img"></view>
+				<view class="dycs-tip">单元测试已完成</view>
+				
+				<view class="dycs-fenshu-box">
+					<view class="fenshu-item-box">
+						<view class="item-number">{{data.right}}</view>
+						<view>正确</view>
+					</view>
+					<view class="item-line"></view>
+					<view class="fenshu-item-box">
+						<view class="item-number red-number">{{data.wrong}}</view>
+						<view>错误</view>
+					</view>
+				</view>
+				
+				<view class="dycs-btn-box">
+					<view @click="handleRestart" class="cxcs-btn">重新测试</view>
+					<view @click="handleCheckAnswer" class="ckda-btn">查看答案</view>
+				</view>
+			</view>
+		</view>
+	</uni-popup>
+</view>
+</template>
+
+<script setup>
+	import {
+		ref,
+		reactive
+	} from "vue";
+
+	const popupRef = ref(null)
+	const data = reactive({
+		right: 0,
+		wrong: 0,
+	})
+
+	const emits = defineEmits(['check-answer', 'do-replay'])
+
+	function handleRestart() {
+		emits('do-replay')
+	}
+
+	function handleCheckAnswer() {
+		emits('check-answer')
+	}
+
+	function showPopup(options) {
+		data.right = options.right;
+		data.wrong = options.wrong;
+
+		popupRef.value.open();
+	}
+
+	function closePopup() {
+		popupRef.value.close();
+	}
+
+	function handleBack() {
+		closePopup();
+	}
+
+
+	defineExpose({
+		showPopup,
+		closePopup
+	})
+</script>
+
+<style>
+</style>

+ 159 - 0
pages/ziranpindu/components/usePinduUnitTest.js

@@ -0,0 +1,159 @@
+import * as httpApi from "@/api/chanpinZiRanPinDu.js"
+import {
+	reactive,
+	watch
+} from "vue"
+import {
+	onLoad
+} from "@dcloudio/uni-app"
+import {
+	catchError,
+	toast
+} from "@/utils/common.js"
+import cacheManager from "@/utils/cacheManager.js";
+
+
+export function usePinduTest(handleSeeResult,handleSeeResultClose) {
+
+
+	const data = reactive({
+		list: [],
+		total: 0,
+		current: 0,
+		jieId: null,
+		rightAnswer: 0, // 答对
+		wrongAnswer: 0, // 答错
+	})
+
+	watch(() => data.list, (val) => {
+		const list = data.list.filter(item => {
+			if (item.type == 3) {
+				// 填空题 所有试题答完
+				return !item.reply.some(citem => citem.trim() == '');
+			} else {
+				return item.reply !== null
+			}
+		});
+		data.count = list.length;
+	}, {
+		deep: true
+	})
+	// 更新试题对错
+	function updateRightWrong({
+		rightAnswer,
+		wrongAnswer,
+	}) {
+		data.rightAnswer = rightAnswer;
+		data.wrongAnswer = wrongAnswer;
+	}
+
+	// 初始化页面数据
+	async function initPage() {
+		const [err, cdata] = await catchError(httpApi.getPinduChanpinShitiList({
+			jieId: data.jieId
+		}))
+
+		if (err) {
+			toast("单元测试数据获取异常");
+			return;
+		}
+
+		refreshExam(cdata);
+	}
+
+	function formatListToUse(list) {
+		list.forEach((item, index) => {
+			item.mta_show = false;
+			item.reply = null;
+			if (item.type == 3) {
+				item.result = JSON.parse(item.result);
+				item.placeholders = item.result.map((item, cindex) => `[bank${cindex+1}]`)
+				item.reply = item.reply ? JSON.parse(item.reply) : item.result.map(() => '');
+			}
+		})
+	}
+
+
+	// 数据赋值
+	function refreshExam(list) {
+		const cList = list;
+		formatListToUse(cList)
+		data.list = cList;
+		data.total = cList.length;
+	}
+
+	// 交卷
+	async function handleSubmit() {
+
+		const result = [];
+		data.list.forEach(item => {
+			if (item.type == 1) {
+				result.push({
+					reply: item.reply,
+					stId: item.stId
+				})
+			} else if (item.type == 2) {
+				result.push({
+					reply: item.reply,
+					stId: item.stId
+				})
+			} else if (item.type == 3) {
+				result.push({
+					reply: item.reply ? JSON.stringify(item.reply) : '',
+					stId: item.stId
+				})
+			} else if (item.type == 4) {
+				result.push({
+					reply: item.reply,
+					stId: item.stId
+				})
+			}
+
+		})
+		uni.showLoading({
+			title: '交卷中...'
+		});
+		const [error, cdata] = await catchError(httpApi.getPinduChanpinShitiSave({
+			jieId: data.jieId,
+			shitiList: result
+		}));
+		uni.hideLoading()
+		if (error) {
+			toast("单元测试数据提交异常");
+			return;
+		}
+		// 更新单元测试状态
+		cacheManager.updatePinduWanchengStatus(data.jieId)
+		// 执行跳页
+		uni.$emit('unitShuxueTest-submit', {
+			rightAnswer: cdata.dui,
+			wrongAnswer: cdata.cuo,
+		})
+
+		handleSeeResult()
+	}
+
+	onLoad((options) => {
+		data.jieId = options.jieId
+		initPage()
+	})
+
+	function resetStart() {
+		data.list = [];
+		data.total = 0;
+		data.current= 0;
+		data.rightAnswer = 0; // 答对
+		data.wrongAnswer = 0; // 答错
+		handleSeeResultClose();
+		initPage();
+	}
+
+
+	return {
+		data,
+		handleSubmit,
+		updateRightWrong,
+		resetStart
+	}
+}
+

+ 222 - 0
pages/ziranpindu/components/videoPlay.vue

@@ -0,0 +1,222 @@
+<template>
+	<view class="ezy-video-box course-video-box">
+		<view ref="videoContent" id="video-play1" :playAuth="playAuth1" :count="count" :change:count="renderScript.stopPlayer"
+			:change:playAuth="renderScript.receiveMsg" :videoId="videoId1" :change:videoId="renderScript.videoIdFun"
+			:hideFlag="hideFlag1" :change:hideFlag="renderScript.hideFlagFun" :progressMarkers="progressMarkers1"
+			:change:progressMarkers="renderScript.progressMarkersMsg" :seekTime="seekTime1"
+			:change:seekTime="renderScript.seekTimeFun" class="ezy-video">
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: "videoPlay",
+		props: {
+			cId: {
+				type: String,
+			},
+			progressMarkers1: {
+				type: Array,
+				default: () => ([])
+			},
+			videoId1: {
+				type: String,
+			},
+			playAuth1: {
+				type: String,
+			},
+			seekTime1: {
+				type: String
+			},
+			hideFlag1: {
+				type: String
+			}
+		},
+		data() {
+			return {
+				count: 0
+			}
+		},
+		methods: {
+			handleStop() {
+				this.count++;
+			},
+			playEnd() {
+				this.$emit('playEnd')
+			}
+		}
+	}
+</script>
+
+<script module="renderScript" lang="renderjs">
+	export default {
+		data() {
+
+			return {
+				player: null,
+				playAuth: '',
+				videoId: '',
+				progressMarkers: [],
+				isFullScreen: false,
+				seekTime: '',
+			}
+		},
+		methods: {
+			stopPlayer() {
+				console.log('暂停stopPlayer1')
+				this.player && this.player.pause();
+			},
+			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()
+				}
+			},
+			progressMarkersMsg(newValue, oldValue, ownerInstance, instance) {
+				if (newValue) {
+					this.progressMarkers = newValue
+				}
+			},
+			seekTimeFun(newValue, oldValue, ownerInstance, instance) {
+				if (newValue) {
+					this.player.play()
+					this.player.seek(newValue)
+				}
+			},
+			playAli() {
+				let that = this
+				//配置播放器
+				if (!this.playAuth) {
+					return false;
+				}
+				var player = new Aliplayer({
+					id: 'video-play1',
+					"vid": this.videoId,
+					"playauth": this.playAuth,
+					extraInfo: {
+						poster: 'noposter'
+					},
+					fullscreenEvents: {
+						fullscreenChange: (isFull) => {
+							this.isFullScreen = isFull
+						}
+					},
+					"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,
+					"progressMarkers": this.progressMarkers,
+					"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(data) {
+					that.exitFullScreen();
+					that.$ownerInstance.callMethod('playEnd', {
+						data: 'end'
+					})
+				});
+			},
+			exitFullScreen() {
+				if (document.exitFullscreen) {
+					document.exitFullscreen(); // 标准方法
+				} else if (document.mozCancelFullScreen) { // Firefox
+					document.mozCancelFullScreen();
+				} else if (document.webkitExitFullscreen) { // Chrome, Safari & Opera
+					document.webkitExitFullscreen();
+				} else if (document.msExitFullscreen) { // IE/Edge
+					document.msExitFullscreen();
+				}
+			},
+
+			loadWebPlayerSDK() {
+				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>

+ 220 - 0
pages/ziranpindu/components/videoPlay2.vue

@@ -0,0 +1,220 @@
+<template>
+	<view class="ezy-video-box course-video-box">
+		<view ref="videoContent" id="video-play2" :count="count" :change:count="renderScript.stopPlayer" :playAuth="playAuth1"
+			:change:playAuth="renderScript.receiveMsg" :videoId="videoId1" :change:videoId="renderScript.videoIdFun"
+			:hideFlag="hideFlag1" :change:hideFlag="renderScript.hideFlagFun" :progressMarkers="progressMarkers1"
+			:change:progressMarkers="renderScript.progressMarkersMsg" :seekTime="seekTime1"
+			:change:seekTime="renderScript.seekTimeFun" class="ezy-video">
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: "videoPlay",
+		props: {
+			progressMarkers1: {
+				type: Array,
+				default: () => ([])
+			},
+			videoId1: {
+				type: String,
+			},
+			playAuth1: {
+				type: String,
+			},
+			seekTime1: {
+				type: String
+			},
+			hideFlag1: {
+				type: String
+			}
+		},
+		data() {
+			return {
+				count: 0
+			}
+		},
+		methods: {
+			handleStop() {
+				this.count++;
+			},
+			playEnd() {
+				// 增加videoPlay2 用于判断能力提升视频学习完不作为本节已学完的标准
+        this.$emit('playEnd')
+			}
+		}
+	}
+</script>
+
+<script module="renderScript" lang="renderjs">
+	export default {
+		data() {
+			return {
+				player: null,
+				playAuth: '',
+				videoId: '',
+				progressMarkers: [],
+				isFullScreen: false,
+				seekTime: '',
+			}
+		},
+		methods: {
+			stopPlayer() {
+				this.player && this.player.pause();
+			},
+			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()
+				}
+			},
+			progressMarkersMsg(newValue, oldValue, ownerInstance, instance) {
+				if (newValue) {
+					this.progressMarkers = newValue
+				}
+			},
+			seekTimeFun(newValue, oldValue, ownerInstance, instance) {
+				if (newValue) {
+					this.player.play()
+					this.player.seek(newValue)
+				}
+			},
+			playAli() {
+				
+				
+				let that = this
+				//配置播放器
+				if (!this.playAuth) {
+					return false;
+				}
+				var player = new Aliplayer({
+					id: 'video-play2',
+					"vid": this.videoId,
+					"playauth": this.playAuth,
+					extraInfo: {
+						poster: 'noposter'
+					},
+					fullscreenEvents: {
+						fullscreenChange: (isFull) => {
+							this.isFullScreen = isFull
+						}
+					},
+					"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,
+					"progressMarkers": this.progressMarkers,
+					"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(data) {
+					that.exitFullScreen();
+					that.$ownerInstance.callMethod('playEnd', {
+						data: 'end'
+					})
+				});
+			},
+			exitFullScreen() {
+				if (document.exitFullscreen) {
+					document.exitFullscreen(); // 标准方法
+				} else if (document.mozCancelFullScreen) { // Firefox
+					document.mozCancelFullScreen();
+				} else if (document.webkitExitFullscreen) { // Chrome, Safari & Opera
+					document.webkitExitFullscreen();
+				} else if (document.msExitFullscreen) { // IE/Edge
+					document.msExitFullscreen();
+				}
+			},
+
+			loadWebPlayerSDK() {
+				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>

+ 273 - 0
pages/ziranpindu/lookShipin.vue

@@ -0,0 +1,273 @@
+<template>
+	<view class="ezy-ksp-page">
+		<view class="icon-title-navBar-box">
+			<view @click="goUpPage" class="nav-bar-icon"></view>
+			<text class="nav-bar-title">{{jieInfo.jieIntro}}</text>
+		</view>
+		<view class="ezy-page-body ksp-page-body">
+			<view class="ksp-tab-box">
+				<ezyActiveVue class="ezy-tab-item-active tab-item" :class="{active: showA}"
+					@click="handleSelectHexinti">核心基础题</ezyActiveVue>
+				<ezyActiveVue class="ezy-tab-item-active tab-item" :class="{active: showB}"
+					@click="handleSelectNengliTishengti">能力提升题</ezyActiveVue>
+			</view>
+			<!-- 核心基础题 -->
+			<videoPlayVue ref="c1" v-show="showA" :key="1" :videoId1="videoId" :progressMarkers1="progressMarkers"
+				:playAuth1="playAuth" :hideFlag1="hideFlag" :seek-time1="seekTime" class="ksp-video-box"
+				@playEnd="playEnd"></videoPlayVue>
+			<videoPlayVue2 ref="c2" v-show="videoId2 && showB" :key="2" :videoId1="videoId2"
+				:progressMarkers1="progressMarkers2" :playAuth1="playAuth2" :hideFlag1="hideFlag2"
+				:seek-time1="seekTime2" class="ksp-video-box" @playEnd="playEnd2"></videoPlayVue2>
+			<view class="ksp-scroll-view">
+				<view class="ksp-item-list" v-for="(item,index) in jieInfo.jiedianList1" :key="index" v-show="showA">
+					<view class="list-head">
+						<view class="list-title">{{item.name}}</view>
+						<ezyActiveVue class="ezy-btn-active list-btn" @click="markersClick(item)"></ezyActiveVue>
+					</view>
+					<view class="list-body">
+						<!-- <view class="ksp-title">课程位置:{{item.time1}}-{{item.time2}}</view> -->
+						<rich-text :nodes="item.title"></rich-text>
+					</view>
+				</view>
+				<!-- 能力提升题 -->
+				<template v-if="!!videoId2">
+					<view class="ksp-item-list" v-for="(item,index) in jieInfo.jiedianList2" :key="index"
+						v-show="showB">
+						<view class="list-head">
+							<view class="list-title">{{item.name}}</view>
+							<ezyActiveVue class="ezy-btn-active list-btn" @click="markersClick2(item)"></ezyActiveVue>
+						</view>
+						<view class="list-body">
+							<!-- <view class="ksp-title">课程位置:{{item.time1}}-{{item.time2}}</view> -->
+							<rich-text :nodes="item.title"></rich-text>
+						</view>
+					</view>
+				</template>
+
+
+			</view>
+			<!-- 无数据 -->
+			<template v-if="!videoId2 && showB">
+				<view class="ezy-no-sj" v-if="showB">
+					<icon></icon>
+					<text>暂无数据</text>
+				</view>
+			</template>
+		</view>
+		<!-- 弹窗 -->
+		<tishiDlVue ref="popupRef"></tishiDlVue>
+	</view>
+
+</template>
+
+<script>
+	import {
+		ref
+	} from 'vue';
+	import {
+		onLoad,
+		onReady
+	} from '@dcloudio/uni-app';
+	import {
+		getVideoAuth,
+		getVideoAuthYk,
+		videoWancheng
+	} from "@/api/shipin.js"
+	import {
+		toast,
+		convertTimeToSeconds
+	} from "@/utils/common";
+	import cacheManager from "@/utils/cacheManager.js";
+	import * as httpApi from "@/api/chanpinZiRanPinDu.js";
+	import tishiDlVue from './components/tishiDl.vue';
+	import videoPlayVue from './components/videoPlay.vue';
+	import videoPlayVue2 from './components/videoPlay2.vue';
+	import ezyActiveVue from "@/components/ezyActive/ezyActive.vue";
+	export default {
+		data() {
+			return {
+				danyuanId: null,
+				jieInfo: {
+					cover1: '',
+					cover2: '',
+					jieId: '',
+					jieIntro: '',
+					jieName: '',
+					jiedianList1: [],
+					jiedianList2: [],
+					type: '',
+					video1: '',
+					video2: '',
+				},
+
+				jieId: '',
+				shipinTitle: '',
+
+				pageData: null, //上个页面获取的视频参数(视频id)
+				playAuth: "", //播放凭证
+				progressMarkers: [],
+				hideFlag: 'show',
+				videoId: "", //阿里云视频id
+				seekTime: '',
+				showA: true,
+
+				pageData2: null, //上个页面获取的视频参数(视频id)
+				playAuth2: "", //播放凭证
+				progressMarkers2: [],
+				hideFlag2: 'show',
+				videoId2: "", //阿里云视频id
+				seekTime2: '',
+				showB: false,
+			}
+		},
+		components: {
+			tishiDlVue,
+			videoPlayVue,
+			videoPlayVue2,
+			ezyActiveVue
+		},
+		onLoad(options) {
+			this.init(options)
+		},
+		onHide() {
+			this.hideFlag = 'hide'
+			this.hideFlag2 = 'hide'
+		},
+		onUnload() {
+			this.hideFlag = 'hide'
+			this.hideFlag2 = 'hide'
+		},
+		methods: {
+			handleSelectHexinti() {
+				if (this.showA) return;
+				this.showB = false;
+				this.showA = true;
+				this.$refs.c1 && this.$refs.c1.handleStop()
+				this.$refs.c2 && this.$refs.c2.handleStop()
+			},
+			handleSelectNengliTishengti() {
+				if (this.showB) return;
+				this.showB = true;
+				this.showA = false;
+				this.$refs.c1 && this.$refs.c1.handleStop()
+				this.$refs.c2 && this.$refs.c2.handleStop()
+			},
+			//  当前节学习完成
+			saveJieWancheng() {
+				httpApi.getPinduChanpinWancheng({
+					jieId: this.jieInfo.jieId
+				}).then(res => {
+					if (res.data) {
+						// 更新单员状态
+						cacheManager.updateShuxueWanchengStatus(this.jieInfo.jieId)
+						// 学习完成提示弹窗
+						this.$refs.popupRef.open();
+					}
+				})
+			},
+			// 当前节学习开始
+			saveJinduStart() {
+				httpApi.getPinduChanpinSave({
+					jieId: this.jieInfo.jieId
+				})
+			},
+			courseBjFun() {
+				return 'static/images/course/couse-shuxue-bj.png'
+			},
+			courseIconFun() {
+				return 'static/images/course/shuxue-icon.png'
+			},
+			getDataInfo() {
+				httpApi.getPinduChanpinJieInfo({
+					jieId: this.jieId
+				}).then(res => {
+					// 时间节点转换
+					res.data.jiedianList1.forEach(item => item.offset = convertTimeToSeconds(item.time1))
+					res.data.jiedianList2.forEach(item => item.offset = convertTimeToSeconds(item.time1))
+					// 重新赋值
+					Object.assign(this.jieInfo, res.data)
+					// 触发当前节学习进度
+					// this.saveJinduStart();
+					// 	针对视频进行赋值
+					this.videoId = this.jieInfo.video1;
+					this.videoId2 = this.jieInfo.video2;
+					// 针对节点赋值
+					this.progressMarkers = this.jieInfo.jiedianList1;
+					this.progressMarkers = this.jieInfo.jiedianList2;
+					// 执行方法
+					this.getLive(); //获取播放凭证
+
+					this.getLive2();
+				})
+			},
+			init(options) {
+				this.jieId = options.jieId;
+				this.getDataInfo()
+			},
+			playEnd(data) {
+				// #ifdef APP-PLUS
+				plus.screen.lockOrientation('portrait-primary');
+				// #endif
+				this.saveJieWancheng();
+			},
+      playEnd2(data) {
+        // #ifdef APP-PLUS
+        plus.screen.lockOrientation('portrait-primary');
+        // #endif
+      },
+			getLive() {
+				if (!this.videoId) {
+					toast("video缺失!")
+					return false
+				}
+				let req = {
+					videoId: this.videoId
+				}
+
+				getVideoAuth(req).then(res => {
+					this.playAuth = res.data
+				})
+			},
+			getLive2() {
+				if (!this.videoId2) {
+					// toast("video缺失!")
+					return false
+				}
+				let req = {
+					videoId: this.videoId2
+				}
+
+				getVideoAuth(req).then(res => {
+					this.playAuth2 = res.data
+				})
+			},
+			markersClick(data) {
+				this.showA = true;
+				this.showB = false;
+				this.$refs.c2 && this.$refs.c2.handleStop();
+				this.seekTime = ""
+				this.$nextTick(() => {
+					this.seekTime = data.offset
+				});
+			},
+			markersClick2(data) {
+				this.showA = false;
+				this.showB = true;
+				this.$refs.c1 && this.$refs.c1.handleStop()
+				this.seekTime2 = ""
+				this.$nextTick(() => {
+					this.seekTime2 = data.offset
+				});
+			},
+			goUpPage() {
+				uni.switchTab({
+					url: "/pages/chanpinneirong/index"
+				})
+				// uni.navigateBack()
+				// uni.redirectTo({
+				// 	url: "/pages/chanpinneirong/index"
+				// })
+			},
+		},
+	}
+</script>

+ 183 - 0
pages/ziranpindu/unitTest.vue

@@ -0,0 +1,183 @@
+<template>
+	<view class="ezy-exam-page">
+		<view class="icon-title-navBar-box">
+			<view @click="handleBack" class="nav-bar-icon"></view>
+			<text class="nav-bar-title">单元测试</text>
+		</view>
+
+		<view class="exam-body">
+			<view class="xx-jd-box"  v-if="data.total">
+				<view class="xx-row">
+					<view>当前学习进度</view>
+					<view class="text-row">
+						<text class="dq-jd-text">{{data.current+1}}</text>
+						<text class="dq-jd-line">/</text>{{data.total}}
+					</view>
+				</view>
+				<progress :percent="(data.current+1)/data.total * 100" class="exam-progress-box" stroke-width="10"
+					backgroundColor="#3c7dfd" activeColor="#ffd11c" />
+			</view>
+
+
+			<view class="shiti-frame-box">
+				<template v-if="data.list.length" >
+					<w-swiper :list="data.list" :current="data.current" class="ezy-exam-swiper" @change="onSwiperChange">
+						<template v-slot:default="{item}">
+							<view class="body" v-if="item.mta_show">
+								<danxuan :question="item" v-if="item.type == '1'"></danxuan>
+								<panduan :question="item" v-if="item.type == '2'"></panduan>
+								<tiankong :question="item" v-if="item.type == '3'" :placeholders="item.placeholders">
+								</tiankong>
+								<!-- 交卷按钮 -->
+								<view class="shiti-jj-btn" v-if="item.stId == data.list[data.total-1].stId"
+									@click="handleSubmit"></view>
+							</view>
+						</template>
+					</w-swiper>
+				</template>
+				<!-- 无数据 -->
+				<view class="ezy-no-sj" v-else>
+					<icon></icon>
+					<text>暂无数据</text>
+				</view>
+				
+				<!--  左右滑动提示  -->
+				<view class="swiper-tip-box">
+					左右滑动查看更多题目
+				</view>
+			</view>
+		</view>
+
+
+
+
+		<!-- 填空 -->
+		<FillItem :value="result" ref="popupRef" @blur="onBlur"></FillItem>
+
+		<unitResultVue ref="uniResRef" @check-answer="onCheckAnswer" @do-replay="onDoReplay"></unitResultVue>
+
+		<unitAnswerVue :list="data.list" ref="uniAnsRef" @back="handleBack"></unitAnswerVue>
+	</view>
+</template>
+
+<script setup>
+	import mtaRadio from '@/components/question/yingyu/mtaRadio.vue'
+	import FillItem from "@/components/question/FillItem.vue";
+	import wSwiper from '@/components/wSwiper/wSwiper.vue';
+	import danxuan from "@/components/question/danxuan.vue";
+	import panduan from "@/components/question/panduan.vue";
+	import tiankong from "@/components/question/tiankong.vue";
+	import unitResultVue from './components/unitResult.vue';
+	import unitAnswerVue from "./components/unitAnswer.vue";
+
+	import * as httpApi from "@/api/chanpinZiRanPinDu.js"
+	import {
+		reactive,
+		ref
+	} from "vue"
+	import {
+		onLoad
+	} from "@dcloudio/uni-app"
+	import {
+		usePinduTest
+	} from "./components/usePinduUnitTest.js"
+	const {
+		data,
+		handleSubmit,
+		updateRightWrong,
+		resetStart
+	} = usePinduTest(handleSeeResult, handleSeeResultClose)
+
+	const curTiankong = ref(null);
+	const result = ref('');
+	const popupRef = ref(null);
+	const uniResRef = ref(null);
+	const uniAnsRef = ref(null);
+
+	function handleSeeResultClose() {
+		uniResRef.value.closePopup()
+	}
+
+	function handleSeeResult() {
+		uniResRef.value.showPopup({
+			right: data.rightAnswer,
+			wrong: data.wrongAnswer
+		})
+	}
+
+	function handleCheckAnswer() {
+		uniResRef.value.showPopup({
+			jieId: data.jieId
+		})
+	}
+
+	function onDoReplay() {
+		resetStart()
+	}
+
+	function onCheckAnswer() {
+		uniAnsRef.value.showPopup();
+	}
+
+
+	onLoad(() => {
+		uni.$on('tiankong-fillItem', (val) => {
+			const {
+				index,
+				question
+			} = val;
+			curTiankong.value = val;
+			result.value = question.reply[index];
+			const dom = getPopupRef();
+			dom && dom.showPopup();
+		})
+
+		uni.$on('unitShuxueTest-submit', val => {
+			updateRightWrong(val)
+		})
+	})
+
+	function getPopupRef() {
+		return popupRef.value;
+	}
+
+	function onBlur({
+		result
+	}) {
+		if (curTiankong.value) {
+			uni.$emit('tiankong-setResult', {
+				index: curTiankong.value.index,
+				stId: curTiankong.value.question.stId,
+				result
+			});
+		}
+		const dom = getPopupRef();
+		dom && dom.handleClear();
+	}
+
+	function handleBack() {
+		// uni.navigateBack()
+		uni.switchTab({
+			url: "/pages/chanpinneirong/index"
+		})
+	}
+
+	function onSwiperChange(index) {
+		data.current = index;
+		uni.$emit('swiper-change', index)
+	}
+</script>
+
+<style lang="scss" scoped>
+	.swiper-box {
+		height: 200px;
+	}
+
+	.swiper-item {
+		display: flex;
+		flex-direction: column;
+		justify-content: center;
+		align-items: center;
+		height: 200px;
+	}
+</style>

+ 17 - 1
utils/cacheManager.js

@@ -133,6 +133,21 @@ const cacheManager = (function() {
 	    }
 	    set('contentInfo', obj);
 	}
+	
+	function updatePinduWanchengStatus(currentJieId) {
+	    let obj = get('contentInfo') || {};
+	    if (obj && obj.danyuanList) {
+	        obj.danyuanList.forEach(danyuan => {
+	            if (danyuan.jieList) {
+	                const jie = danyuan.jieList.find(j => j.jieId == currentJieId);
+	                if (jie) {
+	                    jie.wanchengFlag = 1;
+	                }
+	            }
+	        });
+	    }
+	    set('contentInfo', obj);
+	}
 
 	return {
 		set,
@@ -144,7 +159,8 @@ const cacheManager = (function() {
 		updateObject,
 		findArrayInObject,
 		clearAll,
-		updateJisuanWanchengStatus
+		updateJisuanWanchengStatus,
+		updatePinduWanchengStatus
 	};
 })();