Compare commits

...

6 Commits

  1. 16
      src/App.vue
  2. 97
      src/jtools/store/user.js
  3. 377
      src/pages/index/videoVip.vue
  4. 236
      src/pages/login/login.vue
  5. 54
      src/pages/me/index.vue
  6. 108
      src/pages/questionBank/components/Question.vue
  7. BIN
      src/static/image/mine/callme.png
  8. 11
      src/uni_modules/g-preview-img/changelog.md
  9. 235
      src/uni_modules/g-preview-img/components/g-preview-img/g-preview-img.vue
  10. 84
      src/uni_modules/g-preview-img/package.json
  11. 64
      src/uni_modules/g-preview-img/readme.md
  12. 24
      src/uni_modules/q-previewImage/changelog.md
  13. 121
      src/uni_modules/q-previewImage/components/q-previewImage/q-previewImage.vue
  14. 81
      src/uni_modules/q-previewImage/package.json
  15. 244
      src/uni_modules/q-previewImage/readme.md

@ -1,16 +1,21 @@
<script>
import useUserStore from '@/jtools/store/user'
import useQuestionStore from '@/jtools/store/question' //store
import storage from './jtools/storage'
export default {
onLaunch: function () {
onLaunch: function (options) {
// id
if (options.query?.scene) {
storage.set('companyId', options.query?.scene)
}
useUserStore().queryVipList()
if(useUserStore().isLogin) {
if (useUserStore().isLogin) {
useUserStore().getUserInfo()
useUserStore().searchUserVip()
}
},
onShow: function () {
useQuestionStore().getAllQuestion()
useQuestionStore().getAllQuestion()
console.log('App Show')
},
onHide: function () {
@ -23,5 +28,8 @@ export default {
/*每个页面公共css */
@import "uni_modules/uview-plus/index.scss";
@import "static/style/index.scss";
button::after{ border: none;}
button::after {
border: none;
}
</style>

@ -1,6 +1,6 @@
import { defineStore } from 'pinia';
import { login,logout,getInfo } from '@/jtools/api/login';
import { queryVip,getVipList } from '@/jtools/api/vip'
import { login, logout, getInfo } from '@/jtools/api/login';
import { queryVip, getVipList } from '@/jtools/api/vip';
import constants from '@/jtools/constants';
import storage from '@/jtools/storage';
@ -16,76 +16,77 @@ const useUserStore = defineStore({
}),
actions: {
login(params) {
return new Promise(async (resolve, reject) => {
const resp = await login(params);
if (resp.code === '0000') {
// 保存登录信息,用于重新登录
this.isLogin = true;
this.token = resp.data.token;
this.userInfo = resp.data
storage.set('isLogin', true)
storage.set('token', resp.data.token)
storage.set('userInfo', resp.data)
resolve(resp.data);
} else {
reject();
}
});
},
login(params) {
return new Promise(async (resolve, reject) => {
const resp = await login(params);
if (resp.code === '0000') {
// 保存登录信息,用于重新登录
this.isLogin = true;
this.token = resp.data.token;
this.userInfo = resp.data;
storage.set('isLogin', true);
storage.set('token', resp.data.token);
storage.set('userInfo', resp.data);
storage.remove('companyId');
resolve(resp.data);
} else {
reject();
}
});
},
// 登出
logout(force = false) {
return new Promise((resolve, reject) => {
this.resetUserData();
uni.redirectTo({
url: '/pages/login/login'
})
});
resolve();
})
});
},
//过期登出
logoutWithoutToken(force = false) {
return new Promise((resolve, reject) => {
this.resetUserData();
resolve();
});
},
//过期登出
logoutWithoutToken(force = false) {
return new Promise((resolve, reject) => {
this.resetUserData();
resolve();
})
},
// 获取用户信息
getUserInfo() {
getInfo().then(resp => {
if(resp.code == '0000') {
this.userInfo = resp.data
storage.set('userInfo', resp.data)
if (resp.code == '0000') {
this.userInfo = resp.data;
storage.set('userInfo', resp.data);
}
})
});
},
resetUserData() {
this.isLogin = false;
this.token = '';
this.userInfo = {}
this.vipOnList = []
storage.remove('isLogin')
storage.remove('token')
storage.remove('userInfo')
this.userInfo = {};
this.vipOnList = [];
storage.remove('isLogin');
storage.remove('token');
storage.remove('userInfo');
},
// 查询当前用户的vip开通情况
async searchUserVip() {
this.currentCartype=storage.get('carType') || '1001'
const resp=await queryVip({ carTypeId: this.currentCartype,memberId: null, subject:'' })
if(resp.code == '0000') {
this.vipOnList = resp.data
}
this.currentCartype = storage.get('carType') || '1001';
const resp = await queryVip({ carTypeId: this.currentCartype, memberId: null, subject: '' });
if (resp.code == '0000') {
this.vipOnList = resp.data;
}
},
// 查询所有的vip
queryVipList() {
this.currentCartype= storage.get('carType') || '1001'
getVipList({ carTypeId: this.currentCartype,memberId: null, subject:'' }).then(resp => {
if(resp.code == '0000') {
this.vipAllList = resp.data
this.currentCartype = storage.get('carType') || '1001';
getVipList({ carTypeId: this.currentCartype, memberId: null, subject: '' }).then(resp => {
if (resp.code == '0000') {
this.vipAllList = resp.data;
}
})
});
}
},
}
});
export default useUserStore;

@ -4,12 +4,15 @@
<image style="width: 100%;height: 600rpx;" src="https://oss-bq.ahduima.com/%E5%B0%8F%E7%A8%8B%E5%BA%8F/%E5%9B%BE%E7%89%87/vip%E9%A2%98%E5%BA%93_20230911211532.png"></image>
<view style="margin-bottom: 100px;">
<view class="flex jc-fa ai-c wp100 p14">
<view style="width: 33.3%;" v-for="(item,index) of priceList" :key="index">
<view class="option_tem relative" :class="checkedId===item.memberId?'checked_item':''" @click="checkPrice(item.memberId,item.price)">
<text class="fw600 fs12 cor-333">{{item.memberName}}</text>
<view class="mt5">
<view style="width: 33.3%;" v-for="(item, index) of priceList" :key="index">
<view class="option_tem relative" :class="checkedId === item.memberId ? 'checked_item' : ''" @click="checkPrice(item.memberId, item.price)">
<text class="fw600 fs12 cor-333">{{ item.memberName }}</text>
<view class="mt5" v-if="!isIOS">
<text class="fs14" style="color: #FF6E02;">¥</text>
<text class="fs30 fw600" style="color: #FF6E02;">{{item.price}}</text>
<text class="fs30 fw600" style="color: #FF6E02;">{{ item.price }}</text>
</view>
<view v-else class="mt5">
<text class="fs14" style="color: #FF6E02;">iOS暂不支持</text>
</view>
<text class="fs12 cor-999">一年有效</text>
<!-- <view class="bottom_box fs12 cor-333" :class="checkedId===item.memberId?'checked_bottom':''">赠送vip题库</view> -->
@ -21,12 +24,12 @@
</view>
<view class="intr_box p14">
<view class="fw600 fs16 cor-000">尊享以下权益</view>
<view class="flex ai-c jc-sb mt15" v-if="subject=='1'||subject=='4'">
<view class="flex ai-c jc-sb mt15" v-if="subject == '1' || subject == '4'">
<view class="text-center" style="width: 33%">
<view class="wp100 flex ai-c jc-c mb5">
<image style="width: 63rpx;height: 63rpx;margin-right: 5px;" src="../../static/image/index/vip500.png"></image>
</view>
<text>精简{{titleNum}}</text>
<text>精简{{ titleNum }}</text>
</view>
<view class="text-center" style="width: 33%;">
<view class="wp100 flex ai-c jc-c mb5">
@ -59,14 +62,14 @@
</view>
</view>
</view>
<view class="wp100 mt15" v-if="subject=='1'||subject=='4'">
<view class="wp100 mt15" v-if="subject == '1' || subject == '4'">
<image class="wp100" mode="widthFix" :src="picUrl"></image>
</view>
</view>
</view>
<view class="wp100 p14" style="position: absolute;left: 0;bottom:20px" @tap="handlePay()">
<view v-if="!isIOS" class="wp100 p14" style="position: absolute;left: 0;bottom:20px" @tap="handlePay()">
<view class="sub_btn flex ai-c jc-sb">
<text class="cor-fff fs14">¥<text class="fs24 cor-fff">{{nowPrice}}</text></text>
<text class="cor-fff fs14">¥<text class="fs24 cor-fff">{{ nowPrice }}</text></text>
<image style="width: 276rpx;height: 88rpx;margin-top: -5px;" src="../../static/image/index/buy.png"></image>
</view>
</view>
@ -74,187 +77,197 @@
</template>
<script>
import {
mapState,
mapActions
} from 'pinia' //
import { getVipList } from '@/jtools/api/vip'
import { querySysConfig } from '@/jtools/api/question';
import storage from '@/jtools/storage';
import Pay from '@/jtools/pay/index.js';
import useUserStore from '@/jtools/store/user'
export default {
data(){
return{
picUrl:'',
titleNum:500,
subject:'1',
loading:true,
nowPrice:168,
checkedId:0,
priceList:[],
order:{
money:0,
description:'会员充值'
import {
mapState,
mapActions
} from 'pinia' //
import { getVipList } from '@/jtools/api/vip'
import { querySysConfig } from '@/jtools/api/question';
import storage from '@/jtools/storage';
import Pay from '@/jtools/pay/index.js';
import useUserStore from '@/jtools/store/user'
export default {
data() {
return {
picUrl: '',
titleNum: 500,
subject: '1',
loading: true,
nowPrice: 168,
checkedId: 0,
priceList: [],
order: {
money: 0,
description: '会员充值'
},
isIOS: true
}
},
onLoad(op) {
this.isIOS = this.$platform.device().includes('ios')
if (op.subject) {
this.subject = op.subject
}
this.loading = true
this.getVipList()
this.getWXOpenId()
this.getTitle()
this.getPic()
this.$set(this.order, 'userId', this.userInfo.userId);
},
computed: {
...mapState(useUserStore, ["userInfo"])
},
methods: {
getPic() {
const currentCartype = storage.get('carType') || '1001'
querySysConfig(currentCartype, 'VipDescImageUrl').then(res => {
this.picUrl = JSON.parse(res.data.configJson).url
})
},
getTitle() {
const carId = storage.get('carType') || '1001'
querySysConfig(carId, 'SimplifyQuestionNum').then(resp => {
if (resp.code === '0000') {
const list = JSON.parse(resp.data.configJson)
this.titleNum = list.find(item => item.subject == this.subject).num
}
}
})
},
onLoad(op){
if(op.subject){
this.subject=op.subject
async handlePay() {
if (this.loading) {
this.loading = false
await this.getWXOpenId()
new Pay('wechat', this.order);
this.loading = true
}
this.loading=true
this.getVipList()
this.getWXOpenId()
this.getTitle()
this.getPic()
this.$set(this.order, 'userId', this.userInfo.userId);
},
computed: {
...mapState(useUserStore, ["userInfo"])
getWXOpenId() {
const that = this
uni.login({
success(res) {
that.$set(that.order, 'code', res.code);
}
})
},
methods:{
getPic(){
const currentCartype = storage.get('carType') || '1001'
querySysConfig(currentCartype, 'VipDescImageUrl').then(res => {
this.picUrl = JSON.parse(res.data.configJson).url
getVipList() {
getVipList({
carTypeId: storage.get('carType') || '1001',
subject: this.subject
}).then(resp => {
if (resp.code === '0000') {
this.priceList = resp.data
this.checkedId = this.priceList[0].memberId
this.order.outTradeNo = this.priceList[0].memberId
this.order.money = this.priceList[0].price
this.nowPrice = this.priceList[0].price
this.priceList.forEach(item => {
if (item.subjects.length > 1) {
item.all = true
}
})
},
getTitle(){
const carId=storage.get('carType') || '1001'
querySysConfig(carId,'SimplifyQuestionNum').then(resp=>{
if(resp.code==='0000'){
const list = JSON.parse(resp.data.configJson)
this.titleNum=list.find(item=>item.subject==this.subject).num
}
})
},
async handlePay(){
if(this.loading){
this.loading=false
await this.getWXOpenId()
new Pay('wechat', this.order);
this.loading=true
}
},
getWXOpenId() {
const that = this
uni.login({
success(res) {
that.$set(that.order, 'code', res.code);
}
})
},
getVipList(){
getVipList({
carTypeId: storage.get('carType') || '1001',
subject:this.subject
}).then(resp=>{
if(resp.code==='0000'){
this.priceList=resp.data
this.checkedId=this.priceList[0].memberId
this.order.outTradeNo=this.priceList[0].memberId
this.order.money=this.priceList[0].price
this.nowPrice=this.priceList[0].price
this.priceList.forEach(item=>{
if(item.subjects.length>1){
item.all=true
}
})
}
})
},
checkPrice(val,price){
this.checkedId=val
this.order.outTradeNo=val
this.nowPrice=price
this.order.money=price
}
}
})
},
checkPrice(val, price) {
this.checkedId = val
this.order.outTradeNo = val
this.nowPrice = price
this.order.money = price
}
}
}
</script>
<style scoped>
.option_tem{
width: 220rpx;
height: 241rpx;
text-align: center;
background: #FFFFFF;
border: 2px solid #D8D8D8;
border-radius: 16rpx 46rpx 16rpx 16rpx;
padding: 14px;
}
.checked_item{
background: #FFF0E5;
border: 4px solid #FF6E02;
}
.bottom_box{
width: 214rpx;
height: 40rpx;
line-height: 40rpx;
text-align: center;
background: rgb(239,239,239);
border-radius: 0 0 16rpx 16rpx;
position: absolute;
bottom: 0;
left: 0;
}
.checked_bottom{
width: 218rpx;
border-radius: 0 0 16rpx 5rpx;
background-color: #FF6E02;
color:#fff
}
.tag{
padding:0 5px;
height: 36rpx;
background: linear-gradient(90deg, #E66501 0%, #F8A42C 100%);
border-radius: 8rpx 20rpx 8rpx 8rpx;
line-height: 36rpx;
text-align: center;
font-size: 12px;
color: #FFFC27;
position: absolute;
left: 10rpx;
top:-18rpx
}
.intr_box{
width: 100%;
text-align: center;
padding: 40rpx;
background: #FFF0E5;
border-radius: 16rpx;
}
.vip_item{
width: 208rpx;
height: 54rpx;
line-height: 54rpx;
text-align: center;
font-size: 14px;
background: #F3D7C2;
border-radius: 0rpx 10rpx 10rpx 10rpx;
}
.sub_btn{
width:100%;
height: 110rpx;
border: 4px solid #F59B26;
background: linear-gradient(0deg, #E66501 0%, #F8A42C 100%);
box-shadow: 0rpx 16rpx 20rpx 1rpx rgba(245,155,38,0.78);
border-radius: 55rpx;
padding: 14rpx;
}
.contain-box {
width: 344rpx;
height: 196rpx;
background: #00B74F;
border-radius: 16rpx;
}
.play_btn_2 {
width: 65rpx;
height: 65rpx;
position: absolute;
left: 165.5rpx;
top: 78rpx
}
.option_tem {
width: 220rpx;
height: 241rpx;
text-align: center;
background: #FFFFFF;
border: 2px solid #D8D8D8;
border-radius: 16rpx 46rpx 16rpx 16rpx;
padding: 14px;
}
.checked_item {
background: #FFF0E5;
border: 4px solid #FF6E02;
}
.bottom_box {
width: 214rpx;
height: 40rpx;
line-height: 40rpx;
text-align: center;
background: rgb(239, 239, 239);
border-radius: 0 0 16rpx 16rpx;
position: absolute;
bottom: 0;
left: 0;
}
.checked_bottom {
width: 218rpx;
border-radius: 0 0 16rpx 5rpx;
background-color: #FF6E02;
color: #fff
}
.tag {
padding: 0 5px;
height: 36rpx;
background: linear-gradient(90deg, #E66501 0%, #F8A42C 100%);
border-radius: 8rpx 20rpx 8rpx 8rpx;
line-height: 36rpx;
text-align: center;
font-size: 12px;
color: #FFFC27;
position: absolute;
left: 10rpx;
top: -18rpx
}
.intr_box {
width: 100%;
text-align: center;
padding: 40rpx;
background: #FFF0E5;
border-radius: 16rpx;
}
.vip_item {
width: 208rpx;
height: 54rpx;
line-height: 54rpx;
text-align: center;
font-size: 14px;
background: #F3D7C2;
border-radius: 0rpx 10rpx 10rpx 10rpx;
}
.sub_btn {
width: 100%;
height: 110rpx;
border: 4px solid #F59B26;
background: linear-gradient(0deg, #E66501 0%, #F8A42C 100%);
box-shadow: 0rpx 16rpx 20rpx 1rpx rgba(245, 155, 38, 0.78);
border-radius: 55rpx;
padding: 14rpx;
}
.contain-box {
width: 344rpx;
height: 196rpx;
background: #00B74F;
border-radius: 16rpx;
}
.play_btn_2 {
width: 65rpx;
height: 65rpx;
position: absolute;
left: 165.5rpx;
top: 78rpx
}
</style>

@ -13,7 +13,7 @@
<view class="list-call">
<u-input class="sl-input" v-model="login.code" type="text" maxlength="6" border="none" placeholder="输入验证码">
<template #suffix>
<text class="fs14 mr10" style="color: #05C341;" @tap="getCode">{{countDown==0?'获取验证码':countDown}}</text>
<text class="fs14 mr10" style="color: #05C341;" @tap="getCode">{{ countDown == 0 ? '获取验证码' : countDown }}</text>
</template>
</u-input>
</view>
@ -27,138 +27,142 @@
</template>
<script>
import {
isPhone
} from '@/jtools/utils/validate.js'
import {
getCode,
login
} from '@/jtools/api/login'
import useUserStore from '@/jtools/store/user'
export default {
data() {
return {
login: {
phone: '',
code: ''
},
countDown: 0,
js: undefined
};
},
onShow() {
if(useUserStore().isLogin) {
this.toHome()
}
},
methods: {
getCode() {
if (isPhone(this.login.phone) && this.countDown == 0) {
getCode({
phone: this.login.phone
}).then(resp => {
// if (resp.code == '0000') {
uni.showToast({
title: '发送成功!',
icon: 'none'
})
this.countDown = 60
this.js = setInterval(() => {
this.countDown--;
if (this.countDown == 0) {
this.clear()
}
}, 1000)
// }
})
}
},
clear() {
clearInterval(js)
this.js = null
this.countDown = 0
import {
isPhone
} from '@/jtools/utils/validate.js'
import {
getCode,
login
} from '@/jtools/api/login'
import useUserStore from '@/jtools/store/user'
import storage from '@/jtools/storage';
export default {
data() {
return {
login: {
phone: '',
code: ''
},
bindLogin() {
if(isPhone(this.login.phone) && this.login.code) {
useUserStore().login(this.login).then(resp => {
if(resp.userId) {
useUserStore().getUserInfo()
useUserStore().searchUserVip()
this.toHome()
}
countDown: 0,
js: undefined
};
},
onShow() {
if (useUserStore().isLogin) {
this.toHome()
}
},
methods: {
getCode() {
if (isPhone(this.login.phone) && this.countDown == 0) {
getCode({
phone: this.login.phone
}).then(resp => {
// if (resp.code == '0000') {
uni.showToast({
title: '发送成功!',
icon: 'none'
})
this.countDown = 60
this.js = setInterval(() => {
this.countDown--;
if (this.countDown == 0) {
this.clear()
}
}, 1000)
// }
})
}
},
clear() {
clearInterval(js)
this.js = null
this.countDown = 0
},
bindLogin() {
if (isPhone(this.login.phone) && this.login.code) {
let params = { ...this.login }
if (storage.get('companyId')) {
params.id = storage.get('companyId')
}
},
toHome() {
uni.switchTab({
url: '/pages/index/index'
useUserStore().login(params).then(resp => {
if (resp.userId) {
useUserStore().getUserInfo()
useUserStore().searchUserVip()
this.toHome()
}
})
}
},
toHome() {
uni.switchTab({
url: '/pages/index/index'
})
}
}
}
</script>
<style>
page {
background-color: #fff;
}
.content {
display: flex;
flex-direction: column;
justify-content: center;
}
page {
background-color: #fff;
}
.header {
margin-top: 166rpx;
margin-left: auto;
margin-right: auto;
letter-spacing: 10rpx;
}
.content {
display: flex;
flex-direction: column;
justify-content: center;
}
.header image {
width: 383rpx;
}
.header {
margin-top: 166rpx;
margin-left: auto;
margin-right: auto;
letter-spacing: 10rpx;
}
.list {
display: flex;
flex-direction: column;
padding-top: 120rpx;
padding-left: 90rpx;
padding-right: 90rpx;
}
.header image {
width: 383rpx;
}
.list-call {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
height: 100rpx;
color: #333333;
border-bottom: 0.5px solid #e2e2e2;
}
.list {
display: flex;
flex-direction: column;
padding-top: 120rpx;
padding-left: 90rpx;
padding-right: 90rpx;
}
.list-call {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
height: 100rpx;
color: #333333;
border-bottom: 0.5px solid #e2e2e2;
}
.list-call .sl-input {
flex: 1;
text-align: left;
font-size: 32rpx;
margin-left: 16rpx;
}
.button-login {
color: #FFFFFF;
font-size: 34rpx;
width: 560rpx;
height: 100rpx;
background: linear-gradient(90deg, #11DF20 0%, #00B74F 100%);
border-radius: 50rpx;
line-height: 100rpx;
text-align: center;
margin-top: 100rpx;
margin-left: auto;
margin-right: auto;
}
.list-call .sl-input {
flex: 1;
text-align: left;
font-size: 32rpx;
margin-left: 16rpx;
}
.button-login {
color: #FFFFFF;
font-size: 34rpx;
width: 560rpx;
height: 100rpx;
background: linear-gradient(90deg, #11DF20 0%, #00B74F 100%);
border-radius: 50rpx;
line-height: 100rpx;
text-align: center;
margin-top: 100rpx;
margin-left: auto;
margin-right: auto;
}
</style>

@ -40,7 +40,7 @@
<view v-if="!isLogin || !vipOn.length" class="text-center">
<view class="fs18 fwb" style="color: #7E4012FF;">开通VIP尊享以下权益</view>
<view class="fs15" style="color: #7E4012FF;">精选500题 / 真是模考 / 考前密卷</view>
<view class="study fs16 text-center" style="margin: 25px auto 0;color: #F6E99FFF;">立即开通</view>
<view class="study fs16 text-center" style="margin: 25px auto 0;color: #F6E99FFF;">{{ isIOS ? 'iOS暂不可用' : '立即开通' }}</view>
</view>
<view v-else-if="vipOn.length" class="text-center">
<view class="fs18 fwb" style="color: #7E4012FF;">{{ vipText }}</view>
@ -81,11 +81,16 @@
<img src="/static/image/mine/wdtj.png" style="width: 24px;height: 24px;">
</template>
</u-cell>
<u-cell size="large" title="我的题库" :value="carName" isLink @tap="toChangeCarType">
<u-cell size="large" title="我的题库" :value="carName" @tap="toChangeCarType">
<template #icon>
<img src="/static/image/mine/wdtk.png" style="width: 24px;height: 24px;">
</template>
</u-cell>
<u-cell size="large" title="联系我们" @tap="callPhoneNumber">
<template #icon>
<img src="/static/image/mine/callme.png" style="width: 24px;height: 24px;">
</template>
</u-cell>
</u-cell-group>
</view>
<view v-if="isLogin" class="flex ai-c jc-c mt12 br8 bc-fff" style="height: 50px;" @tap="handleLogout">
@ -135,26 +140,37 @@ export default {
}
}
},
data(){
return{
carName:storage.get('carName') || '小车C1/C2/C3'
}
},
data() {
return {
carName: storage.get('carName') || '小车C1/C2/C3',
isIOS: true
}
},
onShow() {
this.carName=storage.get('carName') || '小车C1/C2/C3'
this.isIOS = this.$platform.device().includes('ios')
this.carName = storage.get('carName') || '小车C1/C2/C3'
},
methods: {
toChangeCarType(){
uni.navigateTo({
url:"/pages/me/changeCarType"
})
//
callPhoneNumber() {
uni.makePhoneCall({
phoneNumber: '15105693067'
});
},
toChangeCarType() {
uni.navigateTo({
url: "/pages/me/changeCarType"
})
},
handleVip() {
if (this.isIOS) {
return
}
if (this.isLogin) {
// if (this.vipOn.length) {
uni.navigateTo({
url: '/pages/me/vip'
})
uni.navigateTo({
url: '/pages/me/vip'
})
// } else {
// uni.navigateTo({
// url: '/pages/index/videoVip'
@ -192,10 +208,10 @@ export default {
// uni.navigateTo({
// url: '/pages/me/tijian'
// })
uni.showToast({
title:'敬请期待',
icon:'none'
})
uni.showToast({
title: '敬请期待',
icon: 'none'
})
} else {
this.toLogin()
}

@ -7,9 +7,8 @@
:class="tCurrent==item.value?'checked':'unchecked'" @tap="sectionChange(item.value)">{{item.label}}</view>
</view>
</view>
<swiper class="swiper mt20" :current="swiperIndex" :duration="duration" :autoplay="false"
@change="onChange" @animationfinish="onAnimationfinish"
@touchend="touchEnd">
<swiper class="swiper mt20" :current="swiperIndex" :duration="duration" :autoplay="false" @change="onChange"
@animationfinish="onAnimationfinish" @touchend="touchEnd">
<swiper-item v-for="(quesItem,quesIndex) in swiperList" :key="quesIndex.questionId">
<scroll-view scroll-y="true" class="swiper-scroll">
<view>
@ -17,8 +16,10 @@
<text class="tag_box">{{getQuestType(quesItem.type)}}</text>
<text class="fs18" style="line-height: 42rpx;vertical-align: middle;">{{quesItem.question}}</text>
</view>
<view class="p14" v-if="quesItem.imageUrl">
<image v-show="quesItem.imageUrl" style="width: 100%;height: auto;" mode="widthFix" :lazy-load="true" @load="onoff='1'" :src="quesItem.imageUrl"></image>
<view class="p14 flex jc-c ai-c" v-if="quesItem.imageUrl">
<image v-show="quesItem.imageUrl" style="width: auto;max-height:40vh;" mode="heightFix"
:lazy-load="true" @load="onoff='1'" :src="quesItem.imageUrl" @click="preview(quesItem.imageUrl)">
</image>
</view>
<template v-if="quesItem.type!='3'">
<view class="flex m14lr ai-c mt20" v-for="(item,index) in quesItem.optionList" :key="item.op"
@ -41,7 +42,8 @@
v-if="quesItem.clickAnswer&&!quesItem.trueAnswer.includes(quesItem.clickAnswer) || showBestAnswer">
<view class="answer_box">
<text class="fs18 fw600 cor-000">答案:{{getRightOp(quesItem.trueAnswer)}}</text>
<view v-if="showSkillInfo==='show'&&quesItem.skillInfo" class="fs18 cor-000 mt5">答题技巧{{quesItem.skillInfo}}</view>
<view v-if="showSkillInfo==='show'&&quesItem.skillInfo" class="fs18 cor-000 mt5">
答题技巧{{quesItem.skillInfo}}</view>
</view>
<view class="flex ai-c jc-c mt10">
<view style="height: 6rpx;width: 120rpx;background-color: rgb(232, 232, 232);"></view>
@ -50,7 +52,10 @@
</view>
<view class="mt10">
<view class="fw600 cor-000 mb10 flex ai-c">
<view style="background: linear-gradient(90deg, #11DF20 0%, #00B74F 100%);height: 36rpx;width: 8rpx;" class="mr5"></view>题目解析</view>
<view
style="background: linear-gradient(90deg, #11DF20 0%, #00B74F 100%);height: 36rpx;width: 8rpx;"
class="mr5"></view>题目解析
</view>
<view style="text-indent:2em;">{{quesItem.bestAnswer}}</view>
</view>
</view>
@ -92,24 +97,29 @@
<view class="m14lr mt30" v-if="isShowAnswer">
<view class="answer_box">
<text class="fs18 fw600 cor-000">答案:{{getRightOp(quesItem.trueAnswer)}}</text>
<view v-if="showSkillInfo==='show'&&quesItem.skillInfo" class="fs18 cor-000"> 答题技巧{{quesItem.skillInfo}}</view>
</view>
<view class="flex ai-c jc-c mt10">
<view style="height: 6rpx;width: 120rpx;background-color: rgb(232, 232, 232);"></view>
<view class="fs18 fw600 cor-000 p15lr">试题详解</view>
<view style="height: 6rpx;width: 120rpx;background-color: rgb(232, 232, 232);"></view>
</view>
<view class="mt10">
<view class="fw600 cor-000 mb10 flex ai-c">
<view style="background: linear-gradient(90deg, #11DF20 0%, #00B74F 100%);height: 36rpx;width: 8rpx;" class="mr5"></view>题目解析</view>
<view style="text-indent:2em;">{{quesItem.bestAnswer}}</view>
<view v-if="showSkillInfo==='show'&&quesItem.skillInfo" class="fs18 cor-000">
答题技巧{{quesItem.skillInfo}}</view>
</view>
<view class="flex ai-c jc-c mt10">
<view style="height: 6rpx;width: 120rpx;background-color: rgb(232, 232, 232);"></view>
<view class="fs18 fw600 cor-000 p15lr">试题详解</view>
<view style="height: 6rpx;width: 120rpx;background-color: rgb(232, 232, 232);"></view>
</view>
<view class="mt10">
<view class="fw600 cor-000 mb10 flex ai-c">
<view
style="background: linear-gradient(90deg, #11DF20 0%, #00B74F 100%);height: 36rpx;width: 8rpx;"
class="mr5"></view>题目解析
</view>
<view style="text-indent:2em;">{{quesItem.bestAnswer}}</view>
</view>
</view>
</template>
</view>
</scroll-view>
</swiper-item>
</swiper>
<q-previewImage ref="previewRef" :urls="imgs" @open="open"></q-previewImage>
<view class="wp100 flex jc-sb ai-c p14 bc-fff" v-if="isShowAll" style="position: fixed;bottom: 0;left: 0;">
<view style="width: 220rpx;">
<view v-if="type==='practice'" style="width: 220rpx;height: 80rpx;"></view>
@ -232,8 +242,8 @@
</view>
</view>
<view class="flex ai-c jc-fs p14" style="flex-wrap: wrap;max-height: 400px;overflow-y: scroll;">
<view v-for="(item,index) of questionList" :key="item.questionId" style="width:20%;position: relative;" class="flex ai-c jc-c"
@tap="chooseQueston(index)">
<view v-for="(item,index) of questionList" :key="item.questionId" style="width:20%;position: relative;"
class="flex ai-c jc-c" @tap="chooseQueston(index)">
<view class="tCircle mb10" :class="{
'active':index == topicIndex,
'success':type=='exam'?rightList.includes(item.questionId):storageRightList.includes(item.questionId),
@ -241,8 +251,8 @@
}">
{{index+1}}
</view>
<u-icon name="star-fill" v-if="collectList.includes(item.questionId)" style="position: absolute;right: 5px;top:-3px"
color="rgb(249,236,141)" size="24"></u-icon>
<u-icon name="star-fill" v-if="collectList.includes(item.questionId)"
style="position: absolute;right: 5px;top:-3px" color="rgb(249,236,141)" size="24"></u-icon>
</view>
</view>
</view>
@ -317,10 +327,11 @@
},
data() {
return {
subject:'1',
showSkillInfo:'hidden',
currentType:storage.get('carType') || '1001',
onoff:'0',
imgs: [],
subject: '1',
showSkillInfo: 'hidden',
currentType: storage.get('carType') || '1001',
onoff: '0',
navTitle: '',
originArray: '',
showBestAnswer: false,
@ -333,7 +344,7 @@
tCurrent: 0,
index: 0,
qIndex: 0,
storageRightList:storage.get(`rightList_subject${this.subject}`) || [],
storageRightList: storage.get(`rightList_subject${this.subject}`) || [],
storageWrongList: storage.get(`wrongList_subject${this.subject}`) || [],
rightList: [],
wrongList: [],
@ -348,9 +359,9 @@
}
},
created() {
const carType=storage.get('carType') || '1001'
querySysConfig(carType, 'NeedSkillInfo').then(resp=>{
if(resp.code === '0000'){
const carType = storage.get('carType') || '1001'
querySysConfig(carType, 'NeedSkillInfo').then(resp => {
if (resp.code === '0000') {
this.showSkillInfo = resp.data.configValue
}
})
@ -377,12 +388,27 @@
},
timeCount() {
const time = 45 * 60 * 1000
const time = 45 * 60 * 1000
return time
}
},
methods: {
...mapActions(useQuestionStore, ['getCurrentIndex']),
open() {
},
preview(url) {
this.imgs = [url] //
// #ifdef MP-WEIXIN
this.$nextTick(() => {
this.imgs = [url]
setTimeout(()=>{
this.$refs.previewRef.open(url);
},500)
})
// #endif
},
getOriginArr(val) {
const arr = JSON.parse(val)
let arr1 = []
@ -536,11 +562,11 @@
toSubmit() {
const restTime = this.time.hours * 60 * 60 + this.time.minutes * 60 + this.time.seconds
const score = (this.rightList.length / this.questionList.length * 100).toFixed(0)
if(this.rightList.length+this.wrongList.length==0){
if (this.rightList.length + this.wrongList.length == 0) {
uni.navigateBack({
delta:1
delta: 1
})
}else{
} else {
submitTest({
"carTypeId": storage.get('carType') || '1001',
"score": score,
@ -769,12 +795,12 @@
if (title) {
this.navTitle = title
}
if(subject){
if (subject) {
this.subject = subject
console.log(this.subject);
this.storageRightList=storage.get(`rightList_subject${subject}`) || []
this.storageWrongList=storage.get(`wrongList_subject${subject}`) || []
this.collectList=storage.get(`collectList_subject${subject}`) || []
this.storageRightList = storage.get(`rightList_subject${subject}`) || []
this.storageWrongList = storage.get(`wrongList_subject${subject}`) || []
this.collectList = storage.get(`collectList_subject${subject}`) || []
}
if (val && val.length) {
this.questionList = JSON.parse(val)
@ -783,12 +809,12 @@
}
console.log(this.questionList);
if (this.navTitle === '顺序答题') {
if(subject){
if (subject) {
this.pickerTopic(this[`currentIndex_subject${subject}`])
}else{
} else {
this.pickerTopic(this[`currentIndex_subject${this.subject}`])
}
} else {
this.pickerTopic(this.topicIndex)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

@ -0,0 +1,11 @@
## 1.0.4(2022-12-07)
修改:判断在APP端不监听document的滚动
## 1.0.3(2022-12-05)
新增:支持视频预览,视频图片混用
新增:支持预览单张,handlePreviewImg方法直接传入图片或视频地址即可单张预览
## 1.0.2(2022-12-05)
## 1.0.1(2022-12-05)
文档错误修改
## 1.0.0(2022-11-29)
初始化插件

@ -0,0 +1,235 @@
<template>
<view class="pos">
<uni-transition :mode-class="modeClass" :show="show">
<!-- 多张图片预览 -->
<view class="content" @tap="closedPreview">
<swiper
class="swiper"
circular
:current="curDot"
@change="swiperChange"
:indicator-dots="false"
>
<swiper-item v-for="(item, idx) in selfImgList" :key="idx">
<movable-area scale-area>
<movable-view
:scale="!disabledScale"
direction="all"
scale="true"
scale-min="0.5"
scale-max="5"
:scale-value="1"
damping="150"
friction="15"
>
<image v-if="isImg(item)" :src="item" mode="widthFix"></image>
<view class="video-preview" v-else>
<video
:autoplay="true"
:src="item"
:enable-progress-gesture="false"
:show-fullscreen-btn="false"
></video>
</view>
</movable-view>
</movable-area>
</swiper-item>
</swiper>
</view>
<!-- 指示器 -->
<slot name="indicator" v-if="imgList.length > 1 && !indicatorDotsType">
<view class="current-dot">
<view class="change-buttom" @tap.stop="previousImg">
<uni-icons class="font-white" type="back" size="30"></uni-icons>
</view>
<view class="font-white cur">
{{ curDot + 1 }}/{{ imgList.length }}
</view>
<view class="change-buttom" @tap.stop="nextImg">
<uni-icons class="font-white" type="forward" size="30"></uni-icons>
</view>
</view>
</slot>
</uni-transition>
</view>
</template>
<script>
export default {
props: {
//
modeClass: {
type: Array,
default: ['fade', 'zoom-out'],
},
// true false
indicatorDotsType: {
type: Boolean,
default: true,
},
//
imgList: {
type: Array,
default: () => [],
},
// swiper
disabledScale: {
type: Boolean,
default: false,
},
},
data() {
return {
show: false,
curDot: 0,
selfImgList: [],
};
},
computed: {
isImg() {
return (src) => {
return src.indexOf('.mp4') === -1 ? true : false;
};
},
},
watch: {
//
/* #ifdef APP-PLUS*/
show(val) {
if (val) {
document
.getElementsByClassName('pos')[0]
.addEventListener('touchmove', function (e) {
e.preventDefault();
});
}
},
/* #endif */
imgList: {
handler(val) {
if (val.length) {
this.selfImgList = val.concat();
}
},
},
},
methods: {
handlePreviewImg(param) {
this.show = !this.show;
if (typeof param === 'string') {
this.selfImgList = [param];
} else {
if (param) {
this.curDot = param;
}
}
this.$emit('preview', this.show);
},
closedPreview() {
this.show = !this.show;
this.curDot = 0;
this.$emit('preview', this.show);
},
swiperChange(e) {
this.curDot = e.detail.current;
this.$emit('changeImg', e.detail.current);
},
previousImg() {
let num = this.imgList.length - 1;
if (this.curDot <= 0) {
this.curDot = num;
} else {
this.curDot--;
}
},
nextImg() {
let num = this.imgList.length - 1;
if (this.curDot >= num) {
this.curDot = 0;
} else {
this.curDot++;
}
},
},
};
</script>
<style lang="scss" scoped>
movable-view {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
}
movable-area {
height: 100%;
width: 100%;
position: fixed;
overflow: hidden;
}
movable-view image {
width: 100%;
}
.content {
height: 100vh;
width: 100vw;
display: flex;
align-items: center;
background: #00000076;
}
.pos {
position: absolute;
top: 0;
left: 0;
z-index: 9999;
}
.swiper {
height: 100%;
width: 100%;
}
.current-dot {
position: absolute;
bottom: 10%;
left: 25%;
width: 50%;
display: flex;
align-items: center;
justify-content: space-around;
.change-buttom {
padding: 10rpx;
border-radius: 50%;
background: #3f3f3f;
}
.cur {
font-size: 20rpx;
}
}
.font-white {
color: #fff !important;
}
::v-deep {
.uni-swiper-dots-horizontal {
bottom: 12%;
}
.uni-swiper-dot {
width: 10rpx;
height: 10rpx;
}
uni-video {
width: 100vw;
height: 100vh;
}
}
.video-preview {
position: relative;
.video-close {
position: absolute;
right: 50rpx;
top: 50rpx;
}
}
</style>

@ -0,0 +1,84 @@
{
"id": "g-preview-img",
"displayName": "g-preview-img一款兼容vue2,vue3的图片预览插件,视频预览,支持单张多张,左右滑动,放大缩小",
"version": "1.0.4",
"description": "g-preview-img一款兼容vue2,vue3的图片预览插件,视频预览,支持单张多张,左右滑动,放大缩小",
"keywords": [
"vue2",
"vue3",
"图片预览",
"视频预览"
],
"repository": "",
"engines": {
"HBuilderX": "^3.1.0"
},
"dcloudext": {
"type": "component-vue",
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": ""
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"Vue": {
"vue2": "y",
"vue3": "y"
},
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "u",
"阿里": "u",
"百度": "u",
"字节跳动": "u",
"QQ": "u",
"钉钉": "u",
"快手": "u",
"飞书": "u",
"京东": "u"
},
"快应用": {
"华为": "u",
"联盟": "u"
}
}
}
}
}

@ -0,0 +1,64 @@
![image](https://deaon-saasvideo.oss-cn-shanghai.aliyuncs.com/11111.gif)
### 一款兼容vue2,vue3的图片预览插件,视频预览,支持图片视频混用,支持单张多张,左右滑动,放大缩小
### 基础使用方法
```javascript
<template>
<image v-for="(item,idx) in imgList" :src="item" :key="idx" @tap="handleClick(idx)"></image>
<g-preview-img :imgList="imgList" ref="preview"><g-preview-img>
</template>
<script setup>
import { ref } from 'vue'
const preview = ref(null)
const imgList = ['图片路径1','图片路径2']
const handleClick = (idx)=>{
// idx为要打开的图片的索引,也可以不传,默认打开第一张
// handlePreviewImg的参数支持传入单张图片地址或单个视频地址
preview.value.handlePreviewImg(idx)
}
</script>
```
| 属性名/事件 | 类型 | 默认值 | 说明 |
| ----------------- | ------------ | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| modeClass | Array/String | \['fade', 'zoom-out'] | uni-transition组件过渡效果,可选值见 <https://uniapp.dcloud.net.cn/component/uniui/uni-transition.html#mode-class-%E5%86%85%E7%BD%AE%E8%BF%87%E6%B8%A1%E5%8A%A8%E7%94%BB%E7%B1%BB%E5%9E%8B%E8%AF%B4%E6%98%8E> |
| indicatorDotsType | Boolean | false | 多张图片的指示器,ture为圆点,false数字,当图片列表只有一张图片时,默认不展示指示器 |
| imgList | Array | | 图片列表 |
| disabledScale | Boolean | false | 是否禁止双指放大缩小 |
| @preview | 打开关闭事件 | | 接受一个参数,ture为开启,false为关闭 |
| @changeImg | 图片切换的事件 | | 参数为当前的图片索引 |
#### 插槽,自定义翻页按钮
```js
<g-preview-img :imgList="imgList" ref="preview">
<template>
<!--你的翻页按钮-->
<view @tap.stop="previousImg">上一页</view>
<view @tap.stop="nextImg">下一页</view>
</template>
</g-preview-img>
<script>
const preview = ref(null)
//上一页的方法
const previousImg = ()=>{
preview.value.previousImg()
}
//下一页的方法
const previousImg = ()=>{
preview.value.nextImg()
}
</script>
```
#### 支持uniapp原生swiper的属性
插件内部swiper标签上绑定了$attrs,所以在使用时可以传入一些swiper的属性
注意:不要传disable-touch这个属性,会有意想不到的错误
**插件bug会及时修复!!**

@ -0,0 +1,24 @@
## 1.1.1(2023-08-01)
优化文档
## 1.1.0(2023-08-01)
优化文档
## 1.0.9(2023-07-10)
优化文档
## 1.0.8(2023-06-25)
优化文档
## 1.0.7(2023-06-25)
优化文档
## 1.0.6(2023-05-26)
优化文档
## 1.0.5(2023-05-22)
优化文档
## 1.0.4(2023-04-30)
新增图片放大功能,解决原生组件和tabbar导航栏等无法覆盖的问题
## 1.0.3(2023-04-28)
优化文档
## 1.0.2(2023-04-28)
优化文档
## 1.0.1(2023-04-28)
新增长按事件
## 1.0.0(2023-04-28)
插件上线

@ -0,0 +1,121 @@
<template>
<view class="previewImage" v-if="show" @tap="close">
<view class="page" v-if="urls.length > 0">
<text class="text">{{ current + 1 }} / {{ urls.length }}</text>
</view>
<swiper class="swiper" :current="current" @change="swiperChange" @touchstart="handleTouchStart" @touchend="handleTouchEnd">
<swiper-item v-for="(item, index) in urls" :key="index">
<movable-area class="movable-area" scale-area>
<movable-view class="movable-view" direction="all" :inertia="true" damping="100" scale="true" scale-min="1" scale-max="4" :scale-value="scale">
<scroll-view scroll-y="true" class="uni-scroll-view">
<view class="scroll-view"><image :key="index" class="image" :src="item" mode="widthFix" @longpress="onLongpress(item)" /></view>
</scroll-view>
</movable-view>
</movable-area>
</swiper-item>
</swiper>
</view>
</template>
<script>
export default {
props: {
urls: {
type: Array,
required: true,
default: () => {
return [];
}
}
},
data() {
return {
show: false,
current: 0, //
scale: 1,
isZooming: false //
};
},
methods: {
//
open(current) {
this.current = this.urls.findIndex(item => item === current);
this.show = true;
this.$emit('open');
},
//
close() {
if (!this.isZooming) {
this.show = false;
this.current = 0;
this.$emit('close');
}
},
//
swiperChange(e) {
this.current = e.detail.current;
},
//
onLongpress(e) {
this.$emit('onLongpress', e);
},
handleTouchStart() {
this.isZooming = true;
},
handleTouchEnd() {
this.isZooming = false;
}
}
};
</script>
<style lang="scss" scoped>
.previewImage {
z-index: 9999;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #000000;
.swiper {
width: 100%;
height: 100vh;
swiper-item {
.movable-area {
height: 100%;
width: 100%;
.movable-view {
width: 100%;
min-height: 100%;
.scroll-view {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
.image {
width: 100%;
height: auto;
}
}
}
}
}
}
.page {
position: absolute;
z-index: 9999;
width: 100%;
top: 60rpx;
text-align: center;
.text {
color: #fff;
font-size: 32rpx;
background-color: rgba(0, 0, 0, 0.5);
padding: 3rpx 16rpx;
border-radius: 20rpx;
user-select: none;
}
}
}
</style>

@ -0,0 +1,81 @@
{
"id": "q-previewImage",
"displayName": "图片预览、多图左右滑动、图片放大、支持覆盖原生组件、原生导航栏、tabbar",
"version": "1.1.1",
"description": "最简洁的模拟图片预览,支持长按事件,多图左右滑动,大图上下滑动查看,支持图片放大,支持覆盖原生组件/原生导航栏/tabbar 支持vue2/vue3/app/小程序/h5",
"keywords": [
"图片预览"
],
"repository": "",
"engines": {
"HBuilderX": "^3.4.14"
},
"dcloudext": {
"type": "component-vue",
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": ""
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"Vue": {
"vue2": "y",
"vue3": "y"
},
"App": {
"app-vue": "y",
"app-nvue": "n"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "u",
"微信浏览器(Android)": "u",
"QQ浏览器(Android)": "u"
},
"H5-pc": {
"Chrome": "u",
"IE": "u",
"Edge": "u",
"Firefox": "u",
"Safari": "u"
},
"小程序": {
"微信": "y",
"阿里": "u",
"百度": "u",
"字节跳动": "u",
"QQ": "u",
"钉钉": "u",
"快手": "u",
"飞书": "u",
"京东": "u"
},
"快应用": {
"华为": "u",
"联盟": "u"
}
}
}
}
}

@ -0,0 +1,244 @@
# 最简洁的模拟图片预览,支持长按事件,多图左右滑动,大图上下滑动查看,支持图片放大,支持覆盖原生组件/原生导航栏/tabbar 支持vue2/vue3/app/小程序/h5
- 为了解决项目中因一些特殊原因无法使用uni.previewImage,例如App.onShow或者页面的oShow中写了方法。
- 如果用uni.previewImage,每次预览图片都会进到onShow的方法里
- 可以基本实现官方的预览图片功能,但是体验不如uni.previewImage()
- 如没有特殊原因,还是推荐官方的uni.previewImage()
## 安装指引
##1. 在插件市场打开本插件页面,在右侧点击`使用 HBuilderX 导入插件`,选择要导入的项目点击确定
##2. 使用方法 vue2写法
```
<template>
<view>
<video v-if="videoShow" id="myVideo" src="https://img.cdn.aliyun.dcloud.net.cn/guide/uniapp/%E7%AC%AC1%E8%AE%B2%EF%BC%88uni-app%E4%BA%A7%E5%93%81%E4%BB%8B%E7%BB%8D%EF%BC%89-%20DCloud%E5%AE%98%E6%96%B9%E8%A7%86%E9%A2%91%E6%95%99%E7%A8%8B@20200317.mp4" controls></video>
<image v-for="(item, index) in imgs" :key="index" :src="item" @click="preview(item)"></image>
<q-previewImage ref="previewImage" :urls="imgs" @onLongpress="onLongpress" @open="open" @close="close"></q-previewImage>
</view>
</template>
<script>
export default {
data() {
return {
videoShow:true,//video组件是否显示
imgs: [],
};
},
methods: {
preview(url) {
this.imgs = ['https://web-assets.dcloud.net.cn/unidoc/zh/multiport-20210812.png', 'https://web-assets.dcloud.net.cn/unidoc/zh/uni-function-diagram.png'] //设置图片数组
// #ifdef MP-WEIXIN
this.$nextTick(()=>{
this.$refs.previewImage.open(url); // 传入当前选中的图片地址(小程序必须添加$nextTick,解决组件首次加载无图)
})
// #endif
// #ifndef MP-WEIXIN
this.$refs.previewImage.open(url); // 传入当前选中的图片地址
// #endif
},
onLongpress(e){ //长按事件
console.log('当前长按的图片是' + e);
uni.showActionSheet({
itemList: ['转发给朋友', '保存到手机'],
success: function (res) {
console.log('选中了第' + (res.tapIndex + 1) + '个按钮');
},
fail: function (res) {
console.log(res.errMsg);
}
});
},
/* open和close方法一般用不到,但是在一些特殊场景会用到,
* 比如预览图片时你需要覆盖 NavigationBar和 TabBar,
* 或者在app中需要预览图片时覆盖住原生组件,比如video或者map等,
* 你可以根据open和close去做一些操作,例如隐藏导航栏或者隐藏一些原生组件等
*/
open(){ //监听组件显示 (隐藏TabBar和NavigationBar,隐藏video原生组件)
// uni.hideTabBar()
// uni.setNavigationBarColor({
// frontColor: '#000000', // 设置前景色为黑色
// backgroundColor: '#000000', // 设置背景色为黑色
// })
// this.videoShow = false
},
close(){ //监听组件隐藏 (显示TabBar和NavigationBar,显示video原生组件)
// uni.showTabBar()
// uni.setNavigationBarColor({
// frontColor: '#ffffff', // 设置前景色为白色
// backgroundColor: '#000000', // 设置背景色为黑色
// })
// this.videoShow = true
}
}
};
</script>
```
##3. vue3 setup写法
```
<template>
<view>
<video v-if="videoShow" id="myVideo" src="https://img.cdn.aliyun.dcloud.net.cn/guide/uniapp/%E7%AC%AC1%E8%AE%B2%EF%BC%88uni-app%E4%BA%A7%E5%93%81%E4%BB%8B%E7%BB%8D%EF%BC%89-%20DCloud%E5%AE%98%E6%96%B9%E8%A7%86%E9%A2%91%E6%95%99%E7%A8%8B@20200317.mp4" controls></video>
<image v-for="(item, index) in imgs" :key="index" :src="item" @click="preview(item)"></image>
<q-previewImage ref="previewImage" :urls="imgs" @onLongpress="onLongpress" @open="open" @close="close"></q-previewImage>
</view>
</template>
<script setup>
import { reactive, ref, toRefs,nextTick } from 'vue';
const data = reactive({
videoShow:true,//video组件是否显示
imgs: [],
});
const previewImage = ref(null);
const { imgs,videoShow } = toRefs(data)// 解构
const preview = url => {
data.imgs = ['https://web-assets.dcloud.net.cn/unidoc/zh/multiport-20210812.png', 'https://web-assets.dcloud.net.cn/unidoc/zh/uni-function-diagram.png'] //设置图片数组
// #ifdef MP-WEIXIN
nextTick(()=>{
previewImage.value.open(url); // 传入当前选中的图片地址(小程序必须添加nextTick,解决组件首次加载无图)
})
// #endif
// #ifndef MP-WEIXIN
previewImage.value.open(url); // 传入当前选中的图片地址
// #endif
};
const onLongpress = e =>{
console.log('当前长按的图片是' + e);
uni.showActionSheet({
itemList: ['转发给朋友', '保存到手机'],
success: function (res) {
console.log('选中了第' + (res.tapIndex + 1) + '个按钮');
},
fail: function (res) {
console.log(res.errMsg);
}
});
}
/* open和close方法一般用不到,但是在一些特殊场景会用到,
* 比如预览图片时你需要覆盖 NavigationBar和 TabBar,
* 或者在app中需要预览图片时覆盖住原生组件,比如video或者map等,
* 你可以根据open和close去做一些操作,例如隐藏导航栏或者隐藏一些原生组件等
*/
const open = () => { //监听组件显示 (隐藏TabBar和NavigationBar,隐藏video原生组件)
// uni.hideTabBar()
// uni.setNavigationBarColor({
// frontColor: '#000000', // 设置前景色为黑色
// backgroundColor: '#000000', // 设置背景色为黑色
// })
// data.videoShow = false
}
const close = () => { //监听组件隐藏 (显示TabBar和NavigationBar,显示video原生组件)
// uni.showTabBar()
// uni.setNavigationBarColor({
// frontColor: '#ffffff', // 设置前景色为白色
// backgroundColor: '#000000', // 设置背景色为黑色
// })
// data.videoShow = true
}
</script>
```
##4. 项目示例 (一般返回的数据图片是以逗号或特殊字符分割的字符串,点击时就需要传两个参数,一个是图片数组,一个是当前图片的index)
## 注意q-previewImage不要写在循环体中,imgs其实就是用来存放当前图片的数组,每次点击每次赋值就行
```
<template>
<view>
<video v-if="videoShow" id="myVideo" src="https://img.cdn.aliyun.dcloud.net.cn/guide/uniapp/%E7%AC%AC1%E8%AE%B2%EF%BC%88uni-app%E4%BA%A7%E5%93%81%E4%BB%8B%E7%BB%8D%EF%BC%89-%20DCloud%E5%AE%98%E6%96%B9%E8%A7%86%E9%A2%91%E6%95%99%E7%A8%8B@20200317.mp4" controls></video>
<view v-for="(item, index) in list" :key="index" class="list">
<image :src="i" mode="aspectFill" v-for="(i,imgindex) in item.urls.split(',')" @click.stop="preimg(item.urls.split(','),imgindex)"></image>
<view>
<q-previewImage ref="previewImage" :urls="imgs" @onLongpress="onLongpress" @open="open" @close="close"></q-previewImage>
</view>
</template>
<script>
export default {
data() {
return {
videoShow:true,//是否显示video组件
imgs: [],//imgs其实就是用来存放当前图片的数组,每次点击每次赋值就行
};
},
methods: {
preimg(urls,index){
this.imgs = urls //imgs其实就是用来存放当前图片的数组,每次点击每次赋值就行
// #ifdef MP-WEIXIN
this.$nextTick(()=>{
this.$refs.previewImage.open(this.imgs[index]); // 传入当前选中的图片地址(小程序必须添加$nextTick,解决组件首次加载无图)
})
// #endif
// #ifndef MP-WEIXIN
this.$refs.previewImage.open(this.imgs[index]); // 传入当前选中的图片地址
// #endif
},
onLongpress(e){ //长按事件
console.log('当前长按的图片是' + e);
uni.showActionSheet({
itemList: ['转发给朋友', '保存到手机'],
success: function (res) {
console.log('选中了第' + (res.tapIndex + 1) + '个按钮');
},
fail: function (res) {
console.log(res.errMsg);
}
});
},
/* open和close方法一般用不到,但是在一些特殊场景会用到,
* 比如预览图片时你需要覆盖 NavigationBar和 TabBar,
* 或者在app中需要预览图片时覆盖住原生组件,比如video或者map等,
* 你可以根据open和close去做一些操作,例如隐藏导航栏或者隐藏一些原生组件等
*/
open(){ //监听组件显示 (隐藏TabBar和NavigationBar,隐藏video原生组件)
// uni.hideTabBar()
// uni.setNavigationBarColor({
// frontColor: '#000000', // 设置前景色为黑色
// backgroundColor: '#000000', // 设置背景色为黑色
// })
// this.videoShow = false
},
close(){ //监听组件隐藏 (显示TabBar和NavigationBar,显示video原生组件)
// uni.showTabBar()
// uni.setNavigationBarColor({
// frontColor: '#ffffff', // 设置前景色为白色
// backgroundColor: '#000000', // 设置背景色为黑色
// })
// this.videoShow = true
}
}
};
</script>
```
## 如果插件对您有一点帮助,请给个五星好评,感谢支持
## 如有问题,请加qq 965969604
Loading…
Cancel
Save