Przeglądaj źródła

feat(游戏模块): 添加游戏详情页及支付功能

- 新增游戏详情页面路由配置及页面文件
- 修改游戏模块跳转路径至新详情页
- 添加微信支付相关API接口
- 实现支付弹窗及支付流程
- 优化图片路径处理逻辑
- 调整混合模块页面资源路径
whj 2 tygodni temu
rodzic
commit
e031eb7aca

+ 41 - 2
components/lock.uvue

@@ -1,4 +1,5 @@
 <script setup lang='ts'>
+import { wechatPay, wechatPayRequest } from '@/services/user'
 import { ref } from 'vue'
 const props = defineProps({
   record: {
@@ -7,12 +8,50 @@ const props = defineProps({
   }
 })
 const visible = ref(false)
-const handlePay = () => {
+function handleOpen() {
   visible.value = true
 }
+const handlePay = async () => {
+  console.log(props.record)
+  try {
+    const { prepayId, outTradeNo } = await wechatPay({
+      subjectId: props.record.subjectId,
+    })
+    const { signature } = await wechatPayRequest({
+      prepayId, outTradeNo
+    })
+    console.log(signature)
+    uni.requestPayment({
+      provider: "wxpay",
+      orderInfo: orderInfo,
+      ...JSON.parse(orderInfo),
+      success: (res) => {
+        console.log('res: ', res)
+        uni.showToast({
+          title: "支付成功",
+          icon: 'success'
+        });
+      },
+      fail: (err) => {
+        console.error("err", err);
+        uni.hideLoading();
+        uni.showToast({
+          title: "支付失败",
+          icon: 'error'
+        });
+      }
+    });
+  } catch (err: any) {
+    uni.showToast({
+      title: err.message,
+      icon: 'error'
+    });
+  }
+
+}
 </script>
 <template>
-  <view class="absolute top-0 left-0 w-full h-full flex items-center justify-center bg1" @tap.stop="handlePay">
+  <view class="absolute top-0 left-0 w-full h-full flex items-center justify-center bg1" @tap.stop="handleOpen">
     <cl-image src="https://oss.xiaoxiongcode.com/static/home/lock.png" mode="widthFix" width="30%" height="auto" />
   </view>
   <cl-popup v-model="visible" showClose :size="400" :show-header="false" direction="center">

+ 7 - 0
pages.json

@@ -82,6 +82,13 @@
 				"navigationStyle": "custom",
 			"disableScroll": true
 			}
+		},
+		{
+			"path": "pages/game/detail",
+			"style": {
+				"navigationStyle": "custom",
+				"disableScroll": true
+			}
 		}
 	],
 	"globalStyle": {

+ 117 - 0
pages/game/detail.uvue

@@ -0,0 +1,117 @@
+<script setup lang='ts'>
+import Back from '@/components/back.uvue'
+import Loading from '@/components/loading.uvue'
+import { ref, onMounted, watchEffect, nextTick, onUnmounted } from 'vue'
+import { type SubjectCourseResult, fetchSubjectCourseApp, updateSubjectProgress } from '@/services/subject/course'
+import { router } from '@/.cool'
+const isLoading = ref(true)
+const showProgress = ref(true)
+const showControls = ref(true)
+const showVideo = ref(true)
+
+const data = ref({
+  videoSrc: '',
+})
+//当前进度
+
+const course = ref<SubjectCourseResult>()
+//通过路由参数获取课程id
+async function fetchCatalog() {
+  course.value = await fetchSubjectCourseApp({ id: router.query().id })
+  if (!course.value?.videoPath) {
+    return
+  }
+  data.value.videoSrc = course.value?.videoPath.includes('http') ? course.value?.videoPath : ('https://oss.xiaoxiongcode.com' + course.value?.videoPath)
+}
+onMounted(async () => {
+  await fetchCatalog()
+  isLoading.value = false
+  setTimeout(() => {
+    isLoading.value = false
+  }, 1000)
+})
+async function handleEnded() {
+
+}
+
+function handleControlsToggle(e) {
+  showControls.value = e.detail.show
+}
+
+
+
+</script>
+<template>
+  <Loading v-show="isLoading" />
+  <cl-page v-show="!isLoading">
+    <view class="w-full h-full">
+      <web-view :src="data.videoSrc + '?' + Math.random()" class="w-full h-full"></web-view>
+    </view>
+  </cl-page>
+</template>
+<style lang="scss" scoped>
+.translate50 {
+  transform: translateY(-50%);
+}
+
+.course-detail-page {
+  @apply flex flex-row items-center;
+  background-color: #3498DB;
+  height: 100vh;
+  color: black;
+  transition: all 1s ease-in-out;
+
+}
+
+.video-container {
+  width: 100vw;
+  height: 100vh;
+  top: 0;
+  left: 0;
+  transform: translate(0, 0);
+  animation: spin 2s linear 1;
+  transition: all 2s ease-in-out;
+}
+
+@keyframes spin {
+  0% {
+    opacity: 50%;
+  }
+
+  100% {
+    opacity: 1;
+  }
+}
+
+.hidden {
+  opacity: 0;
+  transition: all 3s ease-in-out;
+}
+
+.video-fullscreen_title {
+  @apply absolute top-3 left-0 pl-[80px] w-[100vw] z-10 flex items-center justify-between flex-row;
+  color: #fff;
+
+  .control-progress {
+    @apply flex flex-row gap-[3px] relative justify-end;
+    flex: 1;
+
+    .before {
+      @apply absolute top-1/2 right-0 w-[340px] h-[40px] bg-[#2BA0F3] rounded-l-full;
+      transform: translateY(-30%);
+    }
+  }
+}
+
+video::-webkit-media-controls-fullscreen-button,
+video::-webkit-media-controls-enter-fullscreen-button,
+video::-webkit-media-controls-rotate-button,
+video::-webkit-media-controls-seek-back-button,
+video::-webkit-media-controls-seek-forward-button {
+  display: none !important;
+}
+
+.mic {
+  @apply absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2;
+}
+</style>

+ 1 - 1
pages/game/index.uvue

@@ -41,7 +41,7 @@ function handleDetail(item: SubjectCatalogResult) {
     return
   }
   router.push({
-    path: "/pages/english/detail",
+    path: "/pages/game/detail",
     query: {
       id: item.id,
     }

+ 1 - 2
pages/index/components/english.uvue

@@ -38,8 +38,7 @@ function handleDetail(item: any) {
     <scroll-view class="scroll-view_H" direction="horizontal" :show-scrollbar="false">
       <view class="scroll-view-item_H bg-[white]" v-for="course in dataList || []" :key="course.id"
         @tap="handleDetail(course)">
-        <cl-image :src="config.baseUrl + course?.iconPath" mode="heightFix"
-          class="!w-full !h-[26vh] mb-[2px] rounded-xl"></cl-image>
+        <cl-image :src="course?.iconPath" mode="heightFix" class="!w-full !h-[26vh] mb-[2px] rounded-xl"></cl-image>
         <text class="text-[4vh] font-bold">{{
           course.mainTitle }}</text>
         <text class="text-[3vh] text-[#666]">{{

+ 1 - 1
pages/index/components/mix.uvue

@@ -25,7 +25,7 @@ onMounted(async () => {
 })
 function handleDetail(item: any) {
   router.push({
-    path: "/pages/english/index",
+    path: "/pages/mix/index",
     query: {
       id: item.id,
     }

+ 3 - 3
pages/mix/index.uvue

@@ -51,11 +51,11 @@ function handleDetail(item: SubjectCatalogResult) {
   <Loading v-show="isLoading" />
   <cl-page v-show="!isLoading">
     <Back />
-    <img src="https://oss.xiaoxiongcode.com/static/英语/图层 6.png" alt="" class="w-full h-full object-cover" />
+    <img src="https://oss.xiaoxiongcode.com/static/语文/图层 4.png" alt="" class="w-full h-full object-cover" />
 
     <!-- 精灵图动画 -->
-    <cl-image src="https://oss.xiaoxiongcode.com/static/home/3.gif" mode="heightFix"
-      class="!absolute bottom-0 left-0 !w-[44vh] !h-[55vh] z-[1]" />
+    <!-- <cl-image src="https://oss.xiaoxiongcode.com/static/home/3.gif" mode="heightFix"
+      class="!absolute bottom-0 left-0 !w-[44vh] !h-[55vh] z-[1]" /> -->
     <view>
 
     </view>

+ 6 - 0
services/user.ts

@@ -63,4 +63,10 @@ export function bindWechatOpenId(parameter: any) {
 }
 export function wechatLogin(parameter: any) {
   return useGet(`/wechat/quickly/login/oauth`, parameter) as Promise<any>
+}
+export function wechatPay(parameter: any) {
+  return useGet(`/wechat/pay/jsapi`, parameter) as Promise<any>
+}
+export function wechatPayRequest(parameter: any) {
+  return useGet(`/wechat/pay/request/payment`, parameter) as Promise<any>
 }