chore(组件): 全部使用easycom来处理组件问题
This commit is contained in:
@@ -357,14 +357,10 @@
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import nsLoading from '@/components/ns-loading/ns-loading.vue'
|
||||
import aiService from '@/common/js/ai-service.js'
|
||||
|
||||
export default {
|
||||
name: 'ai-chat-message',
|
||||
components: {
|
||||
nsLoading
|
||||
},
|
||||
props: {
|
||||
// 初始消息列表
|
||||
initialMessages: {
|
||||
|
||||
332
components/chat-message/chat-message.vue
Normal file
332
components/chat-message/chat-message.vue
Normal file
@@ -0,0 +1,332 @@
|
||||
<template>
|
||||
<view class="chat-message">
|
||||
<block v-if="message.contentType == 'sendGood'">
|
||||
<ns-chat-goods :skuId="message.sku_id" :goodsDetail="message.goodsDetail" @sendMsg="sendGood"></ns-chat-goods>
|
||||
</block>
|
||||
<block v-if="message.contentType == 'sendOrder'">
|
||||
<ns-chat-order :orderId="message.order_id" :orderdetails="message.orderDetail" @sendMsg="sendOrder"></ns-chat-order>
|
||||
</block>
|
||||
<block v-if="message.contentType == 'goodssku'">
|
||||
<ns-chat-receiveGoods :skuId="message.sku_id"></ns-chat-receiveGoods>
|
||||
</block>
|
||||
<view class="message" v-if="message.contentType == 'string'">
|
||||
<view class="message-item " :class="message.isItMe ? 'right' : 'left'">
|
||||
<block v-if="message.isItMe">
|
||||
<view class="head_img">
|
||||
<image class="img" :src="myHeadImg" v-if="myHeadImg" @error="myHeadImgError" mode="aspectFit"/>
|
||||
<image class="img" :src="defaultHead" mode="aspectFit" v-else/>
|
||||
</view>
|
||||
</block>
|
||||
<block v-else>
|
||||
<view class="head_img">
|
||||
<image class="img" :src="avatar" mode="aspectFit" v-if="avatar"></image>
|
||||
<image class="img" :src="defaultHead" mode="aspectFit" v-else></image>
|
||||
</view>
|
||||
</block>
|
||||
<view class="chat_text">
|
||||
<text class="iconfont icon-warn margin-right color-base-text" v-if="message.isItMe && !message.sendStatus"></text>
|
||||
<view class="content"><rich-text :nodes="stringToEmjoy(message.content)"></rich-text></view>
|
||||
<!-- <text class="iconfont icon-warn margin-left" v-if="!message.isItMe && !message.sendStatus"></text> -->
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="message" v-if="message.contentType == 'image'">
|
||||
<view class="message-item " :class="message.isItMe ? 'right' : 'left'">
|
||||
<block v-if="message.isItMe">
|
||||
<view class="head_img">
|
||||
<image class="img" :src="myHeadImg" v-if="myHeadImg" mode="aspectFit"></image>
|
||||
<image class="img" :src="defaultHead" mode="aspectFit" v-else></image>
|
||||
</view>
|
||||
</block>
|
||||
<block v-else>
|
||||
<view class="head_img">
|
||||
<image class="img" :src="avatar" mode="aspectFit" v-if="avatar"></image>
|
||||
<image class="img" :src="defaultHead" mode="aspectFit" v-else></image>
|
||||
</view>
|
||||
</block>
|
||||
<view class="chat_img">
|
||||
<text class="iconfont icon-warn margin-right color-base-text" v-if="message.isItMe && !message.sendStatus"></text>
|
||||
<view class="content_img" @click="previewMedia($util.img(message.image))" :style="{ backgroundImage: 'url(' + $util.img(message.image) + ')' }">
|
||||
<!-- <image class="img_img" :src="$util.img(message.image)" mode="aspectFit"></image> -->
|
||||
</view>
|
||||
<!-- <text class="iconfont icon-warn margin-left" v-if="!message.isItMe && !message.sendStatus"></text> -->
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else-if="message.contentType == 'goods'"><ns-chat-goods :isCanSend="false" :skuId="message.sku_id"></ns-chat-goods></view>
|
||||
<view v-else-if="message.contentType == 'order'"><ns-chat-order :isCanSend="false" :orderId="message.order_id"></ns-chat-order></view>
|
||||
|
||||
<view class="no-connect-box" v-if="message.contentType == 'noline'">
|
||||
<view class="no-connect">客服不在线</view>
|
||||
</view>
|
||||
<view class="no-connect-box" v-if="message.contentType == 'online'">
|
||||
<view class="no-connect">客服在线</view>
|
||||
</view>
|
||||
<uni-popup ref="imgPopup" type="center">
|
||||
<view class="imagePop">
|
||||
<image :src="$util.img(currImg)" mode="aspectFit"></image>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import htmlParser from '@/common/js/html-parser';
|
||||
import emjoy from '@/common/js/emjoy.js';
|
||||
|
||||
export default {
|
||||
name: 'chat-message',
|
||||
props: {
|
||||
message: {
|
||||
type: Object
|
||||
},
|
||||
send: {
|
||||
type: Boolean
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
avatar: '', //店铺头像
|
||||
defaultAvatar: this.$util.getDefaultImage().store,
|
||||
myHeadImg: '', //我的头像
|
||||
defaultHead: this.$util.getDefaultImage().head,
|
||||
emjoyList: emjoy.emjoyList,
|
||||
currImg: ''
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.avatar = this.$util.img(this.siteInfo.logo_square);
|
||||
this.myHeadImg = this.$util.img(this.memberInfo.headimg);
|
||||
},
|
||||
methods: {
|
||||
// 预览图片
|
||||
previewMedia(img_url) {
|
||||
var paths = [img_url];
|
||||
uni.previewImage({
|
||||
current: 0,
|
||||
urls: paths
|
||||
});
|
||||
},
|
||||
sendGood() {
|
||||
this.$emit('sendGood', 'goods');
|
||||
},
|
||||
sendOrder() {
|
||||
this.$emit('sendOrder', 'order');
|
||||
},
|
||||
// 处理图片错误
|
||||
myHeadImgError() {
|
||||
this.myHeadImg = this.defaultHead;
|
||||
},
|
||||
stringToEmjoy(value) {
|
||||
if (!value) return;
|
||||
// 兼容旧版本图片
|
||||
var reg = RegExp(/\[/);
|
||||
if (reg.test(value)) {
|
||||
let string = value; // 需要把和匹配出来
|
||||
let reg = new RegExp('\\[emjoy_(.+?)\\]', 'g');
|
||||
let emjoyString = string.replace(reg, v => {
|
||||
let emjoy = '';
|
||||
for (let index in this.emjoyList) {
|
||||
if (v == index) {
|
||||
let _url = this.$util.img(this.emjoyList[index]);
|
||||
emjoy = "<img class='message-img' src='" + _url + "'/>";
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (emjoy) {
|
||||
return emjoy;
|
||||
} else {
|
||||
return v;
|
||||
}
|
||||
});
|
||||
let content = htmlParser(emjoyString);
|
||||
content.forEach(v => {
|
||||
if (v.name == 'img') {
|
||||
v.attrs.style = 'display: inline-block;width: 32rpx !important;height: 32rpx !important;padding:0 2rpx;';
|
||||
}
|
||||
});
|
||||
return content;
|
||||
} else {
|
||||
let content = value;
|
||||
return content;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
/deep/.uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
/deep/.uni-popup__wrapper.uni-custom.center .uni-popup__wrapper-box {
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.imagePop {
|
||||
height: 50vh;
|
||||
width: 100vw;
|
||||
text-align: center;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-message {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.message {
|
||||
padding: 13rpx 20rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.left .content {
|
||||
padding: 20rpx;
|
||||
max-width: 450rpx;
|
||||
border-radius: 10rpx;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
.right .content {
|
||||
padding: 20rpx;
|
||||
max-width: 450rpx;
|
||||
border-radius: 10rpx;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
.content_img {
|
||||
height: 200rpx;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
text-align: right;
|
||||
margin-left: 28rpx;
|
||||
background-position: center right;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
|
||||
image {
|
||||
min-height: 80rpx;
|
||||
min-width: 80rpx;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.right .content_img {
|
||||
margin-right: 28rpx;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.message-item {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
align-content: flex-start;
|
||||
flex-wrap: nowrap;
|
||||
flex-direction: row;
|
||||
|
||||
.head_img {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
.img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
//图片
|
||||
.contentType3 {
|
||||
padding: 0;
|
||||
border-radius: 2rpx;
|
||||
background-color: transparent !important;
|
||||
|
||||
.img {
|
||||
width: 200rpx;
|
||||
height: auto;
|
||||
max-width: 300rpx;
|
||||
max-height: 400rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.contentType3::after {
|
||||
border: none !important;
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.content-type-right {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
&.right {
|
||||
flex-direction: row-reverse;
|
||||
|
||||
.content {
|
||||
background-color: #4cd964;
|
||||
margin-right: 28rpx;
|
||||
word-break: break-all;
|
||||
line-height: 36rpx;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
&.left {
|
||||
.content {
|
||||
background-color: #ffffff;
|
||||
margin-left: 28rpx;
|
||||
word-break: break-all;
|
||||
line-height: 36rpx;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.next {
|
||||
width: 100%;
|
||||
height: 20rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.no-connect-box {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
margin: 20rpx 0 50rpx;
|
||||
|
||||
.no-connect {
|
||||
display: inline-block;
|
||||
padding: 0 20rpx;
|
||||
height: 40rpx;
|
||||
background: red;
|
||||
margin: 0 auto;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
border-radius: 9rpx;
|
||||
text-align: center;
|
||||
line-height: 40rpx;
|
||||
font-size: 22rpx;
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
.chat_text,
|
||||
.chat_img {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.iconfont {
|
||||
font-size: 36rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.chat_img {
|
||||
width: 30%;
|
||||
height: 200rpx;
|
||||
}
|
||||
</style>
|
||||
@@ -636,30 +636,13 @@
|
||||
<script>
|
||||
import payment from './payment.js';
|
||||
|
||||
import nsSelectTime from '@/components/ns-select-time/ns-select-time.vue';
|
||||
import MescrollUni from "@/components/mescroll/my-list-mescroll.vue";
|
||||
import nsLogin from '@/components/ns-login/ns-login.vue';
|
||||
import loadingCover from '@/components/loading-cover/loading-cover.vue';
|
||||
import nsEmpty from '@/components/ns-empty/ns-empty.vue';
|
||||
// #ifdef MP-WEIXIN
|
||||
import privacyPopup from '@/components/wx-privacy-popup/privacy-popup.vue';
|
||||
// #endif
|
||||
|
||||
|
||||
export default {
|
||||
name: 'common-payment',
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
components: {
|
||||
nsSelectTime,
|
||||
nsLogin,
|
||||
MescrollUni,
|
||||
loadingCover,
|
||||
nsEmpty,
|
||||
// #ifdef MP-WEIXIN
|
||||
privacyPopup
|
||||
// #endif
|
||||
},
|
||||
props: {
|
||||
api: Object,
|
||||
createDataKey: String
|
||||
|
||||
@@ -420,12 +420,7 @@
|
||||
|
||||
<script>
|
||||
// 商品详情视图
|
||||
import uniPopup from '@/components/uni-popup/uni-popup.vue';
|
||||
import nsGoodsRecommend from '@/components/ns-goods-recommend/ns-goods-recommend.vue';
|
||||
import pengpaiFadeinOut from '@/components/pengpai-fadein-out/pengpai-fadein-out.vue';
|
||||
import xiaoStarComponent from '@/components/xiao-star-component/xiao-star-component.vue';
|
||||
import scroll from '@/common/js/scroll-view.js';
|
||||
import toTop from '@/components/toTop/toTop.vue';
|
||||
import detail from './detail.js';
|
||||
|
||||
export default {
|
||||
@@ -438,13 +433,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
components: {
|
||||
uniPopup,
|
||||
nsGoodsRecommend,
|
||||
pengpaiFadeinOut,
|
||||
toTop,
|
||||
xiaoStarComponent
|
||||
},
|
||||
mixins: [scroll, detail]
|
||||
};
|
||||
</script>
|
||||
|
||||
1484
components/img-cropping/img-cropping.vue
Normal file
1484
components/img-cropping/img-cropping.vue
Normal file
File diff suppressed because it is too large
Load Diff
56
components/l-time/l-time.vue
Normal file
56
components/l-time/l-time.vue
Normal file
@@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<text>{{ temp }}</text>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import _time_ from './time.js';
|
||||
export default {
|
||||
name: 'l-time',
|
||||
props: {
|
||||
//日期字符串
|
||||
text: {
|
||||
type: [String, Number, Date],
|
||||
default: ''
|
||||
},
|
||||
//是否显示大于当前时间日期,默认false:大于显示刚刚
|
||||
maxDate: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
textVal: this.text
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
text() {
|
||||
this.textVal = this.text;
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
temp() {
|
||||
return this.getText();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getText() {
|
||||
let self = this;
|
||||
let timeVal = _time_.getFormatTime(self.textVal, self.maxDate);
|
||||
if (timeVal && (timeVal.endsWith('刚刚') || timeVal.endsWith('分钟前'))) {
|
||||
setTimeout(() => {
|
||||
let temp = self.textVal;
|
||||
self.textVal = '';
|
||||
self.textVal = temp;
|
||||
}, 60000);
|
||||
}
|
||||
return this.textVal ? timeVal : '';
|
||||
},
|
||||
onClick() {
|
||||
this.$emit('on-tap', this.textVal);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
161
components/l-time/time.js
Normal file
161
components/l-time/time.js
Normal file
@@ -0,0 +1,161 @@
|
||||
Function.prototype.asyAfter = function(afterfn) {
|
||||
var _self = this;
|
||||
return function() {
|
||||
var ret = _self.apply(this, arguments);
|
||||
if (ret === 'next') {
|
||||
return afterfn.apply(this, arguments);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
Date.prototype.pattern = function(fmt) {
|
||||
var o = {
|
||||
"M+": this.getMonth() + 1, //月份
|
||||
"d+": this.getDate(), //日
|
||||
"h+": this.getHours() % 12 == 0 ? 12 : this.getHours() % 12, //小时
|
||||
"H+": this.getHours(), //小时
|
||||
"m+": this.getMinutes(), //分
|
||||
"s+": this.getSeconds(), //秒
|
||||
"q+": Math.floor((this.getMonth() + 3) / 3), //季度
|
||||
"S": this.getMilliseconds() //毫秒
|
||||
};
|
||||
var week = {
|
||||
"0": "\u65e5",
|
||||
"1": "\u4e00",
|
||||
"2": "\u4e8c",
|
||||
"3": "\u4e09",
|
||||
"4": "\u56db",
|
||||
"5": "\u4e94",
|
||||
"6": "\u516d"
|
||||
};
|
||||
if (/(y+)/.test(fmt)) {
|
||||
fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
|
||||
}
|
||||
if (/(E+)/.test(fmt)) {
|
||||
fmt = fmt.replace(RegExp.$1, ((RegExp.$1.length > 1) ? (RegExp.$1.length > 2 ? "\u661f\u671f" : "\u5468") :
|
||||
"") +
|
||||
week[this.getDay() + ""]);
|
||||
}
|
||||
for (var k in o) {
|
||||
if (new RegExp("(" + k + ")").test(fmt)) {
|
||||
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k])
|
||||
.length)));
|
||||
}
|
||||
}
|
||||
return fmt;
|
||||
}
|
||||
|
||||
const isType = type => (/^\[object\s(.*)\]$/.exec(Object.prototype.toString.call(type)))[1];
|
||||
let Time = function() {};
|
||||
let timeProto = Time.prototype;
|
||||
|
||||
//获取当前时间戳
|
||||
timeProto.getUnix = function() {
|
||||
return new Date().getTime();
|
||||
}
|
||||
|
||||
//获取当天0点0分0秒时间戳
|
||||
timeProto.getTodayUnix = function() {
|
||||
let date = new Date();
|
||||
let myDate = `${date.getFullYear()}/${(date.getMonth() + 1)}/${date.getDate()} 00:00:00`;
|
||||
return new Date(myDate).getTime();
|
||||
}
|
||||
|
||||
//获取今年1月1日0点0分0秒时间戳
|
||||
timeProto.getYearUnix = function() {
|
||||
let date = new Date();
|
||||
date.setMonth(0);
|
||||
date.setDate(1);
|
||||
date.setHours(0);
|
||||
date.setMinutes(0);
|
||||
date.setSeconds(0);
|
||||
date.setMilliseconds(0);
|
||||
return date.getTime();
|
||||
}
|
||||
|
||||
//获取当前时间标准年月日
|
||||
timeProto.getLastDate = function(constTime) {
|
||||
if (!constTime) {
|
||||
return;
|
||||
}
|
||||
let date = new Date(constTime);
|
||||
if (date.pattern) {
|
||||
return date.pattern("yyyy-MM-dd");
|
||||
}
|
||||
|
||||
let month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1;
|
||||
let day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate();
|
||||
return date.getFullYear() + '-' + month + '-' + day;
|
||||
}
|
||||
|
||||
const resDateStr = function(timer, constTime) {
|
||||
let _just = function(timer) {
|
||||
|
||||
if (timer <= 0 || Math.floor(timer / 60) <= 0) {
|
||||
return "刚刚"
|
||||
} else return 'next';
|
||||
}
|
||||
|
||||
let _mm = function(timer) {
|
||||
if (timer < 3600) {
|
||||
return Math.floor(timer / 60) + "分钟前"
|
||||
} else return 'next';
|
||||
}
|
||||
let _hh = function(timer, constTime) {
|
||||
let today = _time_.getTodayUnix();
|
||||
if (timer >= 3600 && (constTime - today >= 0)) {
|
||||
//可切换显示模式
|
||||
// return "今天 " + new Date(constTime).pattern("HH:mm");
|
||||
return Math.floor(timer / 60 / 60) + "小时前";
|
||||
} else {
|
||||
return 'next'
|
||||
};
|
||||
}
|
||||
let _dd = function(timer, constTime) {
|
||||
let today = _time_.getTodayUnix();
|
||||
timer = (today - constTime) / 1000;
|
||||
if (timer / 86400 <= 31) {
|
||||
return Math.ceil(timer / 86400) + "天前"
|
||||
} else return 'next';
|
||||
}
|
||||
let _dlast = function(timer, constTime) {
|
||||
return _time_.getLastDate(constTime);
|
||||
}
|
||||
|
||||
let dateFilter = _just.asyAfter(_mm).asyAfter(_hh).asyAfter(_dd).asyAfter(_dlast);
|
||||
return dateFilter(timer, constTime);
|
||||
}
|
||||
|
||||
|
||||
//转换时间
|
||||
const reg = new RegExp("-", "g");
|
||||
timeProto.getFormatTime = function(constTime, max) {
|
||||
if (!constTime) {
|
||||
return "";
|
||||
}
|
||||
|
||||
switch (isType(constTime)) {
|
||||
case 'Date':
|
||||
constTime = constTime.getTime();
|
||||
break;
|
||||
case 'String':
|
||||
constTime = constTime.replace(reg, "/");
|
||||
default:
|
||||
constTime = new Date(constTime).getTime();
|
||||
break;
|
||||
}
|
||||
|
||||
let now = this.getUnix();
|
||||
let year = this.getYearUnix();
|
||||
let timer = (now - constTime) / 1000;
|
||||
if (constTime > now && max) {
|
||||
return this.getLastDate(constTime);
|
||||
}
|
||||
|
||||
let _t = this;
|
||||
return resDateStr(timer, constTime);
|
||||
}
|
||||
|
||||
const _time_ = new Time();
|
||||
export default _time_;
|
||||
@@ -62,8 +62,6 @@
|
||||
// 引入回到顶部组件
|
||||
import MescrollTop from './components/mescroll-top.vue';
|
||||
|
||||
import nsLoading from '@/components/ns-loading/ns-loading.vue';
|
||||
|
||||
export default {
|
||||
name: 'mescroll-uni',
|
||||
components: {
|
||||
|
||||
234
components/myp-one/myp-one.vue
Normal file
234
components/myp-one/myp-one.vue
Normal file
@@ -0,0 +1,234 @@
|
||||
<template>
|
||||
<view class="code-box">
|
||||
<view class="flex-box">
|
||||
<input :value="inputValue" type="number" :focus="autoFocus" :maxlength="maxlength" class="hide-input" @input="getVal" />
|
||||
<block v-for="(item, index) in ranges" :key="index">
|
||||
<view :class="['item', { active: codeIndex === item, middle: type === 'middle', bottom: type === 'bottom', box: type === 'box' }]">
|
||||
<view class="line" v-if="type !== 'middle'"></view>
|
||||
<view v-if="type === 'middle' && codeIndex <= item" class="bottom-line"></view>
|
||||
<block v-if="isPwd && codeArr.length >= item"><text class="dot">●</text></block>
|
||||
<block v-else>
|
||||
<text class="number">{{ codeArr[index] ? codeArr[index] : '' }}</text>
|
||||
</block>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 支持使用 v-model
|
||||
// 支持使用refs
|
||||
export default {
|
||||
name: 'mypOneInput',
|
||||
props: {
|
||||
// 支持外部提供,支持使用v-model
|
||||
// 支持通过value来做清空
|
||||
value: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 4/6
|
||||
maxlength: {
|
||||
type: Number,
|
||||
default: 4
|
||||
},
|
||||
autoFocus: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isPwd: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// middle-middle line, bottom-bottom line, box-square box
|
||||
type: {
|
||||
type: String,
|
||||
default: 'bottom'
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
maxlength: {
|
||||
immediate: true,
|
||||
handler: function(newV) {
|
||||
if (newV === 6) {
|
||||
this.ranges = [1, 2, 3, 4, 5, 6];
|
||||
} else {
|
||||
this.ranges = [1, 2, 3, 4];
|
||||
}
|
||||
}
|
||||
},
|
||||
value: {
|
||||
immediate: true,
|
||||
handler: function(newV) {
|
||||
if (newV !== this.inputValue) {
|
||||
this.inputValue = newV;
|
||||
this.toMakeAndCheck(newV);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
inputValue: '',
|
||||
codeIndex: 1,
|
||||
codeArr: [],
|
||||
ranges: [1, 2, 3, 4]
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
getVal(e) {
|
||||
const val = e.detail.value;
|
||||
this.inputValue = val;
|
||||
this.$emit('input', val);
|
||||
this.toMakeAndCheck(val);
|
||||
},
|
||||
toMakeAndCheck(val) {
|
||||
const arr = val.split('');
|
||||
this.codeIndex = arr.length + 1;
|
||||
this.codeArr = arr;
|
||||
if (this.codeIndex > Number(this.maxlength)) {
|
||||
this.$emit('finish', this.codeArr.join(''));
|
||||
}
|
||||
},
|
||||
// refs 时不再提供 v-model 支持
|
||||
// 支持使用refs来设置value
|
||||
// 没有提供数据保护与检测,自己在外面对数据进行检测保护
|
||||
set(val) {
|
||||
this.inputValue = val;
|
||||
this.toMakeAndCheck(val);
|
||||
},
|
||||
// 支持使用refs来清空
|
||||
clear() {
|
||||
this.inputValue = '';
|
||||
this.codeArr = [];
|
||||
this.codeIndex = 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@keyframes twinkling {
|
||||
0% {
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 0.2;
|
||||
}
|
||||
}
|
||||
|
||||
.code-box {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.flex-box {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.flex-box .hide-input {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -100%;
|
||||
width: 200%;
|
||||
height: 100%;
|
||||
text-align: left;
|
||||
z-index: 9;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.flex-box .item {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
margin-right: 18rpx;
|
||||
font-size: 70rpx;
|
||||
font-weight: bold;
|
||||
color: #333333;
|
||||
line-height: 100rpx;
|
||||
}
|
||||
|
||||
.flex-box .item::before {
|
||||
content: '';
|
||||
padding-top: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.flex-box .item:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.flex-box .middle {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.flex-box .box {
|
||||
box-sizing: border-box;
|
||||
border: 2rpx solid #cccccc;
|
||||
border-width: 2rpx 0 2rpx 2rpx;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.flex-box .box:first-of-type {
|
||||
border-top-left-radius: 8rpx;
|
||||
border-bottom-left-radius: 8rpx;
|
||||
}
|
||||
|
||||
.flex-box .box:last-child {
|
||||
border-right: 2rpx solid #cccccc;
|
||||
border-top-right-radius: 8rpx;
|
||||
border-bottom-right-radius: 8rpx;
|
||||
}
|
||||
|
||||
.flex-box .bottom {
|
||||
box-sizing: border-box;
|
||||
border-bottom: 2rpx solid #ddd;
|
||||
}
|
||||
|
||||
.flex-box .active {
|
||||
border-color: #ddd;
|
||||
}
|
||||
|
||||
.flex-box .active .line {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.flex-box .line {
|
||||
display: none;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 2rpx;
|
||||
height: 40rpx;
|
||||
background: #333333;
|
||||
animation: twinkling 1s infinite ease;
|
||||
}
|
||||
|
||||
.flex-box .dot,
|
||||
.flex-box .number {
|
||||
line-height: 40rpx;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.flex-box .bottom-line {
|
||||
height: 8rpx;
|
||||
background: #000000;
|
||||
width: 80%;
|
||||
position: absolute;
|
||||
border-radius: 4rpx;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
</style>
|
||||
@@ -1,120 +1,120 @@
|
||||
<template>
|
||||
<view v-if="advList.length" :class="['container-box',className]">
|
||||
<swiper :indicator-dots="advList.length > 1" indicator-active-color="#ffffff" :autoplay="true" :interval="3000" :duration="1000" v-if="advList.length > 1" @change="changeSwiper" :current="currentIndex" :style="{ height: swiperHeight + 'px' }" class="item-wrap">
|
||||
<swiper-item v-for="(item, index) in advList" :key="index" @click="jumppage(item.adv_url)">
|
||||
<view class="image-box">
|
||||
<image :src="$util.img(item.adv_image)" mode="widthFix" :id="'content-wrap' + index"/>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<view v-else class="container-box item-wrap">
|
||||
<image :src="$util.img(advList[0]['adv_image'])" mode="widthFix" lazy-load="true" @load="imageLoad" @click="jumppage(advList[0].adv_url)"/>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ns-advert',
|
||||
props: {
|
||||
keyword: {
|
||||
type: String
|
||||
},
|
||||
className: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
advList: [],
|
||||
isImage: false,
|
||||
//滑块的高度(单位px)
|
||||
swiperHeight: 150,
|
||||
//当前索引
|
||||
currentIndex: 0,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getAdvList();
|
||||
},
|
||||
methods: {
|
||||
//获取广告位
|
||||
getAdvList() {
|
||||
var item = {
|
||||
adv_image: '',
|
||||
adv_url: ''
|
||||
};
|
||||
this.$api.sendRequest({
|
||||
url: '/api/adv/detail',
|
||||
data: {
|
||||
keyword: this.keyword
|
||||
},
|
||||
success: res => {
|
||||
if (res.code == 0) {
|
||||
var data = res.data.adv_list;
|
||||
for (var index in data) {
|
||||
if (data[index].adv_url) data[index].adv_url = JSON.parse(data[index].adv_url);
|
||||
}
|
||||
this.advList = res.data.adv_list;
|
||||
|
||||
//动态设置swiper的高度
|
||||
this.$nextTick(() => {
|
||||
this.setSwiperHeight();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
jumppage(e) {
|
||||
this.$util.diyRedirectTo(e);
|
||||
},
|
||||
imageLoad(data) {
|
||||
this.isImage = true;
|
||||
},
|
||||
//手动切换题目
|
||||
changeSwiper(e) {
|
||||
this.currentIndex = e.detail.current;
|
||||
//动态设置swiper的高度,使用nextTick延时设置
|
||||
this.$nextTick(() => {
|
||||
this.setSwiperHeight();
|
||||
});
|
||||
},
|
||||
//动态设置swiper的高度
|
||||
setSwiperHeight() {
|
||||
if (this.advList.length > 1) {
|
||||
setTimeout(() => {
|
||||
let element = "#content-wrap" + this.currentIndex;
|
||||
let query = uni.createSelectorQuery().in(this);
|
||||
query.select(element).boundingClientRect();
|
||||
query.exec((res) => {
|
||||
if (res && res[0]) {
|
||||
this.swiperHeight = res[0].height;
|
||||
}
|
||||
});
|
||||
}, 10);
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.container-box {
|
||||
width: 100%;
|
||||
|
||||
.item-wrap {
|
||||
border-radius: 10rpx;
|
||||
|
||||
.image-box {
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
border-radius: 10rpx;
|
||||
will-change: transform;
|
||||
}
|
||||
}
|
||||
}
|
||||
<template>
|
||||
<view v-if="advList.length" :class="['container-box',className]">
|
||||
<swiper :indicator-dots="advList.length > 1" indicator-active-color="#ffffff" :autoplay="true" :interval="3000" :duration="1000" v-if="advList.length > 1" @change="changeSwiper" :current="currentIndex" :style="{ height: swiperHeight + 'px' }" class="item-wrap">
|
||||
<swiper-item v-for="(item, index) in advList" :key="index" @click="jumppage(item.adv_url)">
|
||||
<view class="image-box">
|
||||
<image :src="$util.img(item.adv_image)" mode="widthFix" :id="'content-wrap' + index"/>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<view v-else class="container-box item-wrap">
|
||||
<image :src="$util.img(advList[0]['adv_image'])" mode="widthFix" lazy-load="true" @load="imageLoad" @click="jumppage(advList[0].adv_url)"/>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ns-advert',
|
||||
props: {
|
||||
keyword: {
|
||||
type: String
|
||||
},
|
||||
className: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
advList: [],
|
||||
isImage: false,
|
||||
//滑块的高度(单位px)
|
||||
swiperHeight: 150,
|
||||
//当前索引
|
||||
currentIndex: 0,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getAdvList();
|
||||
},
|
||||
methods: {
|
||||
//获取广告位
|
||||
getAdvList() {
|
||||
var item = {
|
||||
adv_image: '',
|
||||
adv_url: ''
|
||||
};
|
||||
this.$api.sendRequest({
|
||||
url: '/api/adv/detail',
|
||||
data: {
|
||||
keyword: this.keyword
|
||||
},
|
||||
success: res => {
|
||||
if (res.code == 0) {
|
||||
var data = res.data.adv_list;
|
||||
for (var index in data) {
|
||||
if (data[index].adv_url) data[index].adv_url = JSON.parse(data[index].adv_url);
|
||||
}
|
||||
this.advList = res.data.adv_list;
|
||||
|
||||
//动态设置swiper的高度
|
||||
this.$nextTick(() => {
|
||||
this.setSwiperHeight();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
jumppage(e) {
|
||||
this.$util.diyRedirectTo(e);
|
||||
},
|
||||
imageLoad(data) {
|
||||
this.isImage = true;
|
||||
},
|
||||
//手动切换题目
|
||||
changeSwiper(e) {
|
||||
this.currentIndex = e.detail.current;
|
||||
//动态设置swiper的高度,使用nextTick延时设置
|
||||
this.$nextTick(() => {
|
||||
this.setSwiperHeight();
|
||||
});
|
||||
},
|
||||
//动态设置swiper的高度
|
||||
setSwiperHeight() {
|
||||
if (this.advList.length > 1) {
|
||||
setTimeout(() => {
|
||||
let element = "#content-wrap" + this.currentIndex;
|
||||
let query = uni.createSelectorQuery().in(this);
|
||||
query.select(element).boundingClientRect();
|
||||
query.exec((res) => {
|
||||
if (res && res[0]) {
|
||||
this.swiperHeight = res[0].height;
|
||||
}
|
||||
});
|
||||
}, 10);
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.container-box {
|
||||
width: 100%;
|
||||
|
||||
.item-wrap {
|
||||
border-radius: 10rpx;
|
||||
|
||||
.image-box {
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
border-radius: 10rpx;
|
||||
will-change: transform;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -80,14 +80,10 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import uniPopup from '../uni-popup/uni-popup.vue';
|
||||
|
||||
// 注册奖励弹出层
|
||||
export default {
|
||||
name: 'ns-birthday-gift',
|
||||
components: {
|
||||
uniPopup
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
birthday: {
|
||||
|
||||
142
components/ns-chat/ns-chat-goods.vue
Normal file
142
components/ns-chat/ns-chat-goods.vue
Normal file
@@ -0,0 +1,142 @@
|
||||
<template>
|
||||
<view class="message">
|
||||
<view class="goods-item" v-if="goodsInfo.goods_name || goodsInfo.en_goods_name">
|
||||
<image :src="$util.img(goodsInfo.sku_image)" mode="aspectFill"></image>
|
||||
<view class="goods-info">
|
||||
<view class="goods-name">{{ goodsInfo.sku_name ? goodsInfo.sku_name : (isEnEnv ? goodsInfo.en_goods_name : goodsInfo.goods_name) }}</view>
|
||||
<view class="goods-bottom">
|
||||
<view class="goods-price">
|
||||
<text class="goods-price-sign color-base-text">¥</text>
|
||||
<text class="color-base-text">{{ goodsInfo.price }}</text>
|
||||
</view>
|
||||
<view class="goods-option font-size-goods-tag disabled">已发送</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="goods-item" v-else-if="goodsDetail">
|
||||
<image :src="$util.img(goodsDetail.sku_image)" mode="aspectFill"></image>
|
||||
<view class="goods-info">
|
||||
<view class="goods-name">{{ goodsDetail.sku_name ? goodsDetail.sku_name : (isEnEnv ? goodsDetail.en_goods_name : goodsDetail.goods_name) }}</view>
|
||||
<view class="goods-bottom">
|
||||
<view class="goods-price">
|
||||
<text class="goods-price-sign color-base-text">¥</text>
|
||||
<text class="color-base-text">{{ goodsDetail.price }}</text>
|
||||
</view>
|
||||
<view class="goods-option font-size-goods-tag color-base-bg" @click="sendMsg('goods')">发送</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ns-chat-goods',
|
||||
props: {
|
||||
skuId: {
|
||||
type: [Number, String]
|
||||
},
|
||||
goodsDetail: {
|
||||
type: [Object]
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
goodsInfo: {}
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.getGoodsInfo();
|
||||
},
|
||||
methods: {
|
||||
getGoodsInfo() {
|
||||
this.$api.sendRequest({
|
||||
url: '/api/goodssku/detail',
|
||||
data: {
|
||||
sku_id: this.skuId
|
||||
},
|
||||
success: res => {
|
||||
if (res.code >= 0) {
|
||||
this.goodsInfo = res.data.goods_sku_detail;
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
sendMsg() {
|
||||
this.$emit('sendMsg', 'goods');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.message {
|
||||
padding: 13rpx 20rpx;
|
||||
box-sizing: border-box;
|
||||
width: 100vw;
|
||||
position: relative;
|
||||
.goods-item {
|
||||
width: 100%;
|
||||
height: 220rpx;
|
||||
|
||||
background: #ffffff;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 20rpx;
|
||||
margin: 0 auto;
|
||||
padding: $padding;
|
||||
box-sizing: border-box;
|
||||
image {
|
||||
width: 180rpx;
|
||||
height: 180rpx;
|
||||
min-width: 180rpx;
|
||||
}
|
||||
.goods-info {
|
||||
width: 100%;
|
||||
height: 180rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
padding-left: 20rpx;
|
||||
box-sizing: border-box;
|
||||
.goods-name {
|
||||
width: 100%;
|
||||
line-height: 1.4;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
}
|
||||
.goods-bottom {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
text {
|
||||
line-height: 1;
|
||||
}
|
||||
.goods-price {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
padding-bottom: 10rpx;
|
||||
font-weight: 500;
|
||||
.goods-price-sign {
|
||||
font-size: $font-size-activity-tag;
|
||||
}
|
||||
}
|
||||
.goods-option {
|
||||
width: 150rpx;
|
||||
height: 50rpx;
|
||||
line-height: 50rpx;
|
||||
text-align: center;
|
||||
border-radius: $border-radius;
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
.disabled {
|
||||
background: #e5e5e5;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
149
components/ns-chat/ns-chat-order.vue
Normal file
149
components/ns-chat/ns-chat-order.vue
Normal file
@@ -0,0 +1,149 @@
|
||||
<template>
|
||||
<view class="message">
|
||||
<view class="goods-item" v-if="orderdetails">
|
||||
<image :src="$util.img(orderdetails.order_goods ? orderdetails.order_goods[0].sku_image : '')" mode="aspectFill"></image>
|
||||
<view class="goods-info">
|
||||
<view class="goods-name">{{ orderdetails.order_goods ? orderdetails.order_goods[0].sku_name : '' }}</view>
|
||||
<view class="font-size-goods-tag">订单状态:{{ orderdetails.order_status_name }}</view>
|
||||
<view class="font-size-goods-tag">配送方式:{{ orderdetails.delivery_type_name }}</view>
|
||||
<view class="goods-bottom">
|
||||
<view class="goods-price color-base-text">
|
||||
<text class="goods-price-sign">¥</text>
|
||||
<text>{{ orderdetails.order_goods ? orderdetails.order_goods[0].price : '' }}</text>
|
||||
</view>
|
||||
<view class="goods-option font-size-goods-tag color-base-bg" @click="sendMsg('order')">发送</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="goods-item" v-else-if="orderInfo">
|
||||
<image :src="$util.img(orderInfo.order_goods ? orderInfo.order_goods[0].sku_image : '')" mode="aspectFill"></image>
|
||||
<view class="goods-info">
|
||||
<view class="goods-name">{{ orderInfo.order_goods ? orderInfo.order_goods[0].sku_name : '' }}</view>
|
||||
<view class="font-size-goods-tag">订单状态:{{ orderInfo.order_status_name }}</view>
|
||||
<view class="font-size-goods-tag">配送方式:{{ orderInfo.delivery_type_name }}</view>
|
||||
<view class="goods-bottom">
|
||||
<view class="goods-price color-base-text">
|
||||
<text class="goods-price-sign">¥</text>
|
||||
<text>{{ orderInfo.order_goods ? orderInfo.order_goods[0].price : '' }}</text>
|
||||
</view>
|
||||
<view class="goods-option font-size-goods-tag disabled">已发送</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ns-chat-order',
|
||||
props: {
|
||||
orderId: {
|
||||
type: [Number, String]
|
||||
},
|
||||
isCanSend: Boolean,
|
||||
orderdetails: {
|
||||
type: [Object]
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
orderInfo: {}
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.getGoodsInfo();
|
||||
},
|
||||
methods: {
|
||||
getGoodsInfo() {
|
||||
if (this.orderId) {
|
||||
this.$api.sendRequest({
|
||||
url: '/api/order/detail',
|
||||
data: {
|
||||
order_id: this.orderId
|
||||
},
|
||||
success: res => {
|
||||
if (res.code >= 0) {
|
||||
this.orderInfo = res.data;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
sendMsg() {
|
||||
this.$emit('sendMsg', 'order');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.message {
|
||||
padding: 13rpx 20rpx;
|
||||
box-sizing: border-box;
|
||||
width: 100vw;
|
||||
position: relative;
|
||||
.goods-item {
|
||||
width: 100%;
|
||||
height: 220rpx;
|
||||
background: #ffffff;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 20rpx;
|
||||
margin: 0 auto;
|
||||
padding: $padding;
|
||||
box-sizing: border-box;
|
||||
image {
|
||||
width: 180rpx;
|
||||
height: 180rpx;
|
||||
}
|
||||
.goods-info {
|
||||
width: 100%;
|
||||
height: 180rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
padding-left: 20rpx;
|
||||
box-sizing: border-box;
|
||||
.goods-name {
|
||||
width: 100%;
|
||||
line-height: 1.4;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
overflow: hidden;
|
||||
// font-size: $font-size-tag;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
.goods-bottom {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
text {
|
||||
line-height: 1;
|
||||
}
|
||||
.goods-price {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
padding-bottom: 10rpx;
|
||||
font-weight: 500;
|
||||
.goods-price-sign {
|
||||
font-size: 20rpx;
|
||||
}
|
||||
}
|
||||
.goods-option {
|
||||
width: 150rpx;
|
||||
height: 50rpx;
|
||||
line-height: 50rpx;
|
||||
text-align: center;
|
||||
border-radius: $border-radius;
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
.disabled {
|
||||
background: #e5e5e5;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
142
components/ns-chat/ns-chat-receiveGoods.vue
Normal file
142
components/ns-chat/ns-chat-receiveGoods.vue
Normal file
@@ -0,0 +1,142 @@
|
||||
<template>
|
||||
<view class="goods">
|
||||
<view class="goods-msg">
|
||||
<image :src="$util.img(goodsInfo.sku_image)" mode="aspectFill"></image>
|
||||
<view class="goods-item">
|
||||
<view class="title">{{ isEnEnv ? goodsInfo.en_goods_name : goodsInfo.goods_name }}</view>
|
||||
<view class="goods-sku">
|
||||
库存:{{ goodsInfo.stock }}
|
||||
<text>销量:{{ goodsInfo.sale_num }}</text>
|
||||
</view>
|
||||
<view class="goods-price">
|
||||
<view class="price color-base-text">
|
||||
<text class="price-util">¥</text>
|
||||
<text class="price-num">{{ goodsInfo.price }}</text>
|
||||
</view>
|
||||
<view class="see-shop color-base-text" @click="go_shop()">
|
||||
查看商品
|
||||
<text class="iconfont icon-right"></text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ns-chat-receiveGoods',
|
||||
props: {
|
||||
skuId: {
|
||||
type: [Number, String]
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
goodsInfo: {}
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.getInfo();
|
||||
},
|
||||
methods: {
|
||||
getInfo() {
|
||||
this.$api.sendRequest({
|
||||
url: '/api/goodssku/detail',
|
||||
data: {
|
||||
sku_id: this.skuId
|
||||
},
|
||||
success: res => {
|
||||
if (res.code >= 0) {
|
||||
this.goodsInfo = res.data.goods_sku_detail;
|
||||
this.$emit('upDOM');
|
||||
// that.setPageScrollTo();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
go_shop() {
|
||||
this.$util.redirectTo('/pages_goods/detail?goods_id=' + this.goodsInfo.goods_id);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.goods {
|
||||
padding: 13rpx 20rpx;
|
||||
box-sizing: border-box;
|
||||
width: 100vw;
|
||||
position: relative;
|
||||
|
||||
.goods-msg {
|
||||
width: 100%;
|
||||
height: 220rpx;
|
||||
background: #ffffff;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 20rpx;
|
||||
margin: 0 auto;
|
||||
padding: $padding;
|
||||
box-sizing: border-box;
|
||||
|
||||
image {
|
||||
width: 180rpx;
|
||||
height: 180rpx;
|
||||
min-width: 180rpx;
|
||||
border-radius: $border-radius;
|
||||
}
|
||||
|
||||
.goods-item {
|
||||
width: 100%;
|
||||
height: 180rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
padding-left: 20rpx;
|
||||
box-sizing: border-box;
|
||||
|
||||
.title {
|
||||
width: 100%;
|
||||
line-height: 1.4;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.goods-sku {
|
||||
color: $color-sub;
|
||||
|
||||
text {
|
||||
padding-left: $padding;
|
||||
}
|
||||
}
|
||||
|
||||
.goods-price {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.price {
|
||||
.price-util {
|
||||
font-size: $font-size-activity-tag;
|
||||
}
|
||||
}
|
||||
|
||||
.see-shop {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
text {
|
||||
padding-top: 4rpx;
|
||||
padding-left: 4rpx;
|
||||
font-size: $font-size-sub;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -200,12 +200,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import pickRegions from '@/components/pick-regions/pick-regions.vue';
|
||||
export default {
|
||||
name: 'ns-form',
|
||||
components: {
|
||||
pickRegions
|
||||
},
|
||||
props: {
|
||||
data: {
|
||||
type: Array,
|
||||
|
||||
@@ -1,96 +1,96 @@
|
||||
<template>
|
||||
<view class="action-buttom-wrap disabled" v-if="disabled" @click="clickEvent">{{ disabledText }}</view>
|
||||
<view class="action-buttom-wrap"
|
||||
:class="[backgroundClass, textPrice ? 'has-second' : '', background ? 'color-join-cart' : 'color-base-bg']"
|
||||
:style="{background:backgroundColor+'!important', 'color':textColor ? textColor : '#ffffff'}" v-else
|
||||
@click="clickEvent">
|
||||
<text class="price-font">{{ textPrice }}</text>
|
||||
<text>{{ text }}</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ns-goods-action-button',
|
||||
props: {
|
||||
// 商品底部按钮文字
|
||||
text: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 商品底部按钮价格文字
|
||||
textPrice: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 背景色
|
||||
background: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 背景色样式
|
||||
backgroundClass: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
//
|
||||
backgroundColor: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 是否禁用
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 禁用文字提示
|
||||
disabledText: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 文字颜色
|
||||
textColor: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
},
|
||||
computed: {},
|
||||
methods: {
|
||||
clickEvent() {
|
||||
this.$emit('click');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.action-buttom-wrap {
|
||||
flex: 1;
|
||||
height: 70rpx;
|
||||
font-weight: 600;
|
||||
font-size: 30rpx;
|
||||
line-height: 70rpx;
|
||||
border: none;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
border-radius: 10rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.action-buttom-wrap.has-second {
|
||||
line-height: 50rpx;
|
||||
}
|
||||
|
||||
.action-buttom-wrap.has-second text {
|
||||
display: block;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.action-buttom-wrap:active {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.action-buttom-wrap.disabled {
|
||||
background: $color-disabled;
|
||||
}
|
||||
<template>
|
||||
<view class="action-buttom-wrap disabled" v-if="disabled" @click="clickEvent">{{ disabledText }}</view>
|
||||
<view class="action-buttom-wrap"
|
||||
:class="[backgroundClass, textPrice ? 'has-second' : '', background ? 'color-join-cart' : 'color-base-bg']"
|
||||
:style="{background:backgroundColor+'!important', 'color':textColor ? textColor : '#ffffff'}" v-else
|
||||
@click="clickEvent">
|
||||
<text class="price-font">{{ textPrice }}</text>
|
||||
<text>{{ text }}</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ns-goods-action-button',
|
||||
props: {
|
||||
// 商品底部按钮文字
|
||||
text: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 商品底部按钮价格文字
|
||||
textPrice: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 背景色
|
||||
background: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 背景色样式
|
||||
backgroundClass: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
//
|
||||
backgroundColor: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 是否禁用
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 禁用文字提示
|
||||
disabledText: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 文字颜色
|
||||
textColor: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
},
|
||||
computed: {},
|
||||
methods: {
|
||||
clickEvent() {
|
||||
this.$emit('click');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.action-buttom-wrap {
|
||||
flex: 1;
|
||||
height: 70rpx;
|
||||
font-weight: 600;
|
||||
font-size: 30rpx;
|
||||
line-height: 70rpx;
|
||||
border: none;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
border-radius: 10rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.action-buttom-wrap.has-second {
|
||||
line-height: 50rpx;
|
||||
}
|
||||
|
||||
.action-buttom-wrap.has-second text {
|
||||
display: block;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.action-buttom-wrap:active {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.action-buttom-wrap.disabled {
|
||||
background: $color-disabled;
|
||||
}
|
||||
</style>
|
||||
@@ -20,7 +20,6 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import nsContact from '@/components/ns-contact/ns-contact.vue';
|
||||
export default {
|
||||
name: 'ns-goods-action-icon',
|
||||
props: {
|
||||
@@ -72,9 +71,6 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
components:{
|
||||
nsContact
|
||||
},
|
||||
methods: {
|
||||
clickEvent() {
|
||||
this.$emit('click');
|
||||
|
||||
@@ -3,16 +3,9 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import nsLoading from '@/components/ns-loading/ns-loading.vue';
|
||||
import nsGoodsSkuIndex from '@/components/ns-goods-sku/ns-goods-sku-index.vue';
|
||||
|
||||
// 商品推荐
|
||||
export default {
|
||||
name: 'ns-goods-recommend',
|
||||
components: {
|
||||
nsLoading,
|
||||
nsGoodsSkuIndex
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: [],
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import uniPopup from '@/components/uni-popup/uni-popup-sku-new.vue';
|
||||
import uniPopup from '@/uni_modules/uni-popup/components/uni-popup/uni-popup-sku-new.vue';
|
||||
// 商品SKU
|
||||
export default {
|
||||
name: 'ns-goods-sku-category',
|
||||
|
||||
@@ -2,235 +2,233 @@
|
||||
<view class="goods-sku">
|
||||
<ns-login ref="login"></ns-login>
|
||||
<!-- sku选择 -->
|
||||
<ns-goods-sku v-if="goodsDetail.goods_id" ref="goodsSku" :goods-id="goodsDetail.goods_id" :goods-detail="goodsDetail" :max-buy="goodsDetail.max_buy" :min-buy="goodsDetail.min_buy" @refresh="refreshGoodsSkuDetail"></ns-goods-sku>
|
||||
<ns-goods-sku v-if="goodsDetail.goods_id" ref="goodsSku" :goods-id="goodsDetail.goods_id"
|
||||
:goods-detail="goodsDetail" :max-buy="goodsDetail.max_buy" :min-buy="goodsDetail.min_buy"
|
||||
@refresh="refreshGoodsSkuDetail"></ns-goods-sku>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import nsGoodsSku from '@/components/ns-goods-sku/ns-goods-sku.vue';
|
||||
// 商品SKU
|
||||
export default {
|
||||
name: 'ns-goods-sku-index',
|
||||
components: {
|
||||
nsGoodsSku
|
||||
// 商品SKU
|
||||
export default {
|
||||
name: 'ns-goods-sku-index',
|
||||
data() {
|
||||
return {
|
||||
timeout: {},
|
||||
isRepeat: false,
|
||||
goodsDetail: {}
|
||||
};
|
||||
},
|
||||
created() { },
|
||||
methods: {
|
||||
/**
|
||||
* 添加购物车
|
||||
* @param {Object} config 购物车事件(detail-详情,cart-加入购物车)
|
||||
* @param {Object} data 商品项
|
||||
*/
|
||||
addCart(config, data, event) {
|
||||
if (!this.storeToken) {
|
||||
this.$refs.login.open('/pages/index/index')
|
||||
return;
|
||||
}
|
||||
if (config == "detail" || data.is_virtual) {
|
||||
this.$util.redirectTo('/pages_goods/detail', {
|
||||
goods_id: data.goods_id
|
||||
});
|
||||
return false;
|
||||
}
|
||||
// 多规格
|
||||
if (data.goods_spec_format) {
|
||||
this.multiSpecificationGoods(data);
|
||||
} else {
|
||||
this.singleSpecificationGoods(data, event);
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
timeout: {},
|
||||
isRepeat: false,
|
||||
goodsDetail: {}
|
||||
};
|
||||
},
|
||||
created() {},
|
||||
methods: {
|
||||
/**
|
||||
* 添加购物车
|
||||
* @param {Object} config 购物车事件(detail-详情,cart-加入购物车)
|
||||
* @param {Object} data 商品项
|
||||
*/
|
||||
addCart(config, data, event) {
|
||||
if (!this.storeToken) {
|
||||
this.$refs.login.open('/pages/index/index')
|
||||
return;
|
||||
}
|
||||
if (config == "detail" || data.is_virtual) {
|
||||
this.$util.redirectTo('/pages_goods/detail', {
|
||||
goods_id: data.goods_id
|
||||
});
|
||||
return false;
|
||||
}
|
||||
// 多规格
|
||||
if (data.goods_spec_format) {
|
||||
this.multiSpecificationGoods(data);
|
||||
} else {
|
||||
this.singleSpecificationGoods(data, event);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 单规格
|
||||
* @param {Object} data 商品项
|
||||
*/
|
||||
singleSpecificationGoods(data, event) {
|
||||
let cart =
|
||||
this.cartList['goods_' + data.goods_id] && this.cartList['goods_' + data.goods_id]['sku_' + data
|
||||
.sku_id
|
||||
] ?
|
||||
/**
|
||||
* 单规格
|
||||
* @param {Object} data 商品项
|
||||
*/
|
||||
singleSpecificationGoods(data, event) {
|
||||
let cart =
|
||||
this.cartList['goods_' + data.goods_id] && this.cartList['goods_' + data.goods_id]['sku_' + data
|
||||
.sku_id
|
||||
] ?
|
||||
this.cartList['goods_' + data.goods_id]['sku_' + data.sku_id] :
|
||||
null;
|
||||
|
||||
let cartNum = cart ? cart.num : 0;
|
||||
let api = cart && cart.cart_id ? '/api/cart/edit' : '/api/cart/add';
|
||||
let minBuy = data.min_buy > 0 ? data.min_buy : 1;
|
||||
let num = cartNum >= minBuy ? cartNum : minBuy;
|
||||
let _num = num;
|
||||
if(cart && cart.cart_id){
|
||||
_num = _num + (data.min_buy > 0 ? data.min_buy : 1)
|
||||
}
|
||||
let cart_id = cart ? cart.cart_id : 0;
|
||||
if (_num > parseInt(data.stock)) {
|
||||
this.$util.showToast({
|
||||
title: '商品库存不足'
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (data.is_limit && data.max_buy && _num > parseInt(data.max_buy)) {
|
||||
this.$util.showToast({
|
||||
title: `该商品每人限购${data.max_buy}${data.unit || '件'}`
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (cart) {
|
||||
this.cartList['goods_' + data.goods_id]['sku_' + data.sku_id].num = _num;
|
||||
} else {
|
||||
|
||||
// 如果商品第一次添加,则初始化数据
|
||||
if (!this.cartList['goods_' + data.goods_id]) {
|
||||
this.cartList['goods_' + data.goods_id] = {};
|
||||
}
|
||||
|
||||
let discount_price = data.discount_price;
|
||||
if (data.member_price > 0 && Number(data.member_price) <= Number(data.discount_price)) {
|
||||
discount_price = data.member_price;
|
||||
}
|
||||
|
||||
this.cartList['goods_' + data.goods_id]['sku_' + data.sku_id] = {
|
||||
cart_id,
|
||||
goods_id: data.goods_id,
|
||||
sku_id: data.sku_id,
|
||||
num: _num,
|
||||
discount_price
|
||||
};
|
||||
}
|
||||
|
||||
if (this.isRepeat) return;
|
||||
this.isRepeat = true;
|
||||
|
||||
this.$emit('addCart', event.currentTarget.id);
|
||||
|
||||
this.$api.sendRequest({
|
||||
url: api,
|
||||
data: {
|
||||
cart_id,
|
||||
sku_id: data.sku_id,
|
||||
num: _num
|
||||
},
|
||||
success: res => {
|
||||
this.isRepeat = false;
|
||||
if (res.code == 0) {
|
||||
if (cart_id == 0) {
|
||||
this.cartList['goods_' + data.goods_id]['sku_' + data.sku_id].cart_id =
|
||||
res.data;
|
||||
}
|
||||
this.$util.showToast({
|
||||
title: "商品添加购物车成功"
|
||||
});
|
||||
this.$store.commit('setCartChange');
|
||||
this.$store.dispatch('cartCalculate');
|
||||
this.$emit("cartListChange", this.cartList);
|
||||
} else {
|
||||
this.$util.showToast({
|
||||
title: res.message
|
||||
});
|
||||
}
|
||||
}
|
||||
let cartNum = cart ? cart.num : 0;
|
||||
let api = cart && cart.cart_id ? '/api/cart/edit' : '/api/cart/add';
|
||||
let minBuy = data.min_buy > 0 ? data.min_buy : 1;
|
||||
let num = cartNum >= minBuy ? cartNum : minBuy;
|
||||
let _num = num;
|
||||
if (cart && cart.cart_id) {
|
||||
_num = _num + (data.min_buy > 0 ? data.min_buy : 1)
|
||||
}
|
||||
let cart_id = cart ? cart.cart_id : 0;
|
||||
if (_num > parseInt(data.stock)) {
|
||||
this.$util.showToast({
|
||||
title: '商品库存不足'
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 多规格
|
||||
* @param {Object} data 商品项
|
||||
*/
|
||||
multiSpecificationGoods(data) {
|
||||
this.$api.sendRequest({
|
||||
url: '/api/goodssku/getInfoForCategory',
|
||||
data: {
|
||||
sku_id: data.sku_id
|
||||
},
|
||||
success: res => {
|
||||
if (res.code >= 0) {
|
||||
let item = res.data;
|
||||
item.unit = item.unit || '件';
|
||||
return;
|
||||
}
|
||||
if (data.is_limit && data.max_buy && _num > parseInt(data.max_buy)) {
|
||||
this.$util.showToast({
|
||||
title: `该商品每人限购${data.max_buy}${data.unit || '件'}`
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.sku_images) item.sku_images = item.sku_images.split(',');
|
||||
else item.sku_images = [];
|
||||
if (cart) {
|
||||
this.cartList['goods_' + data.goods_id]['sku_' + data.sku_id].num = _num;
|
||||
} else {
|
||||
|
||||
// 多规格时合并主图
|
||||
if (item.goods_spec_format && item.goods_image) {
|
||||
item.goods_image = item.goods_image.split(',');
|
||||
item.sku_images = item.goods_image.concat(item.sku_images);
|
||||
}
|
||||
// 如果商品第一次添加,则初始化数据
|
||||
if (!this.cartList['goods_' + data.goods_id]) {
|
||||
this.cartList['goods_' + data.goods_id] = {};
|
||||
}
|
||||
|
||||
// 当前商品SKU规格
|
||||
if (item.sku_spec_format) item.sku_spec_format = JSON.parse(item.sku_spec_format);
|
||||
let discount_price = data.discount_price;
|
||||
if (data.member_price > 0 && Number(data.member_price) <= Number(data.discount_price)) {
|
||||
discount_price = data.member_price;
|
||||
}
|
||||
|
||||
// 商品SKU格式
|
||||
if (item.goods_spec_format) item.goods_spec_format = JSON.parse(item.goods_spec_format);
|
||||
this.cartList['goods_' + data.goods_id]['sku_' + data.sku_id] = {
|
||||
cart_id,
|
||||
goods_id: data.goods_id,
|
||||
sku_id: data.sku_id,
|
||||
num: _num,
|
||||
discount_price
|
||||
};
|
||||
}
|
||||
|
||||
// 限时折扣
|
||||
if (item.promotion_type == 1) {
|
||||
item.discountTimeMachine = this.$util.countDown(item.end_time - res.timestamp);
|
||||
}
|
||||
if (this.isRepeat) return;
|
||||
this.isRepeat = true;
|
||||
|
||||
if (item.promotion_type == 1 && item.discountTimeMachine) {
|
||||
if (item.member_price > 0 && Number(item.member_price) <= Number(item.discount_price)) {
|
||||
item.show_price = item.member_price;
|
||||
} else {
|
||||
item.show_price = item.discount_price;
|
||||
}
|
||||
} else if (item.member_price > 0) {
|
||||
this.$emit('addCart', event.currentTarget.id);
|
||||
|
||||
this.$api.sendRequest({
|
||||
url: api,
|
||||
data: {
|
||||
cart_id,
|
||||
sku_id: data.sku_id,
|
||||
num: _num
|
||||
},
|
||||
success: res => {
|
||||
this.isRepeat = false;
|
||||
if (res.code == 0) {
|
||||
if (cart_id == 0) {
|
||||
this.cartList['goods_' + data.goods_id]['sku_' + data.sku_id].cart_id =
|
||||
res.data;
|
||||
}
|
||||
this.$util.showToast({
|
||||
title: "商品添加购物车成功"
|
||||
});
|
||||
this.$store.commit('setCartChange');
|
||||
this.$store.dispatch('cartCalculate');
|
||||
this.$emit("cartListChange", this.cartList);
|
||||
} else {
|
||||
this.$util.showToast({
|
||||
title: res.message
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 多规格
|
||||
* @param {Object} data 商品项
|
||||
*/
|
||||
multiSpecificationGoods(data) {
|
||||
this.$api.sendRequest({
|
||||
url: '/api/goodssku/getInfoForCategory',
|
||||
data: {
|
||||
sku_id: data.sku_id
|
||||
},
|
||||
success: res => {
|
||||
if (res.code >= 0) {
|
||||
let item = res.data;
|
||||
item.unit = item.unit || '件';
|
||||
|
||||
if (item.sku_images) item.sku_images = item.sku_images.split(',');
|
||||
else item.sku_images = [];
|
||||
|
||||
// 多规格时合并主图
|
||||
if (item.goods_spec_format && item.goods_image) {
|
||||
item.goods_image = item.goods_image.split(',');
|
||||
item.sku_images = item.goods_image.concat(item.sku_images);
|
||||
}
|
||||
|
||||
// 当前商品SKU规格
|
||||
if (item.sku_spec_format) item.sku_spec_format = JSON.parse(item.sku_spec_format);
|
||||
|
||||
// 商品SKU格式
|
||||
if (item.goods_spec_format) item.goods_spec_format = JSON.parse(item.goods_spec_format);
|
||||
|
||||
// 限时折扣
|
||||
if (item.promotion_type == 1) {
|
||||
item.discountTimeMachine = this.$util.countDown(item.end_time - res.timestamp);
|
||||
}
|
||||
|
||||
if (item.promotion_type == 1 && item.discountTimeMachine) {
|
||||
if (item.member_price > 0 && Number(item.member_price) <= Number(item.discount_price)) {
|
||||
item.show_price = item.member_price;
|
||||
} else {
|
||||
item.show_price = item.price;
|
||||
item.show_price = item.discount_price;
|
||||
}
|
||||
this.goodsDetail = item;
|
||||
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.goodsSku) {
|
||||
this.$refs.goodsSku.show("join_cart", (res) => {
|
||||
|
||||
let goods = this.cartList['goods_' + res.goods_id];
|
||||
let cart = null;
|
||||
if (goods && goods['sku_' + res.sku_id]) {
|
||||
cart = goods['sku_' + res.sku_id];
|
||||
}
|
||||
|
||||
if (cart) {
|
||||
this.cartList['goods_' + res.goods_id]['sku_' + res.sku_id].num = res.num;
|
||||
} else {
|
||||
|
||||
// 如果商品第一次添加,则初始化数据
|
||||
if (!this.cartList['goods_' + res.goods_id]) {
|
||||
this.cartList['goods_' + res.goods_id] = {};
|
||||
}
|
||||
|
||||
this.cartList['goods_' + res.goods_id]['sku_' + res.sku_id] = {
|
||||
cart_id: res.cart_id,
|
||||
goods_id: res.goods_id,
|
||||
sku_id: res.sku_id,
|
||||
num: res.num,
|
||||
discount_price: res.discount_price
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
this.$store.dispatch('cartCalculate');
|
||||
this.$emit("cartListChange", this.cartList);
|
||||
|
||||
// 加入购物车动效
|
||||
setTimeout(() => {
|
||||
this.$store.commit('setCartChange');
|
||||
}, 100);
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
} else if (item.member_price > 0) {
|
||||
item.show_price = item.member_price;
|
||||
} else {
|
||||
item.show_price = item.price;
|
||||
}
|
||||
this.goodsDetail = item;
|
||||
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.goodsSku) {
|
||||
this.$refs.goodsSku.show("join_cart", (res) => {
|
||||
|
||||
let goods = this.cartList['goods_' + res.goods_id];
|
||||
let cart = null;
|
||||
if (goods && goods['sku_' + res.sku_id]) {
|
||||
cart = goods['sku_' + res.sku_id];
|
||||
}
|
||||
|
||||
if (cart) {
|
||||
this.cartList['goods_' + res.goods_id]['sku_' + res.sku_id].num = res.num;
|
||||
} else {
|
||||
|
||||
// 如果商品第一次添加,则初始化数据
|
||||
if (!this.cartList['goods_' + res.goods_id]) {
|
||||
this.cartList['goods_' + res.goods_id] = {};
|
||||
}
|
||||
|
||||
this.cartList['goods_' + res.goods_id]['sku_' + res.sku_id] = {
|
||||
cart_id: res.cart_id,
|
||||
goods_id: res.goods_id,
|
||||
sku_id: res.sku_id,
|
||||
num: res.num,
|
||||
discount_price: res.discount_price
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
this.$store.dispatch('cartCalculate');
|
||||
this.$emit("cartListChange", this.cartList);
|
||||
|
||||
// 加入购物车动效
|
||||
setTimeout(() => {
|
||||
this.$store.commit('setCartChange');
|
||||
}, 100);
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
refreshGoodsSkuDetail(data) {
|
||||
this.goodsDetail = Object.assign({}, this.goodsDetail, data);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
refreshGoodsSkuDetail(data) {
|
||||
this.goodsDetail = Object.assign({}, this.goodsDetail, data);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -214,7 +214,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import uniPopup from '@/components/uni-popup/uni-popup-sku.vue';
|
||||
import uniPopup from '@/uni_modules/uni-popup/components/uni-popup/uni-popup-sku.vue';
|
||||
// 商品SKU
|
||||
export default {
|
||||
name: 'ns-goods-sku',
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -75,12 +75,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import uniPopup from '../uni-popup/uni-popup.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
uniPopup
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
newgift: {
|
||||
|
||||
@@ -278,13 +278,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import pickRegions from '@/components/pick-regions/pick-regions.vue'
|
||||
|
||||
export default {
|
||||
name: 'ns-form',
|
||||
components: {
|
||||
pickRegions
|
||||
},
|
||||
props: {
|
||||
data: {
|
||||
type: Array,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
37
components/ns-progress/ns-progress.vue
Normal file
37
components/ns-progress/ns-progress.vue
Normal file
@@ -0,0 +1,37 @@
|
||||
<template>
|
||||
<view class="progress"><view class="progress-bar " ref="progress" :style="{ width: progress + '%' }"></view></view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
props: {
|
||||
progress: {
|
||||
type: [Number, String],
|
||||
default: 10
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.progress {
|
||||
height: 12rpx;
|
||||
overflow: hidden;
|
||||
background-color: #ccc;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
float: left;
|
||||
height: 100%;
|
||||
font-size: $font-size-tag;
|
||||
line-height: 40rpx;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
transition: width 0.6s ease;
|
||||
background-color: #fff;
|
||||
}
|
||||
</style>
|
||||
@@ -30,12 +30,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import uniPopup from '@/components/uni-popup/uni-popup.vue';
|
||||
export default {
|
||||
name: "nsSelectTime",
|
||||
components: {
|
||||
uniPopup
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
//选中日期的键值
|
||||
|
||||
@@ -43,9 +43,6 @@
|
||||
|
||||
<!-- 新版支付组件 订单表为order表 的订单支付时使用该组件 -->
|
||||
<script>
|
||||
import uniPopup from '@/components/uni-popup/uni-popup.vue';
|
||||
import nsSwitch from '@/components/ns-switch/ns-switch.vue';
|
||||
|
||||
// #ifdef H5
|
||||
import {
|
||||
Weixin
|
||||
@@ -54,10 +51,6 @@
|
||||
|
||||
export default {
|
||||
name: 'payment',
|
||||
components: {
|
||||
uniPopup,
|
||||
nsSwitch
|
||||
},
|
||||
props: {
|
||||
// 是否可用余额支付
|
||||
balanceUsable: {
|
||||
|
||||
@@ -78,14 +78,9 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import uniPopup from '@/components/uni-popup/uni-popup.vue';
|
||||
|
||||
// 注册奖励弹出层
|
||||
export default {
|
||||
name: 'register-reward',
|
||||
components: {
|
||||
uniPopup
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
reward: null,
|
||||
|
||||
6
components/sx-rate/common.js
Normal file
6
components/sx-rate/common.js
Normal file
@@ -0,0 +1,6 @@
|
||||
export function getClientRect(selector, component) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let query = component ? uni.createSelectorQuery().in(component) : uni.createSelectorQuery();
|
||||
return query.select(selector).boundingClientRect(resolve).exec()
|
||||
})
|
||||
}
|
||||
218
components/sx-rate/index.vue
Normal file
218
components/sx-rate/index.vue
Normal file
@@ -0,0 +1,218 @@
|
||||
<template>
|
||||
<view class="rate-box" :class="[{ animation }, containerClass]" @touchmove="ontouchmove" @touchend="touchMoving = false">
|
||||
<view
|
||||
v-for="(val, i) in list"
|
||||
:key="val"
|
||||
class="rate"
|
||||
:style="{ fontSize, paddingLeft: i !== 0 ? rateMargin : 0, paddingRight: i < list.length - 1 ? rateMargin : 0 }"
|
||||
:class="[
|
||||
{ scale: !disabled && val <= rateValue && animation && touchMoving, 'color-base-text': val <= rateValue, defaultColor: val > rateValue },
|
||||
`rate-${i}`,
|
||||
rateClass
|
||||
]"
|
||||
:data-val="val"
|
||||
@click="onItemClick"
|
||||
>
|
||||
<text class="iconfont icon-star"></text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getClientRect } from './common';
|
||||
|
||||
export default {
|
||||
name: 'sx-rate',
|
||||
props: {
|
||||
// 当前值
|
||||
value: {
|
||||
type: [Number, String]
|
||||
},
|
||||
// 最大星星数量
|
||||
max: {
|
||||
type: Number,
|
||||
default: 5
|
||||
},
|
||||
// 禁用
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 动画效果
|
||||
animation: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 默认星星颜色
|
||||
defaultColor: {
|
||||
type: String,
|
||||
default: '#ccc'
|
||||
},
|
||||
// 滑选后星星颜色
|
||||
activeColor: {
|
||||
type: String
|
||||
// default: '#FFB700'
|
||||
},
|
||||
// 星星大小
|
||||
fontSize: {
|
||||
type: String,
|
||||
default: 'inherit'
|
||||
},
|
||||
// 星星间距
|
||||
margin: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 自定义类名-容器
|
||||
containerClass: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 自定义类名-星星
|
||||
rateClass: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
index: {
|
||||
// 如果页面中存在多个该组件,通过该属性区分
|
||||
type: [Number, String]
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
rateValue: 0,
|
||||
touchMoving: false,
|
||||
startX: [],
|
||||
startW: 30
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
list() {
|
||||
return [...new Array(this.max)].map((_, i) => i + 1);
|
||||
},
|
||||
rateMargin() {
|
||||
let margin = this.margin;
|
||||
if (!margin) return 0;
|
||||
|
||||
switch (typeof margin) {
|
||||
case 'number':
|
||||
margin = margin * 2 + 'rpx';
|
||||
case 'string':
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
let reg = /^(\d+)([^\d]*)/;
|
||||
let result = reg.exec(margin);
|
||||
if (!result) return 0;
|
||||
|
||||
let [_, num, unit] = result;
|
||||
return num / 2 + unit;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value: {
|
||||
handler(val) {
|
||||
this.rateValue = val;
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 计算星星位置
|
||||
async initStartX() {
|
||||
let { max } = this;
|
||||
this.startX = [];
|
||||
|
||||
for (let i = 0; i < max; i++) {
|
||||
let selector = `.rate-${i}`;
|
||||
let { left, width } = await getClientRect(selector, this);
|
||||
|
||||
this.startX.push(left);
|
||||
this.startW = width;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 手指滑动事件回调
|
||||
* https://github.com/sunxi1997/uni-app-sx-rate/pull/1
|
||||
* 原本的触摸处理在自定了样式后可能会出现bug, 已解决
|
||||
*/
|
||||
async ontouchmove(e) {
|
||||
if (!this.touchMoving) {
|
||||
this.touchMoving = true;
|
||||
// 开始手指滑动时重新计算星星位置,防止星星位置意外变化
|
||||
await this.initStartX();
|
||||
}
|
||||
|
||||
let { startX, startW, max } = this;
|
||||
let { touches } = e;
|
||||
|
||||
// 触摸焦点停留的位置
|
||||
let { pageX } = touches[touches.length - 1];
|
||||
|
||||
// 超出最左边, 0 星
|
||||
if (pageX <= startX[0]) return this.toggle(0);
|
||||
// 刚好在第一颗星
|
||||
else if (pageX <= startX[0] + startW) return this.toggle(1);
|
||||
// 超出最右边, 最大星
|
||||
else if (pageX >= startX[max - 1]) return this.toggle(max);
|
||||
|
||||
//计算星星停留的位置
|
||||
let startXHash = startX.concat(pageX).sort((a, b) => a - b);
|
||||
this.toggle(startXHash.indexOf(pageX));
|
||||
},
|
||||
// 点击回调
|
||||
onItemClick(e) {
|
||||
let { val } = e.currentTarget.dataset;
|
||||
this.toggle(val);
|
||||
},
|
||||
// 修改值
|
||||
toggle(val) {
|
||||
let { disabled } = this;
|
||||
if (disabled) return;
|
||||
if (this.rateValue !== val) {
|
||||
this.rateValue = val;
|
||||
this.$emit('update:value', val);
|
||||
let data = {
|
||||
index: this.index,
|
||||
value: val
|
||||
};
|
||||
this.$emit('change', data);
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@import './sx-rate/iconfont.css';
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
.rate-box {
|
||||
min-height: 1.4em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.rate {
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 1.2em;
|
||||
transition: all 0.15s linear;
|
||||
}
|
||||
|
||||
.rate.scale {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.defaultColor {
|
||||
color: #ccc !important;
|
||||
}
|
||||
.activeColor {
|
||||
}
|
||||
</style>
|
||||
21
components/sx-rate/sx-rate/iconfont.css
Normal file
21
components/sx-rate/sx-rate/iconfont.css
Normal file
@@ -0,0 +1,21 @@
|
||||
@font-face {font-family: "iconfont";
|
||||
src: url('~@/pages_tool/components/sx-rate/sx-rate/iconfont.eot?t=1574760464482'); /* IE9 */
|
||||
src: url('~@/pages_tool/components/sx-rate/sx-rate/iconfont.eot?t=1574760464482#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||
url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAK8AAsAAAAABnAAAAJwAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCCcAp8gQgBNgIkAwgLBgAEIAWEbQcuG6wFyA4lTcHACOEZBUg8fL/2O3f3fTHEkoh28SSayCSxkkgQG6Uz3UvYITu9Qr5K0Vh6Ij6f+8CXKzVBHDvWa6d0lSfK57mc3gQ6kGt8oBz3ojUG9QLqxYEU6B4YRVYqecPYBS7hMYG6QWF0dlOycoGxxFoViFuxkALGuYAksXRVKNccTOJdSTV7zbSAt/D78Y8XxmRKOavq5CZZAOK+7u2svLVode0TggR0vIQc84BEXNQmjugJxumpJ/SNAvsqD77ui8K3i71aBPvrrNIm6IfSe5K58ltNZ3BbU40Blkf9OmKsIW/Un1qddc4dcSma3ArIX7PPXdlxK5l2zJ+aD6TXnQqmu330wqpeWkYN/OnNm/0trU+YvqNR4UN99f+x/tApIFTfR7u39X4gKPnb9pOX5RAQB6DYyc/zOKCD4OUp6KiiPeqnapbAp56NdegrdhLo5wKq+3UG/0fWcyDpCsuWJVVWO5oZO29bXR0FwJ4uV2ONvTeTCVW9I1wVAylyVeNkYudR0rCOsqoN1M1JPd7QDdMTqYZZXQChwwYybT6Q63BIJvYSJX1eUNYReqi7CrsLGyZDbJqIEUWQAPLroJhWKhjHQUyj8mwkrJJROKsI+XyENeIw5LI4xXQqUiA8xxZNtZBHCAMZrJTDFPAcksmUUIWVEkQTlogQVQSbzdS9iUUr5cDUDgyhEIgAxFcHEqMpKTD+eMK09PlsiFAVGQpu6atJ5kMwDfHsEBcLpweZqlX06ruXVzSqCfEQBANiYEpyUAqYh8jIKEGq+nkSCI1gEY2IqURg28OYvlrW+nr5152AOsuUhV2fSy+EwgAAAA==') format('woff2'),
|
||||
url('~@/pages_tool/components/sx-rate/sx-rate/iconfont.woff?t=1574760464482') format('woff'),
|
||||
url('~@/pages_tool/components/sx-rate/sx-rate/iconfont.ttf?t=1574760464482') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
|
||||
url('~@/pages_tool/components/sx-rate/sx-rate/iconfont.svg?t=1574760464482#iconfont') format('svg'); /* iOS 4.1- */
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-family: "iconfont" !important;
|
||||
font-size: inherit;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-star:before {
|
||||
content: "\e6e3";
|
||||
}
|
||||
|
||||
BIN
components/sx-rate/sx-rate/iconfont.eot
Normal file
BIN
components/sx-rate/sx-rate/iconfont.eot
Normal file
Binary file not shown.
29
components/sx-rate/sx-rate/iconfont.svg
Normal file
29
components/sx-rate/sx-rate/iconfont.svg
Normal file
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<!--
|
||||
2013-9-30: Created.
|
||||
-->
|
||||
<svg>
|
||||
<metadata>
|
||||
Created by iconfont
|
||||
</metadata>
|
||||
<defs>
|
||||
|
||||
<font id="iconfont" horiz-adv-x="1024" >
|
||||
<font-face
|
||||
font-family="iconfont"
|
||||
font-weight="500"
|
||||
font-stretch="normal"
|
||||
units-per-em="1024"
|
||||
ascent="896"
|
||||
descent="-128"
|
||||
/>
|
||||
<missing-glyph />
|
||||
|
||||
<glyph glyph-name="star" unicode="" d="M544.256 812.032l117.248-237.568c5.12-10.752 15.36-17.92 27.136-19.456l262.144-37.888c29.696-4.096 41.472-40.448 19.968-61.44l-189.44-184.832c-8.704-8.192-12.288-19.968-10.24-31.744l44.544-261.12c5.12-29.184-25.6-51.712-52.224-37.888l-234.496 123.392c-10.24 5.632-23.04 5.632-33.28 0L261.12-59.904c-26.112-13.824-57.344 8.704-52.224 37.888l44.544 261.12c2.048 11.776-2.048 23.552-10.24 31.744L53.76 455.68C32.256 476.16 44.032 512.512 73.728 517.12l262.144 37.888c11.776 1.536 22.016 9.216 27.136 19.456l117.248 237.568C493.056 838.656 530.944 838.656 544.256 812.032z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
|
||||
|
||||
</font>
|
||||
</defs></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
BIN
components/sx-rate/sx-rate/iconfont.ttf
Normal file
BIN
components/sx-rate/sx-rate/iconfont.ttf
Normal file
Binary file not shown.
BIN
components/sx-rate/sx-rate/iconfont.woff
Normal file
BIN
components/sx-rate/sx-rate/iconfont.woff
Normal file
Binary file not shown.
BIN
components/sx-rate/sx-rate/iconfont.woff2
Normal file
BIN
components/sx-rate/sx-rate/iconfont.woff2
Normal file
Binary file not shown.
@@ -1,105 +0,0 @@
|
||||
<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>
|
||||
.uni-badge {
|
||||
font-family: 'Helvetica Neue', Helvetica, sans-serif;
|
||||
box-sizing: border-box;
|
||||
font-size: 24rpx;
|
||||
line-height: 1;
|
||||
display: inline-block;
|
||||
padding: 6rpx 12rpx;
|
||||
color: #333;
|
||||
border-radius: 200rpx;
|
||||
background-color: #e5e5e5;
|
||||
}
|
||||
|
||||
.uni-badge.uni-badge-inverted {
|
||||
padding: 0 10rpx 0 0;
|
||||
color: #999;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.uni-badge-primary {
|
||||
color: #fff;
|
||||
background-color: #007aff;
|
||||
}
|
||||
|
||||
.uni-badge-primary.uni-badge-inverted {
|
||||
color: #007aff;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.uni-badge-success {
|
||||
color: #fff;
|
||||
background-color: #4cd964;
|
||||
}
|
||||
|
||||
.uni-badge-success.uni-badge-inverted {
|
||||
color: #4cd964;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.uni-badge-warning {
|
||||
color: #fff;
|
||||
background-color: #f0ad4e;
|
||||
}
|
||||
|
||||
.uni-badge-warning.uni-badge-inverted {
|
||||
color: #f0ad4e;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.uni-badge-error {
|
||||
color: #fff;
|
||||
background-color: #dd524d;
|
||||
}
|
||||
|
||||
.uni-badge-error.uni-badge-inverted {
|
||||
color: #dd524d;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.uni-badge--small {
|
||||
transform: scale(0.8);
|
||||
transform-origin: center center;
|
||||
}
|
||||
</style>
|
||||
@@ -1,252 +0,0 @@
|
||||
<template>
|
||||
<view class="uni-countdown">
|
||||
<view
|
||||
v-if="showDay && d > 0"
|
||||
:style="{ borderColor: borderColor, color: color, background: backgroundColor }"
|
||||
class="uni-countdown__number "
|
||||
:class="[backgroundColorClass, colorClass, borderColorClass]"
|
||||
>
|
||||
{{ d }}
|
||||
</view>
|
||||
<view v-if="showDay && d > 0" :style="{ color: splitorColor }" class="uni-countdown__splitor day" :class="splitorColorClass">{{ showColon ? '天' : '天' }}</view>
|
||||
<view
|
||||
:style="{ borderColor: borderColor, color: color, background: backgroundColor }"
|
||||
class="uni-countdown__number "
|
||||
:class="[backgroundColorClass, colorClass, borderColorClass]"
|
||||
>
|
||||
{{ h }}
|
||||
</view>
|
||||
<view :style="{ color: splitorColor }" class="uni-countdown__splitor" :class="splitorColorClass">{{ showColon ? ':' : '时' }}</view>
|
||||
<view
|
||||
:style="{ borderColor: borderColor, color: color, background: backgroundColor }"
|
||||
class="uni-countdown__number "
|
||||
:class="[backgroundColorClass, colorClass, borderColorClass]"
|
||||
>
|
||||
{{ i }}
|
||||
</view>
|
||||
<view :style="{ color: splitorColor }" class="uni-countdown__splitor" :class="splitorColorClass">{{ showColon ? ':' : '分' }}</view>
|
||||
<view
|
||||
:style="{ borderColor: borderColor, color: color, background: backgroundColor }"
|
||||
class="uni-countdown__number "
|
||||
:class="[backgroundColorClass, colorClass, borderColorClass]"
|
||||
>
|
||||
{{ s }}
|
||||
</view>
|
||||
<view v-if="!showColon" :style="{ color: splitorColor }" class="uni-countdown__splitor" :class="splitorColorClass">秒</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'UniCountDown',
|
||||
props: {
|
||||
showDay: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
showColon: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
backgroundColor: {
|
||||
type: String,
|
||||
default: '#FFFFFF'
|
||||
},
|
||||
backgroundColorClass: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
borderColor: {
|
||||
type: String,
|
||||
default: '#000000'
|
||||
},
|
||||
borderColorClass: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: '#000000'
|
||||
},
|
||||
colorClass: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
splitorColor: {
|
||||
type: String,
|
||||
default: '#000000'
|
||||
},
|
||||
splitorColorClass: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
day: {
|
||||
type: [Number, String],
|
||||
default: 0
|
||||
},
|
||||
hour: {
|
||||
type: [Number, String],
|
||||
default: 0
|
||||
},
|
||||
minute: {
|
||||
type: [Number, String],
|
||||
default: 0
|
||||
},
|
||||
second: {
|
||||
type: [Number, String],
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
timer: null,
|
||||
d: '00',
|
||||
h: '00',
|
||||
i: '00',
|
||||
s: '00',
|
||||
leftTime: 0,
|
||||
seconds: 0
|
||||
};
|
||||
},
|
||||
mounted: 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);
|
||||
},
|
||||
watch: {
|
||||
day: function(newVal) {
|
||||
this.timeUp();
|
||||
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);
|
||||
},
|
||||
hour: function(newVal) {
|
||||
this.timeUp();
|
||||
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);
|
||||
},
|
||||
minute: function(newVal) {
|
||||
this.timeUp();
|
||||
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);
|
||||
},
|
||||
second: function(newVal) {
|
||||
this.timeUp();
|
||||
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) {
|
||||
day = Number(day);
|
||||
hours = Number(hours);
|
||||
minutes = Number(minutes);
|
||||
seconds = Number(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">
|
||||
|
||||
.uni-countdown {
|
||||
padding: 2rpx 0;
|
||||
display: inline-flex;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.uni-countdown__splitor {
|
||||
justify-content: center;
|
||||
line-height: 44rpx;
|
||||
padding: 0 5rpx;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
.uni-countdown__splitor.day {
|
||||
line-height: 50rpx;
|
||||
}
|
||||
|
||||
.uni-countdown__number {
|
||||
line-height: 44rpx;
|
||||
justify-content: center;
|
||||
height: 44rpx;
|
||||
border-radius: 6rpx;
|
||||
margin: 0 5rpx;
|
||||
border: 2rpx solid #000;
|
||||
font-size: 24rpx;
|
||||
padding: 0 10rpx;
|
||||
}
|
||||
</style>
|
||||
@@ -1,146 +0,0 @@
|
||||
<template>
|
||||
<view v-if="visibleSync" :class="{ 'uni-drawer--visible': showDrawer, 'uni-drawer--right': rightMode }" class="uni-drawer" @touchmove.stop.prevent="moveHandle">
|
||||
<view class="uni-drawer__mask" @tap="close" ></view>
|
||||
<view class="uni-drawer__content" :class="{ 'safe-area': isIphoneX }"><slot /></view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'UniDrawer',
|
||||
props: {
|
||||
/**
|
||||
* 显示状态
|
||||
*/
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
/**
|
||||
* 显示模式(左、右),只在初始化生效
|
||||
*/
|
||||
mode: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
/**
|
||||
* 蒙层显示状态
|
||||
*/
|
||||
mask: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
visibleSync: false,
|
||||
showDrawer: false,
|
||||
rightMode: false,
|
||||
closeTimer: null,
|
||||
watchTimer: null,
|
||||
isIphoneX: false
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
visible(val) {
|
||||
clearTimeout(this.watchTimer);
|
||||
setTimeout(() => {
|
||||
this.showDrawer = val;
|
||||
}, 100);
|
||||
if (this.visibleSync) {
|
||||
clearTimeout(this.closeTimer);
|
||||
}
|
||||
if (val) {
|
||||
this.visibleSync = val;
|
||||
} else {
|
||||
this.watchTimer = setTimeout(() => {
|
||||
this.visibleSync = val;
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.isIphoneX = this.$util.uniappIsIPhoneX();
|
||||
this.visibleSync = this.visible;
|
||||
setTimeout(() => {
|
||||
this.showDrawer = this.visible;
|
||||
}, 100);
|
||||
this.rightMode = this.mode === 'right';
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
this.showDrawer = false;
|
||||
this.closeTimer = setTimeout(() => {
|
||||
this.visibleSync = false;
|
||||
this.$emit('close');
|
||||
}, 200);
|
||||
},
|
||||
moveHandle() {}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
.uni-drawer {
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
z-index: 999;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.uni-drawer.uni-drawer--right .uni-drawer__content {
|
||||
left: auto;
|
||||
right: 0;
|
||||
transform: translatex(100%);
|
||||
}
|
||||
|
||||
.uni-drawer.uni-drawer--visible {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.uni-drawer.uni-drawer--visible .uni-drawer__content {
|
||||
transform: translatex(0);
|
||||
}
|
||||
|
||||
.uni-drawer.uni-drawer--visible .uni-drawer__mask {
|
||||
display: block;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.uni-drawer__mask {
|
||||
display: block;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
|
||||
.uni-drawer__content {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 61.8%;
|
||||
height: 100%;
|
||||
background: #fff;
|
||||
transition: all 0.3s ease-out;
|
||||
transform: translatex(-100%);
|
||||
}
|
||||
|
||||
.safe-area {
|
||||
padding-bottom: 68rpx;
|
||||
padding-top: 44rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
</style>
|
||||
@@ -1,223 +0,0 @@
|
||||
<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 * 2 + 'rpx', top: left * 2 + 'rpx' }" class="uni-grid-item__box-dot" />
|
||||
<view v-if="marker === 'badge'" :style="{ left: top * 2 + 'rpx', top: left * 2 + 'rpx' }" 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 * 2 + 'rpx', top: left * 2 + 'rpx' }" class="uni-grid-item__box-image">
|
||||
<image :style="{ width: imgWidth * 2 + 'rpx' }" :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: '#e5e5e5'
|
||||
};
|
||||
},
|
||||
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() {
|
||||
this.grid.change({
|
||||
detail: {
|
||||
index: this.index
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.uni-grid-item {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.uni-grid-item__box {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.uni-grid-item__box-item {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: 32rpx;
|
||||
color: #666;
|
||||
padding: 20rpx 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.uni-grid-item__box-item .image {
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
}
|
||||
|
||||
.uni-grid-item__box-item .text {
|
||||
font-size: 26rpx;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
.uni-grid-item__box.uni-grid-item__box-square {
|
||||
height: 0;
|
||||
padding-top: 100%;
|
||||
}
|
||||
|
||||
.uni-grid-item__box.uni-grid-item__box-square .uni-grid-item__box-item {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.uni-grid-item__box.border {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
border-bottom: 2rpx #e5e5e5 solid;
|
||||
border-right: 2rpx #e5e5e5 solid;
|
||||
}
|
||||
|
||||
.uni-grid-item__box.border-top {
|
||||
border-top: 2rpx #e5e5e5 solid;
|
||||
}
|
||||
|
||||
.uni-grid-item__box.uni-highlight:active {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.uni-grid-item__box-badge,
|
||||
.uni-grid-item__box-dot,
|
||||
.uni-grid-item__box-image {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.uni-grid-item__box-dot {
|
||||
width: 20rpx;
|
||||
height: 20rpx;
|
||||
background: #ff5a5f;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.uni-grid-item__box-badge {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.uni-grid-item__box-image {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.uni-grid-item__box-image .box-image {
|
||||
width: 90rpx;
|
||||
}
|
||||
</style>
|
||||
@@ -1,95 +0,0 @@
|
||||
<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: '#e5e5e5'
|
||||
},
|
||||
// 全局标记水平方向移动距离 ,起点为中心,负数为左移动,正数为右移动
|
||||
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) * 2 + 'rpx';
|
||||
typeof fn === 'function' && fn(width);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
.uni-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
box-sizing: border-box;
|
||||
border-left: 2rpx #e5e5e5 solid;
|
||||
}
|
||||
</style>
|
||||
@@ -1,96 +0,0 @@
|
||||
export default {
|
||||
'contact': '\ue100',
|
||||
'person': '\ue101',
|
||||
'personadd': '\ue102',
|
||||
'contact-filled': '\ue130',
|
||||
'person-filled': '\ue131',
|
||||
'personadd-filled': '\ue132',
|
||||
'phone': '\ue200',
|
||||
'email': '\ue201',
|
||||
'chatbubble': '\ue202',
|
||||
'chatboxes': '\ue203',
|
||||
'phone-filled': '\ue230',
|
||||
'email-filled': '\ue231',
|
||||
'chatbubble-filled': '\ue232',
|
||||
'chatboxes-filled': '\ue233',
|
||||
'weibo': '\ue260',
|
||||
'weixin': '\ue261',
|
||||
'pengyouquan': '\ue262',
|
||||
'chat': '\ue263',
|
||||
'qq': '\ue264',
|
||||
'videocam': '\ue300',
|
||||
'camera': '\ue301',
|
||||
'mic': '\ue302',
|
||||
'location': '\ue303',
|
||||
'mic-filled': '\ue332',
|
||||
'speech': '\ue332',
|
||||
'location-filled': '\ue333',
|
||||
'micoff': '\ue360',
|
||||
'image': '\ue363',
|
||||
'map': '\ue364',
|
||||
'compose': '\ue400',
|
||||
'trash': '\ue401',
|
||||
'upload': '\ue402',
|
||||
'download': '\ue403',
|
||||
'close': '\ue404',
|
||||
'redo': '\ue405',
|
||||
'undo': '\ue406',
|
||||
'refresh': '\ue407',
|
||||
'star': '\ue408',
|
||||
'plus': '\ue409',
|
||||
'minus': '\ue410',
|
||||
'circle': '\ue411',
|
||||
'checkbox': '\ue411',
|
||||
'close-filled': '\ue434',
|
||||
'clear': '\ue434',
|
||||
'refresh-filled': '\ue437',
|
||||
'star-filled': '\ue438',
|
||||
'plus-filled': '\ue439',
|
||||
'minus-filled': '\ue440',
|
||||
'circle-filled': '\ue441',
|
||||
'checkbox-filled': '\ue442',
|
||||
'closeempty': '\ue460',
|
||||
'refreshempty': '\ue461',
|
||||
'reload': '\ue462',
|
||||
'starhalf': '\ue463',
|
||||
'spinner': '\ue464',
|
||||
'spinner-cycle': '\ue465',
|
||||
'search': '\ue466',
|
||||
'plusempty': '\ue468',
|
||||
'forward': '\ue470',
|
||||
'back': '\ue471',
|
||||
'left-nav': '\ue471',
|
||||
'checkmarkempty': '\ue472',
|
||||
'home': '\ue500',
|
||||
'navigate': '\ue501',
|
||||
'gear': '\ue502',
|
||||
'paperplane': '\ue503',
|
||||
'info': '\ue504',
|
||||
'help': '\ue505',
|
||||
'locked': '\ue506',
|
||||
'more': '\ue507',
|
||||
'flag': '\ue508',
|
||||
'home-filled': '\ue530',
|
||||
'gear-filled': '\ue532',
|
||||
'info-filled': '\ue534',
|
||||
'help-filled': '\ue535',
|
||||
'more-filled': '\ue537',
|
||||
'settings': '\ue560',
|
||||
'list': '\ue562',
|
||||
'bars': '\ue563',
|
||||
'loop': '\ue565',
|
||||
'paperclip': '\ue567',
|
||||
'eye': '\ue568',
|
||||
'arrowup': '\ue580',
|
||||
'arrowdown': '\ue581',
|
||||
'arrowleft': '\ue582',
|
||||
'arrowright': '\ue583',
|
||||
'arrowthinup': '\ue584',
|
||||
'arrowthindown': '\ue585',
|
||||
'arrowthinleft': '\ue586',
|
||||
'arrowthinright': '\ue587',
|
||||
'pulldown': '\ue588',
|
||||
'closefill': '\ue589',
|
||||
'sound': '\ue590',
|
||||
'scan': '\ue612'
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,261 +0,0 @@
|
||||
<template>
|
||||
<view class="uni-numbox" :class="{ small: size == 'small' }">
|
||||
<button type="default" class="decrease" :class="{ disabled: inputValue <= min || disabled, small: size == 'small' }" @click="_calcValue('minus')">-</button>
|
||||
<!-- <view
|
||||
class="uni-numbox__minus"
|
||||
> -->
|
||||
<!-- :style="'background-image:url(' + $util.img('public/uniapp/jian.png') + ')'" -->
|
||||
<!-- </view> -->
|
||||
<!-- <input :disabled="disabled || inputDisabled" class="uni-input uni-numbox__value" type="number" @input="_onInput" @blur="_onInput" :class="{ small: size == 'small' }" v-model="inputValue"/> -->
|
||||
<input :disabled="disabled || inputDisabled" class="uni-input uni-numbox__value" type="number" @blur="_onInput" :class="{ small: size == 'small' }" v-model="inputValue" />
|
||||
<button type="default" class="increase" :class="{ disabled: inputValue >= max || disabled, small: size == 'small' }" @click="_calcValue('plus')">+</button>
|
||||
<!-- <view
|
||||
class="uni-numbox__plus" @click="_calcValue('plus')"
|
||||
:style="'background-image:url(' + $util.img('public/uniapp/jia.png') + ')'"
|
||||
>
|
||||
</view> -->
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'UniNumberBox',
|
||||
props: {
|
||||
value: {
|
||||
type: [Number, String],
|
||||
default: 1
|
||||
},
|
||||
min: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
max: {
|
||||
type: Number,
|
||||
default: 100
|
||||
},
|
||||
step: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
inputDisabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: 'default'
|
||||
},
|
||||
index: {
|
||||
type: [Number, String],
|
||||
default: -1
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
inputValue: 0,
|
||||
initialValue: 0, // 初始值,防止第一次触发变化
|
||||
initialIndex: 0, // 初始索引,防止第一次触发变化
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
value(val) {
|
||||
this.inputValue = +val;
|
||||
},
|
||||
inputValue(newVal, oldVal, params) {
|
||||
// 与初始值相同,不允许操作
|
||||
if (+newVal != 0 && +newVal == this.initialValue) return;
|
||||
|
||||
// 索引不同,不允许操作
|
||||
if (this.initialIndex != this.index) return;
|
||||
|
||||
if (+newVal !== +oldVal) {
|
||||
this.$emit('change', newVal, params);
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.initialValue = +this.value;
|
||||
this.inputValue = +this.value;
|
||||
this.initialIndex = this.index;
|
||||
},
|
||||
methods: {
|
||||
_calcValue(type) {
|
||||
if (this.disabled) {
|
||||
return;
|
||||
}
|
||||
const scale = this._getDecimalScale();
|
||||
let value = this.inputValue * scale;
|
||||
let step = this.step * scale;
|
||||
if (type === 'minus') {
|
||||
value -= step;
|
||||
} else if (type === 'plus') {
|
||||
value += step;
|
||||
}
|
||||
|
||||
if (value < this.min && type === 'minus') {
|
||||
this.$emit('limit', {
|
||||
value: this.inputValue,
|
||||
type
|
||||
}, this.index);
|
||||
return;
|
||||
}
|
||||
|
||||
if (value > this.max && type === 'plus') {
|
||||
this.$emit('limit', {
|
||||
value: this.inputValue,
|
||||
type
|
||||
}, this.index);
|
||||
return;
|
||||
}
|
||||
|
||||
this.inputValue = value / scale;
|
||||
},
|
||||
_getDecimalScale() {
|
||||
let scale = 1;
|
||||
// 浮点型
|
||||
if (~~this.step !== this.step) {
|
||||
scale = Math.pow(10, (this.step + '').split('.')[1].length);
|
||||
}
|
||||
return scale;
|
||||
},
|
||||
_onInput(event) {
|
||||
setTimeout(() => {
|
||||
let value = event.detail.value;
|
||||
// if (!/(^[1-9]\d*$)/.test(value)) value = this.min;
|
||||
// if (!value) {
|
||||
// this.inputValue = 0;
|
||||
// return;
|
||||
// }
|
||||
value = +value;
|
||||
|
||||
if (value > this.max) {
|
||||
value = this.max;
|
||||
this.$util.showToast({
|
||||
title: '商品库存不足'
|
||||
});
|
||||
} else if (value < this.min) {
|
||||
this.$util.showToast({
|
||||
title: '商品最少购买' + this.min + '件'
|
||||
});
|
||||
value = this.min;
|
||||
}
|
||||
// 如果没有最小购买,同时也删除了输入框的内容,默认赋值为1
|
||||
if (!value) value = 1;
|
||||
|
||||
this.inputValue = value;
|
||||
this.$forceUpdate();
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.uni-numbox {
|
||||
display: inline-flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
height: 70rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.uni-numbox.small {
|
||||
height: 44rpx;
|
||||
}
|
||||
|
||||
.uni-numbox:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
transform-origin: center;
|
||||
box-sizing: border-box;
|
||||
pointer-events: none;
|
||||
top: -50%;
|
||||
left: -50%;
|
||||
right: -50%;
|
||||
bottom: -50%;
|
||||
border-radius: 12rpx;
|
||||
transform: scale(0.5);
|
||||
}
|
||||
|
||||
.uni-numbox__minus,
|
||||
.uni-numbox__plus {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
border-radius: 50%;
|
||||
background-size: 100% 100%;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.uni-numbox__value {
|
||||
position: relative;
|
||||
background-color: $color-bg;
|
||||
width: 80rpx;
|
||||
height: 40rpx;
|
||||
text-align: center;
|
||||
border: 1px solid $color-line;
|
||||
display: inline-block;
|
||||
line-height: 36rpx;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
vertical-align: top;
|
||||
min-height: initial;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.uni-numbox__value.small {
|
||||
width: 60rpx;
|
||||
font-size: $font-size-tag;
|
||||
}
|
||||
|
||||
.uni-numbox__value:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
transform-origin: center;
|
||||
box-sizing: border-box;
|
||||
pointer-events: none;
|
||||
top: -50%;
|
||||
left: -50%;
|
||||
right: -50%;
|
||||
bottom: -50%;
|
||||
border-top-width: 0;
|
||||
border-bottom-width: 0;
|
||||
transform: scale(0.5);
|
||||
}
|
||||
|
||||
.uni-numbox--disabled {
|
||||
color: silver;
|
||||
}
|
||||
|
||||
.uni-numbox button {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
display: inline-block;
|
||||
box-sizing: content-box;
|
||||
border: 1px solid $color-line;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
background-color: #fff;
|
||||
font-weight: bold;
|
||||
|
||||
&.disabled {
|
||||
color: $color-line;
|
||||
background-color: #f8f8f8 !important;
|
||||
}
|
||||
|
||||
&.decrease {
|
||||
font-size: 44rpx;
|
||||
line-height: 32rpx;
|
||||
}
|
||||
|
||||
&.increase {
|
||||
font-size: $font-size-toolbar;
|
||||
line-height: 36rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,221 +0,0 @@
|
||||
<template>
|
||||
<view v-if="showPopup" class="uni-popup">
|
||||
<view :class="[ani, animation ? 'ani' : '', !custom ? 'uni-custom' : '']" class="uni-popup__mask" @click="close(true)" ></view>
|
||||
<view :class="[type, ani, animation ? 'ani' : '', !custom ? 'uni-custom' : '']" class="uni-popup__wrapper goodslist-uni-popup safe-area" @click="close(true)" v-if="isIphoneX">
|
||||
<view class="uni-popup__wrapper-box goodslist-uni-popup-box" @click.stop="clear"><slot /></view>
|
||||
</view>
|
||||
<view :class="[type, ani, animation ? 'ani' : '', !custom ? 'uni-custom' : '']" class="uni-popup__wrapper goodslist-uni-popup" @click="close(true)" v-else>
|
||||
<view class="uni-popup__wrapper-box goodslist-uni-popup-box" @click.stop="clear"><slot /></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'UniPopup',
|
||||
props: {
|
||||
// 开启动画
|
||||
animation: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 弹出层类型,可选值,top: 顶部弹出层;bottom:底部弹出层;center:全屏弹出层
|
||||
type: {
|
||||
type: String,
|
||||
default: 'center'
|
||||
},
|
||||
// 是否开启自定义
|
||||
custom: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// maskClick
|
||||
maskClick: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
ani: '',
|
||||
showPopup: false,
|
||||
callback: null,
|
||||
isIphoneX: false
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
show(newValue) {
|
||||
if (newValue) {
|
||||
this.open();
|
||||
} else {
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.isIphoneX = this.$util.uniappIsIPhoneX();
|
||||
},
|
||||
methods: {
|
||||
clear() {},
|
||||
open(callback) {
|
||||
if (callback) this.callback = callback;
|
||||
|
||||
this.$emit('change', {
|
||||
show: true
|
||||
});
|
||||
this.showPopup = true;
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.ani = 'uni-' + this.type;
|
||||
}, 30);
|
||||
});
|
||||
},
|
||||
close(type, callback) {
|
||||
if (!this.maskClick && type) return;
|
||||
this.$emit('change', {
|
||||
show: false
|
||||
});
|
||||
this.ani = '';
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.showPopup = false;
|
||||
}, 300);
|
||||
});
|
||||
|
||||
if (callback) callback();
|
||||
|
||||
if (this.callback) this.callback.call(this);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
|
||||
.uni-popup {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 999;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.uni-popup__mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 998;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.uni-popup__mask.ani {
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.uni-popup__mask.uni-bottom,
|
||||
.uni-popup__mask.uni-center,
|
||||
.uni-popup__mask.uni-right,
|
||||
.uni-popup__mask.uni-left,
|
||||
.uni-popup__mask.uni-top {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper {
|
||||
position: absolute;
|
||||
z-index: 999;
|
||||
box-sizing: border-box;
|
||||
//background: #ffffff;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.ani {
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.top {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.bottom {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translateY(100%);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.right {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.left {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.center {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
transform: scale(1.2);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper-box {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
|
||||
//background: #fff;
|
||||
}
|
||||
.uni-popup__wrapper.uni-custom.center .uni-popup__wrapper-box {
|
||||
position: relative;
|
||||
max-width: 80%;
|
||||
max-height: 80%;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.uni-custom.bottom .uni-popup__wrapper-box,
|
||||
.uni-popup__wrapper.uni-custom.top .uni-popup__wrapper-box {
|
||||
width: 100%;
|
||||
max-height: 500px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.uni-bottom,
|
||||
.uni-popup__wrapper.uni-top {
|
||||
transform: translateY(0);
|
||||
}
|
||||
.uni-popup__wrapper.uni-left,
|
||||
.uni-popup__wrapper.uni-right {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.uni-center {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* isIphoneX系列手机底部安全距离 */
|
||||
.bottom.safe-area {
|
||||
padding-bottom: constant(safe-area-inset-bottom);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
</style>
|
||||
@@ -1,222 +0,0 @@
|
||||
<template>
|
||||
<view v-if="showPopup" class="uni-popup">
|
||||
<view :class="[ani, animation ? 'ani' : '', !custom ? 'uni-custom' : '']" class="uni-popup__mask" @click="close(true)" ></view>
|
||||
<view :class="[type, ani, animation ? 'ani' : '', !custom ? 'uni-custom' : '']" class="uni-popup__wrapper safe-area" @click="close(true)" v-if="isIphoneX">
|
||||
<view class="uni-popup__wrapper-box" @click.stop="clear"><slot /></view>
|
||||
</view>
|
||||
<view :class="[type, ani, animation ? 'ani' : '', !custom ? 'uni-custom' : '']" class="uni-popup__wrapper" @click="close(true)" v-else>
|
||||
<view class="uni-popup__wrapper-box" @click.stop="clear"><slot /></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'UniPopup',
|
||||
props: {
|
||||
// 开启动画
|
||||
animation: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 弹出层类型,可选值,top: 顶部弹出层;bottom:底部弹出层;center:全屏弹出层
|
||||
type: {
|
||||
type: String,
|
||||
default: 'center'
|
||||
},
|
||||
// 是否开启自定义
|
||||
custom: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// maskClick
|
||||
maskClick: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
ani: '',
|
||||
showPopup: false,
|
||||
callback: null,
|
||||
isIphoneX: false
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
show(newValue) {
|
||||
if (newValue) {
|
||||
this.open();
|
||||
} else {
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.isIphoneX = this.$util.uniappIsIPhoneX();
|
||||
},
|
||||
methods: {
|
||||
clear() {},
|
||||
open(callback) {
|
||||
if (callback) this.callback = callback;
|
||||
|
||||
this.$emit('change', {
|
||||
show: true
|
||||
});
|
||||
this.showPopup = true;
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.ani = 'uni-' + this.type;
|
||||
}, 30);
|
||||
});
|
||||
},
|
||||
close(type, callback) {
|
||||
|
||||
if (!this.maskClick && type) return;
|
||||
this.$emit('change', {
|
||||
show: false
|
||||
});
|
||||
this.ani = '';
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.showPopup = false;
|
||||
}, 300);
|
||||
});
|
||||
|
||||
if (callback) callback();
|
||||
|
||||
if (this.callback) this.callback.call(this);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
|
||||
.uni-popup {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 999;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.uni-popup__mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 998;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.uni-popup__mask.ani {
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.uni-popup__mask.uni-bottom,
|
||||
.uni-popup__mask.uni-center,
|
||||
.uni-popup__mask.uni-right,
|
||||
.uni-popup__mask.uni-left,
|
||||
.uni-popup__mask.uni-top {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper {
|
||||
position: absolute;
|
||||
z-index: 999;
|
||||
box-sizing: border-box;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.ani {
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.top {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.bottom {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translateY(100%);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.right {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.left {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.center {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
transform: scale(1.2);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper-box {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
|
||||
background: #fff;
|
||||
}
|
||||
.uni-popup__wrapper.uni-custom.center .uni-popup__wrapper-box {
|
||||
position: relative;
|
||||
max-width: 80%;
|
||||
max-height: 80%;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.uni-custom.bottom .uni-popup__wrapper-box,
|
||||
.uni-popup__wrapper.uni-custom.top .uni-popup__wrapper-box {
|
||||
width: 100%;
|
||||
max-height: 500px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.uni-bottom,
|
||||
.uni-popup__wrapper.uni-top {
|
||||
transform: translateY(0);
|
||||
}
|
||||
.uni-popup__wrapper.uni-left,
|
||||
.uni-popup__wrapper.uni-right {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.uni-center {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* isIphoneX系列手机底部安全距离 */
|
||||
.bottom.safe-area {
|
||||
padding-bottom: constant(safe-area-inset-bottom);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
</style>
|
||||
@@ -1,244 +0,0 @@
|
||||
<template>
|
||||
<view v-if="showPopup" class="uni-popup" :class="customClass" :style="{'top': top}">
|
||||
<view :class="[ani, animation ? 'ani' : '', !custom ? 'uni-custom' : '']" class="uni-popup__mask" @click="close(true)" ></view>
|
||||
<view :class="[type, ani, animation ? 'ani' : '', !custom ? 'uni-custom' : '']" class="uni-popup__wrapper goodslist-uni-popup safe-area" @click="close(true)" v-if="isIphoneX">
|
||||
<view class="uni-popup__wrapper-box goodslist-uni-popup-box" @click.stop="clear">
|
||||
<slot />
|
||||
</view>
|
||||
</view>
|
||||
<view :class="[type, ani, animation ? 'ani' : '', !custom ? 'uni-custom' : '']" class="uni-popup__wrapper goodslist-uni-popup" @click="close(true)" v-else>
|
||||
<view class="uni-popup__wrapper-box goodslist-uni-popup-box" @click.stop="clear">
|
||||
<slot />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'UniPopup',
|
||||
props: {
|
||||
// 开启动画
|
||||
animation: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 弹出层类型,可选值,top: 顶部弹出层;bottom:底部弹出层;center:全屏弹出层
|
||||
type: {
|
||||
type: String,
|
||||
default: 'center'
|
||||
},
|
||||
// 是否开启自定义
|
||||
custom: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// maskClick
|
||||
maskClick: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
top: {
|
||||
type: String,
|
||||
default: '0'
|
||||
},
|
||||
customClass: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
ani: '',
|
||||
showPopup: false,
|
||||
callback: null,
|
||||
isIphoneX: false
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
show(newValue) {
|
||||
if (newValue) {
|
||||
this.open();
|
||||
} else {
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.isIphoneX = this.$util.uniappIsIPhoneX();
|
||||
},
|
||||
methods: {
|
||||
clear() {},
|
||||
open(callback) {
|
||||
if (callback) this.callback = callback;
|
||||
|
||||
this.$emit('change', {
|
||||
show: true
|
||||
});
|
||||
this.showPopup = true;
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.ani = 'uni-' + this.type;
|
||||
}, 30);
|
||||
});
|
||||
},
|
||||
close(type, callback) {
|
||||
if (!this.maskClick && type) return;
|
||||
this.$emit('change', {
|
||||
show: false
|
||||
});
|
||||
this.ani = '';
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.showPopup = false;
|
||||
}, 300);
|
||||
});
|
||||
|
||||
if (callback) callback();
|
||||
|
||||
if (this.callback) this.callback.call(this);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.uni-popup {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 999;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.uni-popup__mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 998;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.uni-popup__mask.ani {
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.uni-popup__mask.uni-bottom,
|
||||
.uni-popup__mask.uni-center,
|
||||
.uni-popup__mask.uni-right,
|
||||
.uni-popup__mask.uni-left,
|
||||
.uni-popup__mask.uni-top {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper {
|
||||
position: absolute;
|
||||
z-index: 999;
|
||||
box-sizing: border-box;
|
||||
//background: #ffffff;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.ani {
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.top {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.bottom {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translateY(100%);
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.right {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.left {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.center {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
transform: scale(1.2);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper-box {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.uni-custom.center .uni-popup__wrapper-box {
|
||||
position: relative;
|
||||
max-width: 80%;
|
||||
max-height: 80%;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.uni-custom.bottom .uni-popup__wrapper-box,
|
||||
.uni-popup__wrapper.uni-custom.top .uni-popup__wrapper-box {
|
||||
width: 100%;
|
||||
max-height: 500px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.uni-bottom,
|
||||
.uni-popup__wrapper.uni-top {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.uni-left,
|
||||
.uni-popup__wrapper.uni-right {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.uni-center {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* isIphoneX系列手机底部安全距离 */
|
||||
.bottom.safe-area {
|
||||
padding-bottom: constant(safe-area-inset-bottom);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
|
||||
.left.safe-area {
|
||||
padding-bottom: 68rpx;
|
||||
}
|
||||
|
||||
.right.safe-area {
|
||||
padding-bottom: 68rpx;
|
||||
}
|
||||
</style>
|
||||
@@ -1,158 +0,0 @@
|
||||
<template>
|
||||
<view
|
||||
v-if="text"
|
||||
:class="[
|
||||
disabled === true || disabled === 'true' ? 'uni-tag--disabled' : '',
|
||||
inverted === true || inverted === 'true' ? 'uni-tag--inverted' : '',
|
||||
circle === true || circle === 'true' ? 'uni-tag--circle' : '',
|
||||
mark === true || mark === 'true' ? 'uni-tag--mark' : '',
|
||||
'uni-tag--' + size,
|
||||
'uni-tag--' + type
|
||||
]"
|
||||
class="uni-tag"
|
||||
@click="onClick()"
|
||||
>
|
||||
{{ text }}
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'UniTag',
|
||||
props: {
|
||||
type: {
|
||||
// 标签类型default、primary、success、warning、danger、royal
|
||||
type: String,
|
||||
default: 'default'
|
||||
},
|
||||
size: {
|
||||
// 标签大小 normal, small
|
||||
type: String,
|
||||
default: 'normal'
|
||||
},
|
||||
// 标签内容
|
||||
text: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
disabled: {
|
||||
// 是否为禁用状态
|
||||
type: [String, Boolean],
|
||||
defalut: false
|
||||
},
|
||||
inverted: {
|
||||
// 是否为空心
|
||||
type: [String, Boolean],
|
||||
defalut: false
|
||||
},
|
||||
circle: {
|
||||
// 是否为圆角样式
|
||||
type: [String, Boolean],
|
||||
defalut: false
|
||||
},
|
||||
mark: {
|
||||
// 是否为标记样式
|
||||
type: [String, Boolean],
|
||||
defalut: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onClick() {
|
||||
if (this.disabled === true || this.disabled === 'true') {
|
||||
return;
|
||||
}
|
||||
this.$emit('click');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
.uni-tag {
|
||||
box-sizing: border-box;
|
||||
padding: 0 32rpx;
|
||||
height: 60rpx;
|
||||
line-height: calc(60rpx - 2px);
|
||||
font-size: 28rpx;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
color: #333;
|
||||
border-radius: 6rpx;
|
||||
background-color: #f8f8f8;
|
||||
border: 1px solid #f8f8f8;
|
||||
}
|
||||
|
||||
.uni-tag--circle {
|
||||
border-radius: 30rpx;
|
||||
}
|
||||
|
||||
.uni-tag--mark {
|
||||
border-radius: 0 30rpx 30rpx 0;
|
||||
}
|
||||
|
||||
.uni-tag--disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.uni-tag--small {
|
||||
height: 40rpx;
|
||||
padding: 0 16rpx;
|
||||
line-height: calc(40rpx - 2px);
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.uni-tag--primary {
|
||||
color: #fff;
|
||||
background-color: #007aff;
|
||||
border: 1px solid #007aff;
|
||||
}
|
||||
|
||||
.uni-tag--primary.uni-tag--inverted {
|
||||
color: #007aff;
|
||||
background-color: #fff;
|
||||
border: 1px solid #007aff;
|
||||
}
|
||||
|
||||
.uni-tag--success {
|
||||
color: #fff;
|
||||
background-color: #4cd964;
|
||||
border: 1px solid #4cd964;
|
||||
}
|
||||
|
||||
.uni-tag--success.uni-tag--inverted {
|
||||
color: #4cd964;
|
||||
background-color: #fff;
|
||||
border: 1px solid #4cd964;
|
||||
}
|
||||
|
||||
.uni-tag--warning {
|
||||
color: #fff;
|
||||
background-color: #f0ad4e;
|
||||
border: 1px solid #f0ad4e;
|
||||
}
|
||||
|
||||
.uni-tag--warning.uni-tag--inverted {
|
||||
color: #f0ad4e;
|
||||
background-color: #fff;
|
||||
border: 1px solid #f0ad4e;
|
||||
}
|
||||
|
||||
.uni-tag--error {
|
||||
color: #fff;
|
||||
background-color: #dd524d;
|
||||
border: 1px solid #dd524d;
|
||||
}
|
||||
|
||||
.uni-tag--error.uni-tag--inverted {
|
||||
color: #dd524d;
|
||||
background-color: #fff;
|
||||
border: 1px solid #dd524d;
|
||||
}
|
||||
|
||||
.uni-tag--inverted {
|
||||
color: #333;
|
||||
background-color: #fff;
|
||||
border: 1px solid #f8f8f8;
|
||||
}
|
||||
</style>
|
||||
98
components/yuyue-date/yuyue-date.js
Normal file
98
components/yuyue-date/yuyue-date.js
Normal file
@@ -0,0 +1,98 @@
|
||||
//字符串拼接
|
||||
export function strFormat(str) {
|
||||
return str < 10 ? `0${str}` : str
|
||||
}
|
||||
// 获取当前时间
|
||||
export function currentTime() {
|
||||
const myDate = new Date();
|
||||
const year = myDate.getFullYear()
|
||||
const m = myDate.getMonth() + 1;
|
||||
const d = myDate.getDate();
|
||||
// const date = year + '-' + strFormat(m) + '-' + strFormat(d); // 隐藏年
|
||||
const date = strFormat(m) + '-' + strFormat(d);
|
||||
|
||||
const hour = myDate.getHours()
|
||||
const min = myDate.getMinutes()
|
||||
const secon = myDate.getSeconds()
|
||||
const time = strFormat(hour) + ':' + strFormat(min) + ':' + strFormat(secon);
|
||||
return {
|
||||
year,
|
||||
date,
|
||||
time
|
||||
}
|
||||
}
|
||||
|
||||
//时间戳转日期
|
||||
export function timeStamp(time) {
|
||||
const dates = new Date(time)
|
||||
const year = dates.getFullYear()
|
||||
const month = dates.getMonth() + 1
|
||||
const date = dates.getDate()
|
||||
const day = dates.getDay()
|
||||
const hour = dates.getHours()
|
||||
const min = dates.getMinutes()
|
||||
const days = ['日', '一', '二', '三', '四', '五', '六']
|
||||
return {
|
||||
allDate: `${year}/${strFormat(month)}/${strFormat(date)}`,
|
||||
date: `${strFormat(month)}-${strFormat(date)}`, //返回的日期 07-01,${strFormat(year)}-${strFormat(month)}-${strFormat(date)}
|
||||
day: `周${days[day]}`, //返回的礼拜天数 星期一
|
||||
hour: strFormat(hour) + ':' + strFormat(min) // + ':00' //返回的时钟 08:00
|
||||
}
|
||||
}
|
||||
|
||||
//获取最近7天的日期和礼拜天数
|
||||
export function initData(appointedDay = '') {
|
||||
const time = []
|
||||
const date = appointedDay ? new Date(appointedDay) : new Date()
|
||||
|
||||
const now = date.getTime() //获取当前日期的时间戳
|
||||
let timeStr = 3600 * 24 * 1000 //一天的时间戳
|
||||
let obj = {
|
||||
0: "今天",
|
||||
1: "明天",
|
||||
2: "后天"
|
||||
}
|
||||
for (let i = 0; i < 7; i++) {
|
||||
const timeObj = {}
|
||||
timeObj.date = timeStamp(now + timeStr * i).date //保存日期
|
||||
timeObj.timeStamp = now + timeStr * i //保存时间戳
|
||||
timeObj.week = appointedDay == '' ? (obj[i] ?? timeStamp(now + timeStr * i).day) : timeStamp(now + timeStr * i)
|
||||
.day
|
||||
time.push(timeObj)
|
||||
}
|
||||
return time
|
||||
}
|
||||
|
||||
//时间数组
|
||||
export function initTime(startTime = '09:00', endTime = '18:30', timeInterval = 1) {
|
||||
const time = []
|
||||
const date = timeStamp(Date.now()).allDate
|
||||
const startDate = `${date} ${startTime}`
|
||||
const endDate = `${date} ${endTime}`
|
||||
const startTimeStamp = new Date(startDate).getTime()
|
||||
const endTimeStamp = new Date(endDate).getTime()
|
||||
const timeStr = 3600 * 1000 * timeInterval
|
||||
for (let i = startTimeStamp; i <= endTimeStamp; i = i + timeStr) {
|
||||
const timeObj = {}
|
||||
timeObj.time = timeStamp(i).hour
|
||||
timeObj.disable = false
|
||||
time.push(timeObj)
|
||||
}
|
||||
return time
|
||||
}
|
||||
|
||||
export function weekDate(){
|
||||
var now = new Date(); //当前日期
|
||||
var nowDayOfWeek = now.getDay(); //今天本周的第几天
|
||||
var nowDay = now.getDate(); //当前日
|
||||
var nowMonth = now.getMonth(); //当前月
|
||||
var nowYear = now.getYear(); //当前年
|
||||
|
||||
var weekStartDate = new Date(nowYear, nowMonth, nowDay - nowDayOfWeek + 1);
|
||||
var weekEndDate = new Date(nowYear, nowMonth, nowDay + (7 - nowDayOfWeek));
|
||||
|
||||
var arr = [];
|
||||
arr[0] = strFormat(weekStartDate.getMonth()+1) + '-' + strFormat(weekStartDate.getDate());
|
||||
arr[1] = strFormat(weekEndDate.getMonth()+1) + '-' + strFormat(weekEndDate.getDate());
|
||||
return arr;
|
||||
}
|
||||
158
components/yuyue-date/yuyue-date.scss
Normal file
158
components/yuyue-date/yuyue-date.scss
Normal file
@@ -0,0 +1,158 @@
|
||||
.content {
|
||||
text-align: center;
|
||||
height: 100%;
|
||||
.head {
|
||||
position: relative;
|
||||
font-weight: bold;
|
||||
padding: 32rpx 0 24rpx;
|
||||
font-size: $font-size-toolbar;
|
||||
.iconfont {
|
||||
position: absolute;
|
||||
right: 20rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
view,
|
||||
text,
|
||||
image {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.date-list-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: 2rpx solid #e6e6e6;
|
||||
scroll-view {
|
||||
width: 80%;
|
||||
white-space: nowrap;
|
||||
height: 100rpx;
|
||||
line-height: 100rpx;
|
||||
background-color: #fff;
|
||||
position: relative;
|
||||
.flex-box {
|
||||
display: inline-block;
|
||||
width: 25%;
|
||||
|
||||
&.active {
|
||||
.date-box {
|
||||
border: none;
|
||||
.days {
|
||||
font-weight: bold;
|
||||
color: #818181;
|
||||
}
|
||||
.date {
|
||||
font-weight: bold;
|
||||
color: #818181;
|
||||
}
|
||||
}
|
||||
}
|
||||
.date-box {
|
||||
color: #909399;
|
||||
text {
|
||||
font-size: $font-size-tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.appointed-day {
|
||||
flex: 1;
|
||||
border-left: 2rpx solid #e6e6e6;
|
||||
.day-box,
|
||||
.iconfont {
|
||||
font-size: $font-size-tag;
|
||||
color: #909399;
|
||||
}
|
||||
.iconfont {
|
||||
margin-left: 4rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
.time-box {
|
||||
padding: 0 12rpx;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
overflow: scroll;
|
||||
background-color: #fff;
|
||||
height: auto;
|
||||
.item {
|
||||
width: 25%;
|
||||
padding: 0 8rpx;
|
||||
margin-top: 30rpx;
|
||||
&-box {
|
||||
width: 100%;
|
||||
height: 140rpx;
|
||||
padding: 0 40rpx;
|
||||
background: #fff;
|
||||
color: #333;
|
||||
border: 2rpx solid #eeeeee;
|
||||
font-size: $font-size-base;
|
||||
border-radius: 10rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
&.disable {
|
||||
background: #f1f3f6 !important;
|
||||
color: #999 !important;
|
||||
}
|
||||
&.active {
|
||||
background: $base-color;
|
||||
color:#fff;
|
||||
// background: #0094D7;
|
||||
border: 2rpx solid $base-color;
|
||||
font-weight: bold;
|
||||
}
|
||||
.all {
|
||||
font-size: $font-size-tag;
|
||||
padding-top: 10rpx;
|
||||
}
|
||||
// 自定义样式
|
||||
&.diy{
|
||||
height: 60rpx;
|
||||
border-radius: 40rpx;
|
||||
.all{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bottom {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
position: fixed;
|
||||
align-items: center;
|
||||
bottom: 0;
|
||||
top: auto;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 -2rpx 20rpx #bcbcbc;
|
||||
|
||||
.show-time {
|
||||
width: 66%;
|
||||
height: 100rpx;
|
||||
line-height: 100rpx;
|
||||
font-size: $font-size-base;
|
||||
text-align: left;
|
||||
margin-left: 40rpx;
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
width: 25%;
|
||||
height: 70rpx;
|
||||
line-height: 70rpx;
|
||||
font-size: $font-size-base;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.yuyue-date-desc{
|
||||
padding-top: 2rpx;
|
||||
padding-bottom: 4rpx;
|
||||
font-size: $font-size-tag;
|
||||
color: $color-sub;
|
||||
text-align: center;
|
||||
}
|
||||
414
components/yuyue-date/yuyue-date.vue
Normal file
414
components/yuyue-date/yuyue-date.vue
Normal file
@@ -0,0 +1,414 @@
|
||||
<template>
|
||||
<view>
|
||||
<!-- <uni-popup ref="timePopup" type="bottom"> -->
|
||||
<view class="content">
|
||||
<!-- <view class="head">
|
||||
<text class="title">选择时间</text>
|
||||
<text class="iconfont iconclose" @click="close()"></text>
|
||||
</view> -->
|
||||
<view class="container">
|
||||
<view class="date-list-wrap">
|
||||
<!-- 日期列表 -->
|
||||
<scroll-view scroll-x>
|
||||
<block v-for="(item, index) in dateArr" :key="index">
|
||||
<div class="flex-box" @click="selectDateEvent(index, item)">
|
||||
<view class="date-box" :style="{ color: index == dateActive ? selectedTabColor : '#909399' }">
|
||||
<text>{{ item.week }} {{ item.date }}</text>
|
||||
</view>
|
||||
</div>
|
||||
</block>
|
||||
</scroll-view>
|
||||
<div class="appointed-day">
|
||||
<uni-datetime-picker type="date" :start="pickerStartDay" :end="pickerEndDay" @change="change">
|
||||
<text class="day-box">指定日期</text>
|
||||
<text class="iconfont iconyoujiantou"></text>
|
||||
</uni-datetime-picker>
|
||||
</div>
|
||||
</view>
|
||||
|
||||
<!-- 时间选项 -->
|
||||
<view class="time-box" v-if="!isSection">
|
||||
<block v-for="(item, _index) in timeArr" :key="_index">
|
||||
<view class="item">
|
||||
<view class="item-box diy" :class="{ disable: item.disable, active: isMultiple ? item.isActive : _index == timeActive }" @click="selectTimeEvent(_index, item)">
|
||||
<!-- :style="{ color: isMultiple ? (item.isActive ? selectedItemColor : '#333') : _index == timeActive ? selectedItemColor : '#333' }" -->
|
||||
<text>{{ item.time }}</text>
|
||||
<!-- <text class="all">{{ item.disable ? disableText : undisableText }}</text> -->
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
|
||||
<!-- 预约时间段 -->
|
||||
<view class="time-box" v-else>
|
||||
<block v-for="(item, _index) in timeArr" :key="_index">
|
||||
<view class="item">
|
||||
<view class="item-box" :class="{ disable: item.disable || item.isInclude, active: item.time == timeQuanBegin || item.time == timeQuanEnd }" @click="handleSelectQuantum(_index, item)">
|
||||
<!-- :style="{ color: item.time == timeQuanBegin || item.time == timeQuanEnd ? selectedItemColor : '#333' }" -->
|
||||
<text>{{ item.time }}</text>
|
||||
<text class="all">{{ item.disable ? disableText : undisableText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
<!-- <view class="bottom">
|
||||
<view class="show-time" v-if="!isMultiple && !isSection">
|
||||
<text>预约时间:</text>
|
||||
<text class="color-base-text">{{ orderDateTime }}</text>
|
||||
</view>
|
||||
<button form-type="submit" type="primary" size="mini" class="submit-btn" @click="handleSubmit">确认预约</button>
|
||||
</view> -->
|
||||
</view>
|
||||
<!-- <view class="yuyue-date-desc">如不想线上预约,可致电商家电话预约</view> -->
|
||||
<!-- </uni-popup> -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 插件地址:https://ext.dcloud.net.cn/plugin?id=3593
|
||||
import {
|
||||
initData,
|
||||
initTime,
|
||||
timeStamp,
|
||||
currentTime,
|
||||
strFormat,
|
||||
weekDate
|
||||
} from './yuyue-date.js';
|
||||
export default {
|
||||
name: 'times',
|
||||
model: {
|
||||
prop: 'showPop',
|
||||
event: 'change'
|
||||
},
|
||||
props: {
|
||||
isMultiple: {
|
||||
//是否多选
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isSection: {
|
||||
//预约时间段
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
advanceTime: {
|
||||
//提前预约时间
|
||||
type: [String, Number],
|
||||
default: "0"
|
||||
},
|
||||
disableText: {
|
||||
//禁用显示的文本
|
||||
type: String,
|
||||
default: '已约满'
|
||||
},
|
||||
undisableText: {
|
||||
//未禁用显示的文本
|
||||
type: String,
|
||||
default: '可预约'
|
||||
},
|
||||
timeInterval: {
|
||||
// 时间间隔,小时为单位
|
||||
type: String,
|
||||
default: "1"
|
||||
},
|
||||
selectedTabColor: {
|
||||
// 日期栏选中的颜色
|
||||
type: String,
|
||||
default: '#303133'
|
||||
},
|
||||
selectedItemColor: {
|
||||
// 时间选中的颜色
|
||||
type: String,
|
||||
default: '#D50AEF'
|
||||
},
|
||||
beginTime: {
|
||||
type: String,
|
||||
default: '09:00'
|
||||
},
|
||||
endTime: {
|
||||
type: String,
|
||||
default: '19:00'
|
||||
},
|
||||
appointTime: {
|
||||
// 预约的时间
|
||||
type: Array,
|
||||
default () {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
disableTimeSlot: {
|
||||
// 预约开始和结束时间,来禁用时间段
|
||||
type: Object,
|
||||
default () {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
disableWeek: {
|
||||
// 限制周几不可以预约
|
||||
type: Array,
|
||||
default () {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
appointTime: {
|
||||
handler(val) {
|
||||
if (val && val.length) {
|
||||
this.initOnload();
|
||||
}
|
||||
}
|
||||
},
|
||||
beginTime: function(nVal, oVal) {
|
||||
this.initOnload();
|
||||
this.handleSubmit();
|
||||
},
|
||||
endTime: function(nVal, oVal) {
|
||||
this.initOnload();
|
||||
this.handleSubmit();
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pickerStartDay: '', // 指定开始日期
|
||||
pickerEndDay: '', // 指定结束日期
|
||||
orderDateTime: '暂无选择', // 选中时间
|
||||
orderTimeArr: {}, //多选的时间
|
||||
dateArr: [], //日期数据
|
||||
timeArr: [], //时间数据
|
||||
nowDate: '', // 当前日期
|
||||
dateActive: 0, //选中的日期索引
|
||||
timeActive: 0, //选中的时间索引
|
||||
timeQuanBeginIndex: 0, //时间段开始的下标
|
||||
selectDate: '', //选择的日期
|
||||
selectTime: '', //选择的时间
|
||||
timeQuanBegin: '', //时间段开始时间
|
||||
timeQuanEnd: '' //时间段结束时间
|
||||
};
|
||||
},
|
||||
created(props) {
|
||||
this.selectDate = this.nowDate = currentTime().date;
|
||||
this.pickerStartDay = currentTime().year + '-' + currentTime().date;
|
||||
const now = new Date(this.pickerStartDay).getTime(); //获取当前日期的时间戳
|
||||
let timeStr = 3600 * 24 * 1000; //一天的时间戳
|
||||
let day = 90; // 未来3个月
|
||||
this.pickerEndDay = timeStamp(now + timeStr * day).allDate;
|
||||
this.initOnload();
|
||||
this.dateArr = initData(); // 日期栏初始化
|
||||
},
|
||||
methods: {
|
||||
open() {
|
||||
this.$refs.timePopup.open();
|
||||
},
|
||||
close() {
|
||||
this.$refs.timePopup.close();
|
||||
},
|
||||
// 指定时间
|
||||
change(e) {
|
||||
let date = e.split("-");
|
||||
date = date[1] + "-" + date[2];
|
||||
if (this.disableWeek.length && date >= weekDate()[0] && date <= weekDate()[1]) {
|
||||
let weekBox = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
|
||||
let index = new Date(e).getDay();
|
||||
if (this.disableWeek.indexOf(weekBox[index]) != -1) {
|
||||
uni.showToast({
|
||||
title: weekBox[index] + '不可以预约',
|
||||
icon: 'none'
|
||||
})
|
||||
return false;
|
||||
}
|
||||
}
|
||||
this.initOnload(e);
|
||||
this.dateArr = initData(e); // 日期栏初始化
|
||||
this.selectDateEvent(0, this.dateArr[0]);
|
||||
},
|
||||
initOnload(appointedDay) {
|
||||
this.timeArr = initTime(this.beginTime, this.endTime, parseFloat(this.timeInterval)); //时间选项初始化
|
||||
this.timeQuanBegin = this.timeQuanEnd = '';
|
||||
let isFullTime = true;
|
||||
this.timeArr.forEach((item, index) => {
|
||||
// 判断默认是不能选择的周,则都禁止选中
|
||||
if (this.disableWeek.length && this.selectDate >= weekDate()[0] && this.selectDate <=
|
||||
weekDate()[1]) {
|
||||
let weekBox = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
|
||||
let date = currentTime().year + '-' + this.selectDate;
|
||||
let index = new Date(date).getDay();
|
||||
if (this.disableWeek.indexOf(weekBox[index]) != -1) {
|
||||
item.disable = true;
|
||||
}
|
||||
}
|
||||
|
||||
//判断是当前这一天,选中时间小于当前时间则禁用
|
||||
if (this.selectDate == this.nowDate && currentTime().time > item.time) {
|
||||
item.disable = true;
|
||||
}
|
||||
|
||||
// 将提前预约的时间禁用 advanceTime
|
||||
var advTime = new Date(new Date().setMinutes(new Date().getMinutes() + parseInt(this.advanceTime) * 60));
|
||||
var advTimeStr = strFormat(advTime.getHours()) + ":" + strFormat(advTime.getMinutes()) + ":" + strFormat(advTime.getSeconds());
|
||||
var advTimeStr1 = strFormat(advTime.getMonth() + 1) + "-" + strFormat(advTime.getDate());
|
||||
if (this.selectDate == advTimeStr1 && advTimeStr > item.time || advTimeStr1 > this.selectDate) {
|
||||
item.disable = true;
|
||||
}
|
||||
|
||||
// 将预约的时间禁用
|
||||
this.appointTime.forEach(t => {
|
||||
let [date, time] = t.split(' ');
|
||||
time = time.slice(0, -3);
|
||||
|
||||
if (date == currentTime().year + '-' + this.selectDate && item.time == time ||
|
||||
date == currentTime().year + '-' + advTimeStr1 && item.time == time) {
|
||||
item.disable = true;
|
||||
}
|
||||
});
|
||||
|
||||
// 禁用时间段
|
||||
const cur_time = `${this.selectDate} ${item.time}`;
|
||||
const {
|
||||
begin_time,
|
||||
end_time
|
||||
} = this.disableTimeSlot;
|
||||
if (begin_time && end_time && (begin_time <= cur_time && cur_time <= end_time)) {
|
||||
item.disable = true;
|
||||
}
|
||||
|
||||
// 判断是否当前日期时间都被预约
|
||||
if (!item.disable) {
|
||||
isFullTime = false;
|
||||
}
|
||||
this.isSection && (item.isInclude = false);
|
||||
});
|
||||
|
||||
this.orderDateTime = isFullTime ? '暂无选择' : this.selectDate;
|
||||
this.timeActive = -1;
|
||||
for (let i = 0, len = this.timeArr.length; i < len; i++) {
|
||||
if (!this.timeArr[i].disable) {
|
||||
this.orderDateTime = {
|
||||
data: `${this.selectDate}`,
|
||||
time: `${this.timeArr[i].time}`
|
||||
};
|
||||
this.timeActive = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 日期选择事件
|
||||
selectDateEvent(index, item) {
|
||||
if (this.disableWeek.length && item.date >= weekDate()[0] && item.date <= weekDate()[1]) {
|
||||
let weekBox = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
|
||||
let index = new Date(item.timeStamp).getDay();
|
||||
if (this.disableWeek.indexOf(weekBox[index]) != -1) {
|
||||
uni.showToast({
|
||||
title: weekBox[index] + '不可以预约',
|
||||
icon: 'none'
|
||||
})
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
this.dateActive = index;
|
||||
this.selectDate = item.date;
|
||||
this.initOnload();
|
||||
this.handleSubmit();
|
||||
},
|
||||
|
||||
// 时间选择事件
|
||||
selectTimeEvent(index, item) {
|
||||
if (item.disable) return;
|
||||
if (this.isMultiple) {
|
||||
item.isActive = !item.isActive;
|
||||
this.timeArr = this.timeArr.slice();
|
||||
this.orderTimeArr[this.selectDate] = this.timeArr.reduce((prev, cur) => {
|
||||
cur.isActive && prev.push(cur.time);
|
||||
return prev;
|
||||
}, []);
|
||||
} else {
|
||||
this.timeActive = index;
|
||||
this.selectTime = item.time;
|
||||
this.orderDateTime = {
|
||||
data: `${this.selectDate}`,
|
||||
time: `${item.time}`
|
||||
};
|
||||
}
|
||||
this.handleSubmit();
|
||||
},
|
||||
|
||||
// 选择时间段
|
||||
handleSelectQuantum(index, item) {
|
||||
if (item.disable) return;
|
||||
|
||||
function clearTime() {
|
||||
this.timeQuanBeginIndex = index;
|
||||
this.timeQuanBegin = item.time;
|
||||
this.timeQuanEnd = '';
|
||||
}
|
||||
|
||||
if (!this.timeQuanBegin) {
|
||||
clearTime.call(this);
|
||||
return;
|
||||
}
|
||||
if (!this.timeQuanEnd && this.timeQuanBegin) {
|
||||
let isDisble = false;
|
||||
let start = this.timeQuanBeginIndex;
|
||||
let end = index;
|
||||
start > end && ([start, end] = [end, start]);
|
||||
for (let i = start + 1; i < end; i++) {
|
||||
if (this.timeArr[i].disable) {
|
||||
isDisble = true;
|
||||
clearTime.call(this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!isDisble) {
|
||||
for (let i = start + 1; i < end; i++) {
|
||||
this.timeArr[i].isInclude = true;
|
||||
}
|
||||
}
|
||||
this.timeQuanEnd = item.time;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.timeQuanBegin && this.timeQuanEnd) {
|
||||
this.timeArr.forEach(t => {
|
||||
t.isInclude = false;
|
||||
});
|
||||
clearTime.call(this);
|
||||
}
|
||||
},
|
||||
handleChange() {
|
||||
this.timeQuanBegin > this.timeQuanEnd && ([this.timeQuanBegin, this.timeQuanEnd] = [this.timeQuanEnd, this.timeQuanBegin]);
|
||||
},
|
||||
handleSubmit() {
|
||||
if (this.isSection) {
|
||||
this.handleChange();
|
||||
this.$emit('change', {
|
||||
beginTime: `${this.selectDate} ${this.timeQuanBegin}`,
|
||||
endTime: `${this.selectDate} ${this.timeQuanEnd}`
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isMultiple) {
|
||||
let time = [];
|
||||
for (let date in this.orderTimeArr) {
|
||||
this.orderTimeArr[date].forEach(item => {
|
||||
time.push(`${date} ${item}`);
|
||||
});
|
||||
}
|
||||
this.$emit('change', time);
|
||||
} else {
|
||||
// this.$emit('change', currentTime().year + '-' + this.orderDateTime);
|
||||
this.$emit('change', {
|
||||
date: currentTime().year + '-' + this.orderDateTime.data,
|
||||
time: this.orderDateTime.time
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import './yuyue-date.scss';
|
||||
</style>
|
||||
Reference in New Issue
Block a user