初始项目

This commit is contained in:
liupopo
2023-02-11 12:55:02 +08:00
parent 1748bda84a
commit 0b89e36064
3363 changed files with 506201 additions and 1 deletions

View File

@@ -0,0 +1,107 @@
.lotus-address-picker {
font-size: 26rpx;
padding-top: 30rpx;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
line-height: normal;
padding-right: 30rpx;
box-sizing: border-box;
}
.lotus-address-picker-box {
/*display: -webkit-box;
display: -webkit-flex;*/
display: flex;
align-items: center;
justify-content: center;
justify-content: flex-start;
padding-top: 10rpx;
padding-bottom: 10rpx;
}
.lotus-address-picker-box-item {
height: 600upx;
overflow-y: auto;
width: 33.333%;
padding-left: 20rpx;
padding-right: 20rpx;
box-sizing: border-box;
}
.lotus-address-picker2 {
color: #e93b3d;
position: relative;
}
.lotus-address-picker2:after {
content: '';
position: absolute;
right: 0;
top: 65%;
transform: translateY(-35%) rotate(-45deg);
width: 20rpx;
height: 10rpx;
border-left-width: 4rpx;
border-bottom-width: 4rpx;
border-left-style: solid;
border-bottom-style: solid;
border-left-color: #e93b3d;
border-bottom-color: #e93b3d;
}
.lotus-address-mask {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: 999;
background: rgba(0, 0, 0, 0.5);
}
.lotus-address-box {
background: #fff;
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: auto;
}
.lotus-address-action {
font-size: 30rpx;
/*display: -webkit-box;
display: -webkit-flex;*/
display: flex;
align-items: center;
justify-content: center;
justify-content: space-between;
padding: 25rpx 30rpx;
position: relative;
}
.lotus-address-action:after {
content: " ";
position: absolute;
left: 0;
top: 0;
right: 0;
height: 1px;
border-top: 1px solid #eee;
color: #eee;
transform-origin: 0 0;
transform: scaleY(0.5);
}
.lotus-address-action:before {
content: " ";
position: absolute;
left: 0;
bottom: 0;
right: 0;
height: 1px;
border-bottom: 1px solid #eee;
color: #eee;
transform-origin: 0 100%;
transform: scaleY(0.5);
}
.lotus-address-action-cancel {
color: #969696;
}
.lotus-address-action-affirm {
color: #e93b3d;
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,216 @@
<template>
<!--地址picker-->
<view :status="checkStatus" v-if="lotusAddressData.visible" class="lotus-address-mask">
<view class="lotus-address-box">
<view class="lotus-address-action">
<text @tap="cancelPicker" class="lotus-address-action-cancel">取消</text>
<text @tap="chosedVal" class="lotus-address-action-affirm">确认</text>
</view>
<view class="lotus-address-picker-box">
<!---->
<scroll-view scroll-y :scroll-into-view="'pid'+pChoseIndex" class="lotus-address-picker-box-item">
<view @tap="clickPicker(0,pIndex,pItem);" :id="'pid'+pIndex" :class="pIndex === pChoseIndex?'lotus-address-picker lotus-address-picker2':'lotus-address-picker'" v-for="(pItem,pIndex) in province" :key="pIndex">{{pItem}}</view>
</scroll-view>
<!---->
<scroll-view scroll-y :scroll-into-view="'cid'+cChoseIndex" class="lotus-address-picker-box-item">
<view @tap="clickPicker(1,cIndex,cItem);" :id="'cid'+cIndex" :class="cIndex === cChoseIndex?'lotus-address-picker lotus-address-picker2':'lotus-address-picker'" v-for="(cItem,cIndex) in city" :key="cIndex">{{cItem}}</view>
</scroll-view>
<!---->
<scroll-view scroll-y :scroll-into-view="'tid'+tChoseIndex" class="lotus-address-picker-box-item">
<view @tap="clickPicker(2,tIndex,tItem);" :id="'tid'+tIndex" :class="tIndex === tChoseIndex?'lotus-address-picker lotus-address-picker2':'lotus-address-picker'" v-for="(tItem,tIndex) in town" :key="tIndex">{{tItem}}</view>
</scroll-view>
<!--区END-->
</view>
</view>
</view>
<!--地址picker END-->
</template>
<script>
import {lotusAddressJson} from "./Winglau14-lotusAddress.js";
export default {
props:['lotusAddressData'],
data() {
return {
visible: false,
province:[],
city:[],
town:[],
provinceName:'',
cityName:'',
townName:'',
type:0,//0新增1编辑
pChoseIndex:-1,
cChoseIndex:-1,
tChoseIndex:-1,
};
},
methods:{
//取消
cancelPicker(){
const provinceCode = this.getTarId(this.provinceName);
const cityCode = this.getTarId(this.cityName);
const townCode = this.getTarId(this.townName);
this.$emit("choseVal",{
provice:this.provinceName,
provinceCode,
city:this.cityName,
cityCode,
town:this.townName,
townCode,
isChose:0,
visible:false
});
},
//获取最后选择的省市区的值
chosedVal() {
this.type = 1;
const provinceCode = this.getTarId(this.provinceName);
const cityCode = this.getTarId(this.cityName);
const townCode = this.getTarId(this.townName);
this.$emit("choseVal",{
provice:this.provinceName,
provinceCode,
city:this.cityName,
cityCode,
town:this.townName,
townCode,
isChose:1,
visible:false
});
},
//获取省市区value
getTarId(name,type){
let id = 0;
const _this = this;
lotusAddressJson.map((item,index)=>{
if(item.name === name){
id = item.value;
}
});
return id;
},
//获取市数据
getCityArr(parentId){
let city = [];
lotusAddressJson.map((item,index)=>{
if(item.parent === parentId){
city.push(item.name);
}
});
return city;
},
//获取区数据
getTownArr(parentId){
let town = [];
lotusAddressJson.map((item,index)=>{
if(index>34&&item.parent === parentId){
town.push(item.name);
}
});
return town;
},
//初始化数据
initFn(){
console.log(1);
lotusAddressJson.map((item,index)=>{
if(index<=34){
this.province.push(item.name);
}
});
//已选择省市区,高亮显示对应选择省市区
const p = this._props.lotusAddressData.provinceName;
const c = this._props.lotusAddressData.cityName;
const t = this._props.lotusAddressData.townName;
if(p){
this.pChoseIndex = this.getTarIndex(this.province,p);
}
if(p&&c){
const pid = this.getTarId(p);
this.city = this.getCityArr(pid);
this.cChoseIndex = this.getTarIndex(this.city,c);
}
if(p&&c&&t){
const cid= this.getTarId(c);
this.town = this.getTownArr(cid);
this.tChoseIndex = this.getTarIndex(this.town,t);
}
},
//获取已选省市区
getChosedData(){
const pid = this.getTarId(this.provinceName,'provice');
this.city = this.getCityArr(pid);
const cid= this.getTarId(this.cityName,'city');
this.town = this.getTownArr(cid);
//已选省市区获取对应index
if(this.provinceName){
this.pChoseIndex = this.getTarIndex(this.province,this.provinceName);
}
if(this.cityName){
this.cChoseIndex = this.getTarIndex(this.city,this.cityName);
}
if(this.townName){
this.tChoseIndex = this.getTarIndex(this.town,this.townName);
}
},
//选择省市区交互
clickPicker(type,index,name){
//省
if(type === 0){
this.pChoseIndex = index;
this.provinceName = name;
this.cChoseIndex = -1;
this.tChoseIndex = -1;
this.cityName = '';
this.townName = '';
}
//市
if(type ===1){
this.cChoseIndex = index;
this.cityName = name;
this.tChoseIndex = -1;
this.townName = '';
}
//区
if(type === 2){
this.tChoseIndex = index;
this.townName = name;
}
//获取省市区数据
this.getChosedData();
},
//获取已选省市区index
getTarIndex(arr,tarName){
let cIndex = 0;
arr.map((item,index)=>{
if(item === tarName){
cIndex = index;
}
});
return cIndex;
}
},
created() {
this.provinceName = this._props.lotusAddressData.provinceName;
this.cityName = this._props.lotusAddressData.cityName;
this.townName = this._props.lotusAddressData.townName;
},
computed:{
checkStatus(){
let t = null;
const _this = this;
if(!_this.visible){
_this.initFn();
_this.visible = _this._props.lotusAddressData.visible;
t = _this.visible;
}
return t;
}
}
}
</script>
<style lang="less">
@import "./Winglau14-lotusAddress.css";
</style>

View File

@@ -0,0 +1,125 @@
<template>
<view class="box">
<view class="boxContent">
<view class="boxContent2">
<view class="before" :style="{top: (100-percent)+'%'}"></view>
<view class="jd" :style="{background: bg}"></view>
<view class="after" :style="{top: (100-percent)+'%'}"></view>
</view>
<view class="percent">{{percent}}%</view>
</view>
<view class="atitle">{{titleOne}}</view>
<view class="atitle">{{titleTwo}}</view>
</view>
</template>
<script>
export default {
name: "circle-percent",
props: {
titleOne:{
type:String,
default: '发卡'
},
titleTwo:{
type:String,
default: '21'
},
bg: {
type:String,
default: 'red'
},
percent: {
type:String,
default: "0"
}
},
computed: {
},
data() {
return {
}
},
methods: {
}
}
</script>
<style lang="scss">
.box{
box-sizing: border-box;
width: 33%;
text-align:center;
margin: 20upx 0;
.boxContent{
position: relative;
width: 160upx;
height: 160upx;
border-radius: 50%;
margin: 0 auto;
border: 4upx solid #d9d9d9;
overflow: hidden;
.boxContent2{
width: 100%;
height: 100%;
border-radius: 50%;
border: 4upx solid #fff;
box-sizing: border-box;
overflow: hidden;
.before,
.after{
content: "";
position: absolute;
width: 200%;
height: 200%;
top: 0;
left: 50%;
background-color: rgba(255, 255, 255, .4);
border-radius: 45%;
transform: translate(-50%, -100%) rotate(0);
animation: rotate 6s linear infinite;
z-index: 10;
}
.after {
border-radius: 44%;
background-color: rgba(255, 255, 255, .9);
transform: translate(-50%, -100%) rotate(0);
animation: rotate 10s linear -5s infinite;
z-index: 20;
}
@keyframes rotate {
50% {
transform: translate(-50%, -103%) rotate(180deg);
} 100% {
transform: translate(-50%, -100%) rotate(360deg);
}
}
.jd{
width: 100%;
height: 100%;
bottom:0;
}
}
.percent{
font-size: 36upx;
font-weight: bold;
position: absolute;
top: 52upx;
width: 100%;
text-align: center;
z-index: 90;
}
}
.atitle{
margin-top: 0upx;
font-size: 20upx;
color: $uni-text-color-grey;
font-size: $uni-font-size-base;
}
}
</style>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,93 @@
<template>
<view class="coupon-item">
<view class="coupon-money">
<view class="nick" ></view>
<view class="layof" :style="{color:theme}">{{item.amount}}</view>
<view class="end_time">{{item.endTime | formatCreateTime}}前使用</view>
<view >
<view class="demand">{{ item.minPoint }} {{ item.amount }}</view>
</view>
</view>
<view class="get-btn" v-if="!types" :style="{color:color, borderColor:color, background:solid}" @click="acceptCoupon(item)" >立即领取</view>
<navigator class="get-btn" v-if="types" :style="{color:color, borderColor:color, background:solid}" :url='item.url' @click="acceptCoupon(item)">立即使用</navigator>
</view>
</template>
<script>
import Api from '@/common/api';
import mallplusCopyright from '@/components/mall-copyright/mallplusCopyright.vue';
import { formatDate } from '@/common/date';
export default {
components:{
},
data() {
return {
}
},
props:{
item:{
type: Object
},
types:{
type: String,
default: ''
},
theme:{
type: String,
default: '#ff9000'
},
solid:{
type: String,
default: '#ffffff'
},
color:{
type: String,
default: '#ff9000'
},
},
filters: {
formatCreateTime(time) {
let date = new Date(time);
return formatDate(date, 'yyyy-MM-dd hh:mm:ss')
},
},
methods: {
async acceptCoupon(item){
uni.showLoading({
title: '请稍后'
});
let params = { couponId: item.id };
let data = await Api.apiCall('post', Api.index.acceptCoupon, params);
console.log(data);
if (data) {
this.$api.msg(data);
}
uni.hideLoading();
},
}
}
</script>
<style lang='scss'>
.coupon-item {
width:100%; height:auto; display:table; border-radius:10upx; padding:0 20upx; margin-top:22upx; border:1px solid #eeeeee; position:relative;
.coupon-money {
width:465upx; height:auto; display:table; float:left; padding:26upx 0; border-style:none dotted none none; border-color:#eeeeee;
.nick { width:100%; height:50upx; line-height:30upx; font-size:$font-sm; color:$font-color-999; }
.tit { width:100%; height:50upx; line-height:50upx; font-size:$font-sm; color:$font-color-999; }
.demand { width:100%; height:30upx; line-height:30upx; font-size:$font-sm; color:$font-color-999; }
.layof { width:100%; height:48upx; line-height:30upx; font-size:44upx; color:#ff9000; font-weight:bold; }
.end_time { width:100%; height:30upx; line-height:30upx; font-size:$font-sm; color:$font-color-999; }
}
.get-btn { width:146upx; height:52upx; line-height:50upx; position:absolute; top:50%; right:26upx; margin-top:-26upx; text-align:center; border-radius:60upx; color:#ff9000; border:1px solid #ff9000; font-size:$font-sm; float:right; }
}
.coupon-item:after { width:40upx; height:20upx; position:absolute; left:460upx; top:-1px; border-radius:0 0 40upx 40upx; content:""; display:block; background:$bgcolor_white; border:1px solid #eeeeee; border-top:0px; }
.coupon-item:before { width:40upx; height:20upx; position:absolute; left:460upx; bottom:-1px; border-radius:40upx 40upx 0 0; content:""; display:block; background:$bgcolor_white; border:1px solid #eeeeee; border-bottom:0px; }
</style>

View File

@@ -0,0 +1,85 @@
import value from './ball.js';
var list = []
var boundary = [[],[]]
function getDistance( x_1, y_1, x_2, y_2){
let x = (x_2 - x_1)*2;
let y = (y_2 - y_1)*2;
let s = Math.pow((x * x + y * y), 0.5);
return s;
}
function sustained(that){
let data = value.list;
let index_1 = 0;
let index_2 = 0;
setInterval(function(){
for (let number = 0; number < data.length; number++) {
data[number].y = data[number].y+( data[number].floating[1] ? 0.05 : -0.05) ;
data[number].floating[0] < 15 ? data[number].floating[0] = data[number].floating[0]+1 : data[number].floating[0] = 1 ;
data[number].floating[0] == 1 ? data[number].floating[1] = !data[number].floating[1] : data[number].floating[1];
value.mapping(that);
for (let i = 0; i < data.length; i++) {
index_1 = getDistance(data[i].x,data[i].y,data[number].x,data[number].y);
index_2 = (data[i].radius*2) + (data[number].radius*2);
if(i != number){
if( index_1 < index_2){
data[i].x = data[i].x+(-(data[number].x-data[i].x)/100) ;
data[i].y = data[i].y+(-(data[number].y-data[i].y)/100) ;
(data[i].x-data[i].radius) < 0 ? data[i].x = data[i].radius : data[i].x;
(data[i].y-data[i].radius) < 0 ? data[i].y = data[i].radius : data[i].y;
(data[i].x+data[i].radius) > value.boundary[0] ? data[i].x = (value.boundary[0]-data[i].radius) : data[i].x;
(data[i].y+data[i].radius) > value.boundary[1] ? data[i].y = (value.boundary[1]-data[i].radius) : data[i].y;
value.mapping(that);
}
}
}
}
},100);
}
function mapping(_this){
let data = value.list
let context = uni.createCanvasContext('canvas',_this);
for (let i = 0; i < data.length; i++) {
context.beginPath();
context.arc(data[i].x, data[i].y, data[i].radius, 0, 2 * Math.PI, true);
context.setFillStyle(data[i].color[data[i].colse ? 1 : 0]);
context.fill();
context.setFillStyle('#FFFFFF');
context.setFontSize(data[i].size);
if(data[i].labelName.length < 6){
context.fillText(data[i].labelName,(data[i].x - (data[i].size*(0.5*data[i].labelName.length))), (data[i].y + data[i].size*(0.5)))
}else{
context.fillText(data[i].labelName.substring(0, 3),(data[i].x - (data[i].size*(0.5*(data[i].labelName.substring(0, 3)).length))),
((data[i].y + data[i].size*(0.5))-data[i].size*(0.8)))
context.fillText(data[i].labelName.substring(3, 6),(data[i].x - (data[i].size*(0.5*(data[i].labelName.substring(3, 6)).length))),
((data[i].y + data[i].size*(0.5))+data[i].size*(0.8)))
}
}
context.draw();
}
export default {mapping,list,sustained,boundary}

View File

@@ -0,0 +1,21 @@
import value from '../../componets/drag-ball/drag-ball.js';
var list = [{x:100,y:50,radius:25},{x:200,y:50,radius:25},{x:300,y:50,radius:25}]
function mapping(_this){
let data = value.list
let context = uni.createCanvasContext('canvas',_this);
for (let i = 0; i < data.length; i++) {
context.beginPath();
context.arc(data[i].x, data[i].y, data[i].radius, 0, 2 * Math.PI, true);
context.setFillStyle('#AAAAAA');
context.fill();
}
context.draw();
}
export default {mapping,list}

View File

@@ -0,0 +1,135 @@
<template>
<canvas
:canvas-id="id"
id="canvas"
@touchstart="touchstart"
@touchend="touchend"
></canvas>
<!-- @touchmove.prevent="touchmove" -->
</template>
<script>
import dragBall from './ball.js';
var data = [];
function getDistance( x_1, y_1, x_2, y_2){
let x = (x_2 - x_1)*2;
let y = (y_2 - y_1)*2;
let s = Math.pow((x * x + y * y), 0.5);
return s;
}
export default {
props:{
onInit: {
type: Array,
default: null
},
colse:{
type:Boolean
}
},
data() {
return {
index:'false',
touchstarte_x:0,
touchstarte_y:0,
id:'canvas',
number: 0
}
},
onReady() {
// colse(index) {
// !index ? index : this.trim();
// }
this.trim();
},
watch: {
onInit() {
this.trim();
}
},
methods: {
trim(){
dragBall.boundary[0] = 320; //高
dragBall.boundary[1] = 500; // 宽
// var query = uni.createSelectorQuery();
// query.select('#canvas').boundingClientRect()
// query.exec((res) => {
// dragBall.boundary[0]=res[0].width
// dragBall.boundary[1]=res[0].height;
// })
dragBall.list = this.onInit;
dragBall.mapping(this);
data = dragBall.list;
dragBall.sustained(this);},
touchstart(e){
this.touchstarte_x = e.mp.touches[0].x;
this.touchstarte_y = e.mp.touches[0].y;
for (let i = 0; i < data.length; i++) {
if( getDistance(data[i].x,data[i].y,this.touchstarte_x,this.touchstarte_y) < (data[i].radius*2)){
this.index = i;
if(this.number < 8){
data[i].colse =!data[i].colse;
data[i].colse ? this.number +=1 : this.number -=1;
} else {
if(data[i].colse){
data[i].colse =!data[i].colse;
this.number -=1;
}
}
this.$emit('click_',i)
dragBall.mapping(this);
// this.touchstarte_x = this.touchstarte_x-data[i].x;
// this.touchstarte_y = this.touchstarte_y-data[i].y;
}
}
},
// touchmove(e){
// if(this.index != 'false'){
//
// let index_1,index_2;
// let tag = e.touches[0];
//
// data[this.index].x = tag.x-this.touchstarte_x ;
// data[this.index].y = tag.y-this.touchstarte_y ;
//
// for (let i = 0; i < data.length; i++) {
//
// index_1 = getDistance(data[i].x,data[i].y,data[this.index].x,data[this.index].y);
// index_2 = (data[i].radius*2) + (data[this.index].radius*2);
// if(i!= this.index){
//
// if( index_1 > index_2){
// dragBall.mapping(this);
// }else{
// data[i].x = data[i].x+(-(data[this.index].x-data[i].x)/10) ;
// data[i].y = data[i].y+(-(data[this.index].y-data[i].y)/10) ;
//
// (data[i].x-data[i].radius) < 0 ? data[i].x = data[i].radius : data[i].x;
// (data[i].y-data[i].radius) < 0 ? data[i].y = data[i].radius : data[i].y;
//
//
// (data[i].x+data[i].radius) > dragBall.boundary[0] ? data[i].x = (dragBall.boundary[0]-data[i].radius) : data[i].x;
// (data[i].y+data[i].radius) > dragBall.boundary[1] ? data[i].y = (dragBall.boundary[1]-data[i].radius) : data[i].y;
//
// dragBall.mapping(this);
// break;
// }
// }
// }
// }
// },
touchend(){this.index = 'false';}
}
}
</script>
<style>
page{width: 100%;height: 100%;}
canvas {width: 100%;height: 90%;}
</style>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,453 @@
var eonfox = function(config){
if( config ){
if( config.debug ){
eonfox.prototype.debug = true;
}
if( config.application ){
eonfox.prototype.application = config.application;
}
if( config.api_server_url ){
eonfox.prototype.api_server_url = config.api_server_url;
}
}
};
eonfox.prototype = {
constructor : eonfox,
//是否开启调试模式
debug : false,
//文件服务器URL
file_server_url : 'http://img.eonfox.cc/',
//接口地址 应用ID
api_server_url : 'http://server.test.eapie.com/',
application : "test",
//会话名称
session_name : 'Eonfox_API_Engine_Session',
/*
转换时间格式
*/
switchingTime: function(timestamp) {
var date = new Date(timestamp * 1000); //时间戳为10位需*1000时间戳为13位的话不需乘1000
var Y = date.getFullYear() + '-';
var M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-';
var D = (date.getDate() < 10 ? '0' + date.getDate() : date.getDate()) + ' ';
var h = (date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + ':';
var m = (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()) + ':';
var s = (date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds());
return Y + M + D + h + m + s;
},
//提交的有效等待时间
submit_sleep_expire_time : 30,
//请求任务
submit_task : null,
/**
* 提交队列
*/
submit_queue : [],
/**
* 提交登记
*/
submit_register : function( config ){
config.time = ((new Date()).getTime()/1000);//赋值是 时间戳 (秒),用于有效时间
eonfox.prototype.submit_queue.push(config);
},
/**
* 运行提交
*/
submit_run : function(){
if( eonfox.prototype.submit_queue.length < 1 ){
return false;//没有执行的提交
}
if( eonfox.prototype.submit_queue[0].runtime ){
return false;//正在执行
}
//检查是否已经失效
if( (eonfox.prototype.submit_queue[0].time + eonfox.prototype.submit_sleep_expire_time) < ((new Date()).getTime()/1000) ){
//已经过了有效期
//删除第一个元素
eonfox.prototype.submit_queue.shift();
//再次提交
return eonfox.prototype.submit_run();
}
eonfox.prototype.submit_queue[0].runtime = true;
var config = eonfox.prototype.submit_queue[0];
//从本地缓存中同步获取指定 key 对应的内容。
var token = eonfox.prototype.token(function(e){
config.error(e);
});
if( !(function(){try{ return token['session_right_token'];}catch(e){return false;}}()) ){
config.right_data.session = "start";
config.right_data.application = this.application;
}else{
config.right_data.token = token['session_right_token'];
config.left_data.token = token['session_left_token'];
config.left_data.session = "start";
config.left_data.application = this.application;
}
var request = {
url : config.url,
method : "POST",
dataType : "json",
responseType : "text",
header: {"Content-Type":"application/x-www-form-urlencoded"},//跨域防止请求options
complete : function(){
//当请求完成之后调用这个函数无论成功或失败。执行时间比success晚
//删除第一个元素
eonfox.prototype.submit_queue.shift();
//再次提交
eonfox.prototype.submit_run();
},
success : function(){},
fail : function(err){
config.error(err);
}
}
//右令牌
var right_token_post = function(){
request.data = config.right_data;
request.success = function(success_data_all){
//这里要注意,这里是包含了 data
if(typeof success_data_all != 'object'){
success_data_all = (function(){try{ return JSON.parse(success_data_all);}catch(e){return false;}}());
}
var success_data = success_data_all.data? success_data_all.data : null;
if(typeof success_data != 'object'){
console.warn("应用接口响应异常");
return config.callback(false, success_data_all);
}
//如果存在请求令牌,直接返回数据
if( (function(){try{ return success_data['token'];}catch(e){return false;}}()) ){
//储存令牌
eonfox.prototype.storage_token(success_data);
//返回到回调函数
return config.callback(success_data, success_data_all);
}else{
//否则说明没有这个会话,再进行左令牌查询
return left_token_post();
}
};
if( eonfox.prototype.debug ){
console.log("post():右令牌提交:", request);
}
eonfox.prototype.submit_task = uni.request(request);
};
//左令牌
var left_token_post = function(){
request.data = config.left_data;
request.success = function(success_data_all){
//这里要注意,这里是包含了 data
if(typeof success_data_all != 'object'){
success_data_all = (function(){try{ return JSON.parse(success_data_all);}catch(e){return false;}}());
}
var success_data = success_data_all.data? success_data_all.data : null;
if(typeof success_data != 'object'){
console.warn("应用接口响应异常");
return config.callback(false, success_data_all);
}
//如果没有报错
if( (function(){try{ return success_data['token'];}catch(e){return false;}}()) ){
//储存令牌
eonfox.prototype.storage_token(success_data);
}
//返回到回调函数
return config.callback(success_data, success_data_all);
};
if( eonfox.prototype.debug ){
console.log("post():左令牌提交:", request);
}
eonfox.prototype.submit_task = uni.request(request);
};
return right_token_post();
},
/**
* 获取左token
* 如果没用传入回调函数,那么则直接返回当前左令牌,但是有可能会出现左令牌失效
* 正常操作是,传入一个回调函数,左令牌始终是保持最新的。
*
* @param {Function} #fn
*/
websocketToken : function(fn){
if(typeof fn != "function"){
var storage_token = eonfox.prototype.token();
if( (function(){try{ return storage_token['session_websocket_token'];}catch(e){return false;}}()) ){
return storage_token['session_websocket_token'];
}else{
return '';
}
}else{
eonfox.prototype.submit({
callback: function(){
//从本地缓存中同步获取指定 key 对应的内容。
var websocket_token = "";
var websocket_token = eonfox.prototype.token();
if( (function(){try{ return storage_token['session_websocket_token'];}catch(e){return false;}}()) ){
websocket_token = storage_token['session_websocket_token'];
}
fn(websocket_token);
}
});
return true;
}
},
/* 中断请求任务 */
abort : function(){
//清理等待的请求
eonfox.prototype.submit_queue = [];
//中断请求任务
if( eonfox.prototype.submit_task.abort ){
eonfox.prototype.submit_task.abort();
}
},
/* 提交请求
* 暂时只支持 POST
* {
* url : this.api_server_url,默认接口地址
* data : {},
* callback : 回调函数 第一个是单个 data第二个是 全部的返回数据
* error : 错误回调函数
* }
*
*/
submit : function(config){
if( eonfox.prototype.debug ){
console.log("submit()传入参数:", config);
}
//回调函数
if( !config.callback || config.callback.constructor != Function ){
config.callback = function(){};
}
if( !config.error || config.error.constructor != Function ){
config.error = function(){};
}
//路由
if(typeof config.url == 'undefined' || typeof config.url != 'string'){
config.url = this.api_server_url;
}
config.right_data = {};
config.left_data = {};
//请求字符串
if( config.request ){
//如果是对象,则先转换为字符串
if(typeof config.request == "object"){
config.request = JSON.stringify(config.request)
}
if(typeof config.request == "string"){
config.right_data.data = config.request;
config.left_data.data = config.request;
}
}
//用户传入的data数据
if( config.data && typeof config.data == "object" ){
for(var i in config.data){
config.right_data[i] = config.data[i];
config.left_data[i] = config.data[i];
}
}
if( eonfox.prototype.debug ){
console.log("post()right_data、left_data:", config.right_data, config.left_data);
}
/*//是否强制提交
config.recursion = config.recursion? true : false;
//大于0说明存在队列
if( this.submit_queue.length > 0 ){
//判断是否强制提交
if( config.recursion ){
//去登记注册
eonfox.prototype.submit_register(config);
}else{
//否则返回错误信息
console.warn("应用接口提交队列个数:", this.submit_queue.length);
return config.error("应用接口出现重复提交,前方正在提交队列个数:", this.submit_queue.length);
}
}else{
//去登记注册
eonfox.prototype.submit_register(config);
} */
//去登记注册
eonfox.prototype.submit_register(config);
//并且调用执行
eonfox.prototype.submit_run();
},
/**
* 储存token
*
* @param {Object} data
*/
storage_token : function(data){
if( !data ){
return false;
}
var token_data = null;
var exist_right_token = false;
var exist_left_token = false;
exist_right_token = (function(){try{ return data['token']['session_right_token'];}catch(e){return false;}}());
exist_left_token = (function(){try{ return data['token']['session_left_token'];}catch(e){return false;}}());
if(exist_right_token && exist_left_token){
token_data = data['token'];
}else{
//有可能是顶级关联对象
exist_right_token = (function(){try{ return data['session_right_token'];}catch(e){return false;}}());
exist_left_token = (function(){try{ return data['session_left_token'];}catch(e){return false;}}());
if(exist_right_token && exist_left_token){
token_data = data;
}
}
if(!token_data){
return false;
}
//从本地缓存中同步获取指定 key 对应的内容。
var storage_token = eonfox.prototype.token();
if( (function(){try{ return storage_token['session_right_token'];}catch(e){return false;}}()) &&
(function(){try{ return storage_token['session_left_token'];}catch(e){return false;}}()) ){
if(storage_token['session_right_token'] == token_data['session_right_token'] ||
storage_token['session_left_token'] == token_data['session_left_token'] ){
if( eonfox.prototype.debug ){
console.log("需要对比旧token中的当前时间戳,为true则不需要更新token", storage_token['session_now_time'], token_data['session_now_time'], parseInt(storage_token['session_now_time']) > parseInt(token_data['session_now_time']));
}
if( parseInt(storage_token['session_now_time']) > parseInt(token_data['session_now_time']) ){
if( eonfox.prototype.debug ){
console.log("并发异步不需要更新token" );
}
return false;
}
}
}
//console.log( uni.setStorageSync );
try {
uni.setStorageSync(this.session_name +":"+ this.application, JSON.stringify(token_data));
} catch (e) {
console.warn(e);
return false;
}
return true;
},
/**
* 获取token
*
* @param {Function} error_function
*/
token : function(error_function){
//异步可能存在覆盖的问题所以对比已存在的token,如果右左有一个相同则比较当前时间,即最大的当前时间是最新的。
var storage_token = false;
try {
storage_token = uni.getStorageSync(this.session_name +":"+ this.application);
if( storage_token ){
storage_token = (function(){try{ return JSON.parse(storage_token);}catch(e){return false;}}());
}
} catch (e) {
console.warn(e);
if(error_function){
error_function(e);
}
return false;
}
return storage_token;
},
/**
* 获取左token
* 如果没用传入回调函数,那么则直接返回当前左令牌,但是有可能会出现左令牌失效
* 正常操作是,传入一个回调函数,左令牌始终是保持最新的。
*
* @param {Function} #fn
*/
left_token : function(fn){
if(typeof fn != "function"){
var storage_token = eonfox.prototype.token();
if( (function(){try{ return storage_token['session_left_token'];}catch(e){return false;}}()) ){
return storage_token['session_left_token'];
}else{
return '';
}
}else{
eonfox.prototype.submit({
callback: function(){
//从本地缓存中同步获取指定 key 对应的内容。
var left_token = "";
var storage_token = eonfox.prototype.token();
if( (function(){try{ return storage_token['session_left_token'];}catch(e){return false;}}()) ){
left_token = storage_token['session_left_token'];
}
fn(left_token);
}
});
return true;
}
},
/* 获取 websocket 数据 */
websocket_data : function(res){
console.log(res);
if( !res.data ){
return false;
}
return JSON.parse( res.data );
}
};
export default eonfox;

View File

@@ -0,0 +1,285 @@
var fns = {
//--------------
//api接口验证
checkError: function(data, ids, error){
if(typeof(error)!='function'){
error=function(){
}
}
if(data.errno){
error(data.errno, data.error);
return false;
}
if(!data.data){
error(1, "未知错误");
return false;
}
if(ids){
if(typeof ids =='object'){
for( var i in ids){
if(typeof ids[i] != "undefined"){
var id = ids[i];
if( data.data[id] && data.data[id].errno ){
error(data.data[id].errno, data.data[id].error);
return false;
}
}else{
error(1, "“"+ids[i]+"”目标,未知错误");
return false;
}
}
}else if(typeof ids =='string' || typeof ids == 'number'){
if(typeof data.data[ids] != "undefined" ){
if( data.data[ids].errno ){
error(data.data[ids].errno, data.data[ids].error);
return false;
}
}else{
error(1, "“"+ids+"”目标,未知错误");
return false;
}
}else{
error(1, "“"+ids+"”目标,未知错误");
return false;
}
}
var data_list = {};
if(data.data){
for(var i in data.data){
if(typeof data.data[i].data != "undefined"){
data_list[i] = data.data[i].data;
}
}
}
return data_list;
},
//数据处理 ceil向上取整
number_pre:function(number,pre){
switch(pre){
case 'ceil':
return Math.ceil(number)
break;
}
},
//保留两位小数
number_floor_2:function(number){
var number = number * 100;
number = Math.floor(number)
number = number/100;
return number.toFixed(2);
},
//错误信息处理
err:function(title,data,_json,fun){
if(data){
if(_json){
data=JSON.stringify(data)
}
console.log(title+' :',data)
uni.showToast({
title:title+' : '+data,
icon:'none',
duration:1500,
success() {
if(fun){
fun();
}
}
})
}else{
console.log(title)
uni.showToast({
title:title,
icon:'none',
duration:1500,
success() {
if(fun){
fun();
}
}
})
}
},
//成功信息处理
success(title,fun){
if(fun){
fun();
}
uni.hideLoading();
/* uni.showToast({
title:title,
icon:'success',
success() {
if(fun){
fun();
}
}
}) */
},
//敬请期待
waiting:function(){
uni.showToast({
title:'敬请期待',
icon:'none'
})
},
//授权验证
oauth_:function(){
uni.setStorage({
key:'oauth',
data:true
})
},
noauth:function(){
uni.setStorage({
key:'oauth',
data:false
})
},
//绑定验证
unionid:function(){
uni.setStorage({
key:'unionid',
data:true
})
},
nunionid:function(){
uni.setStorage({
key:'unionid',
data:false
})
},
//绑定
bind:function(){
console.log('oauth');
uni.getStorage({
key:'oauth',
success(re) {
console.log('oauth',re);
}
})
},
//获取指定url参数
getUrlQuery:function (urlStr) {
// var urlStr = location.search.substr(1) ? location.search.substr(1) : "";
var urlArr = [];
for(var i = 0; i < urlStr.split("&").length; i++) {
urlArr.push(urlStr.split("&")[i].split("=")[0] ? urlStr.split("&")[i].split("=")[0] : "");
urlArr.push(urlStr.split("&")[i].split("=")[1] ? urlStr.split("&")[i].split("=")[1] : "onlyKey")
}
if(urlStr == "") {
return;
} else {
var urlObj = {}
for(var i = 0; i < urlArr.length; i += 2) {
if(urlArr[i] != "") {
urlObj[urlArr[i]] = decodeURIComponent(urlArr[i + 1]);
}
}
return urlObj;
}
}
,
// url参数解析
getUrlkey:function(url) {
var params = {};
var urls = url.split("?"); console.log('1_分割url:', urls)
var arr = urls[1].split("&"); console.log('2_分割urls[1]:', arr)
for (var i = 0, l = arr.length; i < l; i++) {
var a = arr[i].split("="); console.log('3_遍历 arr 并分割后赋值给a:', a[0], a[1])
params[a[0]] = a[1]; console.log('4_a给params对象赋值:', params)
} console.log('5_结果:', params)
return params;
}
,
toast(tit,url,time){
if(!time){
time=1500
}
uni.showToast({
title:tit,
success() {
setTimeout(function(){
uni.reLaunch({
url:url
})
},time)
}
})
},
setSystemInfoSync(){
uni.getStorage({
key:'SystemInfoSync',
fail(err) {
console.log('设置缓存');
try {
console.log('star');
const res = uni.getSystemInfoSync();
console.log('config'+JSON.stringify(res));
uni.setStorage({
key:'SystemInfoSync',
data:res
})
console.log('ok');
} catch (e) {
console.log('catch+'+JSON.stringify(e));
// error
}
},
})
},
getCompare(Version,newVersion,fun){
if(Version==newVersion){
console.log('没有更新');
return
}
console.log('接收到参数');
uni.getStorage({
key:'SystemInfoSync',
success(res) {
console.log('缓存:'+JSON.stringify(res));
if(res.data){
var SystemInfoSync=res.data;
console.log('json:'+JSON.stringify(SystemInfoSync));
console.log('设备:'+SystemInfoSync.platform);
if(SystemInfoSync.platform=='android'){
console.log('设备:安卓');
fun();
}
}else{
return this.setSystemInfo();
}
},
fail(err) {
console.log('缓存获取失败'+JSON.stringify(err));
const res = uni.getSystemInfoSync();
console.log('config'+JSON.stringify(res));
uni.setStorage({
key:'SystemInfoSync',
data:res,
success() {
if(res.platform=='android'){
console.log('设备:安卓');
fun();
}
}
})
},
complete() {
console.log('获取缓存');
}
})
}
//------------------------
};
export default fns;

View File

@@ -0,0 +1,39 @@
import eonfox from '@/components/eonfox/eonfox.js';
var ef=new eonfox()
import f from '@/components/eonfox/fns.js';
var pay= {
shoppingCar:function(groupId,method,pass,fun){
ef.submit({
request:{
s:['SHOPGROUPGOODSSELFPAY',[{id:groupId,pay_method:method,pay_password:pass}]]
},
callback:function(data){
const dataList=(data=f.checkError(data,'s',function(errno,error){
f.err(error)
}))
console.log('da...',dataList)
if(dataList.s==true){
fun()
}
// var dataList=data.s
// if(dataList.data){
// if(dataList.data==true){
// f.err('支付成功')
// }else{
// f.err('支付失败')
// }
//
// }
console.log('支付结果');
},
error(err){
f.err('',err,1)
}
})
}
}
export default pay;

View File

@@ -0,0 +1,12 @@
/* 商家模块 */
var merchant = function(){};
merchant.prototype = {
constructor : merchant,
//收银员的订单列表是否需要刷新
cashierOrderListRefresh : false
};
export default merchant;

View File

@@ -0,0 +1,72 @@
import eonfox from '@/components/eonfox/eonfox.js';
var ef = new eonfox();
var order = {
/* 检查支付状态
order_id 要检查的订单ID
frequency 检查的次数当等于0时则返回回调
callback 回调。成功时callback.success 失败时callback.fail
因为有 frequency 次数,所以每次进来 -1 。如果不等于0那么要继续递归
order.checkPayState({
order_id: order_id,
frequency: 3,
success:function(){
},
fail:function(){
}
})
*/
checkPayState : function(data){
var _this = this;
if(typeof data.success != 'function') data.success = function(){};
if(typeof data.fail != 'function') data.fail = function(){};
if( typeof data.frequency != 'number') data.frequency = 3;
if( !data.frequency || !data.order_id ){
return data.fail('参数不正确', data);
}
//如果不等于0那么要继续递归
data.frequency --;
//开始查询状态 0表示未支付1表示支付成功。
ef.submit({
request:{
s:['APPLICATIONORDERSELFPAYSTATE',[{order_id: data.order_id}]]
},
callback: function(r){
console.log('order.checkPayState:::',r);
// console.log('支付查询回调成功',r.data.s.data) ;return r.data.s.data;
if( !r.errno && !r.data.s.errno && r.data.s.data){
console.log('支付成功');
//获取成功,无错误信息时
return data.success();
} else {
console.log('支付状态查询失败或者未支付');
if( !data.frequency ){
return data.fail();
}else{
setTimeout(function() {
return _this.checkPayState(data);
}, 2000);
}
}
},
error(err){
data.fail(err);
}
})
}
};
export default order;

View File

@@ -0,0 +1,70 @@
import eonfox from '@/components/eonfox/eonfox.js';
var ef=new eonfox()
import f from '@/components/eonfox/fns.js';
var pay= {
set_password:function(pass,pass_confirm,fun){
ef.submit({
request:{
set_pass:['setpass',[{password:pass}]]
},
callback:function(data){
if(data=f.checkError(data,'set_pass',function(errno,error){
f.err(error)
})){
fun()
}else{
f.err('设置失败')
}
console.log('支付结果');
},
error(err){
f.err('',err,1)
}
})
},
shoppingCar:function(id,method,pass,fun){
ef.submit({
request:{
s:['SHOPORDERSELFPAYMENT',[{order_id:id,pay_method:method,pay_password:pass}]]
},
callback:function(data){
const dataList=(data=f.checkError(data,'s',function(errno,error){
f.err(error)
}))
console.log('da...',dataList)
if(dataList.s.order_id){
f.err('支付成功')
return ok
}
console.log('支付结果');
},
error(err){
f.err('',err,1)
}
})
},
//取消订单
cancel_order:function(id,fun){
ef.submit({
request:{
cancel_order:['SHOPORDERSELFCANCEL',[{id:id}]]
},
callback:function(data){
if(data=f.checkError(data,'cancel_order',function(errno,error){
f.err(error)
})){
fun()
}else{
f.err('订单取消失败')
}
},
error(err){
f.err('',err,1)
}
})
},
}
export default pay;

View File

@@ -0,0 +1,61 @@
var polling = {
//定时器ID
_interval_id : null,
_switch : false,
//关闭
close : function(){
clearInterval(this._interval_id);
this._interval_id = null;
},
//暂停
stop : function(){
this._switch = false;
},
//启动
start : function(){
this._switch = true;
},
/**
* 开启
*
* @param {Time} ms 毫秒数
* @param {Function} fn 回调函数
*/
run : function(ms, fn){
if( !ms || typeof ms != 'number'){
ms = 3000;//默认3秒
}
if(!fn || typeof fn != 'function'){
fn = function(){};
}
var _this = this;
//如果已经存在,则要关闭轮询
if( _this._interval_id ){
_this.start();
return true;
}
var i = 0;
_this._switch = true;
_this._interval_id = setInterval(function(){
if( !_this._switch ){
return false;
}
i ++;
fn(i);
}, ms);
return true;
}
};
export default polling;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
// 版本控制文件
var version='0.0.12';
export default version;

View File

@@ -0,0 +1,541 @@
import eonfoxObject from '@/components/eonfox/eonfox.js';
var eonfox = new eonfoxObject();
var websocket_app = false;
//#ifdef APP-PLUS
websocket_app = true;
//#endif
var websocket = function(config){};
websocket.prototype = {
// url :'wss://developer.eapie.eonfox.com:9997',//测试版
url :'wss://eapie.eonfox.com:9999',//正式版
connect_type : 0,//连接类型。0是安卓1是非安卓
debug: false,//是否调试
close_type : 0,//1是手动关闭不会再尝试连接
token:'',//websocket令牌
open:false,//打开状态
client_id:'',//连接ID
server_time: 0,//websocket 服务器时间
messages:[],//接受的websocket消息的集合
message_max_number:10,//最大消息个数
messages_change:function(){},//变动时执行的函数
heartbeat_interval_id: null,//心跳检测的定时器ID
heartbeat_ms: 15000,//心跳检测毫秒
heartbeat_messages:[],//心跳检测的信息集合
heartbeat_message_max_number:10,//最大消息个数
heartbeat_messages_change:function(){},//变动时执行的函数
connect_parameter: null,//连接websocket的参数
/* 调试信息 */
debug_message:function(message, fn){
if( !websocket.prototype.debug ){
return false;
}
console.log(message);
uni.showToast({
title: message,
icon: 'none',
duration: 3000
});
if(typeof fn == 'function'){
fn();
}
},
/* 获取 websocket 数据 */
get_data : function(res){
if( !res.data ){
return false;
}
return JSON.parse( res.data );
},
/* 设置心跳检测的信息集合 */
set_heartbeat_messages: function(message){
if( this.heartbeat_messages.length >= this.heartbeat_message_max_number ){
this.heartbeat_messages.pop();//删除最后一个元素
}
//往前面添加
this.heartbeat_messages.unshift(message);
if(typeof websocket.prototype.heartbeat_messages_change == 'function') websocket.prototype.heartbeat_messages_change();
},
/* 设置心跳检测的信息集合 */
set_messages: function(message){
if( this.messages.length >= this.message_max_number ){
this.messages.pop();//删除最后一个元素
}
//往前面添加
this.messages.unshift(message);
if(typeof websocket.prototype.messages_change == 'function') websocket.prototype.messages_change();
},
messages_change_function: function(fn){
websocket.prototype.messages_change = fn;
},
heartbeat_messages_change_function: function(fn){
websocket.prototype.heartbeat_messages_change = fn;
},
/**
* 获取左 websocket_token
* 如果没用传入回调函数,那么则直接返回当前左令牌,但是有可能会出现左令牌失效
* 正常操作是,传入一个回调函数,左令牌始终是保持最新的。
*
* @param {Function} #fn
*/
session_websocket_token : function(fn){
if(typeof fn != "function"){
var storage_token = eonfox.token();
if( (function(){try{ return storage_token['session_websocket_token'];}catch(e){return false;}}()) ){
return storage_token['session_websocket_token'];
}else{
return '';
}
}else{
eonfox.submit({
callback: function(){
//从本地缓存中同步获取指定 key 对应的内容。
var websocket_token = "";
var storage_token = eonfox.token();
if( (function(){try{ return storage_token['session_websocket_token'];}catch(e){return false;}}()) ){
websocket_token = storage_token['session_websocket_token'];
}
fn(websocket_token);
}
});
return true;
}
},
/*
* 获取 websocket 令牌
* 传入一个回调函数
*/
get_token : function(fn){
var websocket_token = websocket.prototype.session_websocket_token();
if( websocket_token ){
console.log('get_websocket_token 已存在', websocket_token);
fn(websocket_token);
}else{
console.log('get_websocket_token 不存在,异步获取');
websocket.prototype.session_websocket_token(function(websocket_token){
fn(websocket_token);
});
}
},
/* 连接 websocket */
connect: function(connectParameter){
websocket.prototype.connect_type = 1;//连接类型。0是安卓1是非安卓
websocket.prototype.not_android_connect(connectParameter);
// if( websocket_app && plus.os.name == 'Android'){
// websocket.prototype.connect_type = 0;//连接类型。0是安卓1是非安卓
// websocket.prototype.android_connect(connectParameter);
// }else{
// websocket.prototype.connect_type = 1;//连接类型。0是安卓1是非安卓
// websocket.prototype.not_android_connect(connectParameter);
// }
},
//安卓程序
android_connect: function(connectParameter){},
//非安卓程序
//data.onSocketOpen
not_android_connect: function(connectParameter){
var _this = this;
websocket.prototype.debug_message('websocket.connect 连接 websocket');
websocket.prototype.connect_parameter = connectParameter;
websocket.prototype.get_token(function(token){
if( !token ){
//这里弹出错误消息
websocket.prototype.debug_message('websocket.connect 连接失败!没有获取到 websocket token');
}
//链接
uni.connectSocket({
url: websocket.prototype.url,
success(){
_this.set_messages({
state:true,
content:'连接webscoket成功',
});
websocket.prototype.token = token;
websocket.prototype.debug_message(' uni.connectSocket 连接webscoket成功!token:'+token);
},
fail(){
_this.set_messages({
state:false,
content:'连接webscoket失败',
});
websocket.prototype.debug_message(' uni.connectSocket 连接webscoket失败!token:'+token);
}
});
});
//WebSocket连接打开监听
uni.onSocketOpen(function () {
websocket.prototype.close_type = 0;
websocket.prototype.open = true;
websocket.prototype.debug_message('uni.onSocketOpen WebSocket连接已经打开监听!');
if(connectParameter && typeof connectParameter.onSocketOpen == 'function'){
connectParameter.onSocketOpen();
}
});
uni.onSocketClose(function (res) {
websocket.prototype.token = '';
websocket.prototype.open = false;
websocket.prototype.client_id = '';
//关闭心跳检测
if( websocket.prototype.heartbeat_interval_id ){
clearInterval( websocket.prototype.heartbeat_interval_id );
}
if(connectParameter && typeof connectParameter.onSocketClose == 'function'){
connectParameter.onSocketClose(res);
}
//开启心跳检测
if( websocket.prototype.close_type == 0){
websocket.prototype.debug_message('uni.onSocketClose 非手动关闭,开启心跳守护');
setTimeout(function(){
websocket.prototype.connect(connectParameter);
}, websocket.prototype.heartbeat_ms);
}
websocket.prototype.debug_message('uni.onSocketClose WebSocket 已关闭!');
});
//收到服务器内容
uni.onSocketMessage(function (res) {
console.log('onSocketMessage!!!!!!!!');
//给一个超时器
setTimeout(function(){
console.log('setTimeout!!!!!!!!');
websocket.prototype.debug_message('onSocketMessage 获取 websocket 数据:' + JSON.stringify(res));
var websocket_token = eonfox.websocketToken();
var r = websocket.prototype.get_data(res);
//websocket 检查连接ID值(旧-新)
if( (r.data && r.data.client_id && websocket.prototype.client_id != r.data.client_id) ||
(r.data && r.data.server_time && websocket.prototype.server_time != r.data.server_time) ||
(websocket.prototype.token != websocket_token) ){
if(r.data && r.data.client_id && websocket.prototype.client_id != r.data.client_id){
websocket.prototype.debug_message('websocket 连接ID 不一致',function(){
console.log('websocket.prototype.client_id != r.data.client_id', websocket.prototype.client_id, r.data.client_id);
});
}
if(r.data && r.data.server_time && websocket.prototype.server_time != r.data.server_time){
websocket.prototype.debug_message('websocket 服务器时间 不一致',function(){
console.log('websocket.prototype.server_time != r.data.server_time', websocket.prototype.server_time, r.data.server_time);
});
}
if(websocket.prototype.token != websocket_token){
websocket.prototype.debug_message('websocket_token 不一致',function(){
console.log('websocket.prototype.token != websocket_token', websocket.prototype.token, websocket_token);
});
}
return websocket.prototype.init( r.data.client_id, r.data.server_time, websocket_token, connectParameter, function(){
if(typeof connectParameter.onSocketMessage == 'function'){
connectParameter.onSocketMessage(res);
}
});//初始化
}else{
if(connectParameter && typeof connectParameter.onSocketMessage == 'function'){
connectParameter.onSocketMessage(res);
}
}
}, 0);
});
uni.onSocketError(function (res) {
//开启心跳检测
setTimeout(function(){
websocket.prototype.connect(connectParameter);
}, websocket.prototype.heartbeat_ms);
if(connectParameter && typeof connectParameter.onSocketError == 'function'){
connectParameter.onSocketError(res);
}
_this.set_messages({
state:false,
content:'连接webscoket失败',
error: res
});
websocket.prototype.debug_message('uni.onSocketError WebSocket连接打开失败请检查!error:'+res);
});
},
/* 初始化 */
init : function( client_id, server_time, token, connectParameter, callback){
var errorData = {
open : websocket.prototype.open,
token : websocket.prototype.token,
client_id : client_id
};
if( !websocket.prototype.open || !client_id ){
_this.set_messages({
state:false,
content:'websocket 初始化失败',
error: ''
});
websocket.prototype.debug_message('websocket 初始化失败!');
};
eonfox.submit({
request: {
s: ['SESSIONWEBSOCKETSELFCLIENT', [{
client_id: client_id, //连接id
server_time: server_time // 服务器时间
}]]
},
callback: function(){
//必须是在初始化成功之后 才更新连接ID值
websocket.prototype.client_id = client_id;
websocket.prototype.server_time = server_time;
//再次重置 websoket 令牌
websocket.prototype.token = token;
//开启心跳检测
if( websocket.prototype.heartbeat_interval_id ){
clearInterval( websocket.prototype.heartbeat_interval_id );
}
websocket.prototype.heartbeat_interval_id = setInterval(function(){
websocket.prototype.debug_message('websocket init 心跳检测');
websocket.prototype.heartbeat(function(errorData){
websocket.prototype.debug_message('websocket init 心跳检测失败', function(){
console.log('websocket_init 心跳检测失败返回值:', errorData);
});
clearInterval( websocket.prototype.heartbeat_interval_id );
websocket.prototype.connect(connectParameter);
});
}, websocket.prototype.heartbeat_ms);
if(typeof connectParameter.initSuccess != 'function') connectParameter.initSuccess = function(){};
connectParameter.initSuccess();
websocket.prototype.debug_message('websocket init 初始化成功');
websocket.prototype.set_heartbeat_messages({
state:true,
content:'websocket init 初始化成功!'
});
if(typeof callback != 'function') callback = function(){};
callback();
},
error : function(errorData){
websocket.prototype.debug_message('websocket init 初始化错误');
websocket.prototype.set_heartbeat_messages({
state:false,
content:'websocket init 初始化错误!',
error:errorData
});
return connectParameter.initError(errorData);
}
});
},
/* 发送心跳 */
heartbeat: function(errorFunction){
var errorData = {
open : websocket.prototype.open,
token : websocket.prototype.token,
client_id : websocket.prototype.client_id
};
if( !websocket.prototype.open || !websocket.prototype.token ){
if(typeof errorFunction != 'function') errorFunction = function(){};
websocket.prototype.debug_message('websocket heartbeat 初始化失败!');
websocket.prototype.set_heartbeat_messages({
state:false,
content:'websocket 初始化失败!'
});
return errorFunction(errorData);
};
var heartbeat = JSON.stringify({
module:'heartbeat',
application: eonfox.application,
token: websocket.prototype.token
});
uni.sendSocketMessage({
data: heartbeat,
success: function(res){
websocket.prototype.debug_message('websocket heartbeat 保持心跳成功!');
websocket.prototype.set_heartbeat_messages({
state:true,
content:'websocket heartbeat 保持心跳成功!'
});
},
fail: function(data){
websocket.prototype.debug_message('websocket heartbeat 保持心跳失败!');
websocket.prototype.set_heartbeat_messages({
state:false,
content:'websocket heartbeat 保持心跳失败!',
error: data
});
return errorFunction(errorData);
}
});
},
//重启 websocket
restart : function(){
websocket.prototype.close();
//重启
websocket.prototype.connect(websocket.prototype.connect_parameter);
websocket.prototype.debug_message('重启 websocket');
},
//关闭
close : function(){
//关闭
if( websocket.prototype.open ){
//连接类型。0是安卓1是非安卓
if( websocket.prototype.connect_type == 1 ){
uni.closeSocket();
}else{
//
}
}
websocket.prototype.close_type = 1;
websocket.prototype.token = '';
websocket.prototype.open = false;
websocket.prototype.client_id = '';
//关闭心跳检测
if( websocket.prototype.heartbeat_interval_id ){
clearInterval( websocket.prototype.heartbeat_interval_id );
}
},
/* 用户向用户推送 */
user_push : function(user_id, message, errorFunction){
var data = {
open : websocket.prototype.open,
token : websocket.prototype.token
}
if( !websocket.prototype.open || !websocket.prototype.token ){
if(typeof errorFunction != 'function') errorFunction = function(){};
return errorFunction(data);
}
var user_push = JSON.stringify({
module:'user_push',
application: eonfox.application,
token: websocket.prototype.token,
user_id:user_id,
message: message,
});
uni.sendSocketMessage({
data: user_push,
success: function(res){
websocket.prototype.debug_message('websocket 消息推送成功!', function(){
console.log('user_push', res)
});
websocket.prototype.set_messages({
state:true,
content:'websocket user_push 消息推送成功!',
});
},
fail: function(faildata){
websocket.prototype.debug_message('websocket 消息推送失败!', function(){
console.log('user_push', faildata)
});
websocket.prototype.set_messages({
state:false,
content:'websocket user_push 消息推送失败!',
error:faildata
});
return errorFunction(errorData);
}
});
},
/* 用户向后台推送 */
admin_push : function(message, errorFunction){
var data = {
open : websocket.prototype.open,
token : websocket.prototype.token
}
if( !websocket.prototype.open || !websocket.prototype.token ){
if(typeof errorFunction != 'function') errorFunction = function(){};
return errorFunction(data);
}
var admin_push = JSON.stringify({
module:'admin_push',
application: eonfox.application,
token: websocket.prototype.token,
message: message,
});
uni.sendSocketMessage({
data: admin_push,
success: function(res){
websocket.prototype.debug_message('websocket 消息推送成功!', function(){
console.log('admin_push', res)
});
websocket.prototype.set_messages({
state:true,
content:'websocket admin_push 消息推送成功!',
});
},
fail: function(faildata){
websocket.prototype.debug_message('websocket 消息推送失败!', function(){
console.log('admin_push', faildata)
});
websocket.prototype.set_messages({
state:false,
content:'websocket admin_push 消息推送失败!',
error:faildata
});
return errorFunction(errorData);
}
});
},
};
export default websocket;

View File

@@ -0,0 +1,28 @@
<template>
<!-- '<audio/>' 组件不再维护建议使用能力更强的 'uni.createInnerAudioContext' 接口 有时间再改-->
<!--增加audio标签支持-->
<audio
:id="node.attr.id"
:class="node.classStr"
:style="node.styleStr"
:src="node.attr.src"
:loop="node.attr.loop"
:poster="node.attr.poster"
:name="node.attr.name"
:author="node.attr.author"
controls></audio>
</template>
<script>
export default {
name: 'wxParseAudio',
props: {
node: {
type: Object,
default() {
return {};
},
},
},
};
</script>

View File

@@ -0,0 +1,119 @@
<template>
<view class="">
<!-- #ifdef MP -->
<image
:lazy-load="node.attr.lazyLoad"
:data-src="node.attr.src"
:src="node.attr.src"
@tap="wxParseImgTap"
mode="widthFix"
class="nodeclassStr"
/>
<!-- #endif -->
<!-- #ifndef MP -->
<image
:lazy-load="node.attr.lazyLoad"
:data-src="node.attr.src"
:src="node.attr.src"
@tap="wxParseImgTap"
:mode="node.attr.mode"
:class="node.classStr"
:style="newStyleStr || node.styleStr"
@load="wxParseImgLoad"
/>
<!-- #endif -->
</view>
</template>
<script>
export default {
name: 'wxParseImg',
data() {
return {
newStyleStr: '',
preview: true
};
},
inject: ['parseWidth'],
mounted() {},
props: {
node: {
type: Object,
default() {
return {};
}
}
},
methods: {
wxParseImgTap(e) {
if (!this.preview) return;
const { src } = e.currentTarget.dataset;
if (!src) return;
let parent = this.$parent;
while (!parent.preview || typeof parent.preview !== 'function') {
// TODO 遍历获取父节点执行方法
parent = parent.$parent;
}
parent.preview(src, e);
},
// 图片视觉宽高计算函数区
wxParseImgLoad(e) {
const { src } = e.currentTarget.dataset;
if (!src) return;
let { width, height } = e.mp.detail;
const recal = this.wxAutoImageCal(width, height);
const { imageheight, imageWidth } = recal;
const { padding, mode } = this.node.attr;//删除padding
// const { mode } = this.node.attr;
const { styleStr } = this.node;
// console.log(styleStr)
const imageHeightStyle = mode === 'widthFix' ? '' : `height: ${imageheight}px`;
// console.log(imageHeightStyle)
this.newStyleStr = `${styleStr}; ${imageHeightStyle}; width: ${imageWidth}px; padding: 0 ${+padding}px;`;//删除padding
// this.newStyleStr = `${styleStr}; ${imageHeightStyle}; width: ${imageWidth}px;`;
// console.log(this.newStyleStr);
},
// 计算视觉优先的图片宽高
wxAutoImageCal(originalWidth, originalHeight) {
// 获取图片的原始长宽
const windowWidth = this.parseWidth.value;
const results = {};
if (originalWidth < 60 || originalHeight < 60) {
const { src } = this.node.attr;
let parent = this.$parent;
while (!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.removeImageUrl(src);
this.preview = false;
}
// 判断按照那种方式进行缩放
if (originalWidth > windowWidth) {
// 在图片width大于手机屏幕width时候
results.imageWidth = windowWidth;
results.imageheight = windowWidth * (originalHeight / originalWidth);
} else {
// 否则展示原来的数据
results.imageWidth = originalWidth;
results.imageheight = originalHeight;
}
return results;
}
}
};
</script>
<style>
.nodeclassStr{
max-width: 100%;
float:left;
width: 750rpx;
padding: 0 0px;
}
</style>

View File

@@ -0,0 +1,53 @@
<template>
<rich-text :nodes="nodes" :class="node.classStr" :style="'user-select:' + parseSelect"></rich-text>
</template>
<script>
export default {
name: 'wxParseTable',
props: {
node: {
type: Object,
default() {
return {};
},
},
},
inject: ['parseSelect'],
data() {
return {
nodes:[]
};
},
mounted() {
this.nodes=this.loadNode([this.node]);
},
methods: {
loadNode(node) {
let obj = [];
for (let children of node) {
if (children.node=='element') {
let t = {
name:children.tag,
attrs: {
class: children.classStr,
// style: children.styleStr,
},
children: children.nodes?this.loadNode(children.nodes):[]
}
obj.push(t)
} else if(children.node=='text'){
obj.push({
type: 'text',
text: children.text
})
}
}
return obj
}
}
};
</script>
<style>
@import url("../parse.css");
</style>

View File

@@ -0,0 +1,98 @@
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node"/>
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</template>
<script>
// #ifdef APP-PLUS | H5
import wxParseTemplate from './wxParseTemplate0';
// #endif
// #ifdef MP
import wxParseTemplate from './wxParseTemplate1';
// #endif
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
// #ifdef APP-PLUS | H5
name: 'wxParseTemplate',
// #endif
// #ifdef MP
name: 'wxParseTemplate0',
// #endif
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(attr,e) {
const {
href
} = e.currentTarget.dataset;// TODO currentTarget才有dataset
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {// TODO 遍历获取父节点执行方法
parent = parent.$parent;
}
parent.navigate(href, e, attr);
}
}
};
</script>

View File

@@ -0,0 +1,88 @@
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate2';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate1',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(attr,e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e, attr);
}
}
};
</script>

View File

@@ -0,0 +1,88 @@
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text' ">{{node.text}}</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate11';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate10',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(attr,e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e, attr);
}
}
};
</script>

View File

@@ -0,0 +1,86 @@
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<rich-text :nodes="node" :class="node.classStr" :style="'user-select:' + parseSelect"></rich-text>
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<rich-text :nodes="node" :class="node.classStr" :style="'user-select:' + parseSelect"></rich-text>
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<rich-text :nodes="node" :class="node.classStr" :style="'user-select:' + parseSelect"></rich-text>
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<rich-text :nodes="node" :class="node.classStr" :style="'user-select:' + parseSelect"></rich-text>
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text' ">{{node.text}}</block>
</template>
<script>
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate11',
props: {
node: {},
},
components: {
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(attr,e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e, attr);
}
}
};
</script>

View File

@@ -0,0 +1,88 @@
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate3';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate2',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(attr,e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e, attr);
}
}
};
</script>

View File

@@ -0,0 +1,88 @@
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text' ">{{node.text}}</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate4';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate3',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(attr,e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e, attr);
}
}
};
</script>

View File

@@ -0,0 +1,88 @@
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text' ">{{node.text}}</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate5';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate4',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(attr,e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e, attr);
}
}
};
</script>

View File

@@ -0,0 +1,88 @@
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text' ">{{node.text}}</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate6';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate5',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(attr,e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e, attr);
}
}
};
</script>

View File

@@ -0,0 +1,88 @@
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text' ">{{node.text}}</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate7';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate6',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(attr,e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e, attr);
}
}
};
</script>

View File

@@ -0,0 +1,88 @@
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text' ">{{node.text}}</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate8';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate7',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(attr,e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e, attr);
}
}
};
</script>

View File

@@ -0,0 +1,88 @@
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text' ">{{node.text}}</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate9';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate8',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(attr,e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e, attr);
}
}
};
</script>

View File

@@ -0,0 +1,88 @@
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text' ">{{node.text}}</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate10';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate9',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(attr,e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e, attr);
}
}
};
</script>

View File

@@ -0,0 +1,15 @@
<template>
<!--增加video标签支持并循环添加-->
<view :class="node.classStr" :style="node.styleStr">
<video :class="node.classStr" :style="node.styleStr" class="video-video" :src="node.attr.src"></video>
</view>
</template>
<script>
export default {
name: 'wxParseVideo',
props: {
node: {},
},
};
</script>

View File

@@ -0,0 +1,262 @@
/**
* html2Json 改造来自: https://github.com/Jxck/html2json
*
*
* author: Di (微信小程序开发工程师)
* organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
* 垂直微信小程序开发交流社区
*
* github地址: https://github.com/icindy/wxParse
*
* for: 微信小程序富文本解析
* detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
*/
import wxDiscode from './wxDiscode';
import HTMLParser from './htmlparser';
function makeMap(str) {
const obj = {};
const items = str.split(',');
for (let i = 0; i < items.length; i += 1) obj[items[i]] = true;
return obj;
}
// Block Elements - HTML 5
const block = makeMap('br,code,address,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video');
// Inline Elements - HTML 5
const inline = makeMap('a,abbr,acronym,applet,b,basefont,bdo,big,button,cite,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var');
// Elements that you can, intentionally, leave open
// (and which close themselves)
const closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr');
function removeDOCTYPE(html) {
const isDocument = /<body.*>([^]*)<\/body>/.test(html);
return isDocument ? RegExp.$1 : html;
}
function trimHtml(html) {
return html
.replace(/<!--.*?-->/gi, '')
.replace(/\/\*.*?\*\//gi, '')
.replace(/[ ]+</gi, '<')
.replace(/<script[^]*<\/script>/gi, '')
.replace(/<style[^]*<\/style>/gi, '');
}
function getScreenInfo() {
const screen = {};
wx.getSystemInfo({
success: (res) => {
screen.width = res.windowWidth;
screen.height = res.windowHeight;
},
});
return screen;
}
function html2json(html, customHandler, imageProp, host) {
// 处理字符串
html = removeDOCTYPE(html);
html = trimHtml(html);
html = wxDiscode.strDiscode(html);
// 生成node节点
const bufArray = [];
const results = {
nodes: [],
imageUrls: [],
};
const screen = getScreenInfo();
function Node(tag) {
this.node = 'element';
this.tag = tag;
this.$screen = screen;
}
HTMLParser(html, {
start(tag, attrs, unary) {
// node for this element
const node = new Node(tag);
if (bufArray.length !== 0) {
const parent = bufArray[0];
if (parent.nodes === undefined) {
parent.nodes = [];
}
}
if (block[tag]) {
node.tagType = 'block';
} else if (inline[tag]) {
node.tagType = 'inline';
} else if (closeSelf[tag]) {
node.tagType = 'closeSelf';
}
node.attr = attrs.reduce((pre, attr) => {
const { name } = attr;
let { value } = attr;
if (name === 'class') {
node.classStr = value;
}
// has multi attibutes
// make it array of attribute
if (name === 'style') {
node.styleStr = value;
}
if (value.match(/ /)) {
value = value.split(' ');
}
// if attr already exists
// merge it
if (pre[name]) {
if (Array.isArray(pre[name])) {
// already array, push to last
pre[name].push(value);
} else {
// single value, make it array
pre[name] = [pre[name], value];
}
} else {
// not exist, put it
pre[name] = value;
}
return pre;
}, {});
// 优化样式相关属性
if (node.classStr) {
node.classStr += ` ${node.tag}`;
} else {
node.classStr = node.tag;
}
if (node.tagType === 'inline') {
node.classStr += ' inline';
}
// 对img添加额外数据
if (node.tag === 'img') {
let imgUrl = node.attr.src;
imgUrl = wxDiscode.urlToHttpUrl(imgUrl, imageProp.domain);
Object.assign(node.attr, imageProp, {
src: imgUrl || '',
});
if (imgUrl) {
results.imageUrls.push(imgUrl);
}
}
// 处理a标签属性
if (node.tag === 'a') {
node.attr.href = node.attr.href || '';
}
// 处理font标签样式属性
if (node.tag === 'font') {
const fontSize = [
'x-small',
'small',
'medium',
'large',
'x-large',
'xx-large',
'-webkit-xxx-large',
];
const styleAttrs = {
color: 'color',
face: 'font-family',
size: 'font-size',
};
if (!node.styleStr) node.styleStr = '';
Object.keys(styleAttrs).forEach((key) => {
if (node.attr[key]) {
const value = key === 'size' ? fontSize[node.attr[key] - 1] : node.attr[key];
node.styleStr += `${styleAttrs[key]}: ${value};`;
}
});
}
// 临时记录source资源
if (node.tag === 'source') {
results.source = node.attr.src;
}
if (customHandler.start) {
customHandler.start(node, results);
}
if (unary) {
// if this tag doesn't have end tag
// like <img src="hoge.png"/>
// add to parents
const parent = bufArray[0] || results;
if (parent.nodes === undefined) {
parent.nodes = [];
}
parent.nodes.push(node);
} else {
bufArray.unshift(node);
}
},
end(tag) {
// merge into parent tag
const node = bufArray.shift();
if (node.tag !== tag) {
console.error('invalid state: mismatch end tag');
}
// 当有缓存source资源时于于video补上src资源
if (node.tag === 'video' && results.source) {
node.attr.src = results.source;
delete results.source;
}
if (customHandler.end) {
customHandler.end(node, results);
}
if (bufArray.length === 0) {
results.nodes.push(node);
} else {
const parent = bufArray[0];
if (!parent.nodes) {
parent.nodes = [];
}
parent.nodes.push(node);
}
},
chars(text) {
// if (!text.trim()){
// return;
// }
const node = {
node: 'text',
text,
};
if (customHandler.chars) {
customHandler.chars(node, results);
}
if (bufArray.length === 0) {
results.nodes.push(node);
} else {
const parent = bufArray[0];
if (parent.nodes === undefined) {
parent.nodes = [];
}
parent.nodes.push(node);
}
},
});
return results;
}
export default html2json;

View File

@@ -0,0 +1,156 @@
/**
*
* htmlParser改造自: https://github.com/blowsie/Pure-JavaScript-HTML5-Parser
*
* author: Di (微信小程序开发工程师)
* organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
* 垂直微信小程序开发交流社区
*
* github地址: https://github.com/icindy/wxParse
*
* for: 微信小程序富文本解析
* detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
*/
// Regular Expressions for parsing tags and attributes
const startTag = /^<([-A-Za-z0-9_]+)((?:\s+[a-zA-Z0-9_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/;
const endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/;
const attr = /([a-zA-Z0-9_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g;
function makeMap(str) {
const obj = {};
const items = str.split(',');
for (let i = 0; i < items.length; i += 1) obj[items[i]] = true;
return obj;
}
// Empty Elements - HTML 5
const empty = makeMap('area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr');
// Block Elements - HTML 5
const block = makeMap('address,code,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video');
// Inline Elements - HTML 5
const inline = makeMap('a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var');
// Elements that you can, intentionally, leave open
// (and which close themselves)
const closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr');
// Attributes that have their values filled in disabled="disabled"
const fillAttrs = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected');
function HTMLParser(html, handler) {
let index;
let chars;
let match;
let last = html;
const stack = [];
stack.last = () => stack[stack.length - 1];
function parseEndTag(tag, tagName) {
// If no tag name is provided, clean shop
let pos;
if (!tagName) {
pos = 0;
} else {
// Find the closest opened tag of the same type
tagName = tagName.toLowerCase();
for (pos = stack.length - 1; pos >= 0; pos -= 1) {
if (stack[pos] === tagName) break;
}
}
if (pos >= 0) {
// Close all the open elements, up the stack
for (let i = stack.length - 1; i >= pos; i -= 1) {
if (handler.end) handler.end(stack[i]);
}
// Remove the open elements from the stack
stack.length = pos;
}
}
function parseStartTag(tag, tagName, rest, unary) {
tagName = tagName.toLowerCase();
if (block[tagName]) {
while (stack.last() && inline[stack.last()]) {
parseEndTag('', stack.last());
}
}
if (closeSelf[tagName] && stack.last() === tagName) {
parseEndTag('', tagName);
}
unary = empty[tagName] || !!unary;
if (!unary) stack.push(tagName);
if (handler.start) {
const attrs = [];
rest.replace(attr, function genAttr(matches, name) {
const value = arguments[2] || arguments[3] || arguments[4] || (fillAttrs[name] ? name : '');
attrs.push({
name,
value,
escaped: value.replace(/(^|[^\\])"/g, '$1\\"'), // "
});
});
if (handler.start) {
handler.start(tagName, attrs, unary);
}
}
}
while (html) {
chars = true;
if (html.indexOf('</') === 0) {
match = html.match(endTag);
if (match) {
html = html.substring(match[0].length);
match[0].replace(endTag, parseEndTag);
chars = false;
}
// start tag
} else if (html.indexOf('<') === 0) {
match = html.match(startTag);
if (match) {
html = html.substring(match[0].length);
match[0].replace(startTag, parseStartTag);
chars = false;
}
}
if (chars) {
index = html.indexOf('<');
let text = '';
while (index === 0) {
text += '<';
html = html.substring(1);
index = html.indexOf('<');
}
text += index < 0 ? html : html.substring(0, index);
html = index < 0 ? '' : html.substring(index);
if (handler.chars) handler.chars(text);
}
if (html === last) throw new Error(`Parse Error: ${html}`);
last = html;
}
// Clean up any remaining tags
parseEndTag();
}
export default HTMLParser;

View File

@@ -0,0 +1,195 @@
// HTML 支持的数学符号
function strNumDiscode(str) {
str = str.replace(/&forall;/g, '∀');
str = str.replace(/&part;/g, '∂');
str = str.replace(/&exist;/g, '∃');
str = str.replace(/&empty;/g, '∅');
str = str.replace(/&nabla;/g, '∇');
str = str.replace(/&isin;/g, '∈');
str = str.replace(/&notin;/g, '∉');
str = str.replace(/&ni;/g, '∋');
str = str.replace(/&prod;/g, '∏');
str = str.replace(/&sum;/g, '∑');
str = str.replace(/&minus;/g, '');
str = str.replace(/&lowast;/g, '');
str = str.replace(/&radic;/g, '√');
str = str.replace(/&prop;/g, '∝');
str = str.replace(/&infin;/g, '∞');
str = str.replace(/&ang;/g, '∠');
str = str.replace(/&and;/g, '∧');
str = str.replace(/&or;/g, '');
str = str.replace(/&cap;/g, '∩');
str = str.replace(/&cup;/g, '');
str = str.replace(/&int;/g, '∫');
str = str.replace(/&there4;/g, '∴');
str = str.replace(/&sim;/g, '');
str = str.replace(/&cong;/g, '≅');
str = str.replace(/&asymp;/g, '≈');
str = str.replace(/&ne;/g, '≠');
str = str.replace(/&le;/g, '≤');
str = str.replace(/&ge;/g, '≥');
str = str.replace(/&sub;/g, '⊂');
str = str.replace(/&sup;/g, '⊃');
str = str.replace(/&nsub;/g, '⊄');
str = str.replace(/&sube;/g, '⊆');
str = str.replace(/&supe;/g, '⊇');
str = str.replace(/&oplus;/g, '⊕');
str = str.replace(/&otimes;/g, '⊗');
str = str.replace(/&perp;/g, '⊥');
str = str.replace(/&sdot;/g, '⋅');
return str;
}
// HTML 支持的希腊字母
function strGreeceDiscode(str) {
str = str.replace(/&Alpha;/g, 'Α');
str = str.replace(/&Beta;/g, 'Β');
str = str.replace(/&Gamma;/g, 'Γ');
str = str.replace(/&Delta;/g, 'Δ');
str = str.replace(/&Epsilon;/g, 'Ε');
str = str.replace(/&Zeta;/g, 'Ζ');
str = str.replace(/&Eta;/g, 'Η');
str = str.replace(/&Theta;/g, 'Θ');
str = str.replace(/&Iota;/g, 'Ι');
str = str.replace(/&Kappa;/g, 'Κ');
str = str.replace(/&Lambda;/g, 'Λ');
str = str.replace(/&Mu;/g, 'Μ');
str = str.replace(/&Nu;/g, 'Ν');
str = str.replace(/&Xi;/g, 'Ν');
str = str.replace(/&Omicron;/g, 'Ο');
str = str.replace(/&Pi;/g, 'Π');
str = str.replace(/&Rho;/g, 'Ρ');
str = str.replace(/&Sigma;/g, 'Σ');
str = str.replace(/&Tau;/g, 'Τ');
str = str.replace(/&Upsilon;/g, 'Υ');
str = str.replace(/&Phi;/g, 'Φ');
str = str.replace(/&Chi;/g, 'Χ');
str = str.replace(/&Psi;/g, 'Ψ');
str = str.replace(/&Omega;/g, 'Ω');
str = str.replace(/&alpha;/g, 'α');
str = str.replace(/&beta;/g, 'β');
str = str.replace(/&gamma;/g, 'γ');
str = str.replace(/&delta;/g, 'δ');
str = str.replace(/&epsilon;/g, 'ε');
str = str.replace(/&zeta;/g, 'ζ');
str = str.replace(/&eta;/g, 'η');
str = str.replace(/&theta;/g, 'θ');
str = str.replace(/&iota;/g, 'ι');
str = str.replace(/&kappa;/g, 'κ');
str = str.replace(/&lambda;/g, 'λ');
str = str.replace(/&mu;/g, 'μ');
str = str.replace(/&nu;/g, 'ν');
str = str.replace(/&xi;/g, 'ξ');
str = str.replace(/&omicron;/g, 'ο');
str = str.replace(/&pi;/g, 'π');
str = str.replace(/&rho;/g, 'ρ');
str = str.replace(/&sigmaf;/g, 'ς');
str = str.replace(/&sigma;/g, 'σ');
str = str.replace(/&tau;/g, 'τ');
str = str.replace(/&upsilon;/g, 'υ');
str = str.replace(/&phi;/g, 'φ');
str = str.replace(/&chi;/g, 'χ');
str = str.replace(/&psi;/g, 'ψ');
str = str.replace(/&omega;/g, 'ω');
str = str.replace(/&thetasym;/g, 'ϑ');
str = str.replace(/&upsih;/g, 'ϒ');
str = str.replace(/&piv;/g, 'ϖ');
str = str.replace(/&middot;/g, '·');
return str;
}
function strcharacterDiscode(str) {
// 加入常用解析
str = str.replace(/&nbsp;/g, "<span class='spaceshow'> </span>");
str = str.replace(/&ensp;/g, '');
str = str.replace(/&emsp;/g, ' ');
str = str.replace(/&quot;/g, "'");
str = str.replace(/&amp;/g, '&');
str = str.replace(/&lt;/g, '<');
str = str.replace(/&gt;/g, '>');
str = str.replace(/&#8226;/g, '•');
return str;
}
// HTML 支持的其他实体
function strOtherDiscode(str) {
str = str.replace(/&OElig;/g, 'Œ');
str = str.replace(/&oelig;/g, 'œ');
str = str.replace(/&Scaron;/g, 'Š');
str = str.replace(/&scaron;/g, 'š');
str = str.replace(/&Yuml;/g, 'Ÿ');
str = str.replace(/&fnof;/g, 'ƒ');
str = str.replace(/&circ;/g, 'ˆ');
str = str.replace(/&tilde;/g, '˜');
str = str.replace(/&ensp;/g, '');
str = str.replace(/&emsp;/g, '');
str = str.replace(/&thinsp;/g, '');
str = str.replace(/&zwnj;/g, '');
str = str.replace(/&zwj;/g, '');
str = str.replace(/&lrm;/g, '');
str = str.replace(/&rlm;/g, '');
str = str.replace(/&ndash;/g, '');
str = str.replace(/&mdash;/g, '—');
str = str.replace(/&lsquo;/g, '');
str = str.replace(/&rsquo;/g, '');
str = str.replace(/&sbquo;/g, '');
str = str.replace(/&ldquo;/g, '“');
str = str.replace(/&rdquo;/g, '”');
str = str.replace(/&bdquo;/g, '„');
str = str.replace(/&dagger;/g, '†');
str = str.replace(/&Dagger;/g, '‡');
str = str.replace(/&bull;/g, '•');
str = str.replace(/&hellip;/g, '…');
str = str.replace(/&permil;/g, '‰');
str = str.replace(/&prime;/g, '');
str = str.replace(/&Prime;/g, '″');
str = str.replace(/&lsaquo;/g, '');
str = str.replace(/&rsaquo;/g, '');
str = str.replace(/&oline;/g, '‾');
str = str.replace(/&euro;/g, '€');
str = str.replace(/&trade;/g, '™');
str = str.replace(/&larr;/g, '←');
str = str.replace(/&uarr;/g, '↑');
str = str.replace(/&rarr;/g, '→');
str = str.replace(/&darr;/g, '↓');
str = str.replace(/&harr;/g, '↔');
str = str.replace(/&crarr;/g, '↵');
str = str.replace(/&lceil;/g, '⌈');
str = str.replace(/&rceil;/g, '⌉');
str = str.replace(/&lfloor;/g, '⌊');
str = str.replace(/&rfloor;/g, '⌋');
str = str.replace(/&loz;/g, '◊');
str = str.replace(/&spades;/g, '♠');
str = str.replace(/&clubs;/g, '♣');
str = str.replace(/&hearts;/g, '♥');
str = str.replace(/&diams;/g, '♦');
str = str.replace(/&#39;/g, "'");
return str;
}
function strDiscode(str) {
str = strNumDiscode(str);
str = strGreeceDiscode(str);
str = strcharacterDiscode(str);
str = strOtherDiscode(str);
return str;
}
function urlToHttpUrl(url, domain) {
if (/^\/\//.test(url)) {
return `https:${url}`;
} else if (/^\//.test(url)) {
return `https://${domain}${url}`;
}
return url;
}
export default {
strDiscode,
urlToHttpUrl,
};

View File

@@ -0,0 +1,248 @@
/**
* author: Di (微信小程序开发工程师)
* organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
* 垂直微信小程序开发交流社区
*
* github地址: https://github.com/icindy/wxParse
*
* for: 微信小程序富文本解析
* detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
*/
/**
* 请在全局下引入该文件,@import '/static/wxParse.css';
*/
.wxParse {
user-select:none;
width: 100%;
font-family: Helvetica, "PingFangSC", 'Microsoft Yahei', '微软雅黑', Arial, sans-serif;
color: #333;
line-height: 1.5;
font-size: 1em;
text-align:justify;/* //左右两端对齐 */
}
.wxParse view ,.wxParse uni-view{
word-break: break-word;
}
.wxParse .p {
padding-bottom: 0;
clear: both;
/* letter-spacing: 0;//字间距 */
}
.wxParse .inline {
display: inline;
margin: 0;
padding: 0;
}
.wxParse .div {
margin: 0;
padding: 0;
display: block;
}
.wxParse .h1{
font-size: 2em;
line-height: 1.2em;
margin: 0.67em 0;
}
.wxParse .h2{
font-size: 1.5em;
margin: 0.83em 0;
}
.wxParse .h3{
font-size: 1.17em;
margin: 1em 0;
}
.wxParse .h4{
margin: 1.33em 0;
}
.wxParse .h5{
font-size: 0.83em;
margin: 1.67em 0;
}
.wxParse .h6{
font-size: 0.83em;
margin: 1.67em 0;
}
.wxParse .h1,
.wxParse .h2,
.wxParse .h3,
.wxParse .h4,
.wxParse .h5,
.wxParse .h6,
.wxParse .b,
.wxParse .strong{
font-weight: bolder;
}
.wxParse .i,
.wxParse .cite,
.wxParse .em,
.wxParse .var,
.wxParse .address {
font-style: italic;
}
.wxParse .spaceshow{
white-space: pre;
}
.wxParse .pre,
.wxParse .tt,
.wxParse .code,
.wxParse .kbd,
.wxParse .samp {
font-family: monospace;
}
.wxParse .pre {
overflow: auto;
background: #f5f5f5;
padding: 16upx;
white-space: pre;
margin: 1em 0upx;
font-size: 24upx;
}
.wxParse .code {
overflow: auto;
padding: 16upx;
white-space: pre;
margin: 1em 0upx;
background: #f5f5f5;
font-size: 24upx;
}
.wxParse .big {
font-size: 1.17em;
}
.wxParse .small,
.wxParse .sub,
.wxParse .sup {
font-size: 0.83em;
}
.wxParse .sub {
vertical-align: sub;
}
.wxParse .sup {
vertical-align: super;
}
.wxParse .s,
.wxParse .strike,
.wxParse .del {
text-decoration: line-through;
}
.wxParse .strong,
.wxParse .s {
display: inline;
}
.wxParse .a {
color: deepskyblue;
}
.wxParse .video {
text-align: center;
margin: 22upx 0;
}
.wxParse .video-video {
width: 100%;
}
.wxParse .uni-image{
max-width: 100%;
}
.wxParse .img {
display: block;
max-width: 100%;
margin-bottom: 0em;/* //与p标签底部padding同时修改 */
overflow: hidden;
}
.wxParse .blockquote {
margin: 10upx 0;
padding: 22upx 0 22upx 22upx;
font-family: Courier, Calibri, "宋体";
background: #f5f5f5;
border-left: 6upx solid #dbdbdb;
}
.wxParse .blockquote .p {
margin: 0;
}
.wxParse .ul, .wxParse .ol {
display: block;
margin: 1em 0;
padding-left: 2em;
}
.wxParse .ol {
list-style-type: disc;
}
.wxParse .ol {
list-style-type: decimal;
}
.wxParse .ol>weixin-parse-template,.wxParse .ul>weixin-parse-template {
display: list-item;
align-items: baseline;
text-align: match-parent;
}
.wxParse .ol>.li,.wxParse .ul>.li {
display: list-item;
align-items: baseline;
text-align: match-parent;
}
.wxParse .ul .ul, .wxParse .ol .ul {
list-style-type: circle;
}
.wxParse .ol .ol .ul, .wxParse .ol .ul .ul, .wxParse .ul .ol .ul, .wxParse .ul .ul .ul {
list-style-type: square;
}
.wxParse .u {
text-decoration: underline;
}
.wxParse .hide {
display: none;
}
.wxParse .del {
display: inline;
}
.wxParse .figure {
overflow: hidden;
}
.wxParse .table .table{
border-collapse:collapse;
box-sizing: border-box;
/* 内边框 */
border: 1px solid #dadada;
width: 100%;
}
.wxParse .tbody{
border-collapse:collapse;
box-sizing: border-box;
/* 内边框 */
border: 1px solid #dadada;
}
.wxParse .thead, .wxParse .tfoot, .wxParse .th{
border-collapse:collapse;
box-sizing: border-box;
background: #ececec;
font-weight: 40;
}
.wxParse .tr {
border-collapse:collapse;
box-sizing: border-box;
/* border: 2px solid #F0AD4E; */
overflow:auto;
}
.wxParse .th,
.wxParse .td{
border-collapse:collapse;
box-sizing: border-box;
border: 2upx solid #dadada;
overflow:auto;
}
.wxParse .audio, .wxParse .uni-audio-default{
display: block;
}

View File

@@ -0,0 +1,223 @@
<!--**
* forked fromhttps://github.com/F-loat/mpvue-wxParse
*
* github地址: https://github.com/dcloudio/uParse
*
* for: uni-app框架下 富文本解析
*
* 优化 by gaoyia@qq.com https://github.com/gaoyia/parse
*/-->
<template>
<!--基础元素-->
<div class="wxParse" :class="className" :style="'user-select:' + userSelect">
<block v-for="(node, index) of nodes" :key="index" v-if="!loading">
<wxParseTemplate :node="node" />
</block>
</div>
</template>
<script>
import HtmlToJson from './libs/html2json';
import wxParseTemplate from './components/wxParseTemplate0';
export default {
name: 'wxParse',
props: {
// user-select:none;
userSelect: {
type: String,
default: 'text' //none |text| all | element
},
imgOptions: {
type: [Object, Boolean],
default: function() {
return {
loop: false,
indicator: 'number',
longPressActions: false
// longPressActions: {
// itemList: ['发送给朋友', '保存图片', '收藏'],
// success: function (res) {
// console.log('选中了第' + (res.tapIndex + 1) + '个按钮');
// },
// fail: function (res) {
// console.log(res.errMsg);
// }
// }
// }
}
}
},
loading: {
type: Boolean,
default: false
},
className: {
type: String,
default: ''
},
content: {
type: String,
default: ''
},
noData: {
type: String,
default: '<div style="color: red;">数据不能为空</div>'
},
startHandler: {
type: Function,
default () {
return node => {
node.attr.class = null;
node.attr.style = null;
};
}
},
endHandler: {
type: Function,
default: null
},
charsHandler: {
type: Function,
default: null
},
imageProp: {
type: Object,
default () {
return {
mode: 'aspectFit',
padding: 0,
lazyLoad: false,
domain: ''
};
}
}
},
components: {
wxParseTemplate
},
data() {
return {
nodes: {},
imageUrls: [],
wxParseWidth: {
value: 0
}
};
},
computed: {},
mounted() {
let that = this
this.getWidth().then(function(data) {
that.wxParseWidth.value = data;
})
this.setHtml()
},
methods: {
setHtml() {
// this.getWidth().then((data) => {
// this.wxParseWidth.value = data;
// })
let {
content,
noData,
imageProp,
startHandler,
endHandler,
charsHandler
} = this;
let parseData = content || noData;
let customHandler = {
start: startHandler,
end: endHandler,
chars: charsHandler
};
let results = HtmlToJson(parseData, customHandler, imageProp, this);
this.imageUrls = results.imageUrls;
// this.nodes = results.nodes;
this.nodes = [];
results.nodes.forEach((item) => {
setTimeout(() => {
this.nodes.push(item)
}, 0);
})
},
getWidth() {
return new Promise((res, rej) => {
// #ifndef MP-ALIPAY || MP-BAIDU
uni.createSelectorQuery()
.in(this)
.select('.wxParse')
.fields({
size: true,
scrollOffset: true
},
data => {
res(data.width);
}
).exec();
// #endif
// #ifdef MP-BAIDU
swan.createSelectorQuery().select('.wxParse').boundingClientRect(function(rect) {
rect[0].width
}).exec()
// #endif
// #ifdef MP-ALIPAY
my.createSelectorQuery()
.select('.wxParse')
.boundingClientRect().exec((ret) => {
res(ret[0].width);
});
// #endif
});
},
navigate(href, $event, attr) {
console.log(href, attr);
this.$emit('navigate', href, $event);
},
preview(src, $event) {
if (!this.imageUrls.length || typeof this.imgOptions === 'boolean') {
} else {
uni.previewImage({
current: src,
urls: this.imageUrls,
loop: this.imgOptions.loop,
indicator: this.imgOptions.indicator,
longPressActions: this.imgOptions.longPressActions
});
}
this.$emit('preview', src, $event);
},
removeImageUrl(src) {
const {
imageUrls
} = this;
imageUrls.splice(imageUrls.indexOf(src), 1);
}
},
// 父组件中提供
provide() {
return {
parseWidth: this.wxParseWidth,
parseSelect: this.userSelect
// 提示provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的。
};
},
watch: {
content(){
this.setHtml()
}
// content: {
// handler: function(newVal, oldVal) {
// if (newVal !== oldVal) {
//
// }
// },
// deep: true
// }
}
};
</script>

View File

@@ -0,0 +1,50 @@
<template>
<view>
<radio-group class="uni-list" @change="radioChange">
<label class="uni-list-cell uni-list-cell-pd" v-for="(item, index) in type_list" :key="index">
<view class="invoice-type-icon">
<radio class="a-radio" :id="item.name" :value="item.value" :checked="item.checked" :disabled="item.disabled"></radio>
</view>
<view class="invoice-type-c">
<label class="label-2-text" :for="item.name">
<text>{{item.name}}</text>
</label>
</view>
</label>
</radio-group>
</view>
</template>
<script>
export default {
data() {
return {
type_list: [
{ value: '1', name: '仅退款', checked: true, disabled: false },
{ value: '2', name: '退货退款', checked: false, disabled:false },
],
};
},
methods:{
radioChange: function(evt) {
this.type_list.forEach(item => {
if (item.value === evt.target.value) {
item.checked = true;
this.aftersale_type = evt.target.value;
}else{
item.checked = false;
}
});
if(this.type_list[0].checked){
this.refund_input_noedit = true;
}else{
this.refund_input_noedit = false;
}
},
}
}
</script>
<style>
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,192 @@
<template>
<!-- 单图 -->
<view class="jshop-adpop" v-if="jdata.options.colorGroup && jdata.options.colorGroup.length > 0">
<view class="adpop" v-if="closeAd">
<view class="adpop-c">
<view class="adpop-img">
<!-- #ifdef MP-WEIXIN -->
<view @click="navToTabPage(jdata.options.colorGroup[0].adLink)">
<image class="ad-img" :src="jdata.options.colorGroup[0].adImg" mode="widthFix" ></image>
</view>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<image class="ad-img" :src="jdata.options.colorGroup[0].adImg" mode="widthFix" @click="navToTabPage(jdata.options.colorGroup[0].adLink)"></image>
<!-- #endif -->
</view>
<image class="close-btn" src="/static/image/close-pink.png" mode="" @click="closePop"></image>
</view>
</view>
</view>
</template>
<script>
export default {
name: "jshopadpop",
props: {
jdata: {
// type: Object,
required: true,
}
},
data(){
return{
closeAd: true
}
},
computed: {
count() {
// console.log(jdata)
return (this.jdata.options.colorGroup.length > 0)
}
},
methods: {
closePop(){
this.closeAd = false
},
navToTabPage(url) {
uni.navigateTo({
url: url
});
},
showSliderInfo(type, val) {
console.log(type);
if (!val) {
return;
}
if (type == 1) {
if (val.indexOf('http') != -1) {
// #ifdef H5
window.location.href = val
// #endif
} else {
// #ifdef H5 || APP-PLUS || APP-PLUS-NVUE || MP
if (val == '/pages/index/index' || val == '/pages/classify/classify' || val == '/pages/cart/index/index' || val == '/pages/member/index/index') {
uni.switchTab({
url: val
});
return;
} else if(val.indexOf('/pages/coupon/coupon')>-1){
var id = val.replace('/pages/coupon/coupon?id=',"");
this.receiveCoupon(id)
} else {
this.$common.navigateTo(val);
return;
}
// #endif
}
} else if (type == 2) {
// 商品详情
this.goodsDetail(val)
} else if (type == 3) {
// 文章详情
this.$common.navigateTo('/pages/article/index?id=' + val + '&id_type=1')
} else if (type == 4) {
// 文章列表
this.$common.navigateTo('/pages/article/list?cid=' + val)
} else if (type == 5) {
//智能表单
this.$common.navigateTo('/pages/form/detail/form?id=' + val)
}
},
//跳转到商品详情页面
goodsDetail: function(id) {
// let ins = encodeURIComponent('id='+id);
let url = '/pages/goods/index/index?id=' + id;
this.$common.navigateTo(url);
},
// 用户领取优惠券
receiveCoupon(couponId) {
let data = {
promotion_id: couponId
}
this.$api.getCoupon(data, res => {
if (res.status) {
this.$common.successToShow(res.msg)
} else {
this.$common.errorToShow(res.msg)
}
})
},
// #ifdef MP-WEIXIN
showSliderInfo2:function(e){
let type = e.currentTarget.dataset.type;
let val = e.currentTarget.dataset.val;
console.log(type);
console.log(val)
console.log(type);
if (!val) {
return;
}
if (type == 1) {
if (val.indexOf('http') != -1) {
// #ifdef H5
window.location.href = val
// #endif
} else {
// #ifdef H5 || APP-PLUS || APP-PLUS-NVUE || MP
if (val == '/pages/index/index' || val == '/pages/classify/classify' || val == '/pages/cart/index/index' || val == '/pages/member/index/index') {
uni.switchTab({
url: val
});
return;
} else if(val.indexOf('/pages/coupon/coupon')>-1){
var id = val.replace('/pages/coupon/coupon?id=',"");
this.receiveCoupon(id)
} else {
this.$common.navigateTo(val);
return;
}
// #endif
}
} else if (type == 2) {
// 商品详情
this.goodsDetail(val)
} else if (type == 3) {
// 文章详情
this.$common.navigateTo('/pages/article/index?id=' + val + '&id_type=1')
} else if (type == 4) {
// 文章列表
this.$common.navigateTo('/pages/article/list?cid=' + val)
} else if (type == 5) {
//智能表单
this.$common.navigateTo('/pages/form/detail/form?id=' + val)
}
}
// #endif
},
}
</script>
<style>
.adpop{
position: fixed;
background: rgba(0,0,0,.5);
width: 100%;
height: 100vh;
z-index: 999;
top: 0;
left: 0;
}
.adpop-c{
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
width: 70%;
text-align: center;
}
.adpop-img{
width: 100%;
max-height: 1000rpx;
margin-bottom: 50rpx;
}
.ad-img{
width: 100%;
max-height: 1000rpx;
}
.close-btn{
width: 80rpx;
height: 80rpx;
}
</style>

View File

@@ -0,0 +1,82 @@
<template>
<view class='index-article cell-group bottom-cell-group' v-if="jdata.options.colorGroup && count">
<view class='cell-item'
v-for="item in jdata.options.colorGroup"
:key="item.id"
@click="articleDetail(item.id)"
>
<view class="cell-item-bd">
<view class="article-title ">
{{ item.title }}
</view>
<view class="article-time">
{{ item.ctime }}
</view>
</view>
<view class="cell-title-img">
<image :src="item.cover" mode="aspectFill"></image>
</view>
</view>
</view>
</template>
<script>
export default {
name: "jshoparticle",
props: {
jdata:{
// type: Array,
required: true,
}
},
computed: {
count() {
return (this.jdata.options.colorGroup.length > 0)
}
},
methods: {
// 查看文章详情
articleDetail (articleId) {
this.$common.navigateTo('/pages/article/index?id=' + articleId+'&id_type=1')
}
}
}
</script>
<style>
.index-article .cell-title-img{
width: 160upx;
height: 160upx;
float: right;
}
.index-article .cell-title-img image{
width: 100%;
height: 100%;
}
.index-article .cell-item-bd{
padding-right: 0;
vertical-align: top;
position: relative;
}
.index-article .article-title{
font-size: 28upx;
color: #333;
width: 100%;
min-height: 80upx;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
.index-article .article-time{
font-size: 24upx;
color: #999;
display: inline-block;
min-width: 220upx;
min-height: 32upx;
position: absolute;
bottom: 0;
}
</style>

View File

@@ -0,0 +1,82 @@
<template>
<view class='index-article cell-group bottom-cell-group' v-if="jdata.options.colorGroup && count">
<view class='cell-item'
v-for="item in jdata.options.colorGroup"
:key="item.id"
@click="articleDetail(item.id)"
>
<view class="cell-item-bd">
<view class="article-title ">
{{ item.title }}
</view>
<view class="article-time">
{{ item.ctime }}
</view>
</view>
<view class="cell-title-img">
<image :src="item.cover" mode="aspectFill"></image>
</view>
</view>
</view>
</template>
<script>
export default {
name: "jshoparticleclassify",
props: {
jdata:{
// type: Array,
required: true,
}
},
computed: {
count() {
return (this.jdata.options.colorGroup.length > 0)
}
},
methods: {
// 查看文章详情
articleDetail (articleId) {
this.$common.navigateTo('/pages/article/index?id=' + articleId+'&id_type=1')
}
}
}
</script>
<style>
.index-article .cell-title-img{
width: 160upx;
height: 160upx;
float: right;
}
.index-article .cell-title-img image{
width: 100%;
height: 100%;
}
.index-article .cell-item-bd{
padding-right: 0;
vertical-align: top;
position: relative;
}
.index-article .article-title{
font-size: 28upx;
color: #333;
width: 100%;
min-height: 80upx;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
.index-article .article-time{
font-size: 24upx;
color: #999;
display: inline-block;
min-width: 220upx;
min-height: 32upx;
position: absolute;
bottom: 0;
}
</style>

View File

@@ -0,0 +1,21 @@
<template>
<view class="blank" :style="{background:jdata.options.search_bg,height:jdata.options.udPadding*2+'rpx'}"></view>
</template>
<script>
export default {
name: "jshopblank",
props: {
jdata:{
// type: Array,
required: true,
}
},
methods: {
}
}
</script>
<style>
</style>

View File

@@ -0,0 +1,27 @@
<template>
<view class="content">
<u-parse :content="content" @preview="preview" @navigate="navigate" style="background-color: #fff;"/>
</view>
</template>
<script>
//视频和文本解析组件
import uParse from '@/components/gaoyia-parse/parse.vue'
export default {
name: 'jshop-content',
components: {
uParse
},
props: {
content: {}
},
created() {},
methods: {
preview(src, e) {
// do something
},
navigate(href, e) {
// do something
}
}
}
</script>

View File

@@ -0,0 +1,101 @@
<template>
<view class="coupon bottom-cell-group" v-if="count">
<view class="coupon-item" v-for="item in jdata.options.colorGroup" :key="item.id" @click="receiveCoupon(item.id)">
<view class="coupon-i-l">
<view class="coupon-i-l-t">
<image class="icon" src="/static/image/element-ic.png" mode=""></image>
<text>{{ item.name }}</text>
</view>
<view class="coupon-i-l-b">
{{ item.expression1 + item.expression2 }}
</view>
</view>
<view class="coupon-i-r">
<image class="coupon-logo" src="/static/image/coupon-element.png" mode=""></image>
</view>
</view>
</view>
</template>
<script>
export default {
name: "jshopcoupon",
props: {
jdata:{
// type: Array,
required: true,
}
},
computed: {
count() {
return (this.jdata.options.colorGroup.length > 0)
}
},
methods: {
// 用户领取优惠券
receiveCoupon(couponId) {
let jdata = {
promotion_id: couponId
}
this.$api.getCoupon(jdata, res => {
if (res.status) {
this.$common.successToShow(res.msg)
} else {
this.$common.errorToShow(res.msg)
}
})
},
}
}
</script>
<style>
.coupon {
padding: 0 26upx;
background-color: #f8f8f8;
}
.coupon-item {
padding: 20upx;
margin-bottom: 20upx;
background-color: #fff;
}
.coupon-i-l {
width: 400upx;
display: inline-block;
}
.coupon-i-l-t {
font-size: 32upx;
position: relative;
margin-bottom: 10upx;
}
.coupon-i-l-t .icon {
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.coupon-i-l-t text {
margin-left: 60upx;
}
.coupon-i-l-b {
font-size: 24upx;
color: #999;
}
.coupon-i-r {
width: 258upx;
display: inline-block;
text-align: center;
}
.coupon-logo {
width: 130upx;
height: 100upx;
}
</style>

View File

@@ -0,0 +1,604 @@
<template>
<view class="container">
<!-- 新品上市 -->
<view class="f-header m-t" @click="navToTabPage('../../pagesA/product/list')">
<image src="/static/temp/h1.png" ></image>
<view class="tit-box">
<text class="tit">新品上市</text>
<text class="tit2">Guess You Like It</text>
</view>
<text class="yticon icon-you"></text>
</view>
<view class="guess-section">
<view v-for="(item, index) in jdata.options.colorGroup" :key="index" class="guess-item" @click="goodsDetail(item.id)">
<view class="image-wrapper"><image :src="item.pic" mode="aspectFill"></image></view>
<text class="title clamp">{{ item.title }}</text>
<text class="price">{{ item.price }}</text>
</view>
</view>
</view>
</view>
</template>
<script>
import {goods} from '@/config/mixins.js'
export default {
filters:{
substr(val) {
if (val.length == 0 || val == undefined) {
return false;
} else if (val.length > 13) {
return val.substring(0, 13) + "...";
} else {
return val;
}
}
},
mixins: [goods],
name: "jshopgoods",
props: {
jdata:{
// type: Array,
required: true,
}
},
computed: {
count() {
return (this.jdata.options.colorGroup.length > 0)
}
},
methods: {
navToTabPage(url) {
uni.navigateTo({
url: url
});
},
//跳转到商品详情页面
goodsDetail: function(id) {
let url = '../../pagesA/product/product?id=' + id;
this.$common.navigateTo(url);
},
},
}
</script>
<style lang="scss">
.MP-search{
background: #FFFFFF;height: 80upx;display: flex;justify-content: center;align-items: center;position: fixed;width: 100%;z-index: 999;
}
.MP-search-input{
font-size: 28upx;background: #F5F5F5;height: 60upx;width: 90%;border-radius: 50upx;text-align: center;
}
.mp-search-box {
position: absolute;
left: 0;
top: 30upx;
z-index: 9999;
width: 100%;
padding: 0 80upx;
.ser-input {
flex: 1;
height: 60upx;
line-height: 60upx;
text-align: center;
font-size: 28upx;
color: $font-color-base;
border-radius: 20px;
background: rgba(255, 255, 255, 0.6);
}
}
page {
.cate-section {
position: relative;
z-index: 5;
border-radius: 16upx 16upx 0 0;
margin-top: -20upx;
}
.carousel-section {
padding: 0;
.titleNview-placing {
padding-top: 0;
height: 0;
}
.carousel {
.carousel-item {
padding: 0;
}
}
.swiper-dots {
left: 45upx;
bottom: 40upx;
}
}
}
page {
background: #f5f5f5;
}
.m-t {
margin-top: 20upx;
}
/* 头部 轮播图 */
.carousel-section {
position: relative;
padding-top: 10px;
.titleNview-placing {
height: var(--status-bar-height);
padding-top: 44px;
box-sizing: content-box;
}
.titleNview-background {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 426upx;
transition: 0.4s;
}
}
.carousel {
width: 100%;
height: 350upx;
.carousel-item {
width: 100%;
height: 100%;
padding: 0 28upx;
overflow: hidden;
}
image {
width: 100%;
height: 100%;
border-radius: 10upx;
}
}
.swiper-dots {
display: flex;
position: absolute;
left: 60upx;
bottom: 15upx;
width: 72upx;
height: 36upx;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAABkCAYAAADDhn8LAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTMyIDc5LjE1OTI4NCwgMjAxNi8wNC8xOS0xMzoxMzo0MCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OTk4MzlBNjE0NjU1MTFFOUExNjRFQ0I3RTQ0NEExQjMiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OTk4MzlBNjA0NjU1MTFFOUExNjRFQ0I3RTQ0NEExQjMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTcgKFdpbmRvd3MpIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6Q0E3RUNERkE0NjExMTFFOTg5NzI4MTM2Rjg0OUQwOEUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6Q0E3RUNERkI0NjExMTFFOTg5NzI4MTM2Rjg0OUQwOEUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4Gh5BPAAACTUlEQVR42uzcQW7jQAwFUdN306l1uWwNww5kqdsmm6/2MwtVCp8CosQtP9vg/2+/gY+DRAMBgqnjIp2PaCxCLLldpPARRIiFj1yBbMV+cHZh9PURRLQNhY8kgWyL/WDtwujjI8hoE8rKLqb5CDJaRMJHokC6yKgSCR9JAukmokIknCQJpLOIrJFwMsBJELFcKHwM9BFkLBMKFxNcBCHlQ+FhoocgpVwwnv0Xn30QBJGMC0QcaBVJiAMiec/dcwKuL4j1QMsVCXFAJE4s4NQA3K/8Y6DzO4g40P7UcmIBJxbEesCKWBDg8wWxHrAiFgT4fEGsB/CwIhYE+AeBAAdPLOcV8HRmWRDAiQVcO7GcV8CLM8uCAE4sQCDAlHcQ7x+ABQEEAggEEAggEEAggEAAgQACASAQQCCAQACBAAIBBAIIBBAIIBBAIABe4e9iAe/xd7EAJxYgEGDeO4j3EODp/cOCAE4sYMyJ5cwCHs4rCwI4sYBxJ5YzC84rCwKcXxArAuthQYDzC2JF0H49LAhwYUGsCFqvx5EF2T07dMaJBetx4cRyaqFtHJ8EIhK0i8OJBQxcECuCVutxJhCRoE0cZwMRyRcFefa/ffZBVPogePihhyCnbBhcfMFFEFM+DD4m+ghSlgmDkwlOgpAl4+BkkJMgZdk4+EgaSCcpVX7bmY9kgXQQU+1TgE0c+QJZUUz1b2T4SBbIKmJW+3iMj2SBVBWz+leVfCQLpIqYbp8b85EskIxyfIOfK5Sf+wiCRJEsllQ+oqEkQfBxmD8BBgA5hVjXyrBNUQAAAABJRU5ErkJggg==);
background-size: 100% 100%;
.num {
width: 36upx;
height: 36upx;
border-radius: 50px;
font-size: 24upx;
color: #fff;
text-align: center;
line-height: 36upx;
}
.sign {
position: absolute;
top: 0;
left: 50%;
line-height: 36upx;
font-size: 12upx;
color: #fff;
transform: translateX(-50%);
}
}
/* 分类 */
.cate-section {
display: flex;
justify-content: space-around;
align-items: center;
flex-wrap: wrap;
padding: 30upx 22upx;
background: #fff;
.cate-item {
display: flex;
flex-direction: column;
align-items: center;
font-size: $font-sm + 2upx;
color: $font-color-dark;
}
/* 原图标颜色太深,不想改图了,所以加了透明度 */
image {
width: 88upx;
height: 88upx;
margin-bottom: 14upx;
border-radius: 50%;
opacity: 0.7;
box-shadow: 4upx 4upx 20upx rgba(250, 67, 106, 0.3);
}
}
.ad-1 {
width: 100%;
height: 210upx;
padding: 10upx 0;
background: #fff;
image {
width: 100%;
height: 100%;
}
}
/* 秒杀专区 */
.seckill-section {
padding: 0upx 20upx 20upx;
background: #fff;
.s-header {
display: flex;
align-items: center;
height: 90upx;
line-height: 1;
.s-img {
width: 140upx;
height: 30upx;
}
.tip {
font-size: $font-base;
color: $font-color-light;
// margin: 0 20upx 0 40upx;
}
.timer {
display: inline-block;
width: 40upx;
height: 36upx;
text-align: center;
line-height: 36upx;
margin-right: 14upx;
font-size: $font-sm + 2upx;
color: #fff;
border-radius: 2px;
background: rgba(0, 0, 0, 0.8);
}
.icon-you {
font-size: $font-lg;
color: $font-color-light;
flex: 1;
text-align: right;
}
}
.floor-list {
white-space: nowrap;
}
.scoll-wrapper {
display: flex;
align-items: flex-start;
}
.floor-item {
width: 150upx;
margin-right: 20upx;
font-size: $font-sm + 2upx;
color: $font-color-dark;
line-height: 1.8;
image {
width: 150upx;
height: 150upx;
border-radius: 6upx;
}
.price {
color: $uni-color-primary;
}
}
}
.f-header {
display: flex;
align-items: center;
height: 140upx;
padding: 0upx 20upx;
background: #fff;
image {
flex-shrink: 0;
width: 80upx;
height: 80upx;
margin-right: 20upx;
}
.tit-box {
flex: 1;
display: flex;
flex-direction: column;
}
.tit {
font-size: $font-lg + 2upx;
color: #font-color-dark;
line-height: 1.3;
}
.tit2 {
font-size: $font-sm;
color: $font-color-light;
}
.icon-you {
font-size: $font-lg + 2upx;
color: $font-color-light;
}
}
/* 团购楼层 */
.group-section {
background: #fff;
.g-swiper {
height: 650upx;
padding-bottom: 20upx;
}
.g-swiper-item {
width: 100%;
padding: 0 20upx;
display: flex;
}
image {
width: 100%;
height: 460upx;
border-radius: 4px;
}
.g-item {
display: flex;
flex-direction: column;
overflow: hidden;
}
.left {
flex: 1.2;
// margin-right: 24upx;
.t-box {
padding-top: 20upx;
}
}
.right {
flex: 0.8;
flex-direction: column-reverse;
.t-box {
padding-bottom: 20upx;
}
}
.t-box {
height: 160upx;
font-size: $font-base + 2upx;
color: $font-color-dark;
line-height: 1.6;
}
.price {
color: $uni-color-primary;
}
.m-price {
font-size: $font-sm + 2upx;
text-decoration: line-through;
color: $font-color-light;
margin-left: 8upx;
}
.pro-box {
display: flex;
align-items: center;
margin-top: 10upx;
font-size: $font-sm;
color: $font-base;
padding-right: 10upx;
}
.progress-box {
flex: 1;
border-radius: 10px;
overflow: hidden;
margin-right: 8upx;
}
}
/* 分类推荐楼层 */
.hot-floor {
width: 100%;
overflow: hidden;
margin-bottom: 20upx;
.floor-img-box {
width: 100%;
height: 320upx;
position: relative;
&:after {
content: '';
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: linear-gradient(rgba(255, 255, 255, 0.06) 30%, #f8f8f8);
}
}
.floor-img {
width: 100%;
height: 100%;
}
.floor-list {
white-space: nowrap;
padding: 20upx;
padding-right: 50upx;
border-radius: 6upx;
margin-top: -140upx;
margin-left: 30upx;
background: #fff;
box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.2);
position: relative;
z-index: 1;
}
.scoll-wrapper {
display: flex;
align-items: flex-start;
}
.floor-item {
width: 180upx;
margin-right: 20upx;
font-size: $font-sm + 2upx;
color: $font-color-dark;
line-height: 1.8;
image {
width: 180upx;
height: 180upx;
border-radius: 6upx;
}
.price {
color: $uni-color-primary;
}
}
.more {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
flex-shrink: 0;
width: 180upx;
height: 180upx;
border-radius: 6upx;
background: #f3f3f3;
font-size: $font-base;
color: $font-color-light;
text:first-child {
margin-bottom: 4upx;
}
}
}
/* 单条商品 */
.goods-box-single {
display: flex;
padding: 20upx 0;
.goods-img {
display: block;
width: 120upx;
height: 120upx;
}
.right {
flex: 1;
display: flex;
flex-direction: column;
padding: 0 30upx 0 24upx;
overflow: hidden;
.title {
font-size: $font-base + 2upx;
color: $font-color-dark;
line-height: 1;
}
.attr-box {
font-size: $font-sm + 2upx;
color: $font-color-light;
padding: 10upx 12upx;
}
.price {
font-size: $font-base + 2upx;
color: $font-color-dark;
&:before {
content: '¥';
font-size: $font-sm;
margin: 0 2upx 0 8upx;
}
}
}
}
.price-box {
display: flex;
justify-content: flex-end;
align-items: baseline;
padding: 20upx 30upx;
font-size: $font-sm + 2upx;
color: $font-color-light;
.num {
margin: 0 8upx;
color: $font-color-dark;
}
.price {
font-size: $font-lg;
color: $font-color-dark;
&:before {
content: '¥';
font-size: $font-sm;
margin: 0 2upx 0 8upx;
}
}
}
.action-box {
display: flex;
justify-content: flex-end;
align-items: center;
height: 100upx;
position: relative;
padding-right: 30upx;
}
.action-btn {
width: 160upx;
height: 60upx;
margin: 0;
margin-left: 24upx;
padding: 0;
text-align: center;
line-height: 60upx;
font-size: $font-sm + 2upx;
color: $font-color-dark;
background: #fff;
border-radius: 100px;
&:after {
border-radius: 100px;
}
&.recom {
background: #fff9f9;
color: $base-color;
&:after {
border-color: #f7bcc8;
}
}
}
/* 猜你喜欢 */
.guess-section {
display: flex;
flex-wrap: wrap;
padding: 0 30upx;
background: #fff;
.guess-item {
display: flex;
flex-direction: column;
width: 48%;
padding-bottom: 40upx;
&:nth-child(2n + 1) {
margin-right: 4%;
}
}
.image-wrapper {
width: 100%;
height: 330upx;
border-radius: 3px;
overflow: hidden;
image {
width: 100%;
height: 100%;
opacity: 1;
}
}
.title {
font-size: $font-lg;
color: $font-color-dark;
line-height: 80upx;
}
.price {
font-size: $font-lg;
color: $uni-color-primary;
line-height: 1;
}
.coupon_box {
width:100%; height:auto; display:table; padding:6upx 26upx 26upx 26upx;
}
.other_type {
width:100%; height:90upx; padding-top:50upx;
.text { width:100%; border-top:1px solid #eeeeee; display:block; text-align:center; position:relative; }
.text span { width:180upx; height:40upx; line-height:40upx; color:#999999; display:block; background:#ffffff; position:absolute; left:50%; top:50%; margin-left:-90upx; margin-top:-20upx; font-size:$font-base; }
}
}
.getPosition{
height: 100upx;
display: flex;
justify-content: center;
align-items: center;
font-size: 32upx;
background-color: #FFF;
}
</style>

View File

@@ -0,0 +1,132 @@
<template>
<!-- 团购秒杀 -->
<view class="img-list bottom-cell-group group-buying" v-if="jdata.options.colorGroup && count">
<view class='cell-item right-img'>
<view class='cell-item-hd group-title'>
{{jdata.params.title}}
<!-- <view class='cell-hd-title'></view> -->
</view>
</view>
<view class='swiper-grids'>
<scroll-view class='swiper-list' scroll-x="true">
<view class="img-list-item" v-if="item.goods !== 'undefined' && item.goods" v-for="(item, key) in jdata.options.colorGroup"
:key="key">
<image class="img-list-item-l medium-img have-none" :src="item.goods.image_url" mode='aspectFill' @click="groupDetail(item.goods.id, item.goods.group_id)"></image>
<view class="img-list-item-r medium-right">
<view class="goods-name list-goods-name" @click="groupDetail(item.goods.id, item.goods.group_id)">{{item.goods.name}}</view>
<view class="goods-item-c">
<view class="goods-price red-price">{{item.goods.product.price}}</view>
<view class="goods-buy">
<view class="goods-salesvolume red-price" v-if="(item.goods.lasttime != '已经结束' || item.goods.lasttime != '即将开始') && item.goods.lasttime">剩余<uni-countdown
:show-day="false" :hour="item.goods.lasttime.hour" :minute="item.goods.lasttime.minute" :second="item.goods.lasttime.second"></uni-countdown>
</view>
<view class="goods-salesvolume red-price" v-if="item.goods.lasttime == '已经结束'">已结束</view>
<view class="goods-salesvolume red-price" v-if="item.goods.lasttime == '即将开始'">即将开始</view>
<image class="goods-cart" src="/static/image/ic-car.png" @click="groupDetail(item.goods.id, item.goods.group_id)"></image>
</view>
</view>
</view>
</view>
</scroll-view>
</view>
</view>
</template>
<script>
import uniCountdown from "@/components/uni-countdown/uni-countdown.vue"
import {
goods
} from '@/config/mixins.js'
export default {
mixins: [goods],
components: {
uniCountdown
},
name: "jshopgrouppurchase",
props: {
jdata: {
// type: Array,
required: false,
}
},
computed: {
count() {
return (this.jdata.options.colorGroup.length > 0)
}
},
methods: {
showSliderInfo(type, val) {
if (type == 1) {
if (val.indexOf('http') != -1) {
// #ifdef H5
window.location.href = val
// #endif
} else {
// #ifdef H5 || APP-PLUS || APP-PLUS-NVUE || MP
if (val == '/pages/classify/classify' || val == '/pages/cart/index/index' || val == '/pages/member/index/index') {
uni.switchTab({
url: val
});
return;
} else {
this.$common.navigateTo(val);
return;
}
// #endif
}
} else if (type == 2) {
// 商品详情
this.goodsDetail(val)
} else if (type == 3) {
// 文章详情
this.$common.navigateTo('/pages/article/index?id=' + val +'&id_type=1')
} else if (type == 4) {
// 文章列表
this.$common.navigateTo('/pages/article/list?cid=' + val)
} else if (type == 5) {
//智能表单
this.$common.navigateTo('/pages/form/detail/form?id=' + val)
}
},
//跳转到商品详情页面
// goodsDetail: function(id) {
// let url = '/pages/goods/index/index?id=' + id;
// this.$common.navigateTo(url);
// },
},
}
</script>
<style>
.img-list,
.img-grids {
background-color: #fff;
}
.cell-item {
border: none;
}
.group-buying .img-list-item {
min-height: 236upx;
padding: 20upx;
margin-left: 26upx;
margin-bottom: 26upx;
display: inline-table;
background-color: #f9f9f9;
}
.swiper-grids .img-list-item:last-child {
margin-right: 26upx;
}
/* .group-buying .goods-name{
min-height: 74upx;
} */
.group-buying .group-title {
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>

View File

@@ -0,0 +1,189 @@
<template>
<!-- 单图 -->
<view class="ad jshop-imgsingle" v-if="jdata.options.colorGroup && jdata.options.colorGroup.length > 0">
<view class="" v-for="item in jdata.options.colorGroup" :key="item.id">
<!-- #ifdef MP-WEIXIN -->
<view @click="showSliderInfo2" :data-type="item.linkType" :data-val="item.linkValue">
<image class="ad-img" :src="item.adImg" mode="widthFix" ></image>
</view>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<image class="ad-img" :src="item.adImg" mode="widthFix" @click="showSliderInfo(item.linkType, item.linkValue)"></image>
<!-- #endif -->
<view class="imgup-btn" v-if="item.buttonText != ''" @click="showSliderInfo(item.linkType, item.linkValue)">
<button class="btn btn-fillet" :style="{background:item.buttonColor,color:item.textColor}">{{item.buttonText}}</button>
</view>
</view>
</view>
</template>
<script>
export default {
name: "jshopimgsingle",
props: {
jdata: {
// type: Object,
required: true,
}
},
computed: {
count() {
// console.log(jdata)
return (this.jdata.options.colorGroup.length > 0)
}
},
methods: {
showSliderInfo(type, val) {
console.log(type);
if (!val) {
return;
}
if (type == 1) {
if (val.indexOf('http') != -1) {
// #ifdef H5
window.location.href = val
// #endif
} else {
// #ifdef H5 || APP-PLUS || APP-PLUS-NVUE || MP
if (val == '/pages/index/index' || val == '/pages/classify/classify' || val == '/pages/cart/index/index' || val == '/pages/member/index/index') {
uni.switchTab({
url: val
});
return;
} else if(val.indexOf('/pages/coupon/coupon')>-1){
var id = val.replace('/pages/coupon/coupon?id=',"");
this.receiveCoupon(id)
} else {
this.$common.navigateTo(val);
return;
}
// #endif
}
} else if (type == 2) {
// 商品详情
this.goodsDetail(val)
} else if (type == 3) {
// 文章详情
this.$common.navigateTo('/pages/article/index?id=' + val + '&id_type=1')
} else if (type == 4) {
// 文章列表
this.$common.navigateTo('/pages/article/list?cid=' + val)
} else if (type == 5) {
//智能表单
this.$common.navigateTo('/pages/form/detail/form?id=' + val)
}
},
//跳转到商品详情页面
goodsDetail: function(id) {
// let ins = encodeURIComponent('id='+id);
let url = '/pages/goods/index/index?id=' + id;
this.$common.navigateTo(url);
},
// 用户领取优惠券
receiveCoupon(couponId) {
let data = {
promotion_id: couponId
}
this.$api.getCoupon(data, res => {
if (res.status) {
this.$common.successToShow(res.msg)
} else {
this.$common.errorToShow(res.msg)
}
})
},
// #ifdef MP-WEIXIN
showSliderInfo2:function(e){
let type = e.currentTarget.dataset.type;
let val = e.currentTarget.dataset.val;
console.log(type);
console.log(val)
console.log(type);
if (!val) {
return;
}
if (type == 1) {
if (val.indexOf('http') != -1) {
// #ifdef H5
window.location.href = val
// #endif
} else {
// #ifdef H5 || APP-PLUS || APP-PLUS-NVUE || MP
if (val == '/pages/index/index' || val == '/pages/classify/classify' || val == '/pages/cart/index/index' || val == '/pages/member/index/index') {
uni.switchTab({
url: val
});
return;
} else if(val.indexOf('/pages/coupon/coupon')>-1){
var id = val.replace('/pages/coupon/coupon?id=',"");
this.receiveCoupon(id)
} else {
this.$common.navigateTo(val);
return;
}
// #endif
}
} else if (type == 2) {
// 商品详情
this.goodsDetail(val)
} else if (type == 3) {
// 文章详情
this.$common.navigateTo('/pages/article/index?id=' + val + '&id_type=1')
} else if (type == 4) {
// 文章列表
this.$common.navigateTo('/pages/article/list?cid=' + val)
} else if (type == 5) {
//智能表单
this.$common.navigateTo('/pages/form/detail/form?id=' + val)
}
}
// #endif
},
}
</script>
<style>
/* .ad {
width: 100%;
overflow: hidden;
}
.ad-img{
width: 100%;
float: left;
margin-bottom: 20upx;
}
.ad-img:last-child{
margin-bottom: 0;
} */
.jshop-imgsingle.ad {
width: 100%;
overflow: hidden;
position: relative;
}
.jshop-imgsingle .ad-img {
width: 100%;
float: left;
position: relative;
z-index: 667;
/* margin-bottom: 20upx; */
}
.jshop-imgsingle .ad-img:last-child {
margin-bottom: 0;
}
.jshop-imgsingle .imgup-btn {
position: absolute;
z-index: 668;
bottom: 80upx;
left: 40upx;
}
.jshop-imgsingle .imgup-btn .btn {
line-height: 2;
font-size: 28upx;
padding: 0 50upx;
}
</style>

View File

@@ -0,0 +1,667 @@
<template>
<!-- 头部轮播 -->
<!-- #ifdef MP -->
<view class="carousel-section" style="margin-top: 80upx;">
<!-- #endif -->
<!-- #ifndef MP -->
<view class="carousel-section">
<!-- #endif -->
<!-- 标题栏和状态栏占位符 -->
<view class="titleNview-placing"></view>
<!-- 背景色区域 -->
<view class="titleNview-background" :style="{ backgroundColor: titleNViewBackground }"></view>
<swiper class="carousel" circular @change="swiperChange">
<swiper-item v-for="(item, index) in jdata.options.colorGroup" :key="index" class="carousel-item" @click="navToTabPage(item.adLink)">
<image :src="item.adImg" />
</swiper-item>
</swiper>
<!-- 自定义swiper指示器 -->
<view class="swiper-dots">
<text class="num">{{ swiperCurrent + 1 }}</text>
<text class="sign">/</text>
<text class="num">{{ jdata.options.colorGroup.length }}</text>
</view>
</view>
</template>
<script>
export default {
name: "jshopimgSlide",
props: {
jdata: {
// type: Object,
required: true,
}
},
data() {
return {
swiperCurrent: 0,
titleNViewBackground: '',
swiperLength: 0,
swiper: {
indicatorDots: true,
autoplay: true,
interval: 2000,
duration: 500,
},
};
},
computed: {
count() {
return (this.jdata.options.colorGroup.length > 0)
}
},
created() {},
watch: {},
methods: {
navToTabPage(url) {
uni.navigateTo({
url: url
});
},
//轮播图切换修改背景色
swiperChange(e) {
const index = e.detail.current;
this.swiperCurrent = index;
// this.titleNViewBackground = this.jdata.options.colorGroup[index].background;
},
// 广告点击查看详情
showSliderInfo(type, val) {
if (!val) {
return;
}
if (type == 1) {
if (val.indexOf('http') != -1) {
// #ifdef H5
window.location.href = val
// #endif
} else {
// #ifdef H5 || APP-PLUS || APP-PLUS-NVUE || MP
if (val == '/pages/index/index' || val == '/pages/classify/classify' || val == '/pages/cart/index/index' || val == '/pages/member/index/index') {
uni.switchTab({
url: val
});
return;
} else if (val.indexOf('/pages/coupon/coupon') > -1) {
var id = val.replace('/pages/coupon/coupon?id=', "");
this.receiveCoupon(id)
} else {
this.$common.navigateTo(val);
return;
}
// #endif
}
} else if (type == 2) {
// 商品详情
this.goodsDetail(val)
} else if (type == 3) {
// 文章详情
this.$common.navigateTo('/pages/article/index?id=' + val + '&id_type=1')
} else if (type == 4) {
// 文章列表
this.$common.navigateTo('/pages/article/list?cid=' + val)
} else if (type == 5) {
//智能表单
this.$common.navigateTo('/pages/form/detail/form?id=' + val)
}
},
//跳转到商品详情页面
goodsDetail: function(id) {
let url = '/pages/goods/index/index?id=' + id;
this.$common.navigateTo(url);
},
// 用户领取优惠券
receiveCoupon(couponId) {
let data = {
promotion_id: couponId
}
this.$api.getCoupon(data, res => {
if (res.status) {
this.$common.successToShow(res.msg)
} else {
this.$common.errorToShow(res.msg)
}
})
},
}
}
</script>
<style lang="scss">
.MP-search{
background: #FFFFFF;height: 80upx;display: flex;justify-content: center;align-items: center;position: fixed;width: 100%;z-index: 999;
}
.MP-search-input{
font-size: 28upx;background: #F5F5F5;height: 60upx;width: 90%;border-radius: 50upx;text-align: center;
}
.mp-search-box {
position: absolute;
left: 0;
top: 30upx;
z-index: 9999;
width: 100%;
padding: 0 80upx;
.ser-input {
flex: 1;
height: 60upx;
line-height: 60upx;
text-align: center;
font-size: 28upx;
color: $font-color-base;
border-radius: 20px;
background: rgba(255, 255, 255, 0.6);
}
}
page {
.cate-section {
position: relative;
z-index: 5;
border-radius: 16upx 16upx 0 0;
margin-top: -20upx;
}
.carousel-section {
padding: 0;
.titleNview-placing {
padding-top: 0;
height: 0;
}
.carousel {
.carousel-item {
padding: 0;
}
}
.swiper-dots {
left: 45upx;
bottom: 40upx;
}
}
}
page {
background: #f5f5f5;
}
.m-t {
margin-top: 20upx;
}
/* 头部 轮播图 */
.carousel-section {
position: relative;
padding-top: 10px;
.titleNview-placing {
height: var(--status-bar-height);
padding-top: 44px;
box-sizing: content-box;
}
.titleNview-background {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 426upx;
transition: 0.4s;
}
}
.carousel {
width: 100%;
height: 350upx;
.carousel-item {
width: 100%;
height: 100%;
padding: 0 28upx;
overflow: hidden;
}
image {
width: 100%;
height: 100%;
border-radius: 10upx;
}
}
.swiper-dots {
display: flex;
position: absolute;
left: 60upx;
bottom: 15upx;
width: 72upx;
height: 36upx;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAABkCAYAAADDhn8LAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTMyIDc5LjE1OTI4NCwgMjAxNi8wNC8xOS0xMzoxMzo0MCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OTk4MzlBNjE0NjU1MTFFOUExNjRFQ0I3RTQ0NEExQjMiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OTk4MzlBNjA0NjU1MTFFOUExNjRFQ0I3RTQ0NEExQjMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTcgKFdpbmRvd3MpIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6Q0E3RUNERkE0NjExMTFFOTg5NzI4MTM2Rjg0OUQwOEUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6Q0E3RUNERkI0NjExMTFFOTg5NzI4MTM2Rjg0OUQwOEUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4Gh5BPAAACTUlEQVR42uzcQW7jQAwFUdN306l1uWwNww5kqdsmm6/2MwtVCp8CosQtP9vg/2+/gY+DRAMBgqnjIp2PaCxCLLldpPARRIiFj1yBbMV+cHZh9PURRLQNhY8kgWyL/WDtwujjI8hoE8rKLqb5CDJaRMJHokC6yKgSCR9JAukmokIknCQJpLOIrJFwMsBJELFcKHwM9BFkLBMKFxNcBCHlQ+FhoocgpVwwnv0Xn30QBJGMC0QcaBVJiAMiec/dcwKuL4j1QMsVCXFAJE4s4NQA3K/8Y6DzO4g40P7UcmIBJxbEesCKWBDg8wWxHrAiFgT4fEGsB/CwIhYE+AeBAAdPLOcV8HRmWRDAiQVcO7GcV8CLM8uCAE4sQCDAlHcQ7x+ABQEEAggEEAggEEAggEAAgQACASAQQCCAQACBAAIBBAIIBBAIIBBAIABe4e9iAe/xd7EAJxYgEGDeO4j3EODp/cOCAE4sYMyJ5cwCHs4rCwI4sYBxJ5YzC84rCwKcXxArAuthQYDzC2JF0H49LAhwYUGsCFqvx5EF2T07dMaJBetx4cRyaqFtHJ8EIhK0i8OJBQxcECuCVutxJhCRoE0cZwMRyRcFefa/ffZBVPogePihhyCnbBhcfMFFEFM+DD4m+ghSlgmDkwlOgpAl4+BkkJMgZdk4+EgaSCcpVX7bmY9kgXQQU+1TgE0c+QJZUUz1b2T4SBbIKmJW+3iMj2SBVBWz+leVfCQLpIqYbp8b85EskIxyfIOfK5Sf+wiCRJEsllQ+oqEkQfBxmD8BBgA5hVjXyrBNUQAAAABJRU5ErkJggg==);
background-size: 100% 100%;
.num {
width: 36upx;
height: 36upx;
border-radius: 50px;
font-size: 24upx;
color: #fff;
text-align: center;
line-height: 36upx;
}
.sign {
position: absolute;
top: 0;
left: 50%;
line-height: 36upx;
font-size: 12upx;
color: #fff;
transform: translateX(-50%);
}
}
/* 分类 */
.cate-section {
display: flex;
justify-content: space-around;
align-items: center;
flex-wrap: wrap;
padding: 30upx 22upx;
background: #fff;
.cate-item {
display: flex;
flex-direction: column;
align-items: center;
font-size: $font-sm + 2upx;
color: $font-color-dark;
}
/* 原图标颜色太深,不想改图了,所以加了透明度 */
image {
width: 88upx;
height: 88upx;
margin-bottom: 14upx;
border-radius: 50%;
opacity: 0.7;
box-shadow: 4upx 4upx 20upx rgba(250, 67, 106, 0.3);
}
}
.ad-1 {
width: 100%;
height: 210upx;
padding: 10upx 0;
background: #fff;
image {
width: 100%;
height: 100%;
}
}
/* 秒杀专区 */
.seckill-section {
padding: 0upx 20upx 20upx;
background: #fff;
.s-header {
display: flex;
align-items: center;
height: 90upx;
line-height: 1;
.s-img {
width: 140upx;
height: 30upx;
}
.tip {
font-size: $font-base;
color: $font-color-light;
// margin: 0 20upx 0 40upx;
}
.timer {
display: inline-block;
width: 40upx;
height: 36upx;
text-align: center;
line-height: 36upx;
margin-right: 14upx;
font-size: $font-sm + 2upx;
color: #fff;
border-radius: 2px;
background: rgba(0, 0, 0, 0.8);
}
.icon-you {
font-size: $font-lg;
color: $font-color-light;
flex: 1;
text-align: right;
}
}
.floor-list {
white-space: nowrap;
}
.scoll-wrapper {
display: flex;
align-items: flex-start;
}
.floor-item {
width: 150upx;
margin-right: 20upx;
font-size: $font-sm + 2upx;
color: $font-color-dark;
line-height: 1.8;
image {
width: 150upx;
height: 150upx;
border-radius: 6upx;
}
.price {
color: $uni-color-primary;
}
}
}
.f-header {
display: flex;
align-items: center;
height: 140upx;
padding: 0upx 20upx;
background: #fff;
image {
flex-shrink: 0;
width: 80upx;
height: 80upx;
margin-right: 20upx;
}
.tit-box {
flex: 1;
display: flex;
flex-direction: column;
}
.tit {
font-size: $font-lg + 2upx;
color: #font-color-dark;
line-height: 1.3;
}
.tit2 {
font-size: $font-sm;
color: $font-color-light;
}
.icon-you {
font-size: $font-lg + 2upx;
color: $font-color-light;
}
}
/* 团购楼层 */
.group-section {
background: #fff;
.g-swiper {
height: 650upx;
padding-bottom: 20upx;
}
.g-swiper-item {
width: 100%;
padding: 0 20upx;
display: flex;
}
image {
width: 100%;
height: 460upx;
border-radius: 4px;
}
.g-item {
display: flex;
flex-direction: column;
overflow: hidden;
}
.left {
flex: 1.2;
// margin-right: 24upx;
.t-box {
padding-top: 20upx;
}
}
.right {
flex: 0.8;
flex-direction: column-reverse;
.t-box {
padding-bottom: 20upx;
}
}
.t-box {
height: 160upx;
font-size: $font-base + 2upx;
color: $font-color-dark;
line-height: 1.6;
}
.price {
color: $uni-color-primary;
}
.m-price {
font-size: $font-sm + 2upx;
text-decoration: line-through;
color: $font-color-light;
margin-left: 8upx;
}
.pro-box {
display: flex;
align-items: center;
margin-top: 10upx;
font-size: $font-sm;
color: $font-base;
padding-right: 10upx;
}
.progress-box {
flex: 1;
border-radius: 10px;
overflow: hidden;
margin-right: 8upx;
}
}
/* 分类推荐楼层 */
.hot-floor {
width: 100%;
overflow: hidden;
margin-bottom: 20upx;
.floor-img-box {
width: 100%;
height: 320upx;
position: relative;
&:after {
content: '';
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: linear-gradient(rgba(255, 255, 255, 0.06) 30%, #f8f8f8);
}
}
.floor-img {
width: 100%;
height: 100%;
}
.floor-list {
white-space: nowrap;
padding: 20upx;
padding-right: 50upx;
border-radius: 6upx;
margin-top: -140upx;
margin-left: 30upx;
background: #fff;
box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.2);
position: relative;
z-index: 1;
}
.scoll-wrapper {
display: flex;
align-items: flex-start;
}
.floor-item {
width: 180upx;
margin-right: 20upx;
font-size: $font-sm + 2upx;
color: $font-color-dark;
line-height: 1.8;
image {
width: 180upx;
height: 180upx;
border-radius: 6upx;
}
.price {
color: $uni-color-primary;
}
}
.more {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
flex-shrink: 0;
width: 180upx;
height: 180upx;
border-radius: 6upx;
background: #f3f3f3;
font-size: $font-base;
color: $font-color-light;
text:first-child {
margin-bottom: 4upx;
}
}
}
/* 单条商品 */
.goods-box-single {
display: flex;
padding: 20upx 0;
.goods-img {
display: block;
width: 120upx;
height: 120upx;
}
.right {
flex: 1;
display: flex;
flex-direction: column;
padding: 0 30upx 0 24upx;
overflow: hidden;
.title {
font-size: $font-base + 2upx;
color: $font-color-dark;
line-height: 1;
}
.attr-box {
font-size: $font-sm + 2upx;
color: $font-color-light;
padding: 10upx 12upx;
}
.price {
font-size: $font-base + 2upx;
color: $font-color-dark;
&:before {
content: '¥';
font-size: $font-sm;
margin: 0 2upx 0 8upx;
}
}
}
}
.price-box {
display: flex;
justify-content: flex-end;
align-items: baseline;
padding: 20upx 30upx;
font-size: $font-sm + 2upx;
color: $font-color-light;
.num {
margin: 0 8upx;
color: $font-color-dark;
}
.price {
font-size: $font-lg;
color: $font-color-dark;
&:before {
content: '¥';
font-size: $font-sm;
margin: 0 2upx 0 8upx;
}
}
}
.action-box {
display: flex;
justify-content: flex-end;
align-items: center;
height: 100upx;
position: relative;
padding-right: 30upx;
}
.action-btn {
width: 160upx;
height: 60upx;
margin: 0;
margin-left: 24upx;
padding: 0;
text-align: center;
line-height: 60upx;
font-size: $font-sm + 2upx;
color: $font-color-dark;
background: #fff;
border-radius: 100px;
&:after {
border-radius: 100px;
}
&.recom {
background: #fff9f9;
color: $base-color;
&:after {
border-color: #f7bcc8;
}
}
}
/* 猜你喜欢 */
.guess-section {
display: flex;
flex-wrap: wrap;
padding: 0 30upx;
background: #fff;
.guess-item {
display: flex;
flex-direction: column;
width: 48%;
padding-bottom: 40upx;
&:nth-child(2n + 1) {
margin-right: 4%;
}
}
.image-wrapper {
width: 100%;
height: 330upx;
border-radius: 3px;
overflow: hidden;
image {
width: 100%;
height: 100%;
opacity: 1;
}
}
.title {
font-size: $font-lg;
color: $font-color-dark;
line-height: 80upx;
}
.price {
font-size: $font-lg;
color: $uni-color-primary;
line-height: 1;
}
.coupon_box {
width:100%; height:auto; display:table; padding:6upx 26upx 26upx 26upx;
}
.other_type {
width:100%; height:90upx; padding-top:50upx;
.text { width:100%; border-top:1px solid #eeeeee; display:block; text-align:center; position:relative; }
.text span { width:180upx; height:40upx; line-height:40upx; color:#999999; display:block; background:#ffffff; position:absolute; left:50%; top:50%; margin-left:-90upx; margin-top:-20upx; font-size:$font-base; }
}
}
.getPosition{
height: 100upx;
display: flex;
justify-content: center;
align-items: center;
font-size: 32upx;
background-color: #FFF;
}
</style>

View File

@@ -0,0 +1,207 @@
<template>
<view class="imgwindow">
<view class="imgwindow-list" v-if="jdata.id == '3' "
v-bind:class="'row'+jdata.id" :style="{margin:-jdata.id+'px'}">
<image v-for="(item, index) in jdata.options.colorGroup" :key="index" :src="item.adImg" mode="widthFix" @click="showSliderInfo(item.linkType, item.linkValue)"></image>
</view>
<view class="imgwindow-list" v-if="jdata.id == '4'" v-bind:class="'row'+jdata.id" :style="{margin:-jdata.id+'px'}">
<view class="imgwindow-item" ref="imgwitem" :style="{height:height+'px',padding:jdata.id+'px'}" v-for="(item, index) in jdata.options.colorGroup"
:key="index" v-if="index == 0">
<image :src="item.adImg" mode="aspectFill" @click="showSliderInfo(item.linkType, item.linkValue)"></image>
</view>
<view class="imgwindow-item" ref="imgwitem" :style="{height:height1+'px',padding:jdata.id+'px'}" v-for="(item, index) in jdata.options.colorGroup"
:key="index" v-if="index !== 0">
<image :src="item.adImg" mode="aspectFill" @click="showSliderInfo(item.linkType, item.linkValue)"></image>
</view>
</view>
</view>
</template>
<script>
export default {
name: "jshopimgwindow",
props: {
jdata: {
// type: Object,
required: true,
}
},
data() {
return {
height: '',
height1: '',
padding: '3'
}
},
mounted() {
// #ifdef H5 || APP-PLUS || APP-PLUS-NVUE
var view = uni.createSelectorQuery().in(this).select(".imgwindow-item");
view.boundingClientRect(data => {
this.height = 50;
// 橱窗小图高度
this.height1 = 50 / 2;
}).exec();
// #endif
// #ifdef MP-ALIPAY
var view = uni.createSelectorQuery().in(this).select(".content").boundingClientRect().exec(data => {
this.height1 = data[0].width / 4;
if (this.data.params.style == '3') {
this.height = data[0].width / 3;
} else if (this.data.params.style == '2') {
this.height = data[0].width / 2;
} else if (this.data.params.style == '4') {
this.height = data[0].width / 4;
} else if (this.data.params.style == '0') {
this.height = data[0].width / 2;
}
});
// #endif
// #ifdef MP-WEIXIN
var view = uni.createSelectorQuery().select(".content");
view.boundingClientRect(jdata => {
this.height1 = jdata.width / 4;
if (this.jdata.params.style == '3') {
this.height = jdata.width / 3;
} else if (this.jdata.params.style == '2') {
this.height = jdata.width / 2;
} else if (this.jdata.params.style == '4') {
this.height = jdata.width / 4;
} else if (this.jdata.params.style == '0') {
this.height = jdata.width / 2;
}
}).exec();
// #endif
},
methods: {
showSliderInfo(type, val) {
if (!val) {
return;
}
if (type == 1) {
if (val.indexOf('http') != -1) {
// #ifdef H5
window.location.href = val
// #endif
} else {
// #ifdef H5 || APP-PLUS || APP-PLUS-NVUE || MP
if (val == '/pages/index/index' || val == '/pages/classify/classify' || val == '/pages/cart/index/index' || val ==
'/pages/member/index/index') {
uni.switchTab({
url: val
});
return;
} else if(val.indexOf('/pages/coupon/coupon')>-1){
var id = val.replace('/pages/coupon/coupon?id=',"");
this.receiveCoupon(id)
} else {
this.$common.navigateTo(val);
return;
}
// #endif
}
} else if (type == 2) {
// 商品详情
this.goodsDetail(val)
} else if (type == 3) {
// 文章详情
this.$common.navigateTo('/pages/article/index?id=' + val + '&id_type=1')
} else if (type == 4) {
// 文章列表
this.$common.navigateTo('/pages/article/list?cid=' + val)
} else if (type == 5) {
//智能表单
this.$common.navigateTo('/pages/form/detail/form?id=' + val)
}
},
//跳转到商品详情页面
goodsDetail: function(id) {
let url = '/pages/goods/index/index?id=' + id;
this.$common.navigateTo(url);
},
// 用户领取优惠券
receiveCoupon(couponId) {
let data = {
promotion_id: couponId
}
this.$api.getCoupon(data, res => {
if (res.status) {
this.$common.successToShow(res.msg)
} else {
this.$common.errorToShow(res.msg)
}
})
},
}
}
</script>
<style>
.imgwindow {
width: 100%;
}
.imgwindow-list {
/* overflow: hidden; */
/* margin: -16upx; */
display: flex;
}
/* 堆积两列 */
.imgwindow-list .imgwindow-item {
height: auto;
flex: 1;
/* float: left; */
/* padding: 8upx; */
}
.imgwindow-list .imgwindow-item image {
width: 100%;
/* height: 100%; */
}
.imgwindow-list.row0{
overflow: hidden;
display: block;
}
.imgwindow-list.row0 .imgwindow-item {
height: auto;
flex: auto;
float: left;
/* padding: 8upx; */
}
.imgwindow-list.row0 .imgwindow-item image {
width: 100%;
height: 100%;
}
.imgwindow-list.row0 .imgwindow-item:first-child {
width: 50%;
}
.imgwindow-list.row0 .imgwindow-item:nth-child(2) {
width: 50%;
}
.imgwindow-list.row0 .imgwindow-item:nth-child(3),
.imgwindow-list.row0 .imgwindow-item:nth-child(4) {
width: 25%;
}
/* .imgwindow-list.row2 .imgwindow-item {
width: 50%;
}
.imgwindow-list.row3 .imgwindow-item {
width: 33.3%;
}
.imgwindow-list.row4 .imgwindow-item {
width: 25%;
} */
</style>

View File

@@ -0,0 +1,616 @@
<template>
<view class="container">
<view class="cate-section">
<view class="cate-item" v-for="(item, index) in jdata.options.colorGroup" @click="navToTabPage(item.tabContent[0].tabLink)">
<image :src="item.tabContent[0].tabImg"></image>
<text>{{item.tabs}}</text>
</view>
</view>
</view>
</template>
<script>
export default {
name: "jshopnavbar",
props: {
jdata: {
// type: Object,
required: true,
}
},
data() {
return {
height: '',
height1: ''
}
},
onLoad() {
},
mounted() {
},
methods: {
showSliderInfo(type, val) {
console.log(val)
if (!val) {
return;
}
console.log("11")
if (type == 1) {
if (val.indexOf('http') != -1) {
// #ifdef H5
window.location.href = val
// #endif
} else {
// #ifdef H5 || APP-PLUS || APP-PLUS-NVUE || MP
if (val == '/pages/index/index' || val == '/pages/classify/classify' || val == '/pages/cart/index/index' || val == '/pages/member/index/index') {
uni.switchTab({
url: val
});
return;
} else {
this.$common.navigateTo(val);
return;
}
// #endif
}
} else if (type == 2) {
// 商品详情
this.goodsDetail(val)
} else if (type == 3) {
// 文章详情
this.$common.navigateTo('/pages/article/index?id=' + val + '&id_type=1')
} else if (type == 4) {
// console.log("11")
// 文章列表
this.$common.navigateTo('/pages/article/list?cid=' + val)
} else if (type == 5) {
//智能表单
this.$common.navigateTo('/pages/form/detail/form?id=' + val)
}
},
//跳转到商品详情页面
goodsDetail: function(id) {
let url = '/pages/goods/index/index?id=' + id;
this.$common.navigateTo(url);
},
}
}
</script>
<style lang="scss">
.MP-search{
background: #FFFFFF;height: 80upx;display: flex;justify-content: center;align-items: center;position: fixed;width: 100%;z-index: 999;
}
.MP-search-input{
font-size: 28upx;background: #F5F5F5;height: 60upx;width: 90%;border-radius: 50upx;text-align: center;
}
.mp-search-box {
position: absolute;
left: 0;
top: 30upx;
z-index: 9999;
width: 100%;
padding: 0 80upx;
.ser-input {
flex: 1;
height: 60upx;
line-height: 60upx;
text-align: center;
font-size: 28upx;
color: $font-color-base;
border-radius: 20px;
background: rgba(255, 255, 255, 0.6);
}
}
page {
.cate-section {
position: relative;
z-index: 5;
border-radius: 16upx 16upx 0 0;
margin-top: -20upx;
}
.carousel-section {
padding: 0;
.titleNview-placing {
padding-top: 0;
height: 0;
}
.carousel {
.carousel-item {
padding: 0;
}
}
.swiper-dots {
left: 45upx;
bottom: 40upx;
}
}
}
page {
background: #f5f5f5;
}
.m-t {
margin-top: 20upx;
}
/* 头部 轮播图 */
.carousel-section {
position: relative;
padding-top: 10px;
.titleNview-placing {
height: var(--status-bar-height);
padding-top: 44px;
box-sizing: content-box;
}
.titleNview-background {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 426upx;
transition: 0.4s;
}
}
.carousel {
width: 100%;
height: 350upx;
.carousel-item {
width: 100%;
height: 100%;
padding: 0 28upx;
overflow: hidden;
}
image {
width: 100%;
height: 100%;
border-radius: 10upx;
}
}
.swiper-dots {
display: flex;
position: absolute;
left: 60upx;
bottom: 15upx;
width: 72upx;
height: 36upx;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAABkCAYAAADDhn8LAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTMyIDc5LjE1OTI4NCwgMjAxNi8wNC8xOS0xMzoxMzo0MCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OTk4MzlBNjE0NjU1MTFFOUExNjRFQ0I3RTQ0NEExQjMiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OTk4MzlBNjA0NjU1MTFFOUExNjRFQ0I3RTQ0NEExQjMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTcgKFdpbmRvd3MpIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6Q0E3RUNERkE0NjExMTFFOTg5NzI4MTM2Rjg0OUQwOEUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6Q0E3RUNERkI0NjExMTFFOTg5NzI4MTM2Rjg0OUQwOEUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4Gh5BPAAACTUlEQVR42uzcQW7jQAwFUdN306l1uWwNww5kqdsmm6/2MwtVCp8CosQtP9vg/2+/gY+DRAMBgqnjIp2PaCxCLLldpPARRIiFj1yBbMV+cHZh9PURRLQNhY8kgWyL/WDtwujjI8hoE8rKLqb5CDJaRMJHokC6yKgSCR9JAukmokIknCQJpLOIrJFwMsBJELFcKHwM9BFkLBMKFxNcBCHlQ+FhoocgpVwwnv0Xn30QBJGMC0QcaBVJiAMiec/dcwKuL4j1QMsVCXFAJE4s4NQA3K/8Y6DzO4g40P7UcmIBJxbEesCKWBDg8wWxHrAiFgT4fEGsB/CwIhYE+AeBAAdPLOcV8HRmWRDAiQVcO7GcV8CLM8uCAE4sQCDAlHcQ7x+ABQEEAggEEAggEEAggEAAgQACASAQQCCAQACBAAIBBAIIBBAIIBBAIABe4e9iAe/xd7EAJxYgEGDeO4j3EODp/cOCAE4sYMyJ5cwCHs4rCwI4sYBxJ5YzC84rCwKcXxArAuthQYDzC2JF0H49LAhwYUGsCFqvx5EF2T07dMaJBetx4cRyaqFtHJ8EIhK0i8OJBQxcECuCVutxJhCRoE0cZwMRyRcFefa/ffZBVPogePihhyCnbBhcfMFFEFM+DD4m+ghSlgmDkwlOgpAl4+BkkJMgZdk4+EgaSCcpVX7bmY9kgXQQU+1TgE0c+QJZUUz1b2T4SBbIKmJW+3iMj2SBVBWz+leVfCQLpIqYbp8b85EskIxyfIOfK5Sf+wiCRJEsllQ+oqEkQfBxmD8BBgA5hVjXyrBNUQAAAABJRU5ErkJggg==);
background-size: 100% 100%;
.num {
width: 36upx;
height: 36upx;
border-radius: 50px;
font-size: 24upx;
color: #fff;
text-align: center;
line-height: 36upx;
}
.sign {
position: absolute;
top: 0;
left: 50%;
line-height: 36upx;
font-size: 12upx;
color: #fff;
transform: translateX(-50%);
}
}
/* 分类 */
.cate-section {
display: flex;
justify-content: space-around;
align-items: center;
flex-wrap: wrap;
padding: 30upx 22upx;
background: #fff;
.cate-item {
display: flex;
flex-direction: column;
align-items: center;
font-size: $font-sm + 2upx;
color: $font-color-dark;
}
/* 原图标颜色太深,不想改图了,所以加了透明度 */
image {
width: 88upx;
height: 88upx;
margin-bottom: 14upx;
border-radius: 50%;
opacity: 0.7;
box-shadow: 4upx 4upx 20upx rgba(250, 67, 106, 0.3);
}
}
.ad-1 {
width: 100%;
height: 210upx;
padding: 10upx 0;
background: #fff;
image {
width: 100%;
height: 100%;
}
}
/* 秒杀专区 */
.seckill-section {
padding: 0upx 20upx 20upx;
background: #fff;
.s-header {
display: flex;
align-items: center;
height: 90upx;
line-height: 1;
.s-img {
width: 140upx;
height: 30upx;
}
.tip {
font-size: $font-base;
color: $font-color-light;
// margin: 0 20upx 0 40upx;
}
.timer {
display: inline-block;
width: 40upx;
height: 36upx;
text-align: center;
line-height: 36upx;
margin-right: 14upx;
font-size: $font-sm + 2upx;
color: #fff;
border-radius: 2px;
background: rgba(0, 0, 0, 0.8);
}
.icon-you {
font-size: $font-lg;
color: $font-color-light;
flex: 1;
text-align: right;
}
}
.floor-list {
white-space: nowrap;
}
.scoll-wrapper {
display: flex;
align-items: flex-start;
}
.floor-item {
width: 150upx;
margin-right: 20upx;
font-size: $font-sm + 2upx;
color: $font-color-dark;
line-height: 1.8;
image {
width: 150upx;
height: 150upx;
border-radius: 6upx;
}
.price {
color: $uni-color-primary;
}
}
}
.f-header {
display: flex;
align-items: center;
height: 140upx;
padding: 0upx 20upx;
background: #fff;
image {
flex-shrink: 0;
width: 80upx;
height: 80upx;
margin-right: 20upx;
}
.tit-box {
flex: 1;
display: flex;
flex-direction: column;
}
.tit {
font-size: $font-lg + 2upx;
color: #font-color-dark;
line-height: 1.3;
}
.tit2 {
font-size: $font-sm;
color: $font-color-light;
}
.icon-you {
font-size: $font-lg + 2upx;
color: $font-color-light;
}
}
/* 团购楼层 */
.group-section {
background: #fff;
.g-swiper {
height: 650upx;
padding-bottom: 20upx;
}
.g-swiper-item {
width: 100%;
padding: 0 20upx;
display: flex;
}
image {
width: 100%;
height: 460upx;
border-radius: 4px;
}
.g-item {
display: flex;
flex-direction: column;
overflow: hidden;
}
.left {
flex: 1.2;
// margin-right: 24upx;
.t-box {
padding-top: 20upx;
}
}
.right {
flex: 0.8;
flex-direction: column-reverse;
.t-box {
padding-bottom: 20upx;
}
}
.t-box {
height: 160upx;
font-size: $font-base + 2upx;
color: $font-color-dark;
line-height: 1.6;
}
.price {
color: $uni-color-primary;
}
.m-price {
font-size: $font-sm + 2upx;
text-decoration: line-through;
color: $font-color-light;
margin-left: 8upx;
}
.pro-box {
display: flex;
align-items: center;
margin-top: 10upx;
font-size: $font-sm;
color: $font-base;
padding-right: 10upx;
}
.progress-box {
flex: 1;
border-radius: 10px;
overflow: hidden;
margin-right: 8upx;
}
}
/* 分类推荐楼层 */
.hot-floor {
width: 100%;
overflow: hidden;
margin-bottom: 20upx;
.floor-img-box {
width: 100%;
height: 320upx;
position: relative;
&:after {
content: '';
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: linear-gradient(rgba(255, 255, 255, 0.06) 30%, #f8f8f8);
}
}
.floor-img {
width: 100%;
height: 100%;
}
.floor-list {
white-space: nowrap;
padding: 20upx;
padding-right: 50upx;
border-radius: 6upx;
margin-top: -140upx;
margin-left: 30upx;
background: #fff;
box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.2);
position: relative;
z-index: 1;
}
.scoll-wrapper {
display: flex;
align-items: flex-start;
}
.floor-item {
width: 180upx;
margin-right: 20upx;
font-size: $font-sm + 2upx;
color: $font-color-dark;
line-height: 1.8;
image {
width: 180upx;
height: 180upx;
border-radius: 6upx;
}
.price {
color: $uni-color-primary;
}
}
.more {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
flex-shrink: 0;
width: 180upx;
height: 180upx;
border-radius: 6upx;
background: #f3f3f3;
font-size: $font-base;
color: $font-color-light;
text:first-child {
margin-bottom: 4upx;
}
}
}
/* 单条商品 */
.goods-box-single {
display: flex;
padding: 20upx 0;
.goods-img {
display: block;
width: 120upx;
height: 120upx;
}
.right {
flex: 1;
display: flex;
flex-direction: column;
padding: 0 30upx 0 24upx;
overflow: hidden;
.title {
font-size: $font-base + 2upx;
color: $font-color-dark;
line-height: 1;
}
.attr-box {
font-size: $font-sm + 2upx;
color: $font-color-light;
padding: 10upx 12upx;
}
.price {
font-size: $font-base + 2upx;
color: $font-color-dark;
&:before {
content: '¥';
font-size: $font-sm;
margin: 0 2upx 0 8upx;
}
}
}
}
.price-box {
display: flex;
justify-content: flex-end;
align-items: baseline;
padding: 20upx 30upx;
font-size: $font-sm + 2upx;
color: $font-color-light;
.num {
margin: 0 8upx;
color: $font-color-dark;
}
.price {
font-size: $font-lg;
color: $font-color-dark;
&:before {
content: '¥';
font-size: $font-sm;
margin: 0 2upx 0 8upx;
}
}
}
.action-box {
display: flex;
justify-content: flex-end;
align-items: center;
height: 100upx;
position: relative;
padding-right: 30upx;
}
.action-btn {
width: 160upx;
height: 60upx;
margin: 0;
margin-left: 24upx;
padding: 0;
text-align: center;
line-height: 60upx;
font-size: $font-sm + 2upx;
color: $font-color-dark;
background: #fff;
border-radius: 100px;
&:after {
border-radius: 100px;
}
&.recom {
background: #fff9f9;
color: $base-color;
&:after {
border-color: #f7bcc8;
}
}
}
/* 猜你喜欢 */
.guess-section {
display: flex;
flex-wrap: wrap;
padding: 0 30upx;
background: #fff;
.guess-item {
display: flex;
flex-direction: column;
width: 48%;
padding-bottom: 40upx;
&:nth-child(2n + 1) {
margin-right: 4%;
}
}
.image-wrapper {
width: 100%;
height: 330upx;
border-radius: 3px;
overflow: hidden;
image {
width: 100%;
height: 100%;
opacity: 1;
}
}
.title {
font-size: $font-lg;
color: $font-color-dark;
line-height: 80upx;
}
.price {
font-size: $font-lg;
color: $uni-color-primary;
line-height: 1;
}
.coupon_box {
width:100%; height:auto; display:table; padding:6upx 26upx 26upx 26upx;
}
.other_type {
width:100%; height:90upx; padding-top:50upx;
.text { width:100%; border-top:1px solid #eeeeee; display:block; text-align:center; position:relative; }
.text span { width:180upx; height:40upx; line-height:40upx; color:#999999; display:block; background:#ffffff; position:absolute; left:50%; top:50%; margin-left:-90upx; margin-top:-20upx; font-size:$font-base; }
}
}
.getPosition{
height: 100upx;
display: flex;
justify-content: center;
align-items: center;
font-size: 32upx;
background-color: #FFF;
}
</style>

View File

@@ -0,0 +1,69 @@
<template>
<view class="notice bottom-cell-group" v-if="jdata.options.colorGroup && count">
<view class="notice-icon">
<image class="icon news-icon" src="/static/image/news.png" mode=""></image>
</view>
<swiper class="notice-c" :indicator-dots="false" :autoplay="true" :interval="3000" :duration="1000" :vertical="true" :circular="true">
<swiper-item v-for="item in jdata.options.colorGroup" :key="item.id">
<view class="swiper-item" @click="goNotice(item.id)">{{ item.title }}</view>
</swiper-item>
</swiper>
</view>
</template>
<script>
export default {
name: "jshopnotice",
props: {
jdata:{
// type: Object,
required: true,
}
},
computed: {
count() {
return (this.jdata.options.colorGroup.length > 0)
}
},
methods: {
// 点击公告
goNotice(id) {
// 文章详情
this.$common.navigateTo('/pages/article/index?id=' + id+'&id_type=2')
},
},
}
</script>
<style>
.notice {
padding: 6upx 26upx 6upx 60upx;
position: relative;
overflow: hidden;
background-color: #fff;
color: #333;
}
.notice-icon {
display: inline-block;
height: 40upx;
position: absolute;
top: 59%;
left: 26upx;
transform: translateY(-50%);
overflow: hidden;
}
.news-icon {
width: 30upx;
height: 30upx;
float: left;
}
.notice-c {
margin-left: 10upx;
height: 50upx;
line-height: 50upx;
width: 630upx;
display: inline-block;
font-size: 28upx;
float: left;
}
</style>

View File

@@ -0,0 +1,150 @@
<template>
<view class="index-goods">
<!-- 列表平铺单列 -->
<view class="img-list bottom-cell-group" >
<view class='cell-item right-img' v-if="jdata.name != ''">
<view class='cell-item-hd'>
<view class='cell-hd-title'>{{jdata.name}}</view>
</view>
<view class='cell-item-bd'>
</view>
<view class='cell-item-ft' >
<text class='cell-ft-text' @click="goodsList({cat_id: jdata.params.classifyId,brand_id:jdata.params.brandId})">查看更多</text>
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
<view v-if="count">
<view class="img-list-item" v-for="(item, index) in jdata.options.colorGroup" :key="index" @click="goodsDetail(item.id)">
<image class="img-list-item-l have-none" :src="item.pic" mode='aspectFill'></image>
<view class="img-list-item-r">
<view class="goods-name list-goods-name">
{{item.title}}
</view>
<view class="goods-item-c">
<view class="goods-price red-price">{{item.price}}</view>
<view class="goods-buy">
<view class="goods-salesvolume" v-if="item.comments_count > 0">{{item.comments_count}}条评论</view>
<view class="goods-salesvolume" v-else-if="item.comments_count <= 0">暂无评论</view>
<image class="goods-cart" src="/static/image/ic-car.png"></image>
</view>
</view>
</view>
</view>
</view>
<view class="order-none" v-else>
<image class="order-none-img" src="/static/image/order.png" mode=""></image>
</view>
</view>
</view>
</view>
</template>
<script>
import {goods} from '@/config/mixins.js'
export default {
filters:{
substr(val) {
if (val.length == 0 || val == undefined) {
return false;
} else if (val.length > 13) {
return val.substring(0, 13) + "...";
} else {
return val;
}
}
},
mixins: [goods],
name: "jshoponegoods",
props: {
jdata:{
// type: Array,
required: true,
}
},
computed: {
count() {
return (this.jdata.options.colorGroup.length > 0)
}
},
methods: {
//跳转到商品详情页面
goodsDetail: function(id) {
let url = '/pages/goods/index/index?id=' + id;
this.$common.navigateTo(url);
},
},
}
</script>
<style>
.cell-item {
border: none;
/* padding-bottom: 0; */
}
.cell-ft-text {
font-size: 22upx;
color: #999;
}
.img-grids,.img-list{
/* margin-top: 20upx; */
background-color: #fff;
}
.img-grids-item{
display: inline-table;
margin-top: 0;
margin-bottom: 14upx;
}
.column3 .img-grids-item{
width: 230upx;
height: 364rpx !important;
margin: 15upx;
margin-right: 0;
margin-top: 0;
margin-bottom: 6upx;
}
.column3 .img-grids-item:nth-child(3n){
margin-right: 15upx;
}
.column3 .img-grids-item-t{
width: 230upx;
height: 230upx;
}
.column3 .grids-goods-name{
font-size: 24upx;
/* height: 68upx; */
/* min-height: 54rpx; */
}
.column3 .img-grids-item-b{
padding: 0 8upx 8upx;
}
.column3 .goods-price{
font-size: 26upx;
}
.slide3 .img-grids-item{
width: 200upx;
}
.slide3 .img-grids-item-t{
width: 200upx;
height: 200upx;
}
.slide3 .grids-goods-name{
font-size: 24rpx;
height: 66rpx;
}
.index-goods .img-grids-item{
display: inline-block;
margin-top: 0;
}
.index-goods .img-list-item{
padding: 0upx 26upx;
margin-bottom: 14upx;
}
.index-goods .img-list{
padding-bottom: 10upx;
}
</style>

View File

@@ -0,0 +1,83 @@
<template>
<!-- 拼团 -->
<view class="img-list bottom-cell-group group-buying" v-if="jdata.options.colorGroup && count">
<view class='cell-item right-img'>
<view class='cell-item-hd group-title'>
{{jdata.params.title}}
</view>
</view>
<view class='swiper-grids' >
<scroll-view class='swiper-list' scroll-x="true">
<view class="img-list-item" v-if="item.goods_id !== 'undefined' && item.goods_id" v-for="(item, key) in jdata.options.colorGroup" :key="key">
<image class="img-list-item-l medium-img have-none" :src="item.goods_image" mode='aspectFill' @click="pintuanDetail(item.goods_id)"></image>
<view class="img-list-item-r medium-right">
<view class="goods-name list-goods-name" @click="pintuanDetail(item.goods_id)">{{item.goods_name}}</view>
<view class="goods-item-c">
<view class="goods-price red-price">{{item.pintuan_price}}</view>
<view class="goods-buy">
<view class="goods-salesvolume red-price" v-if="(item.pintuan_start_status == 1) && item.lasttime">剩余:<uni-countdown :day="item.lasttime.day" :hour="item.lasttime.hour" :minute="item.lasttime.minute" :second="item.lasttime.second"></uni-countdown></view>
<view class="goods-salesvolume red-price" v-if="item.pintuan_start_status == 3">已结束</view>
<view class="goods-salesvolume red-price" v-if="item.pintuan_start_status == 2">即将开团</view>
<image class="goods-cart" src="/static/image/ic-car.png" @click="pintuanDetail(item.goods_id)"></image>
</view>
</view>
</view>
</view>
</scroll-view>
</view>
</view>
</template>
<script>
import uniCountdown from "@/components/uni-countdown/uni-countdown.vue"
import {goods} from '@/config/mixins.js'
export default {
mixins: [goods],
components:{uniCountdown},
name: "jshoppintuan",
props: {
jdata:{
// type: Array,
required: false,
}
},
computed: {
count() {
return (this.jdata.options.colorGroup.length > 0)
}
},
methods: {
},
}
</script>
<style>
.img-list, .img-grids {
background-color: #fff;
}
.cell-item{
border: none;
}
.group-buying .img-list-item{
min-height: 236upx;
padding: 20upx;
margin-left: 26upx;
margin-bottom: 26upx;
display: inline-table;
background-color: #f9f9f9;
}
.swiper-grids .img-list-item:last-child{
margin-right: 26upx;
}
/* .group-buying .goods-name{
min-height: 74upx;
} */
.group-buying .group-title{
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>

View File

@@ -0,0 +1,187 @@
<template>
<view class="adbrathing"
v-show="adbshow"
v-bind:class="['adbrathing'+jdata.params.style.align,!hideanimation?'pc':hideanimation?'hc':'']"
:style="{top:jdata.params.style.top+'%'}" >
<view class="adbrathing-c">
<view class="adbrathing-l">
<image class="user-head-img" :src="log.avatar" mode="aspectFill"></image>
<view class="user-name">
{{log.nickname}}
</view>
</view>
<view class="adbrathing-r">
{{log.ctime}}{{log.desc}}
</view>
</view>
</view>
</template>
<script>
import { apiBaseUrl } from '@/config/config.js';
export default {
name: "jshoprecord",
props: {
jdata:{
// type: Object,
required: true,
},
//记录显示的位置类型
ltype:{
type: String,
required: false,
default:'home',
},
//记录显示的位置的值
lvalue:{
type: String,
required: false,
default:'0',
}
},
data() {
return {
adbshow:false,
hideanimation: true,
log:{
avatar:'/static/demo-img/user-head.jpg',
nickname:'',
desc:'',
ctime:'',
},
times:{},//定时器
};
},
methods:{
//隐藏
hideLog(){
var _this = this;
_this.times = setInterval(function(){
_this.adbshow = !_this.adbshow;
_this.hideanimation = !_this.hideanimation;
clearInterval(_this.times);
_this.times = setInterval(function(){
_this.getRecod();
},5000);
},3000)
},
//获取日志
getRecod(){
var _this = this;
if(_this.times !={}){
clearInterval(_this.times);
}
var data = {
type:_this.ltype,
value:_this.lvalue,
method:'pages.getrecod',
};
uni.request({
url: apiBaseUrl+'api.html',
data: data,
header: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
method: 'POST',
success: (response) => {
var res = response.data;
if(res.status == true){
if(res.data){
_this.log = res.data;
_this.adbshow = true;
_this.hideanimation = false;
_this.hideLog();
}
}
}
});
}
},
mounted() {
this.getRecod();
}
}
</script>
<style lang="scss">
.adbrathing{
position: fixed;
// top: 100px;
// right: 30upx;
// max-width: 400upx;
height: 70upx;
background-color: rgba(0,0,0,.5);
border-radius: 10upx;
padding: 10upx;
z-index: 666;
.adbrathing-c{
width: 100%;
height: 100%;
overflow: hidden;
color: #fff;
font-size: 24upx;
.adbrathing-l{
display: inline-block;
height: 100%;
float: left;
overflow: hidden;
.user-head-img{
width: 50upx;
height: 50upx;
border-radius: 50%;
float: left;
}
.user-name{
float: left;
display: inline-block;
height: 100%;
line-height: 50upx;
margin: 0 4upx 0 10upx;
max-width: 120upx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.adbrathing-r{
float: left;
height: 100%;
display: inline-block;
line-height: 50upx;
}
}
}
.adbrathingleft{
left: 30upx
}
.adbrathingright{
right: 30upx
}
.pc{
animation: showcenter .55s;
}
.hc{
animation: hidecenter .55s;
}
@keyframes showcenter{
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes hidecenter{
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
</style>

View File

@@ -0,0 +1,118 @@
<template>
<view class="" >
<!-- 搜索框 -->
<view class="search" ref="searchBar" id="search">
<view class='search-c round' @click='goSearch()'>
<view class='search-input search-input-p'>
<view class="search-input-p-c">
{{jdata.options.search_tips}}
</view>
</view>
<image class='icon search-icon' src='/static/image/zoom.png'></image>
</view>
</view>
<!-- 搜索框 -->
<view class="search search-fixed" v-show="searchFixed">
<view class='search-c round' @click='goSearch()' >
<view class='search-input search-input-p'>
<view class="search-input-p-c">
{{jdata.options.search_tips}}
</view>
</view>
<image class='icon search-icon' src='/static/image/zoom.png'></image>
</view>
</view>
</view>
</template>
<script>
export default {
name: "jshopsearch",
props: {
jdata:{
// type: Object,
required: true,
}
},
data() {
return {
keyword:'',
searchTop: 0,
scrollTop: 0,
searchFixed: this.$store.state.searchFixed||false
};
},
created() {
//#ifdef H5
this.$nextTick(() => {
this.searchTop = this.$refs.searchBar.$el.offsetTop;
})
// #endif
this.searchStyle()
},
mounted() {
// #ifdef H5
window.addEventListener('scroll', this.handleScroll)
// #endif
},
methods: {
searchStyle (){
},
goSearch() {
uni.navigateTo({
url: '/pages/index/search'
});
},
handleScroll() {
this.scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
this.scrollTop >= this.searchTop? this.searchFixed = true : this.searchFixed = false;
},
},
/*
//失效
onPageScroll(){
var _this = this;
// #ifdef MP-WEIXIN || APP-PLUS || APP-PLUS-NVUE
const query = uni.createSelectorQuery().in(this)
query.select('.search').boundingClientRect(function(res){
if(res.top<0){
_this.searchFixed = true ;
}else{
_this.searchFixed = false;
}
}).exec()
// #endif
} */
}
</script>
<style>
.search-input-p {
color: #888;
}
.square{
border-radius: 0;
}
.radius{
border-radius: 12upx;
}
.search-fixed{
position: fixed;
top: 0;
/* background: linear-gradient(rgba(0, 0, 0, .5), rgba(0, 0, 0, 0)); */
transition: all .5s;
}
/* .isOpacity {
background: linear-gradient(rgba(0, 0, 0, .5), rgba(0, 0, 0, 0));
transition: all .5s;
}
.isOpacity .search-input {
background-color: rgba(255, 255, 255, .5);
transition: all .5s;
} */
</style>

View File

@@ -0,0 +1,614 @@
<template>
<view class="container">
<!-- 团购楼层 -->
<view class="f-header m-t" @click="navToTabPage('../../pagesA/product/groupList')" v-if="jdata.options.colorGroup.length > 0">
<image src="/static/temp/h1.png"></image>
<view class="tit-box">
<text class="tit" >精品团购</text>
<text class="tit2">Boutique Group Buying</text>
</view>
<text class="yticon icon-you"></text>
</view>
<view class="group-section">
<swiper class="g-swiper" :duration="500">
<swiper-item class="g-swiper-item" v-for="(item, index) in jdata.options.colorGroup" :key="index" @click="goodsDetail(item.id)">
<view class="g-item left">
<image :src="item.pic" mode="aspectFill"></image>
<view class="t-box">
<text class="title clamp">{{ item.title }}</text>
<view class="price-box">
<text class="price">{{ item.price }}</text>
<text class="m-price">{{ item.price }}</text>
</view>
<view class="pro-box">
<view class="progress-box"><progress percent="72" activeColor="#fa436a" active stroke-width="6" /></view>
<text>{{ item.maxPeople }}人成团</text>
</view>
</view>
</view>
</swiper-item>
</swiper>
</view>
</view>
</view>
</template>
<script>
import {goods} from '@/config/mixins.js'
export default {
filters:{
substr(val) {
if (val.length == 0 || val == undefined) {
return false;
} else if (val.length > 13) {
return val.substring(0, 13) + "...";
} else {
return val;
}
}
},
mixins: [goods],
name: "jshopgoods",
props: {
jdata:{
// type: Array,
required: true,
}
},
computed: {
count() {
return (this.jdata.options.colorGroup.length > 0)
}
},
methods: {
navToTabPage(url) {
uni.navigateTo({
url: url
});
},
//跳转到商品详情页面
goodsDetail: function(id) {
let url = '../../pagesA/product/product?id=' + id;
this.$common.navigateTo(url);
},
},
}
</script>
<style lang="scss">
.MP-search{
background: #FFFFFF;height: 80upx;display: flex;justify-content: center;align-items: center;position: fixed;width: 100%;z-index: 999;
}
.MP-search-input{
font-size: 28upx;background: #F5F5F5;height: 60upx;width: 90%;border-radius: 50upx;text-align: center;
}
.mp-search-box {
position: absolute;
left: 0;
top: 30upx;
z-index: 9999;
width: 100%;
padding: 0 80upx;
.ser-input {
flex: 1;
height: 60upx;
line-height: 60upx;
text-align: center;
font-size: 28upx;
color: $font-color-base;
border-radius: 20px;
background: rgba(255, 255, 255, 0.6);
}
}
page {
.cate-section {
position: relative;
z-index: 5;
border-radius: 16upx 16upx 0 0;
margin-top: -20upx;
}
.carousel-section {
padding: 0;
.titleNview-placing {
padding-top: 0;
height: 0;
}
.carousel {
.carousel-item {
padding: 0;
}
}
.swiper-dots {
left: 45upx;
bottom: 40upx;
}
}
}
page {
background: #f5f5f5;
}
.m-t {
margin-top: 20upx;
}
/* 头部 轮播图 */
.carousel-section {
position: relative;
padding-top: 10px;
.titleNview-placing {
height: var(--status-bar-height);
padding-top: 44px;
box-sizing: content-box;
}
.titleNview-background {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 426upx;
transition: 0.4s;
}
}
.carousel {
width: 100%;
height: 350upx;
.carousel-item {
width: 100%;
height: 100%;
padding: 0 28upx;
overflow: hidden;
}
image {
width: 100%;
height: 100%;
border-radius: 10upx;
}
}
.swiper-dots {
display: flex;
position: absolute;
left: 60upx;
bottom: 15upx;
width: 72upx;
height: 36upx;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAABkCAYAAADDhn8LAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTMyIDc5LjE1OTI4NCwgMjAxNi8wNC8xOS0xMzoxMzo0MCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OTk4MzlBNjE0NjU1MTFFOUExNjRFQ0I3RTQ0NEExQjMiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OTk4MzlBNjA0NjU1MTFFOUExNjRFQ0I3RTQ0NEExQjMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTcgKFdpbmRvd3MpIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6Q0E3RUNERkE0NjExMTFFOTg5NzI4MTM2Rjg0OUQwOEUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6Q0E3RUNERkI0NjExMTFFOTg5NzI4MTM2Rjg0OUQwOEUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4Gh5BPAAACTUlEQVR42uzcQW7jQAwFUdN306l1uWwNww5kqdsmm6/2MwtVCp8CosQtP9vg/2+/gY+DRAMBgqnjIp2PaCxCLLldpPARRIiFj1yBbMV+cHZh9PURRLQNhY8kgWyL/WDtwujjI8hoE8rKLqb5CDJaRMJHokC6yKgSCR9JAukmokIknCQJpLOIrJFwMsBJELFcKHwM9BFkLBMKFxNcBCHlQ+FhoocgpVwwnv0Xn30QBJGMC0QcaBVJiAMiec/dcwKuL4j1QMsVCXFAJE4s4NQA3K/8Y6DzO4g40P7UcmIBJxbEesCKWBDg8wWxHrAiFgT4fEGsB/CwIhYE+AeBAAdPLOcV8HRmWRDAiQVcO7GcV8CLM8uCAE4sQCDAlHcQ7x+ABQEEAggEEAggEEAggEAAgQACASAQQCCAQACBAAIBBAIIBBAIIBBAIABe4e9iAe/xd7EAJxYgEGDeO4j3EODp/cOCAE4sYMyJ5cwCHs4rCwI4sYBxJ5YzC84rCwKcXxArAuthQYDzC2JF0H49LAhwYUGsCFqvx5EF2T07dMaJBetx4cRyaqFtHJ8EIhK0i8OJBQxcECuCVutxJhCRoE0cZwMRyRcFefa/ffZBVPogePihhyCnbBhcfMFFEFM+DD4m+ghSlgmDkwlOgpAl4+BkkJMgZdk4+EgaSCcpVX7bmY9kgXQQU+1TgE0c+QJZUUz1b2T4SBbIKmJW+3iMj2SBVBWz+leVfCQLpIqYbp8b85EskIxyfIOfK5Sf+wiCRJEsllQ+oqEkQfBxmD8BBgA5hVjXyrBNUQAAAABJRU5ErkJggg==);
background-size: 100% 100%;
.num {
width: 36upx;
height: 36upx;
border-radius: 50px;
font-size: 24upx;
color: #fff;
text-align: center;
line-height: 36upx;
}
.sign {
position: absolute;
top: 0;
left: 50%;
line-height: 36upx;
font-size: 12upx;
color: #fff;
transform: translateX(-50%);
}
}
/* 分类 */
.cate-section {
display: flex;
justify-content: space-around;
align-items: center;
flex-wrap: wrap;
padding: 30upx 22upx;
background: #fff;
.cate-item {
display: flex;
flex-direction: column;
align-items: center;
font-size: $font-sm + 2upx;
color: $font-color-dark;
}
/* 原图标颜色太深,不想改图了,所以加了透明度 */
image {
width: 88upx;
height: 88upx;
margin-bottom: 14upx;
border-radius: 50%;
opacity: 0.7;
box-shadow: 4upx 4upx 20upx rgba(250, 67, 106, 0.3);
}
}
.ad-1 {
width: 100%;
height: 210upx;
padding: 10upx 0;
background: #fff;
image {
width: 100%;
height: 100%;
}
}
/* 秒杀专区 */
.seckill-section {
padding: 0upx 20upx 20upx;
background: #fff;
.s-header {
display: flex;
align-items: center;
height: 90upx;
line-height: 1;
.s-img {
width: 140upx;
height: 30upx;
}
.tip {
font-size: $font-base;
color: $font-color-light;
// margin: 0 20upx 0 40upx;
}
.timer {
display: inline-block;
width: 40upx;
height: 36upx;
text-align: center;
line-height: 36upx;
margin-right: 14upx;
font-size: $font-sm + 2upx;
color: #fff;
border-radius: 2px;
background: rgba(0, 0, 0, 0.8);
}
.icon-you {
font-size: $font-lg;
color: $font-color-light;
flex: 1;
text-align: right;
}
}
.floor-list {
white-space: nowrap;
}
.scoll-wrapper {
display: flex;
align-items: flex-start;
}
.floor-item {
width: 150upx;
margin-right: 20upx;
font-size: $font-sm + 2upx;
color: $font-color-dark;
line-height: 1.8;
image {
width: 150upx;
height: 150upx;
border-radius: 6upx;
}
.price {
color: $uni-color-primary;
}
}
}
.f-header {
display: flex;
align-items: center;
height: 140upx;
padding: 0upx 20upx;
background: #fff;
image {
flex-shrink: 0;
width: 80upx;
height: 80upx;
margin-right: 20upx;
}
.tit-box {
flex: 1;
display: flex;
flex-direction: column;
}
.tit {
font-size: $font-lg + 2upx;
color: #font-color-dark;
line-height: 1.3;
}
.tit2 {
font-size: $font-sm;
color: $font-color-light;
}
.icon-you {
font-size: $font-lg + 2upx;
color: $font-color-light;
}
}
/* 团购楼层 */
.group-section {
background: #fff;
.g-swiper {
height: 650upx;
padding-bottom: 20upx;
}
.g-swiper-item {
width: 100%;
padding: 0 20upx;
display: flex;
}
image {
width: 100%;
height: 460upx;
border-radius: 4px;
}
.g-item {
display: flex;
flex-direction: column;
overflow: hidden;
}
.left {
flex: 1.2;
// margin-right: 24upx;
.t-box {
padding-top: 20upx;
}
}
.right {
flex: 0.8;
flex-direction: column-reverse;
.t-box {
padding-bottom: 20upx;
}
}
.t-box {
height: 160upx;
font-size: $font-base + 2upx;
color: $font-color-dark;
line-height: 1.6;
}
.price {
color: $uni-color-primary;
}
.m-price {
font-size: $font-sm + 2upx;
text-decoration: line-through;
color: $font-color-light;
margin-left: 8upx;
}
.pro-box {
display: flex;
align-items: center;
margin-top: 10upx;
font-size: $font-sm;
color: $font-base;
padding-right: 10upx;
}
.progress-box {
flex: 1;
border-radius: 10px;
overflow: hidden;
margin-right: 8upx;
}
}
/* 分类推荐楼层 */
.hot-floor {
width: 100%;
overflow: hidden;
margin-bottom: 20upx;
.floor-img-box {
width: 100%;
height: 320upx;
position: relative;
&:after {
content: '';
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: linear-gradient(rgba(255, 255, 255, 0.06) 30%, #f8f8f8);
}
}
.floor-img {
width: 100%;
height: 100%;
}
.floor-list {
white-space: nowrap;
padding: 20upx;
padding-right: 50upx;
border-radius: 6upx;
margin-top: -140upx;
margin-left: 30upx;
background: #fff;
box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.2);
position: relative;
z-index: 1;
}
.scoll-wrapper {
display: flex;
align-items: flex-start;
}
.floor-item {
width: 180upx;
margin-right: 20upx;
font-size: $font-sm + 2upx;
color: $font-color-dark;
line-height: 1.8;
image {
width: 180upx;
height: 180upx;
border-radius: 6upx;
}
.price {
color: $uni-color-primary;
}
}
.more {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
flex-shrink: 0;
width: 180upx;
height: 180upx;
border-radius: 6upx;
background: #f3f3f3;
font-size: $font-base;
color: $font-color-light;
text:first-child {
margin-bottom: 4upx;
}
}
}
/* 单条商品 */
.goods-box-single {
display: flex;
padding: 20upx 0;
.goods-img {
display: block;
width: 120upx;
height: 120upx;
}
.right {
flex: 1;
display: flex;
flex-direction: column;
padding: 0 30upx 0 24upx;
overflow: hidden;
.title {
font-size: $font-base + 2upx;
color: $font-color-dark;
line-height: 1;
}
.attr-box {
font-size: $font-sm + 2upx;
color: $font-color-light;
padding: 10upx 12upx;
}
.price {
font-size: $font-base + 2upx;
color: $font-color-dark;
&:before {
content: '¥';
font-size: $font-sm;
margin: 0 2upx 0 8upx;
}
}
}
}
.price-box {
display: flex;
justify-content: flex-end;
align-items: baseline;
padding: 20upx 30upx;
font-size: $font-sm + 2upx;
color: $font-color-light;
.num {
margin: 0 8upx;
color: $font-color-dark;
}
.price {
font-size: $font-lg;
color: $font-color-dark;
&:before {
content: '¥';
font-size: $font-sm;
margin: 0 2upx 0 8upx;
}
}
}
.action-box {
display: flex;
justify-content: flex-end;
align-items: center;
height: 100upx;
position: relative;
padding-right: 30upx;
}
.action-btn {
width: 160upx;
height: 60upx;
margin: 0;
margin-left: 24upx;
padding: 0;
text-align: center;
line-height: 60upx;
font-size: $font-sm + 2upx;
color: $font-color-dark;
background: #fff;
border-radius: 100px;
&:after {
border-radius: 100px;
}
&.recom {
background: #fff9f9;
color: $base-color;
&:after {
border-color: #f7bcc8;
}
}
}
/* 猜你喜欢 */
.guess-section {
display: flex;
flex-wrap: wrap;
padding: 0 30upx;
background: #fff;
.guess-item {
display: flex;
flex-direction: column;
width: 48%;
padding-bottom: 40upx;
&:nth-child(2n + 1) {
margin-right: 4%;
}
}
.image-wrapper {
width: 100%;
height: 330upx;
border-radius: 3px;
overflow: hidden;
image {
width: 100%;
height: 100%;
opacity: 1;
}
}
.title {
font-size: $font-lg;
color: $font-color-dark;
line-height: 80upx;
}
.price {
font-size: $font-lg;
color: $uni-color-primary;
line-height: 1;
}
.coupon_box {
width:100%; height:auto; display:table; padding:6upx 26upx 26upx 26upx;
}
.other_type {
width:100%; height:90upx; padding-top:50upx;
.text { width:100%; border-top:1px solid #eeeeee; display:block; text-align:center; position:relative; }
.text span { width:180upx; height:40upx; line-height:40upx; color:#999999; display:block; background:#ffffff; position:absolute; left:50%; top:50%; margin-left:-90upx; margin-top:-20upx; font-size:$font-base; }
}
}
.getPosition{
height: 100upx;
display: flex;
justify-content: center;
align-items: center;
font-size: 32upx;
background-color: #FFF;
}
</style>

View File

@@ -0,0 +1,163 @@
<template>
<view class="">
<view class="jshop-tabbar bottom-cell-group" ref="tabBar">
<scroll-view scroll-x='true' class="tabbar-list">
<view class="tabbar-item" v-for="(item, index) in jdata.options.colorGroup" :key="index" @click="showSliderInfo(item.linkType, item.linkValue)">
{{item.text}}
<view class="active-tabbar"></view>
</view>
</scroll-view>
</view>
<!-- <view class="jshop-tabbar bottom-cell-group tabbar-fixed" v-show="tabbarFixed">
<scroll-view scroll-x='true' class="tabbar-list">
<view class="tabbar-item" v-for="(item, index) in jdata.options.colorGroup" :key="index" @click="showSliderInfo(item.linkType, item.linkValue)">
{{item.text}}
<view class="active-tabbar"></view>
</view>
</scroll-view>
</view> -->
</view>
</template>
<script>
export default {
name: "jshopTabbar",
props: {
jdata:{
// type: Object,
required: true,
}
},
data() {
return {
searchTop: 0,
scrollTop: 0,
tabbarFixed: false
};
},
created() {
//#ifdef H5
this.$nextTick(() => {
this.searchTop = this.$refs.tabBar.$el.offsetTop - 52;
})
// #endif
this.searchStyle()
},
mounted() {
// #ifdef H5
window.addEventListener('scroll', this.handleScroll)
// #endif
},
methods: {
searchStyle (){
this.$store.commit('searchStyle',this.jdata.params.style)
// console.log(this.data.params.style)
},
handleScroll() {
this.scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
this.scrollTop >= this.searchTop? this.tabbarFixed = true : this.tabbarFixed = false;
},
goClassify(){
uni.switchTab({
url: '/pages/classify/classify'
});
// this.$common.navigateTo('/pages/classify/classify')
},
showSliderInfo(type, val) {
console.log(val)
if (!val) {
return;
}
console.log("11")
if (type == 1) {
if (val.indexOf('http') != -1) {
// #ifdef H5
window.location.href = val
// #endif
} else {
// #ifdef H5 || APP-PLUS || APP-PLUS-NVUE || MP
if (val == '/pages/index/index' || val == '/pages/classify/classify' || val == '/pages/cart/index/index' || val == '/pages/member/index/index') {
uni.switchTab({
url: val
});
return;
} else {
this.$common.navigateTo(val);
return;
}
// #endif
}
} else if (type == 2) {
// 商品详情
this.goodsDetail(val)
} else if (type == 3) {
// 文章详情
this.$common.navigateTo('/pages/article/index?id=' + val + '&id_type=1')
} else if (type == 4) {
// console.log("11")
// 文章列表
this.$common.navigateTo('/pages/article/list?cid=' + val)
} else if (type == 5) {
//智能表单
this.$common.navigateTo('/pages/form/detail/form?id=' + val)
}
},
//跳转到商品详情页面
goodsDetail: function(id) {
let url = '/pages/goods/index/index?id=' + id;
this.$common.navigateTo(url);
},
},
onPageScroll(){
var _this = this;
// #ifdef MP-WEIXIN || APP-PLUS || APP-PLUS-NVUE
const query = uni.createSelectorQuery().in(this)
query.select('.search').boundingClientRect(function(res){
if(res.top<0){
_this.tabbarFixed = true ;
}else{
_this.tabbarFixed = false;
}
}).exec()
// #endif
}
}
</script>
<style>
.tabbar-list{
padding: 10rpx 0;
background-color: #fff;
white-space: nowrap;
width: 100%;
}
.tabbar-item{
display: inline-block;
padding: 10rpx 20rpx;
}
.tabbar-item:first-of-type{
color: #FF7159;
}
.active-tabbar{
display: none;
}
.tabbar-item:first-of-type .active-tabbar{
display: block;
width: 100%;
height: 4rpx;
margin: 10rpx auto 0;
background-color: #FF7159;
}
.tabbar-fixed{
position: fixed;
top: 104rpx;
transition: all .5s;
z-index: 999;
background-color: #fff;
width: 100%;
}
</style>

View File

@@ -0,0 +1,59 @@
<template>
<view class="clearfix">
<view class="textarea bottom-cell-group" >
<jshopContent :content="jdata.params" v-if="jdata.params"></jshopContent>
</view>
</view>
</template>
<script>
import htmlParser from '@/common/html-parser'
import jshopContent from '@/components/jshop/jshop-content.vue'//视频和文本解析组件
export default {
components: {
jshopContent
},
name: "jshoptextarea",
props: {
jdata:{
// type: Object,
required: true,
}
},
created() {
//this.jdata.params = htmlParser(this.jdata.params)
},
onLoad() {
},
methods: {
}
}
</script>
<style>
.textarea{
width: 100%;
background-color: #fff;
padding: 10upx 26upx;
/* height: 40upx; */
}
.textarea p img{
width: 100% !important;
}
.textarea div{
background-color: #000;
}
.textarea p {
background-color: #000;
}
.clearfix:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
</style>

View File

@@ -0,0 +1,30 @@
<template>
<view class="video bottom-cell-group" >
<video :src="jdata.options.video_link" :poster="jdata.options.video_img" controls></video>
</view>
</template>
<script>
export default {
name: "jshopvideo",
props: {
jdata:{
type: Object,
required: true,
}
},
onLoad(){
},
methods: {
}
}
</script>
<style>
.video video{
width: 100%;
min-height: 200upx;
}
</style>

View File

@@ -0,0 +1,88 @@
<template>
<view>
<block v-for="(item,index) in jdata" :key="index">
<jshopsearch :jdata="item" v-if="item.components=='search' "></jshopsearch>
<jshoptabbar :jdata="item" v-if="item.components=='tabBar' "></jshoptabbar>
<jshopnotice :jdata="item" v-if="item.components=='notice' "></jshopnotice>
<jshopimgSlide :jdata="item" v-if="item.components=='banner' "></jshopimgSlide>
<jshopcoupon :jdata="item" v-if="item.components=='coupon' "></jshopcoupon>
<jshopblank :jdata="item" v-if="item.components=='blank' "></jshopblank>
<jshoptextarea :jdata="item" v-if="item.components=='textarea' "></jshoptextarea>
<jshopvideo :jdata="item" v-if="item.components=='video' "></jshopvideo>
<jshopimgWindow :jdata="item" v-if="item.components=='imgWin' "></jshopimgWindow>
<jshopimgSingle :jdata="item" v-if="item.components=='imgImgSlide' "></jshopimgSingle>
<jshopgoods :jdata="item" v-if="item.components=='shuanglieshangpin' "></jshopgoods>
<jshopslidegoods :jdata="item" v-if="item.components=='danlieshangpin' "></jshopslidegoods>
<jshoparticle :jdata="item" v-if="item.components=='article' "></jshoparticle>
<jshoparticleClassify :jdata="item" v-if="item.components=='articleClassify' "></jshoparticleClassify>
<jshopnavBar :jdata="item" v-if="item.components=='xuanxiangqia' "></jshopnavBar>
<jshopgroupPurchase :jdata="item" v-if="item.components=='groupPurchase' "></jshopgroupPurchase>
<jshoprecord :jdata="item" v-if="item.components=='record' "></jshoprecord>
<jshoppintuan :jdata="item" v-if="item.components=='pintuan' "></jshoppintuan>
<jshopadpop :jdata="item" v-if="item.components=='imgGroup' "></jshopadpop>
</block>
</view>
</template>
<script>
/**
* 吉海科技jshop小程序插件集合。
* author:novice
* date:2019:05:20
*/
import uniCountdown from '@/components/uni-countdown/uni-countdown.vue'
import jshopimgSlide from '@/components/jshop/jshop-imgSlide.vue'
import jshopsearch from '@/components/jshop/jshop-search.vue'
import jshopnotice from '@/components/jshop/jshop-notice.vue'
import jshopcoupon from '@/components/jshop/jshop-coupon.vue'
import jshopblank from '@/components/jshop/jshop-blank.vue'
import jshoptextarea from '@/components/jshop/jshop-textarea.vue'
import jshopvideo from '@/components/jshop/jshop-video.vue'
import jshopimgWindow from '@/components/jshop/jshop-imgWindow.vue'
import jshopimgSingle from '@/components/jshop/jshop-imgSingle.vue'
import jshopgoods from '@/components/jshop/jshop-goods.vue'
import jshoponegoods from '@/components/jshop/jshop-onegoods.vue'
import jshopslidegoods from '@/components/jshop/jshop-slidegoods.vue'
import jshoparticle from '@/components/jshop/jshop-article.vue'
import jshoparticleClassify from '@/components/jshop/jshop-articleClassify.vue'
import jshopnavBar from '@/components/jshop/jshop-navBar.vue'
import jshopgroupPurchase from '@/components/jshop/jshop-groupPurchase.vue'
import jshoprecord from '@/components/jshop/jshop-record.vue'
import jshoppintuan from '@/components/jshop/jshop-pintuan.vue'
import jshoptabbar from '@/components/jshop/jshop-tabbar.vue'
import jshopadpop from '@/components/jshop/jshop-adpop.vue'
export default {
name: 'jshop',
components: {
jshopimgSlide,
jshopsearch,
jshopnotice,
jshoponegoods,
jshopslidegoods,
jshopcoupon,
jshopblank,
jshoptextarea,
jshopvideo,
jshopimgWindow,
jshopimgSingle,
jshopgoods,
jshoparticle,
jshoparticleClassify,
jshopnavBar,
jshopgroupPurchase,
jshoprecord,
jshoppintuan,
jshoptabbar,
jshopadpop
},
props: {
jdata: {
default: function() {
return []
}
}
}
}
</script>

View File

@@ -0,0 +1,284 @@
<template>
<view class="index-goods">
<!-- 列表平铺两列三列 -->
<view class='img-grids bottom-cell-group'
v-if="jdata.params.column == '2' && jdata.params.display == 'list' || jdata.params.column == '3' && jdata.params.display == 'list'"
v-bind:class="'column'+jdata.params.column">
<view class='cell-item right-img' v-if="jdata.params.title != ''">
<view class='cell-item-hd'>
<view class='cell-hd-title'>{{jdata.params.title}}</view>
</view>
<view class='cell-item-bd'>
</view>
<view class='cell-item-ft' v-if="jdata.params.lookMore == 'true'">
<text class='cell-ft-text' @click="goodsList({cat_id: jdata.params.classifyId,brand_id:jdata.params.brandId})">查看更多</text>
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
<!-- <view class='img-grids'> -->
<view class="" v-if="count">
<view class="img-grids-item" v-for="item in jdata.params.list" :key="item.id" @click="goodsDetail(item.id)">
<image
class="img-grids-item-t have-none"
:src="item.image_url"
mode='aspectFill'
></image>
<view class="img-grids-item-b">
<view class="goods-name grids-goods-name">
{{item.name}}
</view>
<view class="goods-item-c">
<view class="goods-price red-price">¥{{item.price}}</view>
</view>
</view>
</view>
</view>
<view v-else-if="!count && !jdata.params.listAjax">
<view class='img-grids-item'>
<image class='img-grids-item-t have-none' src='' mode=''></image>
<view class='img-grids-item-b'>
<view class='goods-name grids-goods-name have-none'></view>
<view class='goods-item-c'>
<view class='goods-price red-price have-none'></view>
</view>
</view>
</view>
<view class='img-grids-item'>
<image class='img-grids-item-t have-none' src='' mode=''></image>
<view class='img-grids-item-b'>
<view class='goods-name grids-goods-name have-none'></view>
<view class='goods-item-c'>
<view class='goods-price red-price have-none'></view>
</view>
</view>
</view>
<view class='img-grids-item'>
<image class='img-grids-item-t have-none' src='' mode=''></image>
<view class='img-grids-item-b'>
<view class='goods-name grids-goods-name have-none'></view>
<view class='goods-item-c'>
<view class='goods-price red-price have-none'></view>
</view>
</view>
</view>
</view>
<!-- <view v-else="">
<scroll-view class='swiper-list' scroll-x="true"></scroll-view>
</view> -->
<!-- </view> -->
</view>
<!-- 列表平铺单列 -->
<view class="img-list bottom-cell-group"
v-if="jdata.params.column == '1' && jdata.params.display == 'list'" >
<view class='cell-item right-img' v-if="jdata.params.title != ''">
<view class='cell-item-hd'>
<view class='cell-hd-title'>{{jdata.params.title}}</view>
</view>
<view class='cell-item-bd'>
</view>
<view class='cell-item-ft' v-if="jdata.params.lookMore == 'true'">
<text class='cell-ft-text' @click="goodsList({cat_id: jdata.params.classifyId,brand_id:jdata.params.brandId})">查看更多</text>
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
<view v-if="count">
<view class="img-list-item" v-for="(item, index) in jdata.params.list" :key="index" @click="goodsDetail(item.id)">
<image class="img-list-item-l have-none" :src="item.image_url" mode='aspectFill'></image>
<view class="img-list-item-r">
<view class="goods-name list-goods-name">
{{item.name}}
</view>
<view class="goods-item-c">
<view class="goods-price red-price">¥{{item.price}}</view>
<view class="goods-buy">
<view class="goods-salesvolume" v-if="item.comments_count > 0">{{item.comments_count}}条评论</view>
<view class="goods-salesvolume" v-else-if="item.comments_count <= 0">暂无评论</view>
<image class="goods-cart" src="/static/image/ic-car.png"></image>
</view>
</view>
</view>
</view>
</view>
<view class="order-none" v-else>
<image class="order-none-img" src="/static/image/order.png" mode=""></image>
</view>
</view>
<!-- 横向滚动 -->
<view class='img-grids bottom-cell-group'
v-if="jdata.params.column == '2' && jdata.params.display == 'slide' || jdata.params.column == '3' && jdata.params.display == 'slide'"
v-bind:class="'slide'+jdata.params.column">
<view class='cell-item right-img' v-if="jdata.params.title != ''">
<view class='cell-item-hd'>
<view class='cell-hd-title'>{{jdata.params.title}}</view>
</view>
<view class='cell-item-bd'>
</view>
<view class='cell-item-ft' v-if="jdata.params.lookMore == 'true'">
<text class='cell-ft-text' @click="goodsList({cat_id: jdata.params.classifyId,brand_id:jdata.params.brandId})">查看更多</text>
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
<view class='swiper-grids'>
<scroll-view class='swiper-list' scroll-x="true" v-if="count">
<view class='img-grids-item' v-for="item in jdata.params.list" :key="item.id" @click="goodsDetail(item.id)">
<image class='img-grids-item-t have-none' :src='item.image_url' mode='aspectFill'></image>
<view class='img-grids-item-b'>
<view class='goods-name grids-goods-name' >
{{ item.name|substr }}
</view>
<view class='goods-item-c'>
<view class='goods-price red-price'>¥{{ item.price }}</view>
</view>
</view>
</view>
</scroll-view>
<view v-else-if="!goodsListOfHotAjax && !goodsListOfHot.length">
<scroll-view class='swiper-list' scroll-x="true">
<view class='img-grids-item'>
<image class='img-grids-item-t have-none' src='' mode='aspectFill'></image>
<view class='img-grids-item-b'>
<view class='goods-name grids-goods-name have-none'></view>
<view class='goods-item-c'>
<view class='goods-price red-price have-none'></view>
</view>
</view>
</view>
<view class='img-grids-item'>
<image class='img-grids-item-t have-none' src='' mode='aspectFill'></image>
<view class='img-grids-item-b'>
<view class='goods-name grids-goods-name have-none'></view>
<view class='goods-item-c'>
<view class='goods-price red-price have-none'></view>
</view>
</view>
</view>
<view class='img-grids-item'>
<image class='img-grids-item-t have-none' src='' mode=''></image>
<view class='img-grids-item-b'>
<view class='goods-name grids-goods-name have-none'></view>
<view class='goods-item-c'>
<view class='goods-price red-price have-none'></view>
</view>
</view>
</view>
</scroll-view>
</view>
<view v-else="">
<scroll-view class='swiper-list' scroll-x="true"></scroll-view>
</view>
</view>
</view>
</view>
</template>
<script>
import {goods} from '@/config/mixins.js'
export default {
filters:{
substr(val) {
if (val.length == 0 || val == undefined) {
return false;
} else if (val.length > 13) {
return val.substring(0, 13) + "...";
} else {
return val;
}
}
},
mixins: [goods],
name: "jshopgoods",
props: {
jdata:{
// type: Array,
required: true,
}
},
computed: {
count() {
return (this.jdata.params.list.length > 0)
}
},
methods: {
//跳转到商品详情页面
goodsDetail: function(id) {
let url = '/pages/goods/index/index?id=' + id;
this.$common.navigateTo(url);
},
},
}
</script>
<style>
.cell-item {
border: none;
/* padding-bottom: 0; */
}
.cell-ft-text {
font-size: 22upx;
color: #999;
}
.img-grids,.img-list{
/* margin-top: 20upx; */
background-color: #fff;
}
.img-grids-item{
display: inline-table;
margin-top: 0;
margin-bottom: 14upx;
}
.column3 .img-grids-item{
width: 230upx;
height: 364rpx !important;
margin: 15upx;
margin-right: 0;
margin-top: 0;
margin-bottom: 6upx;
}
.column3 .img-grids-item:nth-child(3n){
margin-right: 15upx;
}
.column3 .img-grids-item-t{
width: 230upx;
height: 230upx;
}
.column3 .grids-goods-name{
font-size: 24upx;
/* height: 68upx; */
/* min-height: 54rpx; */
}
.column3 .img-grids-item-b{
padding: 0 8upx 8upx;
}
.column3 .goods-price{
font-size: 26upx;
}
.slide3 .img-grids-item{
width: 200upx;
}
.slide3 .img-grids-item-t{
width: 200upx;
height: 200upx;
}
.slide3 .grids-goods-name{
font-size: 24rpx;
height: 66rpx;
}
.index-goods .img-grids-item{
display: inline-block;
margin-top: 0;
}
.index-goods .img-list-item{
padding: 0upx 26upx;
margin-bottom: 14upx;
}
.index-goods .img-list{
padding-bottom: 10upx;
}
</style>

View File

@@ -0,0 +1,32 @@
<template>
<view class="cpr">
<view class="color-9">
{{sysInfo.company}} © {{sysInfo.subdomain}} 版权所有
</view>
<view class="color-9 beian">
<view v-if="sysInfo.code"><a href="http://www.beian.miit.gov.cn/publish/query/indexFirst.action" target="_blank">冀ICP备10002647号-11</a></view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
sysInfo : this.$db.get('sysInfo')
}
}
}
</script>
<style>
.cpr{
text-align: center;
font-size: 24upx;
margin: 20upx 0;
}
.beian a{
text-decoration: none;
color: #999 !important;
}
</style>

View File

@@ -0,0 +1,223 @@
<template>
<view class="serach">
<view class="content" :style="{'border-radius':radius+'px'}">
<!-- HM修改 增加进入输入状态的点击范围 -->
<view class="content-box" :class="{'center':mode === 2}" @click="getFocus">
<text class="icon icon-serach"></text>
<!-- HM修改 增加placeholder input confirm-type confirm-->
<input :placeholder="placeholder" @input="inputChange" confirm-type="search" @confirm="triggerConfirm" class="input" :class="{'center':!active && mode === 2}" :focus="isFocus" v-model="inputVal" @focus="focus" @blur="blur"/>
<!-- <view v-if="!active && mode === 2" class="input sub" @click="getFocus">请输入搜索内容</view> -->
<!-- HM修改 @click换成@click.stop阻止冒泡 -->
<text v-if="isDelShow" class="icon icon-del" @click.stop="clear"></text>
</view>
<view v-show="(active&&show&&button === 'inside')||(isDelShow && button === 'inside')" class="serachBtn" @click="search">
搜索
</view>
</view>
<view v-if="button === 'outside'" class="button" :class="{'active':show||active}" @click="search">
<view class="button-item">{{!show?searchName:'搜索'}}</view>
</view>
</view>
</template>
<script>
export default {
props: {
mode: {
value: Number,
default: 1
},
//HM修改 定义默认搜索关键词(水印文字)
placeholder:{
value: String,
default: '请输入搜索内容'
},
value: {
type: String,
default:false
},
button: {
value: String,
default: 'outside'
},
show: {
value: Boolean,
default: true
},
radius: {
value: String,
default: 60
}
},
data() {
return {
active: false,
inputVal: '',
searchName: '取消',
isDelShow: false,
isFocus: false
};
},
methods: {
//HM修改 触发组件confirm事件
triggerConfirm(){
this.$emit('confirm', false);
},
//HM修改 触发组件input事件
inputChange(event){
var keyword = event.detail.value;
this.$emit('input', keyword);
if (this.inputVal) {
this.isDelShow = true;
}
},
focus() {
this.active = true;
//HM修改 增加获取焦点判断
if (this.inputVal) {
this.isDelShow = true;
}
},
blur() {
this.isFocus = false;
if (!this.inputVal) {
this.active = false;
}
},
clear() {
//HM修改 收起键盘
uni.hideKeyboard();
this.isFocus = false;
this.inputVal = '';
this.active = false;
//HM修改 清空内容时候触发组件input
this.$emit('input', '');
//this.$emit('search', '');//HM修改 清空内容时候不进行搜索
},
getFocus() {
this.isFocus = true;
},
search() {
//HM修改 增加点击取消时候退出输入状态,内容为空时,输入默认关键字
if (!this.inputVal) {
if(!this.show&&this.searchName == '取消'){
uni.hideKeyboard();
this.isFocus = false;
this.active = false;
return;
}
}
console.log(this.inputVal);
this.$emit('search', this.inputVal?this.inputVal:this.placeholder);
}
},
watch: {
inputVal(newVal) {
if (newVal) {
this.searchName = '搜索';
//this.isDelShow = true; //HM修改 直接点击页面预设关键字样式异常,注销
} else {
this.searchName = '取消';
this.isDelShow = false;
}
},
//HM修改 双向绑定
value(val) {
this.inputVal = val;
},
}
};
</script>
<style lang="scss">
.serach {
display: flex;
width: 100%;
//border-bottom: 1px #f5f5f5 solid; //HM修改 去掉边框
box-sizing: border-box;
font-size: $uni-font-size-base;
.content {
display: flex;
align-items: center;
width: 100%;
height: 60upx;
//border: 1px #ccc solid; //HM修改 去掉边框
background: #fff;
overflow: hidden;
transition: all 0.2s linear;
border-radius: 30px;
.content-box {
width: 100%;
display: flex;
align-items: center;
&.center {
justify-content: center;
}
.icon {
padding: 0 15upx;
&.icon-del {
font-size: 38upx;
&:before {content:"\e644";}
}
&.icon-serach:before {content:"\e61c";}
}
.input {
width: 100%;
max-width: 100%;
line-height: 60upx;
height: 60upx;
transition: all 0.2s linear;
&.center {
width: 200upx;
}
&.sub {
// position: absolute;
width: auto;
color: grey;
}
}
}
.serachBtn {
height: 100%;
flex-shrink: 0;
padding: 0 30upx;
//HM修改 按钮背景色
background:linear-gradient(to right,#ff9801,#ff570a);
//background: $uni-color-success;
line-height: 60upx;
color: #fff;
//border-left: 1px #ccc solid; //HM修改 去掉边框
transition: all 0.3s;
}
}
.button {
display: flex;
align-items: center;
justify-content: center;
position: relative;
flex-shrink: 0;
width: 0;
transition: all 0.2s linear;
white-space: nowrap;
overflow: hidden;
&.active {
padding-left: 15upx;
width: 100upx;
}
}
}
//HM修改 把字体改成本地加载
@font-face {font-family:"iconfont";src:url('data:application/x-font-woff;charset=utf-8;base64,AAEAAAALAIAAAwAwR1NVQrD+s+0AAAE4AAAAQk9TLzI8fEg3AAABfAAAAFZjbWFws6gbWQAAAeQAAAGcZ2x5ZqgAaogAAAOMAAABMGhlYWQTyEk0AAAA4AAAADZoaGVhB90DhQAAALwAAAAkaG10eBAA//8AAAHUAAAAEGxvY2EA0gBOAAADgAAAAAptYXhwARIANgAAARgAAAAgbmFtZT5U/n0AAAS8AAACbXBvc3SanfjSAAAHLAAAAEUAAQAAA4D/gABcBAD//wAABAAAAQAAAAAAAAAAAAAAAAAAAAQAAQAAAAEAAL8Cm/NfDzz1AAsEAAAAAADYVQKbAAAAANhVApv///+ABAADgQAAAAgAAgAAAAAAAAABAAAABAAqAAQAAAAAAAIAAAAKAAoAAAD/AAAAAAAAAAEAAAAKAB4ALAABREZMVAAIAAQAAAAAAAAAAQAAAAFsaWdhAAgAAAABAAAAAQAEAAQAAAABAAgAAQAGAAAAAQAAAAAAAQQAAZAABQAIAokCzAAAAI8CiQLMAAAB6wAyAQgAAAIABQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUGZFZABA5gbmRAOA/4AAXAOBAIAAAAABAAAAAAAABAAAAAQA//8EAAAABAAAAAAAAAUAAAADAAAALAAAAAQAAAFoAAEAAAAAAGIAAwABAAAALAADAAoAAAFoAAQANgAAAAgACAACAADmBuYc5kT//wAA5gbmHOZE//8AAAAAAAAAAQAIAAgACAAAAAIAAQADAAABBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAA0AAAAAAAAAAMAAOYGAADmBgAAAAIAAOYcAADmHAAAAAEAAOZEAADmRAAAAAMAAAAAADoATgCYAAAAAv///4AEAAOAABMAHwAABQYiLwEGJCcmAjc2JBcWEgcXFhQBJiAHBhQXFiA3NjQD7RQyFMaG/sl9hw2BiQFqjXgTZccT/sBo/spoPz9oATZoPm0TE8dhDG6FAW2OhwaGfv6+h8YUMgLThoZV0FWGhlnMAAABAAD/gAMAA4EABQAACQE1CQE1AQACAP6IAXgBgP4AiAF4AXiIAAAABAAA//4DlAMnABAAIQAlACkAAAUuAzQ+AjIWFxYQBw4BAyIOAhQeAjI2NzYQJy4BFwEnAQU3AQcCAFKScz09c5Kkkjp2djqSUkiBZjU1ZoGQgTNoaDOBfP6YIAFo/qQgAVwgAgE9cpOjknM9PTl8/r18OT0C9zVmgZCBZTU1Mm4BHW0zNb/+mCABZysf/qQgAAAAAAAAEgDeAAEAAAAAAAAAFQAAAAEAAAAAAAEACAAVAAEAAAAAAAIABwAdAAEAAAAAAAMACAAkAAEAAAAAAAQACAAsAAEAAAAAAAUACwA0AAEAAAAAAAYACAA/AAEAAAAAAAoAKwBHAAEAAAAAAAsAEwByAAMAAQQJAAAAKgCFAAMAAQQJAAEAEACvAAMAAQQJAAIADgC/AAMAAQQJAAMAEADNAAMAAQQJAAQAEADdAAMAAQQJAAUAFgDtAAMAAQQJAAYAEAEDAAMAAQQJAAoAVgETAAMAAQQJAAsAJgFpCkNyZWF0ZWQgYnkgaWNvbmZvbnQKaWNvbmZvbnRSZWd1bGFyaWNvbmZvbnRpY29uZm9udFZlcnNpb24gMS4waWNvbmZvbnRHZW5lcmF0ZWQgYnkgc3ZnMnR0ZiBmcm9tIEZvbnRlbGxvIHByb2plY3QuaHR0cDovL2ZvbnRlbGxvLmNvbQAKAEMAcgBlAGEAdABlAGQAIABiAHkAIABpAGMAbwBuAGYAbwBuAHQACgBpAGMAbwBuAGYAbwBuAHQAUgBlAGcAdQBsAGEAcgBpAGMAbwBuAGYAbwBuAHQAaQBjAG8AbgBmAG8AbgB0AFYAZQByAHMAaQBvAG4AIAAxAC4AMABpAGMAbwBuAGYAbwBuAHQARwBlAG4AZQByAGEAdABlAGQAIABiAHkAIABzAHYAZwAyAHQAdABmACAAZgByAG8AbQAgAEYAbwBuAHQAZQBsAGwAbwAgAHAAcgBvAGoAZQBjAHQALgBoAHQAdABwADoALwAvAGYAbwBuAHQAZQBsAGwAbwAuAGMAbwBtAAAAAAIAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAECAQMBBAEFAAZzb3VzdW8IamlhbnRvdTQHc2hhbmNodQAAAAAA');}
.icon {
font-family: iconfont;
font-size: 32upx;
font-style: normal;
color: #999;
}
</style>

View File

@@ -0,0 +1,119 @@
<template>
<view class="content">
<view class="mix-list-cell" :class="border" @click="eventClick" hover-class="cell-hover" :hover-stay-time="50">
<text
v-if="icon"
class="cell-icon yticon"
:style="[{
color: iconColor,
}]"
:class="icon"
></text>
<text class="cell-tit clamp">{{title}}</text>
<text v-if="tips" class="cell-tip">{{tips}}</text>
<text class="cell-more yticon"
:class="typeList[navigateType]"
></text>
</view>
</view>
</template>
<script>
/**
* 简单封装了下, 应用范围比较狭窄,可以在此基础上进行扩展使用
* 比如加入image iconSize可控等
*/
export default {
data() {
return {
typeList: {
left: 'icon-zuo',
right: 'icon-you',
up: 'icon-shang',
down: 'icon-xia'
},
}
},
props: {
icon: {
type: String,
default: ''
},
title: {
type: String,
default: '标题'
},
tips: {
type: String,
default: ''
},
navigateType: {
type: String,
default: 'right'
},
border: {
type: String,
default: 'b-b'
},
hoverClass: {
type: String,
default: 'cell-hover'
},
iconColor: {
type: String,
default: '#333'
}
},
methods: {
eventClick(){
this.$emit('eventClick');
}
},
}
</script>
<style lang='scss'>
.icon .mix-list-cell.b-b:after{
left: 90upx;
}
.mix-list-cell{
display:flex;
align-items:baseline;
padding: 20upx $page-row-spacing;
line-height:60upx;
position:relative;
&.cell-hover{
background:#fafafa;
}
&.b-b:after{
left: 30upx;
}
.cell-icon{
align-self:center;
width:56upx;
max-height:60upx;
font-size:38upx;
}
.cell-more{
align-self: center;
font-size:30upx;
color:$font-color-base;
margin-left:$uni-spacing-row-sm;
}
.cell-tit{
flex: 1;
font-size: $font-base;
color: $font-color-dark;
margin-right:10upx;
}
.cell-tip{
font-size: $font-sm+2upx;
color: $font-color-light;
}
}
</style>

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,139 @@
/* eslint-disable */
var provinceData = [{
"label": "北京市",
"value": "11"
},
{
"label": "天津市",
"value": "12"
},
{
"label": "河北省",
"value": "13"
},
{
"label": "山西省",
"value": "14"
},
{
"label": "内蒙古自治区",
"value": "15"
},
{
"label": "辽宁省",
"value": "21"
},
{
"label": "吉林省",
"value": "22"
},
{
"label": "黑龙江省",
"value": "23"
},
{
"label": "上海市",
"value": "31"
},
{
"label": "江苏省",
"value": "32"
},
{
"label": "浙江省",
"value": "33"
},
{
"label": "安徽省",
"value": "34"
},
{
"label": "福建省",
"value": "35"
},
{
"label": "江西省",
"value": "36"
},
{
"label": "山东省",
"value": "37"
},
{
"label": "河南省",
"value": "41"
},
{
"label": "湖北省",
"value": "42"
},
{
"label": "湖南省",
"value": "43"
},
{
"label": "广东省",
"value": "44"
},
{
"label": "广西壮族自治区",
"value": "45"
},
{
"label": "海南省",
"value": "46"
},
{
"label": "重庆市",
"value": "50"
},
{
"label": "四川省",
"value": "51"
},
{
"label": "贵州省",
"value": "52"
},
{
"label": "云南省",
"value": "53"
},
{
"label": "西藏自治区",
"value": "54"
},
{
"label": "陕西省",
"value": "61"
},
{
"label": "甘肃省",
"value": "62"
},
{
"label": "青海省",
"value": "63"
},
{
"label": "宁夏回族自治区",
"value": "64"
},
{
"label": "新疆维吾尔自治区",
"value": "65"
},
{
"label": "台湾",
"value": "66"
},
{
"label": "香港",
"value": "67"
},
{
"label": "澳门",
"value": "68"
}
]
export default provinceData;

View File

@@ -0,0 +1,210 @@
<template>
<div class="mpvue-picker">
<div :class="{'pickerMask':showPicker}" @click="maskClick" catchtouchmove="true"></div>
<div class="mpvue-picker-content " :class="{'mpvue-picker-view-show':showPicker}">
<div class="mpvue-picker__hd" catchtouchmove="true">
<div class="mpvue-picker__action" @click="pickerCancel">取消</div>
<div class="mpvue-picker__action" :style="{color:themeColor}" @click="pickerConfirm">确定</div>
</div>
<picker-view indicator-style="height: 40px;" class="mpvue-picker-view" :value="pickerValue" @change="pickerChange">
<block>
<picker-view-column>
<div class="picker-item" v-for="(item,index) in provinceDataList" :key="index">{{item.label}}</div>
</picker-view-column>
<picker-view-column>
<div class="picker-item" v-for="(item,index) in cityDataList" :key="index">{{item.label}}</div>
</picker-view-column>
<picker-view-column>
<div class="picker-item" v-for="(item,index) in areaDataList" :key="index">{{item.label}}</div>
</picker-view-column>
</block>
</picker-view>
</div>
</div>
</template>
<script>
import provinceData from './city-data/province.js';
import cityData from './city-data/city.js';
import areaData from './city-data/area.js';
export default {
data() {
return {
pickerValue: [0, 0, 0],
provinceDataList: [],
cityDataList: [],
areaDataList: [],
/* 是否显示控件 */
showPicker: false,
};
},
created() {
this.init()
},
props: {
/* 默认值 */
pickerValueDefault: {
type: Array,
default(){
return [0, 0, 0]
}
},
/* 主题色 */
themeColor: String
},
watch:{
pickerValueDefault(){
this.init();
}
},
methods: {
init() {
this.handPickValueDefault(); // 对 pickerValueDefault 做兼容处理
this.provinceDataList = provinceData;
this.cityDataList = cityData[this.pickerValueDefault[0]];
this.areaDataList = areaData[this.pickerValueDefault[0]][this.pickerValueDefault[1]];
this.pickerValue = this.pickerValueDefault;
},
show() {
setTimeout(() => {
this.showPicker = true;
}, 0);
},
maskClick() {
this.pickerCancel();
},
pickerCancel() {
this.showPicker = false;
this._$emit('onCancel');
},
pickerConfirm(e) {
this.showPicker = false;
this._$emit('onConfirm');
},
showPickerView() {
this.showPicker = true;
},
handPickValueDefault() {
if (this.pickerValueDefault !== [0, 0, 0]) {
if (this.pickerValueDefault[0] > provinceData.length - 1) {
this.pickerValueDefault[0] = provinceData.length - 1;
}
if (this.pickerValueDefault[1] > cityData[this.pickerValueDefault[0]].length - 1) {
this.pickerValueDefault[1] = cityData[this.pickerValueDefault[0]].length - 1;
}
if (this.pickerValueDefault[2] > areaData[this.pickerValueDefault[0]][this.pickerValueDefault[1]].length - 1) {
this.pickerValueDefault[2] = areaData[this.pickerValueDefault[0]][this.pickerValueDefault[1]].length - 1;
}
}
},
pickerChange(e) {
let changePickerValue = e.mp.detail.value;
if (this.pickerValue[0] !== changePickerValue[0]) {
// 第一级发生滚动
this.cityDataList = cityData[changePickerValue[0]];
this.areaDataList = areaData[changePickerValue[0]][0];
changePickerValue[1] = 0;
changePickerValue[2] = 0;
} else if (this.pickerValue[1] !== changePickerValue[1]) {
// 第二级滚动
this.areaDataList =
areaData[changePickerValue[0]][changePickerValue[1]];
changePickerValue[2] = 0;
}
this.pickerValue = changePickerValue;
this._$emit('onChange');
},
_$emit(emitName) {
let pickObj = {
label: this._getLabel(),
value: this.pickerValue,
cityCode: this._getCityCode()
};
this.$emit(emitName, pickObj);
},
_getLabel() {
let pcikerLabel =
this.provinceDataList[this.pickerValue[0]].label +
'-' +
this.cityDataList[this.pickerValue[1]].label +
'-' +
this.areaDataList[this.pickerValue[2]].label;
return pcikerLabel;
},
_getCityCode() {
return this.areaDataList[this.pickerValue[2]].value;
}
}
};
</script>
<style>
.pickerMask {
position: fixed;
z-index: 1000;
top: 0;
right: 0;
left: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
}
.mpvue-picker-content {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
transition: all 0.3s ease;
transform: translateY(100%);
z-index: 3000;
}
.mpvue-picker-view-show {
transform: translateY(0);
}
.mpvue-picker__hd {
display: flex;
padding: 9px 15px;
background-color: #fff;
position: relative;
text-align: center;
font-size: 17px;
}
.mpvue-picker__hd:after {
content: ' ';
position: absolute;
left: 0;
bottom: 0;
right: 0;
height: 1px;
border-bottom: 1px solid #e5e5e5;
color: #e5e5e5;
transform-origin: 0 100%;
transform: scaleY(0.5);
}
.mpvue-picker__action {
display: block;
flex: 1;
color: #1aad19;
}
.mpvue-picker__action:first-child {
text-align: left;
color: #888;
}
.mpvue-picker__action:last-child {
text-align: right;
}
.picker-item {
text-align: center;
line-height: 40px;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 16px;
}
.mpvue-picker-view {
position: relative;
bottom: 0;
left: 0;
width: 100%;
height: 238px;
background-color: rgba(255, 255, 255, 1);
}
</style>

View File

@@ -0,0 +1,463 @@
<template>
<view class="mpvue-picker">
<view :class="{'pickerMask':showPicker}" @click="maskClick" catchtouchmove="true"></view>
<view class="mpvue-picker-content " :class="{'mpvue-picker-view-show':showPicker}">
<view class="mpvue-picker__hd" catchtouchmove="true">
<view class="mpvue-picker__action" @click="pickerCancel">取消</view>
<view class="mpvue-picker__action" :style="{color:themeColor}" @click="pickerConfirm">确定</view>
</view>
<!-- 单列 -->
<picker-view indicator-style="height: 40px;" class="mpvue-picker-view" :value="pickerValue" @change="pickerChange" v-if="mode==='selector' && pickerValueSingleArray.length > 0">
<block>
<picker-view-column>
<view class="picker-item" v-for="(item,index) in pickerValueSingleArray" :key="index">{{item.label}}</view>
</picker-view-column>
</block>
</picker-view>
<!-- 时间选择器 -->
<picker-view indicator-style="height: 40px;" class="mpvue-picker-view" :value="pickerValue" @change="pickerChange" v-if="mode==='timeSelector'">
<block>
<picker-view-column>
<view class="picker-item" v-for="(item,index) in pickerValueHour" :key="index">{{item.label}}</view>
</picker-view-column>
<picker-view-column>
<view class="picker-item" v-for="(item,index) in pickerValueMinute" :key="index">{{item.label}}</view>
</picker-view-column>
</block>
</picker-view>
<!-- 多列选择 -->
<picker-view indicator-style="height: 40px;" class="mpvue-picker-view" :value="pickerValue" @change="pickerChange" v-if="mode==='multiSelector'">
<block v-for="(n,index) in pickerValueMulArray.length" :key="index">
<picker-view-column>
<view class="picker-item" v-for="(item,index1) in pickerValueMulArray[n]" :key="index1">{{item.label}}</view>
</picker-view-column>
</block>
</picker-view>
<!-- 二级联动 -->
<picker-view indicator-style="height: 40px;" class="mpvue-picker-view" :value="pickerValue" @change="pickerChangeMul" v-if="mode==='multiLinkageSelector' && deepLength===2">
<block>
<picker-view-column>
<view class="picker-item" v-for="(item,index) in pickerValueMulTwoOne" :key="index">{{item.label}}</view>
</picker-view-column>
<picker-view-column>
<view class="picker-item" v-for="(item,index) in pickerValueMulTwoTwo" :key="index">{{item.label}}</view>
</picker-view-column>
</block>
</picker-view>
<!-- 三级联动 -->
<picker-view indicator-style="height: 40px;" class="mpvue-picker-view" :value="pickerValue" @change="pickerChangeMul" v-if="mode==='multiLinkageSelector' && deepLength===3">
<block>
<picker-view-column>
<view class="picker-item" v-for="(item,index) in pickerValueMulThreeOne" :key="index">{{item.label}}</view>
</picker-view-column>
<picker-view-column>
<view class="picker-item" v-for="(item,index) in pickerValueMulThreeTwo" :key="index">{{item.label}}</view>
</picker-view-column>
<picker-view-column>
<view class="picker-item" v-for="(item,index) in pickerValueMulThreeThree" :key="index">{{item.label}}</view>
</picker-view-column>
</block>
</picker-view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
pickerChangeValue: [],
pickerValue: [],
pickerValueArrayChange: true,
modeChange: false,
pickerValueSingleArray: [],
pickerValueHour: [],
pickerValueMinute: [],
pickerValueMulArray: [],
pickerValueMulTwoOne: [],
pickerValueMulTwoTwo: [],
pickerValueMulThreeOne: [],
pickerValueMulThreeTwo: [],
pickerValueMulThreeThree: [],
/* 是否显示控件 */
showPicker: false,
};
},
props: {
/* mode */
mode: {
type: String,
default: 'selector'
},
/* picker 数值 */
pickerValueArray: {
type: Array,
default(){
return []
}
},
/* 默认值 */
pickerValueDefault: {
type: Array,
default(){
return []
}
},
/* 几级联动 */
deepLength: {
type: Number,
default: 2
},
/* 主题色 */
themeColor: String
},
watch: {
pickerValueArray(oldVal, newVal) {
this.pickerValueArrayChange = true;
},
mode(oldVal, newVal) {
this.modeChange = true;
},
pickerValueArray(val){
this.initPicker(val);
}
},
methods: {
initPicker(valueArray) {
let pickerValueArray = valueArray;
this.pickerValue = this.pickerValueDefault;
// 初始化多级联动
if (this.mode === 'selector') {
this.pickerValueSingleArray = valueArray;
} else if (this.mode === 'timeSelector') {
this.modeChange = false;
let hourArray = [];
let minuteArray = [];
for (let i = 0; i < 24; i++) {
hourArray.push({
value: i,
label: i > 9 ? `${i}` : `0${i}`
});
}
for (let i = 0; i < 60; i++) {
minuteArray.push({
value: i,
label: i > 9 ? `${i}` : `0${i}`
});
}
this.pickerValueHour = hourArray;
this.pickerValueMinute = minuteArray;
} else if (this.mode === 'multiSelector') {
this.pickerValueMulArray = valueArray;
} else if (this.mode === 'multiLinkageSelector' && this.deepLength === 2) {
// 两级联动
let pickerValueMulTwoOne = [];
let pickerValueMulTwoTwo = [];
// 第一列
for (let i = 0, length = pickerValueArray.length; i < length; i++) {
pickerValueMulTwoOne.push(pickerValueArray[i]);
}
// 渲染第二列
// 如果有设定的默认值
if (this.pickerValueDefault.length === 2) {
let num = this.pickerValueDefault[0];
for (
let i = 0, length = pickerValueArray[num].children.length; i < length; i++
) {
pickerValueMulTwoTwo.push(pickerValueArray[num].children[i]);
}
} else {
for (
let i = 0, length = pickerValueArray[0].children.length; i < length; i++
) {
pickerValueMulTwoTwo.push(pickerValueArray[0].children[i]);
}
}
this.pickerValueMulTwoOne = pickerValueMulTwoOne;
this.pickerValueMulTwoTwo = pickerValueMulTwoTwo;
} else if (
this.mode === 'multiLinkageSelector' &&
this.deepLength === 3
) {
let pickerValueMulThreeOne = [];
let pickerValueMulThreeTwo = [];
let pickerValueMulThreeThree = [];
// 第一列
for (let i = 0, length = pickerValueArray.length; i < length; i++) {
pickerValueMulThreeOne.push(pickerValueArray[i]);
}
// 渲染第二列
this.pickerValueDefault =
this.pickerValueDefault.length === 3 ?
this.pickerValueDefault :
[0, 0, 0];
if (this.pickerValueDefault.length === 3) {
let num = this.pickerValueDefault[0];
for (
let i = 0, length = pickerValueArray[num].children.length; i < length; i++
) {
pickerValueMulThreeTwo.push(pickerValueArray[num].children[i]);
}
// 第三列
let numSecond = this.pickerValueDefault[1];
for (let i = 0, length = pickerValueArray[num].children[numSecond].children.length; i < length; i++) {
pickerValueMulThreeThree.push(
pickerValueArray[num].children[numSecond].children[i]
);
}
}
this.pickerValueMulThreeOne = pickerValueMulThreeOne;
this.pickerValueMulThreeTwo = pickerValueMulThreeTwo;
this.pickerValueMulThreeThree = pickerValueMulThreeThree;
}
},
show() {
setTimeout(() => {
if (this.pickerValueArrayChange || this.modeChange) {
this.initPicker(this.pickerValueArray);
this.showPicker = true;
this.pickerValueArrayChange = false;
this.modeChange = false;
} else {
this.showPicker = true;
}
}, 0);
},
maskClick() {
this.pickerCancel();
},
pickerCancel() {
this.showPicker = false;
this._initPickerVale();
let pickObj = {
index: this.pickerValue,
value: this._getPickerLabelAndValue(this.pickerValue, this.mode).value,
label: this._getPickerLabelAndValue(this.pickerValue, this.mode).label
};
this.$emit('onCancel', pickObj);
},
pickerConfirm(e) {
this.showPicker = false;
this._initPickerVale();
let pickObj = {
index: this.pickerValue,
value: this._getPickerLabelAndValue(this.pickerValue, this.mode).value,
label: this._getPickerLabelAndValue(this.pickerValue, this.mode).label
};
this.$emit('onConfirm', pickObj);
},
showPickerView() {
this.showPicker = true;
},
pickerChange(e) {
this.pickerValue = e.mp.detail.value;
let pickObj = {
index: this.pickerValue,
value: this._getPickerLabelAndValue(this.pickerValue, this.mode).value,
label: this._getPickerLabelAndValue(this.pickerValue, this.mode).label
};
this.$emit('onChange', pickObj);
},
pickerChangeMul(e) {
if (this.deepLength === 2) {
let pickerValueArray = this.pickerValueArray;
let changeValue = e.mp.detail.value;
// 处理第一列滚动
if (changeValue[0] !== this.pickerValue[0]) {
let pickerValueMulTwoTwo = [];
// 第一列滚动第二列数据更新
for (let i = 0, length = pickerValueArray[changeValue[0]].children.length; i < length; i++) {
pickerValueMulTwoTwo.push(pickerValueArray[changeValue[0]].children[i]);
}
this.pickerValueMulTwoTwo = pickerValueMulTwoTwo;
// 第二列初始化为 0
changeValue[1] = 0;
}
this.pickerValue = changeValue;
} else if (this.deepLength === 3) {
let pickerValueArray = this.pickerValueArray;
let changeValue = e.mp.detail.value;
let pickerValueMulThreeTwo = [];
let pickerValueMulThreeThree = [];
// 重新渲染第二列
// 如果是第一列滚动
if (changeValue[0] !== this.pickerValue[0]) {
this.pickerValueMulThreeTwo = [];
for (let i = 0, length = pickerValueArray[changeValue[0]].children.length; i < length; i++) {
pickerValueMulThreeTwo.push(pickerValueArray[changeValue[0]].children[i]);
}
// 重新渲染第三列
for (let i = 0, length = pickerValueArray[changeValue[0]].children[0].children.length; i <
length; i++) {
pickerValueMulThreeThree.push(pickerValueArray[changeValue[0]].children[0].children[i]);
}
changeValue[1] = 0;
changeValue[2] = 0;
this.pickerValueMulThreeTwo = pickerValueMulThreeTwo;
this.pickerValueMulThreeThree = pickerValueMulThreeThree;
} else if (changeValue[1] !== this.pickerValue[1]) {
// 第二列滚动
// 重新渲染第三列
this.pickerValueMulThreeThree = [];
pickerValueMulThreeTwo = this.pickerValueMulThreeTwo;
for (let i = 0, length = pickerValueArray[changeValue[0]].children[changeValue[1]].children.length; i <
length; i++) {
pickerValueMulThreeThree.push(pickerValueArray[changeValue[0]].children[changeValue[1]].children[
i]);
}
changeValue[2] = 0;
this.pickerValueMulThreeThree = pickerValueMulThreeThree;
}
this.pickerValue = changeValue;
}
let pickObj = {
index: this.pickerValue,
value: this._getPickerLabelAndValue(this.pickerValue, this.mode).value,
label: this._getPickerLabelAndValue(this.pickerValue, this.mode).label
};
this.$emit('onChange', pickObj);
},
// 获取 pxikerLabel
_getPickerLabelAndValue(value, mode) {
let pickerLable;
let pickerGetValue = [];
// selector
if (mode === 'selector') {
pickerLable = this.pickerValueSingleArray[value].label;
pickerGetValue.push(this.pickerValueSingleArray[value].value);
} else if (mode === 'timeSelector') {
pickerLable = `${this.pickerValueHour[value[0]].label}-${this.pickerValueMinute[value[1]].label}`;
pickerGetValue.push(this.pickerValueHour[value[0]].value);
pickerGetValue.push(this.pickerValueHour[value[1]].value);
} else if (mode === 'multiSelector') {
for (let i = 0; i < value.length; i++) {
if (i > 0) {
pickerLable += this.pickerValueMulArray[i][value[i]].label + (i === value.length - 1 ? '' :
'-');
} else {
pickerLable = this.pickerValueMulArray[i][value[i]].label + '-';
}
pickerGetValue.push(this.pickerValueMulArray[i][value[i]].value);
}
} else if (mode === 'multiLinkageSelector') {
/* eslint-disable indent */
pickerLable =
this.deepLength === 2 ?
`${this.pickerValueMulTwoOne[value[0]].label}-${this.pickerValueMulTwoTwo[value[1]].label}` :
`${this.pickerValueMulThreeOne[value[0]].label}-${this.pickerValueMulThreeTwo[value[1]].label}-${this.pickerValueMulThreeThree[value[2]].label}`;
if (this.deepLength === 2) {
pickerGetValue.push(this.pickerValueMulTwoOne[value[0]].value);
pickerGetValue.push(this.pickerValueMulTwoTwo[value[1]].value);
} else {
pickerGetValue.push(this.pickerValueMulThreeOne[value[0]].value);
pickerGetValue.push(this.pickerValueMulThreeTwo[value[1]].value);
pickerGetValue.push(this.pickerValueMulThreeThree[value[2]].value);
}
/* eslint-enable indent */
}
return {
label: pickerLable,
value: pickerGetValue
};
},
// 初始化 pickerValue 默认值
_initPickerVale() {
if (this.pickerValue.length === 0) {
if (this.mode === 'selector') {
this.pickerValue = [0];
} else if (this.mode === 'multiSelector') {
this.pickerValue = new Int8Array(this.pickerValueArray.length);
} else if (
this.mode === 'multiLinkageSelector' &&
this.deepLength === 2
) {
this.pickerValue = [0, 0];
} else if (
this.mode === 'multiLinkageSelector' &&
this.deepLength === 3
) {
this.pickerValue = [0, 0, 0];
}
}
}
}
};
</script>
<style>
.pickerMask {
position: fixed;
z-index: 1000;
top: 0;
right: 0;
left: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
}
.mpvue-picker-content {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
transition: all 0.3s ease;
transform: translateY(100%);
z-index: 3000;
}
.mpvue-picker-view-show {
transform: translateY(0);
}
.mpvue-picker__hd {
display: flex;
padding: 9px 15px;
background-color: #fff;
position: relative;
text-align: center;
font-size: 17px;
}
.mpvue-picker__hd:after {
content: ' ';
position: absolute;
left: 0;
bottom: 0;
right: 0;
height: 1px;
border-bottom: 1px solid #e5e5e5;
color: #e5e5e5;
transform-origin: 0 100%;
transform: scaleY(0.5);
}
.mpvue-picker__action {
display: block;
flex: 1;
color: #1aad19;
}
.mpvue-picker__action:first-child {
text-align: left;
color: #888;
}
.mpvue-picker__action:last-child {
text-align: right;
}
.picker-item {
text-align: center;
line-height: 40px;
font-size: 16px;
}
.mpvue-picker-view {
position: relative;
bottom: 0;
left: 0;
width: 100%;
height: 238px;
background-color: rgba(255, 255, 255, 1);
}
</style>

View File

@@ -0,0 +1,260 @@
<template>
<view class="neil-modal" @touchmove.stop.prevent="bindTouchmove" :class="{'neil-modal--show':isOpen}">
<view class="neil-modal__mask" @click="clickMask"></view>
<view class="neil-modal__container">
<view class="neil-modal__header" v-if="title.length > 0">{{title}}</view>
<view class="neil-modal__content" :class="content ? 'neil-modal--padding' : ''" :style="{textAlign:align}">
<template v-if="content">
<text class="modal-content">{{content}}</text>
</template>
<template v-else>
<slot />
</template>
</view>
<view class="neil-modal__footer">
<view v-if="showCancel" class="neil-modal__footer-left" @click="clickLeft" :style="{color:cancelColor}"
hover-class="neil-modal__footer-hover" :hover-start-time="20" :hover-stay-time="70">
{{cancelText}}
</view>
<view class="neil-modal__footer-right" @click="clickRight" :style="{color:confirmColor}" hover-class="neil-modal__footer-hover"
:hover-start-time="20" :hover-stay-time="70">
{{confirmText}}
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'neil-modal',
props: {
title: { //标题
type: String,
default: ''
},
content: String, //提示的内容
align: { //content 的对齐方式left/center/right
type: String,
default: 'left'
},
cancelText: { //取消按钮的文字,默认为"取消"
type: String,
default: '取消'
},
cancelColor: { //取消按钮颜色
type: String,
default: '#333333'
},
confirmText: { //确定按钮的文字,默认为"确定"
type: String,
default: '确定'
},
confirmColor: { //确认按钮颜色
type: String,
default: '#007aff'
},
showCancel: { //是否显示取消按钮,默认为 true
type: [Boolean, String],
default: true
},
show: { //是否显示模态框
type: [Boolean, String],
default: false
},
autoClose: { //点击遮罩是否自动关闭弹窗
type: [Boolean, String],
default: true
}
},
data() {
return {
isOpen: false
}
},
watch: {
show(val) {
this.isOpen = val
}
},
created() {
this.isOpen = this.show
},
methods: {
bindTouchmove() {},
clickLeft() {
setTimeout(() => {
this.$emit('cancel')
}, 200)
this.closeModal()
},
clickRight() {
setTimeout(() => {
this.$emit('confirm')
}, 200)
this.closeModal()
},
clickMask(){
if(this.autoClose){
this.closeModal()
}
},
closeModal() {
this.showAnimation = false
this.isOpen = false
this.$emit('close')
}
}
}
</script>
<style lang="scss">
$bg-color-mask:rgba(0, 0, 0, 0.5); //遮罩颜色
$bg-color-hover:#f1f1f1; //点击状态颜色
.neil-modal {
position: fixed;
visibility: hidden;
width: 100%;
height: 100%;
top: 0;
left: 0;
z-index: 1000;
transition:visibility 200ms ease-in;
&.neil-modal--show{
visibility: visible;
}
&__header {
position: relative;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding: 18upx 24upx;
line-height: 1.5;
color: #333;
font-size: 32upx;
text-align: center;
&::after {
content: " ";
position: absolute;
left: 0;
bottom: 0;
right: 0;
height: 1px;
border-top: 1px solid #e5e5e5;
transform-origin: 0 0;
transform: scaleY(.5);
}
}
&__container {
position: absolute;
z-index: 999;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) ;
transition: transform 0.3s;
width: 540upx;
border-radius: 20upx;
background-color: #fff;
overflow: hidden;
opacity: 0;
transition: opacity 200ms ease-in;
}
&__content {
position: relative;
color: #333;
font-size: 28upx;
box-sizing: border-box;
line-height: 1.5;
&::after {
content: " ";
position: absolute;
left: 0;
bottom: -1px;
right: 0;
height: 1px;
border-bottom: 1px solid #e5e5e5;
transform-origin: 0 0;
transform: scaleY(.5);
}
}
&__footer {
position: relative;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: #333;
font-size: 32upx;
display: flex;
flex-direction: row;
&-left,
&-right {
position: relative;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
height: 88upx;
font-size: 28upx;
line-height: 88upx;
text-align: center;
background-color: #fff;
color: #333;
}
&-right {
color: #007aff;
}
&-left::after {
content: " ";
position: absolute;
right: -1px;
top: 0;
width: 1px;
bottom: 0;
border-right: 1px solid #e5e5e5;
transform-origin: 0 0;
transform: scaleX(.5);
}
&-hover {
background-color: $bg-color-hover;
}
}
&__mask {
display: block;
position: absolute;
z-index: 998;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: $bg-color-mask;
opacity: 0;
transition: opacity 200ms ease-in;
&.neil-modal--show{
opacity: 1;
}
}
&--padding {
padding: 32upx 24upx;
min-height: 90upx;
}
&--show {
.neil-modal__container,.neil-modal__mask{
opacity: 1;
}
}
}
</style>

View File

@@ -0,0 +1,246 @@
<template>
<view class="pay-type-list">
<view class="type-item b-b" v-for="item in payments" :key="item.code" @click="toPayHandler(item.code)"
v-if="!(type == 2 && item.code == 'balancepay')">
<text v-if=" item.code == 'wechatpay'" class="icon yticon icon-weixinzhifu"></text>
<text v-if=" item.code == 'alipay'" class="icon yticon icon-alipay"></text>
<text v-if=" item.code == 'offline'" class="icon yticon icon-weixinzhifu"></text>
<text v-if=" item.code == 'balancepay'" class="icon yticon icon-erjiye-yucunkuan"></text>
<view class="con">
<text class="tit">{{ item.name }}</text>
<text>{{ item.memo }}</text>
</view>
</view>
</view>
</template>
<script>
import { apiBaseUrl } from '@/config/config.js';
import mallplusCopyright from '@/components/mall-copyright/mallplusCopyright.vue';
import Api from '@/common/api';
export default {
props: {
// 如果是商品订单此参数必须
orderId: {
type: String,
default () {
return '';
}
},
// 如果是充值订单此参数必须
recharge: {
type: Number,
default () {
return 0;
}
},
// 用户id
uid: {
type: Number,
default () {
return 0;
}
},
// 订单类型
type: {
type: Number,
default () {
return 1;
}
}
},
data () {
return {
payments: []
}
},
mounted () {
this.getPayments();
},
methods: {
// 获取可用支付方式列表
async getPayments () {
let params = {};
this.orderInfo = await Api.apiCall('get',Api.order.paymentlist,params);
this.payments = this.formatPayments(this.orderInfo)
},
// 支付方式处理
formatPayments (payments) {
payments = payments.filter(item => item.code !== 'wechatpay');
// 如果是充值订单 过滤余额支付 过滤非线上支付方式
if (this.type === 2) {
payments = payments.filter(item => item.code !== 'balancepay' || item.is_online === 1)
}
// 设置logo图片
payments.forEach(item => {
this.$set(item, 'icon', '/static/image/' + item.code + '.png');
});
return payments;
},
// 用户点击支付方式处理
async toPayHandler (code) {
let params = {'orderId':this.orderId};
let data = {
payment_code: code,
payment_type: this.type
}
data['ids'] = (this.type == 1 || this.type == 5 || this.type == 6) ? this.orderId : this.uid
// 判断订单支付类型
if (this.type == 2 && this.recharge) {
data['params'] = {
money: this.recharge,
trade_type: 'JSAPI'
}
} else if ((this.type == 5 || this.type == 6) && this.recharge) {
data['params'] = {
trade_type: 'JSAPI',
formid: this.orderId
}
}else {
data['params'] = {
trade_type: 'JSAPI'
}
}
let _this = this;
switch (code) {
case 'alipay':
let res = await Api.apiCall('get',Api.order.webPay,params);
console.log(res);
if (res) {
uni.requestPayment({
provider: 'alipay',
tradeNO:res.data.trade_no,
success: function (e) {
if (e.errMsg === 'requestPayment:ok') {
_this.$common.successToShow(res.msg, () => {
_this.$common.redirectTo('/pages/order/payment/result?id=' + res.data.id);
});
}
}
});
} else {
this.$common.errorToShow(res.msg);
}
break
case 'balancepay':
//用户余额支付
let params1 = {'orderId':this.orderId};
let data1 = await Api.apiCall('post',Api.order.balancePay,params1);
console.log(data1)
if (data1) {
uni.redirectTo({
url: '/pages/order/payment/result?order=' + JSON.stringify(data1)
})
}else {
this.$api.msg('余额支付失败');
}
break;
case 'offline':
//线下支付
this.$common.modelShow('线下支付说明', '请联系客服进行线下支付',() => {}, false, '取消', '确定')
break;
}
}
}
}
</script>
<style lang='scss'>
.app {
width: 100%;
}
.price-box {
background-color: #fff;
height: 265upx;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 28upx;
color: #909399;
.price{
font-size: 50upx;
color: #303133;
margin-top: 12upx;
&:before{
content: '¥';
font-size: 40upx;
}
}
}
.pay-type-list {
margin-top: 20upx;
background-color: #fff;
padding-left: 60upx;
.type-item{
height: 120upx;
padding: 20upx 0;
display: flex;
justify-content: space-between;
align-items: center;
padding-right: 60upx;
font-size: 30upx;
position:relative;
}
.icon{
width: 100upx;
font-size: 52upx;
}
.icon-erjiye-yucunkuan {
color: #fe8e2e;
}
.icon-weixinzhifu {
color: #36cb59;
}
.icon-alipay {
color: #01aaef;
}
.tit{
font-size: $font-lg;
color: $font-color-dark;
margin-bottom: 4upx;
}
.con{
flex: 1;
display: flex;
flex-direction: column;
font-size: $font-sm;
color: $font-color-light;
}
}
.mix-btn {
display: flex;
align-items: center;
justify-content: center;
width: 630upx;
height: 80upx;
margin: 80upx auto 30upx;
font-size: $font-lg;
color: #fff;
background-color: $base-color;
border-radius: 10upx;
box-shadow: 1px 2px 5px rgba(219, 63, 96, 0.4);
}
</style>

View File

@@ -0,0 +1,287 @@
<template>
<view class="pay-type-list">
<view class="type-item b-b" v-for="item in paymentss" :key="item.code" @click="toPayHandler(item.code)" v-if="!(type == 2 && item.code == 'balancepay')">
<text v-if="item.code == 'wechatpay'" class="icon yticon icon-weixinzhifu"></text>
<text v-if="item.code == 'alipay'" class="icon yticon icon-alipay"></text>
<text v-if="item.code == 'offline'" class="icon yticon icon-weixinzhifu"></text>
<text v-if="item.code == 'balancepay'" class="icon yticon icon-erjiye-yucunkuan"></text>
<view class="con">
<text class="tit">{{ item.name }}</text>
<text>{{ item.memo }}</text>
</view>
</view>
</view>
</template>
<script>
import mallplusCopyright from '@/components/mall-copyright/mallplusCopyright.vue';
import Api from '@/common/api';
export default {
props: {
// 如果是商品订单此参数必须
orderId: {
type: String,
default() {
return '';
}
},
// 如果是充值订单此参数必须
recharge: {
type: Number,
default() {
return 0;
}
},
// 用户id
uid: {
type: Number,
default() {
return 0;
}
},
// 订单类型
type: {
type: Number,
default() {
return 1;
}
}
},
data() {
return {
paymentss: []
};
},
mounted() {
this.getPayment();
},
methods: {
// 获取可用支付方式列表
async getPayment() {
console.log('getPayments');
let params = {};
this.orderInfo = await Api.apiCall('get', Api.order.paymentlist, params);
this.paymentss = this.formatPayments(this.orderInfo);
},
// 支付方式处理
formatPayments(payments) {
// 如果是充值订单 过滤余额支付 过滤非线上支付方式
if (this.type === 2) {
payments = payments.filter(item => item.code !== 'balancepay' || item.is_online === 1);
}
// 设置logo图片
payments.forEach(item => {
this.$set(item, 'icon', '/static/image/' + item.code + '.png');
});
return payments;
},
// 用户点击支付方式处理
async toPayHandler(code) {
let _this = this;
let params = { orderId: this.orderId };
let data = {
payment_code: code,
payment_type: _this.type
};
data['ids'] = this.type == 1 || this.type == 5 || this.type == 6 ? this.orderId : this.uid;
if ((this.type == 5 || this.type == 6) && this.recharge) {
data['params'] = {
trade_type: 'APP',
formid: this.orderId
};
}
switch (code) {
case 'alipay':
/**
* 支付宝支付需要模拟GET提交数据
*/
if (_this.type == 1 && _this.orderId) {
data['params'] = {
trade_type: 'APP'
};
} else if (_this.type == 2 && _this.recharge) {
data['params'] = {
trade_type: 'APP',
money: _this.recharge
};
}
let res = await Api.apiCall('get', Api.order.aliAppPay, params);
if (res) {
console.log(res);
uni.requestPayment({
provider: 'alipay',
orderInfo: res,
success: function(data) {
let rawdataResult = JSON.parse(data.rawdata).result;
let r = rawdataResult.split(';')[0];
let r1 = rawdataResult.split(';')[0].length - 1;
let r2 = rawdataResult.split(';')[0].length - 2;
let alipayTradeAppPayResponse = JSON.parse(r.substr(0, r1)).alipay_trade_app_pay_response;
let out_trade_no = alipayTradeAppPayResponse.out_trade_no;
_this.$common.successToShow('支付成功', () => {
//_this.redirectHandler(res.data.payment_id)
_this.redirectHandler(out_trade_no);
});
}
});
} else {
_this.$comon.errorToShow(res.msg);
}
break;
case 'wechatpay':
// 微信 H5支付
if (_this.type == 1 && _this.orderId) {
data['params'] = {
trade_type: 'APP'
};
} else if (_this.type == 2 && _this.recharge) {
data['params'] = {
trade_type: 'APP',
money: _this.recharge
};
}
// 微信app支付
let res1 = await Api.apiCall('get', Api.order.appPay, params);
debugger
console.log(res1)
console.log(data)
if (res1) {
// 调用微信支付
uni.requestPayment({
provider: 'wxpay',
orderInfo: res1,
success: function(data) {
console.log(res1)
console.log(data)
_this.$common.successToShow('支付成功', () => {
_this.redirectHandler(data);
});
},
fail: function(res) {
console.log(JSON.stringify(res));
}
});
} else {
_this.$common.errorToShow(res.msg);
}
break;
case 'balancepay':
/**
* 用户余额支付
*
*/
let params1 = { orderId: this.orderId };
let data1 = await Api.apiCall('post', Api.order.balancePay, params1);
console.log(data1);
if (data1) {
uni.redirectTo({
url: '/pages/order/payment/result?order=' + JSON.stringify(data1)
});
} else {
this.$api.msg(data1.data);
}
break;
case 'offline':
/**
* 线下支付
*/
_this.$common.modelShow('线下支付说明', '请联系客服进行线下支付', () => {}, false, '取消', '确定');
break;
}
},
// 支付成功后跳转操作
redirectHandler(paymentId) {
this.$common.redirectTo('/pages/order/payment/result?id=' + paymentId);
}
}
};
</script>
<style lang="scss">
.app {
width: 100%;
}
.price-box {
background-color: #fff;
height: 265upx;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 28upx;
color: #909399;
.price {
font-size: 50upx;
color: #303133;
margin-top: 12upx;
&:before {
content: '¥';
font-size: 40upx;
}
}
}
.pay-type-list {
margin-top: 20upx;
background-color: #fff;
padding-left: 60upx;
.type-item {
height: 120upx;
padding: 20upx 0;
display: flex;
justify-content: space-between;
align-items: center;
padding-right: 60upx;
font-size: 30upx;
position: relative;
}
.icon {
width: 100upx;
font-size: 52upx;
}
.icon-erjiye-yucunkuan {
color: #fe8e2e;
}
.icon-weixinzhifu {
color: #36cb59;
}
.icon-alipay {
color: #01aaef;
}
.tit {
font-size: $font-lg;
color: $font-color-dark;
margin-bottom: 4upx;
}
.con {
flex: 1;
display: flex;
flex-direction: column;
font-size: $font-sm;
color: $font-color-light;
}
}
.mix-btn {
display: flex;
align-items: center;
justify-content: center;
width: 630upx;
height: 80upx;
margin: 80upx auto 30upx;
font-size: $font-lg;
color: #fff;
background-color: $base-color;
border-radius: 10upx;
box-shadow: 1px 2px 5px rgba(219, 63, 96, 0.4);
}
</style>

View File

@@ -0,0 +1,412 @@
<template>
<view class="pay-type-list">
<view class="type-item b-b" v-for="item in payments" :key="item.code" @click="toPayHandler(item.code)"
v-if="!(type == 2 && item.code == 'balancepay')">
<text v-if=" item.code == 'wechatpay'" class="icon yticon icon-weixinzhifu"></text>
<text v-if=" item.code == 'alipay'" class="icon yticon icon-alipay"></text>
<text v-if=" item.code == 'offline'" class="icon yticon icon-weixinzhifu"></text>
<text v-if=" item.code == 'balancepay'" class="icon yticon icon-erjiye-yucunkuan"></text>
<view class="con">
<text class="tit">{{ item.name }}</text>
<text>{{ item.memo }}</text>
</view>
</view>
</view>
<!--<view class='cell-group payment-method'>
<view class='cell-item add-title-item' v-for="item in payments" :key="item.code" @click="toPayHandler(item.code)"
v-if="!(type == 2 && item.code == 'balancepay')">
<view class='cell-item-hd'>
<image class='cell-hd-icon' :src='item.icon'></image>
</view>
<view class='cell-item-bd'>
<view class="cell-bd-view">
<text class="cell-bd-text">{{ item.name }}</text>
</view>
<view class="cell-bd-view">
<text class="cell-bd-text address">{{ item.memo }}</text>
</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' src='../../../static/image/right.png'></image>
</view>
</view>
</view>-->
</template>
<script>
import {
baseUrl
} from '@/config/config.js'
import mallplusCopyright from '@/components/mall-copyright/mallplusCopyright.vue';
import Api from '@/common/api';
export default {
props: {
// 如果是商品订单此参数必须
orderId: {
type: String,
default () {
return ''
}
},
// 如果是充值订单此参数必须
recharge: {
type: Number,
default () {
return 0
}
},
// 用户id
uid: {
type: Number,
default () {
return 0
}
},
// 订单类型
type: {
type: Number,
default () {
return 1
}
}
},
data() {
return {
payments: [],
openid: ''
}
},
mounted() {
this.getPayments()
},
methods: {
// 获取可用支付方式列表
async getPayments() {
let params = {};
this.orderInfo = await Api.apiCall('get',Api.order.paymentlist,params);
this.payments = this.formatPayments(this.orderInfo)
},
// 支付方式处理
formatPayments(payments) {
// h5支付并且是在微信浏览器内 过滤支付宝支付
if (this.$common.isWeiXinBrowser()) {
payments = payments.filter(item => item.code !== 'alipay')
}
// 如果是充值订单 过滤余额支付 过滤非线上支付方式
if (this.type === 2) {
payments = payments.filter(
item => item.code !== 'balancepay' || item.is_online === 1
)
}
// 设置logo图片
payments.forEach(item => {
this.$set(item, 'icon', '/static/image/' + item.code + '.png')
})
console.log(payments)
return payments
},
checkWXJSBridge(data) {
let that = this
let interval = setInterval(() => {
if (typeof window.WeixinJSBridge != 'undefined') {
clearTimeout(interval)
that.onBridgeReady(data)
}
}, 200)
},
onBridgeReady(data) {
var _this = this
window.WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
appId: data.appId, // 公众号名称,由商户传入
timeStamp: data.timeStamp, // 时间戳自1970年以来的秒数
nonceStr: data.nonceStr, // 随机串
package: data.package,
signType: data.signType, // 微信签名方式:
paySign: data.paySign // 微信签名
},
function(res) {
if (res.err_msg === 'get_brand_wcpay_request:ok') {
_this.$common.successToShow('支付成功')
} else if (res.err_msg === 'get_brand_wcpay_request:cancel') {
_this.$common.errorToShow('取消支付')
} else {
_this.$common.errorToShow('支付失败')
}
setTimeout(() => {
_this.$common.redirectTo(
'/pages/order/payment/result?id=' + data.payment_id
)
}, 1000)
}
)
},
// 用户点击支付方式处理
async toPayHandler(code) {
let params = {'orderId':this.orderId};
let data = {
payment_code: code,
payment_type: this.type
}
data['orderId'] = (this.type == 1 || this.type == 5 || this.type == 6) ? this.orderId : this.uid
switch (code) {
case 'alipay':
let res = await Api.apiCall('get',Api.order.aliWapPay,params);
console.log('============================')
console.log(res);
console.log('success:' + JSON.stringify(res));
if (res) {
document.body.appendChild(JSON.stringify(res))
let testForm = document.getElementsByName('punchout_form')
// 模拟GET提交
/*
const url = res.data.url
const data = res.data.data
let tempForm = document.createElement('form')
tempForm.id = 'aliPay'
tempForm.methods = 'post'
tempForm.action = url
tempForm.target = '_self'
let input = []
for (let k in data) {
input[k] = document.createElement('input')
input[k].type = 'hidden'
input[k].name = k
input[k].value = data[k]
tempForm.appendChild(input[k])
}
tempForm.addEventListener('submit', function() {}, false)
document.body.appendChild(tempForm)*/
testForm.dispatchEvent(new Event('submit'))
console.log(tempForm);
testForm.submit()
document.body.removeChild(testForm)
}
break
case 'wechatpay':
/**
* 微信支付有两种
* 判断是否在微信浏览器
* 微信jsapi支付
*/
let isWeiXin = this.$common.isWeiXinBrowser()
if (isWeiXin) {
var transitUrl =
baseUrl +
'wap/#/pages/order/payment/auth?order_id=' +
this.orderId +
'&type=' +
this.type;
if (this.type == 1 && this.orderId) {
// 微信jsapi支付
// if (this.openid) {
// data['params'] = {
// trade_type: 'JSAPI_OFFICIAL',
// openid: this.openid
// }
// } else {
// data['params'] = {
// trade_type: 'JSAPI_OFFICIAL',
// url: window.location.href
// }
// }
data['params'] = {
trade_type: 'JSAPI_OFFICIAL',
url: transitUrl
}
} else if (this.type == 2 && this.recharge) {
data['params'] = {
trade_type: 'JSAPI_OFFICIAL',
money: this.recharge,
url: transitUrl + '&uid=' + this.uid + '&money=' + this.recharge
}
// if (this.openid) {
// data['params'] = {
// money: this.recharge,
// openid: this.openid
// }
// } else {
// data['params'] = {
// money: this.recharge,
// url: window.location.href
// }
// }
} else if ((this.type == 5 || this.type == 6) && this.recharge) {
data['params'] = {
orderId: this.orderId
}
}
let res = await Api.apiCall('get',Api.order.webPay,params);
console.log(res);
if (res) {
this.checkWXJSBridge(res)
}else{
window.location.href = res.msg
return;
}
} else {
// 微信 H5支付
if (this.type == 1 && this.orderId) {
data['params'] = {
trade_type: 'MWEB',
return_url: baseUrl +
'wap/#/pages/order/payment/result'
}
} else if (this.type == 2 && this.recharge) {
data['params'] = {
trade_type: 'MWEB',
money: this.recharge,
return_url: baseUrl + 'wap/#/pages/order/payment/result'
}
} else if ((this.type == 5 || this.type == 6) && this.recharge) {
data['params'] = {
orderId: this.orderId
}
}
console.log(data);
// 微信h5支付
let res = await Api.apiCall('get',Api.order.wapPay,params);
console.log(res);
if (res) {
if (res) {
location.href = res
} else {
this.$common.errorToShow(res)
}
}
}
break
case 'balancepay':
/**
* 用户余额支付
*
*/
if ((this.type == 5 || this.type == 6) && this.recharge) {
data['params'] = {
orderId: this.orderId
}
}
let params1 = {'orderId':this.orderId};
let data1 = await Api.apiCall('post',Api.order.balancePay,params1);
console.log(data1)
if (data1) {
uni.redirectTo({
url: '/pages/order/payment/result?order=' + JSON.stringify(data1)
})
}else {
this.$api.msg(data1.data);
}
break
case 'offline':
/**
* 线下支付
*/
this.$common.modelShow(
'线下支付说明',
'请联系客服进行线下支付qq:951449465',
() => {},
false,
'取消',
'确定'
)
break
}
}
}
}
</script>
<style lang='scss'>
.app {
width: 100%;
}
.price-box {
background-color: #fff;
height: 265upx;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 28upx;
color: #909399;
.price{
font-size: 50upx;
color: #303133;
margin-top: 12upx;
&:before{
content: '¥';
font-size: 40upx;
}
}
}
.pay-type-list {
margin-top: 20upx;
background-color: #fff;
padding-left: 60upx;
.type-item{
height: 120upx;
padding: 20upx 0;
display: flex;
justify-content: space-between;
align-items: center;
padding-right: 60upx;
font-size: 30upx;
position:relative;
}
.icon{
width: 100upx;
font-size: 52upx;
}
.icon-erjiye-yucunkuan {
color: #fe8e2e;
}
.icon-weixinzhifu {
color: #36cb59;
}
.icon-alipay {
color: #01aaef;
}
.tit{
font-size: $font-lg;
color: $font-color-dark;
margin-bottom: 4upx;
}
.con{
flex: 1;
display: flex;
flex-direction: column;
font-size: $font-sm;
color: $font-color-light;
}
}
.mix-btn {
display: flex;
align-items: center;
justify-content: center;
width: 630upx;
height: 80upx;
margin: 80upx auto 30upx;
font-size: $font-lg;
color: #fff;
background-color: $base-color;
border-radius: 10upx;
box-shadow: 1px 2px 5px rgba(219, 63, 96, 0.4);
}
</style>

View File

@@ -0,0 +1,249 @@
<template>
<view class="pay-type-list">
<view class="type-item b-b" v-for="item in payments" :key="item.code"
report-submit="true" @click="toPayHandler(item.code)"
v-if="!(type == 2 && item.code == 'balancepay')">
<!-- <text class="icon yticon icon-weixinzhifu"></text> -->
<image :src="item.img" style="width: 80upx;height: 80upx;margin-right: 20upx;"></image>
<view class="con">
<text class="tit">{{ item.name }}</text>
<text>{{ item.memo }}</text>
</view>
</view>
</view>
</template>
<script>
import { apiBaseUrl } from '@/config/config.js'
import mallplusCopyright from '@/components/mall-copyright/mallplusCopyright.vue';
import Api from '@/common/api';
export default {
props: {
// 如果是商品订单此参数必须
orderId: {
type: String,
default () {
return ''
}
},
// 如果是充值订单此参数必须
recharge: {
type: Number,
default () {
return 0
}
},
// 用户id
uid: {
type: Number,
default () {
return 0
}
},
// 订单类型
type: {
type: Number,
default () {
return 1
}
}
},
data () {
return {
payments: [],
imgList: [
'/static/image/wechatpay.png','/static/image/balancepay.png','/static/image/payment_balance.png',
]
}
},
mounted () {
this.getPayments()
},
methods: {
// 获取可用支付方式列表
async getPayments () {
let params = {};
this.orderInfo = await Api.apiCall('get',Api.order.paymentlist,params);
this.payments = this.formatPayments(this.orderInfo)
for(var i = 0;i < this.payments.length;i++){
this.payments[i].img = this.imgList[i]
}
console.log('------',this.payments)
},
// 支付方式处理
formatPayments (payments) {
// 过滤支付宝支付
payments = payments.filter(item => item.code !== 'alipay')
// 如果是充值订单 过滤余额支付 过滤非线上支付方式
if (this.type === 2) {
payments = payments.filter(item => item.code !== 'balancepay' || item.is_online === 1)
}
// 设置logo图片
payments.forEach(item => {
this.$set(item, 'icon', '/static/image/' + item.code + '.png')
})
return payments
},
// 用户点击支付方式处理
async toPayHandler (code) {
let params = {'orderId':this.orderId,
payment_type: this.type};
// 判断订单支付类型
if (this.type == 2 && this.recharge) {
}else if ((this.type == 5 || this.type == 6) && this.recharge) {
}
let _this = this
switch (code) {
case 'wechatpay':
let res = await Api.apiCall('post',Api.order.weixinAppletPay,params);
console.log(res);
if (res) {
uni.requestPayment({
provider: 'wxpay',
timeStamp: res.timeStamp,
nonceStr: res.nonceStr,
package: res.package,
signType: res.signType,
paySign: res.paySign,
success: function (e) {
if (e.errMsg === 'requestPayment:ok') {
_this.$common.successToShow(res.msg, () => {
_this.$common.redirectTo('/pages/order/payment/result?id=' + res.id)
})
}else{
this.$common.errorToShow(res.msg)
}
}
});
} else {
this.$common.errorToShow(res.msg)
}
break
case 'balancepay':
/**
* 用户余额支付
*
*/
let params1 = {'orderId':this.orderId};
let data1 = await Api.apiCall('post',Api.order.balancePay,params1);
console.log(data1)
if (data1) {
uni.redirectTo({
url: '/pages/order/payment/result?order=' + JSON.stringify(data1)
})
}else {
this.$api.msg(data1.data);
}
break
case 'offline':
/**
* 线下支付
*/
this.$common.modelShow('线下支付说明', '请联系客服进行线下支付', () => {},false, '取消', '确定')
break
}
}
}
}
</script>
<style lang='scss'>
.app {
width: 100%;
}
.price-box {
background-color: #fff;
height: 265upx;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 28upx;
color: #909399;
.price{
font-size: 50upx;
color: #303133;
margin-top: 12upx;
&:before{
content: '¥';
font-size: 40upx;
}
}
}
.pay-type-list {
margin-top: 20upx;
background-color: #fff;
padding-left: 60upx;
.type-item{
height: 120upx;
padding: 20upx 0;
display: flex;
justify-content: space-between;
align-items: center;
padding-right: 60upx;
font-size: 30upx;
position:relative;
}
.icon{
width: 100upx;
font-size: 52upx;
}
.icon-erjiye-yucunkuan {
color: #fe8e2e;
}
.icon-weixinzhifu {
color: #36cb59;
}
.icon-alipay {
color: #01aaef;
}
.tit{
font-size: $font-lg;
color: $font-color-dark;
margin-bottom: 4upx;
}
.con{
flex: 1;
display: flex;
flex-direction: column;
font-size: $font-sm;
color: $font-color-light;
}
}
.mix-btn {
display: flex;
align-items: center;
justify-content: center;
width: 630upx;
height: 80upx;
margin: 80upx auto 30upx;
font-size: $font-lg;
color: #fff;
background-color: $base-color;
border-radius: 10upx;
box-shadow: 1px 2px 5px rgba(219, 63, 96, 0.4);
}
</style>

View File

@@ -0,0 +1,79 @@
<template>
<view class="wrapper" v-show="redBagShow">
<view class="modal-bg" >
</view>
<view class="rb-wrapper">
<view class="rb-content" @click="handleBtn">
</view>
<view class="close" @click="handleClose">
<image src='/static/image/close.png' class="img"></image>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'redBag',
components: {},
props: {
},
data() {
return {
redBagShow: true
}
},
watch: {},
computed: {},
methods: {
handleClose() {
this.redBagShow=false
},
handleBtn() {
this.$emit('click')
this.redBagShow=false
}
},
created() {},
mounted() {}
}
</script>
<style lang="scss" scoped>
.modal-bg {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background: rgba(0, 0, 0, 0.4);
}
.rb-wrapper {
position: absolute;
top: 50%;
left: 50%;
width: 60%;
height: 600upx;
transform: translate3d(-50%, -50%, 0);
background: red;
padding: 40upx;
.rb-content{
height: 100%;
}
.close {
position: absolute;
bottom: -120upx;
left: 50%;
margin-left: -30upx;
width: 60upx;
height: 60upx;
border-radius: 50%;
background: #ddd;
.img {
width: 100%;
height: 100%;
}
}
}
</style>

View File

@@ -0,0 +1,496 @@
<template>
<view class="content">
<view class="body">
<view class="head-body">
<text class="date-head">{{swiperData.year}}{{swiperData.month}}</text>
<view>
<view class='pr40' style="display: inline-block;"><uni-icon type="arrowup" size='26' color='#fff' @click='prevDeta'/></view>
<view style="display: inline-block;"><uni-icon type="arrowdown" size='26' color='#fff' @click='nextDate' /></view>
</view>
</view>
<view class="mian-body">
<!-- 星期 -->
<view class="mian-bolck"> <text></text> </view>
<view class="mian-bolck"> <text></text> </view>
<view class="mian-bolck"> <text></text> </view>
<view class="mian-bolck"> <text></text> </view>
<view class="mian-bolck"> <text></text> </view>
<view class="mian-bolck"> <text></text> </view>
<view class="mian-bolck"> <text></text> </view>
<!-- -->
<view v-for="(val, index) in swiperData.dateDay" class="mian-bolck" :class="val.disable == true ? 'disable' : val.Choice == true ? 'Choice' : ''"
@click="ChoiceDate(index, val.disable)" :key='index'>
<view class="border">
<text class="day">{{val.day}}</text>
<text class="price" v-show="val.priceType">{{val.price == undefined ? '' : val.price}}</text>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import uniIcon from './uni-icon.vue';
export default {
data() {
return {
swiperData: {},
year: '',
month: '',
day: '',
storageDate: []
}
},
props: {
// 当前日期
date: {
type: String,
default: () => {
let _dateData = new Date(),
_date = `${_dateData.getFullYear()}-${_dateData.getMonth() + 1}-${_dateData.getDate()}`
return _date
}
},
// 禁用开始之前日期
startDate: {
type: String,
default: ''
},
// 禁用开始之后日期
endDate: {
type: String,
default: ''
},
// 是否禁用今天之前的日期
disableBefore: {
type: Boolean,
default: false
},
// 价格
price: {
type: Object,
default: () => {
return {type: false, data: []}
}
},
// 是否选择默认日期
isNowDate: {
type: Boolean,
default: true
},
// 单选或多选
singleElection: {
type: Boolean,
default: true
}
},
computed: {
PriceData: {
get() {
return this.price.data
}
}
},
created() {
let dateArr = this.date.split('-')
if (this.date != '' && dateArr.length == 3) {
// 初始化年月日
this.year = Number(dateArr[0])
this.month = Number(dateArr[1])
this.day = Number(dateArr[2])
this.InitializationHomeDate(true).then((val) => {
this.Preprocessing(dateArr)
})
} else {
console.error('error 请检查传入日期是否正确,如: 2019-5-12')
}
},
methods: {
// 是否添加初始化日期
InitializationHomeDate(type) {
// 指定日期
let ThisDate = this.compareDate(this.date)
// 禁用开始时间
let startDate = this.compareDate(this.startDate)
// 禁用结束时间
let endDate = this.compareDate(this.endDate)
// 当前日期
let _date = new Date()
let currDate = this.compareDate(`${_date.getFullYear()}-${_date.getMonth() + 1}-${_date.getDate()}`)
return new Promise((resolve, reject) => {
let judge = (this.disableBefore == false && this.startDate == '' && this.endDate == '') || // 没有任何禁止
(this.disableBefore == true && ThisDate >= currDate) || // 是否禁用今天之前的日期
(ThisDate >= startDate && this.disableBefore == false && this.startDate != '') || // 禁用只有开始时间,没有结束时间
(ThisDate <= endDate && this.disableBefore == false && this.endDate != '') || // 禁用只有结束时间,没有开始时间
(ThisDate <= endDate && this.disableBefore == false && ThisDate >= startDate && this.startDate != '' &&this.endDate != '') // 禁用结束时间,开始时间
if (this.isNowDate == false) {
resolve(true)
return false
} else if (judge && type) {
this.storageDate.push({date: this.date})
}
resolve(true)
})
},
// 时间转换为时间戳
compareDate(s1) {
let curTime = new Date();
//把字符串格式转化为日期类
return s1 ? new Date(s1).valueOf() : false
},
// 上一个月
prevDeta() {
let dateLen = new Date(this.year, this.month - 1, 0).getDate()
this.month = Number(this.month) - 1
if (this.month == 0) {
this.month = 12
this.year = Number(this.year) - 1
}
if (this.month<10){
this.month='0'+this.month;
}
this.Preprocessing([this.year, this.month, this.day])
if (this.price.type) {
this.$emit('changeMonth', [this.year, this.month, dateLen])
}
},
// 下一个月
nextDate() {
let dateLen = new Date(this.year, this.month - 1, 0).getDate()
this.month = 1 + Number(this.month)
if (this.month == 13) {
this.month = 1
this.year = 1 + Number(this.year)
}
if (this.month<10){
this.month='0'+this.month;
}
this.Preprocessing([this.year, this.month, this.day])
if (this.price.type) {
this.$emit('changeMonth', [this.year, this.month, dateLen])
}
},
// 数据发布
ChoiceDate(index, disable) {
let day = this.swiperData.dateDay[index].day
let _Choice = this.swiperData.dateDay[index].Choice
let _date = {}
if (this.price.type == true) {
_date = {date: `${this.swiperData.year}-${this.swiperData.month}-${day}`, price: this.swiperData.dateDay[index].price}
} else {
_date = {date: `${this.swiperData.year}-${this.swiperData.month}-${day}`}
}
if (disable != true) {
// 添加数据
if (JSON.stringify(this.storageDate).indexOf(_date.date) == -1) {
// 单选还是多选
if (this.singleElection == true) {
this.storageDate = []
this.swiperData.dateDay.forEach((val, inde) => {
val.Choice = false
})
// 多选
}
this.storageDate.push(_date)
// 删除数据
} else {
this.storageDate = this.storageDate.filter((val, index) => {
if (val.date != _date.date) {
return val
}
})
}
this.swiperData.dateDay[index].Choice = !_Choice
this.$emit('changeDay', this.storageDate)
}
},
// 日期初始化
Preprocessing(arr) {
let swiperData = {}
this.getDay(`${arr[0]}-${arr[1]}-${arr[2]}`).then((val) => {
swiperData = val
this.$emit('changeDay', this.storageDate)
this.$set(this, 'swiperData', swiperData)
})
},
// 判断当前是 安卓还是ios ,传入不容的日期格式
judgeDate(dateData) {
if (typeof dateData !== 'object') {
dateData = dateData.replace(/-/g, '/')
}
return dateData
},
// 循环上个月末尾几天添加到数组
getDay(dateData) {
dateData = this.judgeDate(dateData)
// 获取年,月,日,星期
let _date = new Date(dateData),
year = _date.getFullYear(),
month = _date.getMonth() + 1,
date = _date.getDate(),
day = _date.getDay()
return new Promise((resolve, reject) => {
//获取上个月末尾几天
let prevDayArr = [],
prevDayLength = new Date(year, month - 1, 1).getDay()
for (let i = prevDayLength; i > 0; i--) {
let prevDay = new Date(year, month - 1, -i + 1).getDate()
prevDayArr.push({
day: prevDay,
disable: true,
Choice: false
})
}
// 获取本月
let thisDayArr = [],
thisDaylength = new Date(year, month - 1, 0).getDate()
for (let i = 1; i <= new Date(year, month, 0).getDate(); i++) {
thisDayArr.push({
day: i,
disable: false,
Choice: false,
price: this.price.data[i-1],
priceType: this.price.type
})
// 重绘已选择日期
this.storageDate.forEach((val, index) => {
let valArr = val.date.split('-');
if (year == valArr[0] && month == valArr[1] && i == valArr[2]) {
thisDayArr[i - 1].Choice = true
val.price = this.price.data[i-1]
}
})
}
// 获取下个月开始几天
let nextDayArr = [],
nextDaylength = 42 - (prevDayArr.length + thisDayArr.length)
for (let i = 1; i < nextDaylength + 1; i++) {
nextDayArr.push({
day: i,
disable: true,
Choice: false
})
}
// 数据合并
let dateShow = []
dateShow = dateShow.concat(prevDayArr, thisDayArr, nextDayArr)
// 禁用今天之前的日期
if (this.disableBefore) {
let __beForeDeta = new Date(),
dDate = `${__beForeDeta.getFullYear()}-${__beForeDeta.getMonth() + 1}-${__beForeDeta.getDate()}`
this.disableDatePrevFn(dateShow, dDate.split('-'), year, month).then((val) => {
resolve({
dateDay: val,
year: year,
month: month
})
})
// 禁用双向指定范围可用
} else if (this.startDate != '' && this.endDate != '') {
let startDateArr = this.startDate.split('-')
let endDateArr = this.endDate.split('-')
if (startDateArr.length == 3 && endDateArr.length == 3) {
this.disableDatePrevFn(dateShow, startDateArr, year, month).then((val) => {
return this.disableDateNextFn(val, endDateArr, year, month)
}).then((val) => {
resolve({
dateDay: val,
year: year,
month: month
})
})
} else if (endDateArr.length != 3) {
console.error('error 日期选择范围-结束日期错误,如: 2019-5-12')
if (startDateArr.length != 3) {
console.error('error 日期选择范围-开始日期错误,如: 2019-5-12')
}
}
// 禁用开始日期之前
} else if (this.startDate != '') {
let startDateArr = this.startDate.split('-')
if (startDateArr.length == 3) {
this.disableDatePrevFn(dateShow, startDateArr, year, month).then((val) => {
resolve({
dateDay: val,
year: year,
month: month
})
})
} else {
console.error('error 日期选择范围-开始日期错误,如: 2019-5-12')
}
// 禁用结束日期之前
} else if (this.endDate != '') {
let endDateArr = this.endDate.split('-')
if (endDateArr.length == 3) {
this.disableDateNextFn(dateShow, endDateArr, year, month).then((val) => {
resolve({
dateDay: val,
year: year,
month: month
})
})
} else {
console.error('error 日期选择范围-结束日期错误,如: 2019-5-12')
}
// 不禁用
} else {
this.disableDatePrevFn(dateShow, new Array(3), year, month).then((val) => {
resolve({
dateDay: val,
year: year,
month: month
})
})
}
})
},
// 禁用指定日期之前的日期
disableDatePrevFn() {
let DateObj = arguments,
dateShow = DateObj[0],
dDate = DateObj[1],
year = DateObj[2],
month = DateObj[3]
return new Promise((resolve, reject) => {
dateShow = dateShow.map((val, index) => {
if (dDate[0] > year) {
val.disable = true
} else if (dDate[1] > month && dDate[0] >= year) {
val.disable = true
} else if (dDate[0] >= year && dDate[2] > val.day && dDate[1] >= month) {
val.disable = true
}
return val
})
resolve(dateShow)
})
},
// 禁用指定日期之后的日期
disableDateNextFn() {
let DateObj = arguments,
dateShow = DateObj[0],
dDate = DateObj[1],
year = DateObj[2],
month = DateObj[3]
return new Promise((resolve, reject) => {
dateShow = dateShow.map((val, index) => {
if (dDate[0] < year) {
val.disable = true
} else if (dDate[0] <= year && dDate[1] < month) {
val.disable = true
} else if (dDate[0] <= year && dDate[1] <= month && dDate[2] < val.day) {
val.disable = true
}
return val
})
resolve(dateShow)
})
},
},
components: {
uniIcon
},
watch: {
'PriceData': {
handler(newData, oldData) {
this.InitializationHomeDate(false).then((val) => {
this.Preprocessing([this.year, this.month, this.day])
})
},
immediate: false,
deep: true
}
}
}
</script>
<style lang="scss" scoped>
.content {
.body {
width: 100%;
background: #000;
.head-body {
display: flex;
flex-direction: row;
height: 41px;
box-sizing: border-box;
padding: 5px 30upx 10px 30upx;
justify-content: space-between;
.date-head {
font-size: 36upx;
color: #fff;
line-height: 26px;
letter-spacing: 1px;
text{
font-size: 36upx;
}
}
.pr40 {
padding-right: 40upx;
}
}
.mian-body {
width: 100%;
height: calc(100% - 46px);
color: #fff;
display: flex;
flex-flow: row wrap;
justify-content: center;
align-items: center;
.mian-bolck {
width: calc(100% / 7 - 10upx);
padding: 8upx 0;
min-height: calc(750upx / 7 - 26upx);
box-sizing: border-box;
font-size: 34upx;
display: flex;
flex-flow: row wrap;
justify-content: center;
align-items: center;
margin: 5upx;
cursor: pointer;
.border {
width: 100%;
height: 100%;
display: flex;
flex-flow: row wrap;
justify-content: center;
align-items: center;
text-align: center;
.price{
font-size: 24upx;
}
.day{
width: 100%;
}
text{
font-size: 36upx;
}
}
}
.disable {
color: #939393;
}
.Choice {
display: flex;
flex-flow: row wrap;
justify-content: center;
align-items: center;
box-sizing: border-box;
background: #0078d7;
}
}
}
}
</style>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,238 @@
<template>
<view v-if="show" class="mask" @click="toggleMask" @touchmove.stop.prevent="stopPrevent" :style="{ backgroundColor: backgroundColor }">
<view
class="mask-content"
@click.stop.prevent="stopPrevent"
:style="[
{
height: config.height,
transform: transform
}
]"
>
<scroll-view class="view-content" show-scrollbar="false" scroll-y>
<view class="share-header">分享到</view>
<view class="share-list">
<view v-for="(item, index) in shareList" :key="index" class="share-item" @click="shareToFriend(item.typeIcon, item.scene, item.provider)">
<image :src="item.icon" mode=""></image>
<text>{{ item.text }}</text>
</view>
</view>
</scroll-view>
<view class="bottom b-t" @click="toggleMask">取消</view>
</view>
</view>
</template>
<script>
var href = null;
var title = null;
var imgUrl = null;
export default {
data() {
return {
transform: 'translateY(50vh)',
timer: 0,
backgroundColor: 'rgba(0,0,0,0)',
show: false,
config: {}
};
},
props: {
contentHeight: {
type: Number,
default: 0
},
//是否是tabbar页面
hasTabbar: {
type: Boolean,
default: false
},
shareList: {
type: Array,
default: function() {
return [];
}
}
},
created() {
const height = uni.upx2px(this.contentHeight) + 'px';
this.config = {
height: height,
transform: `translateY(${height})`,
backgroundColor: 'rgba(0,0,0,.4)'
};
this.transform = this.config.transform;
},
methods: {
toggleMask(title, imgUrl, href) {
this.title = title;
this.imgUrl = imgUrl;
this.href = href;
//防止高频点击
if (this.timer == 1) {
return;
}
this.timer = 1;
setTimeout(() => {
this.timer = 0;
}, 500);
if (this.show) {
this.transform = this.config.transform;
this.backgroundColor = 'rgba(0,0,0,0)';
setTimeout(() => {
this.show = false;
this.hasTabbar && uni.showTabBar();
}, 200);
return;
}
this.show = true;
//等待mask重绘完成执行
if (this.hasTabbar) {
uni.hideTabBar({
success: () => {
setTimeout(() => {
this.backgroundColor = this.config.backgroundColor;
this.transform = 'translateY(0px)';
}, 10);
}
});
} else {
setTimeout(() => {
this.backgroundColor = this.config.backgroundColor;
this.transform = 'translateY(0px)';
}, 10);
}
},
//防止冒泡和滚动穿透
stopPrevent() {},
//分享操作
shareToFriend(type, scene, provider) {
// this.$api.msg(`分享给${type}`);
// this.toggleMask();
var url = this.href;
var title = this.title;
var imgUrl = this.imgUrl;
uni.share({
provider: provider,
scene: scene,
type: type,
href: url,
title: title,
imageUrl: imgUrl,
success: function(res) {
console.log(JSON.stringify(res));
uni.showToast({
title: '已分享',
duration: 2000
});
},
fail: function(err) {
var errrr = JSON.stringify(err);
if (errrr) {
uni.showModal({
success: function(res) {
if (res.confirm) {
console.log('用户点击确定');
} else if (res.cancel) {
console.log('用户点击取消');
}
}
});
}
}
});
this.toggleMask();
}
}
};
</script>
<style lang="scss">
.mask {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
display: flex;
justify-content: center;
align-items: flex-end;
z-index: 998;
transition: 0.3s;
.bottom {
position: absolute;
left: 0;
bottom: 0;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 90upx;
background: #fff;
z-index: 9;
font-size: $font-base + 2upx;
color: $font-color-dark;
}
}
.mask-content {
width: 100%;
height: 580upx;
transition: 0.3s;
background: #fff;
&.has-bottom {
padding-bottom: 90upx;
}
.view-content {
height: 100%;
background: #ffffff;
}
}
.share-header {
height: 110upx;
font-size: $font-base + 2upx;
color: font-color-dark;
display: flex;
align-items: center;
justify-content: center;
padding-top: 10upx;
&:before,
&:after {
content: '';
width: 240upx;
heighg: 0;
border-top: 1px solid $border-color-base;
transform: scaleY(0.5);
margin-right: 30upx;
}
&:after {
margin-left: 30upx;
margin-right: 0;
}
}
.share-list {
display: flex;
flex-wrap: wrap;
}
.share-item {
min-width: 33.33%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 180upx;
image {
width: 80upx;
height: 80upx;
margin-bottom: 16upx;
}
text {
font-size: $font-base;
color: $font-color-base;
}
}
</style>

View File

@@ -0,0 +1,205 @@
<template>
<view class="dateContent">
<view class="line"></view>
<view v-for="(item,key) in dateList" :class="{'item':true, 'item-checked': key==nowIndex, 'item-close': !item.isActive}" :key="key" @click="choseTime(item,key)">
<!--<view class="value">{{item.value}}</view>-->
<view class="circle"></view>
<view class="week">{{item.name}}</view>
</view>
</view>
</template>
<script>
export default {
props: {
type: {
type: String,
default: 'month'
}
},
computed: {
dateList() {
var arr = this.getArr(this.type)
return arr
}
},
data() {
return {
nowIndex: 6
}
},
methods: {
getArr(type) {
var timeArr = []
if(type == 'month'){
timeArr = [
{
name: '6月前',
isActive: true,
checked: false,
value: -6
},
{
name: '5月前',
isActive: true,
checked: false,
value: -5
},
{
name: '4月前',
isActive: true,
checked: false,
value: -4
},
{
name: '3月前',
isActive: true,
checked: false,
value: -3
},
{
name: '2月前',
isActive: true,
checked: false,
value: -2
},
{
name: '上月',
isActive: true,
checked: false,
value: -1
},
{
name: '本月',
isActive: true,
checked: true,
value: 0
}
]
}
if(type == 'day'){
timeArr = [
{
name: '6天前',
isActive: true,
checked: false,
value: -6
},
{
name: '5天前',
isActive: true,
checked: false,
value: -5
},
{
name: '4天前',
isActive: true,
checked: false,
value: -4
},
{
name: '3天前',
isActive: true,
checked: false,
value: -3
},
{
name: '2天前',
isActive: true,
checked: false,
value: -2
},
{
name: '昨天',
isActive: true,
checked: false,
value: -1
},
{
name: '今天',
isActive: true,
checked: true,
value: 0
}
]
}
return timeArr;
},
getMonth(month) {
var time = new Date();
time.setMonth(time.getMonth() + month);//设置month月后的时间
var y = time.getFullYear();
var m = time.getMonth() + 1;//获取当前月份
var d = time.getDate();
if(m<10){
m = "0"+m
}
return y + "-" + m ;
},
addDate(days) {
var d = new Date();
d.setDate(d.getDate() + days);
var m = d.getMonth() + 1;
if(m < 10){
m='0'+m
}
var day = d.getDate()
if(day < 10){
day='0'+day
}
return d.getFullYear() + '-' + m + '-' + day;
},
choseTime(item, index) {
this.$emit('chooseTime', item)
this.nowIndex = index
}
}
}
</script>
<style lang="scss">
.dateContent{
background: $uni-bg-color;
display: flex;
flex-direction: row;
padding: 18upx 6upx 4upx 6upx;
.item{
z-index: 9;
color: $uni-text-color-grey;
flex: 1;
text-align: center;
padding-bottom: 12upx;
&-checked{
color: #3FC0A2;
font-weight: bolder;
.circle{
background-color: #3FC0A2!important;
}
}
&-close{
color: $uni-text-color-grey;
}
.week{
margin-top: 4upx;
font-size: $uni-font-size-base;
}
.circle{
width: 18upx;
height: 18upx;
border-radius: 50%;
border:1px solid #ebedf0;
margin: 20upx auto ;
background-color: $uni-bg-color;
}
}
.line{
position: absolute;
top: 47upx;
width: 94%;
left: 3%;
height: 4upx;
background-color: #ebedf0;
}
}
</style>

View File

@@ -0,0 +1,165 @@
<template>
<canvas v-if="canvasId" :id="canvasId" :canvasId="canvasId" :style="{'width':cWidth*pixelRatio+'px','height':cHeight*pixelRatio+'px', 'transform': 'scale('+(1/pixelRatio)+')','margin-left':-cWidth*(pixelRatio-1)/2+'px','margin-top':-cHeight*(pixelRatio-1)/2+'px'}"
@touchstart="touchStart" @touchmove="touchMove" @touchend="touchEnd" @error="error">
</canvas>
</template>
<script>
import uCharts from './u-charts.js';
var canvases = {};
export default {
props: {
chartType: {
required: true,
type: String,
default: 'column'
},
opts: {
required: true,
type: Object,
default () {
return null;
},
},
canvasId: {
type: String,
default: 'u-canvas',
},
cWidth: {
default: 375,
},
cHeight: {
default: 250,
},
pixelRatio: {
type: Number,
default: 1,
},
},
mounted() {
this.init();
},
methods: {
init() {
switch (this.chartType) {
case 'column':
this.initColumnChart();
break;
case 'line':
this.initLineChart();
break;
default:
break;
}
},
initColumnChart() {
canvases[this.canvasId] = new uCharts({
$this: this,
canvasId: this.canvasId,
type: 'column',
legend: true,
fontSize: 11,
background: '#FFFFFF',
pixelRatio: this.pixelRatio,
animation: true,
categories: this.opts.categories,
series: this.opts.series,
enableScroll: true,
xAxis: {
disableGrid: true,
itemCount: 4,
scrollShow: true
},
yAxis: {
//disabled:true
},
dataLabel: true,
width: this.cWidth * this.pixelRatio,
height: this.cHeight * this.pixelRatio,
extra: {
column: {
type: 'group',
}
}
});
},
initLineChart() {
canvases[this.canvasId] = new uCharts({
$this: this,
canvasId: this.canvasId,
type: 'line',
fontSize: 11,
legend: true,
dataLabel: false,
dataPointShape: true,
background: '#FFFFFF',
pixelRatio: this.pixelRatio,
categories: this.opts.categories,
series: this.opts.series,
animation: true,
enableScroll: true,
xAxis: {
type: 'grid',
gridColor: '#CCCCCC',
gridType: 'dash',
dashLength: 8,
itemCount: 4,
scrollShow: true
},
yAxis: {
gridType: 'dash',
gridColor: '#CCCCCC',
dashLength: 8,
splitNumber: 5,
min: 10,
max: 180,
format: (val) => {
return val.toFixed(0) + '元'
}
},
width: this.cWidth * this.pixelRatio,
height: this.cHeight * this.pixelRatio,
extra: {
line: {
type: 'straight'
}
}
});
},
// 这里仅作为示例传入两个参数cid为canvas-id,newdata为更新的数据需要更多参数请自行修改
changeData(cid,newdata) {
canvases[cid].updateData({
series: newdata.series,
categories: newdata.categories
});
},
touchStart(e) {
canvases[this.canvasId].showToolTip(e, {
format: function(item, category) {
return category + ' ' + item.name + ':' + item.data
}
});
canvases[this.canvasId].scrollStart(e);
},
touchMove(e) {
canvases[this.canvasId].scroll(e);
},
touchEnd(e) {
canvases[this.canvasId].scrollEnd(e);
},
error(e) {
console.log(e)
}
},
};
</script>
<style scoped>
.charts {
width: 100%;
height: 100%;
flex: 1;
background-color: #FFFFFF;
}
</style>

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,101 @@
<template>
<text v-if="text" :class="inverted ? 'uni-badge-' + type + ' uni-badge--' + size + ' uni-badge-inverted' : 'uni-badge-' + type + ' uni-badge--' + size"
class="uni-badge" @click="onClick()">{{ text }}</text>
</template>
<script>
export default {
name: 'UniBadge',
props: {
type: {
type: String,
default: 'default'
},
inverted: {
type: Boolean,
default: false
},
text: {
type: String,
default: ''
},
size: { // small.normal
type: String,
default: 'normal'
}
},
methods: {
onClick() {
this.$emit('click')
}
}
}
</script>
<style lang="scss">
$bage-size:12px;
$bage-small:scale(0.8);
.uni-badge {
font-family: 'Helvetica Neue', Helvetica, sans-serif;
box-sizing: border-box;
font-size: $bage-size;
line-height: 1;
display: inline-block;
padding: 3px 6px;
color: $uni-text-color;
border-radius: 100px;
background-color: $uni-bg-color-hover;
&.uni-badge-inverted {
padding: 0 5px 0 0;
color: $uni-text-color-grey;
background-color: transparent;
}
&-primary {
color: $uni-text-color-inverse;
background-color: $uni-color-primary;
&.uni-badge-inverted {
color: $uni-color-primary;
background-color: transparent
}
}
&-success {
color: $uni-text-color-inverse;
background-color: $uni-color-success;
&.uni-badge-inverted {
color: $uni-color-success;
background-color: transparent
}
}
&-warning {
color: $uni-text-color-inverse;
background-color: $uni-color-warning;
&.uni-badge-inverted {
color: $uni-color-warning;
background-color: transparent
}
}
&-error {
color: $uni-text-color-inverse;
background-color: $uni-color-error;
&.uni-badge-inverted {
color: $uni-color-error;
background-color: transparent
}
}
&--small {
transform: $bage-small;
transform-origin: center center;
}
}
</style>

View File

@@ -0,0 +1,73 @@
### CountDown 倒计时
倒计时组件,组件名:``uni-countdown``,代码块: uCountDown。
**使用方式:**
在 ``script`` 中引用组件
```javascript
import uniCountdown from "@/components/uni-countdown/uni-countdown.vue"
export default {
components: {uniCountdown}
}
```
一般用法
```html
<uni-countdown
:day="1"
:hour="1"
:minute="12"
:second="40">
</uni-countdown>
```
不显示天数
```html
<uni-countdown
:show-day="false"
:hour="12"
:minute="12"
:second="12">
</uni-countdown>
```
修改颜色
```html
<uni-countdown
color="#FFFFFF"
background-color="#00B26A"
border-color="#00B26A"
:day="1"
:hour="2"
:minute="30"
:second="0">
</uni-countdown>
```
实际效果参考:[https://github.com/dcloudio/uni-ui](https://github.com/dcloudio/uni-ui)
**uniCountDown 属性说明:**
|属性名|类型|默认值 |说明|
|---|----|---|---|
|background-color|String|#FFFFFF|背景色|
|border-color|String|#000000|边框颜色|
|color |String |#000000|文字颜色|
|splitor-color|String|#000000|割符号颜色|
|day|Number|0|天数|
|hour|Number|0|小时|
|minute|Number|0|分钟|
|second|Number|0|秒|
|show-day|Boolean|true|是否显示天数|
|show-colon|Boolean|true|是否以冒号为分隔符|
**uniCountDown 事件说明:**
|事件称名|说明|返回参数|
|---|----|---|
|timeup|倒计时时间到触发事件|-|

View File

@@ -0,0 +1,156 @@
<template>
<view class="uni-countdown">
<view v-if="showDay && d!=0" class="uni-countdown__number" :style="{borderColor:borderColor, color:color, background:backgroundColor}">{{d}}</view>
<view v-if="showDay && d!=0" class="uni-countdown__splitor" :style="{color:textColor}"></view>
<view class="uni-countdown__number" :style="{borderColor:borderColor, color:color, background:backgroundColor}">{{h}}</view>
<view class="uni-countdown__splitor" :style="{color:textColor}">{{showColon ? ':' : '时'}}</view>
<view class="uni-countdown__number" :style="{borderColor:borderColor, color:color, background:backgroundColor}">{{i}}</view>
<view class="uni-countdown__splitor" :style="{color:textColor}">{{showColon ? ':' : '分'}}</view>
<view class="uni-countdown__number" :style="{borderColor:borderColor, color:color, background:backgroundColor}">{{s}}</view>
<view v-if="!showColon" class="uni-countdown__splitor" :style="{color:textColor}"></view>
</view>
</template>
<script>
export default {
name: "uni-countdown",
props: {
showDay: {
type: Boolean,
default: true
},
showColon: {
type: Boolean,
default: true
},
backgroundColor: {
type: String,
default: "#FFFFFF"
},
borderColor: {
type: String,
default: "#000000"
},
color: {
type: String,
// value: "#000000"
},
textColor: {
type: String,
default: "#000000"
},
splitorColor: {
type: String,
default: "#000"
},
day: {
type: Number,
default: 0
},
hour: {
type: Number,
default: 0
},
minute: {
type: Number,
default: 0
},
second: {
type: Number,
default: 0
}
},
data() {
return {
timer: null,
d: '00',
h: '00',
i: '00',
s: '00',
leftTime: 0,
seconds: 0
}
},
created: function(e) {
this.seconds = this.toSeconds(this.day, this.hour, this.minute, this.second)
this.countDown()
this.timer = setInterval(() => {
this.seconds--
if (this.seconds < 0) {
this.timeUp()
return
}
this.countDown()
}, 1000)
},
beforeDestroy() {
clearInterval(this.timer)
},
methods: {
toSeconds(day, hours, minutes, seconds) {
return (day * 60 * 60 * 24) + (hours * 60 * 60) + (minutes * 60) + seconds
},
timeUp() {
clearInterval(this.timer)
this.$emit('timeup')
},
countDown() {
let seconds = this.seconds
let [day, hour, minute, second] = [0, 0, 0, 0]
if (seconds > 0) {
day = Math.floor(seconds / (60 * 60 * 24))
hour = Math.floor(seconds / (60 * 60)) - (day * 24)
minute = Math.floor(seconds / 60) - (day * 24 * 60) - (hour * 60)
second = Math.floor(seconds) - (day * 24 * 60 * 60) - (hour * 60 * 60) - (minute * 60)
} else {
this.timeUp()
}
if (day < 10) {
day = '0' + day
}
if (hour < 10) {
hour = '0' + hour
}
if (minute < 10) {
minute = '0' + minute
}
if (second < 10) {
second = '0' + second
}
this.d = day
this.h = hour
this.i = minute
this.s = second
}
}
}
</script>
<style lang="scss">
$countdown-height:44upx;
.uni-countdown {
padding: 2upx 0;
display: inline-flex;
flex-wrap: nowrap;
justify-content: center;
&__splitor {
justify-content: center;
line-height: $countdown-height;
padding: 0 5upx;
font-size: 24upx;
// color: #d0d0d0;
}
&__number {
line-height: $countdown-height;
justify-content: center;
height: $countdown-height;
border-radius: $uni-border-radius-base;
// margin: 0 5upx;
font-size: 24upx;
// border: 1px solid #000000;
font-size: $uni-font-size-sm;
// padding: 0 10upx;
}
}
</style>

View File

@@ -0,0 +1,239 @@
<template>
<view
v-if="width"
:style="{ width: width }"
class="uni-grid-item">
<view
:class="{ border: showBorder, 'uni-grid-item__box-square': square, 'border-top': showBorder && index < column, 'uni-highlight': highlight }"
:style="{ 'border-color': borderColor }"
class="uni-grid-item__box"
@click="_onClick"
>
<view
v-if="marker === 'dot'"
:style="{ left: top + 'px', top: left + 'px' }"
class="uni-grid-item__box-dot" />
<view
v-if="marker === 'badge'"
:style="{ left: top + 'px', top: left + 'px' }"
class="uni-grid-item__box-badge">
<uni-badge
:text="text"
:type="type"
:size="size"
:inverted="inverted" />
</view>
<view
v-if="marker === 'image'"
:style="{ left: top + 'px', top: left + 'px' }"
class="uni-grid-item__box-image">
<image
:style="{ width: imgWidth + 'px' }"
:src="src"
class="box-image"
mode="widthFix" />
</view>
<view class="uni-grid-item__box-item"><slot /></view>
</view>
</view>
</template>
<script>
import uniBadge from '@/components/uni-badge/uni-badge.vue'
export default {
name: 'UniGridItem',
components: { uniBadge },
props: {
// 类型可选值dot圆点badge角标image图片
marker: {
type: String,
default: ''
},
// 水平方向
hor: {
type: Number,
default: 0
},
// 垂直方向
ver: {
type: Number,
default: 0
},
// badge 下颜色类型可选值default灰色、primary蓝色、success绿色、warning(黄色)、error(红色)
type: {
type: String,
default: ''
},
// badge 下显示内容汉字最多为1个
text: {
type: String,
default: ''
},
// badge 下 Badge 大小
size: {
type: String,
default: 'normal'
},
// badge 下 是否无需背景颜色
inverted: {
type: Boolean,
default: false
},
// image 下图片路径
src: {
type: String,
default: ''
},
// image 下图片宽度 ,最大 为 100 。 默认为 30
imgWidth: {
type: Number,
default: 30
}
},
inject: ['grid'],
data () {
return {
column: 0,
showBorder: true,
square: true,
highlight: true,
left: 0,
top: 0,
index: 0,
openNum: 2,
width: 0,
borderColor: '#d0dee5'
}
},
created () {
this.column = this.grid.column
this.showBorder = this.grid.showBorder
this.square = this.grid.square
this.highlight = this.grid.highlight
this.top = this.hor === 0 ? this.grid.hor : this.hor
this.left = this.ver === 0 ? this.grid.ver : this.ver
this.borderColor = this.grid.borderColor
this.index = this.grid.index++
},
// #ifdef H5
mounted () {
this.grid._getSize(width => {
this.width = width
})
},
// #endif
// #ifndef H5
onReady () {
this.grid._getSize(width => {
this.width = width
})
},
// #endif
methods: {
_onClick () {
// console.log('点击', this.index);
this.grid.change({ detail: { index: this.index } })
}
}
}
</script>
<style lang="scss">
.uni-grid-item {
box-sizing: border-box;
&__box {
position: relative;
width: 100%;
// overflow: hidden;
&-item {
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
width: 100%;
height: 100%;
font-size: 32upx;
color: #666;
padding: 20upx 0;
box-sizing: border-box;
.image {
width: 50upx;
height: 50upx;
}
.text {
font-size: 26upx;
margin-top: 10upx;
}
}
&.uni-grid-item__box-square {
height: 0;
padding-top: 100%;
& .uni-grid-item__box-item {
position: absolute;
top: 0;
}
}
&.border {
position: relative;
box-sizing: border-box;
// box-shadow: 0 0 0 1px #d0dee5;
// border-left: 1px #d0dee5 solid;
border-bottom: 1px #d0dee5 solid;
border-right: 1px #d0dee5 solid;
// &::after {
// content: '';
// position: absolute;
// top: 0%;
// bottom: 0%;
// left: 0%;
// right: 0%;
// border-right: 1px #d0dee5 solid;
// border-bottom: 1px #d0dee5 solid;
// }
}
&.border-top {
border-top: 1px #d0dee5 solid;
}
&.uni-highlight:active {
background-color: #eee;
}
&-dot,
&-badge,
&-image {
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
margin: auto;
z-index: 10;
}
&-dot {
width: 20upx;
height: 20upx;
background: #ff5a5f;
border-radius: 50%;
}
&-badge {
display: flex;
justify-content: center;
align-items: center;
width: 0;
height: 0;
}
&-image {
display: flex;
justify-content: center;
align-items: center;
width: 100upx;
height: 100upx;
overflow: hidden;
.box-image {
width: 90upx;
// height: 100upx;
}
}
}
}
</style>

View File

@@ -0,0 +1,96 @@
<template>
<view>
<view
:id="elId"
:class="{ border: showBorder }"
:style="{ 'border-left': showBorder ? '1px ' + borderColor + ' solid' : 'none' }"
class="uni-grid"><slot /></view>
</view>
</template>
<script>
export default {
name: 'UniGrid',
props: {
// 每列显示个数
column: {
type: Number,
default: 3
},
// 是否显示边框
showBorder: {
type: Boolean,
default: true
},
// 是否显示边框
borderColor: {
type: String,
default: '#d0dee5'
},
// 全局标记水平方向移动距离 ,起点为中心,负数为左移动,正数为右移动
hor: {
type: Number,
default: 0
},
// 全局标记垂直方向移动距离 ,起点为中心,负数为上移动,正数为下移动
ver: {
type: Number,
default: 0
},
// 是否正方形显示,默认为 true
square: {
type: Boolean,
default: true
},
highlight: {
type: Boolean,
default: true
}
},
provide () {
return {
grid: this
}
},
data () {
const elId = `Uni_${Math.ceil(Math.random() * 10e5).toString(36)}`
return {
index: 0,
elId
}
},
created () {
this.index = 0
this.childrens = []
this.pIndex = this.pIndex ? this.pIndex++ : 0
},
methods: {
change (e) {
this.$emit('change', e)
},
_getSize (fn) {
uni.createSelectorQuery()
.in(this)
.select(`#${this.elId}`)
.boundingClientRect()
.exec(ret => {
if (!ret[0]) {
setTimeout(this._getSize(fn))
return
}
let width = parseInt(ret[0].width / this.column) - 1 + 'px'
typeof fn === 'function' && fn(width)
})
}
}
}
</script>
<style lang="scss">
.uni-grid {
display: flex;
flex-wrap: wrap;
box-sizing: border-box;
border-left: 1px #d0dee5 solid;
}
</style>

View File

@@ -0,0 +1,127 @@
### Icon 图标
用于展示 icon组件名``uni-icon``,代码块: uIcon。
**使用方式:**
在 ``script`` 中引用组件
```javascript
import uniIcon from "@/components/uni-icon/uni-icon.vue"
export default {
components: {uniIcon}
}
```
在 ``template`` 中使用组件
```html
<uni-icon type="contact" size="30"></uni-icon>
```
实际效果参考:[https://github.com/dcloudio/uni-ui](https://github.com/dcloudio/uni-ui)
**Icon 属性说明:**
|属性名 |类型|默认值 |说明|
|---|----|---|---|
|type |String |-|图标图案,参考下表|
|color |String |-|图标颜色 |
|size |Number |24|图标大小|
|@click |EventHandle|-|点击 Icon 触发事件|
**type 类型:**
<div>
<link rel="stylesheet" type="text/css" href="https://img-cdn-qiniu.dcloud.net.cn/uniapp/doc/icon1.1.css"/>
<ul class="icon-group">
<li class="icon-item"><span class="uni-icon uni-icon-contact"></span><span>contact</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-person"></span><span>person</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-personadd"></span><span>personadd</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-contact-filled"></span><span>contact-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-person-filled"></span><span>person-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-personadd-filled"></span><span>personadd-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-phone"></span><span>phone</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-email"></span><span>email</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-chatbubble"></span><span>chatbubble</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-chatboxes"></span><span>chatboxes</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-phone-filled"></span><span>phone-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-email-filled"></span><span>email-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-chatbubble-filled"></span><span>chatbubble-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-chatboxes-filled"></span><span>chatboxes-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-weibo"></span><span>weibo</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-weixin"></span><span>weixin</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-pengyouquan"></span><span>pengyouquan</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-chat"></span><span>chat</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-qq"></span><span>qq</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-videocam"></span><span>videocam</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-camera"></span><span>camera</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-mic"></span><span>mic</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-location"></span><span>location</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-mic-filled"></span><span>mic-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-location-filled"></span><span>location-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-micoff"></span><span>micoff</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-image"></span><span>image</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-map"></span><span>map</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-compose"></span><span>compose</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-trash"></span><span>trash</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-upload"></span><span>upload</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-download"></span><span>download</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-close"></span><span>close</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-redo"></span><span>redo</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-undo"></span><span>undo</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-refresh"></span><span>refresh</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-star"></span><span>star</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-plus"></span><span>plus</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-minus"></span><span>minus</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-circle"></span><span>circle</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-clear"></span><span>clear</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-refresh-filled"></span><span>refresh-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-star-filled"></span><span>star-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-plus-filled"></span><span>plus-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-minus-filled"></span><span>minus-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-circle-filled"></span><span>circle-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-checkbox-filled"></span><span>checkbox-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-closeempty"></span><span>closeempty</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-refreshempty"></span><span>refreshempty</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-reload"></span><span>reload</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-starhalf"></span><span>starhalf</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-spinner"></span><span>spinner</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-spinner-cycle"></span><span>spinner-cycle</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-search"></span><span>search</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-plusempty"></span><span>plusempty</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-forward"></span><span>forward</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-back"></span><span>back</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-checkmarkempty"></span><span>checkmarkempty</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-home"></span><span>home</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-navigate"></span><span>navigate</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-gear"></span><span>gear</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-paperplane"></span><span>paperplane</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-info"></span><span>info</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-help"></span><span>help</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-locked"></span><span>locked</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-more"></span><span>more</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-flag"></span><span>flag</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-home-filled"></span><span>home-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-gear-filled"></span><span>gear-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-info-filled"></span><span>info-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-help-filled"></span><span>help-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-more-filled"></span><span>more-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-settings"></span><span>settings</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-list"></span><span>list</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-bars"></span><span>bars</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-loop"></span><span>loop</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-paperclip"></span><span>paperclip</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-eye"></span><span>eye</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-arrowup"></span><span>arrowup</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-arrowdown"></span><span>arrowdown</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-arrowleft"></span><span>arrowleft</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-arrowright"></span><span>arrowright</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-arrowthinup"></span><span>arrowthinup</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-arrowthindown"></span><span>arrowthindown</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-arrowthinleft"></span><span>arrowthinleft</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-arrowthinright"></span><span>arrowthinright</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-pulldown"></span><span>pulldown</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-scan"></span><span>scan</span></li>
</ul>
</div>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,194 @@
<template>
<view class="uni-load-more">
<view class="uni-load-more__img" v-show="status === 'loading' && showIcon">
<view class="load1">
<view :style="{background:color}"></view>
<view :style="{background:color}"></view>
<view :style="{background:color}"></view>
<view :style="{background:color}"></view>
</view>
<view class="load2">
<view :style="{background:color}"></view>
<view :style="{background:color}"></view>
<view :style="{background:color}"></view>
<view :style="{background:color}"></view>
</view>
<view class="load3">
<view :style="{background:color}"></view>
<view :style="{background:color}"></view>
<view :style="{background:color}"></view>
<view :style="{background:color}"></view>
</view>
</view>
<text class="uni-load-more__text" :style="{color:color}">{{status === 'more' ? contentText.contentdown : (status === 'loading' ? contentText.contentrefresh : contentText.contentnomore)}}</text>
</view>
</template>
<script>
export default {
name: "uni-load-more",
props: {
status: {
//上拉的状态more-loading前loading-loading中noMore-没有更多了
type: String,
default: 'more'
},
showIcon: {
type: Boolean,
default: true
},
color: {
type: String,
default: "#777777"
},
contentText: {
type: Object,
default () {
return {
contentdown: "上拉显示更多",
contentrefresh: "正在加载...",
contentnomore: "没有更多数据了"
};
}
}
},
data() {
return {}
}
}
</script>
<style>
@charset "UTF-8";
.uni-load-more {
display: flex;
flex-direction: row;
height: 80upx;
align-items: center;
justify-content: center
}
.uni-load-more__text {
font-size: 28upx;
color: #999
}
.uni-load-more__img {
height: 24px;
width: 24px;
margin-right: 10px
}
.uni-load-more__img>view {
position: absolute
}
.uni-load-more__img>view view {
width: 6px;
height: 2px;
border-top-left-radius: 1px;
border-bottom-left-radius: 1px;
background: #999;
position: absolute;
opacity: .2;
transform-origin: 50%;
animation: load 1.56s ease infinite
}
.uni-load-more__img>view view:nth-child(1) {
transform: rotate(90deg);
top: 2px;
left: 9px
}
.uni-load-more__img>view view:nth-child(2) {
transform: rotate(180deg);
top: 11px;
right: 0
}
.uni-load-more__img>view view:nth-child(3) {
transform: rotate(270deg);
bottom: 2px;
left: 9px
}
.uni-load-more__img>view view:nth-child(4) {
top: 11px;
left: 0
}
.load1,
.load2,
.load3 {
height: 24px;
width: 24px
}
.load2 {
transform: rotate(30deg)
}
.load3 {
transform: rotate(60deg)
}
.load1 view:nth-child(1) {
animation-delay: 0s
}
.load2 view:nth-child(1) {
animation-delay: .13s
}
.load3 view:nth-child(1) {
animation-delay: .26s
}
.load1 view:nth-child(2) {
animation-delay: .39s
}
.load2 view:nth-child(2) {
animation-delay: .52s
}
.load3 view:nth-child(2) {
animation-delay: .65s
}
.load1 view:nth-child(3) {
animation-delay: .78s
}
.load2 view:nth-child(3) {
animation-delay: .91s
}
.load3 view:nth-child(3) {
animation-delay: 1.04s
}
.load1 view:nth-child(4) {
animation-delay: 1.17s
}
.load2 view:nth-child(4) {
animation-delay: 1.3s
}
.load3 view:nth-child(4) {
animation-delay: 1.43s
}
@-webkit-keyframes load {
0% {
opacity: 1
}
100% {
opacity: .2
}
}
</style>

View File

@@ -0,0 +1,199 @@
<template>
<view class="uni-numbox">
<view class="uni-numbox-minus"
@click="_calcValue('subtract')"
>
<text class="yticon icon--jianhao" :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="yticon icon-jia2" :class="maxDisabled?'uni-numbox-disabled': ''" ></text>
</view>
</view>
</template>
<script>
export default {
name: 'uni-number-box',
props: {
isMax: {
type: Boolean,
default: false
},
isMin: {
type: Boolean,
default: false
},
index: {
type: Number,
default: 0
},
value: {
type: Number,
default: 0
},
min: {
type: Number,
default: -Infinity
},
max: {
type: Number,
default: Infinity
},
step: {
type: Number,
default: 1
},
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
}
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){
newValue = this.max
}
if(newValue > this.min && this.minDisabled === true){
this.minDisabled = false;
}
}
if(newValue === value){
return;
}
this.inputValue = newValue / scale;
},
_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:230upx;
height: 70upx;
background:#f5f5f5;
}
.uni-numbox-minus,
.uni-numbox-plus {
margin: 0;
background-color: #f5f5f5;
width: 70upx;
height: 100%;
line-height: 70upx;
text-align: center;
position: relative;
}
.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>

View File

@@ -0,0 +1,59 @@
### Rate 评分
评分组件,组件名:``uni-rate``,代码块: uRate。
**使用方式:**
在 ``script`` 中引用组件
```javascript
import uniRate from "@/components/uni-rate/uni-rate.vue"
export default {
components: {uniRate}
}
```
基本用法
```html
<uni-rate value="2"></uni-rate>
```
自定义星星大小
```html
<uni-rate size="18" value="5"></uni-rate>
```
设置评分数
```html
<uni-rate max="10" value="5"></uni-rate>
```
不可点击状态
```html
<uni-rate disabled="true" value="3.5"></uni-rate>
```
实际效果参考:[https://github.com/dcloudio/uni-ui](https://github.com/dcloudio/uni-ui)
**属性说明:**
|属性名|类型|默认值 |说明|
|---|----|---|---|
|value|Number|0|当前评分|
|max|Number|5|最大的评分|
|size|Number|24|星星的大小|
|margin|Number|0|星星的间距|
|color|String|#ececec|星星的颜色|
|active-color|String|#ffca3e|选中状态的星星的颜色|
|is-fill|Boolean|true|星星的类型,是否为实心类型|
|disabled|Boolean|false|是否为不可点击状态|
**事件说明:**
|事件称名|说明|返回参数|
|---|----|---|
|change|Rate 的 value 改变时触发事件返回参数为Rate的value|{value:Number}|

Some files were not shown because too many files have changed in this diff Show More