Initial commit: 积分兑换电商平台多商户版 MER-2.2

Made-with: Cursor
This commit is contained in:
apple
2026-03-08 20:07:52 +08:00
commit de02c8a3e1
4954 changed files with 703009 additions and 0 deletions

View File

@@ -0,0 +1,358 @@
<template>
<view v-if="formsValue && formValue.length>0">
<view v-for="(list,idx) in formValue" :key="idx" class="wrapper virtual_form bg-f boder-24">
<!-- <view class="title">{{formsValue.name}}</view> -->
<block v-for="(item,index) in list" :key="index">
<view class='item acea-row row-between-wrapper'>
<view class="name">
<text class="item-require" v-if="item.titleShow.val">*</text>
{{ item.titleConfig.value }}
</view>
<!-- radio -->
<view v-if="item.name=='radios'" class="discount">
<radio-group @change="radioChange($event, idx, index, item)" class="acea-row row-middle row-right">
<label class="radio" v-for="(j,jindex) in item.wordsConfig.list" :key="jindex">
<view class="acea-row row-middle">
<!-- #ifndef MP -->
<radio :value="jindex.toString()" :checked='j.show'/>
<!-- #endif -->
<!-- #ifdef MP -->
<radio :value="jindex" :checked='j.show'/>
<!-- #endif -->
<view>{{j.val}}</view>
</view>
</label>
</radio-group>
</view>
<!-- checkbox -->
<view v-if="item.name=='checkboxs'" class="discount acea-row">
<checkbox-group @change="checkboxChange($event, idx, index, item)" class="acea-row row-middle row-right">
<label class="radio" v-for="(j,jindex) in item.wordsConfig.list" :key="jindex">
<view class="acea-row row-middle">
<!-- #ifndef MP -->
<checkbox :value="jindex.toString()" :checked="j.show" style="transform:scale(0.9)" />
<!-- #endif -->
<!-- #ifdef MP -->
<checkbox :value="jindex" :checked="j.show" style="transform:scale(0.9)" />
<!-- #endif -->
<view>{{j.val}}</view>
</view>
</label>
</checkbox-group>
</view>
<!-- text -->
<view v-if="item.name=='texts' && item.valConfig.tabVal == 0" class="discount">
<input type="text" :placeholder="item.tipConfig.value" placeholder-class="placeholderc" v-model="item.value" />
</view>
<!-- number -->
<view v-if="item.name=='texts' && item.valConfig.tabVal == 4" class="discount">
<input type="number" :placeholder="item.tipConfig.value" placeholder-class="placeholderc" v-model="item.value" />
</view>
<!-- email -->
<view v-if="item.name=='texts' && item.valConfig.tabVal == 3" class="discount">
<input type="text" :placeholder="item.tipConfig.value" placeholder-class="placeholderc" v-model="item.value" />
</view>
<!-- data -->
<view v-if="item.name=='dates'" class="discount">
<picker mode="date" :value="item.value" @change="bindDateChange($event,idx,index)">
<view class="acea-row row-between-wrapper">
<view v-if="item.value == ''">{{item.tipConfig.value}}</view>
<view v-else>{{item.value}}</view>
<text class='iconfont icon-ic_rightarrow'></text>
</view>
</picker>
</view>
<!-- dateranges -->
<view v-if="item.name=='dateranges'" class="discount">
<uni-datetime-picker v-model="item.value" type="daterange" @maskClick="maskClick">
{{item.value.length?item.value[0]+' - '+item.value[1]:item.tipConfig.value}}
<text class='iconfont icon-ic_rightarrow'></text>
</uni-datetime-picker>
</view>
<!-- time -->
<view v-if="item.name=='times'" class="discount">
<picker mode="time" :value="item.value" @change="bindTimeChange($event, idx, index)"
:placeholder="item.tipConfig.value">
<view class="acea-row row-between-wrapper">
<view v-if="item.value == ''">{{item.tipConfig.value}}</view>
<view v-else>{{item.value}}</view>
<text class='iconfont icon-ic_rightarrow'></text>
</view>
</picker>
</view>
<!-- timeranges -->
<view v-if="item.name=='timeranges'" class="discount acea-row row-between-wrapper" @click="getTimeranges(idx,index)">
<view v-if="item.value">{{item.value}}</view>
<view v-else>{{item.tipConfig.value}}</view>
<text class='iconfont icon-ic_rightarrow'></text>
</view>
<!-- select -->
<view v-if="item.name=='selects'" class="discount">
<picker :value="item.value" :range="item.wordsConfig.list" @change="bindSelectChange($event,idx,index,item)" range-key="val">
<view class="acea-row row-between-wrapper">
<view v-if="item.value">{{item.value}}</view>
<view v-else>请选择</view>
<text class='iconfont icon-ic_rightarrow'></text>
</view>
</picker>
</view>
<!-- city -->
<view v-if="item.name=='citys'" class="discount" @click="changeRegion(idx,index)">
<view class="acea-row row-middle row-right">
<view class="city" v-if="item.value == ''">{{item.tipConfig.value}}</view>
<view class="city" v-else>{{item.value}}</view>
<text class='iconfont icon-ic_rightarrow'></text>
</view>
</view>
<!-- id -->
<view v-if="item.name=='texts' && item.valConfig.tabVal == 2" class="discount">
<input type="idcard" :placeholder="item.tipConfig.value" placeholder-class="placeholderc" v-model="item.value" />
</view>
<!-- phone -->
<view v-if="item.name=='texts' && item.valConfig.tabVal == 1" class="discount">
<input type="number" :placeholder="item.tipConfig.value" placeholder-class="placeholderc" v-model="item.value" />
</view>
<!-- img -->
<scroll-view scroll-x="true" show-scrollbar="false" class="item-scroll" :style="'width:'+item.scrollWidth" v-if="item.name=='uploadPicture'">
<view class='upload' :style="'width:'+item.scrollWidth">
<view class='pictrue acea-row row-center-wrapper row-column' @tap='uploadpic(idx,index)'
v-if="item.value.length < item.numConfig.val">
<image class="camera-icon" :src="`${domain}/static/images/ic_camera.png`"></image>
<view>上传图片</view>
</view>
<view class='pictrue' v-for="(items,indexs) in item.value" :key="indexs">
<image :src='items' mode="aspectFill"></image>
<view class="close acea-row row-center-wrapper" @tap='DelPic(idx,index,indexs)'>
<view class="iconfont icon-ic_close"></view>
</view>
</view>
</view>
</scroll-view>
</view>
</block>
<timeranges :isShow='isShow' :time='timeranges' @confrim="confrim" @cancel="cancels"></timeranges>
<areaWindow ref="areaWindow" :display="display" :address='addressInfoArea' :cityShow='cityShow' @submit="OnAreaAddress" @changeClose="changeAddressClose"></areaWindow>
</view>
</view>
</template>
<script>
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
const CACHE_CITY = {};
import areaWindow from '@/components/areaWindow';
import timeranges from '@/components/timeranges';
import dayjs from "@/plugin/dayjs/dayjs.min.js";
import { HTTP_REQUEST_URL } from '@/config/app';
export default {
components: {
areaWindow,
timeranges
},
props: {
formsValue: {
type: Object,
default: function() {
return {};
}
},
},
data() {
return {
formValue: [],
isShow: false,
display: false,
cityShow: 2,
addressInfoArea: [],
timeranges: [],
timerangesIndex: 0,
formIndex: 0,
newImg: [],
domain: HTTP_REQUEST_URL,
};
},
mounted(){
},
methods: {
getFormList(form,count) {
let arr = []
let data = this.getFormData(form)
for(var i=0; i<count; i++) {
arr.push(JSON.parse(JSON.stringify(data)))
}
this.formValue = arr
},
getFormData(form) {
let that = this;
let formData = that.objToArr(form.value)
formData.forEach((item, index, arr)=>{
that.$set(item, 'value', "");
CACHE_CITY[index] = ''; //清空省市区
if(item.name == 'texts'){
if(item.defaultValConfig.value){
item.value = item.defaultValConfig.value
}else{
item.value = ''
}
}else if(item.name == 'radios'){
item.value = item.wordsConfig.list[0].val
}else if(item.name == 'uploadPicture'){
item.value = [];
item.scrollWidth = '106rpx'
}else if(item.name == 'dateranges'){
if(item.valConfig.tabVal==0){
if(item.valConfig.tabData==0){
let obj = dayjs(new Date(Number(new Date().getTime()))).format('YYYY-MM-DD');
item.value = [obj,obj]
}else{
let data1 = dayjs(new Date(Number(new Date(item.valConfig.specifyDate[0]).getTime()))).format('YYYY-MM-DD');
let data2 = dayjs(new Date(Number(new Date(item.valConfig.specifyDate[1]).getTime()))).format('YYYY-MM-DD');
item.value = [data1,data2];
}
}else{
item.value = [];
}
}else{
if(['times','dates','timeranges'].indexOf(item.name) != -1){
if(item.valConfig.tabVal==0){ //显示默认值
if(item.valConfig.tabData==0){
if(item.name == 'times'){
item.value = dayjs(new Date(Number(new Date().getTime()))).format('HH:mm');
}else if(item.name == 'dates'){
item.value = dayjs(new Date(Number(new Date().getTime()))).format('YYYY-MM-DD');
}else{
let current = dayjs(new Date(Number(new Date().getTime()))).format('HH:mm');
item.value = current+' - '+current;
}
}else{
if(item.name == 'times' || item.name == 'dates'){
item.value = item.valConfig.specifyDate;
}else{
item.value = item.valConfig.specifyDate[0]+' - '+item.valConfig.specifyDate[1];
}
}
}else{
item.value = '';
}
}else{
item.value = '';
}
}
})
function sortNumber(a, b) {
return a.timestamp - b.timestamp;
}
formData.sort(sortNumber);
// that.$set(that, 'formValue', formData);
return formData
},
// 对象转数组
objToArr(data) {
let obj = Object.keys(data);
let m = obj.map(key => data[key]);
return m;
},
// 单选
radioChange(e, i, index, item){
this.formValue[i][index].value = item.wordsConfig.list[e.detail.value].val
},
// 多选
checkboxChange(e, i, index, item){
let obj = e.detail.value;
let val = '';
item.wordsConfig.list.forEach((j,jindex)=>{
obj.forEach(x=>{
if(jindex == x){
val = val +(val?',':'') + j.val;
}
})
})
this.formValue[i][index].value = val
},
bindDateChange(e, idx, index) {
this.formValue[idx][index].value = e.target.value
this.$forceUpdate()
},
bindTimeChange(e, i, index) {
this.formValue[i][index].value = e.target.value
},
getTimeranges(i,index){
this.isShow = true
this.formIndex = i;
this.timerangesIndex = index
},
bindSelectChange(e, i, index, item) {
this.$set(this.formValue[i][index], 'value', item.wordsConfig.list[e.detail.value].val);
},
changeRegion(i,index){
if(!this.formValue[i][index].value){
this.addressInfoArea = [];
}
this.timerangesIndex = index;
this.cityShow = Number(this.formValue[i][index].valConfig.tabVal) + 1;
this.formIndex = i;
this.display = true;
if(CACHE_CITY[i]){
this.addressInfoArea = CACHE_CITY[i];
}
},
/**上传文件*/
uploadpic: function(idx,index) {
let that = this;
this.$util.uploadImageOne('upload/image', function(res) {
let arr = that.formValue[idx][index]['value'];
arr.push(res.data.path);
that.$set(that.formValue[idx][index], 'value', arr);
that.$set(that.formValue[idx][index], 'scrollWidth', (arr.length+1)*118+'rpx');
});
},
/** 删除图片*/
DelPic: function(idx,index, indexs) {
let that = this,
pic = this.formValue[idx][index].value;
that.formValue[idx][index].value.splice(indexs, 1);
that.$set(that.formValue[idx][index], 'value', that.formValue[index].value);
},
OnAreaAddress(address){
let addr = '';
addr = address.map(v=>v.name).join('/');
this.formValue[this.formIndex][this.timerangesIndex].value = addr;
CACHE_CITY[this.timerangesIndex] = address;
},
// 关闭地址弹窗;
changeAddressClose: function() {
this.display = false;
},
confrim(e){
this.isShow = false;
this.$set(this.formValue[this.formIndex][this.timerangesIndex], 'value', e.time);
let arrayNew = [];
e.val.forEach(item=>{
arrayNew.push(Number(item))
})
this.timeranges = arrayNew;
},
cancels(){
this.isShow = false;
},
getFormValue() {
return this.formValue
}
}
}
</script>
<style scoped lang="scss">
.discount {
text-align: right;
}
</style>

View File

@@ -0,0 +1,130 @@
/*
*此函数的作用是根据传入的一个日期,返回这一周的日期或者这一个月的日期,
* 如果是月的话注意还包含上个月和下个月的日期,月的话总共数据有 6 * 7 = 42个
*
*/
/*
* 时间格式化函数
* 重要提示微信小程序new Date('2020-04-16')在ios中无法获取时间对象
* 解决方式: 建议将时间都格式化成'2020/04/16 00:00:00'的格式
* 函数示例: formatDate(new Date(), 'YYYY/MM/dd hh:mm:ss')
*/
export const formatDate = (date, fmt) => {
if (/(y+)/.test(fmt)) {
fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length))
}
let o = {
'M+': date.getMonth() + 1,
'd+': date.getDate(),
'h+': date.getHours(),
'm+': date.getMinutes(),
's+': date.getSeconds()
}
for (let k in o) {
if (new RegExp(`(${k})`).test(fmt)) {
let str = o[k] + ''
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? str : padLeftZero(str))
}
}
return fmt
}
const padLeftZero = (str) => {
return ('00' + str).substr(str.length)
}
export const judgeType = (s) => {
// 函数返回数据的具体类型
return Object.prototype.toString.call(s).slice(8,-1);
}
export const equalDate = (d1, d2) => {
let result = false;
if (d1.getFullYear() === d2.getFullYear() && d1.getMonth() === d2.getMonth() && d1.getDate() === d2.getDate()) {
result = true;
}
return result;
}
/* 比较时间,时间格式为2020-04-04
*/
export const dateEqual = (before, after) => {
before = new Date(before.replace('-', '/').replace('-', '/'))
after = new Date(after.replace('-', '/').replace('-', '/'))
if (before.getTime() - after.getTime() === 0) {
return true
} else {
return false
}
}
export const gegerateDates = (date = new Date(), type='week') => {
const result = [];
if (judgeType(date) === 'Date') {
// 年,月,日
const y = date.getFullYear();
const m = date.getMonth();
const d = date.getDate();
const days = new Date(y, m+1, 0).getDate();
// 获取日期是星期几
let weekIndex = date.getDay() === 0 ? 7 : date.getDay();
if (type === 'month') {
const dobj = new Date(y,m,1);
weekIndex = dobj.getDay() === 0 ? 7 : dobj.getDay();
}
if (type === 'week') {
for(let i = weekIndex - 1; i >0; i--) {
const dtemp = new Date(y,m,d);
dtemp.setDate(dtemp.getDate() - i);
result.push({
time: dtemp,
show: dtemp.getMonth()+1 == new Date(y,m,d).getMonth() + 1,
fullDate: formatDate(dtemp, 'yyyy-MM-dd'),
isToday: equalDate(new Date(), dtemp)
})
}
for(let i = 0; i <= 7 - weekIndex; i++) {
const dtemp = new Date(y,m,d);
dtemp.setDate(dtemp.getDate() + i);
result.push({
time: dtemp,
show: dtemp.getMonth()+1 == new Date(y,m,d).getMonth() + 1,
fullDate: formatDate(dtemp, 'yyyy-MM-dd'),
isToday: equalDate(new Date(), dtemp)
})
}
} else if (type === 'month') {
// 上个月
for(let i = weekIndex - 1; i > 0; i--) {
const dtemp = new Date(y,m,1);
dtemp.setDate(dtemp.getDate() - i);
result.push({
time: dtemp,
show: false,
fullDate: formatDate(dtemp, 'yyyy-MM-dd'),
isToday: equalDate(new Date(), dtemp)
});
}
// 这个月的日期
for (let i = 0; i < days; i++) {
const dtemp = new Date(y,m,1);
dtemp.setDate(dtemp.getDate() + i);
result.push({
time: dtemp,
show: true,
fullDate: formatDate(dtemp, 'yyyy-MM-dd'),
isToday: equalDate(new Date(), dtemp)
});
}
const len = 42 - result.length;
// 下个月的日期
for (let i = 1; i <= len;i++) {
const dtemp = new Date(y,m+1,0);
dtemp.setDate(dtemp.getDate() + i);
result.push({
time: dtemp,
show: false,
fullDate: formatDate(dtemp, 'yyyy-MM-dd'),
isToday: equalDate(new Date(), dtemp)
})
}
}
}
return result;
}

View File

@@ -0,0 +1,476 @@
<template>
<view class="zzx-calendar">
<view class="calendar-heander acea-row row-center-wrapper">
<view class="title">预约时间</view>
<view class="iconfont icon-ic_left2" :class="ymArr?'':'text-w111-ddd'" @click="daysPre(1)"></view>
<view class="dates">{{timeStr}}</view>
<view class="iconfont icon-ic_right2" @click="daysNext(1)"></view>
<view class="back-today" @click="goback" v-if="showBack">
返回今日
</view>
</view>
<view class="calendar-weeks">
<view class="calendar-week" v-for="(week, index) in weeks" :key="index">
{{week}}
</view>
</view>
<view class="calendar-content">
<view class="calendar-swiper" :style="{
width: '100%',
height: sheight
}" :indicator-dots="false" :autoplay="false" :duration="duration" :current="current" @change="changeSwp"
:circular="true">
<view class="calendar-item" v-for="sitem in swiper" :key="sitem">
<view class="calendar-days">
<template v-if="sitem === current">
<view class="calendar-day" v-for="(item,index) in days" :key="index" :class="{
'day-hidden': !item.show
}" @click="clickItem(item)">
<view class="date" :class="[
dotListData.indexOf(item.fullDate)==-1?'text-w111-ccc':'',
item.isToday ? todayClass : '',
item.fullDate == selectedDate ? checkedClass : ''
]">
<text v-if="item.isToday"></text>
<text v-else>{{item.time.getDate()>9?item.time.getDate():'0'+item.time.getDate()}}</text>
</view>
</view>
</template>
<template v-else>
<template v-if="current - sitem === 1 || current-sitem ===-2">
<view class="calendar-day" v-for="(item,index) in predays" :key="index" :class="{
'day-hidden': !item.show
}">
<view class="date" :class="[
item.isToday ? todayClass : ''
]">
{{item.time.getDate()}}
</view>
</view>
</template>
<template v-else>
<view class="calendar-day" v-for="(item,index) in nextdays" :key="index" :class="{
'day-hidden': !item.show
}">
<view class="date" :class="[
item.isToday ? todayClass : ''
]">
{{item.time.getDate()}}
</view>
</view>
</template>
</template>
</view>
</view>
</view>
<view class="mode-change" @click="changeMode">
<view class="iconfont" :class="weekMode ? 'icon-ic_downarrow' : 'icon-ic_uparrow'">
</view>
</view>
</view>
</view>
</template>
<script>
import {
gegerateDates,
dateEqual,
formatDate
} from './generateDates.js';
export default {
props: {
duration: {
type: Number,
default: 500
},
dotList: {
type: Array, /// 打点日期列表
default () {
return []
}
},
reservationDefaultDate:{
type: String,
default: ''
},
showBack: {
type: Boolean, // 是否返回今日
default: false
},
todayClass: {
type: String, // 今日的自定义样式class
default: 'is-today'
},
checkedClass: {
type: String, // 选中日期的样式class
default: 'is-checked'
},
dotStyle: {
type: Object, // 打点日期的自定义样式
default () {
return {
background: '#c6c6c6'
}
}
},
initDay: {
type: String,
default: ''
}
},
watch: {
dotList: function(newvalue) {
const days = this.days.slice(0);
this.days = days;
},
reservationDefaultDate: function(newvalue){
this.selectedDate = newvalue
}
},
computed: {
ymArr() {
const nowY = new Date().getFullYear()
const nowM = new Date().getMonth() + 1
return nowY<this.currentYear || (nowY==this.currentYear && parseInt(nowM)<parseInt(this.currentMonth));
},
dotListData(){
let data = [];
this.dotList.forEach(item=>{
data.push(item.date)
})
return data
},
sheight() {
// 根据年月判断有多少行
// 判断该月有多少天
let h = '70rpx';
if (!this.weekMode) {
const d = new Date(this.currentYear, this.currentMonth, 0);
const days = d.getDate(); // 判断本月有多少天
let day = new Date(d.setDate(1)).getDay();
if (day === 0) {
day = 7;
}
const pre = 8 - day;
const rows = Math.ceil((days - pre) / 7) + 1;
h = 70 * rows + 'rpx'
}
return h
},
timeStr() {
let str = '';
const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate);
const y = d.getFullYear();
const m = (d.getMonth() + 1) <= 9 ? `0${d.getMonth()+1}` : d.getMonth() + 1;
str = `${y}${m}`;
return str;
},
predays() {
let pres = [];
if (this.weekMode) {
const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate)
d.setDate(d.getDate() - 7);
pres = gegerateDates(d, 'week')
} else {
const d = new Date(this.currentYear, this.currentMonth - 2, 1)
pres = gegerateDates(d, 'month')
}
return pres;
},
nextdays() {
let nexts = [];
if (this.weekMode) {
const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate)
d.setDate(d.getDate() + 7);
nexts = gegerateDates(d, 'week')
} else {
const d = new Date(this.currentYear, this.currentMonth, 1)
nexts = gegerateDates(d, 'month')
}
return nexts;
}
},
data() {
return {
weeks: ['一', '二', '三', '四', '五', '六', '日'],
current: 1,
currentYear: '',
currentMonth: '',
currentDate: '',
days: [],
weekMode: true,
swiper: [1],
selectedDate: this.initDay
};
},
methods: {
changeSwp(e) {
const pre = this.current;
const current = e.target.current;
/* 根据前一个减去目前的值我们可以判断是下一个月/周还是上一个月/周
*current - pre === 1, -2时是下一个月/周
*current -pre === -1, 2时是上一个月或者上一周
*/
this.current = current;
if (current - pre === 1 || current - pre === -2) {
this.daysNext();
} else {
this.daysPre();
}
},
// 初始化日历的方法
initDate(cur) {
let date = ''
if (cur) {
date = new Date(cur)
} else {
date = new Date()
}
this.currentDate = date.getDate() // 今日日期 几号
this.currentYear = date.getFullYear() // 当前年份
this.currentMonth = date.getMonth() + 1 // 当前月份
this.currentWeek = date.getDay() === 0 ? 7 : date.getDay() // 1...6,0 // 星期几
const nowY = new Date().getFullYear() // 当前年份
const nowM = new Date().getMonth() + 1
const nowD = new Date().getDate() // 今日日期 几号
const nowW = new Date().getDay();
this.days = [];
let days = [];
if (this.weekMode) {
days = gegerateDates(date, 'week');
} else {
days = gegerateDates(date, 'month');
}
this.days = days;
// 派发事件,时间发生改变
let obj = {
start: '',
end: ''
};
if (this.weekMode) {
obj.start = this.days[0].time;
obj.end = this.days[6].time
} else {
const start = new Date(this.currentYear, this.currentMonth - 1, 1);
const end = new Date(this.currentYear, this.currentMonth, 0);
obj.start = start;
obj.end = end;
}
this.$emit('days-change', obj)
},
// 上一个
daysPre(num) {
if(!this.ymArr) return
if (this.weekMode && !num) {
const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate);
d.setDate(d.getDate() - 7);
this.initDate(d);
} else {
const d = new Date(this.currentYear, this.currentMonth - 2, 1);
this.initDate(d);
}
this.$emit('dateChange', this.currentYear + '-' + (this.currentMonth<10?'0'+this.currentMonth:this.currentMonth)); //传给调用模板页面去拿新数据
},
// 下一个
daysNext(num) {
if (this.weekMode && !num) {
const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate);
d.setDate(d.getDate() + 7);
this.initDate(d);
} else {
const d = new Date(this.currentYear, this.currentMonth, 1);
this.initDate(d);
}
this.$emit('dateChange', this.currentYear + '-' + (this.currentMonth<10?'0'+this.currentMonth:this.currentMonth)); //传给调用模板页面去拿新数据
},
changeMode() {
const premode = this.weekMode;
let isweek = false;
if (premode) {
isweek = !!this.days.find(item => item.fullDate === this.selectedDate)
}
this.weekMode = !this.weekMode;
let d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate)
const sel = new Date(this.selectedDate.replace('-', '/').replace('-', '/'));
const isMonth = sel.getFullYear() === this.currentYear && (sel.getMonth() + 1) === this.currentMonth;
if ((this.selectedDate && isMonth) || isweek) {
d = new Date(this.selectedDate.replace('-', '/').replace('-', '/'))
}
this.initDate(d)
},
// 点击日期
clickItem(e) {
if(this.dotListData.indexOf(e.fullDate)==-1 || e.fullDate == this.selectedDate) return
this.selectedDate = e.fullDate;
this.$emit('dayChange', e.fullDate);
},
goback() {
const d = new Date();
this.initDate(d);
}
},
created() {
this.initDate();
},
mounted() {}
}
</script>
<style lang="scss" scoped>
.text-w111-ccc{
color: #ccc !important;
}
.text-w111-ddd {
color: #ddd;
}
.zzx-calendar {
width: 710rpx;
height: auto;
background-color: #ffffff;
margin: 20rpx auto 0 auto;
border-radius: 16rpx;
padding-top: 20rpx;
.calendar-heander {
text-align: center;
height: 60rpx;
line-height: 60rpx;
position: relative;
font-size: 30rpx;
.iconfont{
width: 52rpx;
height: 52rpx;
text-align: center;
line-height: 52rpx;
font-size: 24rpx;
}
.dates {
font-size: 28rpx;
font-family: PingFang SC, PingFang SC;
font-weight: 500;
color: #333;
}
.title{
position: absolute;
left: 0;
font-size: 28rpx;
color: #333;
padding-left: 24rpx;
}
.back-today {
position: absolute;
right: 0;
width: 100rpx;
height: 30rpx;
line-height: 30rpx;
font-size: 20rpx;
top: 15rpx;
border-radius: 15rpx 0 0 15rpx;
color: #ffffff;
background-color: #FF6633;
}
}
.calendar-weeks {
width: 100%;
display: flex;
flex-flow: row nowrap;
height: 60rpx;
line-height: 60rpx;
justify-content: center;
align-items: center;
font-size: 30rpx;
margin: 26rpx 0 14rpx 0;
.calendar-week {
width: calc(100% / 7);
height: 100%;
text-align: center;
font-size: 28rpx;
}
}
swiper {
width: 100%;
height: 60rpx;
}
.calendar-content {
min-height: 60rpx;
}
.calendar-swiper {
min-height: 70rpx;
transition: height ease-out 0.3s;
}
.calendar-item {
margin: 0;
padding: 0;
height: 100%;
}
.calendar-days {
display: flex;
flex-flow: row wrap;
width: 100%;
height: 100%;
overflow: hidden;
font-size: 28rpx;
.calendar-day {
width: calc(100% / 7);
height: 70rpx;
text-align: center;
display: flex;
flex-flow: column nowrap;
justify-content: flex-start;
align-items: center;
}
}
.day-hidden {
visibility: hidden;
}
.mode-change {
display: flex;
justify-content: center;
margin-top: 10rpx;
.iconfont{
width: 80rpx;
height: 60rpx;
line-height: 32rpx;
text-align: center;
}
.mode-arrow-top {
width: 0;
height: 0;
border-left: 12rpx solid transparent;
border-right: 12rpx solid transparent;
border-bottom: 10rpx solid #FF6633;
}
.mode-arrow-bottom {
width: 0;
height: 0;
border-left: 12rpx solid transparent;
border-right: 12rpx solid transparent;
border-top: 10rpx solid #FF6633;
}
}
.is-today {
background: #ffffff;
border-radius: 50%;
// color: var(--view-theme);
}
.is-checked {
@include main_color(theme);
@include coupons_light_color(theme);
font-weight: 500;
}
.date {
width: 50rpx;
height: 50rpx;
line-height: 50rpx;
margin: 0 auto;
border-radius: 50rpx;
font-size: 28rpx;
}
.dot-show {
margin-top: 4rpx;
width: 10rpx;
height: 10rpx;
background: #c6c6c6;
border-radius: 10rpx;
}
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,428 @@
<template>
<view class="reservation" :style="viewColor">
<!-- 自定义顶部背景颜色 -->
<view class="top">
<!-- #ifdef MP || APP-PLUS -->
<view class="sys-head fixed">
<view class="sys-bar" :style="{height:sysHeight}"></view>
<!-- #ifdef MP -->
<view class="sys-title">
<view class='iconfont icon-ic_leftarrow' :style="{lineHeight:sysHeight}" @tap='goBack'></view>
预约信息
</view>
<!-- #endif -->
<view class="bg"></view>
</view>
<!-- #endif -->
</view>
<view class="header" :style="{marginTop:marTop}"></view>
<view class="pad20 reservation-main">
<view>
<view class="store-info bg-f boder-24" v-for="(item,index) in cartInfo" :key="index">
<view class="store-title acea-row row-middle"@click="goStore(item.mer_id)">
<text class="iconfont icon-ic_mall"></text>
<view class="txt font-500">{{item.mer_name}}</view>
<text class="iconfont icon-ic_rightarrow"></text>
</view>
<view class="product-item" v-for="(itm,idx) in item.list" :key="idx">
<view class="img-box">
<image :src="(itm.productAttr && itm.productAttr.image) || itm.product.image"></image>
</view>
<view class="content">
<view class="name line1">{{itm.product.store_name}}</view>
<view v-if="itm.productAttr.sku" class="label" style="width: 70%;">{{itm.productAttr.sku}}</view>
<view class="acea-row row-middle">
<view class="price acea-row row-bottom">
<priceFormat :price="itm.productAttr.price" weight intSize="28" floatSize="20" labelSize="20"></priceFormat>
<view v-if="itm.productAttr.show_svip_price" class="acea-row row-middle vip-price">
<text class="vip-money regular">¥{{itm.productAttr.product.svip_price}}</text>
<image class="vip-image" :src="`${domain}/static/images/svip.png`"></image>
</view>
</view>
</view>
</view>
<view class="item-count">x{{itm.cart_num}}</view>
</view>
</view>
<systemFrom v-model="orderInfoVo.systemFormValue"></systemFrom>
<!-- <associationForm ref="associationForm" :formsValue="formList" @getDatas="getDatas"></associationForm>-->
</view>
</view>
<view class="heights"></view>
<view class="reservation-bottom">
<view class='footer acea-row row-between-wrapper'>
<view class="footer_count">
<view class="acea-row">
<view>合计:</view>
<view class='pColor'>
<priceFormat :price="totalPrice" weight intSize="48" floatSize="32" labelSize="32"></priceFormat>
</view>
</view>
</view>
<view class='settlement' style='z-index:100' @click="SubOrder">确认下单</view>
</view>
</view>
</view>
</template>
<script>
let sysHeight = uni.getSystemInfoSync().statusBarHeight + 'px';
const CACHE_CITY = {};
import { mapGetters } from "vuex";
import { HTTP_REQUEST_URL } from '@/config/app';
import { getOrderConfirm } from '@/api/order.js';
//import associationForm from '../components/associationForm';
export default {
name: 'reservationInfo',
components: {
//associationForm
},
data() {
return {
//#ifdef H5
marTop: 0,
//#endif
//#ifdef MP
marTop: uni.getSystemInfoSync().statusBarHeight+43+'px',
//#endif
//#ifdef APP-PLUS
marTop: uni.getSystemInfoSync().statusBarHeight+'px',
//#endif
domain: HTTP_REQUEST_URL,
sysHeight: sysHeight,
formList: {},
formValue: [],
storeInfo: {},
totalPrice: "",
address_id: 0,
cart_id: "",
service_type: "",
cartInfo: {},
extend: {},
post: {},
payType: 'weixin', //支付方式
order_form: [],
mer_id: "",
formType: 2
}
},
computed: {
...mapGetters(['viewColor','isLogin','hide_mer_status']),
},
onLoad(options){
this.address_id = options.address_id
this.cart_id = options.cart_id
this.service_type = options.service_type
this.mer_id = options.mer_id
this.formType = options.formType
},
mounted(){
uni.setStorageSync('extendInfo',[])
this.getConfirm();
},
methods: {
goBack: function() {
uni.navigateBack();
},
// 进店
goStore: function(id) {
if (this.hide_mer_status != 1) {
uni.navigateTo({
url: `/pages/store/home/index?id=${id}`
})
}
},
/**
* 获取当前订单详细信息
*
*/
getConfirm: function() {
let that = this;
uni.showLoading({
title: '',
mask: true
});
let data = {
cart_id: that.cart_id.split(",")
}
if(that.service_type == 1){
data.takes = [that.mer_id]
}else {
data.address_id = that.address_id
}
getOrderConfirm(data).then(res => {
that.$set(that, 'cartInfo', res.data.order);
let count = that.formType == 1 ? res.data.order[0]['list'][0]['cart_num'] : 1;
that.$set(that, 'totalPrice', res.data.order_price);
that.$set(that, 'formList', res.data.mer_form_info);
if(res.data.mer_form_info&&res.data.mer_form_info.name)that.$refs.associationForm.getFormList(res.data.mer_form_info,count);
uni.hideLoading();
}).catch(err => {
return this.$util.Tips({
title: err
}, {
tab: 3,
url: 1
});
});
},
getDatas() {
let data = this.$refs.associationForm.getFormValue();
return data;
},
SubOrder: function(e) {
let that = this,data = {};
if(that.formList && that.formList.name)that.order_form = that.getDatas();
let extendArr = [];
for(var i=0; i<that.order_form.length; i++) {
let extendData = {}
for (var j = 0; j < that.order_form[i].length; j++) {
let curdata = that.order_form[i][j]
if (['radios'].indexOf(curdata.name) == -1 && (curdata.titleShow.val || (['uploadPicture','dateranges'].indexOf(curdata.name) == -1 && curdata.value && curdata.value.trim()))) {
if ((curdata.name === 'texts' && curdata.valConfig.tabVal == 0) || ['dates','times','selects','citys','checkboxs'].indexOf(curdata.name) != -1) {
if (!curdata.value || (curdata.value && !curdata.value.trim())) {
return that.$util.Tips({
title: `请填写第${i+1}个表单的${curdata.titleConfig.value}`
});
}
}
if(curdata.name === 'timeranges'){
if(!curdata.value){
return that.$util.Tips({
title: `请选择第${i+1}个表单的${curdata.titleConfig.value}`
});
}
}
if (curdata.name === 'dateranges') {
if (!curdata.value.length) {
return that.$util.Tips({
title: `请选择第${i+1}个表单的${curdata.titleConfig.value}`
});
}
}
if (curdata.name === 'texts' && curdata.valConfig.tabVal == 4) {
if (curdata.value <= 0) {
return that.$util.Tips({
title: `${i+1}个表单请填写大于0的${curdata.titleConfig.value}`
});
}
}
if (curdata.name === 'texts' && curdata.valConfig.tabVal == 3) {
if (!/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/.test(curdata.value)) {
return that.$util.Tips({
title: `${i+1}个表单请填写正确的${curdata.titleConfig.value}`
});
}
}
if (curdata.name === 'texts' && curdata.valConfig.tabVal == 1) {
if (!/^1(3|4|5|7|8|9|6)\d{9}$/i.test(curdata.value)) {
return that.$util.Tips({
title: `${i+1}个表单请填写正确的${curdata.titleConfig.value}`
});
}
}
if (curdata.name === 'texts' && curdata.valConfig.tabVal == 2) {
if (!
/^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$|^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/i
.test(curdata.value)) {
return that.$util.Tips({
title: `${i+1}个表单请填写正确的${curdata.titleConfig.value}`
});
}
}
if (curdata.name === 'uploadPicture') {
if (!curdata.value.length) {
return that.$util.Tips({
title: `请上传第${i+1}个表单的${curdata.titleConfig.value}`
});
}
}
}
extendData[curdata.key] = curdata.value
}
extendArr.push(extendData)
}
let formId = extendArr.length > 0 ? 1 : 0
uni.setStorageSync('extendInfo',extendArr)
uni.navigateTo({
url: `/pages/users/order_confirm/index?cartId=${this.cart_id}&serviceType=${this.service_type}&addressId=${this.address_id}&formId=${formId}&merId=${that.mer_id}`
})
return
},
}
};
</script>
<style lang="scss" scoped>
.sys-head .bg{
background-image: linear-gradient( 90deg, var(--view-bntColor22) 0%, var(--view-bntColor21) 100%);
}
.reservation-main {
position: relative;
margin-top: -100rpx;
}
.reservation-header {
background: rgba(255,255,255,.9);
}
.store-info {
.store-title {
display: flex;
align-items: center;
padding: 28rpx 30rpx;
.icon-ic_mall {
font-size: 32rpx;
}
.icon-ic_rightarrow {
font-size: 26rpx;
}
.txt {
margin: 0 8rpx;
}
}
.product-item {
display: flex;
padding: 0 30rpx 26rpx;
.img-box {
width: 130rpx;
height: 130rpx;
image {
width: 130rpx;
height: 130rpx;
border-radius: 16rpx;
}
}
.content {
position: relative;
width: 550rpx;
margin-left: 20rpx;
font-size: 28rpx;
color: #282828;
overflow: hidden;
.line1 {
width: 480rpx;
}
.label {
margin-top: 8rpx;
color: #999999;
font-size: 20rpx;
}
.price {
margin-top: 10rpx;
position: relative;
color: var(--view-theme);
.vip-price {
position: relative;
top: -2rpx;
}
}
.vip-money{
margin-left: 13rpx;
color: #282828;
font-size: 22rpx;
font-weight: 700;
margin-left: 12rpx;
}
.vip-image{
width: 60rpx;
height: 25rpx;
margin-left: 6rpx;
}
}
.item-count {
color: #999999;
font-size: 26rpx;
}
}
}
.reservation-bottom {
width: 100%;
position: fixed;
bottom: 0;
left: 0;
background-color: #fff;
.area-tip {
padding: 0 32rpx;
height: 80rpx;
background: var(--view-bgColor);
color: var(--view-theme);
.iconfont {
margin-right: 10rpx;
}
}
}
.reservation .footer {
width: 100%;
height: 100rpx;
height: calc(120rpx+ constant(safe-area-inset-bottom)); ///兼容 IOS<11.2/
height: calc(120rpx + env(safe-area-inset-bottom)); ///兼容 IOS>11.2/
padding: 0 30rpx;
font-size: 28rpx;
color: #333;
box-sizing: border-box;
z-index: 30;
.footer_count{
font-size: 28rpx;
>view {
align-items: baseline;
}
.pColor {
margin-left: 12rpx;
}
}
.coupon_price{
color: #999999;
font-size: 22rpx;
margin-top: 10rpx;
.detail{
color: #666666;
background: #F5F5F5;
border-radius: 26rpx;
margin-left: 20rpx;
height: 34rpx;
line-height: 34rpx;
display: inline-block;
width: 104rpx;
text-align: center;
font-size: 18rpx;
}
}
}
.pColor{
color: var(--view-priceColor);
}
.reservation .footer .settlement {
font-size: 30rpx;
color: #fff;
width: 200rpx;
height: 72rpx;
background-color: var(--view-theme);
border-radius: 60rpx;
text-align: center;
line-height: 72rpx;
font-size: 26rpx;
&.disabled {
background-color: #cccccc;
}
}
.heights{
height: calc(140rpx+ constant(safe-area-inset-bottom)); ///兼容 IOS<11.2/
height: calc(140rpx + env(safe-area-inset-bottom)); ///兼容 IOS>11.2/
}
.header{
height: 160rpx;
background: linear-gradient( 360deg, #F5F5F5 0%, rgba(245,245,245,0) 100%);
background-image: linear-gradient( 90deg, var(--view-bntColor22) 0%, var(--view-bntColor21) 100%);
position: relative;
&::after {
content: "";
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 86rpx;
background: linear-gradient(0deg, #F5F5F5 0%, rgba(245, 245, 245, 0) 100%);
}
}
</style>