代码更新
This commit is contained in:
parent
d27814d0b9
commit
f63f640a7b
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
// launch.json 配置了启动调试时相关设置,configurations下节点名称可为 app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
|
||||
// launchtype项可配置值为local或remote, local代表前端连本地云函数,remote代表前端连云端云函数
|
||||
"version" : "0.0",
|
||||
"configurations" : [
|
||||
{
|
||||
"app-plus" : {
|
||||
"launchtype" : "local"
|
||||
},
|
||||
"default" : {
|
||||
"launchtype" : "local"
|
||||
},
|
||||
"type" : "uniCloud"
|
||||
},
|
||||
{
|
||||
"playground" : "custom",
|
||||
"type" : "uni-app:app-android"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
import request from "@/utils/request.js";
|
||||
import requesta from "@/utils/requesta.js";
|
||||
|
||||
/**
|
||||
* 直播列表
|
||||
*/
|
||||
export function live(data) {
|
||||
return request.get("zhibo/live" ,data);
|
||||
}
|
||||
/**
|
||||
* 直播详情
|
||||
*/
|
||||
export function liveDetail(data) {
|
||||
return request.get("zhibo/liveDetail" ,data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取直播详情接口
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* 创建直播间
|
||||
*/
|
||||
export function createPushLive(data) {
|
||||
return request.post("zhibo/createPushLive", data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭直播间
|
||||
*/
|
||||
export function stopPushLive(data) {
|
||||
return request.post("zhibo/stopPushLive", data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 绑定用户client客户
|
||||
*/
|
||||
export function bindUser(data) {
|
||||
return request.post("zhibo/bindUser", data,{});
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 加入直播间聊天室
|
||||
*/
|
||||
export function joinChatRoom(data) {
|
||||
return request.post("zhibo/joinChatRoom", data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 直播间聊天室发言
|
||||
*/
|
||||
export function sendGroupMessage(data) {
|
||||
return request.post("zhibo/sendGroupMessage", data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//商品列表
|
||||
export function good(data) {
|
||||
return requesta.get("product/spu/lst", data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息
|
||||
*
|
||||
*/
|
||||
export function getUserInfo() {
|
||||
return request.get('user');
|
||||
}
|
||||
|
||||
|
||||
|
||||
//关注
|
||||
export function getfans(id,data) {
|
||||
return requesta.post('community/fans/'+id,data);
|
||||
}
|
||||
|
||||
//我关注的人
|
||||
export function getfocuslst(data) {
|
||||
return requesta.post('community/focus/lst',data);
|
||||
}
|
||||
|
||||
//关注我的人
|
||||
export function getfanslst(data) {
|
||||
return requesta.post('community/fans/lst',data);
|
||||
}
|
||||
|
||||
//用户送礼
|
||||
export function reward(data) {
|
||||
return request.post('zhibo/reward',data);
|
||||
}
|
||||
//获取礼物
|
||||
export function rewardList(data) {
|
||||
return requesta.get('zhibo/rewardList',data);
|
||||
}
|
||||
|
||||
//获取礼物
|
||||
export function giftList(data) {
|
||||
return request.get('zhibo/giftList',data);
|
||||
}
|
||||
|
||||
//获取房间人数
|
||||
export function liveAudience(data) {
|
||||
return request.get('zhibo/liveAudience',data);
|
||||
}
|
||||
|
||||
//获取用户余额
|
||||
export function getuser(data) {
|
||||
return requesta.get('user',data);
|
||||
}
|
||||
|
||||
|
||||
//送礼
|
||||
export function sendGift(data) {
|
||||
return request.post('zhibo/sendGift',data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 充值金额选择
|
||||
*/
|
||||
export function getRechargeApi() {
|
||||
return requesta.get("common/recharge_quota");
|
||||
}
|
||||
|
||||
//历史直播记录
|
||||
|
||||
export function playbackList(data) {
|
||||
return request.get("zhibo/playbackList",data);
|
||||
}
|
||||
|
||||
//获取直播回放详情
|
||||
export function playbackDetail(data) {
|
||||
return request.get("zhibo/playbackDetail",data);
|
||||
}
|
||||
//获取观众关注主播状态
|
||||
export function getAjuser(data) {
|
||||
return requesta.get("community/user/info/"+data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 滑块信息
|
||||
* @param {Object} data
|
||||
*/
|
||||
export function getAjcaptcha(data) {
|
||||
return requesta.get("ajcaptcha", data, {
|
||||
noAuth: true
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 滑块验证
|
||||
* @param {Object} data
|
||||
*/
|
||||
export function ajcaptchaCheck(data) {
|
||||
return requesta.post("ajcheck", data, {
|
||||
noAuth: true
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
import request from "@/utils/requesta.js";
|
||||
|
||||
export function getVersion() {
|
||||
return request.get("version",{},{noAuth: true});
|
||||
}
|
||||
export function commonAuth(data) {
|
||||
return request.post(
|
||||
"auth", data, {
|
||||
noAuth: true
|
||||
}
|
||||
);
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
import request from "@/utils/requesta.js";
|
||||
|
||||
|
||||
export function getAdminApplyListAPI(merId) {
|
||||
return request.get(`admin/${merId}/lis_apply`);
|
||||
}
|
||||
/**
|
||||
* 获取用户信息
|
||||
*
|
||||
*/
|
||||
export function getUserInfo() {
|
||||
return request.get('user');
|
||||
}
|
||||
/**
|
||||
* 头像
|
||||
*
|
||||
*/
|
||||
export function editAvatar(data) {
|
||||
return request.post('user/change/info', data);
|
||||
}
|
||||
|
||||
// 修改昵称
|
||||
export function updateInfo(data) {
|
||||
return request.post('user/change/avatar', data);
|
||||
}
|
||||
/**
|
||||
* h5用户登录
|
||||
* @param data object 用户账号密码
|
||||
*/
|
||||
export function loginH5(data) {
|
||||
return request.post("auth/login", data, {
|
||||
noAuth: true
|
||||
});
|
||||
}
|
||||
/**
|
||||
* h5用户手机号登录
|
||||
* @param data object 用户手机号 也只能
|
||||
*/
|
||||
export function loginMobile(data) {
|
||||
return request.post("auth/smslogin", data, {
|
||||
noAuth: true
|
||||
});
|
||||
}
|
||||
/**
|
||||
* h5用户手机号登录
|
||||
* @param data object 用户手机号 也只能
|
||||
*/
|
||||
export function loginMpPhone(data) {
|
||||
return request.post("auth/mp_phone", data, {
|
||||
noAuth: true
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 验证码key
|
||||
*/
|
||||
export function getCodeApi() {
|
||||
return request.get("verify_code", {}, {
|
||||
noAuth: true
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* h5用户发送验证码
|
||||
* @param data object 用户手机号
|
||||
*/
|
||||
export function registerVerify(data) {
|
||||
return request.post("auth/verify", data, {
|
||||
noAuth: true
|
||||
});
|
||||
}
|
||||
/**
|
||||
* h5用户手机号注册
|
||||
* @param data object 用户手机号 验证码 密码
|
||||
*/
|
||||
export function register(data) {
|
||||
return request.post("auth/register", data, {
|
||||
noAuth: true
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户手机号修改密码
|
||||
* @param data object 用户手机号 验证码 密码
|
||||
*/
|
||||
export function registerReset(data) {
|
||||
return request.post("/register/reset", data, {
|
||||
noAuth: true
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 用户手机号忘记密码
|
||||
*/
|
||||
export function registerForget(data) {
|
||||
return request.post("user/change_pwd", data, {
|
||||
noAuth: true
|
||||
});
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
<template>
|
||||
<view class="empty-box">
|
||||
<image src="/static/images/empty-box.png"></image>
|
||||
<view class="txt">{{title}}</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
export default{
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: '暂无记录',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.empty-box{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-top: 200rpx;
|
||||
image{
|
||||
width: 414rpx;
|
||||
height: 240rpx;
|
||||
}
|
||||
.txt{
|
||||
font-size: 26rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,168 @@
|
|||
<template>
|
||||
<view class="men-ban box " v-if ='isShow' @touchmove.stop.prevent="">
|
||||
<view class="box_next">
|
||||
<view class="box_next_title">
|
||||
<text class="box_next_title_z">{{title}}</text>
|
||||
</view>
|
||||
<slot></slot>
|
||||
<view class="box_next_but_d" v-if="isBut">
|
||||
<view @click='show' class="box_next_but_d_but">
|
||||
<text class="box_next_but_d_but_text">{{nName}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="box_next_but_s" v-else>
|
||||
<view class="box_next_but_s_lbut" @click="lEvent">
|
||||
<text class="box_next_but_d_but_text">{{lName}}</text>
|
||||
</view>
|
||||
<view @click="rEvent" class="box_next_but_s_rbut" hover-class="zcolor-while1">
|
||||
<text class="box_next_but_d_but_text">{{rName}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: "温馨提示"
|
||||
},
|
||||
isShow: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
nName: String,
|
||||
lName: String,
|
||||
rName: String,
|
||||
isBut: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
show() {
|
||||
|
||||
this.$emit('show');
|
||||
},
|
||||
lEvent() {
|
||||
this.$emit('lEvent');
|
||||
},
|
||||
rEvent() {
|
||||
this.$emit('rEvent');
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.men-ban {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 999999;
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.box {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
}
|
||||
|
||||
.box_next {
|
||||
background-color: #ffffff;
|
||||
width: 550rpx;
|
||||
border-radius: 30rpx;
|
||||
}
|
||||
|
||||
.box_next_title {
|
||||
padding: 30rpx 30rpx 0 30rpx;
|
||||
}
|
||||
|
||||
.box_next_title_z {
|
||||
font-size: 31rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.box_next_but_d {
|
||||
width: 550rpx;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 130rpx;
|
||||
}
|
||||
|
||||
.box_next_but_d_but {
|
||||
width: 500rpx;
|
||||
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 80rpx;
|
||||
border-radius: 50rpx;
|
||||
background-color: #fee610;
|
||||
}
|
||||
|
||||
.box_next_but_d_but_text {
|
||||
font-size: 30rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.box_next_but_s {
|
||||
width: 550rpx;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
|
||||
flex-direction: row;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
height: 130rpx;
|
||||
}
|
||||
|
||||
.box_next_but_s_lbut {
|
||||
width: 200rpx;
|
||||
background-color: #f1f1f1;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 80rpx;
|
||||
border-radius: 50rpx;
|
||||
}
|
||||
|
||||
.box_next_but_s_rbut {
|
||||
width: 200rpx;
|
||||
background-color: #fee610;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 80rpx;
|
||||
border-radius: 50rpx;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,815 @@
|
|||
<!--
|
||||
parser 主模块组件
|
||||
github:https://github.com/jin-yufeng/Parser
|
||||
docs:https://jin-yufeng.github.io/Parser
|
||||
插件市场:https://ext.dcloud.net.cn/plugin?id=805
|
||||
author:JinYufeng
|
||||
update:2020/04/14
|
||||
-->
|
||||
<template>
|
||||
<view>
|
||||
<slot v-if="!nodes.length" />
|
||||
<!--#ifdef APP-PLUS-NVUE-->
|
||||
<web-view id="top" ref="web" :src="src" :style="'margin-top:-2px;height:'+height+'px'" @onPostMessage="_message" />
|
||||
<!--#endif-->
|
||||
<!--#ifndef APP-PLUS-NVUE-->
|
||||
<view id="top" :style="showAm+(selectable?';user-select:text;-webkit-user-select:text':'')" :animation="scaleAm" @tap="_tap"
|
||||
@touchstart="_touchstart" @touchmove="_touchmove">
|
||||
<!--#ifdef H5-->
|
||||
<div :id="'rtf'+uid"></div>
|
||||
<!--#endif-->
|
||||
<!--#ifndef H5-->
|
||||
<trees :nodes="nodes" :lazy-load="lazyLoad" :loadVideo="loadVideo" />
|
||||
<image v-for="(item, index) in imgs" v-bind:key="index" :id="index" :src="item" hidden @load="_load" />
|
||||
<!--#endif-->
|
||||
<image v-for="(item, index) in imgs" v-bind:key="index" :id="index" :src="item" hidden @load="_load" />
|
||||
</view>
|
||||
<!--#endif-->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// #ifndef H5 || APP-PLUS-NVUE
|
||||
import trees from './libs/trees';
|
||||
var cache = {},
|
||||
// #ifdef MP-WEIXIN || MP-TOUTIAO
|
||||
fs = uni.getFileSystemManager ? uni.getFileSystemManager() : null,
|
||||
// #endif
|
||||
Parser = require('./libs/MpHtmlParser.js');
|
||||
var document; // document 补丁包 https://jin-yufeng.github.io/Parser/#/instructions?id=document
|
||||
// 计算 cache 的 key
|
||||
function hash(str) {
|
||||
for (var i = str.length, val = 5381; i--;)
|
||||
val += (val << 5) + str.charCodeAt(i);
|
||||
return val;
|
||||
}
|
||||
// #endif
|
||||
// #ifdef H5 || APP-PLUS-NVUE
|
||||
var rpx = uni.getSystemInfoSync().screenWidth / 750,
|
||||
cfg = require('./libs/config.js');
|
||||
// #endif
|
||||
// #ifdef APP-PLUS-NVUE
|
||||
var dom = weex.requireModule('dom');
|
||||
// #endif
|
||||
export default {
|
||||
name: 'parser',
|
||||
data() {
|
||||
return {
|
||||
// #ifdef APP-PLUS
|
||||
loadVideo: false,
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
uid: this._uid,
|
||||
// #endif
|
||||
// #ifdef APP-PLUS-NVUE
|
||||
src: '',
|
||||
height: 1,
|
||||
// #endif
|
||||
// #ifndef APP-PLUS-NVUE
|
||||
scaleAm: '',
|
||||
showAm: '',
|
||||
imgs: [],
|
||||
// #endif
|
||||
nodes: []
|
||||
}
|
||||
},
|
||||
// #ifndef H5 || APP-PLUS-NVUE
|
||||
components: {
|
||||
trees
|
||||
},
|
||||
// #endif
|
||||
props: {
|
||||
'html': null,
|
||||
// #ifndef MP-ALIPAY
|
||||
'autopause': {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// #endif
|
||||
'autosetTitle': {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// #ifndef H5 || APP-PLUS-NVUE
|
||||
'compress': Number,
|
||||
'useCache': Boolean,
|
||||
'xml': Boolean,
|
||||
// #endif
|
||||
'domain': String,
|
||||
// #ifndef MP-BAIDU || MP-ALIPAY || APP-PLUS
|
||||
'gestureZoom': Boolean,
|
||||
// #endif
|
||||
// #ifdef MP-WEIXIN || MP-QQ || H5 || APP-PLUS
|
||||
'lazyLoad': Boolean,
|
||||
// #endif
|
||||
'selectable': Boolean,
|
||||
'tagStyle': Object,
|
||||
'showWithAnimation': Boolean,
|
||||
'useAnchor': Boolean
|
||||
},
|
||||
watch: {
|
||||
html(html) {
|
||||
this.setContent(html);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// 图片数组
|
||||
this.imgList = [];
|
||||
this.imgList.each = function(f) {
|
||||
for (var i = 0, len = this.length; i < len; i++)
|
||||
this.setItem(i, f(this[i], i, this));
|
||||
}
|
||||
this.imgList.setItem = function(i, src) {
|
||||
if (i == void 0 || !src) return;
|
||||
// #ifndef MP-ALIPAY || APP-PLUS
|
||||
// 去重
|
||||
if (src.indexOf('http') == 0 && this.includes(src)) {
|
||||
var newSrc = '';
|
||||
for (var j = 0, c; c = src[j]; j++) {
|
||||
if (c == '/' && src[j - 1] != '/' && src[j + 1] != '/') break;
|
||||
newSrc += Math.random() > 0.5 ? c.toUpperCase() : c;
|
||||
}
|
||||
newSrc += src.substr(j);
|
||||
return this[i] = newSrc;
|
||||
}
|
||||
// #endif
|
||||
this[i] = src;
|
||||
// 暂存 data src
|
||||
if (src.includes('data:image')) {
|
||||
var filePath, info = src.match(/data:image\/(\S+?);(\S+?),(.+)/);
|
||||
if (!info) return;
|
||||
// #ifdef MP-WEIXIN || MP-TOUTIAO
|
||||
filePath = `${wx.env.USER_DATA_PATH}/${Date.now()}.${info[1]}`;
|
||||
fs && fs.writeFile({
|
||||
filePath,
|
||||
data: info[3],
|
||||
encoding: info[2],
|
||||
success: () => this[i] = filePath
|
||||
})
|
||||
// #endif
|
||||
// #ifdef APP-PLUS
|
||||
filePath = `_doc/parser_tmp/${Date.now()}.${info[1]}`;
|
||||
var bitmap = new plus.nativeObj.Bitmap();
|
||||
bitmap.loadBase64Data(src, () => {
|
||||
bitmap.save(filePath, {}, () => {
|
||||
bitmap.clear()
|
||||
this[i] = filePath;
|
||||
})
|
||||
})
|
||||
// #endif
|
||||
}
|
||||
}
|
||||
if (this.html) this.setContent(this.html);
|
||||
},
|
||||
beforeDestroy() {
|
||||
// #ifdef H5
|
||||
if (this._observer) this._observer.disconnect();
|
||||
// #endif
|
||||
this.imgList.each(src => {
|
||||
// #ifdef APP-PLUS
|
||||
if (src && src.includes('_doc')) {
|
||||
plus.io.resolveLocalFileSystemURL(src, entry => {
|
||||
entry.remove();
|
||||
});
|
||||
}
|
||||
// #endif
|
||||
// #ifdef MP-WEIXIN || MP-TOUTIAO
|
||||
if (src && src.includes(uni.env.USER_DATA_PATH))
|
||||
fs && fs.unlink({
|
||||
filePath: src
|
||||
})
|
||||
// #endif
|
||||
})
|
||||
clearInterval(this._timer);
|
||||
},
|
||||
methods: {
|
||||
// #ifdef H5 || APP-PLUS-NVUE
|
||||
_Dom2Str(nodes) {
|
||||
var str = '';
|
||||
for (var node of nodes) {
|
||||
if (node.type == 'text')
|
||||
str += node.text;
|
||||
else {
|
||||
str += ('<' + node.name);
|
||||
for (var attr in node.attrs || {})
|
||||
str += (' ' + attr + '="' + node.attrs[attr] + '"');
|
||||
if (!node.children || !node.children.length) str += '>';
|
||||
else str += ('>' + this._Dom2Str(node.children) + '</' + node.name + '>');
|
||||
}
|
||||
}
|
||||
return str;
|
||||
},
|
||||
_handleHtml(html, append) {
|
||||
if (typeof html != 'string') html = this._Dom2Str(html.nodes || html);
|
||||
// 处理 rpx
|
||||
if (html.includes('rpx'))
|
||||
html = html.replace(/[0-9.]+\s*rpx/g, $ => parseFloat($) * rpx + 'px');
|
||||
if (!append) {
|
||||
// 处理 tag-style 和 userAgentStyles
|
||||
var style = '<style>@keyframes show{0%{opacity:0}100%{opacity:1}}';
|
||||
for (var item in cfg.userAgentStyles)
|
||||
style += `${item}{${cfg.userAgentStyles[item]}}`;
|
||||
for (item in this.tagStyle)
|
||||
style += `${item}{${this.tagStyle[item]}}`;
|
||||
style += '</style>';
|
||||
html = style + html;
|
||||
}
|
||||
return html;
|
||||
},
|
||||
// #endif
|
||||
setContent(html, append) {
|
||||
// #ifdef APP-PLUS-NVUE
|
||||
if (!html) {
|
||||
this.src = '';
|
||||
this.height = 1;
|
||||
return;
|
||||
}
|
||||
if (append) return;
|
||||
plus.io.resolveLocalFileSystemURL('_doc', entry => {
|
||||
entry.getDirectory('parser_tmp', {
|
||||
create: true
|
||||
}, entry => {
|
||||
var fileName = Date.now() + '.html';
|
||||
entry.getFile(fileName, {
|
||||
create: true
|
||||
}, entry => {
|
||||
entry.createWriter(writer => {
|
||||
writer.onwriteend = () => {
|
||||
this.nodes = [1];
|
||||
this.src = '_doc/parser_tmp/' + fileName;
|
||||
this.$nextTick(function() {
|
||||
entry.remove();
|
||||
})
|
||||
}
|
||||
html =
|
||||
'<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1' +
|
||||
(this.selectable ? '' : ',user-scalable=no') +
|
||||
'"><script type="text/javascript" src="https://js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.1.5.2.js"></' +
|
||||
'script><base href="' + this.domain + '">' + this._handleHtml(html) +
|
||||
'<script>"use strict";function post(t){uni.postMessage({data:t})}' +
|
||||
(this.showWithAnimation ? 'document.body.style.animation="show .5s",' : '') +
|
||||
'document.addEventListener("UniAppJSBridgeReady",function(){post({action:"load",text:document.body.innerText});var t=document.getElementsByTagName("title");t.length&&post({action:"getTitle",title:t[0].innerText});for(var e,o=document.getElementsByTagName("img"),n=[],i=0,r=0;e=o[i];i++)e.onerror=function(){post({action:"error",source:"img",target:this})},e.hasAttribute("ignore")||"A"==e.parentElement.nodeName||(e.i=r++,n.push(e.src),e.onclick=function(){post({action:"preview",img:{i:this.i,src:this.src}})});post({action:"getImgList",imgList:n});for(var a,s=document.getElementsByTagName("a"),c=0;a=s[c];c++)a.onclick=function(){var t,e=this.getAttribute("href");if("#"==e[0]){var r=document.getElementById(e.substr(1));r&&(t=r.offsetTop)}return post({action:"linkpress",href:e,offset:t}),!1};;for(var u,m=document.getElementsByTagName("video"),d=0;u=m[d];d++)u.style.maxWidth="100%;",u.onerror=function(){post({action:"error",source:"video",target:this})}' +
|
||||
(this.autopause ? ',u.onplay=function(){for(var t,e=0;t=m[e];e++)t!=this&&t.pause()}' : '') +
|
||||
';for(var g,l=document.getElementsByTagName("audio"),p=0;g=l[p];p++)g.onerror=function(){post({action:"error",source:"audio",target:this})};window.onload=function(){post({action:"ready",height:document.body.scrollHeight})}});</' +
|
||||
'script>';
|
||||
writer.write(html);
|
||||
});
|
||||
})
|
||||
})
|
||||
})
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
if (!html) {
|
||||
if (this.rtf && !append) this.rtf.parentNode.removeChild(this.rtf);
|
||||
return;
|
||||
}
|
||||
var div = document.createElement('div');
|
||||
if (!append) {
|
||||
if (this.rtf) this.rtf.parentNode.removeChild(this.rtf);
|
||||
this.rtf = div;
|
||||
} else {
|
||||
if (!this.rtf) this.rtf = div;
|
||||
else this.rtf.appendChild(div);
|
||||
}
|
||||
div.innerHTML = this._handleHtml(html, append);
|
||||
for (var styles = this.rtf.getElementsByTagName('style'), i = 0, style; style = styles[i++];) {
|
||||
style.innerHTML = style.innerHTML.replace(/body/g, '#rtf' + this._uid);
|
||||
style.setAttribute('scoped', 'true');
|
||||
}
|
||||
// 懒加载
|
||||
if (!this._observer && this.lazyLoad && IntersectionObserver) {
|
||||
this._observer = new IntersectionObserver(changes => {
|
||||
for (let item, i = 0; item = changes[i++];) {
|
||||
if (item.isIntersecting) {
|
||||
item.target.src = item.target.getAttribute('data-src');
|
||||
item.target.removeAttribute('data-src');
|
||||
this._observer.unobserve(item.target);
|
||||
}
|
||||
}
|
||||
}, {
|
||||
rootMargin: '900px 0px 900px 0px'
|
||||
})
|
||||
}
|
||||
var _ts = this;
|
||||
// 获取标题
|
||||
var title = this.rtf.getElementsByTagName('title');
|
||||
if (title.length && this.autosetTitle)
|
||||
uni.setNavigationBarTitle({
|
||||
title: title[0].innerText
|
||||
})
|
||||
// 图片处理
|
||||
this.imgList.length = 0;
|
||||
var imgs = this.rtf.getElementsByTagName('img');
|
||||
for (let i = 0, j = 0, img; img = imgs[i]; i++) {
|
||||
img.style.maxWidth = '100%';
|
||||
var src = img.getAttribute('src');
|
||||
if (this.domain && src) {
|
||||
if (src[0] == '/') {
|
||||
if (src[1] == '/')
|
||||
img.src = (this.domain.includes('://') ? this.domain.split('://')[0] : '') + ':' + src;
|
||||
else img.src = this.domain + src;
|
||||
} else if (!src.includes('://')) img.src = this.domain + '/' + src;
|
||||
}
|
||||
if (!img.hasAttribute('ignore') && img.parentElement.nodeName != 'A') {
|
||||
img.i = j++;
|
||||
_ts.imgList.push(img.src || img.getAttribute('data-src'));
|
||||
img.onclick = function() {
|
||||
var preview = true;
|
||||
this.ignore = () => preview = false;
|
||||
_ts.$emit('imgtap', this);
|
||||
if (preview) {
|
||||
uni.previewImage({
|
||||
current: this.i,
|
||||
urls: _ts.imgList
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
img.onerror = function() {
|
||||
_ts.$emit('error', {
|
||||
source: 'img',
|
||||
target: this
|
||||
});
|
||||
}
|
||||
if (_ts.lazyLoad && this._observer && img.src && img.i != 0) {
|
||||
img.setAttribute('data-src', img.src);
|
||||
img.removeAttribute('src');
|
||||
this._observer.observe(img);
|
||||
}
|
||||
}
|
||||
// 链接处理
|
||||
var links = this.rtf.getElementsByTagName('a');
|
||||
for (var link of links) {
|
||||
link.onclick = function() {
|
||||
var jump = true,
|
||||
href = this.getAttribute('href');
|
||||
_ts.$emit('linkpress', {
|
||||
href,
|
||||
ignore: () => jump = false
|
||||
});
|
||||
if (jump && href) {
|
||||
if (href[0] == '#') {
|
||||
if (_ts.useAnchor) {
|
||||
_ts.navigateTo({
|
||||
id: href.substr(1)
|
||||
})
|
||||
}
|
||||
} else if (href.indexOf('http') == 0 || href.indexOf('//') == 0)
|
||||
return true;
|
||||
else {
|
||||
uni.navigateTo({
|
||||
url: href
|
||||
})
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// 视频处理
|
||||
var videos = this.rtf.getElementsByTagName('video');
|
||||
_ts.videoContexts = videos;
|
||||
for (let video, i = 0; video = videos[i++];) {
|
||||
video.style.maxWidth = '100%';
|
||||
video.onerror = function() {
|
||||
_ts.$emit('error', {
|
||||
source: 'video',
|
||||
target: this
|
||||
});
|
||||
}
|
||||
video.onplay = function() {
|
||||
if (_ts.autopause)
|
||||
for (let item, i = 0; item = _ts.videoContexts[i++];)
|
||||
if (item != this) item.pause();
|
||||
}
|
||||
}
|
||||
// 音频处理
|
||||
var audios = this.rtf.getElementsByTagName('audios');
|
||||
for (var audio of audios)
|
||||
audio.onerror = function() {
|
||||
_ts.$emit('error', {
|
||||
source: 'audio',
|
||||
target: this
|
||||
});
|
||||
}
|
||||
this.document = this.rtf;
|
||||
if (!append) document.getElementById('rtf' + this._uid).appendChild(this.rtf);
|
||||
this.$nextTick(() => {
|
||||
this.nodes = [1];
|
||||
this.$emit('load');
|
||||
})
|
||||
setTimeout(() => this.showAm = '', 500);
|
||||
// #endif
|
||||
// #ifndef H5 || APP-PLUS-NVUE
|
||||
var nodes;
|
||||
if (!html)
|
||||
return this.nodes = [];
|
||||
else if (typeof html == 'string') {
|
||||
let parser = new Parser(html, this);
|
||||
// 缓存读取
|
||||
if (this.useCache) {
|
||||
var hashVal = hash(html);
|
||||
if (cache[hashVal])
|
||||
nodes = cache[hashVal];
|
||||
else {
|
||||
nodes = parser.parse();
|
||||
cache[hashVal] = nodes;
|
||||
}
|
||||
} else nodes = parser.parse();
|
||||
this.$emit('parse', nodes);
|
||||
} else if (Object.prototype.toString.call(html) == '[object Array]') {
|
||||
// 非本插件产生的 array 需要进行一些转换
|
||||
if (html.length && html[0].PoweredBy != 'Parser') {
|
||||
let parser = new Parser(html, this);
|
||||
(function f(ns) {
|
||||
for (var i = 0, n; n = ns[i]; i++) {
|
||||
if (n.type == 'text') continue;
|
||||
n.attrs = n.attrs || {};
|
||||
for (var item in n.attrs)
|
||||
if (typeof n.attrs[item] != 'string') n.attrs[item] = n.attrs[item].toString();
|
||||
parser.matchAttr(n, parser);
|
||||
if (n.children && n.children.length) {
|
||||
parser.STACK.push(n);
|
||||
f(n.children);
|
||||
parser.popNode(parser.STACK.pop());
|
||||
} else n.children = void 0;
|
||||
}
|
||||
})(html);
|
||||
}
|
||||
nodes = html;
|
||||
} else if (typeof html == 'object' && html.nodes) {
|
||||
nodes = html.nodes;
|
||||
console.warn('错误的 html 类型:object 类型已废弃');
|
||||
} else
|
||||
return console.warn('错误的 html 类型:' + typeof html);
|
||||
// #ifdef APP-PLUS
|
||||
this.loadVideo = false;
|
||||
// #endif
|
||||
if (document) this.document = new document(this.nodes, 'nodes', this);
|
||||
if (append) this.nodes = this.nodes.concat(nodes);
|
||||
else this.nodes = nodes;
|
||||
if (nodes.length && nodes[0].title && this.autosetTitle)
|
||||
uni.setNavigationBarTitle({
|
||||
title: nodes[0].title
|
||||
})
|
||||
this.$nextTick(() => {
|
||||
this.imgList.length = 0;
|
||||
this.videoContexts = [];
|
||||
// #ifdef MP-TOUTIAO
|
||||
setTimeout(() => {
|
||||
// #endif
|
||||
var f = (cs) => {
|
||||
for (let i = 0, c; c = cs[i++];) {
|
||||
if (c.$options.name == 'trees') {
|
||||
for (var j = c.nodes.length, item; item = c.nodes[--j];) {
|
||||
if (item.c) continue;
|
||||
if (item.name == 'img') {
|
||||
this.imgList.setItem(item.attrs.i, item.attrs.src);
|
||||
// #ifndef MP-ALIPAY
|
||||
if (!c.observer && !c.imgLoad && item.attrs.i != '0') {
|
||||
if (this.lazyLoad && uni.createIntersectionObserver) {
|
||||
c.observer = uni.createIntersectionObserver(c);
|
||||
c.observer.relativeToViewport({
|
||||
top: 900,
|
||||
bottom: 900
|
||||
}).observe('._img', () => {
|
||||
c.imgLoad = true;
|
||||
c.observer.disconnect();
|
||||
})
|
||||
} else
|
||||
c.imgLoad = true;
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
// #ifndef MP-ALIPAY
|
||||
else if (item.name == 'video') {
|
||||
var ctx = uni.createVideoContext(item.attrs.id, c);
|
||||
ctx.id = item.attrs.id;
|
||||
this.videoContexts.push(ctx);
|
||||
}
|
||||
// #endif
|
||||
// #ifdef MP-BAIDU || MP-ALIPAY || APP-PLUS
|
||||
if (item.attrs && item.attrs.id) {
|
||||
this.anchors = this.anchors || [];
|
||||
this.anchors.push({
|
||||
id: item.attrs.id,
|
||||
node: c
|
||||
})
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
}
|
||||
if (c.$children.length)
|
||||
f(c.$children)
|
||||
}
|
||||
}
|
||||
f(this.$children);
|
||||
// #ifdef MP-TOUTIAO
|
||||
}, 200)
|
||||
this.$emit('load');
|
||||
// #endif
|
||||
// #ifdef APP-PLUS
|
||||
setTimeout(() => {
|
||||
this.loadVideo = true;
|
||||
}, 3000);
|
||||
// #endif
|
||||
})
|
||||
// #endif
|
||||
// #ifndef APP-PLUS-NVUE
|
||||
var height;
|
||||
clearInterval(this._timer);
|
||||
this._timer = setInterval(() => {
|
||||
// #ifdef H5
|
||||
var res = [this.rtf.getBoundingClientRect()];
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
// #ifdef APP-PLUS
|
||||
uni.createSelectorQuery().in(this)
|
||||
// #endif
|
||||
// #ifndef APP-PLUS
|
||||
this.createSelectorQuery()
|
||||
// #endif
|
||||
.select('#top').boundingClientRect().exec(res => {
|
||||
// #endif
|
||||
this.width = res[0].width;
|
||||
if (res[0].height == height) {
|
||||
this.$emit('ready', res[0])
|
||||
clearInterval(this._timer);
|
||||
}
|
||||
height = res[0].height;
|
||||
// #ifndef H5
|
||||
});
|
||||
// #endif
|
||||
}, 350)
|
||||
if (this.showWithAnimation && !append) this.showAm = 'animation:show .5s';
|
||||
// #endif
|
||||
},
|
||||
getText(ns = this.nodes) {
|
||||
// #ifdef APP-PLUS-NVUE
|
||||
return this._text;
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
return this.rtf.innerText;
|
||||
// #endif
|
||||
// #ifndef H5 || APP-PLUS-NVUE
|
||||
var txt = '';
|
||||
for (var i = 0, n; n = ns[i++];) {
|
||||
if (n.type == 'text') txt += n.text.replace(/ /g, '\u00A0').replace(/</g, '<').replace(/>/g, '>')
|
||||
.replace(/&/g, '&');
|
||||
else if (n.type == 'br') txt += '\n';
|
||||
else {
|
||||
// 块级标签前后加换行
|
||||
var block = n.name == 'p' || n.name == 'div' || n.name == 'tr' || n.name == 'li' || (n.name[0] == 'h' && n.name[1] >
|
||||
'0' && n.name[1] < '7');
|
||||
if (block && txt && txt[txt.length - 1] != '\n') txt += '\n';
|
||||
if (n.children) txt += this.getText(n.children);
|
||||
if (block && txt[txt.length - 1] != '\n') txt += '\n';
|
||||
else if (n.name == 'td' || n.name == 'th') txt += '\t';
|
||||
}
|
||||
}
|
||||
return txt;
|
||||
// #endif
|
||||
},
|
||||
navigateTo(obj) {
|
||||
if (!this.useAnchor)
|
||||
return obj.fail && obj.fail({
|
||||
errMsg: 'Anchor is disabled'
|
||||
})
|
||||
// #ifdef APP-PLUS-NVUE
|
||||
if (!obj.id)
|
||||
dom.scrollToElement(this.$refs.web);
|
||||
else
|
||||
this.$refs.web.evalJs('var pos=document.getElementById("' + obj.id +
|
||||
'");if(pos)post({action:"linkpress",href:"#",offset:pos.offsetTop})');
|
||||
return obj.success && obj.success({
|
||||
errMsg: 'pageScrollTo:ok'
|
||||
});
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
if (!obj.id) {
|
||||
window.scrollTo(0, this.rtf.offsetTop);
|
||||
return obj.success && obj.success({
|
||||
errMsg: 'pageScrollTo:ok'
|
||||
});
|
||||
}
|
||||
var target = document.getElementById(obj.id);
|
||||
if (!target) return obj.fail && obj.fail({
|
||||
errMsg: 'Label not found'
|
||||
});
|
||||
obj.scrollTop = this.rtf.offsetTop + target.offsetTop;
|
||||
uni.pageScrollTo(obj);
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
var Scroll = (selector, component) => {
|
||||
uni.createSelectorQuery().in(component ? component : this).select(selector).boundingClientRect().selectViewport()
|
||||
.scrollOffset()
|
||||
.exec(res => {
|
||||
if (!res || !res[0])
|
||||
return obj.fail && obj.fail({
|
||||
errMsg: 'Label not found'
|
||||
});
|
||||
obj.scrollTop = res[1].scrollTop + res[0].top;
|
||||
uni.pageScrollTo(obj);
|
||||
})
|
||||
}
|
||||
if (!obj.id) Scroll('#top');
|
||||
else {
|
||||
// #ifndef MP-BAIDU || MP-ALIPAY || APP-PLUS
|
||||
Scroll('#top >>> #' + obj.id + ', #top >>> .' + obj.id);
|
||||
// #endif
|
||||
// #ifdef MP-BAIDU || MP-ALIPAY || APP-PLUS
|
||||
for (var anchor of this.anchors)
|
||||
if (anchor.id == obj.id)
|
||||
Scroll('#' + obj.id + ', .' + obj.id, anchor.node);
|
||||
// #endif
|
||||
}
|
||||
// #endif
|
||||
},
|
||||
getVideoContext(id) {
|
||||
// #ifndef APP-PLUS-NVUE
|
||||
if (!id) return this.videoContexts;
|
||||
else
|
||||
for (var i = this.videoContexts.length; i--;)
|
||||
if (this.videoContexts[i].id == id) return this.videoContexts[i];
|
||||
// #endif
|
||||
},
|
||||
// 预加载
|
||||
preLoad(html, num) {
|
||||
// #ifdef H5 || APP-PLUS-NVUE
|
||||
if (html.constructor == Array)
|
||||
html = this._Dom2Str(html);
|
||||
var script = "var contain=document.createElement('div');contain.innerHTML='" + html.replace(/'/g, "\\'") +
|
||||
"';for(var imgs=contain.querySelectorAll('img'),i=imgs.length-1;i>=" + num +
|
||||
";i--)imgs[i].removeAttribute('src');";
|
||||
// #endif
|
||||
// #ifdef APP-PLUS-NVUE
|
||||
this.$refs.web.evalJs(script);
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
eval(script);
|
||||
// #endif
|
||||
// #ifndef H5 || APP-PLUS-NVUE
|
||||
if (typeof html == 'string') {
|
||||
var id = hash(html);
|
||||
html = new Parser(html, this).parse();
|
||||
cache[id] = html;
|
||||
}
|
||||
var wait = [];
|
||||
(function f(ns) {
|
||||
for (var i = 0, n; n = ns[i++];) {
|
||||
if (n.name == 'img' && n.attrs.src && !wait.includes(n.attrs.src))
|
||||
wait.push(n.attrs.src);
|
||||
f(n.children || []);
|
||||
}
|
||||
})(html);
|
||||
if (num) wait = wait.slice(0, num);
|
||||
this._wait = (this._wait || []).concat(wait);
|
||||
if (!this.imgs) this.imgs = this._wait.splice(0, 15);
|
||||
else if (this.imgs.length < 15)
|
||||
this.imgs = this.imgs.concat(this._wait.splice(0, 15 - this.imgs.length));
|
||||
// #endif
|
||||
},
|
||||
// #ifdef APP-PLUS-NVUE
|
||||
_message(e) {
|
||||
// 接收 web-view 消息
|
||||
var data = e.detail.data[0];
|
||||
if (data.action == 'load') {
|
||||
this.$emit('load');
|
||||
this._text = data.text;
|
||||
} else if (data.action == 'getTitle') {
|
||||
if (this.autosetTitle)
|
||||
uni.setNavigationBarTitle({
|
||||
title: data.title
|
||||
})
|
||||
} else if (data.action == 'getImgList') {
|
||||
this.imgList.length = 0;
|
||||
for (var i = data.imgList.length; i--;)
|
||||
this.imgList.setItem(i, data.imgList[i]);
|
||||
} else if (data.action == 'preview') {
|
||||
var preview = true;
|
||||
data.img.ignore = () => preview = false;
|
||||
this.$emit('imgtap', data.img);
|
||||
if (preview)
|
||||
uni.previewImage({
|
||||
current: data.img.i,
|
||||
urls: this.imgList
|
||||
})
|
||||
} else if (data.action == 'linkpress') {
|
||||
var jump = true,
|
||||
href = data.href;
|
||||
this.$emit('linkpress', {
|
||||
href,
|
||||
ignore: () => jump = false
|
||||
})
|
||||
if (jump && href) {
|
||||
if (href[0] == '#') {
|
||||
if (this.useAnchor)
|
||||
dom.scrollToElement(this.$refs.web, {
|
||||
offset: data.offset
|
||||
})
|
||||
} else if (href.includes('://'))
|
||||
plus.runtime.openWeb(href);
|
||||
else
|
||||
uni.navigateTo({
|
||||
url: href
|
||||
})
|
||||
}
|
||||
} else if (data.action == 'error')
|
||||
this.$emit('error', {
|
||||
source: data.source,
|
||||
target: data.target
|
||||
})
|
||||
else if (data.action == 'ready') {
|
||||
this.height = data.height;
|
||||
this.$nextTick(() => {
|
||||
uni.createSelectorQuery().in(this).select('#top').boundingClientRect().exec(res => {
|
||||
this.rect = res[0];
|
||||
this.$emit('ready', res[0]);
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
// #endif
|
||||
// #ifndef APP-PLUS-NVUE
|
||||
// #ifndef H5
|
||||
_load(e) {
|
||||
if (this._wait.length)
|
||||
this.$set(this.imgs, e.target.id, this._wait.shift());
|
||||
},
|
||||
// #endif
|
||||
_tap(e) {
|
||||
// #ifndef MP-BAIDU || MP-ALIPAY || APP-PLUS
|
||||
if (this.gestureZoom && e.timeStamp - this._lastT < 300) {
|
||||
var initY = e.touches[0].pageY - e.currentTarget.offsetTop;
|
||||
if (this._zoom) {
|
||||
this._scaleAm.translateX(0).scale(1).step();
|
||||
uni.pageScrollTo({
|
||||
scrollTop: (initY + this._initY) / 2 - e.touches[0].clientY,
|
||||
duration: 400
|
||||
})
|
||||
} else {
|
||||
var initX = e.touches[0].pageX - e.currentTarget.offsetLeft;
|
||||
this._initY = initY;
|
||||
this._scaleAm = uni.createAnimation({
|
||||
transformOrigin: `${initX}px ${this._initY}px 0`,
|
||||
timingFunction: 'ease-in-out'
|
||||
});
|
||||
// #ifdef MP-TOUTIAO
|
||||
this._scaleAm.opacity(1);
|
||||
// #endif
|
||||
this._scaleAm.scale(2).step();
|
||||
this._tMax = initX / 2;
|
||||
this._tMin = (initX - this.width) / 2;
|
||||
this._tX = 0;
|
||||
}
|
||||
this._zoom = !this._zoom;
|
||||
this.scaleAm = this._scaleAm.export();
|
||||
}
|
||||
this._lastT = e.timeStamp;
|
||||
// #endif
|
||||
},
|
||||
_touchstart(e) {
|
||||
// #ifndef MP-BAIDU || MP-ALIPAY || APP-PLUS
|
||||
if (e.touches.length == 1)
|
||||
this._initX = this._lastX = e.touches[0].pageX;
|
||||
// #endif
|
||||
},
|
||||
_touchmove(e) {
|
||||
// #ifndef MP-BAIDU || MP-ALIPAY || APP-PLUS
|
||||
var diff = e.touches[0].pageX - this._lastX;
|
||||
if (this._zoom && e.touches.length == 1 && Math.abs(diff) > 20) {
|
||||
this._lastX = e.touches[0].pageX;
|
||||
if ((this._tX <= this._tMin && diff < 0) || (this._tX >= this._tMax && diff > 0))
|
||||
return;
|
||||
this._tX += (diff * Math.abs(this._lastX - this._initX) * 0.05);
|
||||
if (this._tX < this._tMin) this._tX = this._tMin;
|
||||
if (this._tX > this._tMax) this._tX = this._tMax;
|
||||
this._scaleAm.translateX(this._tX).step();
|
||||
this.scaleAm = this._scaleAm.export();
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@keyframes show {
|
||||
0% {
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* #ifdef MP-WEIXIN */
|
||||
:host {
|
||||
display: block;
|
||||
overflow: scroll;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
</style>
|
|
@ -0,0 +1,111 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
/*
|
||||
解析和匹配 Css 的选择器
|
||||
github:https://github.com/jin-yufeng/Parser
|
||||
docs:https://jin-yufeng.github.io/Parser
|
||||
author:JinYufeng
|
||||
update:2020/03/15
|
||||
*/
|
||||
var cfg = require('./config.js');
|
||||
class CssHandler {
|
||||
constructor(tagStyle) {
|
||||
var styles = Object.assign({}, cfg.userAgentStyles);
|
||||
for (var item in tagStyle)
|
||||
styles[item] = (styles[item] ? styles[item] + ';' : '') + tagStyle[item];
|
||||
this.styles = styles;
|
||||
}
|
||||
getStyle = data => this.styles = new CssParser(data, this.styles).parse();
|
||||
match(name, attrs) {
|
||||
var tmp, matched = (tmp = this.styles[name]) ? tmp + ';' : '';
|
||||
if (attrs.class) {
|
||||
var items = attrs.class.split(' ');
|
||||
for (var i = 0, item; item = items[i]; i++)
|
||||
if (tmp = this.styles['.' + item])
|
||||
matched += tmp + ';';
|
||||
}
|
||||
if (tmp = this.styles['#' + attrs.id])
|
||||
matched += tmp + ';';
|
||||
return matched;
|
||||
}
|
||||
}
|
||||
module.exports = CssHandler;
|
||||
class CssParser {
|
||||
constructor(data, init) {
|
||||
this.data = data;
|
||||
this.floor = 0;
|
||||
this.i = 0;
|
||||
this.list = [];
|
||||
this.res = init;
|
||||
this.state = this.Space;
|
||||
}
|
||||
parse() {
|
||||
for (var c; c = this.data[this.i]; this.i++)
|
||||
this.state(c);
|
||||
return this.res;
|
||||
}
|
||||
section = () => this.data.substring(this.start, this.i);
|
||||
isLetter = c => (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
||||
// 状态机
|
||||
Space(c) {
|
||||
if (c == '.' || c == '#' || this.isLetter(c)) {
|
||||
this.start = this.i;
|
||||
this.state = this.Name;
|
||||
} else if (c == '/' && this.data[this.i + 1] == '*')
|
||||
this.Comment();
|
||||
else if (!cfg.blankChar[c] && c != ';')
|
||||
this.state = this.Ignore;
|
||||
}
|
||||
Comment() {
|
||||
this.i = this.data.indexOf('*/', this.i) + 1;
|
||||
if (!this.i) this.i = this.data.length;
|
||||
this.state = this.Space;
|
||||
}
|
||||
Ignore(c) {
|
||||
if (c == '{') this.floor++;
|
||||
else if (c == '}' && !--this.floor) this.state = this.Space;
|
||||
}
|
||||
Name(c) {
|
||||
if (cfg.blankChar[c]) {
|
||||
this.list.push(this.section());
|
||||
this.state = this.NameSpace;
|
||||
} else if (c == '{') {
|
||||
this.list.push(this.section());
|
||||
this.Content();
|
||||
} else if (c == ',') {
|
||||
this.list.push(this.section());
|
||||
this.Comma();
|
||||
} else if (!this.isLetter(c) && (c < '0' || c > '9') && c != '-' && c != '_')
|
||||
this.state = this.Ignore;
|
||||
}
|
||||
NameSpace(c) {
|
||||
if (c == '{') this.Content();
|
||||
else if (c == ',') this.Comma();
|
||||
else if (!cfg.blankChar[c]) this.state = this.Ignore;
|
||||
}
|
||||
Comma() {
|
||||
while (cfg.blankChar[this.data[++this.i]]);
|
||||
if (this.data[this.i] == '{') this.Content();
|
||||
else {
|
||||
this.start = this.i--;
|
||||
this.state = this.Name;
|
||||
}
|
||||
}
|
||||
Content() {
|
||||
this.start = ++this.i;
|
||||
if ((this.i = this.data.indexOf('}', this.i)) == -1) this.i = this.data.length;
|
||||
var content = this.section();
|
||||
for (var i = 0, item; item = this.list[i++];)
|
||||
if (this.res[item]) this.res[item] += ';' + content;
|
||||
else this.res[item] = content;
|
||||
this.list = [];
|
||||
this.state = this.Space;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,586 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
/*
|
||||
将 html 解析为适用于小程序 rich-text 的 DOM 结构
|
||||
github:https://github.com/jin-yufeng/Parser
|
||||
docs:https://jin-yufeng.github.io/Parser
|
||||
author:JinYufeng
|
||||
update:2020/04/13
|
||||
*/
|
||||
var cfg = require('./config.js'),
|
||||
blankChar = cfg.blankChar,
|
||||
CssHandler = require('./CssHandler.js'),
|
||||
{
|
||||
screenWidth,
|
||||
system
|
||||
} = wx.getSystemInfoSync();
|
||||
// #ifdef MP-BAIDU || MP-ALIPAY || MP-TOUTIAO
|
||||
var entities = {
|
||||
lt: '<',
|
||||
gt: '>',
|
||||
amp: '&',
|
||||
quot: '"',
|
||||
apos: "'",
|
||||
nbsp: '\xA0',
|
||||
ensp: '\u2002',
|
||||
emsp: '\u2003',
|
||||
ndash: '–',
|
||||
mdash: '—',
|
||||
middot: '·',
|
||||
lsquo: '‘',
|
||||
rsquo: '’',
|
||||
ldquo: '“',
|
||||
rdquo: '”',
|
||||
bull: '•',
|
||||
hellip: '…',
|
||||
permil: '‰',
|
||||
copy: '©',
|
||||
reg: '®',
|
||||
trade: '™',
|
||||
times: '×',
|
||||
divide: '÷',
|
||||
cent: '¢',
|
||||
pound: '£',
|
||||
yen: '¥',
|
||||
euro: '€',
|
||||
sect: '§'
|
||||
};
|
||||
// #endif
|
||||
var emoji; // emoji 补丁包 https://jin-yufeng.github.io/Parser/#/instructions?id=emoji
|
||||
class MpHtmlParser {
|
||||
constructor(data, options = {}) {
|
||||
this.attrs = {};
|
||||
this.compress = options.compress;
|
||||
this.CssHandler = new CssHandler(options.tagStyle, screenWidth);
|
||||
this.data = data;
|
||||
this.domain = options.domain;
|
||||
this.DOM = [];
|
||||
this.i = this.start = this.audioNum = this.imgNum = this.videoNum = 0;
|
||||
this.protocol = this.domain && this.domain.includes('://') ? this.domain.split('://')[0] : '';
|
||||
this.state = this.Text;
|
||||
this.STACK = [];
|
||||
this.useAnchor = options.useAnchor;
|
||||
this.xml = options.xml;
|
||||
}
|
||||
parse() {
|
||||
if (emoji) this.data = emoji.parseEmoji(this.data);
|
||||
for (var c; c = this.data[this.i]; this.i++)
|
||||
this.state(c);
|
||||
if (this.state == this.Text) this.setText();
|
||||
while (this.STACK.length) this.popNode(this.STACK.pop());
|
||||
// #ifdef MP-BAIDU || MP-TOUTIAO
|
||||
// 将顶层标签的一些样式提取出来给 rich-text
|
||||
(function f(ns) {
|
||||
for (var i = ns.length, n; n = ns[--i];) {
|
||||
if (n.type == 'text') continue;
|
||||
if (!n.c) {
|
||||
var style = n.attrs.style;
|
||||
if (style) {
|
||||
var j, k, res;
|
||||
if ((j = style.indexOf('display')) != -1)
|
||||
res = style.substring(j, (k = style.indexOf(';', j)) == -1 ? style.length : k);
|
||||
if ((j = style.indexOf('float')) != -1)
|
||||
res += ';' + style.substring(j, (k = style.indexOf(';', j)) == -1 ? style.length : k);
|
||||
n.attrs.contain = res;
|
||||
}
|
||||
} else f(n.children);
|
||||
}
|
||||
})(this.DOM);
|
||||
// #endif
|
||||
if (this.DOM.length) {
|
||||
this.DOM[0].PoweredBy = 'Parser';
|
||||
if (this.title) this.DOM[0].title = this.title;
|
||||
}
|
||||
return this.DOM;
|
||||
}
|
||||
// 设置属性
|
||||
setAttr() {
|
||||
var name = this.getName(this.attrName);
|
||||
if (cfg.trustAttrs[name]) {
|
||||
if (!this.attrVal) {
|
||||
if (cfg.boolAttrs[name]) this.attrs[name] = 'T';
|
||||
} else if (name == 'src') this.attrs[name] = this.getUrl(this.attrVal.replace(/&/g, '&'));
|
||||
else this.attrs[name] = this.attrVal;
|
||||
}
|
||||
this.attrVal = '';
|
||||
while (blankChar[this.data[this.i]]) this.i++;
|
||||
if (this.isClose()) this.setNode();
|
||||
else {
|
||||
this.start = this.i;
|
||||
this.state = this.AttrName;
|
||||
}
|
||||
}
|
||||
// 设置文本节点
|
||||
setText() {
|
||||
var back, text = this.section();
|
||||
if (!text) return;
|
||||
text = (cfg.onText && cfg.onText(text, () => back = true)) || text;
|
||||
if (back) {
|
||||
this.data = this.data.substr(0, this.start) + text + this.data.substr(this.i);
|
||||
let j = this.start + text.length;
|
||||
for (this.i = this.start; this.i < j; this.i++) this.state(this.data[this.i]);
|
||||
return;
|
||||
}
|
||||
if (!this.pre) {
|
||||
// 合并空白符
|
||||
var tmp = [];
|
||||
for (let i = text.length, c; c = text[--i];)
|
||||
if (!blankChar[c] || (!blankChar[tmp[0]] && (c = ' '))) tmp.unshift(c);
|
||||
text = tmp.join('');
|
||||
if (text == ' ') return;
|
||||
}
|
||||
// 处理实体
|
||||
var siblings = this.siblings(),
|
||||
i = -1,
|
||||
j, en;
|
||||
while (1) {
|
||||
if ((i = text.indexOf('&', i + 1)) == -1) break;
|
||||
if ((j = text.indexOf(';', i + 2)) == -1) break;
|
||||
if (text[i + 1] == '#') {
|
||||
en = parseInt((text[i + 2] == 'x' ? '0' : '') + text.substring(i + 2, j));
|
||||
if (!isNaN(en)) text = text.substr(0, i) + String.fromCharCode(en) + text.substring(j + 1);
|
||||
} else {
|
||||
en = text.substring(i + 1, j);
|
||||
// #ifdef MP-WEIXIN || MP-QQ || APP-PLUS
|
||||
if (en == 'nbsp') text = text.substr(0, i) + '\xA0' + text.substr(j + 1); // 解决 失效
|
||||
else if (en != 'lt' && en != 'gt' && en != 'amp' && en != 'ensp' && en != 'emsp' && en != 'quot' && en != 'apos') {
|
||||
i && siblings.push({
|
||||
type: 'text',
|
||||
text: text.substr(0, i)
|
||||
})
|
||||
siblings.push({
|
||||
type: 'text',
|
||||
text: `&${en};`,
|
||||
en: 1
|
||||
})
|
||||
text = text.substr(j + 1);
|
||||
i = -1;
|
||||
}
|
||||
// #endif
|
||||
// #ifdef MP-BAIDU || MP-ALIPAY || MP-TOUTIAO
|
||||
if (entities[en]) text = text.substr(0, i) + entities[en] + text.substr(j + 1);
|
||||
// #endif
|
||||
}
|
||||
}
|
||||
text && siblings.push({
|
||||
type: 'text',
|
||||
text
|
||||
})
|
||||
}
|
||||
// 设置元素节点
|
||||
setNode() {
|
||||
var node = {
|
||||
name: this.tagName.toLowerCase(),
|
||||
attrs: this.attrs
|
||||
},
|
||||
close = cfg.selfClosingTags[node.name] || (this.xml && this.data[this.i] == '/');
|
||||
this.attrs = {};
|
||||
if (!cfg.ignoreTags[node.name]) {
|
||||
this.matchAttr(node);
|
||||
if (!close) {
|
||||
node.children = [];
|
||||
if (node.name == 'pre' && cfg.highlight) {
|
||||
this.remove(node);
|
||||
this.pre = node.pre = true;
|
||||
}
|
||||
this.siblings().push(node);
|
||||
this.STACK.push(node);
|
||||
} else if (!cfg.filter || cfg.filter(node, this) != false)
|
||||
this.siblings().push(node);
|
||||
} else {
|
||||
if (!close) this.remove(node);
|
||||
else if (node.name == 'source') {
|
||||
var parent = this.STACK[this.STACK.length - 1],
|
||||
attrs = node.attrs;
|
||||
if (parent && attrs.src)
|
||||
if (parent.name == 'video' || parent.name == 'audio')
|
||||
parent.attrs.source.push(attrs.src);
|
||||
else {
|
||||
var i, media = attrs.media;
|
||||
if (parent.name == 'picture' && !parent.attrs.src && !(attrs.src.indexOf('.webp') && system.includes('iOS')) &&
|
||||
(!media || (media.includes('px') &&
|
||||
(((i = media.indexOf('min-width')) != -1 && (i = media.indexOf(':', i + 8)) != -1 && screenWidth > parseInt(
|
||||
media.substr(i + 1))) ||
|
||||
((i = media.indexOf('max-width')) != -1 && (i = media.indexOf(':', i + 8)) != -1 && screenWidth < parseInt(
|
||||
media.substr(i + 1)))))))
|
||||
parent.attrs.src = attrs.src;
|
||||
}
|
||||
} else if (node.name == 'base' && !this.domain) this.domain = node.attrs.href;
|
||||
}
|
||||
if (this.data[this.i] == '/') this.i++;
|
||||
this.start = this.i + 1;
|
||||
this.state = this.Text;
|
||||
}
|
||||
// 移除标签
|
||||
remove(node) {
|
||||
var name = node.name,
|
||||
j = this.i;
|
||||
while (1) {
|
||||
if ((this.i = this.data.indexOf('</', this.i + 1)) == -1) {
|
||||
if (name == 'pre' || name == 'svg') this.i = j;
|
||||
else this.i = this.data.length;
|
||||
return;
|
||||
}
|
||||
this.start = (this.i += 2);
|
||||
while (!blankChar[this.data[this.i]] && !this.isClose()) this.i++;
|
||||
if (this.getName(this.section()) == name) {
|
||||
// 代码块高亮
|
||||
if (name == 'pre') {
|
||||
this.data = this.data.substr(0, j + 1) + cfg.highlight(this.data.substring(j + 1, this.i - 5), node.attrs) +
|
||||
this.data.substr(this.i - 5);
|
||||
return this.i = j;
|
||||
} else if (name == 'style')
|
||||
this.CssHandler.getStyle(this.data.substring(j + 1, this.i - 7));
|
||||
else if (name == 'title')
|
||||
this.title = this.data.substring(j + 1, this.i - 7);
|
||||
if ((this.i = this.data.indexOf('>', this.i)) == -1) this.i = this.data.length;
|
||||
// 处理 svg
|
||||
if (name == 'svg') {
|
||||
var src = this.data.substring(j, this.i + 1);
|
||||
if (!node.attrs.xmlns) src = ' xmlns="http://www.w3.org/2000/svg"' + src;
|
||||
var i = j;
|
||||
while (this.data[j] != '<') j--;
|
||||
src = this.data.substring(j, i) + src;
|
||||
var parent = this.STACK[this.STACK.length - 1];
|
||||
if (node.attrs.width == '100%' && parent && (parent.attrs.style || '').includes('inline'))
|
||||
parent.attrs.style = 'width:300px;max-width:100%;' + parent.attrs.style;
|
||||
this.siblings().push({
|
||||
name: 'img',
|
||||
attrs: {
|
||||
src: 'data:image/svg+xml;utf8,' + src.replace(/#/g, '%23'),
|
||||
ignore: 'T'
|
||||
}
|
||||
})
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 处理属性
|
||||
matchAttr(node) {
|
||||
var attrs = node.attrs,
|
||||
style = this.CssHandler.match(node.name, attrs, node) + (attrs.style || ''),
|
||||
styleObj = {};
|
||||
if (attrs.id) {
|
||||
if (this.compress & 1) attrs.id = void 0;
|
||||
else if (this.useAnchor) this.bubble();
|
||||
}
|
||||
if ((this.compress & 2) && attrs.class) attrs.class = void 0;
|
||||
switch (node.name) {
|
||||
case 'img':
|
||||
if (attrs['data-src']) {
|
||||
attrs.src = attrs.src || attrs['data-src'];
|
||||
attrs['data-src'] = void 0;
|
||||
}
|
||||
if (attrs.src && !attrs.ignore) {
|
||||
if (this.bubble()) attrs.i = (this.imgNum++).toString();
|
||||
else attrs.ignore = 'T';
|
||||
}
|
||||
break;
|
||||
case 'a':
|
||||
case 'ad':
|
||||
// #ifdef APP-PLUS
|
||||
case 'iframe':
|
||||
case 'embed':
|
||||
// #endif
|
||||
this.bubble();
|
||||
break;
|
||||
case 'font':
|
||||
if (attrs.color) {
|
||||
styleObj['color'] = attrs.color;
|
||||
attrs.color = void 0;
|
||||
}
|
||||
if (attrs.face) {
|
||||
styleObj['font-family'] = attrs.face;
|
||||
attrs.face = void 0;
|
||||
}
|
||||
if (attrs.size) {
|
||||
var size = parseInt(attrs.size);
|
||||
if (size < 1) size = 1;
|
||||
else if (size > 7) size = 7;
|
||||
var map = ['xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large'];
|
||||
styleObj['font-size'] = map[size - 1];
|
||||
attrs.size = void 0;
|
||||
}
|
||||
break;
|
||||
case 'video':
|
||||
case 'audio':
|
||||
if (!attrs.id) attrs.id = node.name + (++this[`${node.name}Num`]);
|
||||
else this[`${node.name}Num`]++;
|
||||
if (node.name == 'video') {
|
||||
if (attrs.width) {
|
||||
style = `width:${parseFloat(attrs.width) + (attrs.width.includes('%') ? '%' : 'px')};${style}`;
|
||||
attrs.width = void 0;
|
||||
}
|
||||
if (attrs.height) {
|
||||
style = `height:${parseFloat(attrs.height) + (attrs.height.includes('%') ? '%' : 'px')};${style}`;
|
||||
attrs.height = void 0;
|
||||
}
|
||||
if (this.videoNum > 3) node.lazyLoad = true;
|
||||
}
|
||||
attrs.source = [];
|
||||
if (attrs.src) attrs.source.push(attrs.src);
|
||||
if (!attrs.controls && !attrs.autoplay)
|
||||
console.warn(`存在没有 controls 属性的 ${node.name} 标签,可能导致无法播放`, node);
|
||||
this.bubble();
|
||||
break;
|
||||
case 'td':
|
||||
case 'th':
|
||||
if (attrs.colspan || attrs.rowspan)
|
||||
for (var k = this.STACK.length, item; item = this.STACK[--k];)
|
||||
if (item.name == 'table') {
|
||||
item.c = void 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (attrs.align) {
|
||||
styleObj['text-align'] = attrs.align;
|
||||
attrs.align = void 0;
|
||||
}
|
||||
// 压缩 style
|
||||
var styles = style.replace(/"/g, '"').replace(/&/g, '&').split(';');
|
||||
style = '';
|
||||
for (var i = 0, len = styles.length; i < len; i++) {
|
||||
var info = styles[i].split(':');
|
||||
if (info.length < 2) continue;
|
||||
let key = info[0].trim().toLowerCase(),
|
||||
value = info.slice(1).join(':').trim();
|
||||
if (value.includes('-webkit') || value.includes('-moz') || value.includes('-ms') || value.includes('-o') || value
|
||||
.includes(
|
||||
'safe'))
|
||||
style += `;${key}:${value}`;
|
||||
else if (!styleObj[key] || value.includes('import') || !styleObj[key].includes('import'))
|
||||
styleObj[key] = value;
|
||||
}
|
||||
if (node.name == 'img' && parseInt(styleObj.width || attrs.width) > screenWidth)
|
||||
styleObj.height = 'auto';
|
||||
for (var key in styleObj) {
|
||||
var value = styleObj[key];
|
||||
if (key.includes('flex') || key == 'order' || key == 'self-align') node.c = 1;
|
||||
// 填充链接
|
||||
if (value.includes('url')) {
|
||||
var j = value.indexOf('(');
|
||||
if (j++ != -1) {
|
||||
while (value[j] == '"' || value[j] == "'" || blankChar[value[j]]) j++;
|
||||
value = value.substr(0, j) + this.getUrl(value.substr(j));
|
||||
}
|
||||
}
|
||||
// 转换 rpx
|
||||
else if (value.includes('rpx'))
|
||||
value = value.replace(/[0-9.]+\s*rpx/g, $ => parseFloat($) * screenWidth / 750 + 'px');
|
||||
else if (key == 'white-space' && value.includes('pre'))
|
||||
this.pre = node.pre = true;
|
||||
style += `;${key}:${value}`;
|
||||
}
|
||||
style = style.substr(1);
|
||||
if (style) attrs.style = style;
|
||||
}
|
||||
// 节点出栈处理
|
||||
popNode(node) {
|
||||
// 空白符处理
|
||||
if (node.pre) {
|
||||
node.pre = this.pre = void 0;
|
||||
for (let i = this.STACK.length; i--;)
|
||||
if (this.STACK[i].pre)
|
||||
this.pre = true;
|
||||
}
|
||||
if (node.name == 'head' || (cfg.filter && cfg.filter(node, this) == false))
|
||||
return this.siblings().pop();
|
||||
var attrs = node.attrs;
|
||||
// 替换一些标签名
|
||||
if (node.name == 'picture') {
|
||||
node.name = 'img';
|
||||
if (!attrs.src && (node.children[0] || '').name == 'img')
|
||||
attrs.src = node.children[0].attrs.src;
|
||||
if (attrs.src && !attrs.ignore)
|
||||
attrs.i = (this.imgNum++).toString();
|
||||
return node.children = void 0;
|
||||
}
|
||||
if (cfg.blockTags[node.name]) node.name = 'div';
|
||||
else if (!cfg.trustTags[node.name]) node.name = 'span';
|
||||
// 处理列表
|
||||
if (node.c) {
|
||||
if (node.name == 'ul') {
|
||||
var floor = 1;
|
||||
for (let i = this.STACK.length; i--;)
|
||||
if (this.STACK[i].name == 'ul') floor++;
|
||||
if (floor != 1)
|
||||
for (let i = node.children.length; i--;)
|
||||
node.children[i].floor = floor;
|
||||
} else if (node.name == 'ol') {
|
||||
for (let i = 0, num = 1, child; child = node.children[i++];)
|
||||
if (child.name == 'li') {
|
||||
child.type = 'ol';
|
||||
child.num = ((num, type) => {
|
||||
if (type == 'a') return String.fromCharCode(97 + (num - 1) % 26);
|
||||
if (type == 'A') return String.fromCharCode(65 + (num - 1) % 26);
|
||||
if (type == 'i' || type == 'I') {
|
||||
num = (num - 1) % 99 + 1;
|
||||
var one = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'],
|
||||
ten = ['X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC'],
|
||||
res = (ten[Math.floor(num / 10) - 1] || '') + (one[num % 10 - 1] || '');
|
||||
if (type == 'i') return res.toLowerCase();
|
||||
return res;
|
||||
}
|
||||
return num;
|
||||
})(num++, attrs.type) + '.';
|
||||
}
|
||||
}
|
||||
}
|
||||
// 处理表格的边框
|
||||
if (node.name == 'table') {
|
||||
var padding = attrs.cellpadding,
|
||||
spacing = attrs.cellspacing,
|
||||
border = attrs.border;
|
||||
if (node.c) {
|
||||
this.bubble();
|
||||
if (!padding) padding = 2;
|
||||
if (!spacing) spacing = 2;
|
||||
}
|
||||
if (border) attrs.style = `border:${border}px solid gray;${attrs.style || ''}`;
|
||||
if (spacing) attrs.style = `border-spacing:${spacing}px;${attrs.style || ''}`;
|
||||
if (border || padding)
|
||||
(function f(ns) {
|
||||
for (var i = 0, n; n = ns[i]; i++) {
|
||||
if (n.name == 'th' || n.name == 'td') {
|
||||
if (border) n.attrs.style = `border:${border}px solid gray;${n.attrs.style}`;
|
||||
if (padding) n.attrs.style = `padding:${padding}px;${n.attrs.style}`;
|
||||
} else f(n.children || []);
|
||||
}
|
||||
})(node.children)
|
||||
}
|
||||
this.CssHandler.pop && this.CssHandler.pop(node);
|
||||
// 自动压缩
|
||||
if (node.name == 'div' && !Object.keys(attrs).length) {
|
||||
var siblings = this.siblings();
|
||||
if (node.children.length == 1 && node.children[0].name == 'div')
|
||||
siblings[siblings.length - 1] = node.children[0];
|
||||
}
|
||||
}
|
||||
// 工具函数
|
||||
bubble() {
|
||||
for (var i = this.STACK.length, item; item = this.STACK[--i];) {
|
||||
if (cfg.richOnlyTags[item.name]) {
|
||||
if (item.name == 'table' && !Object.hasOwnProperty.call(item, 'c')) item.c = 1;
|
||||
return false;
|
||||
}
|
||||
item.c = 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
getName = val => this.xml ? val : val.toLowerCase();
|
||||
getUrl(url) {
|
||||
if (url[0] == '/') {
|
||||
if (url[1] == '/') url = this.protocol + ':' + url;
|
||||
else if (this.domain) url = this.domain + url;
|
||||
} else if (this.domain && url.indexOf('data:') != 0 && !url.includes('://'))
|
||||
url = this.domain + '/' + url;
|
||||
return url;
|
||||
}
|
||||
isClose = () => this.data[this.i] == '>' || (this.data[this.i] == '/' && this.data[this.i + 1] == '>');
|
||||
section = () => this.data.substring(this.start, this.i);
|
||||
siblings = () => this.STACK.length ? this.STACK[this.STACK.length - 1].children : this.DOM;
|
||||
// 状态机
|
||||
Text(c) {
|
||||
if (c == '<') {
|
||||
var next = this.data[this.i + 1],
|
||||
isLetter = c => (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
||||
if (isLetter(next)) {
|
||||
this.setText();
|
||||
this.start = this.i + 1;
|
||||
this.state = this.TagName;
|
||||
} else if (next == '/') {
|
||||
this.setText();
|
||||
if (isLetter(this.data[++this.i + 1])) {
|
||||
this.start = this.i + 1;
|
||||
this.state = this.EndTag;
|
||||
} else
|
||||
this.Comment();
|
||||
} else if (next == '!') {
|
||||
this.setText();
|
||||
this.Comment();
|
||||
}
|
||||
}
|
||||
}
|
||||
Comment() {
|
||||
var key;
|
||||
if (this.data.substring(this.i + 2, this.i + 4) == '--') key = '-->';
|
||||
else if (this.data.substring(this.i + 2, this.i + 9) == '[CDATA[') key = ']]>';
|
||||
else key = '>';
|
||||
if ((this.i = this.data.indexOf(key, this.i + 2)) == -1) this.i = this.data.length;
|
||||
else this.i += key.length - 1;
|
||||
this.start = this.i + 1;
|
||||
this.state = this.Text;
|
||||
}
|
||||
TagName(c) {
|
||||
if (blankChar[c]) {
|
||||
this.tagName = this.section();
|
||||
while (blankChar[this.data[this.i]]) this.i++;
|
||||
if (this.isClose()) this.setNode();
|
||||
else {
|
||||
this.start = this.i;
|
||||
this.state = this.AttrName;
|
||||
}
|
||||
} else if (this.isClose()) {
|
||||
this.tagName = this.section();
|
||||
this.setNode();
|
||||
}
|
||||
}
|
||||
AttrName(c) {
|
||||
var blank = blankChar[c];
|
||||
if (blank) {
|
||||
this.attrName = this.section();
|
||||
c = this.data[this.i];
|
||||
}
|
||||
if (c == '=') {
|
||||
if (!blank) this.attrName = this.section();
|
||||
while (blankChar[this.data[++this.i]]);
|
||||
this.start = this.i--;
|
||||
this.state = this.AttrValue;
|
||||
} else if (blank) this.setAttr();
|
||||
else if (this.isClose()) {
|
||||
this.attrName = this.section();
|
||||
this.setAttr();
|
||||
}
|
||||
}
|
||||
AttrValue(c) {
|
||||
if (c == '"' || c == "'") {
|
||||
this.start++;
|
||||
if ((this.i = this.data.indexOf(c, this.i + 1)) == -1) return this.i = this.data.length;
|
||||
this.attrVal = this.section();
|
||||
this.i++;
|
||||
} else {
|
||||
for (; !blankChar[this.data[this.i]] && !this.isClose(); this.i++);
|
||||
this.attrVal = this.section();
|
||||
}
|
||||
this.setAttr();
|
||||
}
|
||||
EndTag(c) {
|
||||
if (blankChar[c] || c == '>' || c == '/') {
|
||||
var name = this.getName(this.section());
|
||||
for (var i = this.STACK.length; i--;)
|
||||
if (this.STACK[i].name == name) break;
|
||||
if (i != -1) {
|
||||
var node;
|
||||
while ((node = this.STACK.pop()).name != name);
|
||||
this.popNode(node);
|
||||
} else if (name == 'p' || name == 'br')
|
||||
this.siblings().push({
|
||||
name,
|
||||
attrs: {}
|
||||
});
|
||||
this.i = this.data.indexOf('>', this.i);
|
||||
this.start = this.i + 1;
|
||||
if (this.i == -1) this.i = this.data.length;
|
||||
else this.state = this.Text;
|
||||
}
|
||||
}
|
||||
}
|
||||
module.exports = MpHtmlParser;
|
|
@ -0,0 +1,89 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
/* 配置文件 */
|
||||
// #ifdef MP-WEIXIN
|
||||
const canIUse = wx.canIUse('editor'); // 高基础库标识,用于兼容
|
||||
// #endif
|
||||
module.exports = {
|
||||
// 过滤器函数
|
||||
filter: null,
|
||||
// 代码高亮函数
|
||||
highlight: null,
|
||||
// 文本处理函数
|
||||
onText: null,
|
||||
blankChar: makeMap(' ,\xA0,\t,\r,\n,\f'),
|
||||
// 块级标签,将被转为 div
|
||||
blockTags: makeMap('address,article,aside,body,caption,center,cite,footer,header,html,nav,section' + (
|
||||
// #ifdef MP-WEIXIN
|
||||
canIUse ? '' :
|
||||
// #endif
|
||||
',pre')),
|
||||
// 将被移除的标签
|
||||
ignoreTags: makeMap(
|
||||
'area,base,basefont,canvas,command,frame,input,isindex,keygen,link,map,meta,param,script,source,style,svg,textarea,title,track,use,wbr'
|
||||
// #ifdef MP-WEIXIN
|
||||
+ (canIUse ? ',rp' : '')
|
||||
// #endif
|
||||
// #ifndef APP-PLUS
|
||||
+ ',embed,iframe'
|
||||
// #endif
|
||||
),
|
||||
// 只能被 rich-text 显示的标签
|
||||
richOnlyTags: makeMap('a,colgroup,fieldset,legend,picture,table'
|
||||
// #ifdef MP-WEIXIN
|
||||
+ (canIUse ? ',bdi,bdo,caption,rt,ruby' : '')
|
||||
// #endif
|
||||
),
|
||||
// 自闭合的标签
|
||||
selfClosingTags: makeMap(
|
||||
'area,base,basefont,br,col,circle,ellipse,embed,frame,hr,img,input,isindex,keygen,line,link,meta,param,path,polygon,rect,source,track,use,wbr'
|
||||
),
|
||||
// 信任的属性
|
||||
trustAttrs: makeMap(
|
||||
'align,alt,app-id,author,autoplay,border,cellpadding,cellspacing,class,color,colspan,controls,data-src,dir,face,height,href,id,ignore,loop,media,muted,name,path,poster,rowspan,size,span,src,start,style,type,unit-id,width,xmlns'
|
||||
),
|
||||
// bool 型的属性
|
||||
boolAttrs: makeMap('autoplay,controls,ignore,loop,muted'),
|
||||
// 信任的标签
|
||||
trustTags: makeMap(
|
||||
'a,abbr,ad,audio,b,blockquote,br,code,col,colgroup,dd,del,dl,dt,div,em,fieldset,h1,h2,h3,h4,h5,h6,hr,i,img,ins,label,legend,li,ol,p,q,source,span,strong,sub,sup,table,tbody,td,tfoot,th,thead,tr,title,ul,video'
|
||||
// #ifdef MP-WEIXIN
|
||||
+ (canIUse ? ',bdi,bdo,caption,pre,rt,ruby' : '')
|
||||
// #endif
|
||||
// #ifdef APP-PLUS
|
||||
+ ',embed,iframe'
|
||||
// #endif
|
||||
),
|
||||
// 默认的标签样式
|
||||
userAgentStyles: {
|
||||
address: 'font-style:italic',
|
||||
big: 'display:inline;font-size:1.2em',
|
||||
blockquote: 'background-color:#f6f6f6;border-left:3px solid #dbdbdb;color:#6c6c6c;padding:5px 0 5px 10px',
|
||||
caption: 'display:table-caption;text-align:center',
|
||||
center: 'text-align:center',
|
||||
cite: 'font-style:italic',
|
||||
dd: 'margin-left:40px',
|
||||
img: 'max-width:100%',
|
||||
mark: 'background-color:yellow',
|
||||
picture: 'max-width:100%',
|
||||
pre: 'font-family:monospace;white-space:pre;overflow:scroll',
|
||||
s: 'text-decoration:line-through',
|
||||
small: 'display:inline;font-size:0.8em',
|
||||
u: 'text-decoration:underline'
|
||||
}
|
||||
}
|
||||
|
||||
function makeMap(str) {
|
||||
var map = {},
|
||||
list = str.split(',');
|
||||
for (var i = list.length; i--;)
|
||||
map[list[i]] = true;
|
||||
return map;
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
var inlineTags = {
|
||||
abbr: 1,
|
||||
b: 1,
|
||||
big: 1,
|
||||
code: 1,
|
||||
del: 1,
|
||||
em: 1,
|
||||
i: 1,
|
||||
ins: 1,
|
||||
label: 1,
|
||||
q: 1,
|
||||
small: 1,
|
||||
span: 1,
|
||||
strong: 1
|
||||
}
|
||||
export default {
|
||||
// 从顶层标签的样式中取出一些给 rich-text
|
||||
getStyle: function(style) {
|
||||
if (style) {
|
||||
var i, j, res = '';
|
||||
if ((i = style.indexOf('display')) != -1)
|
||||
res = style.substring(i, (j = style.indexOf(';', i)) == -1 ? style.length : j);
|
||||
if ((i = style.indexOf('float')) != -1)
|
||||
res += ';' + style.substring(i, (j = style.indexOf(';', i)) == -1 ? style.length : j);
|
||||
return res;
|
||||
}
|
||||
},
|
||||
getNode: function(item) {
|
||||
return [item];
|
||||
},
|
||||
// 是否通过 rich-text 显示
|
||||
useRichText: function(item) {
|
||||
return !item.c && !inlineTags[item.name] && (item.attrs.style || '').indexOf('display:inline') == -1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
var inlineTags = {
|
||||
abbr: 1,
|
||||
b: 1,
|
||||
big: 1,
|
||||
code: 1,
|
||||
del: 1,
|
||||
em: 1,
|
||||
i: 1,
|
||||
ins: 1,
|
||||
label: 1,
|
||||
q: 1,
|
||||
small: 1,
|
||||
span: 1,
|
||||
strong: 1
|
||||
}
|
||||
module.exports = {
|
||||
// 从顶层标签的样式中取出一些给 rich-text
|
||||
getStyle: function(style) {
|
||||
if (style) {
|
||||
var i, j, res = '';
|
||||
if ((i = style.indexOf('display')) != -1)
|
||||
res = style.substring(i, (j = style.indexOf(';', i)) == -1 ? style.length : j);
|
||||
if ((i = style.indexOf('float')) != -1)
|
||||
res += ';' + style.substring(i, (j = style.indexOf(';', i)) == -1 ? style.length : j);
|
||||
return res;
|
||||
}
|
||||
},
|
||||
// 处理懒加载
|
||||
getNode: function(item, imgLoad) {
|
||||
if (!imgLoad && item.attrs.i != '0') {
|
||||
var img = {
|
||||
name: 'img',
|
||||
attrs: JSON.parse(JSON.stringify(item.attrs))
|
||||
}
|
||||
delete img.attrs.src;
|
||||
img.attrs.style += ';width:20px;height:20px';
|
||||
return [img];
|
||||
} else return [item];
|
||||
},
|
||||
// 是否通过 rich-text 显示
|
||||
useRichText: function(item) {
|
||||
return !item.c && !inlineTags[item.name] && (item.attrs.style || '').indexOf('display:inline') == -1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,485 @@
|
|||
<!--
|
||||
trees 递归显示组件
|
||||
github:https://github.com/jin-yufeng/Parser
|
||||
docs:https://jin-yufeng.github.io/Parser
|
||||
插件市场:https://ext.dcloud.net.cn/plugin?id=805
|
||||
author:JinYufeng
|
||||
update:2020/04/13
|
||||
-->
|
||||
<template>
|
||||
<view class="interlayer">
|
||||
<block v-for="(n, index) in nodes" v-bind:key="index">
|
||||
<!--图片-->
|
||||
<!--#ifdef MP-WEIXIN || MP-QQ || MP-ALIPAY || APP-PLUS-->
|
||||
<rich-text v-if="n.name=='img'" :id="n.attrs.id" class="_img" :style="''+handler.getStyle(n.attrs.style)" :nodes="handler.getNode(n,!lazyLoad||imgLoad)"
|
||||
:data-attrs="n.attrs" @tap="imgtap" @longpress="imglongtap" />
|
||||
<!--#endif-->
|
||||
<!--#ifdef MP-BAIDU || MP-TOUTIAO-->
|
||||
<rich-text v-if="n.name=='img'" :id="n.attrs.id" class="_img" :style="n.attrs.contain" :nodes='[n]' :data-attrs="n.attrs"
|
||||
@tap="imgtap" @longpress="imglongtap" />
|
||||
<!--#endif-->
|
||||
<!--文本-->
|
||||
<!--#ifdef MP-WEIXIN || MP-QQ || APP-PLUS-->
|
||||
<rich-text v-else-if="n.decode" class="_entity" :nodes="[n]"></rich-text>
|
||||
<!--#endif-->
|
||||
<text v-else-if="n.type=='text'" decode>{{n.text}}</text>
|
||||
<text v-else-if="n.name=='br'">\n</text>
|
||||
<!--视频-->
|
||||
<view v-else-if="n.name=='video'">
|
||||
<view v-if="(!loadVideo||n.lazyLoad)&&!(controls[n.attrs.id]&&controls[n.attrs.id].play)" :id="n.attrs.id" :class="'_video '+(n.attrs.class||'')"
|
||||
:style="n.attrs.style" @tap="_loadVideo" />
|
||||
<video v-else :id="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :autoplay="n.attrs.autoplay||(controls[n.attrs.id]&&controls[n.attrs.id].play)"
|
||||
:controls="n.attrs.controls" :loop="n.attrs.loop" :muted="n.attrs.muted" :poster="n.attrs.poster" :src="n.attrs.source[(controls[n.attrs.id]&&controls[n.attrs.id].index)||0]"
|
||||
:unit-id="n.attrs['unit-id']" :data-id="n.attrs.id" data-from="video" data-source="source" @error="error" @play="play" />
|
||||
</view>
|
||||
<!--音频-->
|
||||
<audio v-else-if="n.name=='audio'" :class="n.attrs.class" :style="n.attrs.style" :author="n.attrs.author" :autoplay="n.attrs.autoplay"
|
||||
:controls="n.attrs.controls" :loop="n.attrs.loop" :name="n.attrs.name" :poster="n.attrs.poster" :src="n.attrs.source[(controls[n.attrs.id]&&controls[n.attrs.id].index)||0]"
|
||||
:data-id="n.attrs.id" data-from="audio" data-source="source" @error="error" @play="play" />
|
||||
<!--链接-->
|
||||
<view v-else-if="n.name=='a'" :class="'_a '+(n.attrs.class||'')" hover-class="_hover" :style="n.attrs.style"
|
||||
:data-attrs="n.attrs" @tap="linkpress">
|
||||
<trees class="_span" :nodes="n.children" />
|
||||
</view>
|
||||
<!--广告(按需打开注释)-->
|
||||
<!--#ifdef MP-WEIXIN || MP-QQ || MP-TOUTIAO-->
|
||||
<!--<ad v-else-if="n.name=='ad'" :class="n.attrs.class" :style="n.attrs.style" :unit-id="n.attrs['unit-id']"
|
||||
data-from="ad" @error="error" />-->
|
||||
<!--#endif-->
|
||||
<!--#ifdef MP-BAIDU-->
|
||||
<!--<ad v-else-if="n.name=='ad'" :class="n.attrs.class" :style="n.attrs.style" :appid="n.attrs.appid"
|
||||
:apid="n.attrs.apid" :type="n.attrs.type" data-from="ad" @error="error" />-->
|
||||
<!--#endif-->
|
||||
<!--#ifdef APP-PLUS-->
|
||||
<!--<ad v-else-if="n.name=='ad'" :class="n.attrs.class" :style="n.attrs.style" :adpid="n.attrs.adpid"
|
||||
data-from="ad" @error="error" />-->
|
||||
<!--#endif-->
|
||||
<!--列表-->
|
||||
<view v-else-if="n.name=='li'" :id="n.attrs.id" :class="n.attrs.class" :style="(n.attrs.style||'')+';display:flex'">
|
||||
<view v-if="n.type=='ol'" class="_ol-bef">{{n.num}}</view>
|
||||
<view v-else class="_ul-bef">
|
||||
<view v-if="n.floor%3==0" class="_ul-p1">█</view>
|
||||
<view v-else-if="n.floor%3==2" class="_ul-p2" />
|
||||
<view v-else class="_ul-p1" style="border-radius:50%">█</view>
|
||||
</view>
|
||||
<!--#ifdef MP-ALIPAY-->
|
||||
<view class="_li">
|
||||
<trees :nodes="n.children" />
|
||||
</view>
|
||||
<!--#endif-->
|
||||
<!--#ifndef MP-ALIPAY-->
|
||||
<trees class="_li" :nodes="n.children" :lazyLoad="lazyLoad" :loadVideo="loadVideo" />
|
||||
<!--#endif-->
|
||||
</view>
|
||||
<!--表格-->
|
||||
<view v-else-if="n.name=='table'&&n.c" :id="n.attrs.id" :class="n.attrs.class" :style="(n.attrs.style||'')+';display:table'">
|
||||
<view v-for="(tbody, i) in n.children" v-bind:key="i" :class="tbody.attrs.class" :style="(tbody.attrs.style||'')+(tbody.name[0]=='t'?';display:table-'+(tbody.name=='tr'?'row':'row-group'):'')">
|
||||
<view v-for="(tr, j) in tbody.children" v-bind:key="j" :class="tr.attrs.class" :style="(tr.attrs.style||'')+(tr.name[0]=='t'?';display:table-'+(tr.name=='tr'?'row':'cell'):'')">
|
||||
<trees v-if="tr.name=='td'" :nodes="tr.children" :lazyLoad="lazyLoad" :loadVideo="loadVideo" />
|
||||
<block v-else>
|
||||
<!--#ifdef MP-ALIPAY-->
|
||||
<view v-for="(td, k) in tr.children" v-bind:key="k" :class="td.attrs.class" :style="(td.attrs.style||'')+(td.name[0]=='t'?';display:table-'+(td.name=='tr'?'row':'cell'):'')">
|
||||
<trees :nodes="td.children" />
|
||||
</view>
|
||||
<!--#endif-->
|
||||
<!--#ifndef MP-ALIPAY-->
|
||||
<trees v-for="(td, k) in tr.children" v-bind:key="k" :class="td.attrs.class" :style="(td.attrs.style||'')+(td.name[0]=='t'?';display:table-'+(td.name=='tr'?'row':'cell'):'')"
|
||||
:nodes="td.children" :lazyLoad="lazyLoad" :loadVideo="loadVideo" />
|
||||
<!--#endif-->
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!--#ifdef APP-PLUS-->
|
||||
<iframe v-else-if="n.name=='iframe'" :style="n.attrs.style" :allowfullscreen="n.attrs.allowfullscreen" :frameborder="n.attrs.frameborder"
|
||||
:width="n.attrs.width" :height="n.attrs.height" :src="n.attrs.src" />
|
||||
<embed v-else-if="n.name=='embed'" :style="n.attrs.style" :width="n.attrs.width" :height="n.attrs.height" :src="n.attrs.src" />
|
||||
<!--#endif-->
|
||||
<!--富文本-->
|
||||
<!--#ifdef MP-WEIXIN || MP-QQ || MP-ALIPAY || APP-PLUS-->
|
||||
<rich-text v-else-if="handler.useRichText(n)" :id="n.attrs.id" :class="'_p __'+n.name" :nodes="[n]" />
|
||||
<!--#endif-->
|
||||
<!--#ifdef MP-BAIDU || MP-TOUTIAO-->
|
||||
<rich-text v-else-if="!(n.c||n.continue)" :id="n.attrs.id" :class="_p" :style="n.attrs.contain" :nodes="[n]" />
|
||||
<!--#endif-->
|
||||
<!--#ifdef MP-ALIPAY-->
|
||||
<view v-else :id="n.attrs.id" :class="'_'+n.name+' '+(n.attrs.class||'')" :style="n.attrs.style">
|
||||
<trees :nodes="n.children" />
|
||||
</view>
|
||||
<!--#endif-->
|
||||
<!--#ifndef MP-ALIPAY-->
|
||||
<trees v-else :class="(n.attrs.id||'')+' _'+n.name+' '+(n.attrs.class||'')" :style="n.attrs.style" :nodes="n.children"
|
||||
:lazyLoad="lazyLoad" :loadVideo="loadVideo" />
|
||||
<!--#endif-->
|
||||
</block>
|
||||
</view>
|
||||
</template>
|
||||
<script module="handler" lang="wxs" src="./handler.wxs"></script>
|
||||
<script module="handler" lang="sjs" src="./handler.sjs"></script>
|
||||
<script>
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
global.Parser = {};
|
||||
import trees from './trees'
|
||||
export default {
|
||||
components: {
|
||||
trees
|
||||
},
|
||||
name: 'trees',
|
||||
data() {
|
||||
return {
|
||||
controls: {},
|
||||
// #ifdef MP-WEIXIN || MP-QQ || APP-PLUS
|
||||
imgLoad: false,
|
||||
// #endif
|
||||
// #ifndef APP-PLUS
|
||||
loadVideo: true
|
||||
// #endif
|
||||
}
|
||||
},
|
||||
props: {
|
||||
nodes: Array,
|
||||
// #ifdef MP-WEIXIN || MP-QQ || H5 || APP-PLUS
|
||||
lazyLoad: Boolean,
|
||||
// #endif
|
||||
// #ifdef APP-PLUS
|
||||
loadVideo: Boolean
|
||||
// #endif
|
||||
},
|
||||
mounted() {
|
||||
// 获取顶层组件
|
||||
this.top = this.$parent;
|
||||
while (this.top.$options.name != 'parser') {
|
||||
if (this.top.top) {
|
||||
this.top = this.top.top;
|
||||
break;
|
||||
}
|
||||
this.top = this.top.$parent;
|
||||
}
|
||||
},
|
||||
// #ifdef MP-WEIXIN || MP-QQ || APP-PLUS
|
||||
beforeDestroy() {
|
||||
if (this.observer)
|
||||
this.observer.disconnect();
|
||||
},
|
||||
// #endif
|
||||
methods: {
|
||||
// #ifndef MP-ALIPAY
|
||||
play(e) {
|
||||
if (this.top.videoContexts.length > 1 && this.top.autopause)
|
||||
for (var i = this.top.videoContexts.length; i--;)
|
||||
if (this.top.videoContexts[i].id != e.currentTarget.dataset.id)
|
||||
this.top.videoContexts[i].pause();
|
||||
},
|
||||
// #endif
|
||||
imgtap(e) {
|
||||
var attrs = e.currentTarget.dataset.attrs;
|
||||
if (!attrs.ignore) {
|
||||
var preview = true, data = {
|
||||
id: e.target.id,
|
||||
src: attrs.src,
|
||||
ignore: () => preview = false
|
||||
};
|
||||
global.Parser.onImgtap && global.Parser.onImgtap(data);
|
||||
this.top.$emit('imgtap', data);
|
||||
if (preview) {
|
||||
var urls = this.top.imgList,
|
||||
current = urls[attrs.i] ? parseInt(attrs.i) : (urls = [attrs.src], 0);
|
||||
uni.previewImage({
|
||||
current,
|
||||
urls
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
imglongtap(e) {
|
||||
var attrs = e.item.dataset.attrs;
|
||||
if (!attrs.ignore)
|
||||
this.top.$emit('imglongtap', {
|
||||
id: e.target.id,
|
||||
src: attrs.src
|
||||
})
|
||||
},
|
||||
linkpress(e) {
|
||||
var jump = true,
|
||||
attrs = e.currentTarget.dataset.attrs;
|
||||
attrs.ignore = () => jump = false;
|
||||
global.Parser.onLinkpress && global.Parser.onLinkpress(attrs);
|
||||
this.top.$emit('linkpress', attrs);
|
||||
if (jump) {
|
||||
// #ifdef MP
|
||||
if (attrs['app-id']) {
|
||||
return uni.navigateToMiniProgram({
|
||||
appId: attrs['app-id'],
|
||||
path: attrs.path
|
||||
})
|
||||
}
|
||||
// #endif
|
||||
if (attrs.href) {
|
||||
if (attrs.href[0] == '#') {
|
||||
if (this.top.useAnchor)
|
||||
this.top.navigateTo({
|
||||
id: attrs.href.substring(1)
|
||||
})
|
||||
} else if (attrs.href.indexOf('http') == 0 || attrs.href.indexOf('//') == 0) {
|
||||
// #ifdef APP-PLUS
|
||||
plus.runtime.openWeb(attrs.href);
|
||||
// #endif
|
||||
// #ifndef APP-PLUS
|
||||
uni.setClipboardData({
|
||||
data: attrs.href,
|
||||
success: () =>
|
||||
uni.showToast({
|
||||
title: '链接已复制'
|
||||
})
|
||||
})
|
||||
// #endif
|
||||
} else
|
||||
uni.navigateTo({
|
||||
url: attrs.href
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
error(e) {
|
||||
var context, target = e.currentTarget,
|
||||
source = target.dataset.from;
|
||||
if (source == 'video' || source == 'audio') {
|
||||
// 加载其他 source
|
||||
var index = this.controls[target.id] ? this.controls[target.id].index + 1 : 1;
|
||||
if (index < target.dataset.source.length)
|
||||
this.$set(this.controls, target.id + '.index', index);
|
||||
if (source == 'video') context = uni.createVideoContext(target.id, this);
|
||||
}
|
||||
this.top && this.top.$emit('error', {
|
||||
source,
|
||||
target,
|
||||
errMsg: e.detail.errMsg,
|
||||
errCode: e.detail.errCode,
|
||||
context
|
||||
});
|
||||
},
|
||||
_loadVideo(e) {
|
||||
this.$set(this.controls, e.currentTarget.id, {
|
||||
play: true,
|
||||
index: 0
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* 在这里引入自定义样式 */
|
||||
|
||||
/* 链接和图片效果 */
|
||||
._a {
|
||||
display: inline;
|
||||
color: #366092;
|
||||
word-break: break-all;
|
||||
padding: 1.5px 0 1.5px 0;
|
||||
}
|
||||
|
||||
._hover {
|
||||
opacity: 0.7;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
._img {
|
||||
display: inline-block;
|
||||
text-indent: 0;
|
||||
}
|
||||
|
||||
/* #ifdef MP-WEIXIN */
|
||||
:host {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
|
||||
/* #ifdef MP */
|
||||
.interlayer {
|
||||
align-content: inherit;
|
||||
align-items: inherit;
|
||||
display: inherit;
|
||||
flex-direction: inherit;
|
||||
flex-wrap: inherit;
|
||||
justify-content: inherit;
|
||||
width: 100%;
|
||||
white-space: inherit;
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
|
||||
._b,
|
||||
._strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
._blockquote,
|
||||
._div,
|
||||
._p,
|
||||
._ol,
|
||||
._ul,
|
||||
._li {
|
||||
display: block;
|
||||
}
|
||||
|
||||
._code {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
._del {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
._em,
|
||||
._i {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
._h1 {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
._h2 {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
._h3 {
|
||||
font-size: 1.17em;
|
||||
}
|
||||
|
||||
._h5 {
|
||||
font-size: 0.83em;
|
||||
}
|
||||
|
||||
._h6 {
|
||||
font-size: 0.67em;
|
||||
}
|
||||
|
||||
._h1,
|
||||
._h2,
|
||||
._h3,
|
||||
._h4,
|
||||
._h5,
|
||||
._h6 {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
._ins {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
._li {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
._ol-bef {
|
||||
margin-right: 5px;
|
||||
text-align: right;
|
||||
width: 36px;
|
||||
}
|
||||
|
||||
._ul-bef {
|
||||
line-height: normal;
|
||||
margin: 0 12px 0 23px;
|
||||
}
|
||||
|
||||
._ol-bef,
|
||||
._ul_bef {
|
||||
flex: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
._ul-p1 {
|
||||
display: inline-block;
|
||||
height: 0.3em;
|
||||
line-height: 0.3em;
|
||||
overflow: hidden;
|
||||
width: 0.3em;
|
||||
}
|
||||
|
||||
._ul-p2 {
|
||||
border: 0.05em solid black;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
height: 0.23em;
|
||||
width: 0.23em;
|
||||
}
|
||||
|
||||
._q::before {
|
||||
content: '"';
|
||||
}
|
||||
|
||||
._q::after {
|
||||
content: '"';
|
||||
}
|
||||
|
||||
._sub {
|
||||
font-size: smaller;
|
||||
vertical-align: sub;
|
||||
}
|
||||
|
||||
._sup {
|
||||
font-size: smaller;
|
||||
vertical-align: super;
|
||||
}
|
||||
|
||||
/* #ifndef MP-WEIXIN */
|
||||
._abbr,
|
||||
._b,
|
||||
._code,
|
||||
._del,
|
||||
._em,
|
||||
._i,
|
||||
._ins,
|
||||
._label,
|
||||
._q,
|
||||
._span,
|
||||
._strong,
|
||||
._sub,
|
||||
._sup {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
|
||||
/* #ifdef MP-WEIXIN || MP-QQ || MP-ALIPAY */
|
||||
.__bdo,
|
||||
.__bdi,
|
||||
.__ruby,
|
||||
.__rt,
|
||||
._entity {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
._video {
|
||||
background-color: black;
|
||||
display: inline-block;
|
||||
height: 225px;
|
||||
position: relative;
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
._video::after {
|
||||
border-color: transparent transparent transparent white;
|
||||
border-style: solid;
|
||||
border-width: 15px 0 15px 30px;
|
||||
content: '';
|
||||
left: 50%;
|
||||
margin: -15px 0 0 -15px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,183 @@
|
|||
<template>
|
||||
<view class="msg-view">
|
||||
<scroll-view class="msg-view-p" scroll-y="true" :scroll-top="msgPanelScrollTop">
|
||||
<view id="chatArea">
|
||||
<view class="chat-area-line" v-for="(item,index) in msgList">
|
||||
|
||||
<view class="system-msg"
|
||||
:style="{'flex-direction':((item.userName.length + item.content.length)<15?'row':'')}"
|
||||
v-if="item.msg_type == 'system'">
|
||||
<view class="system-msg-detail ">
|
||||
<text class="system-msg-detail-username " v-for="i in item.userName">{{i}}</text>
|
||||
<text class="system-msg-detail-content " v-for="i in ':'">{{i}}</text>
|
||||
<text class="system-msg-detail-content " v-for="i in item.content">{{i}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="user-msg"
|
||||
:style="{'flex-direction':((item.userName.length + item.content.length)<15?'row':'')}" v-else>
|
||||
|
||||
<view class="user-msg-detail">
|
||||
<view class="user-msg-detail-tag">
|
||||
<!-- <text style="text-align: center;font-size: 20px;color: #DD524D;">★1</text> -->
|
||||
<!-- 这里可以根据用户等级显示图片 -->
|
||||
<image :src="item.avatar" class="user-msg-detail-tag"></image>
|
||||
</view>
|
||||
<text class="user-msg-detail-username" v-for="i in item.userName"
|
||||
@click="test(item.userName)">{{i}}</text>
|
||||
<text class="user-msg-detail-content" v-for="i in ':'">{{i}}</text>
|
||||
<text class="user-msg-detail-content" v-for="i in item.content">{{i}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'MhMsgList',
|
||||
props: {
|
||||
msgList: {
|
||||
type: [Object, Array],
|
||||
default: [{
|
||||
userName: "系统通知",
|
||||
content: "直播倡导绿色直播,严禁发布涉黄涉毒涉赌,严禁发布涉政、违法及低俗违规内容。健康直播,文明互动",
|
||||
cmd: "say",
|
||||
|
||||
msg_type: "system"
|
||||
}, ]
|
||||
},
|
||||
msgPanelScrollTop: {
|
||||
type: [Number, String],
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
|
||||
},
|
||||
|
||||
methods: {
|
||||
test(e) {
|
||||
uni.showToast({
|
||||
title: e,
|
||||
icon: 'none'
|
||||
})
|
||||
},
|
||||
|
||||
setMsgPanelScroll() {
|
||||
var that = this;
|
||||
setTimeout(function() {
|
||||
const query = uni.createSelectorQuery().in(that);
|
||||
query.select('#chatArea').boundingClientRect(data => {
|
||||
that.msgPanelScrollTop = data.height - 200;
|
||||
}).exec();
|
||||
}, 50)
|
||||
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.msg-view-p {
|
||||
display: flex;
|
||||
width: 550rpx;
|
||||
height: 550rpx;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
.chat-area-line {
|
||||
width: 550upx;
|
||||
|
||||
flex-direction: row;
|
||||
margin-bottom: 5upx;
|
||||
}
|
||||
|
||||
.system-msg {
|
||||
width: 550upx;
|
||||
margin-bottom: 5upx;
|
||||
}
|
||||
|
||||
.system-msg-detail {
|
||||
// max-width: 550upx;
|
||||
|
||||
padding: 10upx;
|
||||
border-radius: 30upx;
|
||||
background-color: rgba($color: #000000, $alpha: 0.4);
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
margin-right: 14upx;
|
||||
|
||||
>.system-msg-detail-username {
|
||||
color: red;
|
||||
font-size: 32upx;
|
||||
font-weight: 400;
|
||||
line-height: 40upx;
|
||||
|
||||
}
|
||||
|
||||
>.system-msg-detail-content {
|
||||
font-size: 32upx;
|
||||
font-weight: 400;
|
||||
line-height: 40upx;
|
||||
color: #A0CFFF;
|
||||
}
|
||||
}
|
||||
|
||||
.user-line {
|
||||
// max-width: 530upx;
|
||||
padding: 10upx;
|
||||
color: #FFFFFF;
|
||||
flex-direction: row;
|
||||
border-radius: 30upx;
|
||||
background-color: rgba($color: #000000, $alpha: 0.4);
|
||||
margin-right: 14upx;
|
||||
font-size: 28upx;
|
||||
font-weight: 400;
|
||||
line-height: 40upx;
|
||||
}
|
||||
|
||||
.user-msg {
|
||||
width: 530upx;
|
||||
|
||||
|
||||
margin-bottom: 5upx;
|
||||
}
|
||||
|
||||
.user-msg-detail-tag {
|
||||
width: 40upx;
|
||||
height: 40upx;
|
||||
border-radius: 50%;
|
||||
|
||||
}
|
||||
|
||||
.user-msg-detail {
|
||||
padding: 10upx;
|
||||
border-radius: 30upx;
|
||||
background-color: rgba($color: #000000, $alpha: 0.4);
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
margin-right: 14upx;
|
||||
|
||||
|
||||
|
||||
>.user-msg-detail-username {
|
||||
color: #A0CFFF;
|
||||
font-size: 32upx;
|
||||
font-weight: 400;
|
||||
line-height: 40upx;
|
||||
}
|
||||
|
||||
>.user-msg-detail-content {
|
||||
font-size: 32upx;
|
||||
font-weight: 400;
|
||||
line-height: 40upx;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
</style>
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,488 @@
|
|||
<template>
|
||||
<view class="containers">
|
||||
<view class="header">
|
||||
<view class="search">
|
||||
<text class="iconfont icon-xiazai5"></text>
|
||||
<input type="text" placeholder="请输入商品名称" v-model="searchVal" @input="setValue" confirm-type="search"
|
||||
@confirm="searchBut()" placeholder-class='placeholder'>
|
||||
</view>
|
||||
<view class="iconclose" @click="close">
|
||||
<image src="@/static/img/close.png" mode="aspectFit"></image>
|
||||
</view>
|
||||
</view>
|
||||
<view class="main">
|
||||
<scroll-view scroll-y="true" @touchmove.stop>
|
||||
<block>
|
||||
|
||||
<view v-if="bought.length>0" @touchmove="onTouchmove" id="goods" class="goods">
|
||||
<view class="picTxt acea-row" v-for="(item, i) in bought" :key="i">
|
||||
<view class="checkbox">
|
||||
<text @click.stop="goodsCheck(item)" v-if="item.check" class="iconfont icon-xuanzhong1"
|
||||
style="color: red;"></text>
|
||||
<text @click.stop="goodsCheck(item)" v-else class="iconfont icon-weixuanzhong"></text>
|
||||
</view>
|
||||
<view class='pictrue'>
|
||||
<image :src='item.image'></image>
|
||||
</view>
|
||||
|
||||
<view class='text'>
|
||||
<view class='line2 name'>{{item.store_name}}</view>
|
||||
<view class="" style="margin-top: 20rpx;">
|
||||
{{item.price}}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="empty">
|
||||
<image src="/static/images/no_thing.png"></image>
|
||||
<text>暂无内容哦~</text>
|
||||
</view>
|
||||
</block>
|
||||
</scroll-view>
|
||||
<view class="foot_bar">
|
||||
<button class="confirm_btn" @click="submit">确定({{checkedArr.length}})</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import subtractive from '@/components/subtractive/subtractive.vue';
|
||||
|
||||
import {
|
||||
good
|
||||
} from '@/api/api.js'
|
||||
|
||||
|
||||
export default {
|
||||
props: {
|
||||
checkedObj: {
|
||||
type: Array,
|
||||
default: []
|
||||
}
|
||||
},
|
||||
components: {
|
||||
subtractive
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isActive: 0,
|
||||
loadedb: false,
|
||||
loadingb: false,
|
||||
loadedc: false,
|
||||
loadingc: false,
|
||||
loadeds: false,
|
||||
loadings: false,
|
||||
whereb: {
|
||||
page: 1,
|
||||
limit: 10,
|
||||
keyword: '',
|
||||
},
|
||||
peicenumber: 0,
|
||||
|
||||
searchVal: '',
|
||||
checked: [],
|
||||
list: [],
|
||||
|
||||
bought: [],
|
||||
|
||||
checkedArr: [],
|
||||
aryys: [],
|
||||
// picker下拉数据源
|
||||
storageCustomList: [],
|
||||
index: 0,
|
||||
pickerData: '请选择',
|
||||
itstock: '',
|
||||
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
checkedObj: {
|
||||
handler(n) {
|
||||
this.checkedArr = n
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
|
||||
},
|
||||
mounted() {
|
||||
|
||||
this.checkedArr = this.checkedObj
|
||||
this.aryys = this.checkedObj
|
||||
this.getBounht();
|
||||
},
|
||||
methods: {
|
||||
|
||||
//价格
|
||||
producrprice(e, i, item) {
|
||||
this.bought[i].price = e.detail.value
|
||||
this.$set(item, 'check', false);
|
||||
for (let i in this.checkedArr) {
|
||||
if (this.checkedArr[i].product_id == item.product_id) {
|
||||
this.checkedArr.splice(i, 1)
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
incrementTotal(e, i, item) {
|
||||
// console.log(e, i, item)
|
||||
this.$set(item, 'check', false);
|
||||
for (let i in this.checkedArr) {
|
||||
if (this.checkedArr[i].product_id == item.product_id) {
|
||||
this.checkedArr.splice(i, 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
// picker修改事件
|
||||
bindPickerChange: function(e, storage, num) {
|
||||
this.bought[num].attrValue[this.index].sku = storage[e.detail.value].sku
|
||||
this.bought[num].attrValue[this.index].stock = storage[e.detail.value].stock
|
||||
this.bought[num].product_attr_unique = storage[e.detail.value].unique
|
||||
this.pickerData = storage[this.index] // 这里就是选中的对象
|
||||
if (this.bought[num].attrValue[this.index].stock == 0) {
|
||||
this.$util.Tips({
|
||||
title: '库存不足'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 点击关闭按钮
|
||||
close() {
|
||||
this.$emit('close');
|
||||
},
|
||||
numberChange(data, i) {
|
||||
this.peicenumber = data.number;
|
||||
this.bought[i].number = data.number
|
||||
|
||||
},
|
||||
setValue: function(event) {
|
||||
this.$set(this.whereb, 'keyword', event.detail.value);
|
||||
if (!event.detail.value) {
|
||||
this.whereb.page = 1
|
||||
this.loadedb = false
|
||||
this.getBounht()
|
||||
}
|
||||
|
||||
},
|
||||
searchBut() {
|
||||
this.bought = []
|
||||
this.whereb.page = 1
|
||||
this.loadedb = false
|
||||
this.getBounht()
|
||||
},
|
||||
tabs(index) {
|
||||
this.isActive = index
|
||||
this.$set(this.whereb, 'keyword', '');
|
||||
|
||||
|
||||
},
|
||||
onTouchmove(e) {
|
||||
if (this.loadendb) return;
|
||||
if (this.loadingb) return;
|
||||
const query = uni.createSelectorQuery().in(this);
|
||||
query.select('#goods').boundingClientRect(data => {
|
||||
if (data.bottom < 1500 && data.top < 0) {
|
||||
this.getBounht();
|
||||
}
|
||||
}).exec();
|
||||
|
||||
// 模拟触底刷新
|
||||
},
|
||||
|
||||
|
||||
getBounht() {
|
||||
var that = this;
|
||||
|
||||
// if (that.loadingb || that.loadedb) return;
|
||||
// that.loadingb = true;
|
||||
|
||||
good(that.whereb).then(
|
||||
res => {
|
||||
that.loadingb = false;
|
||||
that.loadedb = res.data.list.length < that.whereb.limit;
|
||||
that.bought.push.apply(that.bought, res.data.list);
|
||||
that.whereb.page = that.whereb.page + 1;
|
||||
that.getInitchecked(that.bought);
|
||||
},
|
||||
error => {
|
||||
|
||||
console.log(error.msg)
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
|
||||
|
||||
/*获取初始化选中的数据*/
|
||||
getInitchecked(arr) {
|
||||
let that = this;
|
||||
arr.forEach((item, index) => {
|
||||
that.$set(item, 'check', false);
|
||||
that.checkedArr.forEach((val, i) => {
|
||||
if (item.product_id == val.product_id) {
|
||||
that.$set(item, 'check', true);
|
||||
that.$set(item, 'number', val.number);
|
||||
that.$set(item, 'price', val.price);
|
||||
that.peicenumber = val.number
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
},
|
||||
/*已选中的商品打钩*/
|
||||
getCheckedGoods() {
|
||||
this.checked = []
|
||||
this.checkedArr.forEach((item, index) => {
|
||||
this.checkedArr.push(item)
|
||||
})
|
||||
},
|
||||
/*点击选中与否*/
|
||||
goodsCheck(item) {
|
||||
this.$set(item, 'check', !item.check);
|
||||
if (item.check) {
|
||||
this.checkedArr.push(item)
|
||||
|
||||
} else {
|
||||
this.checkedArr.splice(this.checkedArr.findIndex(itemn => ((itemn.product_id == item.product_id))), 1)
|
||||
}
|
||||
},
|
||||
|
||||
/*确定提交*/
|
||||
submit() {
|
||||
this.$emit('getProduct', this.checkedArr);
|
||||
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.containers {
|
||||
background: #ffffff;
|
||||
border-radius: 16rpx 16rpx 0 0;
|
||||
padding: 40rpx 0;
|
||||
position: relative;
|
||||
|
||||
.header {
|
||||
position: relative;
|
||||
padding: 0 30rpx;
|
||||
|
||||
.title {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
|
||||
text {
|
||||
position: relative;
|
||||
margin: 0 50rpx;
|
||||
color: #999999;
|
||||
font-size: 30rpx;
|
||||
|
||||
&.on {
|
||||
color: #333333;
|
||||
font-weight: bold;
|
||||
font-size: 34rpx;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
width: 40rpx;
|
||||
height: 5rpx;
|
||||
background: var(--view-theme);
|
||||
position: absolute;
|
||||
bottom: -10rpx;
|
||||
left: 10rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.iconclose {
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
line-height: 44rpx;
|
||||
|
||||
border-radius: 50%;
|
||||
text-align: center;
|
||||
|
||||
position: absolute;
|
||||
top: -150rpx;
|
||||
right: 30rpx;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.sub_title {
|
||||
color: #282828;
|
||||
font-size: 26rpx;
|
||||
margin-top: 30rpx;
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
color: #8A8A8A;
|
||||
font-size: 28rpx;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 30rpx;
|
||||
}
|
||||
}
|
||||
|
||||
scroll-view {
|
||||
height: 650rpx;
|
||||
}
|
||||
|
||||
.main {
|
||||
height: 650rpx;
|
||||
margin: 40rpx 0 80rpx;
|
||||
padding: 0 30rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.picTxt {
|
||||
width: 100%;
|
||||
padding: 25rpx 0;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
border-top: 2rpx solid #E7E6E4;
|
||||
|
||||
.picTxt_one {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.picTxt_one {
|
||||
display: flex;
|
||||
margin-top: 20rpx;
|
||||
|
||||
|
||||
.slecte {
|
||||
margin-right: 30rpx;
|
||||
width: 280rpx;
|
||||
height: 60rpx;
|
||||
line-height: 60rpx;
|
||||
text-align: center;
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #959595;
|
||||
background-color: #E7E6E4;
|
||||
border-radius: 10rpx 10rpx 10rpx 10rpx;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.checkbox {
|
||||
margin-right: 30rpx;
|
||||
|
||||
.iconfont {
|
||||
font-size: 38rpx;
|
||||
color: #CCCCCC;
|
||||
}
|
||||
|
||||
.icon-xuanzhong1 {
|
||||
color: var(--view-theme);
|
||||
}
|
||||
|
||||
.disabled {
|
||||
pointer-events: none;
|
||||
cursor: default;
|
||||
opacity: 0.3;
|
||||
}
|
||||
}
|
||||
|
||||
.pictrue {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.text {
|
||||
width: 430rpx;
|
||||
margin-left: 30rpx;
|
||||
font-size: 28rpx;
|
||||
color: #282828;
|
||||
position: relative;
|
||||
height: 160rpx;
|
||||
|
||||
.name {
|
||||
color: #282828;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.money {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
color: var(--view-priceColor);
|
||||
font-size: 22rpx;
|
||||
font-weight: bold;
|
||||
|
||||
text {
|
||||
font-size: 26rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.foot_bar {
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
// bottom: 54px;
|
||||
left: 0;
|
||||
padding: 20rpx 0;
|
||||
z-index: 5;
|
||||
|
||||
.confirm_btn {
|
||||
width: 710rpx;
|
||||
height: 86rpx;
|
||||
line-height: 86rpx;
|
||||
color: #ffffff;
|
||||
text-align: center;
|
||||
font-size: 32rpx;
|
||||
background-color: red;
|
||||
border-radius: 43rpx;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
.empty {
|
||||
margin: 130rpx 0 150rpx;
|
||||
text-align: center;
|
||||
|
||||
image,
|
||||
uni-image {
|
||||
display: inline-block;
|
||||
width: 414rpx;
|
||||
height: 305rpx;
|
||||
}
|
||||
|
||||
text {
|
||||
display: block;
|
||||
color: #999999;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,217 @@
|
|||
<template>
|
||||
<view class="uni-numbox">
|
||||
<!-- -部分 -->
|
||||
<view class="uni-numbox-minus" @click="_calcValue('subtract')">
|
||||
<text :class="minDisabled?'uni-numbox-disabled': ''">-</text>
|
||||
</view>
|
||||
<!-- 中间输入数值部分 -->
|
||||
<input class="uni-numbox-value" type="number" :disabled="disabled" :value="inputValue" @blur="_onBlur">
|
||||
<!-- + 部分 -->
|
||||
<view class="uni-numbox-plus" @click="_calcValue('add')">
|
||||
<text :class="maxDisabled?'uni-numbox-disabled': ''">+</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'uni-number-box',
|
||||
props: {
|
||||
// isMax 是否有上限设置
|
||||
isMax: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// isMin 是否有下限设置
|
||||
isMin: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// index 唯一值,如果一个页面有多个数量增减组件时,起到唯一的作用
|
||||
index: {
|
||||
type: String,
|
||||
default: 0
|
||||
},
|
||||
// value 是数值
|
||||
value: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
// min 最小值
|
||||
min: {
|
||||
type: Number,
|
||||
default: -Infinity
|
||||
},
|
||||
// max 最大值
|
||||
max: {
|
||||
type: Number,
|
||||
default: Infinity
|
||||
},
|
||||
// step 步长
|
||||
step: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
// disabled 是否禁用
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
inputValue: this.value,
|
||||
minDisabled: false,
|
||||
maxDisabled: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.maxDisabled = this.isMax;
|
||||
this.minDisabled = this.isMin;
|
||||
},
|
||||
computed: {
|
||||
|
||||
},
|
||||
watch: {
|
||||
inputValue(number) {
|
||||
const data = {
|
||||
number: number,
|
||||
index: this.index
|
||||
}
|
||||
this.$emit('eventChange', data);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
_calcValue(type) {
|
||||
const scale = this._getDecimalScale();
|
||||
let value = this.inputValue * scale;
|
||||
let newValue = 0;
|
||||
let step = this.step * scale;
|
||||
|
||||
if (type === 'subtract') {
|
||||
newValue = value - step;
|
||||
if (newValue <= this.min) {
|
||||
this.minDisabled = true;
|
||||
}
|
||||
if (newValue < this.min) {
|
||||
newValue = this.min
|
||||
this.$util.Tips({
|
||||
title: '达到最小值了',
|
||||
icon: 'error'
|
||||
})
|
||||
}
|
||||
if (newValue < this.max && this.maxDisabled === true) {
|
||||
this.maxDisabled = false;
|
||||
}
|
||||
} else if (type === 'add') {
|
||||
newValue = value + step;
|
||||
if (newValue >= this.max) {
|
||||
this.maxDisabled = true;
|
||||
}
|
||||
if (newValue > this.max) {
|
||||
this.$util.Tips({
|
||||
title: '达到最大值了',
|
||||
icon: 'error'
|
||||
})
|
||||
newValue = this.max
|
||||
}
|
||||
if (newValue > this.min && this.minDisabled === true) {
|
||||
this.minDisabled = false;
|
||||
}
|
||||
}
|
||||
if (newValue === value) {
|
||||
return;
|
||||
}
|
||||
this.inputValue = newValue / scale;
|
||||
this.$emit('increment', this.inputValue)
|
||||
},
|
||||
_getDecimalScale() {
|
||||
let scale = 1;
|
||||
// 浮点型
|
||||
if (~~this.step !== this.step) {
|
||||
scale = Math.pow(10, (this.step + '').split('.')[1].length);
|
||||
}
|
||||
return scale;
|
||||
},
|
||||
_onBlur(event) {
|
||||
let value = event.detail.value;
|
||||
if (!value) {
|
||||
this.inputValue = 0;
|
||||
return
|
||||
}
|
||||
value = +value;
|
||||
if (value > this.max) {
|
||||
value = this.max;
|
||||
} else if (value < this.min) {
|
||||
value = this.min
|
||||
}
|
||||
|
||||
this.inputValue = value
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.uni-numbox {
|
||||
/* position:absolute; */
|
||||
/* left: 30upx;
|
||||
bottom: 0; */
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
width: 200upx;
|
||||
height: 50upx;
|
||||
/* background:#f5f5f5; */
|
||||
}
|
||||
|
||||
.uni-numbox-minus {
|
||||
background: #EEEEEE !important;
|
||||
|
||||
color: #909399 !important;
|
||||
}
|
||||
|
||||
.uni-numbox-minus,
|
||||
.uni-numbox-plus {
|
||||
margin: 0;
|
||||
width: 53rpx;
|
||||
height: 53rpx;
|
||||
background-color: #F84221;
|
||||
opacity: 1;
|
||||
line-height: 53rpx;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
color: #fff;
|
||||
font-size: 40upx;
|
||||
}
|
||||
|
||||
.uni-numbox-minus .yticon,
|
||||
.uni-numbox-plus .yticon {
|
||||
font-size: 36upx;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.uni-numbox-minus {
|
||||
/* border-right: none;
|
||||
border-top-left-radius: 6upx;
|
||||
border-bottom-left-radius: 6upx; */
|
||||
}
|
||||
|
||||
.uni-numbox-plus {
|
||||
/* border-left: none;
|
||||
border-top-right-radius: 6upx;
|
||||
border-bottom-right-radius: 6upx; */
|
||||
}
|
||||
|
||||
.uni-numbox-value {
|
||||
position: relative;
|
||||
/* background-color: #f5f5f5; */
|
||||
width: 90upx;
|
||||
height: 50upx;
|
||||
text-align: center;
|
||||
padding: 0;
|
||||
font-size: 30upx;
|
||||
}
|
||||
|
||||
.uni-numbox-disabled.yticon {
|
||||
color: #d6d6d6;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,241 @@
|
|||
<template>
|
||||
<view v-if="showPopup" class="uni-popup" @touchmove.stop.prevent="clear">
|
||||
<uni-transition :mode-class="['fade']" :styles="maskClass" :show="showTrans" @click="onTap" />
|
||||
<uni-transition :mode-class="ani" :styles="transClass" :show="showTrans" @click="onTap">
|
||||
<view class="uni-popup__wrapper-box" @click.stop="clear">
|
||||
<slot />
|
||||
</view>
|
||||
</uni-transition>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
|
||||
|
||||
props: {
|
||||
// 开启动画
|
||||
animation: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 弹出层类型,可选值,top: 顶部弹出层;bottom:底部弹出层;center:全屏弹出层
|
||||
type: {
|
||||
type: String,
|
||||
default: 'center'
|
||||
},
|
||||
// maskClick
|
||||
maskClick: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
ani: [],
|
||||
showPopup: false,
|
||||
showTrans: false,
|
||||
maskClass: {
|
||||
'position': 'fixed',
|
||||
'bottom': 0,
|
||||
'top': 0,
|
||||
'left': 0,
|
||||
'right': 0,
|
||||
'backgroundColor': 'rgba(0, 0, 0, 0)'
|
||||
},
|
||||
transClass: {
|
||||
'position': 'fixed',
|
||||
'left': 0,
|
||||
'right': 0,
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
type: {
|
||||
handler: function(newVal) {
|
||||
switch (this.type) {
|
||||
case 'top':
|
||||
this.ani = ['slide-top']
|
||||
this.transClass = {
|
||||
'position': 'fixed',
|
||||
'left': 0,
|
||||
'right': 0,
|
||||
}
|
||||
break
|
||||
case 'bottom':
|
||||
this.ani = ['slide-bottom']
|
||||
this.transClass = {
|
||||
'position': 'fixed',
|
||||
'left': 0,
|
||||
'right': 0,
|
||||
'bottom': 0
|
||||
}
|
||||
console.log('直播调用弹窗')
|
||||
break
|
||||
case 'center':
|
||||
this.ani = ['zoom-out', 'fade']
|
||||
this.transClass = {
|
||||
'position': 'fixed',
|
||||
/* #ifndef APP-NVUE */
|
||||
'display': 'flex',
|
||||
'flexDirection': 'column',
|
||||
/* #endif */
|
||||
'bottom': 0,
|
||||
'left': 0,
|
||||
'right': 0,
|
||||
'top': 0,
|
||||
'justifyContent': 'center',
|
||||
'alignItems': 'center'
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
created() {},
|
||||
methods: {
|
||||
clear(e) {
|
||||
// TODO nvue 取消冒泡
|
||||
e.stopPropagation()
|
||||
},
|
||||
open() {
|
||||
this.showPopup = true
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.showTrans = true
|
||||
}, 0);
|
||||
})
|
||||
this.$emit('change', {
|
||||
show: true
|
||||
})
|
||||
},
|
||||
close(type) {
|
||||
this.showTrans = false
|
||||
this.$nextTick(() => {
|
||||
clearTimeout(this.timer)
|
||||
this.timer = setTimeout(() => {
|
||||
this.$emit('change', {
|
||||
show: false
|
||||
})
|
||||
this.showPopup = false
|
||||
}, 0)
|
||||
})
|
||||
},
|
||||
onTap() {
|
||||
if (!this.maskClick) return
|
||||
this.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.uni-popup {
|
||||
position: fixed;
|
||||
/* #ifdef H5 */
|
||||
top: var(--window-top);
|
||||
/* #endif */
|
||||
/* #ifndef H5 */
|
||||
top: 0;
|
||||
/* #endif */
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
/* #ifndef APP-NVUE */
|
||||
z-index: 99;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-popup__mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.mask-ani {
|
||||
transition-property: opacity;
|
||||
transition-duration: 0.2s;
|
||||
}
|
||||
|
||||
.uni-top-mask {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.uni-bottom-mask {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.uni-center-mask {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: block;
|
||||
/* #endif */
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.top {
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
transform: translateY(-500px);
|
||||
}
|
||||
|
||||
.bottom {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
transform: translateY(500px);
|
||||
}
|
||||
|
||||
.center {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
/* #endif */
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
transform: scale(1.2);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper-box {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: block;
|
||||
/* #endif */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.content-ani {
|
||||
/* transition: transform 0.3s;
|
||||
*/
|
||||
transition-property: transform, opacity;
|
||||
transition-duration: 0.2s;
|
||||
}
|
||||
|
||||
|
||||
.uni-top-content {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.uni-bottom-content {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.uni-center-content {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,241 @@
|
|||
<template>
|
||||
<view v-if="showPopup" class="uni-popup" @touchmove.stop.prevent="clear">
|
||||
<uni-transition :mode-class="['fade']" :styles="maskClass" :show="showTrans" @click="onTap" />
|
||||
<uni-transition :mode-class="ani" :styles="transClass" :show="showTrans" @click="onTap">
|
||||
<view class="uni-popup__wrapper-box" @click.stop="clear">
|
||||
<slot />
|
||||
</view>
|
||||
</uni-transition>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
|
||||
props: {
|
||||
// 开启动画
|
||||
animation: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 弹出层类型,可选值,top: 顶部弹出层;bottom:底部弹出层;center:全屏弹出层
|
||||
type: {
|
||||
type: String,
|
||||
default: 'center'
|
||||
},
|
||||
// maskClick
|
||||
maskClick: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
ani: [],
|
||||
showPopup: false,
|
||||
showTrans: false,
|
||||
maskClass: {
|
||||
'position': 'fixed',
|
||||
'bottom': 0,
|
||||
'top': 0,
|
||||
'left': 0,
|
||||
'right': 0,
|
||||
'backgroundColor': 'rgba(0, 0, 0, 0.4)'
|
||||
},
|
||||
transClass: {
|
||||
'position': 'fixed',
|
||||
'left': 0,
|
||||
'right': 0,
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
type: {
|
||||
handler: function(newVal) {
|
||||
switch (this.type) {
|
||||
case 'top':
|
||||
this.ani = ['slide-top']
|
||||
this.transClass = {
|
||||
'position': 'fixed',
|
||||
'left': 0,
|
||||
'right': 0,
|
||||
}
|
||||
break
|
||||
case 'bottom':
|
||||
this.ani = ['slide-bottom']
|
||||
this.transClass = {
|
||||
'position': 'fixed',
|
||||
'left': 0,
|
||||
'right': 0,
|
||||
'bottom': 0
|
||||
}
|
||||
console.log('底部条用')
|
||||
console.log(this.type)
|
||||
break
|
||||
case 'center':
|
||||
this.ani = ['zoom-out', 'fade']
|
||||
this.transClass = {
|
||||
'position': 'fixed',
|
||||
/* #ifndef APP-NVUE */
|
||||
'display': 'flex',
|
||||
'flexDirection': 'column',
|
||||
/* #endif */
|
||||
'bottom': 0,
|
||||
'left': 0,
|
||||
'right': 0,
|
||||
'top': 0,
|
||||
'justifyContent': 'center',
|
||||
'alignItems': 'center'
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
created() {},
|
||||
methods: {
|
||||
clear(e) {
|
||||
// TODO nvue 取消冒泡
|
||||
e.stopPropagation()
|
||||
},
|
||||
open() {
|
||||
this.showPopup = true
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.showTrans = true
|
||||
}, 50);
|
||||
})
|
||||
this.$emit('change', {
|
||||
show: true
|
||||
})
|
||||
},
|
||||
close(type) {
|
||||
this.showTrans = false
|
||||
this.$nextTick(() => {
|
||||
clearTimeout(this.timer)
|
||||
this.timer = setTimeout(() => {
|
||||
this.$emit('change', {
|
||||
show: false
|
||||
})
|
||||
this.showPopup = false
|
||||
}, 300)
|
||||
})
|
||||
},
|
||||
onTap() {
|
||||
if (!this.maskClick) return
|
||||
this.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.uni-popup {
|
||||
position: fixed;
|
||||
/* #ifdef H5 */
|
||||
top: var(--window-top);
|
||||
/* #endif */
|
||||
/* #ifndef H5 */
|
||||
top: 0;
|
||||
/* #endif */
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
/* #ifndef APP-NVUE */
|
||||
z-index: 99;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-popup__mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.mask-ani {
|
||||
transition-property: opacity;
|
||||
transition-duration: 0.2s;
|
||||
}
|
||||
|
||||
.uni-top-mask {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.uni-bottom-mask {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.uni-center-mask {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: block;
|
||||
/* #endif */
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.top {
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
transform: translateY(-500px);
|
||||
}
|
||||
|
||||
.bottom {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
transform: translateY(500px);
|
||||
}
|
||||
|
||||
.center {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
/* #endif */
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
transform: scale(1.2);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper-box {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: block;
|
||||
/* #endif */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.content-ani {
|
||||
/* transition: transform 0.3s;
|
||||
*/
|
||||
transition-property: transform, opacity;
|
||||
transition-duration: 0.2s;
|
||||
}
|
||||
|
||||
|
||||
.uni-top-content {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.uni-bottom-content {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.uni-center-content {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,12 @@
|
|||
// import CryptoJS from './crypto-js.js'
|
||||
/**
|
||||
* @word 要加密的内容
|
||||
* @keyWord String 服务器随机返回的关键字
|
||||
* */
|
||||
export function aesEncrypt(word,keyWord="XwKsGlMcdPMEhR1B"){
|
||||
// var key = CryptoJS.enc.Utf8.parse(keyWord);
|
||||
// var srcs = CryptoJS.enc.Utf8.parse(word);
|
||||
// var encrypted = CryptoJS.AES.encrypt(srcs, key, {mode:CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});
|
||||
// return encrypted.toString();
|
||||
return word
|
||||
}
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,544 @@
|
|||
<template>
|
||||
<view style="position: relative">
|
||||
<view class="verify-image-out" v-show="showImage">
|
||||
<view class="verify-image-panel" :style="{'width': imgSize.width,
|
||||
'height': imgSize.height,
|
||||
'margin-bottom': vSpace + 'px'}">
|
||||
<view class="verify-refresh" style="z-index:3" @click="refresh" v-show="showRefresh">
|
||||
<text class="iconfont icon-refresh"></text>
|
||||
</view>
|
||||
<image :src="pointBackImgBase?('data:image/png;base64,'+pointBackImgBase):defaultImg" id="image"
|
||||
ref="canvas" style="width:100%;height:100%;display:block"
|
||||
@click=" bindingClick? canvasClick($event): undefined"></image>
|
||||
<view v-for="(tempPoint, index) in tempPoints" :key="index" class="point-area" :style="{
|
||||
'background-color':'#1abd6c',
|
||||
color:'#fff',
|
||||
'z-index':9999,
|
||||
width:'20px',
|
||||
height:'20px',
|
||||
'text-align':'center',
|
||||
'line-height':'20px',
|
||||
'border-radius': '50%',
|
||||
position:'absolute',
|
||||
top:parseInt(tempPoint.y-10) + 'px',
|
||||
left:parseInt(tempPoint.x-10) + 'px'
|
||||
}">
|
||||
{{index + 1}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 'height': this.barSize.height, -->
|
||||
<view class="verify-bar-area" :style="{'width': imgSize.width,
|
||||
'color': barAreaColor,
|
||||
'border-color': barAreaBorderColor,
|
||||
'line-height':'40px'}">
|
||||
<text class="verify-msg">{{text}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script type="text/babel">
|
||||
/**
|
||||
* VerifyPoints
|
||||
* @description 点选
|
||||
* */
|
||||
import {aesEncrypt} from "./../utils/ase.js"
|
||||
import {getAjcaptcha,ajcaptchaCheck} from '@/api/api.js';
|
||||
|
||||
export default {
|
||||
name: 'VerifyPoints',
|
||||
props: {
|
||||
//弹出式pop,固定fixed
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'fixed'
|
||||
},
|
||||
captchaType:{
|
||||
type:String,
|
||||
},
|
||||
//间隔
|
||||
vSpace: {
|
||||
type: Number,
|
||||
default: 5
|
||||
},
|
||||
imgSize: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
width: '310px',
|
||||
height: '155px'
|
||||
}
|
||||
}
|
||||
},
|
||||
barSize: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
width: '310px',
|
||||
height: '40px'
|
||||
}
|
||||
}
|
||||
},
|
||||
defaultImg: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
secretKey:'', //后端返回的加密秘钥 字段
|
||||
checkNum:3, //
|
||||
fontPos: [], // 选中的坐标信息
|
||||
checkPosArr: [], //用户点击的坐标
|
||||
num: 1, //点击的记数
|
||||
pointBackImgBase:'', //后端获取到的背景图片
|
||||
poinTextList:[], //后端返回的点击字体顺序
|
||||
backToken:'', //后端返回的token值
|
||||
imgRand: 0, //随机的背景图片
|
||||
setSize: {
|
||||
imgHeight: 0,
|
||||
imgWidth: 0,
|
||||
barHeight: 0,
|
||||
barWidth: 0
|
||||
},
|
||||
showImage: true,
|
||||
tempPoints: [],
|
||||
text: '',
|
||||
barAreaColor: '#fff',
|
||||
barAreaBorderColor: "#fff",
|
||||
showRefresh: true,
|
||||
bindingClick: true,
|
||||
imgLeft:'' ,
|
||||
imgTop:'',
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
//加载页面
|
||||
this.fontPos.splice(0, this.fontPos.length)
|
||||
this.checkPosArr.splice(0, this.checkPosArr.length)
|
||||
this.num = 1
|
||||
this.$nextTick(() => {
|
||||
this.refresh();
|
||||
this.$parent.$emit('ready', this)
|
||||
})
|
||||
},
|
||||
canvasClick(e) {
|
||||
const query = uni.createSelectorQuery().in(this);
|
||||
query.select('#image').boundingClientRect(data => {
|
||||
this.imgLeft =Math.ceil(data.left)
|
||||
this.imgTop =Math.ceil(data.top)
|
||||
this.checkPosArr.push(this.getMousePos(this.$refs.canvas, e));
|
||||
if (this.num == this.checkNum) {
|
||||
this.num = this.createPoint(this.getMousePos(this.$refs.canvas, e));
|
||||
//按比例转换坐标值
|
||||
this.checkPosArr = this.pointTransfrom(this.checkPosArr,this.imgSize);
|
||||
//等创建坐标执行完
|
||||
setTimeout(() => {
|
||||
//发送后端请求
|
||||
var captchaVerification =this.secretKey? aesEncrypt(this.backToken+'---'+JSON.stringify(this.checkPosArr),this.secretKey):this.backToken+'---'+JSON.stringify(this.checkPosArr)
|
||||
let data = {
|
||||
captchaType:this.captchaType,
|
||||
"pointJson":this.secretKey? aesEncrypt(JSON.stringify(this.checkPosArr),this.secretKey):JSON.stringify(this.checkPosArr),
|
||||
"token":this.backToken
|
||||
}
|
||||
ajcaptchaCheck(data).then(result => {
|
||||
let res = result.data
|
||||
this.barAreaColor = '#4cae4c'
|
||||
this.barAreaBorderColor = '#5cb85c'
|
||||
this.text = '验证成功'
|
||||
this.bindingClick = false
|
||||
setTimeout(()=>{
|
||||
if (this.mode=='pop') {
|
||||
this.$parent.clickShow = false;
|
||||
}
|
||||
this.refresh();
|
||||
},1500)
|
||||
this.$parent.$emit('success', {captchaVerification})
|
||||
}).catch(res=>{
|
||||
this.$parent.$emit('error', this)
|
||||
this.barAreaColor = '#d9534f'
|
||||
this.barAreaBorderColor = '#d9534f'
|
||||
this.text = '验证失败'
|
||||
setTimeout(() => {
|
||||
this.refresh();
|
||||
}, 700);
|
||||
})
|
||||
}, 400);
|
||||
}
|
||||
if (this.num < this.checkNum) {
|
||||
this.num = this.createPoint(this.getMousePos(this.$refs.canvas, e));
|
||||
}
|
||||
}).exec();
|
||||
},
|
||||
//获取坐标
|
||||
getMousePos: function (obj, e) {
|
||||
let position = {
|
||||
x:Math.ceil(e.detail.x)-this.imgLeft,
|
||||
y:Math.ceil(e.detail.y)-this.imgTop,
|
||||
}
|
||||
return position
|
||||
},
|
||||
//创建坐标点
|
||||
createPoint: function (pos) {
|
||||
this.tempPoints.push(Object.assign({}, pos))
|
||||
return ++this.num;
|
||||
},
|
||||
refresh: function () {
|
||||
this.tempPoints.splice(0, this.tempPoints.length)
|
||||
this.barAreaColor = '#000'
|
||||
this.barAreaBorderColor = '#ddd'
|
||||
this.bindingClick = true
|
||||
|
||||
this.fontPos.splice(0, this.fontPos.length)
|
||||
this.checkPosArr.splice(0, this.checkPosArr.length)
|
||||
this.num = 1
|
||||
|
||||
this.getPictrue();
|
||||
|
||||
// this.text = '验证失败'
|
||||
this.showRefresh = true
|
||||
},
|
||||
// 请求背景图片和验证图片
|
||||
getPictrue(){
|
||||
let data = {
|
||||
captchaType:this.captchaType,
|
||||
clientUid: uni.getStorageSync('point'),
|
||||
ts: Date.now(), // 现在的时间戳
|
||||
}
|
||||
getAjcaptcha(data).then((result) => {
|
||||
let res = result.data
|
||||
this.pointBackImgBase = res.originalImageBase64
|
||||
this.backToken = res.token
|
||||
this.secretKey = res.secretKey
|
||||
this.poinTextList = res.wordList
|
||||
this.text = '请依次点击【' + this.poinTextList.join(",") + '】'
|
||||
}).catch(()=>{
|
||||
this.pointBackImgBase = null
|
||||
})
|
||||
},
|
||||
//坐标转换函数
|
||||
pointTransfrom(pointArr,imgSize){
|
||||
var newPointArr = pointArr.map(p=>{
|
||||
let x = Math.round(310 * p.x/parseInt(imgSize.width))
|
||||
let y =Math.round(155 * p.y/parseInt(imgSize.height))
|
||||
return {x,y}
|
||||
})
|
||||
// console.log(newPointArr,"newPointArr");
|
||||
return newPointArr
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
// type变化则全面刷新
|
||||
type: {
|
||||
immediate: true,
|
||||
handler() {
|
||||
this.init()
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// console.log(this.defaultImg)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.verifybox {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #e4e7eb;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, .3);
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.verifybox-top {
|
||||
padding: 0 15px;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
text-align: left;
|
||||
font-size: 16px;
|
||||
color: #45494c;
|
||||
border-bottom: 1px solid #e4e7eb;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.verifybox-bottom {
|
||||
/* padding: 15px; */
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.verifybox-close {
|
||||
position: absolute;
|
||||
top: 13px;
|
||||
right: 9px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1001;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
background: rgba(0, 0, 0, .3);
|
||||
/* display: none; */
|
||||
transition: all .5s;
|
||||
}
|
||||
|
||||
.verify-tips {
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
bottom: 0px;
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
background-color: rgb(231, 27, 27, .5);
|
||||
line-height: 30px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.tips-enter,
|
||||
.tips-leave-to {
|
||||
bottom: -30px;
|
||||
}
|
||||
|
||||
.tips-enter-active,
|
||||
.tips-leave-active {
|
||||
transition: bottom .5s;
|
||||
}
|
||||
|
||||
/* ---------------------------- */
|
||||
/*常规验证码*/
|
||||
.verify-code {
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
margin-bottom: 5px;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.cerify-code-panel {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.verify-code-area {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.verify-input-area {
|
||||
float: left;
|
||||
width: 60%;
|
||||
padding-right: 10px;
|
||||
|
||||
}
|
||||
|
||||
.verify-change-area {
|
||||
line-height: 30px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.varify-input-code {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
.verify-change-code {
|
||||
color: #337AB7;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.verify-btn {
|
||||
width: 200px;
|
||||
height: 30px;
|
||||
background-color: #337AB7;
|
||||
color: #FFFFFF;
|
||||
border: none;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
|
||||
/*滑动验证码*/
|
||||
.verify-bar-area {
|
||||
position: relative;
|
||||
background: #FFFFFF;
|
||||
text-align: center;
|
||||
-webkit-box-sizing: content-box;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
border: 1px solid #ddd;
|
||||
-webkit-border-radius: 4px;
|
||||
}
|
||||
|
||||
.verify-bar-area .verify-move-block {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0;
|
||||
background: #fff;
|
||||
cursor: pointer;
|
||||
-webkit-box-sizing: content-box;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
box-shadow: 0 0 2px #888888;
|
||||
-webkit-border-radius: 1px;
|
||||
}
|
||||
|
||||
.verify-bar-area .verify-move-block:hover {
|
||||
background-color: #337ab7;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.verify-bar-area .verify-left-bar {
|
||||
position: absolute;
|
||||
top: -1px;
|
||||
left: -1px;
|
||||
background: #f0fff0;
|
||||
cursor: pointer;
|
||||
-webkit-box-sizing: content-box;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.verify-image-panel {
|
||||
margin: 0;
|
||||
-webkit-box-sizing: content-box;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
border-top: 1px solid #ddd;
|
||||
border-bottom: 1px solid #ddd;
|
||||
border-radius: 3px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.verify-image-panel .verify-refresh {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
text-align: center;
|
||||
padding: 5px;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.verify-image-panel .icon-refresh {
|
||||
font-size: 20px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.verify-image-panel .verify-gap {
|
||||
background-color: #fff;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
border: 1px solid #fff;
|
||||
}
|
||||
|
||||
.verify-bar-area .verify-move-block .verify-sub-block {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
z-index: 3;
|
||||
/* border: 1px solid #fff; */
|
||||
}
|
||||
|
||||
.verify-bar-area .verify-move-block .verify-icon {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.verify-bar-area .verify-msg {
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
/*字体图标的css*/
|
||||
/*@font-face {font-family: "iconfont";*/
|
||||
/*src: url('../fonts/iconfont.eot?t=1508229193188'); !* IE9*!*/
|
||||
/*src: url('../fonts/iconfont.eot?t=1508229193188#iefix') format('embedded-opentype'), !* IE6-IE8 *!*/
|
||||
/*url('data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAAaAAAsAAAAACUwAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAADMAAABCsP6z7U9TLzIAAAE8AAAARAAAAFZW7kiSY21hcAAAAYAAAAB3AAABuM+qBlRnbHlmAAAB+AAAAnQAAALYnrUwT2hlYWQAAARsAAAALwAAADYPNwajaGhlYQAABJwAAAAcAAAAJAfeA4dobXR4AAAEuAAAABMAAAAYF+kAAGxvY2EAAATMAAAADgAAAA4CvAGsbWF4cAAABNwAAAAfAAAAIAEVAF1uYW1lAAAE/AAAAUUAAAJtPlT+fXBvc3QAAAZEAAAAPAAAAE3oPPXPeJxjYGRgYOBikGPQYWB0cfMJYeBgYGGAAJAMY05meiJQDMoDyrGAaQ4gZoOIAgCKIwNPAHicY2Bk/sM4gYGVgYOpk+kMAwNDP4RmfM1gxMjBwMDEwMrMgBUEpLmmMDgwVDxbwtzwv4EhhrmBoQEozAiSAwAw1A0UeJzFkcENgCAMRX8RjCGO4gTe9eQcnhzAfXC2rqG/hYsT8MmD9gdS0gJIAAaykAjIBYHppCvuD8juR6zMJ67A89Zdn/f1aNPikUn8RvYo8G20CjKim6Rf6b9m34+WWd/vBr+oW8V6q3vF5qKlYrPRp4L0Ad5nGL8AeJxFUc9rE0EYnTezu8lMsrvtbrqb3TRt0rS7bdOmdI0JbWmCtiItIv5oi14qevCk9SQVLFiQgqAF8Q9QLKIHLx48FkHo3ZNnFUXwD5C2B6dO6sFhmI83w7z3fe8RnZCjb2yX5YlLhskkmScXCIFRxYBFiyjH9Rqtoqes9/g5i8WVuJyqDNTYLPwBI+cljXrkGynDhoU+nCgnjbhGY5yst+gMEq8IBIXwsjPU67CnEPm4b0su0h309Fd67da4XBhr55KSm17POk7gOE/Shq6nKdVsC7d9j+tcGPKVboc9u/0jtB/ZIA7PXTVLBef6o/paccjnwOYm3ELJetPuDrvV3gg91wlSXWY6H5qVwRzWf2TybrYYfSdqoXOwh/Qa8RWIjBTiSI3h614/vKSNRhONOrsnQi6Xf4nQFQDTmJE1NKbhI6crHEJO/+S5QPxhYJRRyvBFBP+5T9EPpEAIVzzRQIrjmJ6jY1WTo+NXTMchuBsKuS8PRZATSMl9oTA4uNLkeIA0V1UeqOoGQh7IAxGo+7T83fn3T+voqCNPPAUazUYUI7LgKSV1Jk2oUeghYGhZ+cKOe2FjVu5ZKEY2VkE13AK1+jI4r1KLbPlZfrKiPhOXKPRj7q9sj9XJ7LFHNmrKJS3VCdhXGSdKrtmoQaWeMjQVt0KD6sGPOx0oH2fgtzoNROxtNq8F3tzYM/n+TjKSX5qf2jx941276TIr9FjXxKr8eX/6bK4yuopwo9py1sw8F9kdw4AmurRpLUM3tYx5ZnKpfHPi8dzz19vJ6MjyxYUrpqeb1uLs3eGV6vr21pSqpeWkqonAN9oUyIiXpv8XvlN5e3icY2BkYGAA4n0vN4fG89t8ZeBmYQCBa9wPPRH0/wcsDMwmQC4HAxNIFABAfAqaAHicY2BkYGBu+N/AEMPCAAJAkpEBFbABAEcMAm94nGNhYGBgfsnAwMKAigESnwEBAAAAAAAAdgCkANoBCAFsAAB4nGNgZGBgYGMIZGBlAAEmIOYCQgaG/2A+AwARSAFzAHicZY9NTsMwEIVf+gekEqqoYIfkBWIBKP0Rq25YVGr3XXTfpk6bKokjx63UA3AejsAJOALcgDvwSCebNpbH37x5Y08A3OAHHo7fLfeRPVwyO3INF7gXrlN/EG6QX4SbaONVuEX9TdjHM6bCbXRheYPXuGL2hHdhDx18CNdwjU/hOvUv4Qb5W7iJO/wKt9Dx6sI+5l5XuI1HL/bHVi+cXqnlQcWhySKTOb+CmV7vkoWt0uqca1vEJlODoF9JU51pW91T7NdD5yIVWZOqCas6SYzKrdnq0AUb5/JRrxeJHoQm5Vhj/rbGAo5xBYUlDowxQhhkiMro6DtVZvSvsUPCXntWPc3ndFsU1P9zhQEC9M9cU7qy0nk6T4E9XxtSdXQrbsuelDSRXs1JErJCXta2VELqATZlV44RelzRiT8oZ0j/AAlabsgAAAB4nGNgYoAALgbsgI2RiZGZkYWRlZGNkZ2BsYI1OSM1OZs1OSe/OJW1KDM9o4S9KDWtKLU4g4EBAJ79CeQ=') format('woff'),*/
|
||||
/*url('../fonts/iconfont.ttf?t=1508229193188') format('truetype'), !* chrome, firefox, opera, Safari, Android, iOS 4.2+*!*/
|
||||
/*url('../fonts/iconfont.svg?t=1508229193188#iconfont') format('svg'); !* iOS 4.1- *!*/
|
||||
/*}*/
|
||||
|
||||
.iconfont {
|
||||
font-family: "iconfont" !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-check:before {
|
||||
content: " ";
|
||||
display: block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
position: absolute;
|
||||
margin: auto;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
z-index: 9999;
|
||||
background-image: url("@/static/images/arrow-good.png");
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
.icon-close:before {
|
||||
content: " ";
|
||||
display: block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
position: absolute;
|
||||
margin: auto;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
z-index: 9999;
|
||||
background-image: url("@/static/images/arrow-close.png");
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
.icon-right:before {
|
||||
content: " ";
|
||||
display: block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
position: absolute;
|
||||
margin: auto;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
background-size: cover;
|
||||
z-index: 9999;
|
||||
background-image: url("@/static/images/arrow-right.png");
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
.icon-refresh:before {
|
||||
content: " ";
|
||||
display: block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
position: absolute;
|
||||
margin: auto;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
z-index: 9999;
|
||||
background-image: url("@/static/images/refresh.png");
|
||||
background-size: contain;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,648 @@
|
|||
<template>
|
||||
<view style="position: relative;">
|
||||
<view v-if="type === '2'" class="verify-img-out" :style="{height: (parseInt(imgSize.height) + vSpace) + 'px'}">
|
||||
<view class="verify-img-panel" :style="{width: imgSize.width,
|
||||
height: imgSize.height,}">
|
||||
|
||||
<image :src="backImgBase?('data:image/png;base64,'+backImgBase):defaultImg" alt=""
|
||||
style="width:100%;height:100%;display:block"></image>
|
||||
<view class="verify-refresh" @click="refresh" v-show="showRefresh">
|
||||
<text class="iconfont icon-refresh"></text>
|
||||
</view>
|
||||
<transition name="tips">
|
||||
<text class="verify-tips" v-if="tipWords" :class="passFalg ? 'suc-bg':'err-bg'">{{tipWords}}</text>
|
||||
</transition>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 公共部分 -->
|
||||
<view class="verify-bar-area" :style="{width: imgSize.width,
|
||||
height: '40px',
|
||||
'line-height':'40px'}">
|
||||
<text class="verify-msg" v-text="text"></text>
|
||||
<view class="verify-left-bar"
|
||||
:style="{width: leftBarWidth?leftBarWidth:'40px', height: '40px', 'border-color': leftBarBorderColor, transaction: transitionWidth}">
|
||||
<text class="verify-msg" v-text="finishText"></text>
|
||||
<view class="verify-move-block" @touchstart="start" @touchend="end" @touchmove="move"
|
||||
:style="{width:'40px', height: '40px', 'background-color': moveBlockBackgroundColor, left: moveBlockLeft, transition: transitionLeft}">
|
||||
<text :class="['verify-icon iconfont', iconClass]" :style="{color: iconColor}"></text>
|
||||
<view v-if="type === '2'" class="verify-sub-block" :style="{'width':Math.floor(parseInt(imgSize.width)*47/310)+ 'px' ,
|
||||
'height': imgSize.height,
|
||||
'top':'-' + (parseInt(imgSize.height) + vSpace) + 'px',
|
||||
}">
|
||||
<image :src="'data:image/png;base64,'+blockBackImgBase" alt=""
|
||||
style="width:100%;height:100%;display:block"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
/**
|
||||
* VerifySlide
|
||||
* @description 滑块
|
||||
* */
|
||||
import {
|
||||
aesEncrypt
|
||||
} from "./../utils/ase.js"
|
||||
import {
|
||||
getAjcaptcha,
|
||||
ajcaptchaCheck
|
||||
} from '@/api/api.js';
|
||||
|
||||
export default {
|
||||
name: 'VerifySlide',
|
||||
props: {
|
||||
captchaType: {
|
||||
type: String,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: '1'
|
||||
},
|
||||
//弹出式pop,固定fixed
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'fixed'
|
||||
},
|
||||
vSpace: {
|
||||
type: Number,
|
||||
default: 5
|
||||
},
|
||||
explain: {
|
||||
type: String,
|
||||
default: '向右滑动完成验证'
|
||||
},
|
||||
imgSize: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {
|
||||
width: '310px',
|
||||
height: '155px'
|
||||
}
|
||||
}
|
||||
},
|
||||
blockSize: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {
|
||||
width: '50px',
|
||||
height: '50px'
|
||||
}
|
||||
}
|
||||
},
|
||||
barSize: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {
|
||||
width: '100%',
|
||||
height: '40px'
|
||||
}
|
||||
}
|
||||
},
|
||||
defaultImg: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
secretKey: '', //后端返回的加密秘钥 字段
|
||||
passFalg: false, //请求通过与否
|
||||
backImgBase: '', //验证码背景图片
|
||||
blockBackImgBase: '', //验证滑块的背景图片
|
||||
backToken: "", //后端返回的唯一token值
|
||||
startMoveTime: "", //移动开始的时间
|
||||
endMovetime: '', //移动结束的时间
|
||||
tipsBackColor: '', //提示词的北京颜色
|
||||
tipWords: '',
|
||||
text: '',
|
||||
finishText: '',
|
||||
setSize: {
|
||||
imgHeight: 0,
|
||||
imgWidth: 0,
|
||||
barHeight: 0,
|
||||
barWidth: 0
|
||||
},
|
||||
top: 0,
|
||||
left: 0,
|
||||
moveBlockLeft: undefined,
|
||||
leftBarWidth: undefined,
|
||||
// 移动中样式
|
||||
moveBlockBackgroundColor: undefined,
|
||||
leftBarBorderColor: '#ddd',
|
||||
iconColor: undefined,
|
||||
iconClass: 'icon-right',
|
||||
status: false, //鼠标状态
|
||||
isEnd: false, //是够验证完成
|
||||
showRefresh: true,
|
||||
transitionLeft: '',
|
||||
transitionWidth: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.text = this.explain
|
||||
this.getPictrue();
|
||||
this.$nextTick(() => {
|
||||
this.$parent.$emit('ready', this)
|
||||
})
|
||||
},
|
||||
|
||||
//鼠标按下
|
||||
start: function(e) {
|
||||
this.startMoveTime = new Date().getTime(); //开始滑动的时间
|
||||
if (this.isEnd == false) {
|
||||
this.text = ''
|
||||
this.moveBlockBackgroundColor = '#337ab7'
|
||||
this.leftBarBorderColor = '#337AB7'
|
||||
this.iconColor = '#fff'
|
||||
e.stopPropagation();
|
||||
this.status = true;
|
||||
}
|
||||
},
|
||||
//鼠标移动
|
||||
move: function(e) {
|
||||
var query = uni.createSelectorQuery().in(this);
|
||||
this.barArea = query.select('.verify-bar-area')
|
||||
var bar_area_left, barArea_offsetWidth;
|
||||
this.barArea.boundingClientRect(data => {
|
||||
bar_area_left = Math.ceil(data.left)
|
||||
barArea_offsetWidth = Math.ceil(data.width)
|
||||
|
||||
if (this.status && this.isEnd == false) {
|
||||
if (!e.touches) { //兼容移动端
|
||||
var x = Math.ceil(e.clientX);
|
||||
} else { //兼容PC端
|
||||
var x = Math.ceil(e.touches[0].pageX);
|
||||
}
|
||||
// var bar_area_left = this.getLeft(this.barArea);
|
||||
|
||||
var move_block_left = x - bar_area_left //小方块相对于父元素的left值
|
||||
if (this.type !== '1') { //图片滑动
|
||||
if (move_block_left >= barArea_offsetWidth - parseInt(parseInt(this.blockSize
|
||||
.width) / 2) - 2) {
|
||||
move_block_left = barArea_offsetWidth - parseInt(parseInt(this.blockSize
|
||||
.width) / 2) - 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (move_block_left <= 0) {
|
||||
move_block_left = parseInt(parseInt(this.blockSize.width) / 2);
|
||||
}
|
||||
|
||||
//拖动后小方块的left值
|
||||
this.moveBlockLeft = (move_block_left - parseInt(parseInt(this.blockSize.width) / 2)) +
|
||||
"px"
|
||||
this.leftBarWidth = (move_block_left - parseInt(parseInt(this.blockSize.width) / 2)) +
|
||||
"px"
|
||||
|
||||
}
|
||||
}).exec();
|
||||
},
|
||||
|
||||
//鼠标松开
|
||||
end: function() {
|
||||
this.endMovetime = new Date().getTime();
|
||||
var _this = this;
|
||||
// 判断是否重合
|
||||
if (this.status && this.isEnd == false) {
|
||||
if (this.type !== '1') { //图片滑动
|
||||
var moveLeftDistance = parseInt((this.moveBlockLeft || '').replace('px', ''));
|
||||
|
||||
moveLeftDistance = moveLeftDistance * 310 / parseInt(this.imgSize.width)
|
||||
|
||||
var captchaVerification = this.secretKey ? aesEncrypt(this.backToken + '---' + JSON.stringify({
|
||||
x: moveLeftDistance,
|
||||
y: 5.0
|
||||
}), this.secretKey) : this.backToken + '---' + JSON.stringify({
|
||||
x: moveLeftDistance,
|
||||
y: 5.0
|
||||
})
|
||||
let data = {
|
||||
captchaType: this.captchaType,
|
||||
"pointJson": this.secretKey ? aesEncrypt(JSON.stringify({
|
||||
x: moveLeftDistance,
|
||||
y: 5.0
|
||||
}), this.secretKey) : JSON.stringify({
|
||||
x: moveLeftDistance,
|
||||
y: 5.0
|
||||
}),
|
||||
"token": this.backToken
|
||||
}
|
||||
ajcaptchaCheck(data).then((result) => {
|
||||
let res = result.data
|
||||
this.moveBlockBackgroundColor = '#5cb85c'
|
||||
this.leftBarBorderColor = '#5cb85c'
|
||||
this.iconColor = '#fff'
|
||||
this.iconClass = 'icon-check'
|
||||
this.showRefresh = true
|
||||
this.isEnd = true;
|
||||
setTimeout(() => {
|
||||
if (this.mode == 'pop') {
|
||||
this.$parent.clickShow = false;
|
||||
}
|
||||
this.refresh();
|
||||
}, 1500)
|
||||
this.passFalg = true
|
||||
this.tipWords =
|
||||
`${((this.endMovetime-this.startMoveTime)/1000).toFixed(2)}s验证成功`
|
||||
setTimeout(() => {
|
||||
this.tipWords = ""
|
||||
this.$emit('success', {
|
||||
captchaVerification
|
||||
})
|
||||
}, 1000)
|
||||
}).catch(res => {
|
||||
this.moveBlockBackgroundColor = '#d9534f'
|
||||
this.leftBarBorderColor = '#d9534f'
|
||||
this.iconColor = '#fff'
|
||||
this.iconClass = 'icon-close'
|
||||
this.passFalg = false
|
||||
setTimeout(() => {
|
||||
this.refresh();
|
||||
}, 1000);
|
||||
this.$parent.$emit('error', this)
|
||||
this.tipWords = "验证失败"
|
||||
setTimeout(() => {
|
||||
this.tipWords = ""
|
||||
}, 1000)
|
||||
})
|
||||
}
|
||||
this.status = false;
|
||||
}
|
||||
},
|
||||
refresh: function() {
|
||||
this.showRefresh = true
|
||||
this.finishText = ''
|
||||
this.transitionLeft = 'left .3s'
|
||||
this.moveBlockLeft = 0
|
||||
this.leftBarWidth = false
|
||||
this.transitionWidth = 'width .3s'
|
||||
this.leftBarBorderColor = '#ddd'
|
||||
this.moveBlockBackgroundColor = '#fff'
|
||||
this.iconColor = '#000'
|
||||
this.iconClass = 'icon-right'
|
||||
this.getPictrue()
|
||||
this.isEnd = false
|
||||
setTimeout(() => {
|
||||
this.transitionWidth = ''
|
||||
this.transitionLeft = ''
|
||||
this.text = this.explain
|
||||
}, 300)
|
||||
},
|
||||
|
||||
//获取left值
|
||||
getLeft: function(node) {
|
||||
let leftValue = 0;
|
||||
while (node) {
|
||||
leftValue += node.offsetLeft;
|
||||
node = node.offsetParent;
|
||||
}
|
||||
let finalvalue = leftValue;
|
||||
return finalvalue;
|
||||
},
|
||||
|
||||
// 请求背景图片和验证图片
|
||||
getPictrue() {
|
||||
let data = {
|
||||
captchaType: this.captchaType,
|
||||
clientUid: uni.getStorageSync('slider'),
|
||||
ts: Date.now(), // 现在的时间戳
|
||||
}
|
||||
getAjcaptcha(data).then((result) => {
|
||||
let res = result.data
|
||||
this.backImgBase = res.originalImageBase64
|
||||
this.blockBackImgBase = res.jigsawImageBase64
|
||||
this.backToken = res.token
|
||||
this.secretKey = res.secretKey
|
||||
}).catch(() => {
|
||||
this.backImgBase = null
|
||||
this.blockBackImgBase = null
|
||||
})
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
// type变化则全面刷新
|
||||
type: {
|
||||
immediate: true,
|
||||
handler() {
|
||||
this.init()
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {},
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.verifybox {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #e4e7eb;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, .3);
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.verifybox-top {
|
||||
padding: 0 15px;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
text-align: left;
|
||||
font-size: 16px;
|
||||
color: #45494c;
|
||||
border-bottom: 1px solid #e4e7eb;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.verifybox-bottom {
|
||||
/* padding: 15px; */
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.verifybox-close {
|
||||
position: absolute;
|
||||
top: 13px;
|
||||
right: 9px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1001;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
background: rgba(0, 0, 0, .3);
|
||||
/* display: none; */
|
||||
transition: all .5s;
|
||||
}
|
||||
|
||||
.verify-tips {
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
bottom: 0px;
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
background-color: rgb(231, 27, 27, .5);
|
||||
line-height: 30px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.suc-bg {
|
||||
background-color: rgba(92, 184, 92, .5);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startcolorstr=#7f5CB85C, endcolorstr=#7f5CB85C);
|
||||
}
|
||||
|
||||
.err-bg {
|
||||
background-color: rgba(217, 83, 79, .5);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startcolorstr=#7fD9534F, endcolorstr=#7fD9534F);
|
||||
}
|
||||
|
||||
|
||||
.tips-enter,
|
||||
.tips-leave-to {
|
||||
bottom: -30px;
|
||||
}
|
||||
|
||||
.tips-enter-active,
|
||||
.tips-leave-active {
|
||||
transition: bottom .5s;
|
||||
}
|
||||
|
||||
/* ---------------------------- */
|
||||
/*常规验证码*/
|
||||
.verify-code {
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
margin-bottom: 5px;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.cerify-code-panel {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.verify-code-area {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.verify-input-area {
|
||||
float: left;
|
||||
width: 60%;
|
||||
padding-right: 10px;
|
||||
|
||||
}
|
||||
|
||||
.verify-change-area {
|
||||
line-height: 30px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.varify-input-code {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
.verify-change-code {
|
||||
color: #337AB7;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.verify-btn {
|
||||
width: 200px;
|
||||
height: 30px;
|
||||
background-color: #337AB7;
|
||||
color: #FFFFFF;
|
||||
border: none;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
|
||||
/*滑动验证码*/
|
||||
.verify-bar-area {
|
||||
position: relative;
|
||||
background: #FFFFFF;
|
||||
text-align: center;
|
||||
-webkit-box-sizing: content-box;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
border: 1px solid #ddd;
|
||||
-webkit-border-radius: 4px;
|
||||
}
|
||||
|
||||
.verify-bar-area .verify-move-block {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0;
|
||||
background: #fff;
|
||||
cursor: pointer;
|
||||
-webkit-box-sizing: content-box;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
box-shadow: 0 0 2px #888888;
|
||||
-webkit-border-radius: 1px;
|
||||
}
|
||||
|
||||
.verify-bar-area .verify-move-block:hover {
|
||||
background-color: #337ab7;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.verify-bar-area .verify-left-bar {
|
||||
position: absolute;
|
||||
top: -1px;
|
||||
left: -1px;
|
||||
background: #f0fff0;
|
||||
cursor: pointer;
|
||||
-webkit-box-sizing: content-box;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.verify-img-panel {
|
||||
margin: 0;
|
||||
-webkit-box-sizing: content-box;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
border-top: 1px solid #ddd;
|
||||
border-bottom: 1px solid #ddd;
|
||||
border-radius: 3px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.verify-img-panel .verify-refresh {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
text-align: center;
|
||||
padding: 5px;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.verify-img-panel .icon-refresh {
|
||||
font-size: 20px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.verify-img-panel .verify-gap {
|
||||
background-color: #fff;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
border: 1px solid #fff;
|
||||
}
|
||||
|
||||
.verify-bar-area .verify-move-block .verify-sub-block {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
z-index: 3;
|
||||
/* border: 1px solid #fff; */
|
||||
}
|
||||
|
||||
.verify-bar-area .verify-move-block .verify-icon {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.verify-bar-area .verify-msg {
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
/*字体图标的css*/
|
||||
/*@font-face {font-family: "iconfont";*/
|
||||
/*src: url('../fonts/iconfont.eot?t=1508229193188'); !* IE9*!*/
|
||||
/*src: url('../fonts/iconfont.eot?t=1508229193188#iefix') format('embedded-opentype'), !* IE6-IE8 *!*/
|
||||
/*url('data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAAaAAAsAAAAACUwAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAADMAAABCsP6z7U9TLzIAAAE8AAAARAAAAFZW7kiSY21hcAAAAYAAAAB3AAABuM+qBlRnbHlmAAAB+AAAAnQAAALYnrUwT2hlYWQAAARsAAAALwAAADYPNwajaGhlYQAABJwAAAAcAAAAJAfeA4dobXR4AAAEuAAAABMAAAAYF+kAAGxvY2EAAATMAAAADgAAAA4CvAGsbWF4cAAABNwAAAAfAAAAIAEVAF1uYW1lAAAE/AAAAUUAAAJtPlT+fXBvc3QAAAZEAAAAPAAAAE3oPPXPeJxjYGRgYOBikGPQYWB0cfMJYeBgYGGAAJAMY05meiJQDMoDyrGAaQ4gZoOIAgCKIwNPAHicY2Bk/sM4gYGVgYOpk+kMAwNDP4RmfM1gxMjBwMDEwMrMgBUEpLmmMDgwVDxbwtzwv4EhhrmBoQEozAiSAwAw1A0UeJzFkcENgCAMRX8RjCGO4gTe9eQcnhzAfXC2rqG/hYsT8MmD9gdS0gJIAAaykAjIBYHppCvuD8juR6zMJ67A89Zdn/f1aNPikUn8RvYo8G20CjKim6Rf6b9m34+WWd/vBr+oW8V6q3vF5qKlYrPRp4L0Ad5nGL8AeJxFUc9rE0EYnTezu8lMsrvtbrqb3TRt0rS7bdOmdI0JbWmCtiItIv5oi14qevCk9SQVLFiQgqAF8Q9QLKIHLx48FkHo3ZNnFUXwD5C2B6dO6sFhmI83w7z3fe8RnZCjb2yX5YlLhskkmScXCIFRxYBFiyjH9Rqtoqes9/g5i8WVuJyqDNTYLPwBI+cljXrkGynDhoU+nCgnjbhGY5yst+gMEq8IBIXwsjPU67CnEPm4b0su0h309Fd67da4XBhr55KSm17POk7gOE/Shq6nKdVsC7d9j+tcGPKVboc9u/0jtB/ZIA7PXTVLBef6o/paccjnwOYm3ELJetPuDrvV3gg91wlSXWY6H5qVwRzWf2TybrYYfSdqoXOwh/Qa8RWIjBTiSI3h614/vKSNRhONOrsnQi6Xf4nQFQDTmJE1NKbhI6crHEJO/+S5QPxhYJRRyvBFBP+5T9EPpEAIVzzRQIrjmJ6jY1WTo+NXTMchuBsKuS8PRZATSMl9oTA4uNLkeIA0V1UeqOoGQh7IAxGo+7T83fn3T+voqCNPPAUazUYUI7LgKSV1Jk2oUeghYGhZ+cKOe2FjVu5ZKEY2VkE13AK1+jI4r1KLbPlZfrKiPhOXKPRj7q9sj9XJ7LFHNmrKJS3VCdhXGSdKrtmoQaWeMjQVt0KD6sGPOx0oH2fgtzoNROxtNq8F3tzYM/n+TjKSX5qf2jx941276TIr9FjXxKr8eX/6bK4yuopwo9py1sw8F9kdw4AmurRpLUM3tYx5ZnKpfHPi8dzz19vJ6MjyxYUrpqeb1uLs3eGV6vr21pSqpeWkqonAN9oUyIiXpv8XvlN5e3icY2BkYGAA4n0vN4fG89t8ZeBmYQCBa9wPPRH0/wcsDMwmQC4HAxNIFABAfAqaAHicY2BkYGBu+N/AEMPCAAJAkpEBFbABAEcMAm94nGNhYGBgfsnAwMKAigESnwEBAAAAAAAAdgCkANoBCAFsAAB4nGNgZGBgYGMIZGBlAAEmIOYCQgaG/2A+AwARSAFzAHicZY9NTsMwEIVf+gekEqqoYIfkBWIBKP0Rq25YVGr3XXTfpk6bKokjx63UA3AejsAJOALcgDvwSCebNpbH37x5Y08A3OAHHo7fLfeRPVwyO3INF7gXrlN/EG6QX4SbaONVuEX9TdjHM6bCbXRheYPXuGL2hHdhDx18CNdwjU/hOvUv4Qb5W7iJO/wKt9Dx6sI+5l5XuI1HL/bHVi+cXqnlQcWhySKTOb+CmV7vkoWt0uqca1vEJlODoF9JU51pW91T7NdD5yIVWZOqCas6SYzKrdnq0AUb5/JRrxeJHoQm5Vhj/rbGAo5xBYUlDowxQhhkiMro6DtVZvSvsUPCXntWPc3ndFsU1P9zhQEC9M9cU7qy0nk6T4E9XxtSdXQrbsuelDSRXs1JErJCXta2VELqATZlV44RelzRiT8oZ0j/AAlabsgAAAB4nGNgYoAALgbsgI2RiZGZkYWRlZGNkZ2BsYI1OSM1OZs1OSe/OJW1KDM9o4S9KDWtKLU4g4EBAJ79CeQ=') format('woff'),*/
|
||||
/*url('../fonts/iconfont.ttf?t=1508229193188') format('truetype'), !* chrome, firefox, opera, Safari, Android, iOS 4.2+*!*/
|
||||
/*url('../fonts/iconfont.svg?t=1508229193188#iconfont') format('svg'); !* iOS 4.1- *!*/
|
||||
/*}*/
|
||||
|
||||
.iconfont {
|
||||
font-family: "iconfont" !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-check:before {
|
||||
content: " ";
|
||||
display: block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
position: absolute;
|
||||
margin: auto;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
z-index: 9999;
|
||||
background-image: url("@/static/images/arrow-good.png");
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
.icon-close:before {
|
||||
content: " ";
|
||||
display: block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
position: absolute;
|
||||
margin: auto;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
z-index: 9999;
|
||||
background-image: url("@/static/images/arrow-close.png");
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
.icon-right:before {
|
||||
content: " ";
|
||||
display: block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
position: absolute;
|
||||
margin: auto;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
background-size: cover;
|
||||
z-index: 9999;
|
||||
background-image: url("@/static/images/arrow-right.png");
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
.icon-refresh:before {
|
||||
content: " ";
|
||||
display: block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
position: absolute;
|
||||
margin: auto;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
z-index: 9999;
|
||||
background-image: url("@/static/images/refresh.png");
|
||||
background-size: contain;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,73 @@
|
|||
// #ifdef H5
|
||||
let VUE_APP_WS_URL = `ws://${location.hostname}?type=user`
|
||||
// #endif
|
||||
|
||||
let openPlantGrass = '-openPlantGrass-'
|
||||
let httpApi
|
||||
|
||||
// 在打包之前请检查当前环境是否正确
|
||||
const env = 'dev'; // 开发
|
||||
// const env = 'prod'; // 生产
|
||||
// const env = 'prew'; // 预上线
|
||||
|
||||
switch (env) {
|
||||
case 'prod':
|
||||
httpApi = 'https://shop.lihaink.cn' // 生产
|
||||
httpApione = 'http://ceshi-zhibo.lihaink.cn'
|
||||
|
||||
break;
|
||||
case 'prew':
|
||||
httpApi = 'https://test.shop.lihaink.cn' //预发布环境
|
||||
httpApione = 'http://ceshi-zhibo.lihaink.cn'
|
||||
break;
|
||||
default:
|
||||
httpApi = "https://crmeb-test.shop.lihaink.cn" // 测试
|
||||
httpApione = 'https://ceshi-zhibo.lihaink.cn'
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 聊天接口修改此字符 小程序聊天要求wss 例如:wss://mer.crmeb.net
|
||||
// let wsApi = 'ws://192.168.3.20:8324'
|
||||
let wsApi = 'wss://ceshi-zhibo.lihaink.cn/chat_room'
|
||||
// console.log(httpApione,'11111111111')
|
||||
|
||||
|
||||
module.exports = {
|
||||
// 请求域名 格式: https://您的域名
|
||||
// #ifdef MP || APP-PLUS
|
||||
// HTTP_REQUEST_URL: httpApi,
|
||||
HTTP_REQUEST_URL: httpApi,
|
||||
HTTP_REQUEST_URL_ONE: httpApione,
|
||||
|
||||
VUE_APP_WS_URL: wsApi,
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifdef H5
|
||||
HTTP_REQUEST_URL: httpApi,
|
||||
HTTP_REQUEST_URL_ONE: httpApione,
|
||||
//H5接口是浏览器地址
|
||||
// 聊天长连接地址
|
||||
VUE_APP_WS_URL: VUE_APP_WS_URL,
|
||||
// #endif
|
||||
openPlantGrass: openPlantGrass,
|
||||
HEADER: {
|
||||
'content-type': 'application/json',
|
||||
|
||||
//#ifdef H5
|
||||
// 'Form-type': navigator.userAgent.toLowerCase().indexOf("micromessenger") !== -1 ? 'wechat' : 'h5',
|
||||
//#endif
|
||||
//#ifdef MP
|
||||
'Form-type': 'routine',
|
||||
//#endif
|
||||
//#ifdef APP-PLUS
|
||||
'Form-type': 'app',
|
||||
//#endif
|
||||
},
|
||||
// 回话密钥名称 请勿修改此配置
|
||||
TOKENNAME: 'X-Token',
|
||||
// 缓存时间 0 永久
|
||||
EXPIRE: 0,
|
||||
};
|
|
@ -0,0 +1,43 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
module.exports = {
|
||||
//token
|
||||
LOGIN_STATUS: 'LOGIN_STATUS_TOKEN',
|
||||
// uid
|
||||
UID:'UID',
|
||||
//<2F>û<EFBFBD>
|
||||
USER_INFO: 'USER_INFO',
|
||||
//token<65><6E><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD>
|
||||
EXPIRES_TIME: 'EXPIRES_TIME',
|
||||
//<2F>Ƿ<EFBFBD><C7B7><EFBFBD>Ȩ
|
||||
WX_AUTH: 'WX_AUTH',
|
||||
//<2F><><EFBFBD>ں<EFBFBD><DABA><EFBFBD>Ȩcode
|
||||
STATE_KEY: 'wx_authorize_state',
|
||||
//<2F>û<EFBFBD><C3BB><EFBFBD><EFBFBD><EFBFBD>
|
||||
LOGINTYPE: 'loginType',
|
||||
//<2F><><EFBFBD>ں<EFBFBD><DABA><EFBFBD>ת<EFBFBD><D7AA><EFBFBD><EFBFBD>
|
||||
BACK_URL: 'login_back_url',
|
||||
// С<><D0A1><EFBFBD><EFBFBD>code
|
||||
STATE_R_KEY: 'roution_authorize_state',
|
||||
//<2F><>ȨlogoС<6F><D0A1><EFBFBD><EFBFBD>
|
||||
LOGO_URL: 'LOGO_URL',
|
||||
//模板缓存
|
||||
SUBSCRIBE_MESSAGE: 'SUBSCRIBE_MESSAGE',
|
||||
|
||||
TIPS_KEY: 'TIPS_KEY',
|
||||
|
||||
SPREAD: 'spread',
|
||||
//缓存经度
|
||||
CACHE_LONGITUDE: 'LONGITUDE',
|
||||
//缓存纬度
|
||||
CACHE_LATITUDE: 'LATITUDE',
|
||||
//缓存地址信息
|
||||
ADRESS_LOCATION:'ADRESS_LOCATION'
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
disabled: false,
|
||||
text: "获取验证码"
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
sendCode() {
|
||||
if (this.disabled) return;
|
||||
this.disabled = true;
|
||||
let n = 60;
|
||||
this.text = "剩余 " + n + "s";
|
||||
const run = setInterval(() => {
|
||||
n = n - 1;
|
||||
if (n < 0) {
|
||||
clearInterval(run);
|
||||
}
|
||||
this.text = "剩余 " + n + "s";
|
||||
if (this.text < "剩余 " + 0 + "s") {
|
||||
this.disabled = false;
|
||||
this.text = "重新获取";
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,25 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
import { history } from '@/api/public.js'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
getHistory() {
|
||||
// console.log(this.$util.getNowUrl(),'page')
|
||||
history({
|
||||
page:this.$util.getNowUrl()
|
||||
}).then(res=>{})
|
||||
},
|
||||
}
|
||||
};
|
|
@ -0,0 +1,84 @@
|
|||
<template>
|
||||
<view>
|
||||
<live-pusher id='livePusher' ref="livePusher" class="livePusher" :url="url" mode="SD" :muted="true"
|
||||
:enable-camera="true" :auto-focus="true" :beauty="1" whiteness="2" aspect="9:16" @statechange="statechange"
|
||||
@netstatus="netstatus" @error="error"
|
||||
:style="'width: '+ windowWidth +'px; height: '+ windowHeight +'px;z-inde:-1;'">
|
||||
</live-pusher>
|
||||
<sd-float-page :room='room' @switchCamera='switchCamera' :msgList='msgList'
|
||||
:style="'width: '+ windowWidth +'px; height: '+ windowHeight +'px;position: absolute;z-index:999999;' "></sd-float-page>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import sdFloatPage from '@/components/sd-live-page/livepage.nvue';
|
||||
|
||||
|
||||
export default {
|
||||
components: {
|
||||
sdFloatPage
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
url: '',
|
||||
windowHeight: 0,
|
||||
windowWidth: 0,
|
||||
room: {},
|
||||
pusherContext: null,
|
||||
userName:this.userName,
|
||||
inputModel:'',
|
||||
msgList:[]
|
||||
};
|
||||
},
|
||||
onReady() {
|
||||
// this.context = uni.createLivePusherContext('livePusher', this);
|
||||
// this.context.switchCamera() // 摄像头切换(切换为后置)
|
||||
// this.context.startPreview() // 摄像头预览 (不加会黑屏)
|
||||
this.windowWidth = uni.getSystemInfoSync().screenWidth //获取屏幕宽度
|
||||
this.windowHeight = uni.getSystemInfoSync().screenHeight; //获取屏幕高度
|
||||
// 监听窗口大小的变化
|
||||
uni.onWindowResize((res) => {
|
||||
this.windowHeight = res.size.windowHeight;
|
||||
})
|
||||
|
||||
},
|
||||
onLoad(options) {
|
||||
|
||||
this.room = JSON.parse(decodeURIComponent(options.data));
|
||||
this.url = this.room.push_url
|
||||
},
|
||||
mounted() {
|
||||
this.pusherContext = uni.createLivePusherContext('livePusher', this);
|
||||
// console.log('创建 pusherContext:', this.pusherContext);
|
||||
|
||||
//开始推流
|
||||
this.pusherContext.start(function(e) {
|
||||
console.log('推流情况')
|
||||
// console.log(e)
|
||||
});
|
||||
|
||||
},
|
||||
methods: {
|
||||
|
||||
statechange(e) {
|
||||
// console.log("statechange:" + JSON.stringify(e));
|
||||
},
|
||||
//切换摄像头
|
||||
switchCamera: function() {
|
||||
this.pusherContext.switchCamera({
|
||||
success: (a) => {
|
||||
console.log("livePusher.switchCamera:" + JSON.stringify(a));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
netstatus(e) {
|
||||
// console.log("netstatus:" + JSON.stringify(e));
|
||||
},
|
||||
error(e) {
|
||||
// console.log("error:" + JSON.stringify(e));
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,104 @@
|
|||
<template>
|
||||
<view class="container">
|
||||
<view :style="'width: '+ windowWidth +'px; height: '+ boxStyle.height +'px;z-inde:-1;'">
|
||||
<!--
|
||||
1.这里的 swiper 不是用来控制视频滑动的,而是用来控制左右滑动的,如果不需要的可以改成 view
|
||||
2.为了 视频无限加载,已经把 21 行的 appear 去掉了,加上了 loadmore 方法(第10行)
|
||||
3.由于方法比较多,可以采取下面的方式查看代码:
|
||||
(1)Mac:按住 option 键,然后点击方法名,即可跳转到方法
|
||||
(2)windows:按住 Alt 键,然后鼠标左击,即可跳转到方法
|
||||
-->
|
||||
<view class="root">
|
||||
<video ref="videoPlayer" :src="currentSrc" controls @ended="playNext" :object-fit="object_fit" :style="'width: '+ windowWidth +'px; height: '+ boxStyle.height +'px;z-inde:-1;'"></video>
|
||||
</view>
|
||||
<sd-float-page :room='room' :msgList='msgList'
|
||||
:style="'width: '+ windowWidth +'px; height: '+ boxStyle.height +'px;position: absolute;' "></sd-float-page>
|
||||
</view>
|
||||
|
||||
|
||||
|
||||
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import sdFloatPage from '@/components/sd-live-page/histroy.nvue';
|
||||
|
||||
import {
|
||||
playbackDetail
|
||||
} from '@/api/api.js'
|
||||
export default {
|
||||
components: {
|
||||
sdFloatPage
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
rtmpSources: [],
|
||||
currentIndex: 0,
|
||||
room: {},
|
||||
wHeight: 0, //获取的屏幕高度🌟💗
|
||||
boxStyle: { //视频,图片封面样式🌟💗
|
||||
'height': 0,
|
||||
'width': 0,
|
||||
},
|
||||
object_fit: 'cover', //视频样式默认包含🌟💗
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
currentSrc() {
|
||||
return this.rtmpSources[this.currentIndex];
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
this.room = JSON.parse(decodeURIComponent(options.data));
|
||||
this.platform = uni.getSystemInfoSync().platform
|
||||
this.windowWidth = uni.getSystemInfoSync().screenWidth //获取屏幕宽度
|
||||
this.boxStyle.width = this.windowWidth + 'px' //给宽度加px
|
||||
this.wHeight = uni.getSystemInfoSync().screenHeight; //获取屏幕高度
|
||||
this.boxStyle.height = this.wHeight; //改变视频高度
|
||||
this.get()
|
||||
|
||||
},
|
||||
mounted() {
|
||||
|
||||
// 初始化时播放第一个源
|
||||
this.playCurrent();
|
||||
},
|
||||
|
||||
methods: {
|
||||
playCurrent() {
|
||||
this.$refs.videoPlayer.load();
|
||||
this.$refs.videoPlayer.play();
|
||||
},
|
||||
playNext() {
|
||||
this.currentIndex++;
|
||||
if (this.currentIndex >= this.rtmpSources.length) {
|
||||
this.currentIndex = 0; // 回到第一个源
|
||||
}
|
||||
this.playCurrent();
|
||||
},
|
||||
|
||||
|
||||
get() {
|
||||
let that = this
|
||||
console.log(this.room)
|
||||
playbackDetail({
|
||||
app_name: 'shop',
|
||||
live_stream_id: this.room.live_stream_id
|
||||
}).then((res) => {
|
||||
// console.log(res.data, '1111')
|
||||
|
||||
this.rtmpSources = res.data.playback_url;
|
||||
|
||||
|
||||
})
|
||||
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,358 @@
|
|||
<template>
|
||||
<view class="container">
|
||||
<view :style="'width: '+ windowWidth +'px; height: '+ boxStyle.height +'px;z-inde:-1;'">
|
||||
<!--
|
||||
1.这里的 swiper 不是用来控制视频滑动的,而是用来控制左右滑动的,如果不需要的可以改成 view
|
||||
2.为了 视频无限加载,已经把 21 行的 appear 去掉了,加上了 loadmore 方法(第10行)
|
||||
3.由于方法比较多,可以采取下面的方式查看代码:
|
||||
(1)Mac:按住 option 键,然后点击方法名,即可跳转到方法
|
||||
(2)windows:按住 Alt 键,然后鼠标左击,即可跳转到方法
|
||||
-->
|
||||
<list @loadmore="getData" @scroll="scrolls" :loadmoreoffset="wHeight*1" :show-scrollbar="false"
|
||||
ref="listBox" :pagingEnabled="true" :scrollable="true">
|
||||
<!-- 循环数据 -->
|
||||
<cell v-for="(item,i) in dataList" :key="i">
|
||||
<!-- 用div把视频模组套起来 -->
|
||||
<div :style="'width: '+ windowWidth +'px; height: '+ boxStyle.height +'px;'">
|
||||
<!-- <view v-if="Math.abs(k-i)<=1"> -->
|
||||
<view v-if="Math.abs(k-i)<=1">
|
||||
<view class="root">
|
||||
<video :ref="'item'+i" :id="item.id" :loop="true" :autoplay="i == k"
|
||||
:src="item.pull_url" :muted="item.isplay" :enable-progress-gesture="false"
|
||||
:page-gesture="false" :controls="false" :show-loading="true" :is-live='true'
|
||||
@error='vedioerr' :show-fullscreen-btn="false" :show-center-play-btn="false"
|
||||
:style="boxStyle" :object-fit="object_fit" @timeupdate="timeupdate($event,i)">
|
||||
|
||||
</video>
|
||||
<!-- {{item}} {{i}} -->
|
||||
|
||||
</view>
|
||||
<sd-float-page :room='room' :msgList='msgList'
|
||||
:style="'width: '+ windowWidth +'px; height: '+ boxStyle.height +'px;position: absolute;' "></sd-float-page>
|
||||
</view>
|
||||
|
||||
</div>
|
||||
</cell>
|
||||
</list>
|
||||
</view>
|
||||
|
||||
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import list from '@/uni_modules/uview-ui/libs/config/props/list';
|
||||
import sdFloatPage from '@/components/sd-live-page/livepage.nvue';
|
||||
import {
|
||||
VUE_APP_WS_URL
|
||||
} from '@/config/app';
|
||||
|
||||
import json from '../../static/js/json';
|
||||
export default {
|
||||
components: {
|
||||
sdFloatPage
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
imgHost: '',
|
||||
//下面打🌟号的是必须要的基础字段
|
||||
//下面打💗号的是拥有滑动条的必须字段
|
||||
dataList: [], //用于数据循环的列表🌟💗
|
||||
wHeight: 0, //获取的屏幕高度🌟💗
|
||||
boxStyle: { //视频,图片封面样式🌟💗
|
||||
'height': 0,
|
||||
'width': 0,
|
||||
},
|
||||
k: 0, //默认为0🌟💗
|
||||
max: 2,
|
||||
playIngIds: [], //正在播放的视频id列队,列队用于处理滑动过快导致的跳频问题🌟💗
|
||||
ready: false, //可忽略
|
||||
isDragging: false, //false代表停止滑动🌟💗
|
||||
refreshing: true, //用于下拉刷新🌟💗
|
||||
windowWidth: 0, //获取屏幕宽度🌟💗
|
||||
windowHeight: 0,
|
||||
dex: [0, 0], //用于判断是上滑还是下滑,第一个存旧值,第二个存新值【目前在1.0.7已经废弃】
|
||||
currents: 0, //用于左右滑动,0代表视频界面,1代表右滑界面🌟💗
|
||||
platform: '', //用于获取操作系统:ios、android🌟💗
|
||||
playIng: false, //用于视频初始化时是否播放,默认不播放🌟💗
|
||||
videoTime: '', //视频总时长,这个主要用来截取时间数值💗
|
||||
videoTimes: '', //视频时长,用这个来获取时间值,例如:00:30这个时间值💗
|
||||
changeTime: '', //显示滑动进度条时变化的时间💗
|
||||
isShowimage: false, //是否显示封面【1.0.4已废弃,但是意思需要记住】
|
||||
currenttimes: 0, //当前时间💗
|
||||
isShowProgressBarTime: false, //是否拖动进度条,如果拖动(true)则显示进度条时间,否则不显示(false)【1.0.4已废弃,但是意思需要记住】
|
||||
ProgressBarOpacity: 0.7, //进度条不拖动时的默认值,就是透明的💗
|
||||
dotWidth: 0, //播放的小圆点,默认没有💗
|
||||
deleteHeight: 0, //测试高度🌟💗
|
||||
percent: 0, //百分小数💗
|
||||
currentPosition: 0, //滑块当前位置💗//2.0已弃用,现已用于后端参数
|
||||
currentPositions: 0, //滑块当前位置的副本💗//2.0已弃用,现已用于后端参数
|
||||
newTime: 0, //跟手滑动后的最新时间💗
|
||||
timeNumber: 0, //🌟💗
|
||||
ProgressBarBottom: 20, //进度条离底部的距离💗
|
||||
object_fit: 'cover', //视频样式默认包含🌟💗
|
||||
mode: 'aspectFit', //图片封面样式🌟💗
|
||||
timeout: "", //🌟用来阻止 setTimeout()方法
|
||||
voice: "", //🌟用来阻止 setTimeout()方法
|
||||
oldVideo: "",
|
||||
isAutoplay: false, //是否开启自动播放(默认不开启)
|
||||
autoplayText: "开启自动播放",
|
||||
msgList: [],
|
||||
room: {},
|
||||
socketTask: null,
|
||||
userName: '',
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
async k(new_k, old_k) { //监听 k 值的变化,可以控制视频的播放与暂停
|
||||
const max = new_k + 2;
|
||||
if (this.max < max) {
|
||||
this.max = max;
|
||||
}
|
||||
// if (this.oldCurrent != this.currentNav) {
|
||||
// this.oldCurrent = this.currentNav
|
||||
// return false
|
||||
// }
|
||||
this.dataList[old_k].playIng = false //如果视频暂停,就加载封面
|
||||
this.dataList[old_k].isplay = true
|
||||
this.dataList[old_k].state = 'pause'
|
||||
// console.log('预留第' + (old_k) + '个视频:' + this.dataList[old_k].community_id)
|
||||
// 2.0版本已经去掉了下面这一句,视频不用暂停,只需要把声音禁止就行
|
||||
uni.createVideoContext(this.dataList[old_k].community_id, this)
|
||||
.pause() //如果视频暂停,那么旧视频停止,这里的this.dataList[old_k].id + '' + old_k,后面加 old_k 是为了每一个视频的 id 值不同,这样就可以大程度的避免串音问题
|
||||
// console.log('已经暂停 --> 第' + (old_k) + '个视频~') //提示
|
||||
this.dataList[new_k].state = 'play'
|
||||
this.dataList[new_k].isplay = false
|
||||
this.dataList[new_k].playIng = true
|
||||
uni.createVideoContext(this.dataList[new_k].community_id, this).play()
|
||||
}
|
||||
},
|
||||
onShow() {
|
||||
uni.hideLoading();
|
||||
// console.log('回到前台' + this.dataList.length);
|
||||
if (this.dataList.length !== 0) {
|
||||
this.dataList[this.k].state = 'play';
|
||||
setTimeout(() => {
|
||||
uni.createVideoContext(this.dataList[this.k].id, this).play()
|
||||
}, 250)
|
||||
}
|
||||
},
|
||||
onHide() {
|
||||
this.dataList[this.k].state = 'pause'; //界面隐藏也要停止播放视频
|
||||
setTimeout(() => {
|
||||
uni.createVideoContext(this.dataList[this.k].community_id, this).pause(); //暂停以后继续播放
|
||||
}, 250)
|
||||
// console.log('到后台');
|
||||
},
|
||||
onLoad(options) {
|
||||
this.platform = uni.getSystemInfoSync().platform
|
||||
this.windowWidth = uni.getSystemInfoSync().screenWidth //获取屏幕宽度
|
||||
this.boxStyle.width = this.windowWidth + 'px' //给宽度加px
|
||||
this.wHeight = uni.getSystemInfoSync().screenHeight; //获取屏幕高度
|
||||
this.boxStyle.height = this.wHeight; //改变视频高度
|
||||
console.log(this.boxStyle.height)
|
||||
this.room = JSON.parse(decodeURIComponent(options.data));
|
||||
|
||||
this.get()
|
||||
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
Ready() {},
|
||||
methods: {
|
||||
|
||||
|
||||
|
||||
autoPlay() {
|
||||
this.isAutoplay = !this.isAutoplay;
|
||||
if (!this.isAutoplay) {
|
||||
this.autoplayText = "开启自动播放"
|
||||
uni.showToast({
|
||||
title: "关闭自动播放",
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
})
|
||||
} else {
|
||||
this.autoplayText = "关闭自动播放"
|
||||
uni.showToast({
|
||||
title: "开启自动播放",
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
})
|
||||
}
|
||||
},
|
||||
getData() {
|
||||
// 这里就是数据加载完以后再向后端发送数据的地方,
|
||||
|
||||
|
||||
},
|
||||
vedioerr(e) {
|
||||
let timer = null
|
||||
if (e.tye = 'error') {
|
||||
timer = setInterval((res) => {
|
||||
uni.createVideoContext('myVideo', this).play()
|
||||
console.log('重新连接', '1111111111')
|
||||
}, 600000)
|
||||
} else {
|
||||
timer = null
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
touchstart(event) {
|
||||
this.dataList[this.k].isShowimage = true //刚触摸的时候就要显示预览视频图片了
|
||||
this.dataList[this.k].isShowProgressBarTime = true //显示时间线
|
||||
this.ProgressBarOpacity = 1 //让滑块显示起来更明显一点
|
||||
this.dotWidth = 10 //让点显示起来更明显一点
|
||||
},
|
||||
touchend() { //当手松开后,跳到最新时间
|
||||
uni.createVideoContext(this.dataList[this.k].community_id, this).seek(this.newTime)
|
||||
if (this.dataList[this.k].state == 'pause') {
|
||||
this.dataList[this.k].state = 'play'
|
||||
uni.createVideoContext(this.dataList[this.k].community_id, this).play()
|
||||
}
|
||||
this.dataList[this.k].isShowProgressBarTime = false //触摸结束后,隐藏时间线
|
||||
this.dataList[this.k].isShowimage = false //触摸结束后,隐藏时间预览
|
||||
this.ProgressBarOpacity = 0.5 //隐藏起来进度条,不那么明显了
|
||||
this.dotWidth = 0 //隐藏起来进度条,不那么明显了
|
||||
},
|
||||
touchmove(event) { //当手移动滑块时,计算位置、百分小数、新的时间
|
||||
var msg = []
|
||||
if (this.videoTime !== '') {
|
||||
msg = this.videoTime.split(':')
|
||||
}
|
||||
var timeNumber = Number(msg[0]) * 60 + Number(msg[1])
|
||||
this.currentPositions = event.changedTouches[0].screenX
|
||||
this.percent = this.currentPositions / this.windowWidth
|
||||
this.newTime = this.percent * timeNumber
|
||||
this.currenttimes = parseInt(this.newTime)
|
||||
let theTime = this.newTime
|
||||
let middle = 0; // 分
|
||||
if (theTime > 60) {
|
||||
middle = parseInt(theTime / 60);
|
||||
theTime = parseInt(theTime % 60);
|
||||
}
|
||||
this.changeTime =
|
||||
`${Math.round(middle)>9?Math.round(middle):'0'+Math.round(middle)}:${Math.round(theTime)>9?Math.round(theTime):'0'+Math.round(theTime)}`
|
||||
},
|
||||
timeupdate(event, index) { //计算滑块当前位置,计算当前百分小数
|
||||
if (index == this.k) {
|
||||
var currenttime = event.detail.currentTime
|
||||
this.timeNumber = Math.round(event.detail.duration)
|
||||
this.getTime()
|
||||
this.percent = currenttime / this.timeNumber
|
||||
this.currentPosition = this.windowWidth * this.percent
|
||||
let theTime = currenttime
|
||||
let middle = 0; // 分
|
||||
if (theTime > 60) {
|
||||
middle = parseInt(theTime / 60);
|
||||
theTime = parseInt(theTime % 60);
|
||||
}
|
||||
this.changeTime =
|
||||
`${Math.round(middle)>9?Math.round(middle):'0'+Math.round(middle)}:${Math.round(theTime)>9?Math.round(theTime):'0'+Math.round(theTime)}`
|
||||
//自动切换视频
|
||||
if (this.isAutoplay) { //true,代表自动播放
|
||||
if (Math.round(currenttime) == this.timeNumber - 1) {
|
||||
const dom = uni.requireNativePlugin('dom')
|
||||
let doms = 'item' + (this.k + 1)
|
||||
setTimeout(() => {
|
||||
let el = this.$refs[doms][0]
|
||||
dom.scrollToElement(el, {
|
||||
offset: 0,
|
||||
animated: true
|
||||
})
|
||||
}, 500)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
getTime() { //得到时间函数
|
||||
this.videoTime = this.formatSeconds(this.timeNumber);
|
||||
var msg = []
|
||||
if (this.videoTime !== '') {
|
||||
msg = this.videoTime.split(':')
|
||||
}
|
||||
this.videoTimes = `${msg[0]>9?msg[0]:'0'+msg[0]}:${msg[1]>9?msg[1]:'0'+msg[1]}`;
|
||||
},
|
||||
formatSeconds(value) { //获取时间函数
|
||||
let theTime = parseInt(value); // 秒
|
||||
let middle = 0; // 分
|
||||
if (theTime > 60) {
|
||||
middle = parseInt(theTime / 60);
|
||||
theTime = parseInt(theTime % 60);
|
||||
}
|
||||
return `${middle>9?middle:middle}:${theTime>9?theTime:theTime}`;
|
||||
},
|
||||
moreVideo(index) {
|
||||
|
||||
},
|
||||
toVideo(index) {
|
||||
|
||||
},
|
||||
scrolls(event) {
|
||||
|
||||
this.showManage = false;
|
||||
this.isDragging = event.isDragging;
|
||||
if (!event.isDragging) { //isDragging:判断用户是不是在滑动,滑动:true,停止滑动:false。我们要用户停止滑动时才给 k 赋值,这样就可以避免很多麻烦
|
||||
var i = Math.round(Math.abs(event.contentOffset.y) / (this.wHeight - this.deleteHeight +
|
||||
1)) //先用绝对值取出滑动的距离,然后除以屏幕高度,取一个整,就知道你现在滑动到哪一个视频了
|
||||
if (i !== this.k) { //这里加判断是因为这个方法会执行很多次,会造成重复请求,所以这里写一个限制
|
||||
if (uni.getSystemInfoSync().platform == 'ios') {
|
||||
this.k = i //判断了用户没有滑动,确认了用户的确是在看这个视频,然后就赋值啦
|
||||
this.dataList[this.k].state = 'play'
|
||||
// console.log('正在播放 --> 第' + (this.k + 1) + '个视频~')
|
||||
} else {
|
||||
clearTimeout(this.timers);
|
||||
this.timers = setTimeout(() => {
|
||||
this.k = i //判断了用户没有滑动,确认了用户的确是在看这个视频,然后就赋值啦
|
||||
this.dataList[this.k].state = 'play'
|
||||
// console.log('正在播放 --> 第' + (this.k + 1) + '个视频~')
|
||||
}, 80)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
get() {
|
||||
let that = this
|
||||
var msg = [this.room];
|
||||
console.log(this.room)
|
||||
for (let i = 0; i < msg.length; i++) {
|
||||
msg[i]['isMore'] = false
|
||||
msg[i]['playIng'] = false
|
||||
msg[i]['state'] = false
|
||||
msg[i]['isplay'] = false
|
||||
msg[i]['loading'] = false
|
||||
msg[i]['id'] = msg[i]['live_stream_id']
|
||||
}
|
||||
this.dataList = msg;
|
||||
|
||||
if (this.dataList.length !== 0) {
|
||||
|
||||
this.dataList[this.k].state = 'play';
|
||||
uni.createVideoContext(this.dataList[this.k].id, this).play()
|
||||
this.page = that.page + 1
|
||||
}
|
||||
|
||||
console.log(this.dataList, this.dataList[this.k].id, 222222)
|
||||
},
|
||||
onpullingdown() {
|
||||
this.refreshing = true
|
||||
},
|
||||
onrefresh() {
|
||||
setTimeout(() => {
|
||||
this.refreshing = false
|
||||
}, 1000)
|
||||
},
|
||||
|
||||
},
|
||||
onReachBottom() {
|
||||
uni.$emit('onReachBottom');
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,534 @@
|
|||
<template name="create-float-page">
|
||||
<view>
|
||||
<view class="do-box">
|
||||
<view class="do-box-top">
|
||||
<text>请输入直播主题:</text>
|
||||
<view class="cover-input">
|
||||
<input type="text" v-model="livename" placeholder="请输入内容,吸引更多观众"
|
||||
placeholder-class="cover-inputplaceholder" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="do-box-top" @click="chooseImage">
|
||||
<text>请上传直播封面:</text>
|
||||
<view class="cover-box">
|
||||
<image :src="imageSrc" mode="aspectFill" v-if='imageSrc'></image>
|
||||
<view class="cover-box-img" v-else>
|
||||
|
||||
<image src="@/static/img/xj.png" mode="aspectFit"></image>
|
||||
</view>
|
||||
<view class="cover-text web-font"v-if='imageSrc'>更新封面</view>
|
||||
<view class="cover-text web-font"v-else style="color: #B3B3B3;">上传图片</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="do-box-check">
|
||||
<view class="do-box-check-top">
|
||||
<view class="do-box-check-left">
|
||||
<view class="check-top-imga">
|
||||
<image src="@/static/img/c2.png" mode="aspectFit"></image>
|
||||
</view>
|
||||
<view class="check-top-txt">请选择直播商品</view>
|
||||
</view>
|
||||
<view class="do-box-check-right">
|
||||
<view class="check-top-imgb" @click="shop">
|
||||
<image src="@/static/img/c1.png" mode="aspectFit"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="" v-if="goodlist.length>0" @click="editshop(goodlist)">
|
||||
<scroll-view scroll-x="true" scroll-left="0" style="width: 450rpx;white-space: nowrap;">
|
||||
<view class="" v-for="(item,i) in goodlist" :key='i'
|
||||
style="width: 100rpx;height: 100rpx;margin-right: 20rpx;display:inline-block;">
|
||||
<image :src="item.app_goods_pic" mode="aspectFit" style="width: 100rpx;height: 100rpx;">
|
||||
</image>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
</view>
|
||||
|
||||
|
||||
|
||||
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="start-but web-font" @click="create_live_room">开始直播</view>
|
||||
|
||||
|
||||
|
||||
<uni-popup ref="popup" type="bottom" style="height: 560rpx;">
|
||||
<shoppinglist @getProduct="getProduct" :checkedObj="productList" @close='close'></shoppinglist>
|
||||
</uni-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
HTTP_REQUEST_URL
|
||||
} from '@/config/app';
|
||||
|
||||
import {
|
||||
good,
|
||||
createPushLive
|
||||
} from '@/api/api.js'
|
||||
import uniPopup from '@/components/uni-popup/uni-popup.vue';
|
||||
import shoppinglist from '@/components/shoppinglist/shoppinglist.vue'
|
||||
export default {
|
||||
components: {
|
||||
uniPopup,
|
||||
shoppinglist
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
livename: '',
|
||||
imageSrc: '',
|
||||
cover_path: '',
|
||||
inputValue: '新建直播间',
|
||||
|
||||
|
||||
|
||||
|
||||
productList: [],
|
||||
goodlist: [],
|
||||
userinfo: {}
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
if (this.isUserInfoExist) {
|
||||
console.log('用户信息存在');
|
||||
} else {
|
||||
console.log('用户信息不存在');
|
||||
uni.showModal({
|
||||
// title: '标题',
|
||||
content: '用户信息不存在,是否重新登录',
|
||||
showCancel: true,
|
||||
cancelText: '取消',
|
||||
confirmText: '确定',
|
||||
success: function(res) {
|
||||
if (res.confirm) {
|
||||
// 用户点击了确定按钮
|
||||
uni.redirectTo({
|
||||
url: '/pages/login/login'
|
||||
})
|
||||
} else if (res.cancel) {
|
||||
// 用户点击了取消按钮
|
||||
console.log('用户点击了取消按钮');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
isUserInfoExist() {
|
||||
const userInfo = this.$store.state.app.userInfo;
|
||||
|
||||
uni.sendHostEvent('userinfo', userInfo, (ret) => {
|
||||
//发送消息成功回调
|
||||
console.log('消息成功' + JSON.stringify(userInfo));
|
||||
});
|
||||
return !!userInfo; // 如果 userInfo 为空,则返回 false;否则返回 true
|
||||
},
|
||||
//关闭弹窗
|
||||
close() {
|
||||
this.$refs.popup.close()
|
||||
},
|
||||
//选择商品
|
||||
shop() {
|
||||
this.$refs.popup.open()
|
||||
},
|
||||
editshop(e) {
|
||||
let arr1 = []
|
||||
for (let i in e) {
|
||||
arr1.push({
|
||||
product_id: e[i].app_goods_id,
|
||||
store_name: e[i].app_goods_name,
|
||||
image: e[i].app_goods_pic,
|
||||
price: e[i].app_goods_price,
|
||||
})
|
||||
}
|
||||
this.productList = arr1
|
||||
this.$refs.popup.open()
|
||||
},
|
||||
//获取商品数据
|
||||
getProduct(e) {
|
||||
|
||||
this.goodlist = []
|
||||
for (let i in e) {
|
||||
this.goodlist.push({
|
||||
app_goods_id: e[i].product_id,
|
||||
app_goods_name: e[i].store_name,
|
||||
app_goods_pic: e[i].image,
|
||||
app_goods_price: e[i].price,
|
||||
})
|
||||
}
|
||||
|
||||
this.$refs.popup.close()
|
||||
},
|
||||
|
||||
//创建房间
|
||||
create_live_room: function(e) {
|
||||
|
||||
if (this.cover_path == '') {
|
||||
uni.showToast({
|
||||
title: '请上传封面',
|
||||
duration: 2000,
|
||||
icon: 'none'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
if (this.livename == '') {
|
||||
uni.showToast({
|
||||
title: '请填写标题',
|
||||
duration: 2000,
|
||||
icon: 'none'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
if (this.goodlist.length == 0) {
|
||||
uni.showToast({
|
||||
title: '请添加商品',
|
||||
duration: 2000,
|
||||
icon: 'none'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
createPushLive({
|
||||
live_name: this.livename,
|
||||
cover: this.cover_path,
|
||||
app_name: "shop",
|
||||
app_user_id: this.$store.state.app.userInfo.uid,
|
||||
goods: this.goodlist
|
||||
}).then(res => {
|
||||
console.log(res)
|
||||
uni.sendHostEvent('log', res, (ret) => {
|
||||
//发送消息成功回调
|
||||
console.log('消息成功' + JSON.stringify(res));
|
||||
|
||||
});
|
||||
|
||||
if (res.code == 1) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/live/anchor?data=' + encodeURIComponent(JSON.stringify(res
|
||||
.data))
|
||||
})
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: res.msg,
|
||||
duration: 2000,
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
}).catch((err) => {
|
||||
uni.sendHostEvent('log', err, (ret) => {
|
||||
//发送消息成功回调
|
||||
console.log('消息成功' + JSON.stringify(err));
|
||||
|
||||
});
|
||||
})
|
||||
|
||||
},
|
||||
chooseImage: function() {
|
||||
let that = this;
|
||||
that.$util.uploadImageOne('upload/image', function(res) {
|
||||
// console.log(res.data.path)
|
||||
that.cover_path = res.data.path
|
||||
that.imageSrc = res.data.path
|
||||
});
|
||||
|
||||
},
|
||||
},
|
||||
onBackPress() {
|
||||
|
||||
|
||||
// this.$refs['showpopup'].close()
|
||||
// this.$refs['showtip'].close()
|
||||
// this.$refs['showimage'].close()
|
||||
// this.$refs['showshare'].close()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.top-do-box {
|
||||
width: 90%;
|
||||
margin: auto;
|
||||
/* #ifdef MP-WEIXIN */
|
||||
margin-top: 120upx;
|
||||
/* #endif */
|
||||
/* #ifdef APP-PLUS */
|
||||
margin-top: 60upx;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.ico-box {
|
||||
width: 70upx;
|
||||
height: 70upx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.ico {
|
||||
color: #FFFFFF;
|
||||
font-size: 48upx;
|
||||
}
|
||||
|
||||
.lico {
|
||||
color: #FFFFFF;
|
||||
font-size: 28upx;
|
||||
margin-right: 4upx;
|
||||
}
|
||||
|
||||
.do-box {
|
||||
width: 90%;
|
||||
padding: 40upx 0;
|
||||
flex-wrap: nowrap;
|
||||
margin: auto;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.do-box-top {
|
||||
.cover-box {
|
||||
width: 193rpx;
|
||||
height: 193rpx;
|
||||
background: #F4F4F4;
|
||||
border-radius: 10upx;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
margin-top: 32rpx;
|
||||
}
|
||||
|
||||
.cover-box-img {
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
margin: 0 auto;
|
||||
margin-top: 30rpx;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.cover-inputplaceholder {
|
||||
font-size: 30rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #737373;
|
||||
}
|
||||
|
||||
.cover-input {
|
||||
font-size: 30rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #000;
|
||||
margin-top: 32rpx;
|
||||
margin-bottom: 70rpx;
|
||||
}
|
||||
|
||||
|
||||
.cover-text {
|
||||
position: absolute;
|
||||
bottom: 30rpx;
|
||||
width: 100%;
|
||||
height: 50upx;
|
||||
line-height: 50upx;
|
||||
text-align: center;
|
||||
font-size: 28upx;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.cover-box image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
.do-box-check {
|
||||
margin-top: 35rpx;
|
||||
flex: 1;
|
||||
|
||||
.do-box-check-top {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 30rpx;
|
||||
|
||||
.do-box-check-left {
|
||||
display: flex;
|
||||
.check-top-imga {
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
margin-right: 20rpx;
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.check-top-txt {
|
||||
font-size: 30rpx;
|
||||
font-family: PingFang SC-Medium, PingFang SC;
|
||||
font-weight: 500;
|
||||
color: #333333;
|
||||
}
|
||||
}
|
||||
|
||||
.do-box-check-right {
|
||||
.check-top-imgb {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.check-lable {
|
||||
width: 200upx;
|
||||
height: 60upx;
|
||||
line-height: 60upx;
|
||||
border-radius: 60upx;
|
||||
background-color: rgba(0, 0, 0, .2);
|
||||
text-align: center;
|
||||
color: #FFFFFF;
|
||||
font-size: 28upx;
|
||||
}
|
||||
|
||||
.uni-input {
|
||||
background: none !important;
|
||||
color: #FFFFFF;
|
||||
font-size: 40upx;
|
||||
margin-top: 20upx;
|
||||
}
|
||||
|
||||
/* 底部分享 */
|
||||
.uni-share {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
/* #endif */
|
||||
background-color: #fff;
|
||||
padding: 0 40upx;
|
||||
border-top-left-radius: 20upx;
|
||||
border-top-right-radius: 20upx;
|
||||
}
|
||||
|
||||
.uni-share-title {
|
||||
line-height: 60rpx;
|
||||
font-size: 24rpx;
|
||||
padding: 15rpx 0;
|
||||
text-align: center;
|
||||
border-bottom: 2upx solid #F0F0F0;
|
||||
}
|
||||
|
||||
.uni-share-content {
|
||||
/* #ifndef APP-NVUE */
|
||||
/* display: flex; */
|
||||
/* #endif */
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
/* justify-content: space-around; */
|
||||
padding: 15px 0;
|
||||
/* padding-bottom: 0; */
|
||||
}
|
||||
|
||||
.content-image {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
}
|
||||
|
||||
.uni-share-content-text {
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.uni-share-btn {
|
||||
height: 90rpx;
|
||||
line-height: 90rpx;
|
||||
font-size: 14px;
|
||||
border-top-color: #f5f5f5;
|
||||
border-top-width: 1px;
|
||||
border-top-style: solid;
|
||||
text-align: center;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.type-lable {
|
||||
width: 20%;
|
||||
margin-left: 2.5%;
|
||||
height: 60upx;
|
||||
line-height: 60upx;
|
||||
border-radius: 60upx;
|
||||
text-align: center;
|
||||
color: #666666;
|
||||
font-size: 24upx;
|
||||
border: 2upx solid #F0F0F0;
|
||||
margin-bottom: 20upx;
|
||||
}
|
||||
|
||||
.type-lable-active {
|
||||
background-color: #ff2d54;
|
||||
border: 2upx solid #ff2d54;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.ok-but {
|
||||
width: 100%;
|
||||
height: 90upx;
|
||||
line-height: 90upx;
|
||||
border-radius: 90upx;
|
||||
font-size: 28upx;
|
||||
color: #FFFFFF;
|
||||
text-align: center;
|
||||
background-color: #ff2d54;
|
||||
margin: 20upx auto;
|
||||
}
|
||||
|
||||
.ok-but-none {
|
||||
background-color: #F0F0F0;
|
||||
}
|
||||
|
||||
.loc-lable {
|
||||
line-height: 70upx;
|
||||
text-align: center;
|
||||
font-size: 32upx;
|
||||
}
|
||||
|
||||
.loc-lable-active {
|
||||
color: #ff2d54;
|
||||
}
|
||||
|
||||
.start-but {
|
||||
width: 60%;
|
||||
height: 90upx;
|
||||
line-height: 90upx;
|
||||
border-radius: 90upx;
|
||||
font-size: 36upx;
|
||||
color: #FFFFFF;
|
||||
text-align: center;
|
||||
background-color: #ff2d54;
|
||||
position: fixed;
|
||||
bottom: 100upx;
|
||||
left: 20%;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,590 @@
|
|||
<template>
|
||||
<view class="view_body">
|
||||
<z-paging ref="paging" refresher-only @onRefresh="onRefresh">
|
||||
<view class="" :style="'height:'+statusBarHeight+'px'">
|
||||
|
||||
</view>
|
||||
<view>
|
||||
<view class="search_content flex_a_c_j_sb">
|
||||
<view class="flex_a_c">
|
||||
<view class="iconfont icon-sousuo" style="font-size: 39rpx;"></view>
|
||||
<input type="text" v-model="keyword" placeholder="搜索主播或关键字"
|
||||
placeholder-style="font-size: 30rpx;" @input="change">
|
||||
</view>
|
||||
<button class="search_btn" @click="search">搜索</button>
|
||||
</view>
|
||||
|
||||
<view class="content-detail">
|
||||
<view class="banner">
|
||||
<view class="banner-detail" v-for="(item,i) in list" :key='i' @click="zhisort(i)">
|
||||
<view class="banner-name">
|
||||
{{item.name}}
|
||||
</view>
|
||||
<view class="banner-t" v-if="isindex==i">
|
||||
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
</view>
|
||||
<view class="content-detaila" @click="jump_url">
|
||||
去开直播
|
||||
<text class="iconfont icon-xiangyou"></text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<scroll-view scroll-top="0" scroll-y="true" class="goods_body_scroll" v-if="isindex==0">
|
||||
<view class="roomsbox">
|
||||
<view class="roomblock" v-for="(room,index) in roomList" :key="index" @click="jump(room)"
|
||||
style="border: 1px solid #e1d9d4;">
|
||||
<image :src="room.cover" mode="aspectFill" v-if="room.cover"></image>
|
||||
<image src="/static/lw/6.gif" mode="aspectFill" v-else></image>
|
||||
<view class="livetitle">{{room.live_name}}</view>
|
||||
<view class="roomstatus-d" v-if="room.status==1" style="background-color: #09BB07;">
|
||||
</view>
|
||||
<view class="roomstatus-d" v-else style="background-color: #fa2306;">
|
||||
</view>
|
||||
|
||||
<view class="roomstatus" style="color: #00B26A;" v-if="room.status==1">直播中
|
||||
</view>
|
||||
<view class="roomstatus" style="color: #fa2306;" v-else>已停播
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</scroll-view>
|
||||
<scroll-view scroll-top="0" scroll-y="true" class="goods_body_scroll" v-if="isindex==1">
|
||||
<view v-for="(pp,index) in roomList" :key="index">
|
||||
<view class="roomsbox-a" v-for="(kk,i) in pp" :key="i">
|
||||
<view class="roomsbox-title">
|
||||
{{i}}
|
||||
</view>
|
||||
<view class="roomsbox">
|
||||
<view class="roomblock" style="border: 1px solid #e1d9d4;" v-for="(room,j) in kk"
|
||||
:key="j" @click="hsitroyjump(room)">
|
||||
<image :src="room.cover" mode="aspectFill" v-if="room.cover"></image>
|
||||
<image src="/static/lw/6.gif" mode="aspectFill" v-else></image>
|
||||
<view class="livetitle">{{room.live_name}}</view>
|
||||
<view class="roomstatus-d" v-if="room.status==1" style="background-color: #09BB07;">
|
||||
</view>
|
||||
<view class="roomstatus-d" v-else style="background-color: #fa2306;">
|
||||
</view>
|
||||
<view class="roomstatus-d" v-if="room.status==3" style="background-color: #e1d9d4;">
|
||||
</view>
|
||||
<view class="roomstatus" style="color: #00B26A;" v-if="room.status==1">直播中
|
||||
</view>
|
||||
<view class="roomstatus" style="color: #fa2306;" v-else>已停播
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
</scroll-view>
|
||||
<view class="noshuju" v-if="roomList.length==0">
|
||||
<emptyPage title="暂无房间信息"></emptyPage>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</z-paging>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import emptyPage from '@/components/emptyPage.vue';
|
||||
import {
|
||||
live,
|
||||
playbackList
|
||||
} from '@/api/api.js'
|
||||
|
||||
|
||||
export default {
|
||||
components: {
|
||||
emptyPage
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
keyword: '',
|
||||
statusBarHeight: 0,
|
||||
page: 1,
|
||||
dataindex: 1,
|
||||
page_data: true,
|
||||
list: [{
|
||||
name: '直播精选'
|
||||
},
|
||||
{
|
||||
name: '历史直播'
|
||||
},
|
||||
|
||||
],
|
||||
roomList: [],
|
||||
user: [],
|
||||
index: 0,
|
||||
isGetLoginInfo: true,
|
||||
isindex: 0,
|
||||
|
||||
};
|
||||
},
|
||||
onLoad() {
|
||||
|
||||
this.statusBarHeight = uni.getSystemInfoSync().statusBarHeight;
|
||||
},
|
||||
mounted() {
|
||||
if (this.isUserInfoExist()) {
|
||||
console.log('用户信息存在');
|
||||
this.getRoomList()
|
||||
} else {
|
||||
console.log('用户信息不存在');
|
||||
uni.showModal({
|
||||
// title: '标题',
|
||||
content: '用户信息不存在,是否重新登录',
|
||||
showCancel: true,
|
||||
cancelText: '取消',
|
||||
confirmText: '确定',
|
||||
success: function(res) {
|
||||
if (res.confirm) {
|
||||
// 用户点击了确定按钮
|
||||
uni.redirectTo({
|
||||
url: '/pages/login/login'
|
||||
})
|
||||
} else if (res.cancel) {
|
||||
// 用户点击了取消按钮
|
||||
console.log('用户点击了取消按钮');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
onShow() {},
|
||||
onReachBottom() {
|
||||
if (this.isindex == 0) {
|
||||
this.getRoomList()
|
||||
} else {
|
||||
this.getbackList()
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
|
||||
onPullDownRefresh: function() {
|
||||
console.log('下拉刷新')
|
||||
this.getRoomList()
|
||||
},
|
||||
methods: {
|
||||
|
||||
//下拉刷新被触发
|
||||
onRefresh() {
|
||||
//以告知z-paging下拉刷新结束,这样才可以开始下一次的下拉刷新
|
||||
setTimeout(() => {
|
||||
//1.5秒之后停止刷新动画
|
||||
if (this.isindex == 0) {
|
||||
this.getRoomList()
|
||||
} else {
|
||||
this.getbackList()
|
||||
}
|
||||
this.$refs.paging.complete();
|
||||
}, 1500)
|
||||
},
|
||||
isUserInfoExist() {
|
||||
const userInfo = this.$store.state.app.userInfo;
|
||||
uni.sendHostEvent('userinfo', userInfo, (ret) => {
|
||||
//发送消息成功回调
|
||||
console.log('消息成功' + JSON.stringify(userInfo));
|
||||
});
|
||||
return !!userInfo; // 如果 userInfo 为空,则返回 false;否则返回 true
|
||||
},
|
||||
//输入
|
||||
change(e) {
|
||||
// console.log(e)
|
||||
if (e.detail.value.length <= 0) {
|
||||
this.page = 1
|
||||
this.getRoomList()
|
||||
}
|
||||
},
|
||||
//查询
|
||||
search() {
|
||||
|
||||
this.page = 1
|
||||
this.roomList = []
|
||||
if (this.isindex == 0) {
|
||||
this.getRoomList()
|
||||
} else {
|
||||
this.getbackList()
|
||||
}
|
||||
},
|
||||
//分类
|
||||
zhisort(i) {
|
||||
this.isindex = i
|
||||
this.page = 1
|
||||
this.roomList = []
|
||||
if (i == 0) {
|
||||
this.getRoomList()
|
||||
} else {
|
||||
this.getbackList()
|
||||
}
|
||||
},
|
||||
getbackList: function() {
|
||||
playbackList({
|
||||
page_size: 100,
|
||||
page: this.page,
|
||||
app_name: 'shop',
|
||||
keyword: this.keyword
|
||||
}).then(res => {
|
||||
// console.log(res)
|
||||
if (res.data.code = 1) {
|
||||
uni.hideLoading()
|
||||
// this.roomList = res.data.lists
|
||||
// this.roomList.push(res.data.lists)
|
||||
if (res.data.lists.length > 0) {
|
||||
const groupedArray = res.data.lists.reduce((acc, obj) => {
|
||||
const date = obj.date;
|
||||
if (!acc[date]) {
|
||||
acc[date] = [];
|
||||
}
|
||||
acc[date].push(obj);
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
this.roomList.push(groupedArray)
|
||||
// 输出结果
|
||||
console.log(this.roomList);
|
||||
}
|
||||
// this.page = this.page + 1
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 拉取房间列表
|
||||
* @return {[type]}
|
||||
* [description]
|
||||
*/
|
||||
getRoomList: function() {
|
||||
live({
|
||||
page_size: 10,
|
||||
page: this.page,
|
||||
app_name: 'shop',
|
||||
keyword: this.keyword
|
||||
}).then(res => {
|
||||
// console.log(res)
|
||||
if (res.data.code = 1) {
|
||||
uni.hideLoading()
|
||||
if (res.data.lists.length > 0) {
|
||||
let list = res.data.lists;
|
||||
let productList = this.$util.SplitArray(list, this.roomList);
|
||||
setTimeout(() => {
|
||||
this.$set(this, 'roomList', productList);
|
||||
}, 500)
|
||||
this.page = this.page + 1
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
},
|
||||
jump: function(e) {
|
||||
console.log(e)
|
||||
uni.navigateTo({
|
||||
url: '/pages/live/spectator' + '?data=' + encodeURIComponent(JSON.stringify(e))
|
||||
})
|
||||
|
||||
},
|
||||
//历史直播间
|
||||
hsitroyjump: function(e) {
|
||||
console.log(e)
|
||||
|
||||
uni.navigateTo({
|
||||
url: '/pages/live/histroyroom' + '?data=' + encodeURIComponent(JSON.stringify(e))
|
||||
})
|
||||
|
||||
},
|
||||
//创建直播间
|
||||
jump_url() {
|
||||
if (this.isUserInfoExist()) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/room/create_room'
|
||||
});
|
||||
} else {
|
||||
uni.showModal({
|
||||
// title: '标题',
|
||||
content: '用户信息不存在,是否重新登录',
|
||||
showCancel: true,
|
||||
cancelText: '取消',
|
||||
confirmText: '确定',
|
||||
success: function(res) {
|
||||
if (res.confirm) {
|
||||
// 用户点击了确定按钮
|
||||
uni.redirectTo({
|
||||
url: '/pages/login/login'
|
||||
})
|
||||
} else if (res.cancel) {
|
||||
// 用户点击了取消按钮
|
||||
console.log('用户点击了取消按钮');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
.goods_body_scroll {
|
||||
margin-top: 50rpx;
|
||||
}
|
||||
|
||||
.search_content {
|
||||
margin: 0 auto;
|
||||
width: 724rpx;
|
||||
height: 64rpx;
|
||||
padding: 2px 2px 2px 21.05rpx;
|
||||
border-radius: 175rpx;
|
||||
background: #fff;
|
||||
margin-bottom: 21rpx;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
border: 2rpx solid #FCB9AD;
|
||||
margin-top: 30rpx;
|
||||
|
||||
.icon-sousuo {
|
||||
font-size: 26.32rpx;
|
||||
font-weight: bold;
|
||||
color: #c8c7c6;
|
||||
margin-right: 17.54rpx;
|
||||
}
|
||||
|
||||
.search_btn {
|
||||
color: #fff;
|
||||
width: 105.26rpx;
|
||||
height: 56rpx;
|
||||
line-height: 56rpx;
|
||||
background: #f84221;
|
||||
border-radius: 100px;
|
||||
font-size: 28.07rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.content-detail {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.banner {
|
||||
display: flex;
|
||||
padding-left: 28rpx;
|
||||
|
||||
}
|
||||
|
||||
.roomsbox-title {
|
||||
font-size: 30rpx;
|
||||
font-family: PingFang SC-Medium, PingFang SC;
|
||||
font-weight: 500;
|
||||
color: #333333;
|
||||
margin-bottom: 30rpx;
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
|
||||
.banner-detail {
|
||||
width: 133rpx;
|
||||
margin-right: 30rpx;
|
||||
}
|
||||
|
||||
.banner-name {
|
||||
font-size: 33rpx;
|
||||
font-family: PingFang SC-Medium, PingFang SC;
|
||||
font-weight: 500;
|
||||
color: #333333;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.content-detaila {
|
||||
font-size: 33rpx;
|
||||
font-family: PingFang SC-Medium, PingFang SC;
|
||||
font-weight: 500;
|
||||
color: #333333;
|
||||
margin-bottom: 10rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.banner-t {
|
||||
width: 46px;
|
||||
height: 0rpx;
|
||||
opacity: 1;
|
||||
border: 2rpx solid #F84221;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.noshuju {
|
||||
height: 760upx;
|
||||
}
|
||||
|
||||
.mico-18 {
|
||||
margin-top: 10upx;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.view_body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
.roomstatus-d {
|
||||
width: 20upx;
|
||||
height: 20upx;
|
||||
border-radius: 20upx;
|
||||
position: absolute;
|
||||
left: 20upx;
|
||||
top: 20upx;
|
||||
}
|
||||
|
||||
.roomstatus {
|
||||
position: absolute;
|
||||
left: 40upx;
|
||||
top: 10upx;
|
||||
font-size: 28upx;
|
||||
}
|
||||
|
||||
.livetitle {
|
||||
position: absolute;
|
||||
bottom: 20upx;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
height: 70upx;
|
||||
line-height: 70upx;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.top {
|
||||
display: flex;
|
||||
padding: 20upx;
|
||||
top: 0;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
width: 95%;
|
||||
background-color: #FFFFFF;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.top_li {
|
||||
font-size: 32upx;
|
||||
padding: 0 20upx;
|
||||
display: table-cell;
|
||||
/* vertical-align:bottom; */
|
||||
padding-top: 10upx;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.top-lable-box {
|
||||
/* #ifdef APP-PLUS */
|
||||
/* flex: 1; */
|
||||
|
||||
/* #endif */
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.active {
|
||||
font-size: 40upx;
|
||||
font-weight: 800;
|
||||
color: #333333;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.roomsbox {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.roomblock {
|
||||
width: 45%;
|
||||
height: 300upx;
|
||||
border-radius: 10upx;
|
||||
overflow: hidden;
|
||||
margin-bottom: 20upx;
|
||||
position: relative;
|
||||
margin-left: 2.5%;
|
||||
}
|
||||
|
||||
.right_top_scroll {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
.scroll-view {
|
||||
display: inline-block;
|
||||
margin-right: 30rpx;
|
||||
text-align: center;
|
||||
font-size: 32rpx;
|
||||
height: 60rpx;
|
||||
line-height: 60rpx;
|
||||
box-sizing: border-box;
|
||||
padding: 0 10rpx;
|
||||
|
||||
}
|
||||
|
||||
.view_body {
|
||||
background: #FFFFFF;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.mico-14 {
|
||||
margin-right: 4upx;
|
||||
}
|
||||
|
||||
.noshuju {
|
||||
height: 750upx;
|
||||
}
|
||||
|
||||
.noshuju_ico {
|
||||
width: 120upx;
|
||||
height: 80upx;
|
||||
margin: 0 auto;
|
||||
margin-top: 300rpx;
|
||||
|
||||
}
|
||||
|
||||
.noshuju_ico image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.mico-18 {
|
||||
margin-top: 10upx;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.create-but {
|
||||
background-color: #1ce0c5;
|
||||
width: 120upx;
|
||||
height: 60upx;
|
||||
line-height: 60upx;
|
||||
color: #FFFFFF;
|
||||
text-align: center;
|
||||
border-radius: 10upx;
|
||||
/* #ifdef MP-WEIXIN */
|
||||
margin-left: 40upx;
|
||||
/* #endif */
|
||||
margin-top: 4upx;
|
||||
}
|
||||
</style>
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue