Browse Source

refactor(视频分享): 优化视频分享逻辑和代码结构

- 修复分享计数逻辑,确保num和timeNum为数字类型
- 调整视频播放和锁定状态的逻辑,避免不必要的弹窗关闭
- 优化代码格式和缩进,提升代码可读性
master
前端-胡立永 2 months ago
parent
commit
551815693a
6 changed files with 392 additions and 378 deletions
  1. +2
    -2
      pages/index/center.vue
  2. +4
    -0
      pages/index/index.vue
  3. +46
    -50
      pages_order/components/popupUnlock.vue
  4. +293
    -311
      pages_order/record/videoSharing.vue
  5. +39
    -10
      pages_order/sharing/video.vue
  6. +8
    -5
      utils/shareLog.js

+ 2
- 2
pages/index/center.vue View File

@ -74,14 +74,14 @@
<button open-type="contact" class="share"> <button open-type="contact" class="share">
<view class="tool"> <view class="tool">
<view class="tool-icon tool-icon-bg"> <view class="tool-icon tool-icon-bg">
<uv-icon name="server-fill" color="#05d9a2" size="60rpx" />
<uv-icon name="server-fill" color="#05d9a2" size="56rpx" />
</view> </view>
<text>联系客服</text> <text>联系客服</text>
</view> </view>
</button> </button>
<view class="tool" @click="$refs.configPopup.open('user_ys')"> <view class="tool" @click="$refs.configPopup.open('user_ys')">
<view class="tool-icon tool-icon-bg"> <view class="tool-icon tool-icon-bg">
<uv-icon name="question-circle" color="#05d9a2" size="60rpx" />
<uv-icon name="question-circle" color="#05d9a2" size="56rpx" />
</view> </view>
<text>隐私政策</text> <text>隐私政策</text>
</view> </view>


+ 4
- 0
pages/index/index.vue View File

@ -59,6 +59,10 @@
title: '文章分享', title: '文章分享',
path: '/pages_order/record/articleSharing' path: '/pages_order/record/articleSharing'
}, },
// {
// title: '',
// path: '/pages_order/sharing/video?id=1922875315630133249'
// },
], ],
} }
}, },


+ 46
- 50
pages_order/components/popupUnlock.vue View File

@ -1,63 +1,59 @@
<template> <template>
<uv-popup
ref="popup"
:overlayOpacity="0.8"
:customStyle="{
<uv-popup ref="popup" :overlayOpacity="0.8" :customStyle="{
backgroundColor: 'transparent', backgroundColor: 'transparent',
}"
>
<view>
<image class="popup-bg" :src="src"></image>
<view class="flex popup-btns">
<button plain class="btn-simple" @click="close">
<image class="popup-btn" src="../static/sharing/cancel.png"></image>
</button>
<button plain class="btn-simple" open-type="share">
<image class="popup-btn" src="../static/sharing/forward.png"></image>
</button>
</view>
</view>
</uv-popup>
}">
<view>
<image class="popup-bg" :src="src"></image>
<view class="flex popup-btns">
<button plain class="btn-simple" @click="close">
<image class="popup-btn" src="../static/sharing/cancel.png"></image>
</button>
<button plain class="btn-simple" open-type="share">
<image class="popup-btn" src="../static/sharing/forward.png"></image>
</button>
</view>
</view>
</uv-popup>
</template> </template>
<script> <script>
export default { export default {
props: {
src: {
type: String,
default: null
}
},
props: {
src: {
type: String,
default: null
}
},
data() { data() {
return {
}
},
methods: {
open() {
this.$refs.popup.open();
},
close() {
console.log('--close popup')
this.$refs.popup.close();
},
},
}
return {}
},
methods: {
open() {
this.$refs.popup.open();
},
close() {
console.log('--close popup')
this.$refs.popup.close();
},
},
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.popup {
&-bg {
width: 578rpx; height: 317rpx;
}
.popup {
&-bg {
width: 578rpx;
height: 317rpx;
}
&-btns {
justify-content: space-between;
margin-top: 56rpx;
}
&-btns {
justify-content: space-between;
margin-top: 56rpx;
}
&-btn {
width: 265rpx;
height: 84rpx;
}
}
&-btn {
width: 265rpx;
height: 84rpx;
}
}
</style> </style>

+ 293
- 311
pages_order/record/videoSharing.vue View File

@ -1,158 +1,138 @@
<template> <template>
<view class="page">
<view class="page">
<navbar title="视频分享" leftClick @leftClick="$utils.navigateBack" /> <navbar title="视频分享" leftClick @leftClick="$utils.navigateBack" />
<view class="content">
<uv-form
ref="form"
:model="form"
:rules="rules"
labelPosition="left"
labelWidth="340rpx"
:labelStyle="{
<view class="content">
<uv-form ref="form" :model="form" :rules="rules" labelPosition="left" labelWidth="340rpx" :labelStyle="{
color: '#1B1B1B', color: '#1B1B1B',
fontSize: '32rpx', fontSize: '32rpx',
fontWeight: 'bold', fontWeight: 'bold',
}"
errorType="toast"
>
<view class="flex upload__view">
<view class="upload upload-cover">
<uv-form-item labelWidth="0" prop="indexImage">
<formUpload v-model="form.indexImage">
<template v-slot="{ value }">
<!-- todo: 默认 -->
<image
:src="value"
mode="aspectFill"
style="width: 344rpx; height: 344rpx;"
radius="14rpx"
/>
</template>
</formUpload>
<view class="upload-cover-text flex">设置封面</view>
</uv-form-item>
</view>
<view class="upload upload-video">
<uv-form-item labelWidth="0" prop="vio">
<formUpload v-model="form.vio" accept="video">
<template v-slot>
<video v-if="form.vio"
:src="form.vio"
style="width: 344rpx; height: 344rpx;"
radius="14rpx"
:controls="false"
:autoplay="false"
:show-center-play-btn="false"
></video>
<view v-else class="flex flex-column" style="width: 344rpx; height: 344rpx;">
<image src="../static/record/icon-camera.png" style="width: 130rpx; height: 105rpx;" ></image>
<text class="upload-video-text">上传视频</text>
</view>
</template>
</formUpload>
</uv-form-item>
</view>
</view>
<view class="form-item">
<uv-form-item label="标题" labelWidth="84rpx" prop="headTitle">
<view class="form-item-content">
<formInput v-model="form.headTitle" placeholder="请输入你的视频名称" width="584rpx"></formInput>
</view>
</uv-form-item>
</view>
<view class="form-item">
<uv-form-item label="设置广告弹出时间(s)" prop="timeNum">
<view class="form-item-content">
<formNumberBox v-model="form.timeNum" ></formNumberBox>
</view>
</uv-form-item>
</view>
<view class="form-item">
<uv-form-item label="设置转发次数(次)" prop="num">
<view class="form-item-content">
<formNumberBox v-model="form.num" ></formNumberBox>
</view>
</uv-form-item>
</view>
<view class="form-item">
<uv-form-item label="选择二维码" prop="wxCodeImage">
<view class="form-item-content">
<formUpload v-model="form.wxCodeImage">
<template v-slot="{ value }">
<view class="flex" style="min-width: 93rpx; height: 45rpx;">
<image
:src="value"
mode="aspectFill"
style="width: 45rpx; height: 45rpx;"
radius="14rpx"
/>
<uv-icon style="margin-left: 20rpx" name="arrow-right" color="#000000" size="28rpx"></uv-icon>
</view>
</template>
</formUpload>
</view>
</uv-form-item>
</view>
<view class="form-item">
<uv-form-item label="视频描述" prop="textDetails" labelPosition="top">
<view style="margin-top: 32rpx;">
<formTextarea
v-model="form.textDetails"
placeholder="请描述你的视频"
></formTextarea>
</view>
</uv-form-item>
</view>
</uv-form>
</view>
<!-- 审核通过 -->
<button v-if="status === 1" class="button-submit" open-type="share">
发布
</button>
<!-- 不是 审核中 已发布 -> 创建分享 审核不通过 -->
<button v-else-if="![0,1].includes(status)" class="button-submit" @click="preSubmit">
提交审核
</button>
<autoCrop ref="autoCropRef" @change="onSubmit"></autoCrop>
</view>
}" errorType="toast">
<view class="flex upload__view">
<view class="upload upload-cover">
<uv-form-item labelWidth="0" prop="indexImage">
<formUpload v-model="form.indexImage">
<template v-slot="{ value }">
<!-- todo: 默认 -->
<image :src="value" mode="aspectFill" style="width: 344rpx; height: 344rpx;"
radius="14rpx" />
</template>
</formUpload>
<view class="upload-cover-text flex">设置封面</view>
</uv-form-item>
</view>
<view class="upload upload-video">
<uv-form-item labelWidth="0" prop="vio">
<formUpload v-model="form.vio" accept="video">
<template v-slot>
<video v-if="form.vio" :src="form.vio" style="width: 344rpx; height: 344rpx;"
radius="14rpx" :controls="false" :autoplay="false"
:show-center-play-btn="false"></video>
<view v-else class="flex flex-column" style="width: 344rpx; height: 344rpx;">
<image src="../static/record/icon-camera.png"
style="width: 130rpx; height: 105rpx;"></image>
<text class="upload-video-text">上传视频</text>
</view>
</template>
</formUpload>
</uv-form-item>
</view>
</view>
<view class="form-item">
<uv-form-item label="标题" labelWidth="84rpx" prop="headTitle">
<view class="form-item-content">
<formInput v-model="form.headTitle" placeholder="请输入你的视频名称" width="584rpx"></formInput>
</view>
</uv-form-item>
</view>
<view class="form-item">
<uv-form-item label="设置广告弹出时间(s)" prop="timeNum">
<view class="form-item-content">
<formNumberBox v-model="form.timeNum"></formNumberBox>
</view>
</uv-form-item>
</view>
<view class="form-item">
<uv-form-item label="设置转发次数(次)" prop="num">
<view class="form-item-content">
<formNumberBox v-model="form.num"></formNumberBox>
</view>
</uv-form-item>
</view>
<view class="form-item">
<uv-form-item label="选择二维码" prop="wxCodeImage">
<view class="form-item-content">
<formUpload v-model="form.wxCodeImage">
<template v-slot="{ value }">
<view class="flex" style="min-width: 93rpx; height: 45rpx;">
<image :src="value" mode="aspectFill" style="width: 45rpx; height: 45rpx;"
radius="14rpx" />
<uv-icon style="margin-left: 20rpx" name="arrow-right" color="#000000"
size="28rpx"></uv-icon>
</view>
</template>
</formUpload>
</view>
</uv-form-item>
</view>
<view class="form-item">
<uv-form-item label="视频描述" prop="textDetails" labelPosition="top">
<view style="margin-top: 32rpx;">
<formTextarea v-model="form.textDetails" placeholder="请描述你的视频"></formTextarea>
</view>
</uv-form-item>
</view>
</uv-form>
</view>
<!-- 审核通过 -->
<button v-if="status === 1" class="button-submit" open-type="share">
发布
</button>
<!-- 不是 审核中 已发布 -> 创建分享 审核不通过 -->
<button v-else-if="![0,1].includes(status)" class="button-submit" @click="preSubmit">
提交审核
</button>
<autoCrop ref="autoCropRef" @change="onSubmit"></autoCrop>
</view>
</template> </template>
<script> <script>
import { mapState } from 'vuex'
import shareLog from '@/utils/shareLog'
import {
mapState
} from 'vuex'
import shareLog from '@/utils/shareLog'
import formUpload from '../components/formUpload.vue'
import formInput from '../components/formInput.vue'
import formNumberBox from '../components/formNumberBox.vue'
import formTextarea from '../components/formTextarea.vue'
import autoCrop from '../components/autoCrop.vue'
import formUpload from '../components/formUpload.vue'
import formInput from '../components/formInput.vue'
import formNumberBox from '../components/formNumberBox.vue'
import formTextarea from '../components/formTextarea.vue'
import autoCrop from '../components/autoCrop.vue'
export default { export default {
components: {
formUpload,
formInput,
formNumberBox,
formTextarea,
autoCrop,
},
components: {
formUpload,
formInput,
formNumberBox,
formTextarea,
autoCrop,
},
data() { data() {
return {
id: null,
status: null,
form: {
headTitle: null,
indexImage: null,
vio: null,
timeNum: 0,
num: 0,
wxCodeImage: null,
textDetails: null,
},
rules: {
return {
id: null,
status: null,
form: {
headTitle: null,
indexImage: null,
vio: null,
timeNum: 0,
num: 0,
wxCodeImage: null,
textDetails: null,
},
rules: {
'indexImage': { 'indexImage': {
type: 'string', type: 'string',
required: true, required: true,
@ -172,11 +152,11 @@
type: 'number', type: 'number',
required: true, required: true,
message: '请设置广告弹出时间(大于1)', message: '请设置广告弹出时间(大于1)',
validator: (rule, value, callback) => {
if (value > 1) {
return true
}
validator: (rule, value, callback) => {
if (value > 1) {
return true
}
return false; return false;
}, },
}, },
@ -184,11 +164,11 @@
type: 'number', type: 'number',
required: true, required: true,
message: '请设置转发次数(大于0)', message: '请设置转发次数(大于0)',
validator: (rule, value, callback) => {
if (value > 0) {
return true
}
validator: (rule, value, callback) => {
if (value > 0) {
return true
}
return false; return false;
}, },
}, },
@ -203,177 +183,179 @@
message: '请描述你的视频', message: '请描述你的视频',
}, },
}, },
}
},
}
},
computed: { computed: {
...mapState(['userInfo']), ...mapState(['userInfo']),
}, },
onLoad(option) { onLoad(option) {
const { id } = option
const {
id
} = option
if (!id) {
return
}
if (!id) {
return
}
this.id = id
this.id = id
this.fetchDetails(id)
this.fetchDetails(id)
}, },
onReady() { onReady() {
this.$refs.form.setRules(this.rules); this.$refs.form.setRules(this.rules);
}, },
onShareAppMessage(res) {
const {
headTitle,
indexImage,
} = this.form
let o = {
title : headTitle,
imageUrl: indexImage,
path: `/pages_order/sharing/video?id=${this.id}&state=1&shareId=${this.userInfo.id}`
}
//
const params = {
id:this.id,
state:"1",
}
this.$fetch('addLogShareInfo', params)
// todo: get times and check is unlocked
shareLog.insert(this.id)
this.isLocked = false
return o
},
methods: {
async fetchDetails(id) {
try {
const result = await this.$fetch('getVideoShareInfo', { id })
const {
headTitle,
indexImage,
vio,
timeNum,
num,
wxCodeImage,
textDetails,
status,
} = result || {}
this.form = {
headTitle,
indexImage,
vio,
timeNum,
num,
wxCodeImage,
textDetails,
}
this.status = status
} catch (err) {
}
},
async preSubmit() {
try {
await this.$refs.form.validate()
this.$refs.autoCropRef.set(this.form.indexImage)
} catch (err) {
}
},
async onSubmit(indexImage) {
try {
await this.$refs.form.validate()
const {
headTitle,
vio,
timeNum,
num,
wxCodeImage,
textDetails,
} = this.form
const params = {
headTitle,
indexImage,
vio,
timeNum,
num,
wxCodeImage,
textDetails,
}
if (this.id) {
params.id = this.id
}
await this.$fetch('saveOrUpdateVideoShare', params)
uni.showToast({
title: '提交成功',
icon: 'none'
})
setTimeout(uni.navigateBack, 1000, -1)
} catch (err) {
}
},
onPublish() {
// todo
},
}
}
onShareAppMessage(res) {
const {
headTitle,
indexImage,
} = this.form
let o = {
title: headTitle,
imageUrl: indexImage,
path: `/pages_order/sharing/video?id=${this.id}&state=1&shareId=${this.userInfo.id}`
}
//
const params = {
id: this.id,
state: "1",
}
this.$fetch('addLogShareInfo', params)
// todo: get times and check is unlocked
shareLog.insert(this.id)
this.isLocked = false
return o
},
methods: {
async fetchDetails(id) {
try {
const result = await this.$fetch('getVideoShareInfo', {
id
})
const {
headTitle,
indexImage,
vio,
timeNum,
num,
wxCodeImage,
textDetails,
status,
} = result || {}
this.form = {
headTitle,
indexImage,
vio,
timeNum,
num,
wxCodeImage,
textDetails,
}
this.status = status
} catch (err) {
}
},
async preSubmit() {
try {
await this.$refs.form.validate()
this.$refs.autoCropRef.set(this.form.indexImage)
} catch (err) {
}
},
async onSubmit(indexImage) {
try {
await this.$refs.form.validate()
const {
headTitle,
vio,
timeNum,
num,
wxCodeImage,
textDetails,
} = this.form
const params = {
headTitle,
indexImage,
vio,
timeNum,
num,
wxCodeImage,
textDetails,
}
if (this.id) {
params.id = this.id
}
await this.$fetch('saveOrUpdateVideoShare', params)
uni.showToast({
title: '提交成功',
icon: 'none'
})
setTimeout(uni.navigateBack, 1000, -1)
} catch (err) {
}
},
onPublish() {
// todo
},
}
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@import '../styles/pageForm.scss';
.upload__view {
justify-content: space-between;
margin-bottom: 20rpx;
}
.upload {
background-color: $uni-fg-color;
border-radius: 12rpx;
overflow: hidden;
/deep/ .uv-form-item__body {
padding: 0 !important;
}
}
.upload-video {
&-text {
color: #1B1B1B;
font-size: 32rpx;
font-weight: 700;
margin-top: 35rpx;
}
}
.upload-cover {
position: relative;
&-text {
position: absolute;
bottom: 0;
width: 100%;
background-color: rgba($color: #000000, $alpha: 0.6);
color: #FFFFFF;
padding: 21rpx 0;
}
}
@import '../styles/pageForm.scss';
.upload__view {
justify-content: space-between;
margin-bottom: 20rpx;
}
.upload {
background-color: $uni-fg-color;
border-radius: 12rpx;
overflow: hidden;
/deep/ .uv-form-item__body {
padding: 0 !important;
}
}
.upload-video {
&-text {
color: #1B1B1B;
font-size: 32rpx;
font-weight: 700;
margin-top: 35rpx;
}
}
.upload-cover {
position: relative;
&-text {
position: absolute;
bottom: 0;
width: 100%;
background-color: rgba($color: #000000, $alpha: 0.6);
color: #FFFFFF;
padding: 21rpx 0;
}
}
</style> </style>

+ 39
- 10
pages_order/sharing/video.vue View File

@ -28,6 +28,7 @@
import popupUnlock from '../components/popupUnlock.vue' import popupUnlock from '../components/popupUnlock.vue'
import popupQrCode from '../components/popupQrCode.vue' import popupQrCode from '../components/popupQrCode.vue'
import shareLog from '@/utils/shareLog'
export default { export default {
components: { components: {
@ -108,6 +109,7 @@
query: `id=${this.id}&state=1&shareId=${this.userInfo.id}`, query: `id=${this.id}&state=1&shareId=${this.userInfo.id}`,
} }
// //
const params = { const params = {
id: this.id, id: this.id,
@ -115,6 +117,7 @@
} }
// this.$fetch('addLogShareInfo', params) // this.$fetch('addLogShareInfo', params)
//
shareLog.insert(this.id) shareLog.insert(this.id)
return o return o
@ -125,6 +128,12 @@
this.detail = await this.$fetch('getVideoShareInfo', { this.detail = await this.$fetch('getVideoShareInfo', {
id id
}) })
// numtimeNum
if (this.detail) {
this.detail.num = parseInt(this.detail.num) || 0;
this.detail.timeNum = parseFloat(this.detail.timeNum) || 0;
}
} catch (err) { } catch (err) {
} }
@ -132,14 +141,20 @@
async initData() { async initData() {
this.isLocked = true this.isLocked = true
await this.fetchDetails(this.id) await this.fetchDetails(this.id)
this.videoContext = uni.createVideoContext('video'); this.videoContext = uni.createVideoContext('video');
//
const result = await this.fetchCheckShare()
if (result.open) {
this.isLocked = false
this.timeIsUp = false
}
}, },
async refreshLockStatus() { async refreshLockStatus() {
this.isLocked = false
this.timeIsUp = false
// timeIsUp = false
// this.timeIsUp = false
setTimeout(async () => { setTimeout(async () => {
const result = await this.fetchCheckShare() const result = await this.fetchCheckShare()
const { const {
open, open,
@ -147,14 +162,18 @@
num num
} = result } = result
console.log('--open', open)
if (open) { // if (open) { //
this.videoContext.play() this.videoContext.play()
this.isLocked = false this.isLocked = false
this.timeIsUp = false //
return return
}
}else{
if(this.timeIsUp){
this.onPlay()
}
}
//
uni.showToast({ uni.showToast({
title: `还需转发${need_num - num}`, title: `还需转发${need_num - num}`,
icon: 'none', icon: 'none',
@ -163,7 +182,9 @@
}, },
async fetchCheckShare() { async fetchCheckShare() {
try { try {
return await shareLog.check(this.id, this.detail.num)
// detail.numAPI
const numValue = parseInt(this.detail.num) || 0;
return await shareLog.check(this.id, numValue)
} catch (err) { } catch (err) {
return {} return {}
} }
@ -173,6 +194,16 @@
return return
} }
//
const result = await this.fetchCheckShare()
if (result.open) {
this.isLocked = false
this.timeIsUp = false
this.videoContext.play()
return
}
//
this.videoContext.pause() this.videoContext.pause()
this.timeIsUp = true this.timeIsUp = true
this.$refs.popupUnlock.open(); this.$refs.popupUnlock.open();
@ -183,8 +214,6 @@
} = e.target } = e.target
if (currentTime >= this.detail.timeNum && this.isLocked) { if (currentTime >= this.detail.timeNum && this.isLocked) {
this.videoContext.pause()
this.timeIsUp = true
this.onPlay() this.onPlay()
} }
}, },


+ 8
- 5
utils/shareLog.js View File

@ -1,9 +1,11 @@
import fetch from '@/api/fetch.js' import fetch from '@/api/fetch.js'
const slog = {}
const get = () => { const get = () => {
try { try {
return JSON.parse(uni.getStorageSync('shareLog')) || {}
return slog
// return JSON.parse(uni.getStorageSync('shareLog')) || {}
} catch (err) { } catch (err) {
return {} return {}
} }
@ -23,11 +25,12 @@ const check = async (id, need_num) => {
try { try {
const log = get() const log = get()
const num = log[id] || 0
const num = parseInt(log[id]) || 0
const safeNeedNum = parseInt(need_num) || 0
const open = num >= need_num
const open = num >= safeNeedNum
return { open, need_num, num, title: `已转发${num}` }
return { open, need_num: safeNeedNum, num, title: `已转发${num}` }
} catch (err) { } catch (err) {
console.error('--校验达标异常', err) console.error('--校验达标异常', err)
return {} return {}


Loading…
Cancel
Save