版本迭代
This commit is contained in:
parent
eec23581e1
commit
a5aab460c6
16
App.vue
16
App.vue
|
|
@ -1,15 +1,22 @@
|
|||
<script>
|
||||
import Vue from 'vue'
|
||||
import Vue from 'vue';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
modalContent: '',
|
||||
cancelMsg: '取消',
|
||||
confirmMsg: '确定'
|
||||
}
|
||||
},
|
||||
onLaunch: function() {
|
||||
uni.getSystemInfo({
|
||||
success: function(e) {
|
||||
// #ifndef MP
|
||||
Vue.prototype.StatusBar = e.statusBarHeight;
|
||||
if (e.platform == 'android') {
|
||||
Vue.prototype.CustomBar = e.statusBarHeight + 50;
|
||||
Vue.prototype.CustomBar = e.statusBarHeight + 50;
|
||||
} else {
|
||||
Vue.prototype.CustomBar = e.statusBarHeight + 45;
|
||||
Vue.prototype.CustomBar = e.statusBarHeight + 45;
|
||||
};
|
||||
// #endif
|
||||
// #ifdef MP-WEIXIN
|
||||
|
|
@ -103,7 +110,7 @@
|
|||
]
|
||||
|
||||
},
|
||||
onShow: function() {
|
||||
onShow: function(data) {
|
||||
console.log('App Show')
|
||||
},
|
||||
onHide: function() {
|
||||
|
|
@ -124,6 +131,7 @@
|
|||
@import '@/uni_modules/uni-scss/index.scss';
|
||||
/* #ifndef APP-NVUE */
|
||||
@import '@/static/customicons.css';
|
||||
|
||||
// 设置整个项目的背景色
|
||||
page {
|
||||
background-color: #f5f5f5;
|
||||
|
|
|
|||
|
|
@ -2,9 +2,16 @@
|
|||
<view>
|
||||
<view class="cu-custom" :style="[{height:CustomBar + 'px'}]">
|
||||
<view class="cu-bar fixed" :style="style" :class="[bgImage!=''?'none-bg text-white bg-img':'',bgColor]">
|
||||
<view class="action" @tap="BackPage" v-if="isBack">
|
||||
<text class="cuIcon-back"></text>
|
||||
<slot name="backText"></slot>
|
||||
<view class="flex justify-start">
|
||||
<view class="action" @tap="BackPage" v-if="isBack">
|
||||
<text class="cuIcon-back"></text>
|
||||
<slot name="backText"></slot>
|
||||
</view>
|
||||
<view class="action" @tap="BackHomePage" v-if="isBackHome">
|
||||
<text class="cuIcon-homefill"></text>
|
||||
<slot name="backHomeText"></slot>
|
||||
</view>
|
||||
<view></view>
|
||||
</view>
|
||||
<view class="content" :style="[{top:StatusBar + 'px'}]">
|
||||
<slot name="content"></slot>
|
||||
|
|
@ -45,6 +52,14 @@
|
|||
type: [Boolean, String],
|
||||
default: false
|
||||
},
|
||||
isBackHome: {
|
||||
type: [Boolean, String],
|
||||
default: false
|
||||
},
|
||||
homePageUrl: {
|
||||
type: [String],
|
||||
default: ''
|
||||
},
|
||||
bgImage: {
|
||||
type: String,
|
||||
default: ''
|
||||
|
|
@ -55,11 +70,22 @@
|
|||
uni.navigateBack({
|
||||
delta: 1
|
||||
});
|
||||
},
|
||||
BackHomePage() {
|
||||
uni.reLaunch({
|
||||
url: this.homePageUrl
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
<style scoped>
|
||||
.cu-bar .action:not(:first-child) {
|
||||
margin-left: 10rpx;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
.cu-bar .action:not(:first-child)>text[class*="cuIcon-"] {
|
||||
margin-right: 0.3em;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,3 @@
|
|||
export default {
|
||||
CONFIRM: 'confirmCallback'
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
// const emailRegex = /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/;
|
||||
const emailRegex = /^\S+?@\S+?.\S+?$/;
|
||||
const contactNumRegex = /^((0\d{2,3}-?\d{7,8})|(1[3465789]\d{9}))$/;
|
||||
const idCardRegex = /^[1-9]\d{5}(18|19|20|(3\d))\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/;
|
||||
const licenseIdNumRegex = /^[a-zA-Z0-9]{10,20}$/;
|
||||
|
||||
export default {
|
||||
validEmail: function(email) {
|
||||
return emailRegex.test(email);
|
||||
},
|
||||
|
||||
validContactNum: function(contactNum) {
|
||||
return contactNumRegex.test(contactNum);
|
||||
},
|
||||
|
||||
validIdCard: function(idCardNum) {
|
||||
return idCardRegex.test(idCardNum);
|
||||
},
|
||||
|
||||
validLicenseIdNum: function(licenseIdNum) {
|
||||
return licenseIdNumRegex.test(licenseIdNum);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,411 @@
|
|||
<template>
|
||||
<view :class="modal?'show-qrcode':'hide-qrcode'">
|
||||
<view class="box-qrcode" :style="{'margin-left': marginLeft + 'px'}" @longtap="longtapCode">
|
||||
<!-- style="width: 550rpx;height: 550rpx;" -->
|
||||
|
||||
<canvas class="canvas-qrcode" :style="style_w_h" :canvas-id="qrcode_id">
|
||||
|
||||
<!-- #ifndef MP -->
|
||||
<view v-if="modal&&is_themeImg" :style="style_w_h" class="box-img-qrcode">
|
||||
<image :style="style_w_h_img" mode="scaleToFill" :src="themeImg"></image>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
|
||||
</canvas>
|
||||
|
||||
<!-- <image mode="scaleToFill" :src="imagePath"></image> -->
|
||||
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
var qr_we = require("./qrcode_wx.js");
|
||||
const qrCode = require('./weapp-qrcode.js')
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
isAndroid : false ,
|
||||
show: true,
|
||||
imagePath: '',
|
||||
// qrcode_id: 'qrcode_id',
|
||||
marginLeft: 0,
|
||||
//一般的安卓app只需加30就能显示全
|
||||
//苹果app的不加就能显示全,加了就要弄margin-left
|
||||
//有些安卓app显示不全
|
||||
add_num : 30 ,
|
||||
add_num_key : 'rectify_code_key',
|
||||
}
|
||||
},
|
||||
props: {
|
||||
modal: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
url: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
height: {
|
||||
type: Number,
|
||||
default: 260
|
||||
},
|
||||
width: {
|
||||
type: Number,
|
||||
default: 260
|
||||
},
|
||||
themeColor: {
|
||||
type: String,
|
||||
default: '#333333',
|
||||
},
|
||||
qrcode_id: {
|
||||
type: String,
|
||||
default: 'qrcode_id',
|
||||
},
|
||||
is_themeImg: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
themeImg: {
|
||||
type: String,
|
||||
default: 'https://cdn.pixabay.com/photo/2016/11/29/13/24/balloons-1869816__340.jpg',
|
||||
},
|
||||
h_w_img: {
|
||||
type: Number,
|
||||
default: 30
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
watch:{
|
||||
|
||||
},
|
||||
computed: {
|
||||
style_w_h() {
|
||||
return this.set_style_w_h();
|
||||
},
|
||||
style_w_h_img() {
|
||||
let that = this;
|
||||
var height = parseInt(that.h_w_img);
|
||||
var width = parseInt(that.h_w_img);
|
||||
var style = '';
|
||||
if (height > 0) {
|
||||
style = `height:${height*2}rpx;`;
|
||||
}
|
||||
if (width > 0) {
|
||||
style += `width:${width*2}rpx;z-index: 2;`;
|
||||
}
|
||||
|
||||
return style;
|
||||
},
|
||||
},
|
||||
created: function() {
|
||||
let that = this;
|
||||
try {
|
||||
//app苹果二维码不居中
|
||||
//#ifndef MP
|
||||
let isAndroid = false ;
|
||||
const res = uni.getSystemInfoSync();
|
||||
if(res.platform == 'android'){
|
||||
isAndroid = true ;
|
||||
}else{
|
||||
isAndroid = false ;
|
||||
}
|
||||
|
||||
|
||||
if (!isAndroid) {
|
||||
that.marginLeft = 46;
|
||||
}
|
||||
|
||||
that.isAndroid = isAndroid ;
|
||||
try {
|
||||
const add_num = uni.getStorageSync(that.add_num_key);
|
||||
if (add_num) {
|
||||
that.add_num = add_num;
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
// error
|
||||
|
||||
}
|
||||
// #endif
|
||||
|
||||
} catch (e) {
|
||||
// error
|
||||
}
|
||||
|
||||
//#ifdef MP
|
||||
//that.marginLeft = 40;
|
||||
// #endif
|
||||
|
||||
},
|
||||
methods: {
|
||||
set_style_w_h(){
|
||||
|
||||
let that = this;
|
||||
var height = parseInt(that.height);
|
||||
var width = parseInt(that.width);
|
||||
var style = '';
|
||||
var height = height*2 ;
|
||||
var width = width*2 ;
|
||||
|
||||
//#ifndef MP
|
||||
var add = that.add_num ;
|
||||
|
||||
height += add;
|
||||
width += add;
|
||||
// #endif
|
||||
|
||||
if (height > 0) {
|
||||
style = `height:${height}rpx;`;
|
||||
}
|
||||
if (width > 0) {
|
||||
style += `width:${width}rpx;`;
|
||||
}
|
||||
|
||||
return style;
|
||||
},
|
||||
hideQrcode() {
|
||||
this.$emit("hideQrcode")
|
||||
},
|
||||
// 二维码生成工具
|
||||
crtQrCode() {
|
||||
let that = this;
|
||||
//#ifndef MP
|
||||
new qrCode(that.qrcode_id, {
|
||||
text: this.url,
|
||||
width: that.width,
|
||||
height: that.height,
|
||||
colorDark: that.themeColor,//#333333
|
||||
colorLight: "#FFFFFF",
|
||||
correctLevel: qrCode.CorrectLevel.H,
|
||||
})
|
||||
// #endif
|
||||
//#ifdef MP
|
||||
that.createQrCode(this.url, that.qrcode_id, that.width, that.height,that.themeColor,that.is_themeImg,that.themeImg,that.h_w_img);
|
||||
// #endif
|
||||
|
||||
//that.createQrCode(this.url, that.qrcode_id, that.width, that.height);
|
||||
},
|
||||
//#ifdef MP
|
||||
|
||||
createQrCode: function(url, canvasId, cavW, cavH,cavColor,haveImg,imgurl,imgsize) {
|
||||
//调用插件中的draw方法,绘制二维码图片
|
||||
qr_we.api.draw(url, canvasId, cavW, cavH,cavColor,haveImg,imgurl,imgsize, this, this.canvasToTempImage);
|
||||
// setTimeout(() => { this.canvasToTempImage();},100);
|
||||
|
||||
},
|
||||
|
||||
// #endif
|
||||
//获取临时缓存照片路径,存入data中
|
||||
canvasToTempImage: function() {
|
||||
var that = this;
|
||||
},
|
||||
saveImage: function() {
|
||||
var that = this;
|
||||
uni.canvasToTempFilePath({
|
||||
canvasId: that.qrcode_id,
|
||||
success: function(res) {
|
||||
var tempFilePath = res.tempFilePath;
|
||||
console.log(tempFilePath);
|
||||
that.imagePath = tempFilePath;
|
||||
|
||||
//保存到相册
|
||||
// uni.saveFile({
|
||||
// tempFilePath: tempFilePath,
|
||||
// success: function (res2) {
|
||||
// var savedFilePath = res2.savedFilePath;
|
||||
|
||||
|
||||
// }
|
||||
// });
|
||||
uni.saveImageToPhotosAlbum({
|
||||
filePath : tempFilePath ,
|
||||
success: function (res3) {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '保存成功',
|
||||
confirmText: '确定',
|
||||
showCancel: false,
|
||||
confirmColor: '#33CCCC',
|
||||
success(res4) {
|
||||
|
||||
}
|
||||
})
|
||||
},
|
||||
});
|
||||
},
|
||||
fail: function(res) {
|
||||
console.log(res);
|
||||
}
|
||||
}, that);
|
||||
},
|
||||
//微信小程序支持:长按二维码,提示是否保存相册
|
||||
//安卓APP长按校正二维码
|
||||
longtapCode(){
|
||||
var that = this;
|
||||
|
||||
//#ifndef MP
|
||||
uni.showModal({
|
||||
title: '校正二维码',
|
||||
content: '二维码是否异常',
|
||||
confirmText: '确定',
|
||||
confirmColor: '#33CCCC',
|
||||
success(res) {
|
||||
if (res.confirm) {
|
||||
that.rectify_code();
|
||||
}
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
|
||||
//#ifdef MP-WEIXIN
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '是否保存到相册',
|
||||
confirmText: '确定',
|
||||
confirmColor: '#33CCCC',
|
||||
success(res) {
|
||||
if (res.confirm) {
|
||||
that.saveImage();
|
||||
}
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
},
|
||||
//安卓有些手机不正常,长按可选择矫正
|
||||
rectify_code(){
|
||||
var that = this;
|
||||
let add_num = that.add_num ;
|
||||
add_num += 30 ;
|
||||
that.add_num = add_num;
|
||||
that.crtQrCode();//重新生成才会立即覆盖
|
||||
try {
|
||||
//第一次长按校正设置了就不用在设置
|
||||
uni.setStorage({
|
||||
key: that.add_num_key,
|
||||
data: add_num,
|
||||
success: function() {
|
||||
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
// error
|
||||
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
// .qrcode-box {
|
||||
// position: fixed;
|
||||
// left: 0;
|
||||
// top: 0;
|
||||
// right: 0;
|
||||
// bottom: 0;
|
||||
// height: 100vh;
|
||||
// width: 100vw;
|
||||
// background-color: rgba(59, 59, 59, 0.6);
|
||||
// // opacity: 0.8;
|
||||
// text-align: center;
|
||||
// display: flex;
|
||||
// align-items: center;
|
||||
// display: none;
|
||||
|
||||
// .qrcode-item {
|
||||
// flex: 1;
|
||||
// position: relative;
|
||||
// text-align: center;
|
||||
|
||||
// .item-box {
|
||||
// width: 90%;
|
||||
// margin: auto;
|
||||
// display: inline-block;
|
||||
// margin-top: 30%;
|
||||
// padding-bottom: 30rpx;
|
||||
|
||||
// // animation: show 0.7s;
|
||||
// .title {
|
||||
// font-size: 46rpx;
|
||||
// text-align: center;
|
||||
// margin-bottom: 24rpx;
|
||||
// }
|
||||
|
||||
// .canvas {
|
||||
// margin: auto;
|
||||
// display: inline-block;
|
||||
// margin: auto;
|
||||
// }
|
||||
|
||||
// background-color: #FFFFFF;
|
||||
// }
|
||||
|
||||
// }
|
||||
// }
|
||||
.box-qrcode{
|
||||
text-align: center;
|
||||
position: relative;
|
||||
.box-img-qrcode{
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
image{
|
||||
width: 60upx;
|
||||
height: 60upx;
|
||||
border-radius: 50%;
|
||||
|
||||
}
|
||||
.canvas-qrcode {
|
||||
|
||||
margin: auto;
|
||||
display: inline-block;
|
||||
float: left;
|
||||
}
|
||||
|
||||
|
||||
.opacity-qrcode {
|
||||
opacity: 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.show-qrcode {
|
||||
display: block;
|
||||
animation: fade 0.7s;
|
||||
|
||||
// -moz-animation: fade 0.5s; /* Firefox */
|
||||
// -webkit-animation: fade 0.5s; /* Safari 和 Chrome */
|
||||
// -o-animation: fade 0.5s;
|
||||
}
|
||||
|
||||
.hide-qrcode {
|
||||
animation: hide 0.7s;
|
||||
}
|
||||
|
||||
@keyframes fade {
|
||||
from {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes hide {
|
||||
from {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,872 @@
|
|||
!(function() {
|
||||
|
||||
// alignment pattern
|
||||
var adelta = [
|
||||
0, 11, 15, 19, 23, 27, 31,
|
||||
16, 18, 20, 22, 24, 26, 28, 20, 22, 24, 24, 26, 28, 28, 22, 24, 24,
|
||||
26, 26, 28, 28, 24, 24, 26, 26, 26, 28, 28, 24, 26, 26, 26, 28, 28
|
||||
];
|
||||
|
||||
// version block
|
||||
var vpat = [
|
||||
0xc94, 0x5bc, 0xa99, 0x4d3, 0xbf6, 0x762, 0x847, 0x60d,
|
||||
0x928, 0xb78, 0x45d, 0xa17, 0x532, 0x9a6, 0x683, 0x8c9,
|
||||
0x7ec, 0xec4, 0x1e1, 0xfab, 0x08e, 0xc1a, 0x33f, 0xd75,
|
||||
0x250, 0x9d5, 0x6f0, 0x8ba, 0x79f, 0xb0b, 0x42e, 0xa64,
|
||||
0x541, 0xc69
|
||||
];
|
||||
|
||||
// final format bits with mask: level << 3 | mask
|
||||
var fmtword = [
|
||||
0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976, //L
|
||||
0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0, //M
|
||||
0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed, //Q
|
||||
0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b //H
|
||||
];
|
||||
|
||||
// 4 per version: number of blocks 1,2; data width; ecc width
|
||||
var eccblocks = [
|
||||
1, 0, 19, 7, 1, 0, 16, 10, 1, 0, 13, 13, 1, 0, 9, 17,
|
||||
1, 0, 34, 10, 1, 0, 28, 16, 1, 0, 22, 22, 1, 0, 16, 28,
|
||||
1, 0, 55, 15, 1, 0, 44, 26, 2, 0, 17, 18, 2, 0, 13, 22,
|
||||
1, 0, 80, 20, 2, 0, 32, 18, 2, 0, 24, 26, 4, 0, 9, 16,
|
||||
1, 0, 108, 26, 2, 0, 43, 24, 2, 2, 15, 18, 2, 2, 11, 22,
|
||||
2, 0, 68, 18, 4, 0, 27, 16, 4, 0, 19, 24, 4, 0, 15, 28,
|
||||
2, 0, 78, 20, 4, 0, 31, 18, 2, 4, 14, 18, 4, 1, 13, 26,
|
||||
2, 0, 97, 24, 2, 2, 38, 22, 4, 2, 18, 22, 4, 2, 14, 26,
|
||||
2, 0, 116, 30, 3, 2, 36, 22, 4, 4, 16, 20, 4, 4, 12, 24,
|
||||
2, 2, 68, 18, 4, 1, 43, 26, 6, 2, 19, 24, 6, 2, 15, 28,
|
||||
4, 0, 81, 20, 1, 4, 50, 30, 4, 4, 22, 28, 3, 8, 12, 24,
|
||||
2, 2, 92, 24, 6, 2, 36, 22, 4, 6, 20, 26, 7, 4, 14, 28,
|
||||
4, 0, 107, 26, 8, 1, 37, 22, 8, 4, 20, 24, 12, 4, 11, 22,
|
||||
3, 1, 115, 30, 4, 5, 40, 24, 11, 5, 16, 20, 11, 5, 12, 24,
|
||||
5, 1, 87, 22, 5, 5, 41, 24, 5, 7, 24, 30, 11, 7, 12, 24,
|
||||
5, 1, 98, 24, 7, 3, 45, 28, 15, 2, 19, 24, 3, 13, 15, 30,
|
||||
1, 5, 107, 28, 10, 1, 46, 28, 1, 15, 22, 28, 2, 17, 14, 28,
|
||||
5, 1, 120, 30, 9, 4, 43, 26, 17, 1, 22, 28, 2, 19, 14, 28,
|
||||
3, 4, 113, 28, 3, 11, 44, 26, 17, 4, 21, 26, 9, 16, 13, 26,
|
||||
3, 5, 107, 28, 3, 13, 41, 26, 15, 5, 24, 30, 15, 10, 15, 28,
|
||||
4, 4, 116, 28, 17, 0, 42, 26, 17, 6, 22, 28, 19, 6, 16, 30,
|
||||
2, 7, 111, 28, 17, 0, 46, 28, 7, 16, 24, 30, 34, 0, 13, 24,
|
||||
4, 5, 121, 30, 4, 14, 47, 28, 11, 14, 24, 30, 16, 14, 15, 30,
|
||||
6, 4, 117, 30, 6, 14, 45, 28, 11, 16, 24, 30, 30, 2, 16, 30,
|
||||
8, 4, 106, 26, 8, 13, 47, 28, 7, 22, 24, 30, 22, 13, 15, 30,
|
||||
10, 2, 114, 28, 19, 4, 46, 28, 28, 6, 22, 28, 33, 4, 16, 30,
|
||||
8, 4, 122, 30, 22, 3, 45, 28, 8, 26, 23, 30, 12, 28, 15, 30,
|
||||
3, 10, 117, 30, 3, 23, 45, 28, 4, 31, 24, 30, 11, 31, 15, 30,
|
||||
7, 7, 116, 30, 21, 7, 45, 28, 1, 37, 23, 30, 19, 26, 15, 30,
|
||||
5, 10, 115, 30, 19, 10, 47, 28, 15, 25, 24, 30, 23, 25, 15, 30,
|
||||
13, 3, 115, 30, 2, 29, 46, 28, 42, 1, 24, 30, 23, 28, 15, 30,
|
||||
17, 0, 115, 30, 10, 23, 46, 28, 10, 35, 24, 30, 19, 35, 15, 30,
|
||||
17, 1, 115, 30, 14, 21, 46, 28, 29, 19, 24, 30, 11, 46, 15, 30,
|
||||
13, 6, 115, 30, 14, 23, 46, 28, 44, 7, 24, 30, 59, 1, 16, 30,
|
||||
12, 7, 121, 30, 12, 26, 47, 28, 39, 14, 24, 30, 22, 41, 15, 30,
|
||||
6, 14, 121, 30, 6, 34, 47, 28, 46, 10, 24, 30, 2, 64, 15, 30,
|
||||
17, 4, 122, 30, 29, 14, 46, 28, 49, 10, 24, 30, 24, 46, 15, 30,
|
||||
4, 18, 122, 30, 13, 32, 46, 28, 48, 14, 24, 30, 42, 32, 15, 30,
|
||||
20, 4, 117, 30, 40, 7, 47, 28, 43, 22, 24, 30, 10, 67, 15, 30,
|
||||
19, 6, 118, 30, 18, 31, 47, 28, 34, 34, 24, 30, 20, 61, 15, 30
|
||||
];
|
||||
|
||||
// Galois field log table
|
||||
var glog = [
|
||||
0xff, 0x00, 0x01, 0x19, 0x02, 0x32, 0x1a, 0xc6, 0x03, 0xdf, 0x33, 0xee, 0x1b, 0x68, 0xc7, 0x4b,
|
||||
0x04, 0x64, 0xe0, 0x0e, 0x34, 0x8d, 0xef, 0x81, 0x1c, 0xc1, 0x69, 0xf8, 0xc8, 0x08, 0x4c, 0x71,
|
||||
0x05, 0x8a, 0x65, 0x2f, 0xe1, 0x24, 0x0f, 0x21, 0x35, 0x93, 0x8e, 0xda, 0xf0, 0x12, 0x82, 0x45,
|
||||
0x1d, 0xb5, 0xc2, 0x7d, 0x6a, 0x27, 0xf9, 0xb9, 0xc9, 0x9a, 0x09, 0x78, 0x4d, 0xe4, 0x72, 0xa6,
|
||||
0x06, 0xbf, 0x8b, 0x62, 0x66, 0xdd, 0x30, 0xfd, 0xe2, 0x98, 0x25, 0xb3, 0x10, 0x91, 0x22, 0x88,
|
||||
0x36, 0xd0, 0x94, 0xce, 0x8f, 0x96, 0xdb, 0xbd, 0xf1, 0xd2, 0x13, 0x5c, 0x83, 0x38, 0x46, 0x40,
|
||||
0x1e, 0x42, 0xb6, 0xa3, 0xc3, 0x48, 0x7e, 0x6e, 0x6b, 0x3a, 0x28, 0x54, 0xfa, 0x85, 0xba, 0x3d,
|
||||
0xca, 0x5e, 0x9b, 0x9f, 0x0a, 0x15, 0x79, 0x2b, 0x4e, 0xd4, 0xe5, 0xac, 0x73, 0xf3, 0xa7, 0x57,
|
||||
0x07, 0x70, 0xc0, 0xf7, 0x8c, 0x80, 0x63, 0x0d, 0x67, 0x4a, 0xde, 0xed, 0x31, 0xc5, 0xfe, 0x18,
|
||||
0xe3, 0xa5, 0x99, 0x77, 0x26, 0xb8, 0xb4, 0x7c, 0x11, 0x44, 0x92, 0xd9, 0x23, 0x20, 0x89, 0x2e,
|
||||
0x37, 0x3f, 0xd1, 0x5b, 0x95, 0xbc, 0xcf, 0xcd, 0x90, 0x87, 0x97, 0xb2, 0xdc, 0xfc, 0xbe, 0x61,
|
||||
0xf2, 0x56, 0xd3, 0xab, 0x14, 0x2a, 0x5d, 0x9e, 0x84, 0x3c, 0x39, 0x53, 0x47, 0x6d, 0x41, 0xa2,
|
||||
0x1f, 0x2d, 0x43, 0xd8, 0xb7, 0x7b, 0xa4, 0x76, 0xc4, 0x17, 0x49, 0xec, 0x7f, 0x0c, 0x6f, 0xf6,
|
||||
0x6c, 0xa1, 0x3b, 0x52, 0x29, 0x9d, 0x55, 0xaa, 0xfb, 0x60, 0x86, 0xb1, 0xbb, 0xcc, 0x3e, 0x5a,
|
||||
0xcb, 0x59, 0x5f, 0xb0, 0x9c, 0xa9, 0xa0, 0x51, 0x0b, 0xf5, 0x16, 0xeb, 0x7a, 0x75, 0x2c, 0xd7,
|
||||
0x4f, 0xae, 0xd5, 0xe9, 0xe6, 0xe7, 0xad, 0xe8, 0x74, 0xd6, 0xf4, 0xea, 0xa8, 0x50, 0x58, 0xaf
|
||||
];
|
||||
|
||||
// Galios field exponent table
|
||||
var gexp = [
|
||||
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1d, 0x3a, 0x74, 0xe8, 0xcd, 0x87, 0x13, 0x26,
|
||||
0x4c, 0x98, 0x2d, 0x5a, 0xb4, 0x75, 0xea, 0xc9, 0x8f, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0,
|
||||
0x9d, 0x27, 0x4e, 0x9c, 0x25, 0x4a, 0x94, 0x35, 0x6a, 0xd4, 0xb5, 0x77, 0xee, 0xc1, 0x9f, 0x23,
|
||||
0x46, 0x8c, 0x05, 0x0a, 0x14, 0x28, 0x50, 0xa0, 0x5d, 0xba, 0x69, 0xd2, 0xb9, 0x6f, 0xde, 0xa1,
|
||||
0x5f, 0xbe, 0x61, 0xc2, 0x99, 0x2f, 0x5e, 0xbc, 0x65, 0xca, 0x89, 0x0f, 0x1e, 0x3c, 0x78, 0xf0,
|
||||
0xfd, 0xe7, 0xd3, 0xbb, 0x6b, 0xd6, 0xb1, 0x7f, 0xfe, 0xe1, 0xdf, 0xa3, 0x5b, 0xb6, 0x71, 0xe2,
|
||||
0xd9, 0xaf, 0x43, 0x86, 0x11, 0x22, 0x44, 0x88, 0x0d, 0x1a, 0x34, 0x68, 0xd0, 0xbd, 0x67, 0xce,
|
||||
0x81, 0x1f, 0x3e, 0x7c, 0xf8, 0xed, 0xc7, 0x93, 0x3b, 0x76, 0xec, 0xc5, 0x97, 0x33, 0x66, 0xcc,
|
||||
0x85, 0x17, 0x2e, 0x5c, 0xb8, 0x6d, 0xda, 0xa9, 0x4f, 0x9e, 0x21, 0x42, 0x84, 0x15, 0x2a, 0x54,
|
||||
0xa8, 0x4d, 0x9a, 0x29, 0x52, 0xa4, 0x55, 0xaa, 0x49, 0x92, 0x39, 0x72, 0xe4, 0xd5, 0xb7, 0x73,
|
||||
0xe6, 0xd1, 0xbf, 0x63, 0xc6, 0x91, 0x3f, 0x7e, 0xfc, 0xe5, 0xd7, 0xb3, 0x7b, 0xf6, 0xf1, 0xff,
|
||||
0xe3, 0xdb, 0xab, 0x4b, 0x96, 0x31, 0x62, 0xc4, 0x95, 0x37, 0x6e, 0xdc, 0xa5, 0x57, 0xae, 0x41,
|
||||
0x82, 0x19, 0x32, 0x64, 0xc8, 0x8d, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0, 0xdd, 0xa7, 0x53, 0xa6,
|
||||
0x51, 0xa2, 0x59, 0xb2, 0x79, 0xf2, 0xf9, 0xef, 0xc3, 0x9b, 0x2b, 0x56, 0xac, 0x45, 0x8a, 0x09,
|
||||
0x12, 0x24, 0x48, 0x90, 0x3d, 0x7a, 0xf4, 0xf5, 0xf7, 0xf3, 0xfb, 0xeb, 0xcb, 0x8b, 0x0b, 0x16,
|
||||
0x2c, 0x58, 0xb0, 0x7d, 0xfa, 0xe9, 0xcf, 0x83, 0x1b, 0x36, 0x6c, 0xd8, 0xad, 0x47, 0x8e, 0x00
|
||||
];
|
||||
|
||||
// Working buffers:
|
||||
// data input and ecc append, image working buffer, fixed part of image, run lengths for badness
|
||||
var strinbuf = [],
|
||||
eccbuf = [],
|
||||
qrframe = [],
|
||||
framask = [],
|
||||
rlens = [];
|
||||
// Control values - width is based on version, last 4 are from table.
|
||||
var version, width, neccblk1, neccblk2, datablkw, eccblkwid;
|
||||
var ecclevel = 2;
|
||||
// set bit to indicate cell in qrframe is immutable. symmetric around diagonal
|
||||
function setmask(x, y) {
|
||||
var bt;
|
||||
if (x > y) {
|
||||
bt = x;
|
||||
x = y;
|
||||
y = bt;
|
||||
}
|
||||
// y*y = 1+3+5...
|
||||
bt = y;
|
||||
bt *= y;
|
||||
bt += y;
|
||||
bt >>= 1;
|
||||
bt += x;
|
||||
framask[bt] = 1;
|
||||
}
|
||||
|
||||
// enter alignment pattern - black to qrframe, white to mask (later black frame merged to mask)
|
||||
function putalign(x, y) {
|
||||
var j;
|
||||
|
||||
qrframe[x + width * y] = 1;
|
||||
for (j = -2; j < 2; j++) {
|
||||
qrframe[(x + j) + width * (y - 2)] = 1;
|
||||
qrframe[(x - 2) + width * (y + j + 1)] = 1;
|
||||
qrframe[(x + 2) + width * (y + j)] = 1;
|
||||
qrframe[(x + j + 1) + width * (y + 2)] = 1;
|
||||
}
|
||||
for (j = 0; j < 2; j++) {
|
||||
setmask(x - 1, y + j);
|
||||
setmask(x + 1, y - j);
|
||||
setmask(x - j, y - 1);
|
||||
setmask(x + j, y + 1);
|
||||
}
|
||||
}
|
||||
|
||||
//========================================================================
|
||||
// Reed Solomon error correction
|
||||
// exponentiation mod N
|
||||
function modnn(x) {
|
||||
while (x >= 255) {
|
||||
x -= 255;
|
||||
x = (x >> 8) + (x & 255);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
var genpoly = [];
|
||||
|
||||
// Calculate and append ECC data to data block. Block is in strinbuf, indexes to buffers given.
|
||||
function appendrs(data, dlen, ecbuf, eclen) {
|
||||
var i, j, fb;
|
||||
|
||||
for (i = 0; i < eclen; i++)
|
||||
strinbuf[ecbuf + i] = 0;
|
||||
for (i = 0; i < dlen; i++) {
|
||||
fb = glog[strinbuf[data + i] ^ strinbuf[ecbuf]];
|
||||
if (fb != 255) /* fb term is non-zero */
|
||||
for (j = 1; j < eclen; j++)
|
||||
strinbuf[ecbuf + j - 1] = strinbuf[ecbuf + j] ^ gexp[modnn(fb + genpoly[eclen - j])];
|
||||
else
|
||||
for (j = ecbuf; j < ecbuf + eclen; j++)
|
||||
strinbuf[j] = strinbuf[j + 1];
|
||||
strinbuf[ecbuf + eclen - 1] = fb == 255 ? 0 : gexp[modnn(fb + genpoly[0])];
|
||||
}
|
||||
}
|
||||
|
||||
//========================================================================
|
||||
// Frame data insert following the path rules
|
||||
|
||||
// check mask - since symmetrical use half.
|
||||
function ismasked(x, y) {
|
||||
var bt;
|
||||
if (x > y) {
|
||||
bt = x;
|
||||
x = y;
|
||||
y = bt;
|
||||
}
|
||||
bt = y;
|
||||
bt += y * y;
|
||||
bt >>= 1;
|
||||
bt += x;
|
||||
return framask[bt];
|
||||
}
|
||||
|
||||
//========================================================================
|
||||
// Apply the selected mask out of the 8.
|
||||
function applymask(m) {
|
||||
var x, y, r3x, r3y;
|
||||
|
||||
switch (m) {
|
||||
case 0:
|
||||
for (y = 0; y < width; y++)
|
||||
for (x = 0; x < width; x++)
|
||||
if (!((x + y) & 1) && !ismasked(x, y))
|
||||
qrframe[x + y * width] ^= 1;
|
||||
break;
|
||||
case 1:
|
||||
for (y = 0; y < width; y++)
|
||||
for (x = 0; x < width; x++)
|
||||
if (!(y & 1) && !ismasked(x, y))
|
||||
qrframe[x + y * width] ^= 1;
|
||||
break;
|
||||
case 2:
|
||||
for (y = 0; y < width; y++)
|
||||
for (r3x = 0, x = 0; x < width; x++, r3x++) {
|
||||
if (r3x == 3)
|
||||
r3x = 0;
|
||||
if (!r3x && !ismasked(x, y))
|
||||
qrframe[x + y * width] ^= 1;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
for (r3y = 0, y = 0; y < width; y++, r3y++) {
|
||||
if (r3y == 3)
|
||||
r3y = 0;
|
||||
for (r3x = r3y, x = 0; x < width; x++, r3x++) {
|
||||
if (r3x == 3)
|
||||
r3x = 0;
|
||||
if (!r3x && !ismasked(x, y))
|
||||
qrframe[x + y * width] ^= 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
for (y = 0; y < width; y++)
|
||||
for (r3x = 0, r3y = ((y >> 1) & 1), x = 0; x < width; x++, r3x++) {
|
||||
if (r3x == 3) {
|
||||
r3x = 0;
|
||||
r3y = !r3y;
|
||||
}
|
||||
if (!r3y && !ismasked(x, y))
|
||||
qrframe[x + y * width] ^= 1;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
for (r3y = 0, y = 0; y < width; y++, r3y++) {
|
||||
if (r3y == 3)
|
||||
r3y = 0;
|
||||
for (r3x = 0, x = 0; x < width; x++, r3x++) {
|
||||
if (r3x == 3)
|
||||
r3x = 0;
|
||||
if (!((x & y & 1) + !(!r3x | !r3y)) && !ismasked(x, y))
|
||||
qrframe[x + y * width] ^= 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
for (r3y = 0, y = 0; y < width; y++, r3y++) {
|
||||
if (r3y == 3)
|
||||
r3y = 0;
|
||||
for (r3x = 0, x = 0; x < width; x++, r3x++) {
|
||||
if (r3x == 3)
|
||||
r3x = 0;
|
||||
if (!(((x & y & 1) + (r3x && (r3x == r3y))) & 1) && !ismasked(x, y))
|
||||
qrframe[x + y * width] ^= 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
for (r3y = 0, y = 0; y < width; y++, r3y++) {
|
||||
if (r3y == 3)
|
||||
r3y = 0;
|
||||
for (r3x = 0, x = 0; x < width; x++, r3x++) {
|
||||
if (r3x == 3)
|
||||
r3x = 0;
|
||||
if (!(((r3x && (r3x == r3y)) + ((x + y) & 1)) & 1) && !ismasked(x, y))
|
||||
qrframe[x + y * width] ^= 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Badness coefficients.
|
||||
var N1 = 3,
|
||||
N2 = 3,
|
||||
N3 = 40,
|
||||
N4 = 10;
|
||||
|
||||
// Using the table of the length of each run, calculate the amount of bad image
|
||||
// - long runs or those that look like finders; called twice, once each for X and Y
|
||||
function badruns(length) {
|
||||
var i;
|
||||
var runsbad = 0;
|
||||
for (i = 0; i <= length; i++)
|
||||
if (rlens[i] >= 5)
|
||||
runsbad += N1 + rlens[i] - 5;
|
||||
// BwBBBwB as in finder
|
||||
for (i = 3; i < length - 1; i += 2)
|
||||
if (rlens[i - 2] == rlens[i + 2] &&
|
||||
rlens[i + 2] == rlens[i - 1] &&
|
||||
rlens[i - 1] == rlens[i + 1] &&
|
||||
rlens[i - 1] * 3 == rlens[i]
|
||||
// white around the black pattern? Not part of spec
|
||||
&&
|
||||
(rlens[i - 3] == 0 // beginning
|
||||
||
|
||||
i + 3 > length // end
|
||||
||
|
||||
rlens[i - 3] * 3 >= rlens[i] * 4 || rlens[i + 3] * 3 >= rlens[i] * 4)
|
||||
)
|
||||
runsbad += N3;
|
||||
return runsbad;
|
||||
}
|
||||
|
||||
// Calculate how bad the masked image is - blocks, imbalance, runs, or finders.
|
||||
function badcheck() {
|
||||
var x, y, h, b, b1;
|
||||
var thisbad = 0;
|
||||
var bw = 0;
|
||||
|
||||
// blocks of same color.
|
||||
for (y = 0; y < width - 1; y++)
|
||||
for (x = 0; x < width - 1; x++)
|
||||
if ((qrframe[x + width * y] && qrframe[(x + 1) + width * y] &&
|
||||
qrframe[x + width * (y + 1)] && qrframe[(x + 1) + width * (y + 1)]) // all black
|
||||
||
|
||||
!(qrframe[x + width * y] || qrframe[(x + 1) + width * y] ||
|
||||
qrframe[x + width * (y + 1)] || qrframe[(x + 1) + width * (y + 1)])) // all white
|
||||
thisbad += N2;
|
||||
|
||||
// X runs
|
||||
for (y = 0; y < width; y++) {
|
||||
rlens[0] = 0;
|
||||
for (h = b = x = 0; x < width; x++) {
|
||||
if ((b1 = qrframe[x + width * y]) == b)
|
||||
rlens[h]++;
|
||||
else
|
||||
rlens[++h] = 1;
|
||||
b = b1;
|
||||
bw += b ? 1 : -1;
|
||||
}
|
||||
thisbad += badruns(h);
|
||||
}
|
||||
|
||||
// black/white imbalance
|
||||
if (bw < 0)
|
||||
bw = -bw;
|
||||
|
||||
var big = bw;
|
||||
var count = 0;
|
||||
big += big << 2;
|
||||
big <<= 1;
|
||||
while (big > width * width)
|
||||
big -= width * width, count++;
|
||||
thisbad += count * N4;
|
||||
|
||||
// Y runs
|
||||
for (x = 0; x < width; x++) {
|
||||
rlens[0] = 0;
|
||||
for (h = b = y = 0; y < width; y++) {
|
||||
if ((b1 = qrframe[x + width * y]) == b)
|
||||
rlens[h]++;
|
||||
else
|
||||
rlens[++h] = 1;
|
||||
b = b1;
|
||||
}
|
||||
thisbad += badruns(h);
|
||||
}
|
||||
return thisbad;
|
||||
}
|
||||
|
||||
function genframe(instring) {
|
||||
var x, y, k, t, v, i, j, m;
|
||||
|
||||
// find the smallest version that fits the string
|
||||
t = instring.length;
|
||||
version = 0;
|
||||
do {
|
||||
version++;
|
||||
k = (ecclevel - 1) * 4 + (version - 1) * 16;
|
||||
neccblk1 = eccblocks[k++];
|
||||
neccblk2 = eccblocks[k++];
|
||||
datablkw = eccblocks[k++];
|
||||
eccblkwid = eccblocks[k];
|
||||
k = datablkw * (neccblk1 + neccblk2) + neccblk2 - 3 + (version <= 9);
|
||||
if (t <= k)
|
||||
break;
|
||||
} while (version < 40);
|
||||
|
||||
// FIXME - insure that it fits insted of being truncated
|
||||
width = 17 + 4 * version;
|
||||
|
||||
// allocate, clear and setup data structures
|
||||
v = datablkw + (datablkw + eccblkwid) * (neccblk1 + neccblk2) + neccblk2;
|
||||
for (t = 0; t < v; t++)
|
||||
eccbuf[t] = 0;
|
||||
strinbuf = instring.slice(0);
|
||||
|
||||
for (t = 0; t < width * width; t++)
|
||||
qrframe[t] = 0;
|
||||
|
||||
for (t = 0; t < (width * (width + 1) + 1) / 2; t++)
|
||||
framask[t] = 0;
|
||||
|
||||
// insert finders - black to frame, white to mask
|
||||
for (t = 0; t < 3; t++) {
|
||||
k = 0;
|
||||
y = 0;
|
||||
if (t == 1)
|
||||
k = (width - 7);
|
||||
if (t == 2)
|
||||
y = (width - 7);
|
||||
qrframe[(y + 3) + width * (k + 3)] = 1;
|
||||
for (x = 0; x < 6; x++) {
|
||||
qrframe[(y + x) + width * k] = 1;
|
||||
qrframe[y + width * (k + x + 1)] = 1;
|
||||
qrframe[(y + 6) + width * (k + x)] = 1;
|
||||
qrframe[(y + x + 1) + width * (k + 6)] = 1;
|
||||
}
|
||||
for (x = 1; x < 5; x++) {
|
||||
setmask(y + x, k + 1);
|
||||
setmask(y + 1, k + x + 1);
|
||||
setmask(y + 5, k + x);
|
||||
setmask(y + x + 1, k + 5);
|
||||
}
|
||||
for (x = 2; x < 4; x++) {
|
||||
qrframe[(y + x) + width * (k + 2)] = 1;
|
||||
qrframe[(y + 2) + width * (k + x + 1)] = 1;
|
||||
qrframe[(y + 4) + width * (k + x)] = 1;
|
||||
qrframe[(y + x + 1) + width * (k + 4)] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// alignment blocks
|
||||
if (version > 1) {
|
||||
t = adelta[version];
|
||||
y = width - 7;
|
||||
for (;;) {
|
||||
x = width - 7;
|
||||
while (x > t - 3) {
|
||||
putalign(x, y);
|
||||
if (x < t)
|
||||
break;
|
||||
x -= t;
|
||||
}
|
||||
if (y <= t + 9)
|
||||
break;
|
||||
y -= t;
|
||||
putalign(6, y);
|
||||
putalign(y, 6);
|
||||
}
|
||||
}
|
||||
|
||||
// single black
|
||||
qrframe[8 + width * (width - 8)] = 1;
|
||||
|
||||
// timing gap - mask only
|
||||
for (y = 0; y < 7; y++) {
|
||||
setmask(7, y);
|
||||
setmask(width - 8, y);
|
||||
setmask(7, y + width - 7);
|
||||
}
|
||||
for (x = 0; x < 8; x++) {
|
||||
setmask(x, 7);
|
||||
setmask(x + width - 8, 7);
|
||||
setmask(x, width - 8);
|
||||
}
|
||||
|
||||
// reserve mask-format area
|
||||
for (x = 0; x < 9; x++)
|
||||
setmask(x, 8);
|
||||
for (x = 0; x < 8; x++) {
|
||||
setmask(x + width - 8, 8);
|
||||
setmask(8, x);
|
||||
}
|
||||
for (y = 0; y < 7; y++)
|
||||
setmask(8, y + width - 7);
|
||||
|
||||
// timing row/col
|
||||
for (x = 0; x < width - 14; x++)
|
||||
if (x & 1) {
|
||||
setmask(8 + x, 6);
|
||||
setmask(6, 8 + x);
|
||||
}
|
||||
else {
|
||||
qrframe[(8 + x) + width * 6] = 1;
|
||||
qrframe[6 + width * (8 + x)] = 1;
|
||||
}
|
||||
|
||||
// version block
|
||||
if (version > 6) {
|
||||
t = vpat[version - 7];
|
||||
k = 17;
|
||||
for (x = 0; x < 6; x++)
|
||||
for (y = 0; y < 3; y++, k--)
|
||||
if (1 & (k > 11 ? version >> (k - 12) : t >> k)) {
|
||||
qrframe[(5 - x) + width * (2 - y + width - 11)] = 1;
|
||||
qrframe[(2 - y + width - 11) + width * (5 - x)] = 1;
|
||||
}
|
||||
else {
|
||||
setmask(5 - x, 2 - y + width - 11);
|
||||
setmask(2 - y + width - 11, 5 - x);
|
||||
}
|
||||
}
|
||||
|
||||
// sync mask bits - only set above for white spaces, so add in black bits
|
||||
for (y = 0; y < width; y++)
|
||||
for (x = 0; x <= y; x++)
|
||||
if (qrframe[x + width * y])
|
||||
setmask(x, y);
|
||||
|
||||
// convert string to bitstream
|
||||
// 8 bit data to QR-coded 8 bit data (numeric or alphanum, or kanji not supported)
|
||||
v = strinbuf.length;
|
||||
|
||||
// string to array
|
||||
for (i = 0; i < v; i++)
|
||||
eccbuf[i] = strinbuf.charCodeAt(i);
|
||||
strinbuf = eccbuf.slice(0);
|
||||
|
||||
// calculate max string length
|
||||
x = datablkw * (neccblk1 + neccblk2) + neccblk2;
|
||||
if (v >= x - 2) {
|
||||
v = x - 2;
|
||||
if (version > 9)
|
||||
v--;
|
||||
}
|
||||
|
||||
// shift and repack to insert length prefix
|
||||
i = v;
|
||||
if (version > 9) {
|
||||
strinbuf[i + 2] = 0;
|
||||
strinbuf[i + 3] = 0;
|
||||
while (i--) {
|
||||
t = strinbuf[i];
|
||||
strinbuf[i + 3] |= 255 & (t << 4);
|
||||
strinbuf[i + 2] = t >> 4;
|
||||
}
|
||||
strinbuf[2] |= 255 & (v << 4);
|
||||
strinbuf[1] = v >> 4;
|
||||
strinbuf[0] = 0x40 | (v >> 12);
|
||||
} else {
|
||||
strinbuf[i + 1] = 0;
|
||||
strinbuf[i + 2] = 0;
|
||||
while (i--) {
|
||||
t = strinbuf[i];
|
||||
strinbuf[i + 2] |= 255 & (t << 4);
|
||||
strinbuf[i + 1] = t >> 4;
|
||||
}
|
||||
strinbuf[1] |= 255 & (v << 4);
|
||||
strinbuf[0] = 0x40 | (v >> 4);
|
||||
}
|
||||
// fill to end with pad pattern
|
||||
i = v + 3 - (version < 10);
|
||||
while (i < x) {
|
||||
strinbuf[i++] = 0xec;
|
||||
// buffer has room if (i == x) break;
|
||||
strinbuf[i++] = 0x11;
|
||||
}
|
||||
|
||||
// calculate and append ECC
|
||||
|
||||
// calculate generator polynomial
|
||||
genpoly[0] = 1;
|
||||
for (i = 0; i < eccblkwid; i++) {
|
||||
genpoly[i + 1] = 1;
|
||||
for (j = i; j > 0; j--)
|
||||
genpoly[j] = genpoly[j] ?
|
||||
genpoly[j - 1] ^ gexp[modnn(glog[genpoly[j]] + i)] : genpoly[j - 1];
|
||||
genpoly[0] = gexp[modnn(glog[genpoly[0]] + i)];
|
||||
}
|
||||
for (i = 0; i <= eccblkwid; i++)
|
||||
genpoly[i] = glog[genpoly[i]]; // use logs for genpoly[] to save calc step
|
||||
|
||||
// append ecc to data buffer
|
||||
k = x;
|
||||
y = 0;
|
||||
for (i = 0; i < neccblk1; i++) {
|
||||
appendrs(y, datablkw, k, eccblkwid);
|
||||
y += datablkw;
|
||||
k += eccblkwid;
|
||||
}
|
||||
for (i = 0; i < neccblk2; i++) {
|
||||
appendrs(y, datablkw + 1, k, eccblkwid);
|
||||
y += datablkw + 1;
|
||||
k += eccblkwid;
|
||||
}
|
||||
// interleave blocks
|
||||
y = 0;
|
||||
for (i = 0; i < datablkw; i++) {
|
||||
for (j = 0; j < neccblk1; j++)
|
||||
eccbuf[y++] = strinbuf[i + j * datablkw];
|
||||
for (j = 0; j < neccblk2; j++)
|
||||
eccbuf[y++] = strinbuf[(neccblk1 * datablkw) + i + (j * (datablkw + 1))];
|
||||
}
|
||||
for (j = 0; j < neccblk2; j++)
|
||||
eccbuf[y++] = strinbuf[(neccblk1 * datablkw) + i + (j * (datablkw + 1))];
|
||||
for (i = 0; i < eccblkwid; i++)
|
||||
for (j = 0; j < neccblk1 + neccblk2; j++)
|
||||
eccbuf[y++] = strinbuf[x + i + j * eccblkwid];
|
||||
strinbuf = eccbuf;
|
||||
|
||||
// pack bits into frame avoiding masked area.
|
||||
x = y = width - 1;
|
||||
k = v = 1; // up, minus
|
||||
/* inteleaved data and ecc codes */
|
||||
m = (datablkw + eccblkwid) * (neccblk1 + neccblk2) + neccblk2;
|
||||
for (i = 0; i < m; i++) {
|
||||
t = strinbuf[i];
|
||||
for (j = 0; j < 8; j++, t <<= 1) {
|
||||
if (0x80 & t)
|
||||
qrframe[x + width * y] = 1;
|
||||
do { // find next fill position
|
||||
if (v)
|
||||
x--;
|
||||
else {
|
||||
x++;
|
||||
if (k) {
|
||||
if (y != 0)
|
||||
y--;
|
||||
else {
|
||||
x -= 2;
|
||||
k = !k;
|
||||
if (x == 6) {
|
||||
x--;
|
||||
y = 9;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (y != width - 1)
|
||||
y++;
|
||||
else {
|
||||
x -= 2;
|
||||
k = !k;
|
||||
if (x == 6) {
|
||||
x--;
|
||||
y -= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
v = !v;
|
||||
} while (ismasked(x, y));
|
||||
}
|
||||
}
|
||||
|
||||
// save pre-mask copy of frame
|
||||
strinbuf = qrframe.slice(0);
|
||||
t = 0; // best
|
||||
y = 30000; // demerit
|
||||
// for instead of while since in original arduino code
|
||||
// if an early mask was "good enough" it wouldn't try for a better one
|
||||
// since they get more complex and take longer.
|
||||
for (k = 0; k < 8; k++) {
|
||||
applymask(k); // returns black-white imbalance
|
||||
x = badcheck();
|
||||
if (x < y) { // current mask better than previous best?
|
||||
y = x;
|
||||
t = k;
|
||||
}
|
||||
if (t == 7)
|
||||
break; // don't increment i to a void redoing mask
|
||||
qrframe = strinbuf.slice(0); // reset for next pass
|
||||
}
|
||||
if (t != k) // redo best mask - none good enough, last wasn't t
|
||||
applymask(t);
|
||||
|
||||
// add in final mask/ecclevel bytes
|
||||
y = fmtword[t + ((ecclevel - 1) << 3)];
|
||||
// low byte
|
||||
for (k = 0; k < 8; k++, y >>= 1)
|
||||
if (y & 1) {
|
||||
qrframe[(width - 1 - k) + width * 8] = 1;
|
||||
if (k < 6)
|
||||
qrframe[8 + width * k] = 1;
|
||||
else
|
||||
qrframe[8 + width * (k + 1)] = 1;
|
||||
}
|
||||
// high byte
|
||||
for (k = 0; k < 7; k++, y >>= 1)
|
||||
if (y & 1) {
|
||||
qrframe[8 + width * (width - 7 + k)] = 1;
|
||||
if (k)
|
||||
qrframe[(6 - k) + width * 8] = 1;
|
||||
else
|
||||
qrframe[7 + width * 8] = 1;
|
||||
}
|
||||
return qrframe;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
var _canvas = null;
|
||||
|
||||
var api = {
|
||||
|
||||
get ecclevel() {
|
||||
return ecclevel;
|
||||
},
|
||||
|
||||
set ecclevel(val) {
|
||||
ecclevel = val;
|
||||
},
|
||||
|
||||
get size() {
|
||||
return _size;
|
||||
},
|
||||
|
||||
set size(val) {
|
||||
_size = val
|
||||
},
|
||||
|
||||
get canvas() {
|
||||
return _canvas;
|
||||
},
|
||||
|
||||
set canvas(el) {
|
||||
_canvas = el;
|
||||
},
|
||||
|
||||
getFrame: function(string) {
|
||||
return genframe(string);
|
||||
},
|
||||
//这里的utf16to8(str)是对Text中的字符串进行转码,让其支持中文
|
||||
utf16to8: function(str) {
|
||||
var out, i, len, c;
|
||||
|
||||
out = "";
|
||||
len = str.length;
|
||||
for (i = 0; i < len; i++) {
|
||||
c = str.charCodeAt(i);
|
||||
if ((c >= 0x0001) && (c <= 0x007F)) {
|
||||
out += str.charAt(i);
|
||||
} else if (c > 0x07FF) {
|
||||
out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F));
|
||||
out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F));
|
||||
out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
|
||||
} else {
|
||||
out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F));
|
||||
out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
|
||||
}
|
||||
}
|
||||
return out;
|
||||
},
|
||||
/**
|
||||
* 新增$this参数,传入组件的this,兼容在组件中生成
|
||||
*/
|
||||
draw: function(str, canvas, cavW, cavH, cavColor, haveImg, imageUrl, imageSize, $this, cb = function() {}, ecc) {
|
||||
var that = this;
|
||||
ecclevel = ecc || ecclevel;
|
||||
canvas = canvas || _canvas;
|
||||
if (!canvas) {
|
||||
console.warn('No canvas provided to draw QR code in!')
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
let pre_background = "#ffffff";
|
||||
var size = Math.min(cavW, cavH);
|
||||
str = that.utf16to8(str); //增加中文显示
|
||||
|
||||
var frame = that.getFrame(str);
|
||||
// 组件中生成qrcode需要绑定this
|
||||
var ctx = uni.createCanvasContext(canvas, $this);
|
||||
var px = Math.round(size / (width ));
|
||||
|
||||
var roundedSize = px * (width);
|
||||
// var px = 1 ;
|
||||
// var roundedSize = px * (width + 8) ;
|
||||
|
||||
//var roundedSize = 0 ;
|
||||
//var offset = Math.floor((size - roundedSize) / 2);
|
||||
var offset = 0 ;
|
||||
size = roundedSize;
|
||||
//ctx.clearRect(0, 0, cavW, cavW);
|
||||
ctx.setFillStyle(pre_background)
|
||||
ctx.fillRect(0, 0, cavW, cavW);
|
||||
ctx.setFillStyle(cavColor);
|
||||
for (var i = 0; i < width; i++) {
|
||||
for (var j = 0; j < width; j++) {
|
||||
if (frame[j * width + i]) {
|
||||
ctx.fillRect(px * ( i) + offset, px * ( j) + offset, px, px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//画图片
|
||||
if (haveImg) {
|
||||
try {
|
||||
var x = Number(((cavW - imageSize - 14) / 2).toFixed(2));
|
||||
var y = Number(((cavH - imageSize -14) / 2).toFixed(2));
|
||||
drawRoundedRect(ctx, x, y, imageSize, imageSize, imageSize / 2, 6, true, true)
|
||||
|
||||
let isNetImg = false;
|
||||
|
||||
isNetImg = imageUrl.substr(0, 4) == 'http' ? true : false;
|
||||
|
||||
if (isNetImg) {
|
||||
//网络图片下载到本地
|
||||
uni.getImageInfo({
|
||||
src: imageUrl,
|
||||
success: function(res) {
|
||||
ctx.drawImage(res.path, x, y, imageSize, imageSize);
|
||||
//--增加绘制完成回调
|
||||
ctx.draw(false, function() {
|
||||
cb();
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
ctx.drawImage(imageUrl, x, y, imageSize, imageSize);
|
||||
//--增加绘制完成回调
|
||||
ctx.draw(false, function() {
|
||||
cb();
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 画圆角矩形
|
||||
function drawRoundedRect(ctxi, x, y, width, height, r, lineWidth, fill, stroke) {
|
||||
ctxi.setLineWidth(lineWidth);
|
||||
ctxi.setFillStyle(pre_background);
|
||||
ctxi.setStrokeStyle(pre_background);
|
||||
ctxi.beginPath(); // draw top and top right corner
|
||||
ctxi.moveTo(x + r, y);
|
||||
ctxi.arcTo(x + width, y, x + width, y + r, r); // draw right side and bottom right corner
|
||||
ctxi.arcTo(x + width, y + height, x + width - r, y + height, r); // draw bottom and bottom left corner
|
||||
ctxi.arcTo(x, y + height, x, y + height - r, r); // draw left and top left corner
|
||||
ctxi.arcTo(x, y, x + r, y, r);
|
||||
ctxi.closePath();
|
||||
if (fill) {
|
||||
ctxi.fill();
|
||||
}
|
||||
if (stroke) {
|
||||
ctxi.stroke();
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
//TODO handle the exception
|
||||
}
|
||||
|
||||
} else {
|
||||
//--增加绘制完成回调
|
||||
ctx.draw(false, function() {
|
||||
cb();
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
module.exports = {
|
||||
api
|
||||
}
|
||||
})();
|
||||
|
|
@ -0,0 +1,424 @@
|
|||
//Core code comes from https://github.com/davidshimjs/qrcodejs
|
||||
|
||||
var QRCode;
|
||||
|
||||
(function () {
|
||||
/**
|
||||
* Get the type by string length
|
||||
*
|
||||
* @private
|
||||
* @param {String} sText
|
||||
* @param {Number} nCorrectLevel
|
||||
* @return {Number} type
|
||||
*/
|
||||
function _getTypeNumber(sText, nCorrectLevel) {
|
||||
var nType = 1;
|
||||
var length = _getUTF8Length(sText);
|
||||
|
||||
for (var i = 0, len = QRCodeLimitLength.length; i <= len; i++) {
|
||||
var nLimit = 0;
|
||||
|
||||
switch (nCorrectLevel) {
|
||||
case QRErrorCorrectLevel.L:
|
||||
nLimit = QRCodeLimitLength[i][0];
|
||||
break;
|
||||
case QRErrorCorrectLevel.M:
|
||||
nLimit = QRCodeLimitLength[i][1];
|
||||
break;
|
||||
case QRErrorCorrectLevel.Q:
|
||||
nLimit = QRCodeLimitLength[i][2];
|
||||
break;
|
||||
case QRErrorCorrectLevel.H:
|
||||
nLimit = QRCodeLimitLength[i][3];
|
||||
break;
|
||||
}
|
||||
|
||||
if (length <= nLimit) {
|
||||
break;
|
||||
} else {
|
||||
nType++;
|
||||
}
|
||||
}
|
||||
|
||||
if (nType > QRCodeLimitLength.length) {
|
||||
throw new Error("Too long data");
|
||||
}
|
||||
|
||||
return nType;
|
||||
}
|
||||
|
||||
function _getUTF8Length(sText) {
|
||||
var replacedText = encodeURI(sText).toString().replace(/\%[0-9a-fA-F]{2}/g, 'a');
|
||||
return replacedText.length + (replacedText.length != sText ? 3 : 0);
|
||||
}
|
||||
|
||||
function QR8bitByte(data) {
|
||||
this.mode = QRMode.MODE_8BIT_BYTE;
|
||||
this.data = data;
|
||||
this.parsedData = [];
|
||||
|
||||
// Added to support UTF-8 Characters
|
||||
for (var i = 0, l = this.data.length; i < l; i++) {
|
||||
var byteArray = [];
|
||||
var code = this.data.charCodeAt(i);
|
||||
|
||||
if (code > 0x10000) {
|
||||
byteArray[0] = 0xF0 | ((code & 0x1C0000) >>> 18);
|
||||
byteArray[1] = 0x80 | ((code & 0x3F000) >>> 12);
|
||||
byteArray[2] = 0x80 | ((code & 0xFC0) >>> 6);
|
||||
byteArray[3] = 0x80 | (code & 0x3F);
|
||||
} else if (code > 0x800) {
|
||||
byteArray[0] = 0xE0 | ((code & 0xF000) >>> 12);
|
||||
byteArray[1] = 0x80 | ((code & 0xFC0) >>> 6);
|
||||
byteArray[2] = 0x80 | (code & 0x3F);
|
||||
} else if (code > 0x80) {
|
||||
byteArray[0] = 0xC0 | ((code & 0x7C0) >>> 6);
|
||||
byteArray[1] = 0x80 | (code & 0x3F);
|
||||
} else {
|
||||
byteArray[0] = code;
|
||||
}
|
||||
|
||||
this.parsedData.push(byteArray);
|
||||
}
|
||||
|
||||
this.parsedData = Array.prototype.concat.apply([], this.parsedData);
|
||||
|
||||
if (this.parsedData.length != this.data.length) {
|
||||
this.parsedData.unshift(191);
|
||||
this.parsedData.unshift(187);
|
||||
this.parsedData.unshift(239);
|
||||
}
|
||||
}
|
||||
|
||||
QR8bitByte.prototype = {
|
||||
getLength: function (buffer) {
|
||||
return this.parsedData.length;
|
||||
},
|
||||
write: function (buffer) {
|
||||
for (var i = 0, l = this.parsedData.length; i < l; i++) {
|
||||
buffer.put(this.parsedData[i], 8);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// QRCodeModel
|
||||
function QRCodeModel(typeNumber, errorCorrectLevel) {
|
||||
this.typeNumber = typeNumber;
|
||||
this.errorCorrectLevel = errorCorrectLevel;
|
||||
this.modules = null;
|
||||
this.moduleCount = 0;
|
||||
this.dataCache = null;
|
||||
this.dataList = [];
|
||||
}
|
||||
QRCodeModel.prototype = {
|
||||
addData: function (data) { var newData = new QR8bitByte(data); this.dataList.push(newData); this.dataCache = null; }, isDark: function (row, col) {
|
||||
if (row < 0 || this.moduleCount <= row || col < 0 || this.moduleCount <= col) { throw new Error(row + "," + col); }
|
||||
return this.modules[row][col];
|
||||
}, getModuleCount: function () { return this.moduleCount; }, make: function () { this.makeImpl(false, this.getBestMaskPattern()); }, makeImpl: function (test, maskPattern) {
|
||||
this.moduleCount = this.typeNumber * 4 + 17; this.modules = new Array(this.moduleCount); for (var row = 0; row < this.moduleCount; row++) { this.modules[row] = new Array(this.moduleCount); for (var col = 0; col < this.moduleCount; col++) { this.modules[row][col] = null; } }
|
||||
this.setupPositionProbePattern(0, 0); this.setupPositionProbePattern(this.moduleCount - 7, 0); this.setupPositionProbePattern(0, this.moduleCount - 7); this.setupPositionAdjustPattern(); this.setupTimingPattern(); this.setupTypeInfo(test, maskPattern); if (this.typeNumber >= 7) { this.setupTypeNumber(test); }
|
||||
if (this.dataCache == null) { this.dataCache = QRCodeModel.createData(this.typeNumber, this.errorCorrectLevel, this.dataList); }
|
||||
this.mapData(this.dataCache, maskPattern);
|
||||
}, setupPositionProbePattern: function (row, col) { for (var r = -1; r <= 7; r++) { if (row + r <= -1 || this.moduleCount <= row + r) continue; for (var c = -1; c <= 7; c++) { if (col + c <= -1 || this.moduleCount <= col + c) continue; if ((0 <= r && r <= 6 && (c == 0 || c == 6)) || (0 <= c && c <= 6 && (r == 0 || r == 6)) || (2 <= r && r <= 4 && 2 <= c && c <= 4)) { this.modules[row + r][col + c] = true; } else { this.modules[row + r][col + c] = false; } } } }, getBestMaskPattern: function () {
|
||||
var minLostPoint = 0; var pattern = 0; for (var i = 0; i < 8; i++) { this.makeImpl(true, i); var lostPoint = QRUtil.getLostPoint(this); if (i == 0 || minLostPoint > lostPoint) { minLostPoint = lostPoint; pattern = i; } }
|
||||
return pattern;
|
||||
}, createMovieClip: function (target_mc, instance_name, depth) {
|
||||
var qr_mc = target_mc.createEmptyMovieClip(instance_name, depth); var cs = 1; this.make(); for (var row = 0; row < this.modules.length; row++) { var y = row * cs; for (var col = 0; col < this.modules[row].length; col++) { var x = col * cs; var dark = this.modules[row][col]; if (dark) { qr_mc.beginFill(0, 100); qr_mc.moveTo(x, y); qr_mc.lineTo(x + cs, y); qr_mc.lineTo(x + cs, y + cs); qr_mc.lineTo(x, y + cs); qr_mc.endFill(); } } }
|
||||
return qr_mc;
|
||||
}, setupTimingPattern: function () {
|
||||
for (var r = 8; r < this.moduleCount - 8; r++) {
|
||||
if (this.modules[r][6] != null) { continue; }
|
||||
this.modules[r][6] = (r % 2 == 0);
|
||||
}
|
||||
for (var c = 8; c < this.moduleCount - 8; c++) {
|
||||
if (this.modules[6][c] != null) { continue; }
|
||||
this.modules[6][c] = (c % 2 == 0);
|
||||
}
|
||||
}, setupPositionAdjustPattern: function () {
|
||||
var pos = QRUtil.getPatternPosition(this.typeNumber); for (var i = 0; i < pos.length; i++) {
|
||||
for (var j = 0; j < pos.length; j++) {
|
||||
var row = pos[i]; var col = pos[j]; if (this.modules[row][col] != null) { continue; }
|
||||
for (var r = -2; r <= 2; r++) { for (var c = -2; c <= 2; c++) { if (r == -2 || r == 2 || c == -2 || c == 2 || (r == 0 && c == 0)) { this.modules[row + r][col + c] = true; } else { this.modules[row + r][col + c] = false; } } }
|
||||
}
|
||||
}
|
||||
}, setupTypeNumber: function (test) {
|
||||
var bits = QRUtil.getBCHTypeNumber(this.typeNumber); for (var i = 0; i < 18; i++) { var mod = (!test && ((bits >> i) & 1) == 1); this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3] = mod; }
|
||||
for (var i = 0; i < 18; i++) { var mod = (!test && ((bits >> i) & 1) == 1); this.modules[i % 3 + this.moduleCount - 8 - 3][Math.floor(i / 3)] = mod; }
|
||||
}, setupTypeInfo: function (test, maskPattern) {
|
||||
var data = (this.errorCorrectLevel << 3) | maskPattern; var bits = QRUtil.getBCHTypeInfo(data); for (var i = 0; i < 15; i++) { var mod = (!test && ((bits >> i) & 1) == 1); if (i < 6) { this.modules[i][8] = mod; } else if (i < 8) { this.modules[i + 1][8] = mod; } else { this.modules[this.moduleCount - 15 + i][8] = mod; } }
|
||||
for (var i = 0; i < 15; i++) { var mod = (!test && ((bits >> i) & 1) == 1); if (i < 8) { this.modules[8][this.moduleCount - i - 1] = mod; } else if (i < 9) { this.modules[8][15 - i - 1 + 1] = mod; } else { this.modules[8][15 - i - 1] = mod; } }
|
||||
this.modules[this.moduleCount - 8][8] = (!test);
|
||||
}, mapData: function (data, maskPattern) {
|
||||
var inc = -1; var row = this.moduleCount - 1; var bitIndex = 7; var byteIndex = 0; for (var col = this.moduleCount - 1; col > 0; col -= 2) {
|
||||
if (col == 6) col--; while (true) {
|
||||
for (var c = 0; c < 2; c++) {
|
||||
if (this.modules[row][col - c] == null) {
|
||||
var dark = false; if (byteIndex < data.length) { dark = (((data[byteIndex] >>> bitIndex) & 1) == 1); }
|
||||
var mask = QRUtil.getMask(maskPattern, row, col - c); if (mask) { dark = !dark; }
|
||||
this.modules[row][col - c] = dark; bitIndex--; if (bitIndex == -1) { byteIndex++; bitIndex = 7; }
|
||||
}
|
||||
}
|
||||
row += inc; if (row < 0 || this.moduleCount <= row) { row -= inc; inc = -inc; break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
QRCodeModel.PAD0 = 0xEC;
|
||||
QRCodeModel.PAD1 = 0x11;
|
||||
QRCodeModel.createData = function (typeNumber, errorCorrectLevel, dataList) {
|
||||
var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel); var buffer = new QRBitBuffer(); for (var i = 0; i < dataList.length; i++) { var data = dataList[i]; buffer.put(data.mode, 4); buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber)); data.write(buffer); }
|
||||
var totalDataCount = 0; for (var i = 0; i < rsBlocks.length; i++) { totalDataCount += rsBlocks[i].dataCount; }
|
||||
if (buffer.getLengthInBits() > totalDataCount * 8) {
|
||||
throw new Error("code length overflow. ("
|
||||
+ buffer.getLengthInBits()
|
||||
+ ">"
|
||||
+ totalDataCount * 8
|
||||
+ ")");
|
||||
}
|
||||
if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) { buffer.put(0, 4); }
|
||||
while (buffer.getLengthInBits() % 8 != 0) { buffer.putBit(false); }
|
||||
while (true) {
|
||||
if (buffer.getLengthInBits() >= totalDataCount * 8) { break; }
|
||||
buffer.put(QRCodeModel.PAD0, 8); if (buffer.getLengthInBits() >= totalDataCount * 8) { break; }
|
||||
buffer.put(QRCodeModel.PAD1, 8);
|
||||
}
|
||||
return QRCodeModel.createBytes(buffer, rsBlocks);
|
||||
};
|
||||
QRCodeModel.createBytes = function (buffer, rsBlocks) {
|
||||
var offset = 0; var maxDcCount = 0; var maxEcCount = 0; var dcdata = new Array(rsBlocks.length); var ecdata = new Array(rsBlocks.length); for (var r = 0; r < rsBlocks.length; r++) {
|
||||
var dcCount = rsBlocks[r].dataCount; var ecCount = rsBlocks[r].totalCount - dcCount; maxDcCount = Math.max(maxDcCount, dcCount); maxEcCount = Math.max(maxEcCount, ecCount); dcdata[r] = new Array(dcCount); for (var i = 0; i < dcdata[r].length; i++) { dcdata[r][i] = 0xff & buffer.buffer[i + offset]; }
|
||||
offset += dcCount; var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount); var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1); var modPoly = rawPoly.mod(rsPoly); ecdata[r] = new Array(rsPoly.getLength() - 1); for (var i = 0; i < ecdata[r].length; i++) { var modIndex = i + modPoly.getLength() - ecdata[r].length; ecdata[r][i] = (modIndex >= 0) ? modPoly.get(modIndex) : 0; }
|
||||
}
|
||||
var totalCodeCount = 0; for (var i = 0; i < rsBlocks.length; i++) { totalCodeCount += rsBlocks[i].totalCount; }
|
||||
var data = new Array(totalCodeCount); var index = 0; for (var i = 0; i < maxDcCount; i++) { for (var r = 0; r < rsBlocks.length; r++) { if (i < dcdata[r].length) { data[index++] = dcdata[r][i]; } } }
|
||||
for (var i = 0; i < maxEcCount; i++) { for (var r = 0; r < rsBlocks.length; r++) { if (i < ecdata[r].length) { data[index++] = ecdata[r][i]; } } }
|
||||
return data;
|
||||
};
|
||||
var QRMode = { MODE_NUMBER: 1 << 0, MODE_ALPHA_NUM: 1 << 1, MODE_8BIT_BYTE: 1 << 2, MODE_KANJI: 1 << 3 };
|
||||
var QRErrorCorrectLevel = { L: 1, M: 0, Q: 3, H: 2 };
|
||||
var QRMaskPattern = { PATTERN000: 0, PATTERN001: 1, PATTERN010: 2, PATTERN011: 3, PATTERN100: 4, PATTERN101: 5, PATTERN110: 6, PATTERN111: 7 };
|
||||
var QRUtil = {
|
||||
PATTERN_POSITION_TABLE: [[], [6, 18], [6, 22], [6, 26], [6, 30], [6, 34], [6, 22, 38], [6, 24, 42], [6, 26, 46], [6, 28, 50], [6, 30, 54], [6, 32, 58], [6, 34, 62], [6, 26, 46, 66], [6, 26, 48, 70], [6, 26, 50, 74], [6, 30, 54, 78], [6, 30, 56, 82], [6, 30, 58, 86], [6, 34, 62, 90], [6, 28, 50, 72, 94], [6, 26, 50, 74, 98], [6, 30, 54, 78, 102], [6, 28, 54, 80, 106], [6, 32, 58, 84, 110], [6, 30, 58, 86, 114], [6, 34, 62, 90, 118], [6, 26, 50, 74, 98, 122], [6, 30, 54, 78, 102, 126], [6, 26, 52, 78, 104, 130], [6, 30, 56, 82, 108, 134], [6, 34, 60, 86, 112, 138], [6, 30, 58, 86, 114, 142], [6, 34, 62, 90, 118, 146], [6, 30, 54, 78, 102, 126, 150], [6, 24, 50, 76, 102, 128, 154], [6, 28, 54, 80, 106, 132, 158], [6, 32, 58, 84, 110, 136, 162], [6, 26, 54, 82, 110, 138, 166], [6, 30, 58, 86, 114, 142, 170]], G15: (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0), G18: (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0), G15_MASK: (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1), getBCHTypeInfo: function (data) {
|
||||
var d = data << 10; while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) { d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15))); }
|
||||
return ((data << 10) | d) ^ QRUtil.G15_MASK;
|
||||
}, getBCHTypeNumber: function (data) {
|
||||
var d = data << 12; while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) { d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18))); }
|
||||
return (data << 12) | d;
|
||||
}, getBCHDigit: function (data) {
|
||||
var digit = 0; while (data != 0) { digit++; data >>>= 1; }
|
||||
return digit;
|
||||
}, getPatternPosition: function (typeNumber) { return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1]; }, getMask: function (maskPattern, i, j) { switch (maskPattern) { case QRMaskPattern.PATTERN000: return (i + j) % 2 == 0; case QRMaskPattern.PATTERN001: return i % 2 == 0; case QRMaskPattern.PATTERN010: return j % 3 == 0; case QRMaskPattern.PATTERN011: return (i + j) % 3 == 0; case QRMaskPattern.PATTERN100: return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0; case QRMaskPattern.PATTERN101: return (i * j) % 2 + (i * j) % 3 == 0; case QRMaskPattern.PATTERN110: return ((i * j) % 2 + (i * j) % 3) % 2 == 0; case QRMaskPattern.PATTERN111: return ((i * j) % 3 + (i + j) % 2) % 2 == 0; default: throw new Error("bad maskPattern:" + maskPattern); } }, getErrorCorrectPolynomial: function (errorCorrectLength) {
|
||||
var a = new QRPolynomial([1], 0); for (var i = 0; i < errorCorrectLength; i++) { a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0)); }
|
||||
return a;
|
||||
}, getLengthInBits: function (mode, type) { if (1 <= type && type < 10) { switch (mode) { case QRMode.MODE_NUMBER: return 10; case QRMode.MODE_ALPHA_NUM: return 9; case QRMode.MODE_8BIT_BYTE: return 8; case QRMode.MODE_KANJI: return 8; default: throw new Error("mode:" + mode); } } else if (type < 27) { switch (mode) { case QRMode.MODE_NUMBER: return 12; case QRMode.MODE_ALPHA_NUM: return 11; case QRMode.MODE_8BIT_BYTE: return 16; case QRMode.MODE_KANJI: return 10; default: throw new Error("mode:" + mode); } } else if (type < 41) { switch (mode) { case QRMode.MODE_NUMBER: return 14; case QRMode.MODE_ALPHA_NUM: return 13; case QRMode.MODE_8BIT_BYTE: return 16; case QRMode.MODE_KANJI: return 12; default: throw new Error("mode:" + mode); } } else { throw new Error("type:" + type); } }, getLostPoint: function (qrCode) {
|
||||
var moduleCount = qrCode.getModuleCount(); var lostPoint = 0; for (var row = 0; row < moduleCount; row++) {
|
||||
for (var col = 0; col < moduleCount; col++) {
|
||||
var sameCount = 0; var dark = qrCode.isDark(row, col); for (var r = -1; r <= 1; r++) {
|
||||
if (row + r < 0 || moduleCount <= row + r) { continue; }
|
||||
for (var c = -1; c <= 1; c++) {
|
||||
if (col + c < 0 || moduleCount <= col + c) { continue; }
|
||||
if (r == 0 && c == 0) { continue; }
|
||||
if (dark == qrCode.isDark(row + r, col + c)) { sameCount++; }
|
||||
}
|
||||
}
|
||||
if (sameCount > 5) { lostPoint += (3 + sameCount - 5); }
|
||||
}
|
||||
}
|
||||
for (var row = 0; row < moduleCount - 1; row++) { for (var col = 0; col < moduleCount - 1; col++) { var count = 0; if (qrCode.isDark(row, col)) count++; if (qrCode.isDark(row + 1, col)) count++; if (qrCode.isDark(row, col + 1)) count++; if (qrCode.isDark(row + 1, col + 1)) count++; if (count == 0 || count == 4) { lostPoint += 3; } } }
|
||||
for (var row = 0; row < moduleCount; row++) { for (var col = 0; col < moduleCount - 6; col++) { if (qrCode.isDark(row, col) && !qrCode.isDark(row, col + 1) && qrCode.isDark(row, col + 2) && qrCode.isDark(row, col + 3) && qrCode.isDark(row, col + 4) && !qrCode.isDark(row, col + 5) && qrCode.isDark(row, col + 6)) { lostPoint += 40; } } }
|
||||
for (var col = 0; col < moduleCount; col++) { for (var row = 0; row < moduleCount - 6; row++) { if (qrCode.isDark(row, col) && !qrCode.isDark(row + 1, col) && qrCode.isDark(row + 2, col) && qrCode.isDark(row + 3, col) && qrCode.isDark(row + 4, col) && !qrCode.isDark(row + 5, col) && qrCode.isDark(row + 6, col)) { lostPoint += 40; } } }
|
||||
var darkCount = 0; for (var col = 0; col < moduleCount; col++) { for (var row = 0; row < moduleCount; row++) { if (qrCode.isDark(row, col)) { darkCount++; } } }
|
||||
var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5; lostPoint += ratio * 10; return lostPoint;
|
||||
}
|
||||
};
|
||||
var QRMath = {
|
||||
glog: function (n) {
|
||||
if (n < 1) { throw new Error("glog(" + n + ")"); }
|
||||
return QRMath.LOG_TABLE[n];
|
||||
}, gexp: function (n) {
|
||||
while (n < 0) { n += 255; }
|
||||
while (n >= 256) { n -= 255; }
|
||||
return QRMath.EXP_TABLE[n];
|
||||
}, EXP_TABLE: new Array(256), LOG_TABLE: new Array(256)
|
||||
}; for (var i = 0; i < 8; i++) { QRMath.EXP_TABLE[i] = 1 << i; }
|
||||
for (var i = 8; i < 256; i++) { QRMath.EXP_TABLE[i] = QRMath.EXP_TABLE[i - 4] ^ QRMath.EXP_TABLE[i - 5] ^ QRMath.EXP_TABLE[i - 6] ^ QRMath.EXP_TABLE[i - 8]; }
|
||||
for (var i = 0; i < 255; i++) { QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i; }
|
||||
function QRPolynomial(num, shift) {
|
||||
if (num.length == undefined) { throw new Error(num.length + "/" + shift); }
|
||||
var offset = 0; while (offset < num.length && num[offset] == 0) { offset++; }
|
||||
this.num = new Array(num.length - offset + shift); for (var i = 0; i < num.length - offset; i++) { this.num[i] = num[i + offset]; }
|
||||
}
|
||||
QRPolynomial.prototype = {
|
||||
get: function (index) { return this.num[index]; }, getLength: function () { return this.num.length; }, multiply: function (e) {
|
||||
var num = new Array(this.getLength() + e.getLength() - 1); for (var i = 0; i < this.getLength(); i++) { for (var j = 0; j < e.getLength(); j++) { num[i + j] ^= QRMath.gexp(QRMath.glog(this.get(i)) + QRMath.glog(e.get(j))); } }
|
||||
return new QRPolynomial(num, 0);
|
||||
}, mod: function (e) {
|
||||
if (this.getLength() - e.getLength() < 0) { return this; }
|
||||
var ratio = QRMath.glog(this.get(0)) - QRMath.glog(e.get(0)); var num = new Array(this.getLength()); for (var i = 0; i < this.getLength(); i++) { num[i] = this.get(i); }
|
||||
for (var i = 0; i < e.getLength(); i++) { num[i] ^= QRMath.gexp(QRMath.glog(e.get(i)) + ratio); }
|
||||
return new QRPolynomial(num, 0).mod(e);
|
||||
}
|
||||
};
|
||||
function QRRSBlock(totalCount, dataCount) { this.totalCount = totalCount; this.dataCount = dataCount; }
|
||||
QRRSBlock.RS_BLOCK_TABLE = [[1, 26, 19], [1, 26, 16], [1, 26, 13], [1, 26, 9], [1, 44, 34], [1, 44, 28], [1, 44, 22], [1, 44, 16], [1, 70, 55], [1, 70, 44], [2, 35, 17], [2, 35, 13], [1, 100, 80], [2, 50, 32], [2, 50, 24], [4, 25, 9], [1, 134, 108], [2, 67, 43], [2, 33, 15, 2, 34, 16], [2, 33, 11, 2, 34, 12], [2, 86, 68], [4, 43, 27], [4, 43, 19], [4, 43, 15], [2, 98, 78], [4, 49, 31], [2, 32, 14, 4, 33, 15], [4, 39, 13, 1, 40, 14], [2, 121, 97], [2, 60, 38, 2, 61, 39], [4, 40, 18, 2, 41, 19], [4, 40, 14, 2, 41, 15], [2, 146, 116], [3, 58, 36, 2, 59, 37], [4, 36, 16, 4, 37, 17], [4, 36, 12, 4, 37, 13], [2, 86, 68, 2, 87, 69], [4, 69, 43, 1, 70, 44], [6, 43, 19, 2, 44, 20], [6, 43, 15, 2, 44, 16], [4, 101, 81], [1, 80, 50, 4, 81, 51], [4, 50, 22, 4, 51, 23], [3, 36, 12, 8, 37, 13], [2, 116, 92, 2, 117, 93], [6, 58, 36, 2, 59, 37], [4, 46, 20, 6, 47, 21], [7, 42, 14, 4, 43, 15], [4, 133, 107], [8, 59, 37, 1, 60, 38], [8, 44, 20, 4, 45, 21], [12, 33, 11, 4, 34, 12], [3, 145, 115, 1, 146, 116], [4, 64, 40, 5, 65, 41], [11, 36, 16, 5, 37, 17], [11, 36, 12, 5, 37, 13], [5, 109, 87, 1, 110, 88], [5, 65, 41, 5, 66, 42], [5, 54, 24, 7, 55, 25], [11, 36, 12], [5, 122, 98, 1, 123, 99], [7, 73, 45, 3, 74, 46], [15, 43, 19, 2, 44, 20], [3, 45, 15, 13, 46, 16], [1, 135, 107, 5, 136, 108], [10, 74, 46, 1, 75, 47], [1, 50, 22, 15, 51, 23], [2, 42, 14, 17, 43, 15], [5, 150, 120, 1, 151, 121], [9, 69, 43, 4, 70, 44], [17, 50, 22, 1, 51, 23], [2, 42, 14, 19, 43, 15], [3, 141, 113, 4, 142, 114], [3, 70, 44, 11, 71, 45], [17, 47, 21, 4, 48, 22], [9, 39, 13, 16, 40, 14], [3, 135, 107, 5, 136, 108], [3, 67, 41, 13, 68, 42], [15, 54, 24, 5, 55, 25], [15, 43, 15, 10, 44, 16], [4, 144, 116, 4, 145, 117], [17, 68, 42], [17, 50, 22, 6, 51, 23], [19, 46, 16, 6, 47, 17], [2, 139, 111, 7, 140, 112], [17, 74, 46], [7, 54, 24, 16, 55, 25], [34, 37, 13], [4, 151, 121, 5, 152, 122], [4, 75, 47, 14, 76, 48], [11, 54, 24, 14, 55, 25], [16, 45, 15, 14, 46, 16], [6, 147, 117, 4, 148, 118], [6, 73, 45, 14, 74, 46], [11, 54, 24, 16, 55, 25], [30, 46, 16, 2, 47, 17], [8, 132, 106, 4, 133, 107], [8, 75, 47, 13, 76, 48], [7, 54, 24, 22, 55, 25], [22, 45, 15, 13, 46, 16], [10, 142, 114, 2, 143, 115], [19, 74, 46, 4, 75, 47], [28, 50, 22, 6, 51, 23], [33, 46, 16, 4, 47, 17], [8, 152, 122, 4, 153, 123], [22, 73, 45, 3, 74, 46], [8, 53, 23, 26, 54, 24], [12, 45, 15, 28, 46, 16], [3, 147, 117, 10, 148, 118], [3, 73, 45, 23, 74, 46], [4, 54, 24, 31, 55, 25], [11, 45, 15, 31, 46, 16], [7, 146, 116, 7, 147, 117], [21, 73, 45, 7, 74, 46], [1, 53, 23, 37, 54, 24], [19, 45, 15, 26, 46, 16], [5, 145, 115, 10, 146, 116], [19, 75, 47, 10, 76, 48], [15, 54, 24, 25, 55, 25], [23, 45, 15, 25, 46, 16], [13, 145, 115, 3, 146, 116], [2, 74, 46, 29, 75, 47], [42, 54, 24, 1, 55, 25], [23, 45, 15, 28, 46, 16], [17, 145, 115], [10, 74, 46, 23, 75, 47], [10, 54, 24, 35, 55, 25], [19, 45, 15, 35, 46, 16], [17, 145, 115, 1, 146, 116], [14, 74, 46, 21, 75, 47], [29, 54, 24, 19, 55, 25], [11, 45, 15, 46, 46, 16], [13, 145, 115, 6, 146, 116], [14, 74, 46, 23, 75, 47], [44, 54, 24, 7, 55, 25], [59, 46, 16, 1, 47, 17], [12, 151, 121, 7, 152, 122], [12, 75, 47, 26, 76, 48], [39, 54, 24, 14, 55, 25], [22, 45, 15, 41, 46, 16], [6, 151, 121, 14, 152, 122], [6, 75, 47, 34, 76, 48], [46, 54, 24, 10, 55, 25], [2, 45, 15, 64, 46, 16], [17, 152, 122, 4, 153, 123], [29, 74, 46, 14, 75, 47], [49, 54, 24, 10, 55, 25], [24, 45, 15, 46, 46, 16], [4, 152, 122, 18, 153, 123], [13, 74, 46, 32, 75, 47], [48, 54, 24, 14, 55, 25], [42, 45, 15, 32, 46, 16], [20, 147, 117, 4, 148, 118], [40, 75, 47, 7, 76, 48], [43, 54, 24, 22, 55, 25], [10, 45, 15, 67, 46, 16], [19, 148, 118, 6, 149, 119], [18, 75, 47, 31, 76, 48], [34, 54, 24, 34, 55, 25], [20, 45, 15, 61, 46, 16]];
|
||||
QRRSBlock.getRSBlocks = function (typeNumber, errorCorrectLevel) {
|
||||
var rsBlock = QRRSBlock.getRsBlockTable(typeNumber, errorCorrectLevel); if (rsBlock == undefined) { throw new Error("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectLevel:" + errorCorrectLevel); }
|
||||
var length = rsBlock.length / 3; var list = []; for (var i = 0; i < length; i++) { var count = rsBlock[i * 3 + 0]; var totalCount = rsBlock[i * 3 + 1]; var dataCount = rsBlock[i * 3 + 2]; for (var j = 0; j < count; j++) { list.push(new QRRSBlock(totalCount, dataCount)); } }
|
||||
return list;
|
||||
};
|
||||
QRRSBlock.getRsBlockTable = function (typeNumber, errorCorrectLevel) { switch (errorCorrectLevel) { case QRErrorCorrectLevel.L: return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0]; case QRErrorCorrectLevel.M: return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1]; case QRErrorCorrectLevel.Q: return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2]; case QRErrorCorrectLevel.H: return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3]; default: return undefined; } };
|
||||
function QRBitBuffer() { this.buffer = []; this.length = 0; }
|
||||
QRBitBuffer.prototype = {
|
||||
get: function (index) { var bufIndex = Math.floor(index / 8); return ((this.buffer[bufIndex] >>> (7 - index % 8)) & 1) == 1; }, put: function (num, length) { for (var i = 0; i < length; i++) { this.putBit(((num >>> (length - i - 1)) & 1) == 1); } }, getLengthInBits: function () { return this.length; }, putBit: function (bit) {
|
||||
var bufIndex = Math.floor(this.length / 8); if (this.buffer.length <= bufIndex) { this.buffer.push(0); }
|
||||
if (bit) { this.buffer[bufIndex] |= (0x80 >>> (this.length % 8)); }
|
||||
this.length++;
|
||||
}
|
||||
};
|
||||
var QRCodeLimitLength = [[17, 14, 11, 7], [32, 26, 20, 14], [53, 42, 32, 24], [78, 62, 46, 34], [106, 84, 60, 44], [134, 106, 74, 58], [154, 122, 86, 64], [192, 152, 108, 84], [230, 180, 130, 98], [271, 213, 151, 119], [321, 251, 177, 137], [367, 287, 203, 155], [425, 331, 241, 177], [458, 362, 258, 194], [520, 412, 292, 220], [586, 450, 322, 250], [644, 504, 364, 280], [718, 560, 394, 310], [792, 624, 442, 338], [858, 666, 482, 382], [929, 711, 509, 403], [1003, 779, 565, 439], [1091, 857, 611, 461], [1171, 911, 661, 511], [1273, 997, 715, 535], [1367, 1059, 751, 593], [1465, 1125, 805, 625], [1528, 1190, 868, 658], [1628, 1264, 908, 698], [1732, 1370, 982, 742], [1840, 1452, 1030, 790], [1952, 1538, 1112, 842], [2068, 1628, 1168, 898], [2188, 1722, 1228, 958], [2303, 1809, 1283, 983], [2431, 1911, 1351, 1051], [2563, 1989, 1423, 1093], [2699, 2099, 1499, 1139], [2809, 2213, 1579, 1219], [2953, 2331, 1663, 1273]];
|
||||
|
||||
// QRCode object
|
||||
QRCode = function (canvasId, vOption) {
|
||||
this._htOption = {
|
||||
width: 256,
|
||||
height: 256,
|
||||
typeNumber: 4,
|
||||
colorDark: "#000000",
|
||||
colorLight: "#ffffff",
|
||||
correctLevel: QRErrorCorrectLevel.H
|
||||
};
|
||||
|
||||
if (typeof vOption === 'string') {
|
||||
vOption = {
|
||||
text: vOption
|
||||
};
|
||||
}
|
||||
|
||||
// Overwrites options
|
||||
if (vOption) {
|
||||
for (var i in vOption) {
|
||||
this._htOption[i] = vOption[i];
|
||||
}
|
||||
}
|
||||
|
||||
this._oQRCode = null;
|
||||
this.canvasId = canvasId
|
||||
|
||||
if (this._htOption.text && this.canvasId) {
|
||||
this.makeCode(this._htOption.text);
|
||||
}
|
||||
};
|
||||
|
||||
QRCode.prototype.makeCode = function (sText) {
|
||||
this._oQRCode = new QRCodeModel(_getTypeNumber(sText, this._htOption.correctLevel), this._htOption.correctLevel);
|
||||
this._oQRCode.addData(sText);
|
||||
this._oQRCode.make();
|
||||
this.makeImage();
|
||||
};
|
||||
|
||||
QRCode.prototype.makeImage = function () {
|
||||
var _oContext
|
||||
if (this._htOption.usingIn) {
|
||||
_oContext = wx.createCanvasContext(this.canvasId, this._htOption.usingIn)
|
||||
}
|
||||
else {
|
||||
_oContext = wx.createCanvasContext(this.canvasId)
|
||||
}
|
||||
var _htOption = this._htOption;
|
||||
var oQRCode = this._oQRCode
|
||||
|
||||
var nCount = oQRCode.getModuleCount();
|
||||
var nWidth = _htOption.width / nCount;
|
||||
var nHeight = _htOption.height / nCount;
|
||||
var nRoundedWidth = Math.round(nWidth);
|
||||
var nRoundedHeight = Math.round(nHeight);
|
||||
|
||||
if (_htOption.image && _htOption.image != '') {
|
||||
_oContext.drawImage(_htOption.image, 0, 0, _htOption.width, _htOption.height)
|
||||
}
|
||||
|
||||
for (var row = 0; row < nCount; row++) {
|
||||
for (var col = 0; col < nCount; col++) {
|
||||
var bIsDark = oQRCode.isDark(row, col);
|
||||
var nLeft = col * nWidth;
|
||||
var nTop = row * nHeight;
|
||||
_oContext.setStrokeStyle(bIsDark ? _htOption.colorDark : _htOption.colorLight)
|
||||
// _oContext.setStrokeStyle('yellow')
|
||||
_oContext.setLineWidth(1)
|
||||
_oContext.setFillStyle(bIsDark ? _htOption.colorDark : _htOption.colorLight)
|
||||
// _oContext.setFillStyle('red')
|
||||
// if (bIsDark) {
|
||||
_oContext.fillRect(nLeft, nTop, nWidth, nHeight);
|
||||
// }
|
||||
|
||||
// 안티 앨리어싱 방지 처리
|
||||
// if (bIsDark) {
|
||||
_oContext.strokeRect(
|
||||
Math.floor(nLeft) + 0.5,
|
||||
Math.floor(nTop) + 0.5,
|
||||
nRoundedWidth,
|
||||
nRoundedHeight
|
||||
);
|
||||
|
||||
_oContext.strokeRect(
|
||||
Math.ceil(nLeft) - 0.5,
|
||||
Math.ceil(nTop) - 0.5,
|
||||
nRoundedWidth,
|
||||
nRoundedHeight
|
||||
);
|
||||
// }
|
||||
// _oContext.fillRect(
|
||||
// Math.floor(nLeft) + 0.5,
|
||||
// Math.floor(nTop) + 0.5,
|
||||
// nRoundedWidth,
|
||||
// nRoundedHeight
|
||||
// );
|
||||
// _oContext.fillRect(
|
||||
// Math.ceil(nLeft) - 0.5,
|
||||
// Math.ceil(nTop) - 0.5,
|
||||
// nRoundedWidth,
|
||||
// nRoundedHeight
|
||||
// );
|
||||
// _oContext.clearRect(
|
||||
// Math.floor(nLeft) + 0.5,
|
||||
// Math.floor(nTop) + 0.5,
|
||||
// nRoundedWidth,
|
||||
// nRoundedHeight
|
||||
// );
|
||||
// _oContext.clearRect(
|
||||
// Math.ceil(nLeft) - 0.5,
|
||||
// Math.ceil(nTop) - 0.5,
|
||||
// nRoundedWidth,
|
||||
// nRoundedHeight
|
||||
// );
|
||||
}
|
||||
}
|
||||
|
||||
_oContext.draw()
|
||||
};
|
||||
|
||||
// 保存为图片,将临时路径传给回调
|
||||
QRCode.prototype.exportImage = function (callback) {
|
||||
if (!callback) {
|
||||
return
|
||||
}
|
||||
wx.canvasToTempFilePath({
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: this._htOption.width,
|
||||
height: this._htOption.height,
|
||||
destWidth: this._htOption.width,
|
||||
destHeight: this._htOption.height,
|
||||
canvasId: this.canvasId,
|
||||
success: function (res) {
|
||||
console.log(res.tempFilePath)
|
||||
callback(res.tempFilePath)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
QRCode.CorrectLevel = QRErrorCorrectLevel;
|
||||
})();
|
||||
|
||||
module.exports = QRCode
|
||||
|
|
@ -1,20 +1,40 @@
|
|||
<template>
|
||||
<view class="product-item flex justify-start">
|
||||
<view class="cu-avatar xl-view" :style="'background-image:url(' + vCard.picUrl + ');'">
|
||||
</view>
|
||||
<view class="margin-left-sm product-content">
|
||||
<view>
|
||||
<view class="text-black text-xl">{{vCard.name}}</view>
|
||||
<view>
|
||||
<view class="flex justify-start">
|
||||
<view class="cu-avatar" :class="avatarPubClass" :style="'background-image:url(' + vCard.picUrl + '); width: ' + avatarWidth + '; height: ' + avatarHeight + ';'">
|
||||
</view>
|
||||
<view class="margin-left-sm product-content">
|
||||
<view>
|
||||
<text v-if="vCard.comments.icon" :class="'cuIcon-' + vCard.comments.icon" class="margin-right-xs text-main-color"></text>
|
||||
<text>{{vCard.comments.desc}}</text>
|
||||
<view class="text-black text-xl">{{vCard.name}}</view>
|
||||
<view>
|
||||
<text v-if="vCard.comments.icon" :class="'cuIcon-' + vCard.comments.icon"
|
||||
class="margin-right-xs text-main-color"></text>
|
||||
<text>{{vCard.comments.desc}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-for="(item, index) in vCard.extraInfos">
|
||||
<view class="text-sm">
|
||||
<text v-if="item.icon" :class="'cuIcon-' + item.icon"
|
||||
class="margin-right-xs text-main-color"></text>
|
||||
<text v-if="item.name" class="margin-right-xs">{{item.name}}:</text>
|
||||
<text>{{item.desc}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-for="(item, index) in vCard.extraInfos">
|
||||
<view class="text-sm">
|
||||
<text v-if="item.icon" :class="'cuIcon-' + item.icon" class="margin-right-xs text-main-color"></text>
|
||||
<text>{{item.desc}}</text>
|
||||
</view>
|
||||
<view class="text-sm padding-top" v-if="vCard.rateInfo">
|
||||
<view class="flex justify-between">
|
||||
<text>{{vCard.rateInfo.rateTitle}}<text class="text-red text-xl margin-left-xs">{{vCard.rateInfo.totalScore}}</text> /{{vCard.rateInfo.maxRate}}分</text>
|
||||
<uni-rate :readonly="true" allow-half :value="vCard.rateInfo.totalScore" />
|
||||
</view>
|
||||
<view class="flex justify-between">
|
||||
<view>
|
||||
<text v-if="vCard.rateInfo.ratePoint" v-for="(ratePoint, index) in vCard.rateInfo.ratePoint">
|
||||
<text>{{ratePoint.name}}</text><text class="margin-lr-xs">{{ratePoint.score}}</text>
|
||||
</text>
|
||||
</view>
|
||||
<view class="text-sm" v-if="vCard.rateInfo.commentNum">评价({{vCard.rateInfo.commentNum}})<text
|
||||
class="text-bold text-gray cuIcon-right"></text></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
|
@ -27,6 +47,18 @@
|
|||
vCard: {
|
||||
type: Object,
|
||||
default: {}
|
||||
},
|
||||
avatarWidth: {
|
||||
type: String,
|
||||
default: '150rpx'
|
||||
},
|
||||
avatarHeight: {
|
||||
type: String,
|
||||
default: '150rpx'
|
||||
},
|
||||
avatarPubClass: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
|
@ -38,11 +70,6 @@
|
|||
</script>
|
||||
|
||||
<style scoped>
|
||||
.xl-view {
|
||||
min-width: 150rpx;
|
||||
min-height: 150rpx;
|
||||
}
|
||||
|
||||
.product-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
|
|||
|
|
@ -1,18 +1,21 @@
|
|||
<template>
|
||||
<!-- 底部fixed操作条,包含发布选项,普通文字加icon加标签选项 -->
|
||||
<view class="cu-bar tabbar margin-bottom-xl bg-white fixed-bottom-bar">
|
||||
<view class="action text-gray add-action" v-for="(item, index) in moduleBarInfos" :key="index"
|
||||
v-if="item.action === 'add'">
|
||||
<button class="cu-btn bg-main-color shadow" :class="'cuIcon-' + item.cuIcon"></button>
|
||||
<view class="action add-action"
|
||||
v-for="(item, index) in moduleBarInfos" :key="index"
|
||||
v-if="item.action === 'add'"
|
||||
:data-cur="item.pageCode"
|
||||
:class="[curPageCode===item.pageCode ? 'text-main-color' : 'text-gray']"
|
||||
@click="navChange($event, false)">
|
||||
<button class="cu-btn shadow bg-main-color"
|
||||
:class="['cuIcon-' + item.cuIcon]">
|
||||
</button>
|
||||
{{item.name}}
|
||||
</view>
|
||||
<view class="action text-main-color" v-else-if="index === 0">
|
||||
<view :class="'cuIcon-' + item.cuIcon">
|
||||
<view class="cu-tag badge" v-if="item.countTag">{{item.countTag > 99 ? '99+' : item.countTag}}</view>
|
||||
</view>
|
||||
{{item.name}}
|
||||
</view>
|
||||
<view class="action text-gray" v-else-if="index > 0">
|
||||
<view class="action" v-else
|
||||
:data-cur="item.pageCode"
|
||||
:class="curPageCode===item.pageCode ? 'text-main-color' : 'text-gray'"
|
||||
@click="navChange($event, true)">
|
||||
<view :class="'cuIcon-' + item.cuIcon">
|
||||
<view class="cu-tag badge" v-if="item.countTag">{{item.countTag > 99 ? '99+' : item.countTag}}</view>
|
||||
</view>
|
||||
|
|
@ -31,10 +34,24 @@
|
|||
}
|
||||
},
|
||||
data() {
|
||||
return {};
|
||||
return {
|
||||
curPageCode: ''
|
||||
};
|
||||
},
|
||||
onReady() {
|
||||
this.loadData();
|
||||
},
|
||||
methods: {
|
||||
|
||||
loadData() {
|
||||
this.curPageCode = this.moduleBarInfos[0].pageCode;
|
||||
},
|
||||
navChange(e, isChangeFocus) {
|
||||
let cur = e.currentTarget.dataset.cur;
|
||||
this.curPageCode = isChangeFocus ? cur : this.curPageCode;
|
||||
uni.$emit('getCurPageInfo', {
|
||||
curPageCode: cur
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<view class="cu-item shadow">
|
||||
<view class="cu-list menu-avatar no-border">
|
||||
<view class="cu-item">
|
||||
<view class="cu-avatar" :style="'background-image:url(' + reviewer.avatarUrl + ');'">
|
||||
<view class="cu-avatar round" :style="'background-image:url(' + reviewer.avatarUrl + ');'">
|
||||
</view>
|
||||
<view class="content flex-sub">
|
||||
<view>{{reviewer.name}}</view>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,21 @@
|
|||
<template>
|
||||
<view class="product-item flex justify-start">
|
||||
<view class="flex justify-start">
|
||||
<view class="cu-avatar xxl-view" :style="'background-image:url(' + product.picUrl + ');'">
|
||||
</view>
|
||||
<view class="margin-left-sm product-content">
|
||||
<view>
|
||||
<view class="text-black">{{product.name}}</view>
|
||||
<view class="text-sm">{{product.comments}}</view>
|
||||
<view class="text-sm" v-if="ifShowComments">{{product.comments}}</view>
|
||||
</view>
|
||||
<view class="flex justify-between align-center">
|
||||
<view class="flex justify-start align-center">
|
||||
<text class="text-price text-red text-bold text-xl">{{product.salePrice}}</text>
|
||||
<text class="text-del">¥{{product.price}}</text>
|
||||
</view>
|
||||
<view class="padding-xs">
|
||||
<view class='cu-tag light bg-blue'>{{product.type}}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="text-price text-red text-bold text-xl" v-if="ifShowPrice">{{product.salePrice}}</view>
|
||||
<view v-if="ifShowServArea">
|
||||
<view class="cu-capsule">
|
||||
<view class='cu-tag bg-main-color sm'>
|
||||
|
|
@ -17,7 +25,7 @@
|
|||
服务区域
|
||||
</view>
|
||||
</view>
|
||||
<text class="margin-lr-xs text-xs" v-if="ifShowServArea">{{product.servArea}}</text>
|
||||
<text class="margin-lr-xs text-sm" v-if="ifShowServArea">{{product.servArea}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
|
@ -31,7 +39,7 @@
|
|||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
ifShowPrice: {
|
||||
ifShowComments: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
|
|
@ -58,6 +66,7 @@
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cu-list.menu-avatar>.cu-item .content .cu-tag.sm {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,74 @@
|
|||
<template>
|
||||
<view>
|
||||
<view class="bg-white padding-bottom">
|
||||
<horizontal-goods-card v-if="product" :ifShowServArea="true" :product="product"></horizontal-goods-card>
|
||||
<view v-if="columnTitleArr.length" class="flex justify-between margin-tb-sm">
|
||||
<view class="basis-df">{{columnTitleArr[0]}}</view>
|
||||
<view class="flex justify-end text-center basis-sm">
|
||||
<view v-for="(title, index) in columnTitleArr" v-if="index >= 1" class="basis-df">{{title}}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="certern-height-with-scroll">
|
||||
<view class="flex justify-between margin-tb-xs align-center" v-for="(item,index) in pickedList" :key="item.id">
|
||||
<view class='cu-tag padding line-main-color basis-df'>{{item.name}}</view>
|
||||
<view v-if="numberBox" class="flex justify-end basis-xs">
|
||||
<uni-number-box :min="0" :max="item.maxPieces" :value="item.pickedNum"
|
||||
@change="changePiecesNum($event, item)">
|
||||
</uni-number-box>
|
||||
</view>
|
||||
<view v-else class="flex justify-end basis-sm text-center">
|
||||
<view class="basis-df"><text v-if="!showToServNum">×</text>{{item.pickedNum}}</view>
|
||||
<view class="basis-df" v-if="showToServNum">
|
||||
{{item.toServNum == undefined || item.toServNum == null ? item.secondColumnNum : item.toServNum}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import horizontalGoodsCard from '@/components/goods-card/horizontal-goods-card.vue';
|
||||
|
||||
export default {
|
||||
name: "product-picked",
|
||||
props: {
|
||||
product: {
|
||||
type: Object,
|
||||
default: null
|
||||
},
|
||||
pickedList: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
columnTitleArr: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
showToServNum: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
numberBox: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
components: {
|
||||
horizontalGoodsCard
|
||||
},
|
||||
methods: {
|
||||
changePiecesNum(curNum, curItem) {
|
||||
uni.$emit('changePickedNum', curNum, curItem)
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.certern-height-with-scroll {
|
||||
max-height: 300rpx;
|
||||
overflow: scroll;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
<template>
|
||||
<view>
|
||||
<!-- 模态框 -->
|
||||
<view class="cu-modal" :class="isShow?'show':''">
|
||||
<view class="cu-dialog">
|
||||
<view class="padding-xl">
|
||||
{{content}}
|
||||
</view>
|
||||
<view class="cu-bar bg-white">
|
||||
<view class="action margin-0 flex-sub text-black" @tap="hideModal">{{cancelMsg}}</view>
|
||||
<view class="action margin-0 flex-sub text-main-color solid-left" @tap="hideModal"
|
||||
@click="confirmCallback">{{confirmMsg}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'confirm-modal',
|
||||
props: {
|
||||
content: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
cancelMsg: {
|
||||
type: String,
|
||||
default: '取消'
|
||||
},
|
||||
confirmMsg: {
|
||||
type: String,
|
||||
default: '确定'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isShow: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
showModal(e) {
|
||||
this.isShow = true
|
||||
},
|
||||
hideModal(e) {
|
||||
this.isShow = false
|
||||
},
|
||||
confirmCallback(e) {
|
||||
uni.$emit(this.$globalFun.CONFIRM);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
503
data.js
503
data.js
|
|
@ -1,503 +0,0 @@
|
|||
/**
|
||||
* 页面静态数据
|
||||
*/
|
||||
|
||||
const swiperList = [{
|
||||
id: 0,
|
||||
type: 'image',
|
||||
url: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big17000.jpg'
|
||||
}, {
|
||||
id: 1,
|
||||
type: 'image',
|
||||
url: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big37006.jpg',
|
||||
}, {
|
||||
id: 2,
|
||||
type: 'image',
|
||||
url: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big39000.jpg'
|
||||
}, {
|
||||
id: 3,
|
||||
type: 'image',
|
||||
url: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big10001.jpg'
|
||||
}, {
|
||||
id: 4,
|
||||
type: 'image',
|
||||
url: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big25011.jpg'
|
||||
}, {
|
||||
id: 5,
|
||||
type: 'image',
|
||||
url: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big21016.jpg'
|
||||
}, {
|
||||
id: 6,
|
||||
type: 'image',
|
||||
url: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big99008.jpg'
|
||||
}]
|
||||
|
||||
const categories = [{
|
||||
id: 1,
|
||||
name: '服务商城'
|
||||
}, {
|
||||
id: 2,
|
||||
name: '二手城'
|
||||
}, {
|
||||
id: 3,
|
||||
name: '供货商城'
|
||||
}]
|
||||
|
||||
const subCategories = [{
|
||||
id: 1,
|
||||
cuIcon: 'shopfill',
|
||||
color: 'red',
|
||||
name: '空调清洗',
|
||||
badge: '69洗'
|
||||
}, {
|
||||
id: 2,
|
||||
cuIcon: 'shopfill',
|
||||
color: 'orange',
|
||||
name: '家庭维修',
|
||||
badge: '新品'
|
||||
}, {
|
||||
id: 3,
|
||||
cuIcon: 'shopfill',
|
||||
color: 'yellow',
|
||||
name: 'iPhone维修',
|
||||
badge: ''
|
||||
}, {
|
||||
id: 4,
|
||||
cuIcon: 'shopfill',
|
||||
color: 'olive',
|
||||
name: '家居安装',
|
||||
badge: ''
|
||||
}, {
|
||||
id: 5,
|
||||
cuIcon: 'shopfill',
|
||||
color: 'green',
|
||||
name: '甲醛治理',
|
||||
badge: ''
|
||||
}, {
|
||||
id: 6,
|
||||
cuIcon: 'shopfill',
|
||||
color: 'cyan',
|
||||
name: '任洗套装',
|
||||
badge: ''
|
||||
}, {
|
||||
id: 7,
|
||||
cuIcon: 'shopfill',
|
||||
color: 'blue',
|
||||
name: '家电安装',
|
||||
badge: ''
|
||||
}, {
|
||||
id: 8,
|
||||
cuIcon: 'shopfill',
|
||||
color: 'purple',
|
||||
name: '领券中心',
|
||||
badge: ''
|
||||
}, {
|
||||
id: 9,
|
||||
cuIcon: 'shopfill',
|
||||
color: 'mauve',
|
||||
name: 'DIY装机',
|
||||
badge: ''
|
||||
}, {
|
||||
id: 10,
|
||||
cuIcon: 'shopfill',
|
||||
color: 'pink',
|
||||
name: '家电回收',
|
||||
badge: ''
|
||||
}, {
|
||||
id: 11,
|
||||
cuIcon: 'shopfill',
|
||||
color: 'cyan',
|
||||
name: '家电清洗',
|
||||
badge: ''
|
||||
}, {
|
||||
id: 12,
|
||||
cuIcon: 'deliver',
|
||||
color: 'green',
|
||||
name: '手机维修',
|
||||
badge: ''
|
||||
}, {
|
||||
id: 13,
|
||||
cuIcon: 'deliver',
|
||||
color: 'pink',
|
||||
name: '洗衣洗鞋',
|
||||
badge: ''
|
||||
}, {
|
||||
id: 14,
|
||||
cuIcon: 'deliver',
|
||||
color: 'pink',
|
||||
name: '上门安装',
|
||||
badge: ''
|
||||
}, {
|
||||
id: 15,
|
||||
cuIcon: 'deliver',
|
||||
color: 'pink',
|
||||
name: '奢品养护',
|
||||
badge: ''
|
||||
}]
|
||||
|
||||
const moduleBarInfos = [{
|
||||
id: 1,
|
||||
cuIcon: 'homefill',
|
||||
name: '首页'
|
||||
}, {
|
||||
id: 2,
|
||||
cuIcon: 'circle',
|
||||
name: '师傅圈'
|
||||
}, {
|
||||
id: 3,
|
||||
cuIcon: 'add',
|
||||
name: '发布',
|
||||
action: 'add'
|
||||
}, {
|
||||
id: 4,
|
||||
cuIcon: 'message',
|
||||
name: '消息',
|
||||
countTag: 100
|
||||
}, {
|
||||
id: 5,
|
||||
cuIcon: 'my',
|
||||
name: '我的'
|
||||
}]
|
||||
|
||||
const discountGoods = {
|
||||
title: '超值服务品牌直降',
|
||||
goodsInfos: [{
|
||||
id: 1,
|
||||
imgUrl: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big10006.jpg',
|
||||
name: '十平米擦玻璃服务',
|
||||
desc: '10平米起擦玻璃服务,超过10平米按照15/平米现场另收费',
|
||||
tag: ['自营直选', '未服务随时可退', '不满意重新服务', '全程上险'],
|
||||
price: '189起'
|
||||
}, {
|
||||
id: 2,
|
||||
imgUrl: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big1010.jpg',
|
||||
name: '十平米擦玻璃服务',
|
||||
desc: '10平米起擦玻璃服务,超过10平米按照15/平米现场另收费',
|
||||
tag: ['自营直选', '未服务随时可退', '不满意重新服务', '全程上险'],
|
||||
price: '200起'
|
||||
}]
|
||||
}
|
||||
|
||||
const hotGoods = {
|
||||
title: '大家都在买',
|
||||
goodsInfos: [{
|
||||
id: 1,
|
||||
imgUrl: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big10000.jpg',
|
||||
name: '十五平米擦玻璃服务',
|
||||
desc: '15平米起擦玻璃服务,超过15平米按照15/平米现场另收费,11111111111111111',
|
||||
tag: ['自营直选', '不满意重新服务', '全程上险'],
|
||||
price: '283起'
|
||||
}]
|
||||
}
|
||||
|
||||
const productDetail = {
|
||||
productDetailImgUrl: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big37006.jpg',
|
||||
swiperList: [{
|
||||
id: 0,
|
||||
type: 'video',
|
||||
// url: 'https://v.quanjing.com/movie/default/bottom/1.mp4'
|
||||
url: 'https://img.cdn.aliyun.dcloud.net.cn/guide/uniapp/%E7%AC%AC1%E8%AE%B2%EF%BC%88uni-app%E4%BA%A7%E5%93%81%E4%BB%8B%E7%BB%8D%EF%BC%89-%20DCloud%E5%AE%98%E6%96%B9%E8%A7%86%E9%A2%91%E6%95%99%E7%A8%8B@20200317.mp4'
|
||||
}, {
|
||||
id: 1,
|
||||
type: 'image',
|
||||
url: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big37006.jpg',
|
||||
}, {
|
||||
id: 2,
|
||||
type: 'image',
|
||||
url: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big1000.jpg'
|
||||
}, {
|
||||
id: 3,
|
||||
type: 'image',
|
||||
url: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big2001.jpg'
|
||||
}, {
|
||||
id: 4,
|
||||
type: 'image',
|
||||
url: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big2002.jpg'
|
||||
}, {
|
||||
id: 5,
|
||||
type: 'image',
|
||||
url: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big1002.jpg'
|
||||
}, {
|
||||
id: 6,
|
||||
type: 'image',
|
||||
url: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big3002.jpg'
|
||||
}],
|
||||
productInfo: {
|
||||
name: '十五平米擦玻璃服务',
|
||||
desc: '15平米起擦玻璃服务,超过15平米按照15/平米现场另收费',
|
||||
isGoldServ: true
|
||||
},
|
||||
guaranteeList: [{
|
||||
id: 1,
|
||||
name: '服务保障',
|
||||
desc: '服务保障描述......',
|
||||
icon: 'repairfill'
|
||||
}, {
|
||||
id: 2,
|
||||
name: '服务区域',
|
||||
desc: '服务区域描述......',
|
||||
icon: 'deliver_fill'
|
||||
}, {
|
||||
id: 3,
|
||||
name: '备注',
|
||||
desc: '备注描述......',
|
||||
icon: 'commentfill'
|
||||
}, ],
|
||||
specsList: [{
|
||||
id: 1,
|
||||
name: '挂机内机拆洗(不分匹)',
|
||||
salePrice: 199.00,
|
||||
price: 300,
|
||||
saledCount: 370,
|
||||
maxPieces: 1000,
|
||||
comments: '备注',
|
||||
commission: 12
|
||||
}, {
|
||||
id: 2,
|
||||
name: '柜机拆洗(方型)含拆风轮',
|
||||
salePrice: 240.00,
|
||||
price: 350,
|
||||
saledCount: 400,
|
||||
maxPieces: 1001,
|
||||
comments: '备注',
|
||||
commission: 16
|
||||
}, {
|
||||
id: 3,
|
||||
name: '柜机圆柱型拆洗',
|
||||
salePrice: 242.00,
|
||||
price: 352,
|
||||
saledCount: 350,
|
||||
maxPieces: 1002,
|
||||
comments: '备注',
|
||||
commission: 13
|
||||
}, {
|
||||
id: 4,
|
||||
name: '中央风口机(单个风口)',
|
||||
salePrice: 243.00,
|
||||
price: 353,
|
||||
saledCount: 100,
|
||||
maxPieces: 1003,
|
||||
comments: '备注',
|
||||
commission: 14
|
||||
}, {
|
||||
id: 5,
|
||||
name: '天花机深度拆洗',
|
||||
salePrice: 244.00,
|
||||
price: 354,
|
||||
saledCount: 109,
|
||||
maxPieces: 1004,
|
||||
comments: '备注',
|
||||
commission: 15
|
||||
}, {
|
||||
id: 6,
|
||||
name: '多台套餐xxx自命名',
|
||||
salePrice: 244.00,
|
||||
price: 354,
|
||||
saledCount: 109,
|
||||
maxPieces: 1005,
|
||||
comments: '备注',
|
||||
commission: 15
|
||||
}, {
|
||||
id: 7,
|
||||
name: '多台套餐xxxxxx自命名',
|
||||
salePrice: 244.00,
|
||||
price: 354,
|
||||
saledCount: 109,
|
||||
maxPieces: 1006,
|
||||
comments: '备注',
|
||||
commission: 15
|
||||
}, {
|
||||
id: 8,
|
||||
name: '多台套餐xxxxxxxx自命名',
|
||||
salePrice: 244.00,
|
||||
price: 354,
|
||||
saledCount: 109,
|
||||
maxPieces: 1007,
|
||||
comments: '备注',
|
||||
commission: 15
|
||||
}, {
|
||||
id: 9,
|
||||
name: '多台套餐xxxxxxxx自命名',
|
||||
salePrice: 244.00,
|
||||
price: 354,
|
||||
saledCount: 109,
|
||||
maxPieces: 1008,
|
||||
comments: '备注',
|
||||
commission: 15
|
||||
}, {
|
||||
id: 10,
|
||||
name: '多台套餐xxxxxxxx自命名',
|
||||
salePrice: 244.00,
|
||||
price: 354,
|
||||
saledCount: 109,
|
||||
maxPieces: 1009,
|
||||
comments: '备注',
|
||||
commission: 15
|
||||
}],
|
||||
reviewers: [{
|
||||
id: 1,
|
||||
avatarUrl: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big3002.jpg',
|
||||
name: 'e**1',
|
||||
reviewTime: '2022年03月17日',
|
||||
comments: '很好用啊......',
|
||||
picList: []
|
||||
}, {
|
||||
id: 2,
|
||||
avatarUrl: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big20001.jpg',
|
||||
name: 'e**1',
|
||||
reviewTime: '2022年03月17日',
|
||||
comments: '很好用啊......',
|
||||
picList: [{
|
||||
id: 21,
|
||||
url: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big3004.jpg'
|
||||
}, {
|
||||
id: 22,
|
||||
url: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big1010.jpg'
|
||||
}, {
|
||||
id: 23,
|
||||
url: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big1010.jpg'
|
||||
}, {
|
||||
id: 24,
|
||||
url: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big1010.jpg'
|
||||
}]
|
||||
}],
|
||||
shopInfo: {
|
||||
id: 1,
|
||||
name: '艺鑫到家(售后无忧)',
|
||||
avatarUrl: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big17005.jpg'
|
||||
}
|
||||
}
|
||||
|
||||
const pickedProductList = [{
|
||||
product: {
|
||||
id: 1,
|
||||
picUrl: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big20000.jpg',
|
||||
name: '柜机空调清洗1',
|
||||
comments: '备---------注',
|
||||
salePrice: 199,
|
||||
servArea: ['天河区', '黄埔区', '荔湾区']
|
||||
},
|
||||
pickedList: [{
|
||||
id: 101,
|
||||
name: '挂机内机拆洗(不分匹)',
|
||||
pickedNum: 1
|
||||
}, {
|
||||
id: 102,
|
||||
name: '柜机拆洗(方型)含拆风轮',
|
||||
pickedNum: 2
|
||||
}]
|
||||
}, {
|
||||
product: {
|
||||
id: 2,
|
||||
picUrl: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big20001.jpg',
|
||||
name: '柜机空调清洗2',
|
||||
comments: '备---------注',
|
||||
salePrice: 200,
|
||||
servArea: ['天河区', '黄埔区']
|
||||
},
|
||||
pickedList: [{
|
||||
id: 201,
|
||||
name: '多台套餐xxx自命名',
|
||||
pickedNum: 2
|
||||
}, {
|
||||
id: 202,
|
||||
name: '多台套餐xxxx自命名',
|
||||
pickedNum: 2
|
||||
}, {
|
||||
id: 203,
|
||||
name: '多台套餐xxxx自命名',
|
||||
pickedNum: 2
|
||||
}, {
|
||||
id: 204,
|
||||
name: '多台套餐xxxx自命名',
|
||||
pickedNum: 2
|
||||
}, {
|
||||
id: 205,
|
||||
name: '多台套餐xxxx自命名',
|
||||
pickedNum: 2
|
||||
}]
|
||||
}]
|
||||
|
||||
const shopInfo = {
|
||||
picUrl: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big17005.jpg',
|
||||
name: '艺鑫到家(售后无忧)',
|
||||
comments: {
|
||||
icon: 'form',
|
||||
desc: '企业认证'
|
||||
},
|
||||
extraInfos: [{
|
||||
icon: 'locationfill',
|
||||
desc: '广东省广州市番禺区钟村街道188号'
|
||||
}],
|
||||
totalScore: 4.5,
|
||||
timeScore: 4.4,
|
||||
attitudeScore: 4.4,
|
||||
skillScore:4.6,
|
||||
servType: '空调',
|
||||
additionalServ: [{
|
||||
id: 1,
|
||||
name: '58速运'
|
||||
}, {
|
||||
id: 2,
|
||||
name: '货拉拉'
|
||||
}, {
|
||||
id: 3,
|
||||
name: '搬货服务'
|
||||
}],
|
||||
servArea: ['天河区', '黄埔区', '荔湾区'],
|
||||
productList: [{
|
||||
id: 1,
|
||||
picUrl: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big20000.jpg',
|
||||
name: '万和(Vanward)电热水器80升电热水器 点热水器速热 储水式电热水器',
|
||||
comments: '智能断点 | 遥控预约调温 | 一级能效',
|
||||
salePrice: 199,
|
||||
servArea: ['广州', '顺德', '南海', '大良', '南海', '大良', '南海', '大良', '南海']
|
||||
}, {
|
||||
id: 2,
|
||||
picUrl: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big20001.jpg',
|
||||
name: '万和(Vanward)电热水器80升电热水器 点热水器速热 储水式电热水器',
|
||||
comments: '智能断点 | 遥控预约调温 | 一级能效',
|
||||
salePrice: 199,
|
||||
servArea: ['广州', '顺德', '南海', '大良', '南海', '大良', '南海', '大良']
|
||||
}, {
|
||||
id: 3,
|
||||
picUrl: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big20002.jpg',
|
||||
name: '万和(Vanward)电热水器80升电热水器 点热水器速热 储水式电热水器',
|
||||
comments: '智能断点 | 遥控预约调温 | 一级能效',
|
||||
salePrice: 199,
|
||||
servArea: ['广州', '顺德', '南海', '大良', '南海', '大良', '南海', '大良']
|
||||
}, {
|
||||
id: 4,
|
||||
picUrl: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big20003.jpg',
|
||||
name: '万和(Vanward)电热水器80升电热水器 点热水器速热 储水式电热水器',
|
||||
comments: '智能断点 | 遥控预约调温 | 一级能效',
|
||||
salePrice: 199,
|
||||
servArea: ['广州', '顺德', '南海', '大良', '南海', '大良', '南海', '大良']
|
||||
}, {
|
||||
id: 5,
|
||||
picUrl: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big20004.jpg',
|
||||
name: '万和(Vanward)电热水器80升电热水器 点热水器速热 储水式电热水器',
|
||||
comments: '智能断点 | 遥控预约调温 | 一级能效',
|
||||
salePrice: 199,
|
||||
servArea: ['广州', '顺德', '南海', '大良', '南海', '大良', '南海', '大良']
|
||||
}, {
|
||||
id: 6,
|
||||
picUrl: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big20005.jpg',
|
||||
name: '万和(Vanward)电热水器80升电热水器 点热水器速热 储水式电热水器',
|
||||
comments: '智能断点 | 遥控预约调温 | 一级能效',
|
||||
salePrice: 199,
|
||||
servArea: ['广州', '顺德', '南海', '大良', '南海', '大良', '南海', '大良']
|
||||
}]
|
||||
}
|
||||
|
||||
export default {
|
||||
swiperList,
|
||||
categories,
|
||||
subCategories,
|
||||
moduleBarInfos,
|
||||
discountGoods,
|
||||
hotGoods,
|
||||
productDetail,
|
||||
pickedProductList,
|
||||
shopInfo
|
||||
}
|
||||
41
main.js
41
main.js
|
|
@ -1,38 +1,47 @@
|
|||
|
||||
// #ifndef VUE3
|
||||
import Vue from 'vue'
|
||||
import App from './App'
|
||||
import cuCustom from 'colorui/components/cu-custom.vue'
|
||||
import Data from './data.js'
|
||||
import Vue from 'vue';
|
||||
import App from './App';
|
||||
import CuCustom from 'colorui/components/cu-custom.vue';
|
||||
import ConfirmModal from '@/components/modal/confirm-modal.vue';
|
||||
import Data from './common/js/data.js';
|
||||
import globalFun from './common/js/glogalFun.js';
|
||||
import validate from './common/js/validate.js';
|
||||
|
||||
Vue.component('cu-custom',cuCustom)
|
||||
const data = type=>{
|
||||
Vue.component('cu-custom', CuCustom)
|
||||
Vue.component('confirm-modal', ConfirmModal);
|
||||
const data = type => {
|
||||
//模拟异步请求数据
|
||||
return new Promise(resolve=>{
|
||||
setTimeout(()=>{
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
resolve(Data[type]);
|
||||
}, 0)
|
||||
})
|
||||
}
|
||||
Vue.prototype.$api = {data}
|
||||
Vue.prototype.$api = {
|
||||
data
|
||||
}
|
||||
Vue.prototype.$globalFun = globalFun;
|
||||
Vue.prototype.$validate = validate;
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
App.mpType = 'app'
|
||||
|
||||
const app = new Vue({
|
||||
...App
|
||||
...App
|
||||
})
|
||||
app.$mount()
|
||||
// #endif
|
||||
|
||||
// #ifdef VUE3
|
||||
import { createSSRApp } from 'vue'
|
||||
import {
|
||||
createSSRApp
|
||||
} from 'vue'
|
||||
import App from './App.vue'
|
||||
export function createApp() {
|
||||
const app = createSSRApp(App)
|
||||
return {
|
||||
app
|
||||
}
|
||||
const app = createSSRApp(App)
|
||||
return {
|
||||
app
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
|
|
@ -52,7 +52,7 @@
|
|||
"appid" : "wxc39c2af3ea24cd37",
|
||||
"setting" : {
|
||||
"urlCheck" : false,
|
||||
"minified" : false,
|
||||
"minified" : true,
|
||||
"es6" : false
|
||||
},
|
||||
"usingComponents" : true,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"id": "ay-qrcode",
|
||||
"name": "生成二维码。传入链接,即可使用,可快速扫出链接",
|
||||
"version": "1.0.7",
|
||||
"description": "生成二维码。传入链接,即可使用,可快速扫出链接,可自定义宽高,适用于APP与H5、微信小程序",
|
||||
"keywords": [
|
||||
"生成二维码",
|
||||
"二维码",
|
||||
"即可使用",
|
||||
"可快速扫出链接",
|
||||
"已解决部分华为荣耀手机缺角问题"
|
||||
]
|
||||
}
|
||||
79
pages.json
79
pages.json
|
|
@ -1,39 +1,56 @@
|
|||
{
|
||||
"pages": [{
|
||||
"path": "pages/index/index"
|
||||
},
|
||||
{
|
||||
"path": "pages/product/product-detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/product/product-pick",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/order/order-detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/product/shop-detail"
|
||||
}
|
||||
],
|
||||
"path": "pages/index/index"
|
||||
}],
|
||||
"subPackages": [{
|
||||
"root": "pages/order/",
|
||||
"pages": [{
|
||||
"path": "order-detail"
|
||||
}]
|
||||
}, {
|
||||
"root": "pages/product/",
|
||||
"pages": [{
|
||||
"path": "product-detail"
|
||||
}, {
|
||||
"path": "product-pick"
|
||||
}, {
|
||||
"path": "shop-detail"
|
||||
}]
|
||||
}, {
|
||||
"root": "pages/my/",
|
||||
"pages": [{
|
||||
"path": "my-order"
|
||||
}, {
|
||||
"path": "my-cart"
|
||||
}, {
|
||||
"path": "my-address"
|
||||
}, {
|
||||
"path": "edit-address"
|
||||
}, {
|
||||
"path": "my-operator"
|
||||
}, {
|
||||
"path": "contract"
|
||||
}, {
|
||||
"path": "apply-operator"
|
||||
}, {
|
||||
"path": "Certification"
|
||||
}, {
|
||||
"path": "my-team-member"
|
||||
}, {
|
||||
"path": "serv-detail"
|
||||
}]
|
||||
}],
|
||||
// "pages": [{
|
||||
// "path": "pages/my/serv-detail"
|
||||
// }],
|
||||
"globalStyle": {
|
||||
"navigationStyle": "custom",
|
||||
"navigationBarTextStyle": "black",
|
||||
"navigationBarTextStyle": "black"
|
||||
// "navigationBarTitleText": "uni-app",
|
||||
// "navigationBarBackgroundColor": "#F8F8F8",
|
||||
"backgroundColor": "#F8F8F8",
|
||||
"app-plus": {
|
||||
"background": "#efeff4"
|
||||
}
|
||||
// "backgroundColor": "#F8F8F8",
|
||||
// "app-plus": {
|
||||
// "background": "#efeff4"
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,153 @@
|
|||
<template name="index">
|
||||
<view>
|
||||
<!-- 轮播图-->
|
||||
<swiper class="screen-swiper" :class="dotStyle?'square-dot':'round-dot'" :indicator-dots="true" :circular="true"
|
||||
:autoplay="true" interval="5000" duration="500">
|
||||
<swiper-item v-for="(item,index) in swiperList" :key="item.id">
|
||||
<image :src="item.url" mode="aspectFill" v-if="item.type=='image'"></image>
|
||||
<video :src="item.url" autoplay loop muted :show-play-btn="false" :controls="false" objectFit="cover"
|
||||
v-if="item.type=='video'"></video>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<!-- 搜索栏 -->
|
||||
<view class="cu-bar search bg-white">
|
||||
<view class="search-form round">
|
||||
<text class="cuIcon-search"></text>
|
||||
<input @confirm="searchGoods" :adjust-position="true" type="text"
|
||||
placeholder="输入搜索内容" confirm-type="search"></input>
|
||||
</view>
|
||||
<view class="action">
|
||||
<text>广州</text>
|
||||
<text class="cuIcon-location"></text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="margin-lr-sm margin-bottom-with-bar">
|
||||
<!-- 大类 -->
|
||||
<view class="flex justify-between text-black">
|
||||
<view class="padding text-lg">
|
||||
<text>分类</text>
|
||||
<text class="cuIcon-apps text-main-color"></text>
|
||||
<text class="cuIcon-triangledownfill"></text>
|
||||
</view>
|
||||
<view>
|
||||
<scroll-view scroll-x class="nav">
|
||||
<view class="flex text-center">
|
||||
<view class="cu-item flex-sub" :class="index==tabCur?'text-main-color cur':''"
|
||||
v-for="(item,index) in categories" :key="item.id" @tap="tabSelect" :data-id="index">
|
||||
{{item.name}}
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 热门细类 -->
|
||||
<view class="cu-list grid no-border hot-sub-category" :class="['col-5']">
|
||||
<view class="cu-item" v-for="(item,index) in subCategories" :key="index" v-if="index < 5" @click="searchGoods(item)">
|
||||
<view class="hot-sub-category-icon" :class="['cuIcon-' + item.cuIcon,'text-' + item.color]">
|
||||
<view class="cu-tag badge" v-if="item.badge!=0">
|
||||
<block v-if="item.badge!=1">{{item.badge}}</block>
|
||||
</view>
|
||||
</view>
|
||||
<text>{{item.name}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 细类 -->
|
||||
<view class="cu-list grid no-border" :class="['col-5']" v-if="subCategories.length > 5">
|
||||
<view class="cu-item" v-for="(item,index) in subCategories" :key="index"
|
||||
v-if="index < subCategories.length && index > 4" @click="searchGoods(item)">
|
||||
<view :class="['cuIcon-' + item.cuIcon,'text-' + item.color]">
|
||||
<view class="cu-tag badge" v-if="item.badge!=0">
|
||||
<block v-if="item.badge!=1">{{item.badge}}</block>
|
||||
</view>
|
||||
</view>
|
||||
<text>{{item.name}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 超值服务 -->
|
||||
<vertical-goods-card ref="discountGoodsCard" :goodsInfos="discountGoods.goodsInfos"
|
||||
:title="discountGoods.title"></vertical-goods-card>
|
||||
<!-- 热门服务 -->
|
||||
<vertical-goods-card ref="hotGoodsCard" :goodsInfos="hotGoods.goodsInfos"
|
||||
:title="hotGoods.title"></vertical-goods-card>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import verticalGoodsCard from '@/components/goods-card/vertical-goods-card.vue';
|
||||
|
||||
export default {
|
||||
name: 'index',
|
||||
components: {
|
||||
verticalGoodsCard
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dotStyle: true,
|
||||
swiperList: [],
|
||||
tabCur: 0,
|
||||
categories: [],
|
||||
subCategories: [],
|
||||
hotGoods: {},
|
||||
discountGoods: {},
|
||||
InputBottom: 0
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.bindEvent();
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.offBindEvent();
|
||||
},
|
||||
onReady() {
|
||||
this.loadData();
|
||||
},
|
||||
methods: {
|
||||
async loadData() {
|
||||
this.swiperList = await this.$api.data('swiperList');
|
||||
this.categories = await this.$api.data('categories');
|
||||
this.subCategories = await this.$api.data('subCategories');
|
||||
this.moduleBarInfos = await this.$api.data('moduleBarInfos');
|
||||
this.hotGoods = await this.$api.data('hotGoods');
|
||||
this.discountGoods = await this.$api.data('discountGoods');
|
||||
},
|
||||
bindEvent() {
|
||||
uni.$on('index_showProductDetail', this.showDetails);
|
||||
},
|
||||
offBindEvent() {
|
||||
uni.$off('index_showProductDetail');
|
||||
},
|
||||
async tabSelect(e) {
|
||||
this.tabCur = e.currentTarget.dataset.id;
|
||||
// 获取大类信息
|
||||
let categoryId = this.categories[this.tabCur].id;
|
||||
console.log("切换细类, 大类id=" + categoryId);
|
||||
let allSubCategories = await this.$api.data('subCategories');
|
||||
this.subCategories = allSubCategories.slice(0, (4 - categoryId) * 5);
|
||||
},
|
||||
searchGoods(item) {
|
||||
console.log("搜索条件信息: " + item)
|
||||
console.log("商品搜索中...");
|
||||
},
|
||||
showDetails(productItem) {
|
||||
uni.navigateTo({
|
||||
url: '../product/product-detail'
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.cu-list+.cu-list {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.cu-list.grid.no-border {
|
||||
padding: 0 10rpx;
|
||||
}
|
||||
|
||||
.hot-sub-category .cu-item .hot-sub-category-icon {
|
||||
font-size: 80rpx;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,148 +1,156 @@
|
|||
<template>
|
||||
<view>
|
||||
<!-- 轮播图-->
|
||||
<swiper class="screen-swiper" :class="dotStyle?'square-dot':'round-dot'" :indicator-dots="true" :circular="true"
|
||||
:autoplay="true" interval="5000" duration="500">
|
||||
<swiper-item v-for="(item,index) in swiperList" :key="item.id">
|
||||
<image :src="item.url" mode="aspectFill" v-if="item.type=='image'"></image>
|
||||
<video :src="item.url" autoplay loop muted :show-play-btn="false" :controls="false" objectFit="cover"
|
||||
v-if="item.type=='video'"></video>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<!-- 搜索栏 -->
|
||||
<view class="cu-bar search bg-white">
|
||||
<view class="search-form round">
|
||||
<text class="cuIcon-search"></text>
|
||||
<input @confirm="searchGoods" :adjust-position="true" type="text"
|
||||
placeholder="输入搜索内容" confirm-type="search"></input>
|
||||
</view>
|
||||
<view class="action">
|
||||
<text>广州</text>
|
||||
<text class="cuIcon-location"></text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="margin-lr-sm margin-bottom-with-bar">
|
||||
<!-- 大类 -->
|
||||
<view class="flex justify-between text-black">
|
||||
<view class="padding text-lg">
|
||||
<text>分类</text>
|
||||
<text class="cuIcon-apps text-main-color"></text>
|
||||
<text class="cuIcon-triangledownfill"></text>
|
||||
</view>
|
||||
<view>
|
||||
<scroll-view scroll-x class="nav">
|
||||
<view class="flex text-center">
|
||||
<view class="cu-item flex-sub" :class="index==tabCur?'text-main-color cur':''"
|
||||
v-for="(item,index) in categories" :key="item.id" @tap="tabSelect" :data-id="index">
|
||||
{{item.name}}
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 热门细类 -->
|
||||
<view class="cu-list grid no-border hot-sub-category" :class="['col-5']">
|
||||
<view class="cu-item" v-for="(item,index) in subCategories" :key="index" v-if="index < 5" @click="searchGoods(item)">
|
||||
<view class="hot-sub-category-icon" :class="['cuIcon-' + item.cuIcon,'text-' + item.color]">
|
||||
<view class="cu-tag badge" v-if="item.badge!=0">
|
||||
<block v-if="item.badge!=1">{{item.badge}}</block>
|
||||
</view>
|
||||
</view>
|
||||
<text>{{item.name}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 细类 -->
|
||||
<view class="cu-list grid no-border" :class="['col-5']" v-if="subCategories.length > 5">
|
||||
<view class="cu-item" v-for="(item,index) in subCategories" :key="index"
|
||||
v-if="index < subCategories.length && index > 4" @click="searchGoods(item)">
|
||||
<view :class="['cuIcon-' + item.cuIcon,'text-' + item.color]">
|
||||
<view class="cu-tag badge" v-if="item.badge!=0">
|
||||
<block v-if="item.badge!=1">{{item.badge}}</block>
|
||||
</view>
|
||||
</view>
|
||||
<text>{{item.name}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 超值服务 -->
|
||||
<vertical-goods-card ref="discountGoodsCard" :goodsInfos="discountGoods.goodsInfos"
|
||||
:title="discountGoods.title"></vertical-goods-card>
|
||||
<!-- 热门服务 -->
|
||||
<vertical-goods-card ref="hotGoodsCard" :goodsInfos="hotGoods.goodsInfos"
|
||||
:title="hotGoods.title"></vertical-goods-card>
|
||||
</view>
|
||||
<index v-if="curPageCode === 'indexPage'"></index>
|
||||
<worker-circle v-if="curPageCode === 'workerCirclePage'"></worker-circle>
|
||||
<personal-center v-if="curPageCode === 'myPage'"></personal-center>
|
||||
<!-- <publish-home v-if="curPageCode === 'publishPage'"></publish-home> -->
|
||||
<module-bar ref="moduleBar" :moduleBarInfos="moduleBarInfos"></module-bar>
|
||||
<view class="cu-modal content-mask" :class="isShowPublish?'show':''">
|
||||
<view class="cu-dialog bottom-dialog margin-bottom-with-bar">
|
||||
<view class="padding-xl">
|
||||
<view class="flex justify-start margin-tb-xl">
|
||||
<view class="cu-avatar round middle-avatar first-avatar">
|
||||
<view class="cuIcon-formfill"></view>
|
||||
</view>
|
||||
<view class="flex flex-column-around text-left margin-left-sm text-white">
|
||||
<view class="text-xl">发布任务</view>
|
||||
<view>公司、家居家政雇佣上门服务</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-start margin-tb-xl">
|
||||
<view class="cu-avatar round middle-avatar second-avatar">
|
||||
<view class="cuIcon-cameraaddfill"></view>
|
||||
</view>
|
||||
<view class="flex flex-column-around text-left margin-left-sm text-white">
|
||||
<view class="text-xl">发闲置</view>
|
||||
<view class="text-gray">30s发布宝贝</view>
|
||||
<view class="text-sm">手机/家电卖出/非上门类</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-start margin-tb-xl">
|
||||
<view class="cu-avatar round middle-avatar third-avatar">
|
||||
<view class="cuIcon-footprint"></view>
|
||||
</view>
|
||||
<view class="flex flex-column-around text-left margin-left-sm text-white">
|
||||
<view class="text-xl">社区跑腿</view>
|
||||
<view>同楼盘跑腿服务</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-start margin-tb-xl">
|
||||
<view class="cu-avatar round middle-avatar fourth-avatar">
|
||||
<view class="cuIcon-shopfill"></view>
|
||||
</view>
|
||||
<view class="flex flex-column-around text-left margin-left-sm text-white">
|
||||
<view class="text-xl">品牌厂商发布</view>
|
||||
<view>销售商电商雇佣</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="cu-bar tabbar margin-bottom-xl fixed-bottom-bar">
|
||||
<view class="action add-action">
|
||||
<button class="cu-btn bg-gray cuIcon-close" @click="hidePublish"></button>
|
||||
<text class="mask-close-text">关闭</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moduleBar from '@/components/custom-bar/module-bar.vue';
|
||||
import verticalGoodsCard from '@/components/goods-card/vertical-goods-card.vue';
|
||||
import index from '@/pages/index/home.vue';
|
||||
import workerCircle from '@/pages/index/worker-home.vue';
|
||||
import personalCenter from '@/pages/index/my-home.vue';
|
||||
import publishHome from '@/pages/index/publish-home.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
moduleBar,
|
||||
verticalGoodsCard
|
||||
index,
|
||||
workerCircle,
|
||||
personalCenter,
|
||||
publishHome
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dotStyle: true,
|
||||
swiperList: [],
|
||||
tabCur: 0,
|
||||
categories: [],
|
||||
subCategories: [],
|
||||
moduleBarInfos: [],
|
||||
hotGoods: {},
|
||||
discountGoods: {},
|
||||
InputBottom: 0
|
||||
curPageCode: 'indexPage',
|
||||
isShowPublish: false
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
this.loadData();
|
||||
this.bindEvent();
|
||||
},
|
||||
onUnload() {
|
||||
this.offEvent();
|
||||
},
|
||||
methods: {
|
||||
async loadData() {
|
||||
this.swiperList = await this.$api.data('swiperList');
|
||||
this.categories = await this.$api.data('categories');
|
||||
this.subCategories = await this.$api.data('subCategories');
|
||||
this.moduleBarInfos = await this.$api.data('moduleBarInfos');
|
||||
this.hotGoods = await this.$api.data('hotGoods');
|
||||
this.discountGoods = await this.$api.data('discountGoods');
|
||||
},
|
||||
bindEvent() {
|
||||
uni.$on('index_showProductDetail', this.showDetails);
|
||||
uni.$on('getCurPageInfo', function(data) {
|
||||
if (data.curPageCode === 'publishPage') {
|
||||
this.isShowPublish = true;
|
||||
} else {
|
||||
this.isShowPublish = false;
|
||||
this.curPageCode = data.curPageCode;
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
async tabSelect(e) {
|
||||
this.tabCur = e.currentTarget.dataset.id;
|
||||
// 获取大类信息
|
||||
let categoryId = this.categories[this.tabCur].id;
|
||||
console.log("切换细类, 大类id=" + categoryId);
|
||||
let allSubCategories = await this.$api.data('subCategories');
|
||||
this.subCategories = allSubCategories.slice(0, (4 - categoryId) * 5);
|
||||
offEvent() {
|
||||
uni.$off('getCurPageInfo')
|
||||
},
|
||||
searchGoods(item) {
|
||||
console.log("搜索条件信息: " + item)
|
||||
console.log("商品搜索中...");
|
||||
},
|
||||
showDetails(productItem) {
|
||||
uni.navigateTo({
|
||||
url: '../product/product-detail'
|
||||
});
|
||||
hidePublish() {
|
||||
this.isShowPublish = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.cu-list+.cu-list {
|
||||
margin-top: 0;
|
||||
.content-mask {
|
||||
z-index: 9999;
|
||||
background: rgba(0, 0, 0, 0.9);
|
||||
}
|
||||
|
||||
.cu-list.grid.no-border {
|
||||
padding: 0 10rpx;
|
||||
.mask-close-text {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.hot-sub-category .cu-item .hot-sub-category-icon {
|
||||
font-size: 80rpx;
|
||||
.middle-avatar {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
}
|
||||
|
||||
.middle-avatar [class*="cuIcon-"] {
|
||||
font-size: 53rpx !important;
|
||||
}
|
||||
|
||||
.cu-avatar.first-avatar {
|
||||
background-color: #0081ff;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.cu-avatar.second-avatar {
|
||||
background-color: #fbbd08;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.cu-avatar.third-avatar {
|
||||
background-color: #f37b1d;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.cu-avatar.fourth-avatar {
|
||||
background-color: #1cbbb4;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.cu-dialog.bottom-dialog {
|
||||
background-color: unset;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,104 @@
|
|||
<template>
|
||||
<view class="margin-bottom-lg">
|
||||
<!-- 顶部操作条 -->
|
||||
<cu-custom :bgColor="'bg-main-color'">
|
||||
<block slot="content">我的消息</block>
|
||||
</cu-custom>
|
||||
<!-- 消息列表 -->
|
||||
<view class="cu-list menu-avatar">
|
||||
<view class="cu-item">
|
||||
<view class="cu-avatar round lg" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big10001.jpg);"></view>
|
||||
<view class="content">
|
||||
<view class="text-grey">凯尔</view>
|
||||
<view class="text-gray text-sm flex">
|
||||
<view class="text-cut">
|
||||
<text class="cuIcon-infofill text-red margin-right-xs"></text>
|
||||
我已天理为凭,踏入这片荒芜,不再受凡人的枷锁遏制。我已天理为凭,踏入这片荒芜,不再受凡人的枷锁遏制。
|
||||
</view> </view>
|
||||
</view>
|
||||
<view class="action">
|
||||
<view class="text-grey text-xs">22:20</view>
|
||||
<view class="cu-tag round bg-grey sm">5</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="cu-item">
|
||||
<view class="cu-avatar round lg" style="background-image:url(https://ossweb-img.qq.com/images/lol/img/champion/Taric.png);">
|
||||
<view class="cu-tag badge">99+</view>
|
||||
</view>
|
||||
<view class="content">
|
||||
<view class="text-grey">
|
||||
<view class="text-cut">瓦洛兰之盾-塔里克</view>
|
||||
<view class="cu-tag round bg-orange sm">战士</view>
|
||||
</view>
|
||||
<view class="text-gray text-sm flex">
|
||||
<view class="text-cut">
|
||||
塔里克是保护者星灵,用超乎寻常的力量守护着符文之地的生命、仁爱以及万物之美。塔里克由于渎职而被放逐,离开了祖国德玛西亚,前去攀登巨神峰寻找救赎,但他找到的却是来自星界的更高层的召唤。现在的塔里克与古代巨神族的神力相融合,以瓦洛兰之盾的身份,永不疲倦地警惕着阴险狡诈的虚空腐化之力。
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="action">
|
||||
<view class="text-grey text-xs">22:20</view>
|
||||
<view class="cuIcon-notice_forbid_fill text-gray"></view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="cu-item ">
|
||||
<view class="cu-avatar radius lg" style="background-image:url(https://ossweb-img.qq.com/images/lol/img/champion/Morgana.png);"></view>
|
||||
<view class="content">
|
||||
<view class="text-pink"><view class="text-cut">莫甘娜</view></view>
|
||||
<view class="text-gray text-sm flex"> <view class="text-cut">凯尔,你被自己的光芒变的盲目!</view></view>
|
||||
</view>
|
||||
<view class="action">
|
||||
<view class="text-grey text-xs">22:20</view>
|
||||
<view class="cu-tag round bg-red sm">5</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="cu-item grayscale">
|
||||
<view class="cu-avatar radius lg" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big81007.jpg);"></view>
|
||||
<view class="content">
|
||||
<view><view class="text-cut">伊泽瑞尔</view>
|
||||
<view class="cu-tag round bg-orange sm">断开连接...</view>
|
||||
</view>
|
||||
<view class="text-gray text-sm flex"> <view class="text-cut"> 等我回来一个打十个</view></view>
|
||||
</view>
|
||||
<view class="action">
|
||||
<view class="text-grey text-xs">22:20</view>
|
||||
<view class="cu-tag round bg-red sm">5</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="cu-item cur">
|
||||
<view class="cu-avatar radius lg" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big81020.jpg);">
|
||||
<view class="cu-tag badge"></view>
|
||||
</view>
|
||||
<view class="content">
|
||||
<view>
|
||||
<view class="text-cut">瓦罗兰大陆-睡衣守护者-新手保护营</view>
|
||||
<view class="cu-tag round bg-orange sm">6人</view>
|
||||
</view>
|
||||
<view class="text-gray text-sm flex">
|
||||
<view class="text-cut"> 伊泽瑞尔:<text class="cuIcon-locationfill text-orange margin-right-xs"></text> 传送中...</view></view>
|
||||
</view>
|
||||
<view class="action">
|
||||
<view class="text-grey text-xs">22:20</view>
|
||||
<view class="cuIcon-notice_forbid_fill text-gray"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
|
@ -0,0 +1,361 @@
|
|||
<template>
|
||||
<view>
|
||||
<!-- 顶部头像栏 -->
|
||||
<view class="padding bg-main-color" :style="'padding-top: ' + pageContentTop + 'px; padding-bottom: 100rpx;'">
|
||||
<view class="flex justify-start padding-bottom-xl solid-bottom">
|
||||
<view class="cu-avatar round"
|
||||
:style="'width: 120rpx; height: 120rpx; background-image:url(' + myInfo.picUrl + ');'"></view>
|
||||
<view class="margin-lr-sm">
|
||||
<view class="text-xl margin-bottom-xs">{{myInfo.name}}</view>
|
||||
<view class="padding-xs text-sm">
|
||||
<view v-if="myInfo.vipInfo.isVip" class='cu-tag bg-yellow radius'>{{myInfo.vipInfo.level}}会员
|
||||
</view>
|
||||
<view v-else class='cu-tag bg-yellow radius'>非会员</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="cu-bar">
|
||||
<view class="action bar-first-action"><text class="margin-right-sm">余额:</text><text>{{myInfo.balance}}</text></view>
|
||||
<view class="action"><text class="margin-right-sm">积分:</text><text>{{myInfo.integrate}}</text></view>
|
||||
<view class="action" @click="showCart">
|
||||
<text class="margin-right-sm">购物车:</text>
|
||||
<text class="cuIcon-cart my-cart">
|
||||
<text class="cu-tag badge my-cart-badge" v-if="myInfo.cartNum > 0">{{myInfo.cartNum}}</text>
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="margin-lr-sm paper-drawer-bar margin-bottom-with-bar">
|
||||
<!-- 服务圈 -->
|
||||
<view class="bg-white padding-lr shadow-warp">
|
||||
<view class="cu-bar margin-top-sm solid-bottom">
|
||||
<view class="action bar-first-action">
|
||||
<text>{{myInfo.servCircle.name}}</text>
|
||||
<view class="cuIcon-title text-main-color"></view>
|
||||
<text>服务圈</text>
|
||||
</view>
|
||||
<view class="flex justify-end">
|
||||
<view class="text-center margin-right-sm">
|
||||
<view class="cuIcon-shop action-icon"></view>
|
||||
<view class="text-xs">邻里商铺</view>
|
||||
</view>
|
||||
<view class="text-center">
|
||||
<view class="cuIcon-roundaddfill text-main-color action-icon"></view>
|
||||
<view class="text-xs">您的小区</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="padding-top serv-news">
|
||||
<view class="flex justify-between padding-bottom" v-for="(item, index) in myInfo.servCircle.news">
|
||||
<view class="flex justify-start">
|
||||
<view class="cu-avatar round margin-right-sm"
|
||||
:style="'background-image:url(' + item.avatarUrl + ');'"></view>
|
||||
<view class="text-sm">
|
||||
<text class="margin-right-xs">{{encryptString(item.userName)}}</text>
|
||||
<text>{{item.action}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="margin-left-sm">
|
||||
<button v-if="item.type === 0" class="cu-btn bg-main-color round sm">立即下单</button>
|
||||
<button v-else class="cu-btn bg-main-color round sm">学家政</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="bg-white padding-lr padding-bottom">
|
||||
<!-- 服务订单 -->
|
||||
<view class="cu-bar solid-bottom margin-top-sm">
|
||||
<view class="action bar-first-action">
|
||||
<text class="cuIcon-titles text-main-color"></text> 服务订单
|
||||
</view>
|
||||
<view @click="showMyOrders(servOrderTabList, 0, servOrderType)">
|
||||
<text>全部</text>
|
||||
<text class="cuIcon-right"></text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="cu-list grid no-border col-5">
|
||||
<view class="cu-item" @click="showMyOrders(servOrderTabList, 0, servOrderType)">
|
||||
<view class="cuIcon-news">
|
||||
<view class="cu-tag badge" v-if="myInfo.serOrderNum.wait2Pay > 0">
|
||||
<block>{{myInfo.serOrderNum.wait2Pay}}</block>
|
||||
</view>
|
||||
</view>
|
||||
<text>待付款</text>
|
||||
</view>
|
||||
<view class="cu-item" @click="showMyOrders(servOrderTabList, 1, servOrderType)">
|
||||
<view class="cuIcon-list">
|
||||
<view class="cu-tag badge" v-if="myInfo.serOrderNum.wait2Serv > 0">
|
||||
<block>{{myInfo.serOrderNum.wait2Serv}}</block>
|
||||
</view>
|
||||
</view>
|
||||
<text>待服务</text>
|
||||
</view>
|
||||
<view class="cu-item" @click="showMyOrders(servOrderTabList, 2, servOrderType)">
|
||||
<view class="cuIcon-repair">
|
||||
<view class="cu-tag badge" v-if="myInfo.serOrderNum.processing > 0">
|
||||
<block>{{myInfo.serOrderNum.processing}}</block>
|
||||
</view>
|
||||
</view>
|
||||
<text>进行中</text>
|
||||
</view>
|
||||
<view class="cu-item" @click="showMyOrders(servOrderTabList, 3, servOrderType)">
|
||||
<view class="cuIcon-comment">
|
||||
<view class="cu-tag badge" v-if="myInfo.serOrderNum.afterServ > 0">
|
||||
<block>{{myInfo.serOrderNum.afterServ}}</block>
|
||||
</view>
|
||||
</view>
|
||||
<text>售后中</text>
|
||||
</view>
|
||||
<view class="cu-item" @click="showMyOrders(servOrderTabList, 4, servOrderType)">
|
||||
<view class="cuIcon-forward">
|
||||
<view class="cu-tag badge" v-if="myInfo.serOrderNum.wait2Forward > 0">
|
||||
<block>{{myInfo.serOrderNum.wait2Forward}}</block>
|
||||
</view>
|
||||
</view>
|
||||
<text>待转发</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 商品订单 -->
|
||||
<view class="cu-bar solid-bottom">
|
||||
<view class="action bar-first-action">
|
||||
<text class="cuIcon-titles text-main-color"></text> 商品订单
|
||||
</view>
|
||||
<view @click="showMyOrders(productOrderTabList, 0, productOrderType)">
|
||||
<text>全部</text>
|
||||
<text class="cuIcon-right"></text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="cu-list grid no-border col-5">
|
||||
<view class="cu-item" @click="showMyOrders(productOrderTabList, 0, productOrderType)">
|
||||
<view class="cuIcon-news">
|
||||
<view class="cu-tag badge" v-if="myInfo.serOrderNum.wait2Pay > 0">
|
||||
<block>{{myInfo.serOrderNum.wait2Pay}}</block>
|
||||
</view>
|
||||
</view>
|
||||
<text>待付款</text>
|
||||
</view>
|
||||
<view class="cu-item" @click="showMyOrders(productOrderTabList, 1, productOrderType)">
|
||||
<view class="cuIcon-goodsfavor">
|
||||
<view class="cu-tag badge" v-if="myInfo.serOrderNum.buy> 0">
|
||||
<block>{{myInfo.serOrderNum.buy}}</block>
|
||||
</view>
|
||||
</view>
|
||||
<text>买到的</text>
|
||||
</view>
|
||||
<view class="cu-item" @click="showMyOrders(productOrderTabList, 2, productOrderType)">
|
||||
<view class="cuIcon-goodsnew">
|
||||
<view class="cu-tag badge" v-if="myInfo.serOrderNum.sale > 0">
|
||||
<block>{{myInfo.serOrderNum.sale}}</block>
|
||||
</view>
|
||||
</view>
|
||||
<text>卖出的</text>
|
||||
</view>
|
||||
<view class="cu-item" @click="showMyOrders(productOrderTabList, 3, productOrderType)">
|
||||
<view class="cuIcon-comment">
|
||||
<view class="cu-tag badge" v-if="myInfo.serOrderNum.afterServ > 0">
|
||||
<block>{{myInfo.serOrderNum.afterServ}}</block>
|
||||
</view>
|
||||
</view>
|
||||
<text>售后中</text>
|
||||
</view>
|
||||
<view class="cu-item" @click="showMyOrders(productOrderTabList, 4, productOrderType)">
|
||||
<view class="cuIcon-forward">
|
||||
<view class="cu-tag badge" v-if="myInfo.serOrderNum.wait2Forward > 0">
|
||||
<block>{{myInfo.serOrderNum.wait2Forward}}</block>
|
||||
</view>
|
||||
</view>
|
||||
<text>待转发</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 所有功能 -->
|
||||
<view class="bg-white padding-lr padding-bottom">
|
||||
<view class="cu-bar margin-top-sm solid-bottom">
|
||||
<view class="action bar-first-action">
|
||||
<view class="cuIcon-titles text-main-color"></view>
|
||||
<text>所有功能</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="cu-list grid no-border col-4">
|
||||
<view class="cu-item">
|
||||
<view class="cuIcon-wefill text-red"></view>
|
||||
<text>我的发布</text>
|
||||
</view>
|
||||
<view class="cu-item" @click="showMyAddress">
|
||||
<view class="cuIcon-locationfill text-orange"></view>
|
||||
<text>地址管理</text>
|
||||
</view>
|
||||
<view class="cu-item">
|
||||
<view class="cuIcon-questionfill text-yellow"></view>
|
||||
<text>常见问题</text>
|
||||
</view>
|
||||
<view class="cu-item">
|
||||
<view class="cuIcon-servicefill text-olive"></view>
|
||||
<text>联系客服</text>
|
||||
</view>
|
||||
<view class="cu-item">
|
||||
<view class="cuIcon-qr_code text-green"></view>
|
||||
<text>二维码分享</text>
|
||||
</view>
|
||||
<view class="cu-item">
|
||||
<view class="cuIcon-moneybagfill text-cyan"></view>
|
||||
<text>钱包</text>
|
||||
</view>
|
||||
<view class="cu-item">
|
||||
<view class="cuIcon-friendaddfill text-blue"></view>
|
||||
<text>加盟项目</text>
|
||||
</view>
|
||||
<view class="cu-item">
|
||||
<view class="cuIcon-group_fill text-purple"></view>
|
||||
<text>社区代理</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 后台入口 -->
|
||||
<view class="bg-white padding-lr padding-bottom">
|
||||
<view class="cu-bar margin-top-sm solid-bottom">
|
||||
<view class="action bar-first-action">
|
||||
<view class="cuIcon-titles text-main-color"></view>
|
||||
<text>后台入口</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="cu-list grid no-border col-4">
|
||||
<view class="cu-item">
|
||||
<view class="cuIcon-brandfill text-mauve"></view>
|
||||
<text>商家注册</text>
|
||||
</view>
|
||||
<view class="cu-item" @click="showApplyOperator">
|
||||
<view class="cuIcon-wenzi text-pink"></view>
|
||||
<text>运营商申请</text>
|
||||
</view>
|
||||
<view class="cu-item">
|
||||
<view class="cuIcon-searchlist text-brown"></view>
|
||||
<text>后台数据</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'personal-center',
|
||||
components: {},
|
||||
data() {
|
||||
return {
|
||||
pageContentTop: this.CustomBar,
|
||||
myInfo: {},
|
||||
servOrderTabList: [{
|
||||
type: 'ordersWait2Pay',
|
||||
name: '待付款'
|
||||
}, {
|
||||
type: 'ordersWait2Serv',
|
||||
name: '待服务'
|
||||
}, {
|
||||
type: 'ordersServing',
|
||||
name: '服务中'
|
||||
}, {
|
||||
type: 'ordersAfterServ',
|
||||
name: '售后中'
|
||||
}, {
|
||||
type: 'ordersFinish',
|
||||
name: '已完成'
|
||||
}],
|
||||
servOrderType: 'servOrder',
|
||||
productOrderTabList: [{
|
||||
type: 'pdOrdersWait2Pay',
|
||||
name: '待付款'
|
||||
}, {
|
||||
type: 'pdOrdersBought',
|
||||
name: '买到的'
|
||||
}, {
|
||||
type: 'pdOrdersSaled',
|
||||
name: '卖出的'
|
||||
}, {
|
||||
type: 'pdOrdersAfterServ',
|
||||
name: '售后中'
|
||||
}, {
|
||||
type: 'pdOrdersFinish',
|
||||
name: '已完成'
|
||||
}],
|
||||
productOrderType: 'productOrder'
|
||||
}
|
||||
},
|
||||
onReady() {
|
||||
this.loadData();
|
||||
},
|
||||
methods: {
|
||||
async loadData() {
|
||||
this.myInfo = await this.$api.data('myInfo');
|
||||
console.log(this.myInfo)
|
||||
},
|
||||
showMyOrders(tabHeaderList, tabCur, orderType) {
|
||||
let tabInfo = {
|
||||
orderType: orderType,
|
||||
tabHeaderList: tabHeaderList,
|
||||
tabCur: tabCur
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: '/pages/my/my-order?tabInfo=' + encodeURIComponent(JSON.stringify(tabInfo))
|
||||
})
|
||||
},
|
||||
encryptString(str) {
|
||||
str = str[0] + "**" + str[str.length - 1];
|
||||
return str;
|
||||
},
|
||||
showCart() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/my/my-cart'
|
||||
});
|
||||
},
|
||||
showMyAddress() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/my/my-address'
|
||||
});
|
||||
},
|
||||
showApplyOperator() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/my/apply-operator'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.bg-main-color .solid-bottom::after {
|
||||
border-bottom: 1upx solid rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.my-cart {
|
||||
position: relative;
|
||||
font-size: 40rpx;
|
||||
}
|
||||
|
||||
.my-cart-badge {
|
||||
right: -30rpx;
|
||||
}
|
||||
|
||||
.action-icon {
|
||||
font-size: 40rpx;
|
||||
}
|
||||
|
||||
.paper-drawer-bar {
|
||||
position: relative;
|
||||
top: -100rpx;
|
||||
}
|
||||
|
||||
.bar-first-action {
|
||||
margin-left: unset !important;
|
||||
font-size: 30rpx !important;
|
||||
}
|
||||
|
||||
.serv-news .cu-avatar {
|
||||
min-width: 64rpx;
|
||||
}
|
||||
|
||||
.serv-news button {
|
||||
min-width: 120rpx;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
<template>
|
||||
<view>
|
||||
<!-- 顶部操作条 -->
|
||||
<cu-custom :bgColor="'bg-main-color'">
|
||||
<block slot="content">全国师傅圈</block>
|
||||
</cu-custom>
|
||||
<!-- 搜索栏 -->
|
||||
<view class="sticky-bar" :style="[{top: stickyTop + 'px'}]">
|
||||
<view class="cu-bar bg-white search solid-bottom margin-bottom-sm">
|
||||
<view class="action">
|
||||
<text class="cuIcon-location"></text>
|
||||
<text>广州</text>
|
||||
</view>
|
||||
<view class="search-form round">
|
||||
<text class="cuIcon-search"></text>
|
||||
<input @confirm="searchGoods" :adjust-position="true" type="text" placeholder="搜索家电维修"
|
||||
confirm-type="search"></input>
|
||||
</view>
|
||||
<view class="action">
|
||||
<text>筛选</text>
|
||||
<text class="cuIcon-filter"></text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="margin-bottom-with-bar">
|
||||
<!-- 师傅卡片 -->
|
||||
<view v-for="(item, index) in workerInfos" class="bg-white padding margin-lr-sm margin-tb-sm shadow-warp">
|
||||
<!-- 师傅信息 -->
|
||||
<view class="solid-bottom padding-bottom-sm">
|
||||
<horizontal-name-card :vCard="item" :avatarPubClass="'round'" :avatarWidth="'130rpx'"
|
||||
:avatarHeight="'130rpx'"></horizontal-name-card>
|
||||
</view>
|
||||
<!-- 服务列表 -->
|
||||
<view class="padding-top-sm padding-bottom-xl grid text-center col-5 grid-square">
|
||||
<view v-for="(product,index) in item.productList" :key="index" class="bg-img"
|
||||
:style="[{ backgroundImage:'url(' + product.picUrl + ')' }]">
|
||||
<view class="pic-down-text">
|
||||
<view class="text-grey text-cut text-sm">{{product.name}}</view>
|
||||
<view class="text-price text-red text-cut">{{product.price}}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view>
|
||||
<view v-for="(item, index) in 3" class="circle-point margin-right-xs bg-grey"></view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 进店看看 -->
|
||||
<view class="flex justify-between align-end margin-top-xs">
|
||||
<view class="cu-capsule">
|
||||
<view class='cu-tag bg-main-color'>
|
||||
<text class='cuIcon-shopfill'></text>
|
||||
</view>
|
||||
<view class="cu-tag line-main-color">
|
||||
{{item.shopInfo.shopName}}
|
||||
</view>
|
||||
</view>
|
||||
<!-- <view class="margin-right-sm text-black">{{item.shopName}}</view> -->
|
||||
<view class='cu-tag light bg-main-color radius' @click="showShopDetail(item.shopInfo)">进店看看<text
|
||||
class="text-bold cuIcon-right"></text></view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="hasMoreData" class="text-center bg-main-color light padding-tb-sm" @click="loadData">
|
||||
<text class="margin-right-xs">查看更多</text>
|
||||
<text class="text-bold cuIcon-unfold"></text>
|
||||
</view>
|
||||
<view class="cu-load" :class="loadMoreStatus"></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import horizontalNameCard from '@/components/common-card/horizontal-name-card.vue';
|
||||
|
||||
export default {
|
||||
name: 'worker-circle',
|
||||
components: {
|
||||
horizontalNameCard
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
workerInfos: [],
|
||||
loadMoreStatus: '',
|
||||
hasMoreData: false,
|
||||
pageIndex: 1,
|
||||
pageSize: 3,
|
||||
stickyTop: this.CustomBar
|
||||
}
|
||||
},
|
||||
onReady() {
|
||||
this.loadData();
|
||||
},
|
||||
methods: {
|
||||
async loadMoreWorkerInfos() {
|
||||
let allData = await this.$api.data('workerInfos');
|
||||
let dataOfPage = allData.slice((this.pageIndex - 1) * this.pageSize, this.pageIndex * this.pageSize);
|
||||
if (dataOfPage.length == 0) {
|
||||
return;
|
||||
} else if (dataOfPage.length === this.pageSize) {
|
||||
this.hasMoreData = true;
|
||||
}
|
||||
this.workerInfos = this.workerInfos.concat(dataOfPage);
|
||||
this.pageIndex++;
|
||||
},
|
||||
async loadData() {
|
||||
this.loadMoreStatus = 'loading bg-main-color light';
|
||||
this.hasMoreData = false;
|
||||
try {
|
||||
await this.loadMoreWorkerInfos();
|
||||
this.loadMoreStatus = this.hasMoreData ? '' : 'over bg-grey';
|
||||
} catch (e) {
|
||||
this.loadMoreStatus = 'erro bg-red'
|
||||
}
|
||||
},
|
||||
showShopDetail(shopInfo) {
|
||||
uni.navigateTo({
|
||||
url: '../product/shop-detail?shopInfo=' + encodeURIComponent(JSON.stringify(shopInfo))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.grid.grid-square {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.grid.grid-square>view {
|
||||
margin-right: 20rpx;
|
||||
margin-bottom: 20rpx;
|
||||
border-radius: 6rpx;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.pic-down-text {
|
||||
margin-top: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.circle-point {
|
||||
display: inline-block;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
margin-top: 50%;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,284 @@
|
|||
<template>
|
||||
<view class="margin-bottom-lg">
|
||||
<!-- 顶部操作条 -->
|
||||
<cu-custom :bgColor="'bg-main-color'" :isBack="true">
|
||||
<block slot="backText">返回</block>
|
||||
<block slot="content">实名认证</block>
|
||||
</cu-custom>
|
||||
<!-- 表单 -->
|
||||
<view class="margin-lr-sm margin-top-sm">
|
||||
<form @submit="submit">
|
||||
<view class="cu-form-group">
|
||||
<view class="title">姓名</view>
|
||||
<input name="name" placeholder="请输入姓名"></input>
|
||||
</view>
|
||||
<view class="cu-form-group">
|
||||
<view class="title">身份证号</view>
|
||||
<input name="idCard" placeholder="请输入身份证号码"></input>
|
||||
</view>
|
||||
<view class="cu-form-group">
|
||||
<view class="title">联系电话</view>
|
||||
<input name="phone" placeholder="请输入联系人电话"></input>
|
||||
</view>
|
||||
<view class="cu-form-group">
|
||||
<view class="title">公司名称</view>
|
||||
<input name="companyName" placeholder="请输入公司名称"></input>
|
||||
</view>
|
||||
<view class="cu-form-group">
|
||||
<view class="title">执照地址</view>
|
||||
<input name="licenseAddress" placeholder="请输入执照地址"></input>
|
||||
</view>
|
||||
<view class="cu-form-group">
|
||||
<view class="title">执照号码</view>
|
||||
<input name="licenseIdNum" placeholder="请输入执照号码"></input>
|
||||
</view>
|
||||
<view class="cu-form-group">
|
||||
<view class="title">运营意向</view>
|
||||
<view class="flex-sub">
|
||||
<picker mode="region" @change="regionChange" name="area" :value="formData.area">
|
||||
<view class="picker">
|
||||
{{formData.area[0]}},{{formData.area[1]}},{{formData.area[2]}}
|
||||
</view>
|
||||
</picker>
|
||||
<radio-group @change="changeOperaLevel" class="margin-bottom-sm">
|
||||
<label class="radio">
|
||||
<radio style="transform:scale(0.7)" class="main-color" value="community"
|
||||
:checked="formData.operaLevel=='community'" />
|
||||
<text class="margin-left-xs">社区运营</text>
|
||||
</label>
|
||||
<label class="radio">
|
||||
<radio style="transform:scale(0.7)" class="main-color" value="cityArea"
|
||||
:checked="formData.operaLevel=='cityArea'" />
|
||||
<text class="margin-left-xs">县区运营</text>
|
||||
</label>
|
||||
<label class="radio">
|
||||
<radio style="transform:scale(0.7)" class="main-color" value="city"
|
||||
:checked="formData.operaLevel=='city'" />
|
||||
<text class="margin-left-xs">城市运营</text>
|
||||
</label>
|
||||
</radio-group>
|
||||
</view>
|
||||
</view>
|
||||
<view class="cu-form-group">
|
||||
<view class="title">质保金</view>
|
||||
<view class="flex flex-sub justify-start">
|
||||
<view>{{formData.deposit}}元</view>
|
||||
<radio-group @change="changeDepositPayNow" class="margin-left">
|
||||
<label class="radio">
|
||||
<radio style="transform:scale(0.7)" class="main-color" value=1
|
||||
:checked="payNow==1" />
|
||||
<text class="margin-left-xs">立即缴纳</text>
|
||||
</label>
|
||||
<label class="radio">
|
||||
<radio style="transform:scale(0.7)" class="main-color" value=0
|
||||
:checked="payNow==0" />
|
||||
<text class="margin-left-xs">以后缴纳</text>
|
||||
</label>
|
||||
</radio-group>
|
||||
</view>
|
||||
</view>
|
||||
<view class="cu-bar bg-white margin-top-sm">
|
||||
<view class="action">
|
||||
身份证上传(正反面)
|
||||
</view>
|
||||
</view>
|
||||
<view class="cu-form-group">
|
||||
<view class="grid col-4 grid-square flex-sub">
|
||||
<view class="bg-img" v-for="(item,index) in formData.idCardImgList" :key="index" @tap="viewImage($event, formData.idCardImgList)"
|
||||
:data-url="item">
|
||||
<image :src="item" mode="aspectFill"></image>
|
||||
<view class="cu-tag bg-red" @tap.stop="delImg($event, formData.idCardImgList)" :data-index="index">
|
||||
<text class='cuIcon-close'></text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="solids" @tap="chooseIdCardImage" v-if="formData.idCardImgList.length<4">
|
||||
<text class='cuIcon-cameraadd'></text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="cu-bar bg-white margin-top-sm">
|
||||
<view class="action">
|
||||
公司营业执照、公司账户
|
||||
</view>
|
||||
</view>
|
||||
<view class="cu-form-group">
|
||||
<view class="grid col-4 grid-square flex-sub">
|
||||
<view class="bg-img" v-for="(item,index) in formData.licenseImgList" :key="index" @tap="viewImage($event, formData.licenseImgList)"
|
||||
:data-url="item">
|
||||
<image :src="item" mode="aspectFill"></image>
|
||||
<view class="cu-tag bg-red" @tap.stop="delImg($event, formData.licenseImgList)" :data-index="index">
|
||||
<text class='cuIcon-close'></text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="solids" @tap="chooseLicenseImage" v-if="formData.licenseImgList.length<4">
|
||||
<text class='cuIcon-cameraadd'></text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="margin-lr-sm margin-top">
|
||||
<button class="bg-main-color long-btn" form-type="submit">提交</button>
|
||||
</view>
|
||||
</form>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
formData: {}
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
this.loadData();
|
||||
},
|
||||
methods: {
|
||||
async loadData() {
|
||||
this.formData = await this.$api.data('certificationInfo');
|
||||
},
|
||||
regionChange(e) {
|
||||
this.formData.area = e.detail.value;
|
||||
},
|
||||
changeOperaLevel(e) {
|
||||
this.formData.operaLevel = e.detail.value;
|
||||
},
|
||||
changeDepositPayNow(e) {
|
||||
this.formData.payNow = e.detail.value;
|
||||
},
|
||||
viewImage(e, imgList) {
|
||||
uni.previewImage({
|
||||
urls: imgList,
|
||||
current: e.currentTarget.dataset.url
|
||||
});
|
||||
},
|
||||
delImg(e, imgList) {
|
||||
uni.showModal({
|
||||
title: '',
|
||||
content: '确定要删除这张图片吗?',
|
||||
cancelText: '取消',
|
||||
confirmText: '确定',
|
||||
success: res => {
|
||||
if (res.confirm) {
|
||||
imgList.splice(e.currentTarget.dataset.index, 1)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
chooseLicenseImage(e) {
|
||||
uni.chooseImage({
|
||||
count: 4, //默认9
|
||||
sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
|
||||
sourceType: ['album'], //从相册选择
|
||||
success: (res) => {
|
||||
if (this.formData.licenseImgList.length != 0) {
|
||||
this.formData.licenseImgList = this.formData.licenseImgList.concat(res.tempFilePaths)
|
||||
} else {
|
||||
this.formData.licenseImgList = res.tempFilePaths
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
chooseIdCardImage(e) {
|
||||
uni.chooseImage({
|
||||
count: 4, //默认9
|
||||
sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
|
||||
sourceType: ['album'], //从相册选择
|
||||
success: (res) => {
|
||||
if (this.formData.idCardImgList.length != 0) {
|
||||
this.formData.idCardImgList = this.formData.idCardImgList.concat(res.tempFilePaths)
|
||||
} else {
|
||||
this.formData.idCardImgList = res.tempFilePaths
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
validateForm(confirmFormData) {
|
||||
let formInfoValid = Boolean(confirmFormData.name) &&
|
||||
Boolean(confirmFormData.idCard) &&
|
||||
Boolean(confirmFormData.phone) &&
|
||||
Boolean(confirmFormData.companyName) &&
|
||||
Boolean(confirmFormData.licenseAddress) &&
|
||||
Boolean(confirmFormData.licenseIdNum) &&
|
||||
Boolean(confirmFormData.operaLevel) &&
|
||||
Boolean(confirmFormData.payNow);
|
||||
if (!formInfoValid) {
|
||||
uni.showToast({
|
||||
title: '请填写完整信息',
|
||||
icon: 'none',
|
||||
mask: true
|
||||
})
|
||||
formInfoValid = false;
|
||||
} else if (!this.$validate.validIdCard(confirmFormData.idCard)) {
|
||||
uni.showToast({
|
||||
title: '身份证号格式错误',
|
||||
icon: 'none',
|
||||
mask: true
|
||||
})
|
||||
formInfoValid = false;
|
||||
} else if (!this.$validate.validContactNum(confirmFormData.phone)) {
|
||||
uni.showToast({
|
||||
title: '联系方式格式错误',
|
||||
icon: 'none',
|
||||
mask: true
|
||||
})
|
||||
formInfoValid = false;
|
||||
} else if (!this.$validate.validLicenseIdNum(confirmFormData.licenseIdNum)) {
|
||||
uni.showToast({
|
||||
title: '执照号码格式错误',
|
||||
icon: 'none',
|
||||
mask: true
|
||||
})
|
||||
formInfoValid = false;
|
||||
} else if (confirmFormData.idCardImgList.length === 0) {
|
||||
uni.showToast({
|
||||
title: '请上传身份证正反面',
|
||||
icon: 'none',
|
||||
mask: true
|
||||
})
|
||||
formInfoValid = false;
|
||||
} else if (confirmFormData.licenseImgList.length === 0) {
|
||||
uni.showToast({
|
||||
title: '请上传公司营业执照',
|
||||
icon: 'none',
|
||||
mask: true
|
||||
})
|
||||
formInfoValid = false;
|
||||
}
|
||||
return formInfoValid;
|
||||
},
|
||||
uploadImg(imgList) {
|
||||
uni.uploadFile({
|
||||
|
||||
})
|
||||
return new Promise(resolve => {
|
||||
resolve();
|
||||
})
|
||||
},
|
||||
async submit(e) {
|
||||
let formData = e.detail.value;
|
||||
formData.operaLevel = this.formData.operaLevel;
|
||||
formData.area = this.formData.area;
|
||||
formData.payNow = this.formData.payNow;
|
||||
formData.idCardImgList = this.formData.idCardImgList;
|
||||
formData.licenseImgList = this.formData.licenseImgList;
|
||||
let formValid = this.validateForm(formData);
|
||||
console.log(formData);
|
||||
if (formValid) {
|
||||
let picUploadResult = await this.uploadImg(formData.idCardImgList.concat(formData.licenseImgList));
|
||||
if (picUploadResult) {
|
||||
}
|
||||
uni.showToast({
|
||||
title: '保存成功',
|
||||
icon: 'success',
|
||||
mask: true
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
|
@ -0,0 +1,209 @@
|
|||
<template>
|
||||
<view class="margin-bottom-lg">
|
||||
<!-- 顶部操作条 -->
|
||||
<cu-custom :bgColor="'bg-main-color'" :isBack="true">
|
||||
<block slot="backText">返回</block>
|
||||
<block slot="content">申请入驻平台运营商</block>
|
||||
</cu-custom>
|
||||
<view class="padding description">
|
||||
欢迎入驻城市运营商,我们在运营全国城市区县、物业、社区、街道等等的C客户端提供包含配送、安装、维修、保养、家政、家具等全面的家居上门服务,以及提供当地服务商、经销商、当地商场、平台的配套售后服务。诚挚邀请您加入所在城市的运营,服务规划行业市场!
|
||||
</view>
|
||||
<view class="padding bg-white">
|
||||
<radio-group @change="changeOperatorType">
|
||||
<view class="flex justify-between align-center">
|
||||
<view class="flex justify-start">
|
||||
<view class="cu-avatar round middle-avatar first-avatar">
|
||||
<text class="cuIcon-friendfill"></text>
|
||||
</view>
|
||||
<view class="margin-left-sm flex-column-around">
|
||||
<view>具备多年经营基础</view>
|
||||
<view>申请入驻社区运营</view>
|
||||
</view>
|
||||
</view>
|
||||
<radio class="main-color" value="community" />
|
||||
</view>
|
||||
<view class="flex justify-between align-center margin-top-sm">
|
||||
<view class="flex justify-start">
|
||||
<view class="cu-avatar round middle-avatar second-avatar">
|
||||
<text class="cuIcon-group_fill"></text>
|
||||
</view>
|
||||
<view class="margin-left-sm flex-column-around">
|
||||
<view>具有良好业务开拓能力</view>
|
||||
<view>申请入驻城市区域营业</view>
|
||||
</view>
|
||||
</view>
|
||||
<radio class="main-color" value="cityArea" />
|
||||
</view>
|
||||
<view class="flex justify-between align-center margin-top-sm">
|
||||
<view class="flex justify-start">
|
||||
<view class="cu-avatar round middle-avatar third-avatar">
|
||||
<text class="cuIcon-activityfill"></text>
|
||||
</view>
|
||||
<view class="margin-left-sm flex-column-around">
|
||||
<view>具有业务团队及管理经营能力</view>
|
||||
<view>申请入驻城市营业</view>
|
||||
</view>
|
||||
</view>
|
||||
<radio class="main-color" value="city" />
|
||||
</view>
|
||||
</radio-group>
|
||||
</view>
|
||||
<view class="padding-sm bg-white">
|
||||
<view class="solid radius padding-bottom">
|
||||
<view class="text-xl text-black text-center">
|
||||
<text class="float-info padding-lr bg-white">申请信息</text>
|
||||
</view>
|
||||
<form @submit="submit">
|
||||
<view class="cu-form-group">
|
||||
<view class="title">您的姓名</view>
|
||||
<input name="name" placeholder="请输入姓名"></input>
|
||||
</view>
|
||||
<view class="cu-form-group">
|
||||
<view class="title">注册电话</view>
|
||||
<input name="phone" placeholder="请输入手机号"></input>
|
||||
</view>
|
||||
<view class="cu-form-group">
|
||||
<view class="title">申请城市</view>
|
||||
<input name="city" placeholder="请输入城市名"></input>
|
||||
</view>
|
||||
<view class="cu-form-group">
|
||||
<view class="title">验证码</view>
|
||||
<input name="identifyCode" placeholder="请输入验证码"></input>
|
||||
<button class='cu-btn bg-main-color shadow'>获取验证码</button>
|
||||
</view>
|
||||
<view class="cu-form-group">
|
||||
<view class="title">关联信息</view>
|
||||
<input name="comments" placeholder="请输入入驻关联信息备注"></input>
|
||||
</view>
|
||||
<view class="cu-form-group">
|
||||
<view>
|
||||
<checkbox style="transform:scale(0.7)" class="main-color" :value="agreeContract" :checked="agreeContract"
|
||||
@click="changeAgreeContract">
|
||||
</checkbox>
|
||||
<text class="margin-left-xs" @click="showContract">合同同意书链接</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="margin-lr-sm">
|
||||
<button class="bg-main-color long-btn" form-type="submit">提交</button>
|
||||
</view>
|
||||
</form>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
operatorType: '',
|
||||
agreeContract: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
changeOperatorType(e) {
|
||||
this.operatorType = e.detail.value;
|
||||
},
|
||||
changeAgreeContract() {
|
||||
this.agreeContract = !this.agreeContract;
|
||||
},
|
||||
showContract() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/my/contract'
|
||||
})
|
||||
},
|
||||
validateForm(confirmFormData) {
|
||||
let formInfoValid = Boolean(confirmFormData.name) &&
|
||||
Boolean(confirmFormData.phone) &&
|
||||
Boolean(confirmFormData.city) &&
|
||||
Boolean(confirmFormData.identifyCode) &&
|
||||
Boolean(confirmFormData.comments);
|
||||
if (!formInfoValid) {
|
||||
uni.showToast({
|
||||
title: '请填写完整信息',
|
||||
icon: 'none',
|
||||
mask: true
|
||||
})
|
||||
} else if (!Boolean(confirmFormData.operatorType)) {
|
||||
uni.showToast({
|
||||
title: '请选择入驻运营商类型',
|
||||
icon: 'none',
|
||||
mask: true
|
||||
});
|
||||
formInfoValid = false;
|
||||
} else if (!confirmFormData.agreeContract) {
|
||||
uni.showToast({
|
||||
title: '请阅读并同意合同书',
|
||||
icon: 'none',
|
||||
mask: true
|
||||
})
|
||||
formInfoValid = false;
|
||||
}
|
||||
return formInfoValid;
|
||||
},
|
||||
submit(e) {
|
||||
let formData = e.detail.value;
|
||||
formData.operatorType = this.operatorType;
|
||||
formData.agreeContract = this.agreeContract;
|
||||
let formValid = this.validateForm(formData);
|
||||
console.log(formData);
|
||||
if (formValid) {
|
||||
uni.showToast({
|
||||
title: '保存成功',
|
||||
icon: 'success',
|
||||
mask: true
|
||||
})
|
||||
uni.navigateTo({
|
||||
url: '/pages/my/my-operator'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.description {
|
||||
line-height: 200%;
|
||||
color: #676666;
|
||||
}
|
||||
|
||||
.middle-avatar {
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
}
|
||||
|
||||
.middle-avatar [class*="cuIcon-"] {
|
||||
font-size: 53rpx !important;
|
||||
}
|
||||
|
||||
radio-group {
|
||||
display: unset;
|
||||
}
|
||||
|
||||
.first-avatar {
|
||||
background-image: linear-gradient(45deg, #Ff9700, #Ed1c24);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.second-avatar {
|
||||
background-image: linear-gradient(45deg, #0081ff, #1cbbb4);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.third-avatar {
|
||||
background-image: linear-gradient(45deg, #Ec008c, #6739b6);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.float-info {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
top: -18rpx;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.radius {
|
||||
border-radius: 37rpx;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<template>
|
||||
<view>
|
||||
<!-- 顶部操作条 -->
|
||||
<cu-custom :bgColor="'bg-main-color'" :isBack="true">
|
||||
<block slot="backText">返回</block>
|
||||
<block slot="content">合同书</block>
|
||||
</cu-custom>
|
||||
<view class="padding">合同书内容</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
<template>
|
||||
<view>
|
||||
<!-- 顶部操作条 -->
|
||||
<cu-custom :bgColor="'bg-main-color'" :isBack="true">
|
||||
<block slot="backText">返回</block>
|
||||
<block slot="content">编辑地址</block>
|
||||
</cu-custom>
|
||||
<!-- 地址信息form -->
|
||||
<view class="bg-white margin-top-sm">
|
||||
<form @submit="submit">
|
||||
<view class="cu-form-group">
|
||||
<view class="title">联系人</view>
|
||||
<input name="person2Contact" :value="formData.person2Contact"></input>
|
||||
</view>
|
||||
<view class="cu-form-group">
|
||||
<view class="title">手机号码</view>
|
||||
<input name="phone" :value="formData.phone"></input>
|
||||
</view>
|
||||
<!-- #ifndef H5 || APP-PLUS || MP-ALIPAY -->
|
||||
<view class="cu-form-group">
|
||||
<view class="title">地址选择</view>
|
||||
<picker mode="region" @change="regionChange" name="area" :value="formData.area">
|
||||
<view class="picker">
|
||||
{{formData.area[0]}},{{formData.area[1]}},{{formData.area[2]}}
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
<view class="cu-form-group">
|
||||
<view class="title">详细地址</view>
|
||||
<input name="address" :value="formData.address"></input>
|
||||
</view>
|
||||
<view class="cu-form-group margin-top">
|
||||
<view class="title">默认地址</view>
|
||||
<switch class="main-color radius" @change="isDefaultChange" :class="formData.isDefault?'checked':''"
|
||||
:checked="formData.isDefault?true:false" name="isDefault" :value="formData.isDefault"></switch>
|
||||
</view>
|
||||
<!-- 底部操作栏 -->
|
||||
<view class="cu-bar tabbar border shop fixed-bottom-bar">
|
||||
<button class="bg-main-color long-btn margin-lr-sm" form-type="submit">保存</button>
|
||||
</view>
|
||||
</form>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
formData: {
|
||||
id: 1,
|
||||
person2Contact: '卢翰',
|
||||
phone: '18928799765',
|
||||
area: ['广西壮族自治区', '梧桐洲', '藤县'],
|
||||
address: '同心镇同心村同心路88号',
|
||||
isDefault: true
|
||||
}
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
const addressInfo = JSON.parse(decodeURIComponent(options.addressInfo));
|
||||
this.fillForm(addressInfo);
|
||||
},
|
||||
methods: {
|
||||
fillForm(addressInfo) {
|
||||
this.formData = addressInfo ? addressInfo : this.formData;
|
||||
},
|
||||
regionChange(e) {
|
||||
this.formData.area = e.detail.value;
|
||||
},
|
||||
isDefaultChange(e) {
|
||||
this.formData.isDefault = e.detail.value;
|
||||
},
|
||||
validateForm(confirmFormData) {
|
||||
return Boolean(confirmFormData.person2Contact) &&
|
||||
Boolean(confirmFormData.phone) &&
|
||||
Boolean(confirmFormData.address);
|
||||
},
|
||||
submit(e) {
|
||||
const confirmFormData = e.detail.value;
|
||||
let formValid = this.validateForm(confirmFormData);
|
||||
if (formValid) {
|
||||
uni.showToast({
|
||||
title: '保存成功',
|
||||
icon: 'success',
|
||||
mask: true
|
||||
})
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '请填写完整信息',
|
||||
icon: 'none',
|
||||
mask: true
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
<template>
|
||||
<view>
|
||||
<!-- 顶部操作条 -->
|
||||
<cu-custom :bgColor="'bg-main-color'" :isBack="true">
|
||||
<block slot="backText">返回</block>
|
||||
<block slot="content">地址列表</block>
|
||||
</cu-custom>
|
||||
<!-- 地址列表 -->
|
||||
<view class="margin-bottom-lg">
|
||||
<view class="padding margin-lr-sm margin-top-sm bg-white flex justify-between align-center" v-for="(item, index) in myAddressList">
|
||||
<view>
|
||||
<view class="flex justify-start align-center">
|
||||
<view class='cu-tag bg-yellow margin-right-sm' v-if="item.isDefault">默认</view>
|
||||
<view class="text-gray">{{item.area}}</view>
|
||||
</view>
|
||||
<view class="text-lg margin-tb-sm">{{item.address}}</view>
|
||||
<view class="text-gray">
|
||||
<text class="margin-right">{{item.person2Contact}}</text>
|
||||
<text>{{item.phone}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="oper-column text-xl flex justify-end">
|
||||
<view class="cuIcon-edit padding-lr-xs padding-tb" @click="showAddressDetail(item)"></view>
|
||||
<view class="cuIcon-close padding-lr-xs padding-tb" @click="confirm2DelAddress(item, index)"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 模态框 -->
|
||||
<view class="cu-modal" :class="modalName=='delAddress'?'show':''">
|
||||
<view class="cu-dialog">
|
||||
<view class="padding-xl">
|
||||
是否删除该地址?
|
||||
</view>
|
||||
<view class="cu-bar bg-white">
|
||||
<view class="action margin-0 flex-sub text-black" @tap="hideModal">取消</view>
|
||||
<view class="action margin-0 flex-sub text-main-color solid-left" @tap="hideModal"
|
||||
@click="delAddress">确定</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<confirm-modal ref="confirmModal" :content="'是否确定删除?'" :confirm="delAddress.bind(this, 1)"></confirm-modal>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
myAddressList: [],
|
||||
modalName: '',
|
||||
delAddressInfo: {},
|
||||
delAddressIndex: 0
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
this.loadData();
|
||||
this.bindEvent();
|
||||
},
|
||||
onUnload() {
|
||||
this.offBindEvent();
|
||||
},
|
||||
methods: {
|
||||
async loadData() {
|
||||
this.myAddressList = await this.$api.data('myAddressList');
|
||||
},
|
||||
bindEvent() {
|
||||
uni.$on(this.$globalFun.CONFIRM, this.delAddress);
|
||||
},
|
||||
offBindEvent() {
|
||||
uni.$off(this.globalFun.CONFIRM);
|
||||
},
|
||||
showAddressDetail(addressInfo) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/my/edit-address?addressInfo=' + encodeURIComponent(JSON.stringify(addressInfo))
|
||||
})
|
||||
},
|
||||
confirm2DelAddress(addressInfo, index) {
|
||||
this.delAddressInfo = addressInfo;
|
||||
this.delAddressIndex = index;
|
||||
this.$refs.confirmModal.showModal();
|
||||
},
|
||||
delAddress() {
|
||||
this.myAddressList = this.myAddressList.slice(0, this.delAddressIndex).concat(this.myAddressList.slice(++this.delAddressIndex));
|
||||
},
|
||||
showModal(e) {
|
||||
this.modalName = typeof e === 'string' ? e : e.currentTarget.dataset.target
|
||||
},
|
||||
hideModal(e) {
|
||||
this.modalName = null
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
<template>
|
||||
<view>
|
||||
<!-- 顶部操作条 -->
|
||||
<cu-custom :bgColor="'bg-main-color'" :isBack="true">
|
||||
<block slot="backText">返回</block>
|
||||
<block slot="content">购物车</block>
|
||||
</cu-custom>
|
||||
<!-- 选购的商品列表 -->
|
||||
<view class="margin-lr-sm margin-top-sm margin-bottom-with-bar">
|
||||
<checkbox-group class="block" @change="checked2Buy($event)">
|
||||
<view class="margin-top-sm bg-white" v-for="(item, index0) in pickedProductList">
|
||||
<view class="cu-bar solid-bottom">
|
||||
<view class="action bar-first-action">
|
||||
<checkbox class='round margin-right main-color' :value="index0" :checked="allChecked">
|
||||
</checkbox>
|
||||
<text class="cuIcon-shopfill text-main-color"></text>
|
||||
{{item.shopName}}
|
||||
<view>
|
||||
<view class="cuIcon-right"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="margin-top-sm padding-lr">
|
||||
<product-picked v-for="(product, index1) in item.product" :product="product"
|
||||
:pickedList="product.pickedList" :numberBox="true">
|
||||
</product-picked>
|
||||
</view>
|
||||
</view>
|
||||
</checkbox-group>
|
||||
</view>
|
||||
<!-- 底部操作栏 -->
|
||||
<view class="cu-bar bg-white tabbar border shop fixed-bottom-bar">
|
||||
<view class="action left-grid">
|
||||
<view class="flex justify-start align-center checked-bar">
|
||||
<checkbox class='round margin-right main-color' @click="toggleCheckedAll"></checkbox>
|
||||
<view class="text-lg">全选</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="bg-main-color submit" @click="submit">提交订单</view>
|
||||
</view>
|
||||
<!-- 模态框 -->
|
||||
<view class="cu-modal" :class="modalName=='delProductModal'?'show':''">
|
||||
<view class="cu-dialog">
|
||||
<view class="padding-xl">
|
||||
是否删除该服务项或商品项?
|
||||
</view>
|
||||
<view class="cu-bar bg-white">
|
||||
<view class="action margin-0 flex-sub text-black" @tap="hideModal">取消</view>
|
||||
<view class="action margin-0 flex-sub text-main-color solid-left" @tap="hideModal"
|
||||
@click="delPickedSpec">确定</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import productPicked from '@/components/goods-card/product-picked.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
productPicked
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pickedProductList: [],
|
||||
modalName: '',
|
||||
curPickedSpec: {},
|
||||
checkedIndexList: [],
|
||||
allChecked: false
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
this.loadData();
|
||||
this.bindEvent();
|
||||
},
|
||||
onUnload() {
|
||||
this.offBindEvent();
|
||||
},
|
||||
methods: {
|
||||
async loadData() {
|
||||
this.pickedProductList = await this.$api.data('pickedProductList');
|
||||
},
|
||||
bindEvent() {
|
||||
uni.$on('changePickedNum', this.changePickedNum);
|
||||
},
|
||||
offBindEvent() {
|
||||
uni.$off('changePickedNum');
|
||||
},
|
||||
changePickedNum(curNum, curItem) {
|
||||
if (curNum === 0) {
|
||||
this.showModal('delProductModal');
|
||||
this.curPickedSpec = curItem;
|
||||
}
|
||||
},
|
||||
delPickedSpec() {
|
||||
let indexPathArr = this.curPickedSpec.indexPath.split("-");
|
||||
let shopIndex = Number(indexPathArr[0]);
|
||||
let productIndex = Number(indexPathArr[1]);
|
||||
let specIndex = Number(indexPathArr[2]);
|
||||
|
||||
// 获取对应商铺下的对应产品选购的规格List
|
||||
let curPickedList = this.pickedProductList[shopIndex].product[productIndex].pickedList;
|
||||
// 判断curPickedList是否只有一个元素,只有一个元素则需要删除整个商品或服务
|
||||
if (curPickedList.length === 1) {
|
||||
let curProductList = this.pickedProductList[shopIndex].product;
|
||||
// 判断curProductList是否只有一个元素,只有一个元素则需要删除整个商铺信息
|
||||
if (curProductList.length === 1) {
|
||||
this.pickedProductList = this.delPickedItem(this.pickedProductList, shopIndex);
|
||||
} else {
|
||||
curProductList = this.delPickedItem(curProductList, productIndex);
|
||||
this.pickedProductList[shopIndex].product = curProductList;
|
||||
}
|
||||
}
|
||||
curPickedList = this.delPickedItem(curPickedList, specIndex);
|
||||
this.pickedProductList[shopIndex].product[productIndex].pickedList = curPickedList;
|
||||
},
|
||||
delPickedItem(list, index) {
|
||||
// 判断待删除的元素是否为List中的最后一个元素,不是的话需要调整待删元素后面所有元素的indexPath属性
|
||||
if (index !== list.length - 1) {
|
||||
for (let i = index + 1; i < list.length; i++) {
|
||||
let lastSplitIndex = Number(list[i].indexPath.lastIndexOf("-"));
|
||||
let oldIndex = list[i].indexPath.slice(++lastSplitIndex);
|
||||
list[i].indexPath = list[i].indexPath.slice(0, lastSplitIndex) + (Number(oldIndex) - 1);
|
||||
}
|
||||
}
|
||||
// 删除指定下标的元素并返回结果List
|
||||
return list.slice(0, index).concat(list.slice(index + 1));
|
||||
},
|
||||
showModal(e) {
|
||||
this.modalName = typeof e === 'string' ? e : e.currentTarget.dataset.target
|
||||
},
|
||||
hideModal(e) {
|
||||
this.modalName = null
|
||||
},
|
||||
checked2Buy(e) {
|
||||
this.checkedIndexList = e.detail.value;
|
||||
},
|
||||
toggleCheckedAll() {
|
||||
this.allChecked = !this.allChecked;
|
||||
},
|
||||
submit() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/order/order-detail'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.fixed-bottom-bar .left-grid {
|
||||
width: 50% !important;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fixed-bottom-bar .checked-bar {
|
||||
padding-left: 15%;
|
||||
}
|
||||
|
||||
.bar-first-action {
|
||||
margin-left: unset !important;
|
||||
padding-left: 23rpx;
|
||||
font-size: 30rpx !important;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,189 @@
|
|||
<template>
|
||||
<view>
|
||||
<!-- 顶部操作条 -->
|
||||
<cu-custom :bgColor="'bg-main-color'" :isBack="true">
|
||||
<block slot="backText">返回</block>
|
||||
<block slot="content">{{myOperator.level.name}}运营商</block>
|
||||
</cu-custom>
|
||||
<view class="margin-top-sm margin-lr-sm padding bg-white name-card shadow-warp">
|
||||
<!-- 个人名片 -->
|
||||
<horizontal-name-card :avatarWidth="'130rpx'" :avatarHeight="'130rpx'" :avatarPubClass="'round'"
|
||||
:vCard="myOperator.myInfo"></horizontal-name-card>
|
||||
<!-- 实名及公告图标 -->
|
||||
<view class="flex justify-end oper-bar">
|
||||
<view class="text-center margin-right-sm" @click="showCertificationForm">
|
||||
<view class="cuIcon-profilefill text-yellow"></view>
|
||||
<view class="text-xs">实名认证</view>
|
||||
</view>
|
||||
<view class="text-center">
|
||||
<view class="cuIcon-notice"></view>
|
||||
<view class="text-xs">公告</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 团队人员统计 -->
|
||||
<view class="cu-list grid no-border col-4 solid-top margin-top-sm">
|
||||
<view class="cu-item">
|
||||
<view class="margin-bottom-xs">客户数</view>
|
||||
<view class="text-red">{{myOperator.customerNums}}</view>
|
||||
</view>
|
||||
<view class="cu-item">
|
||||
<view class="margin-bottom-xs">本月绑定</view>
|
||||
<view class="text-red">{{myOperator.customerBindCurMonth}}</view>
|
||||
</view>
|
||||
<view class="cu-item solid-left">
|
||||
<view class="margin-bottom-xs">团队</view>
|
||||
<view class="text-red">{{myOperator.teamNums}}</view>
|
||||
</view>
|
||||
<view class="cu-item">
|
||||
<view class="margin-bottom-xs">本月绑定</view>
|
||||
<view class="text-red">{{myOperator.teamBindCurMonth}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 团队订单统计 -->
|
||||
<view class="margin-lr-sm margin-top-sm padding bg-white">
|
||||
<view class="cu-list grid no-border col-4">
|
||||
<view class="cu-item" v-for="(item, index) in myOperator.orderAnalyse">
|
||||
<view class="margin-bottom-xs">{{item.title}}</view>
|
||||
<view class="text-red" v-if="item.unit === 'yuan'">
|
||||
¥{{item.num}}
|
||||
</view>
|
||||
<view v-else class="text-red">
|
||||
{{item.num}}{{item.unit}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 操作栏 -->
|
||||
<view class="bg-white padding margin-top-sm fixed-bottom-bar">
|
||||
<view class="flex flex-wrap justify-between">
|
||||
<view class="basis-df margin-tb-sm" v-for="(item, index) in operBtn">
|
||||
<button class="cu-btn long-btn shadow bg-main-color light" :data-cur="item.code"
|
||||
@click="doSomething">{{item.name}}</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 屏蔽设置 模态框 -->
|
||||
<view class="cu-modal" :class="isShowShieldSet?'show':''">
|
||||
<view class="cu-dialog">
|
||||
<view class="cu-bar bg-white justify-end">
|
||||
<view class="content">屏蔽设置</view>
|
||||
<view class="action" @tap="hideModal">
|
||||
<text class="cuIcon-close text-bold text-red"></text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="padding-xl">
|
||||
<view class="margin-bottom">对所有客户屏蔽有竞争关系区域的服务和商品类目</view>
|
||||
<view>
|
||||
<text class="margin-right">屏蔽请勾选: </text>
|
||||
<checkbox style="transform:scale(0.7)" class="round sm main-color" :value="agreeShield" :checked="agreeShield"
|
||||
@click="changeAgreeShield">
|
||||
</checkbox>
|
||||
</view>
|
||||
</view>
|
||||
<view class="cu-bar bg-white">
|
||||
<view class="action margin-0 flex-sub text-black" @tap="hideModal">取消</view>
|
||||
<view class="action margin-0 flex-sub text-main-color solid-left" @tap="hideModal"
|
||||
@click="confirmShield">确定</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import horizontalNameCard from '@/components/common-card/horizontal-name-card.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
horizontalNameCard
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
myOperator: {},
|
||||
operBtn: [{
|
||||
code: 'ShieldSet',
|
||||
name: '屏蔽设置'
|
||||
}, {
|
||||
code: '',
|
||||
name: '加价申请'
|
||||
}, {
|
||||
code: 'showTeamMembers',
|
||||
name: '查看团队'
|
||||
}, {
|
||||
code: '',
|
||||
name: '查看客户'
|
||||
}, {
|
||||
code: '',
|
||||
name: '添加团队'
|
||||
}, {
|
||||
code: '',
|
||||
name: '审批团队'
|
||||
}],
|
||||
agreeShield: false,
|
||||
isShowShieldSet: false
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
this.loadData();
|
||||
},
|
||||
methods: {
|
||||
async loadData() {
|
||||
this.myOperator = await this.$api.data('myOperator');
|
||||
},
|
||||
hideModal(e) {
|
||||
this.isShowShieldSet = false
|
||||
},
|
||||
doSomething(e) {
|
||||
const cur = e.currentTarget.dataset.cur;
|
||||
switch (cur) {
|
||||
case 'ShieldSet':
|
||||
this.isShowShieldSet = !this.isShowShieldSet;
|
||||
break;
|
||||
case 'showTeamMembers':
|
||||
uni.navigateTo({
|
||||
url: '/pages/my/my-team-member'
|
||||
})
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
changeAgreeShield() {
|
||||
this.agreeShield = !this.agreeShield;
|
||||
},
|
||||
confirmShield(e) {},
|
||||
showCertificationForm() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/my/Certification'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.cu-list.grid.no-border>.solid-left.cu-item:after {
|
||||
border-left: 1rpx solid rgba(0, 0, 0, 0.1);
|
||||
border-left-width: 0.5px;
|
||||
border-left-style: solid;
|
||||
border-left-color: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.name-card {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.name-card .oper-bar {
|
||||
position: absolute;
|
||||
top: 20rpx;
|
||||
right: 20rpx;
|
||||
font-size: 40rpx;
|
||||
}
|
||||
|
||||
.long-btn {
|
||||
width: 90%;
|
||||
margin-left: 5%;
|
||||
margin-right: 5%;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
<template>
|
||||
<view>
|
||||
<!-- 顶部操作条 -->
|
||||
<cu-custom :bgColor="'bg-main-color'" :isBack="true">
|
||||
<block slot="backText">返回</block>
|
||||
<block slot="content">我的订单</block>
|
||||
</cu-custom>
|
||||
<!-- tab -->
|
||||
<view class="sticky-bar" :style="[{top: stickyTop + 'px'}]">
|
||||
<scroll-view scroll-x class="bg-white nav text-center" :scroll-with-animation="true"
|
||||
:scroll-left="scrollLeft">
|
||||
<view class="cu-item" :class="index==tabCur?'text-main-color cur':''"
|
||||
v-for="(item,index) in tabHeaderList" :key="index" @tap="tabSelect" :data-id="index">
|
||||
{{item.name}}
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- tab content -->
|
||||
<view class="margin-lr-sm margin-bottom-xl">
|
||||
<view class="margin-top-sm padding-bottom-sm bg-white" v-for="(shopOrder, index) in myOrders">
|
||||
<view class="cu-bar solid-bottom">
|
||||
<view class="action bar-first-action">
|
||||
<text class="cuIcon-shopfill text-main-color"></text>
|
||||
{{shopOrder.shopName}}
|
||||
<view>
|
||||
<view class="cuIcon-right"></view>
|
||||
</view>
|
||||
</view>
|
||||
<view class='cu-tag bg-yellow radius margin-right-sm' v-if="shopOrder.mainProcess === 'ordersServing'" @click="showServDetail(shopOrder)">查看订单详情</view>
|
||||
</view>
|
||||
<view class="padding-lr">
|
||||
<view class="margin-top-sm">
|
||||
<product-picked :product="shopOrder.product" :pickedList="shopOrder.product.pickedList">
|
||||
</product-picked>
|
||||
</view>
|
||||
<view class="flex justify-end align-end padding-bottom-sm">
|
||||
<view class="margin-right-sm"><text>总价</text><text class="text-price text-red">1049.00</text>
|
||||
</view>
|
||||
<view class="margin-right-sm"><text>优惠</text><text class="text-price text-red">50.00</text>
|
||||
</view>
|
||||
<view class="text-lg"><text>需付款</text><text
|
||||
class="text-price text-red text-lg text-bold">999.00</text></view>
|
||||
</view>
|
||||
<view v-if="orderType === 'servOrder'" class="padding-tb-sm flex justify-end oper-bar">
|
||||
<button v-if="shopOrder.subProcessStatus <= 4 && shopOrder.mainProcess !== 'ordersWait2Serv'"
|
||||
class="cu-btn line-black margin-right-sm">取消订单</button>
|
||||
<button v-if="shopOrder.subProcessStatus >= 1 && shopOrder.subProcessStatus <= 2"
|
||||
class="cu-btn line-black margin-right-sm">催单</button>
|
||||
<button v-if="shopOrder.subProcessStatus >= 2 && shopOrder.subProcessStatus <= 3"
|
||||
class="cu-btn line-black margin-right-sm">撤换师傅</button>
|
||||
<button v-if="shopOrder.subProcessStatus >= 1 && shopOrder.subProcessStatus <= 3"
|
||||
class="cu-btn line-black margin-right-sm">加价</button>
|
||||
<button v-if="shopOrder.subProcessStatus === 5"
|
||||
class="cu-btn line-black margin-right-sm">申请售后</button>
|
||||
<button v-if="shopOrder.subProcessStatus >= 4 && shopOrder.subProcessStatus <= 5"
|
||||
class="cu-btn line-black margin-right-sm">评价</button>
|
||||
<button v-if="shopOrder.subProcessStatus === 6"
|
||||
class="cu-btn line-black margin-right-sm">查看进度</button>
|
||||
<button v-if="shopOrder.payStatus === 0" class="cu-btn bg-main-color">付款</button>
|
||||
</view>
|
||||
<view v-if="orderType === 'servOrder' && shopOrder.subProcessStatus === 4"
|
||||
class="padding-tb-sm solid-top">
|
||||
<view>师傅已提交完成,请验收。</view>
|
||||
<view>服务保障权益期:</view>
|
||||
<view class="flex justify-between align-end">
|
||||
<view>{{shopOrder.finishOrder.finishWaitUntil}}</view>
|
||||
<view>
|
||||
<button v-if="shopOrder.finishOrder.finishStatus === 1"
|
||||
class="cu-btn sm bg-yellow margin-right-sm"
|
||||
@click="updateFinisheStatus(2, index)">已验收</button>
|
||||
<button v-if="shopOrder.finishOrder.finishStatus === 1"
|
||||
class="cu-btn sm bg-yellow margin-right-sm"
|
||||
@click="updateFinisheStatus(-1, index)">拒绝完单</button>
|
||||
<button v-if="shopOrder.finishOrder.finishStatus === 2"
|
||||
class="cu-btn sm bg-yellow margin-right-sm" disabled type="">已完成验收</button>
|
||||
<button v-if="shopOrder.finishOrder.finishStatus === -1"
|
||||
class="cu-btn sm bg-yellow margin-right-sm" disabled type="">已拒绝完单</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
v-if="orderType === 'servOrder' && (shopOrder.subProcessStatus === 2 || shopOrder.subProcessStatus === 3)"
|
||||
class="padding-tb-sm solid-top">
|
||||
<view>约定服务时间:</view>
|
||||
<view class="flex justify-between align-end">
|
||||
<view>{{shopOrder.agreedServTime.time}}</view>
|
||||
<view>
|
||||
<button v-if="shopOrder.agreedServTime.customerAgreeStatus === 1"
|
||||
class="cu-btn sm bg-yellow margin-right-sm"
|
||||
@click="updateAgreeStatus(2, index)">同意</button>
|
||||
<button v-if="shopOrder.agreedServTime.customerAgreeStatus === 1"
|
||||
class="cu-btn sm bg-yellow margin-right-sm"
|
||||
@click="updateAgreeStatus(-1, index)">不同意</button>
|
||||
<button v-if="shopOrder.agreedServTime.customerAgreeStatus === 2"
|
||||
class="cu-btn sm bg-yellow margin-right-sm" disabled type="">已同意</button>
|
||||
<button v-if="shopOrder.agreedServTime.customerAgreeStatus === -1"
|
||||
class="cu-btn sm bg-yellow margin-right-sm" disabled type="">已否决</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else-if="orderType === 'servOrder' && shopOrder.subProcessStatus === 1"
|
||||
class="padding-tb-sm solid-top text-orange">
|
||||
路途遥远?服务内容稍难?时间紧迫?您可以试试追加赏金,重金之下必有勇夫噢!
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import productPicked from '@/components/goods-card/product-picked.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
productPicked
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
scrollLeft: 0,
|
||||
tabCur: 0,
|
||||
tabHeaderList: [],
|
||||
orderType: '',
|
||||
myOrders: [],
|
||||
stickyTop: this.CustomBar
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
if (Boolean(options) && Boolean(options.tabInfo)) {
|
||||
let tabInfo = JSON.parse(decodeURIComponent(options.tabInfo));
|
||||
if (tabInfo.tabCur != null || tabInfo.tabCur != undefined) {
|
||||
this.tabCur = tabInfo.tabCur;
|
||||
}
|
||||
if (tabInfo.tabCur != null || tabInfo.tabCur != undefined) {
|
||||
this.orderType = tabInfo.orderType;
|
||||
}
|
||||
if (Array.isArray(tabInfo.tabHeaderList) && tabInfo.tabHeaderList.length > 0) {
|
||||
this.tabHeaderList = tabInfo.tabHeaderList;
|
||||
this.loadData(this.tabHeaderList[this.tabCur].type);
|
||||
}
|
||||
console.log(tabInfo)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async loadData(mainProcess) {
|
||||
// 真实对接口的时候使用
|
||||
// this.myOrders = await this.$api.data(this.orderType, mainProcess);
|
||||
this.myOrders = await this.$api.data(mainProcess);
|
||||
},
|
||||
tabSelect(e) {
|
||||
this.tabCur = e.currentTarget.dataset.id;
|
||||
this.scrollLeft = (e.currentTarget.dataset.id - 1) * 60
|
||||
this.loadData(this.tabHeaderList[this.tabCur].type);
|
||||
},
|
||||
updateAgreeStatus(status, index) {
|
||||
this.myOrders[index].agreedServTime.customerAgreeStatus = status;
|
||||
},
|
||||
updateFinisheStatus(status, index) {
|
||||
this.myOrders[index].finishOrder.finishStatus = status;
|
||||
},
|
||||
showServDetail(shopOrder) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/my/serv-detail'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.bar-first-action {
|
||||
margin-left: unset !important;
|
||||
padding-left: 40rpx;
|
||||
font-size: 30rpx !important;
|
||||
}
|
||||
|
||||
.cu-btn.sm {
|
||||
padding: 0 20rpx;
|
||||
font-size: 23rpx;
|
||||
height: 48rpx;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
<template>
|
||||
<view>
|
||||
<!-- 顶部操作条 -->
|
||||
<cu-custom :bgColor="'bg-main-color'" :isBack="true">
|
||||
<block slot="backText">返回</block>
|
||||
<block slot="content">查看团队({{myOperaMembers.totalMembers}})</block>
|
||||
</cu-custom>
|
||||
<!-- 团队成员信息 -->
|
||||
<view class="margin-top-sm margin-lr-sm padding bg-white name-card shadow-warp" v-for="(member, index) in myOperaMembers.members">
|
||||
<!-- 个人名片 -->
|
||||
<horizontal-name-card :avatarWidth="'130rpx'" :avatarHeight="'130rpx'" :avatarPubClass="'round'"
|
||||
:vCard="member"></horizontal-name-card>
|
||||
<!-- 实名及公告图标 -->
|
||||
<view class="flex justify-end oper-bar">
|
||||
<view class="text-center margin-right-sm" @click="showCertificationForm">
|
||||
<view class="cuIcon-phone"></view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 人员下辖团队统计 -->
|
||||
<view class="cu-list grid no-border col-4 solid-top margin-top-sm">
|
||||
<view class="cu-item">
|
||||
<view class="margin-bottom-xs">客户数</view>
|
||||
<view class="text-red">{{member.customerNums}}</view>
|
||||
</view>
|
||||
<view class="cu-item">
|
||||
<view class="margin-bottom-xs">本月绑定</view>
|
||||
<view class="text-red">{{member.customerBindCurMonth}}</view>
|
||||
</view>
|
||||
<view class="cu-item solid-left">
|
||||
<view class="margin-bottom-xs">团队</view>
|
||||
<view class="text-red">{{member.teamNums}}</view>
|
||||
</view>
|
||||
<view class="cu-item">
|
||||
<view class="margin-bottom-xs">本月绑定</view>
|
||||
<view class="text-red">{{member.teamBindCurMonth}}</view>
|
||||
</view>
|
||||
<view class="cu-item" v-for="(item, index) in member.orderAnalyse">
|
||||
<view class="margin-bottom-xs">{{item.title}}</view>
|
||||
<view class="text-red" v-if="item.unit === 'yuan'">
|
||||
¥{{item.num}}
|
||||
</view>
|
||||
<view v-else class="text-red">
|
||||
{{item.num}}{{item.unit}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import horizontalNameCard from '@/components/common-card/horizontal-name-card.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
horizontalNameCard
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
myOperaMembers: {}
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
this.loadData();
|
||||
},
|
||||
methods: {
|
||||
async loadData() {
|
||||
this.myOperaMembers = await this.$api.data('myOperaMembers');
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.name-card {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.name-card .oper-bar {
|
||||
position: absolute;
|
||||
top: 20rpx;
|
||||
right: 20rpx;
|
||||
font-size: 40rpx;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
<template>
|
||||
<view>
|
||||
<!-- 顶部操作条 -->
|
||||
<cu-custom :bgColor="'bg-main-color'" :isBack="true">
|
||||
<block slot="backText">返回</block>
|
||||
<block slot="content">服务订单详情</block>
|
||||
</cu-custom>
|
||||
<!-- 任务进度跟踪 -->
|
||||
<view class="bg-white margin-lr-sm padding-lr padding-bottom margin-top-sm">
|
||||
<uni-collapse v-model="value">
|
||||
<uni-collapse-item :open="true">
|
||||
<template v-slot:title>
|
||||
<view class="cu-bar">
|
||||
<view class="action bar-first-action">
|
||||
<text class="cuIcon-titles text-main-color"></text> 任务进度跟踪
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<view class="cu-timeline">
|
||||
<view class="cu-item text-main-color" v-for="(item, index) in servDetail.taskTraceLine">
|
||||
<view class="content shadow-blur" :class="index === 0 ? 'bg-main-color light' : 'bg-gray'">
|
||||
<text class="margin-right">{{item.time}}</text>
|
||||
<text>{{item.action}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</uni-collapse-item>
|
||||
</uni-collapse>
|
||||
</view>
|
||||
<!-- 服务单概况 -->
|
||||
<view class="bg-white margin-lr-sm margin-top-sm padding">
|
||||
<view class="flex align-center">
|
||||
<text class="text-xl margin-right">{{servDetail.mainServOrder.servTitle}}</text>
|
||||
<view class='cu-tag bg-purple radius light margin-right-sm'>服务中</view>
|
||||
</view>
|
||||
<view class="margin-top-sm">
|
||||
<view v-for="(item, index) in servDetail.mainServOrder.orderTag" class='cu-tag radius margin-right-sm'>
|
||||
{{item}}</view>
|
||||
</view>
|
||||
<view class="margin-top-sm">
|
||||
<text class="cuIcon-location text-main-color margin-right-xs"></text>
|
||||
<text>{{servDetail.mainServOrder.address}}</text>
|
||||
</view>
|
||||
<view class="margin-top-sm">
|
||||
<text class="cuIcon-people text-main-color margin-right-xs"></text>
|
||||
<text>{{servDetail.mainServOrder.person2Contact.name}}</text>
|
||||
<text>{{servDetail.mainServOrder.person2Contact.phone}}</text>
|
||||
</view>
|
||||
<view class="margin-top-sm">
|
||||
<text class="cuIcon-time text-main-color margin-right-xs"></text>
|
||||
<text>预约时间:{{servDetail.mainServOrder.bookTime}}</text>
|
||||
</view>
|
||||
<view class="margin-top-sm">
|
||||
<text class="cuIcon-time text-main-color margin-right-xs"></text>
|
||||
<text>排单时间:{{servDetail.mainServOrder.boodTime}}</text>
|
||||
</view>
|
||||
<view class="margin-top-sm">
|
||||
<text class="cuIcon-time text-main-color margin-right-xs"></text>
|
||||
<text>上门时间:{{servDetail.mainServOrder.doorTime}}</text>
|
||||
</view>
|
||||
<view class="margin-top-sm">
|
||||
<text class="cuIcon-moneybag text-main-color margin-right-xs"></text>
|
||||
<text>任务金额:</text>
|
||||
<text class="text-price">{{servDetail.mainServOrder.taskPrice}}</text>
|
||||
</view>
|
||||
<view class="margin-top-xs text-sm text-gray"
|
||||
v-for="(item, index) in servDetail.mainServOrder.gratuityRecord">
|
||||
追加费用:<text class="text-price">{{item.price}}</text>[{{item.type}}]
|
||||
</view>
|
||||
</view>
|
||||
<!-- 待服务列 -->
|
||||
<view class="bg-white margin-lr-sm padding-lr padding-bottom margin-top-sm">
|
||||
<view class="cu-bar solid-bottom">
|
||||
<view class="action bar-first-action">
|
||||
<text class="cuIcon-titles text-main-color"></text> 商品信息
|
||||
</view>
|
||||
</view>
|
||||
<view class="margin-top-sm">
|
||||
<product-picked :product="servDetail.product" :pickedList="servDetail.product.pickedList" :columnTitleArr="servingColumnHeaders" :showToServNum="true"></product-picked>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 完成记录 -->
|
||||
<view class="bg-white margin-lr-sm padding-lr padding-bottom margin-top-sm" v-for="(item, index) in servDetail.finishRecord">
|
||||
<view class="cu-bar solid-bottom">
|
||||
<view class="action bar-first-action">
|
||||
<text class="cuIcon-titles text-main-color"></text> 完成记录({{item.finishList.length}})
|
||||
</view>
|
||||
<view class='cu-tag bg-purple radius light margin-right-sm'>{{item.finishTime}}</view>
|
||||
</view>
|
||||
<view class="margin-top-sm">
|
||||
<product-picked :pickedList="item.finishList" :columnTitleArr="servedColumnHeaders" :showToServNum="true"></product-picked>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 订单编码和时间 -->
|
||||
<view class="bg-white margin-top-sm padding margin-lr-sm margin-bottom-with-bar">
|
||||
<view>订单编码:{{servDetail.serialCode}}</view>
|
||||
<view class="margin-top-xs">订单时间:{{servDetail.createTime}}</view>
|
||||
</view>
|
||||
<!-- 底部操作栏 -->
|
||||
<view class="cu-bar bg-white tabbar border shop fixed-bottom-bar">
|
||||
<view class="action">
|
||||
<view class="cuIcon-list"></view> 订单管理
|
||||
</view>
|
||||
<view class="action">
|
||||
<view class="cuIcon-mail">
|
||||
<view class="cu-tag badge" v-if="servDetail.talkMsgNum > 0">{{servDetail.talkMsgNum}}</view>
|
||||
</view>
|
||||
发送急报
|
||||
</view>
|
||||
<view class="bg-main-color submit">立即上门</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import productPicked from '@/components/goods-card/product-picked.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
productPicked
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
value: ['0'],
|
||||
servDetail: {},
|
||||
finishRecord4Show: [],
|
||||
servingColumnHeaders: ['购买型号', '购买量', '待服务'],
|
||||
servedColumnHeaders: ['购买型号', '购买量', '已服务']
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
this.loadData();
|
||||
},
|
||||
methods: {
|
||||
async loadData() {
|
||||
this.servDetail = await this.$api.data('servDetail');
|
||||
this.finishList4Show = this.servDetail.finishRecord;
|
||||
for (let i = 0; i < this.finishList4Show.length; i++) {
|
||||
let finishList = this.finishList4Show[i].finishList;
|
||||
for (let j = 0; j < finishList.length; j++) {
|
||||
finishList[j].secondColumnNum = finishList[j].servedNum;
|
||||
}
|
||||
this.finishList4Show[i].finishList = finishList;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.bar-first-action {
|
||||
margin-left: unset !important;
|
||||
font-size: 30rpx !important;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -25,11 +25,24 @@
|
|||
class="cuIcon-question">选择的为期望上门时间,稍后工程师将与你确认具体上门时间</text></view>
|
||||
</view>
|
||||
<!-- 选购的商品列表 -->
|
||||
<view class="margin-lr-sm margin-top-sm bg-white padding">
|
||||
<view class="solid-bottom" v-for="(item, index) in pickedProductList">
|
||||
<view class="margin-lr-sm margin-top-sm bg-white">
|
||||
<view class="solid-top" v-for="(item, index0) in pickedProductList">
|
||||
<view class="cu-bar">
|
||||
<view class="action bar-first-action">
|
||||
<text class="cuIcon-shopfill text-main-color"></text>
|
||||
{{item.shopName}}
|
||||
<view><view class="cuIcon-right"></view></view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="margin-top-sm padding-lr">
|
||||
<product-picked :columnTitleArr="columnTitleArr" v-for="(product, index1) in item.product" :product="product" :pickedList="product.pickedList">
|
||||
</product-picked>
|
||||
</view>
|
||||
</view>
|
||||
<!-- <view class="solid-bottom" v-for="(item, index) in pickedProductList">
|
||||
<product-picked :columnTitleArr="columnTitleArr" :product="item.product" :pickedList="item.pickedList">
|
||||
</product-picked>
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
<!-- 支付方式 -->
|
||||
<view class="margin-lr-sm margin-top-sm bg-white padding">
|
||||
|
|
@ -78,7 +91,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import productPicked from '@/pages/order/product-picked.vue';
|
||||
import productPicked from '@/components/goods-card/product-picked.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
|
@ -121,4 +134,10 @@
|
|||
width: 55% !important;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.bar-first-action {
|
||||
margin-left: unset !important;
|
||||
padding-left: 40rpx;
|
||||
font-size: 30rpx !important;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,53 +0,0 @@
|
|||
<template>
|
||||
<view>
|
||||
<view class="bg-white">
|
||||
<horizontal-goods-card :ifShowServArea="true" :product="product"></horizontal-goods-card>
|
||||
<view class="flex justify-between margin-lr-sm margin-tb-sm">
|
||||
<view v-for="(title, index) in columnTitleArr">{{title}}</view>
|
||||
</view>
|
||||
<view class="margin-bottom-lg certern-height-with-scroll">
|
||||
<view class="flex justify-between margin-lr-sm margin-tb-sm" v-for="(item,index) in pickedList"
|
||||
:key="item.id">
|
||||
<view class='cu-tag padding line-main-color'>{{item.name}}</view>
|
||||
<view v-if="columnTitleArr.length === 2">{{item.pickedNum}}</view>
|
||||
<view v-else-if="columnTitleArr.length === 3" class="flex justify-end">
|
||||
<view>{{item.pickedNum}}</view>
|
||||
<view>{{item.toServNum}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import horizontalGoodsCard from '@/components/goods-card/horizontal-goods-card.vue';
|
||||
|
||||
export default {
|
||||
name: "product-picked",
|
||||
props: {
|
||||
product: {
|
||||
type: Object,
|
||||
default: []
|
||||
},
|
||||
pickedList: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
columnTitleArr: {
|
||||
type: Array,
|
||||
default: []
|
||||
}
|
||||
},
|
||||
components: {
|
||||
horizontalGoodsCard
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.certern-height-with-scroll {
|
||||
max-height: 300rpx;
|
||||
overflow: scroll;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -2,8 +2,9 @@
|
|||
<page-meta :page-style="'overflow:'+(ifShowPageMeta?'hidden':'visible')"></page-meta>
|
||||
<view>
|
||||
<!-- 顶部操作条 -->
|
||||
<cu-custom :bgColor="'bg-white'" :isBack="true">
|
||||
<block slot="backText">返回</block>
|
||||
<cu-custom :bgColor="'bg-white'" :isBack="true" :isBackHome="true" :homePageUrl="'/pages/index/index'">
|
||||
<!-- <block slot="backText">返回</block> -->
|
||||
<!-- <block slot="backHomeText">首页</block> -->
|
||||
<!-- <block slot="content">商品详情</block> -->
|
||||
</cu-custom>
|
||||
<!-- 导航栏 -->
|
||||
|
|
@ -107,8 +108,11 @@
|
|||
<view class="margin-lr-sm margin-top-sm padding bg-white">
|
||||
<view class="flex justify-between align-center">
|
||||
<view class="flex justify-start align-center">
|
||||
<view class="cu-avatar" :style="'background-image:url(' + shopInfo.avatarUrl + ');'"></view>
|
||||
<view class="margin-lr-sm text-lg text-black">{{shopInfo.name}}</view>
|
||||
<view class="cu-avatar round" :style="'background-image:url(' + shopInfo.avatarUrl + ');'"></view>
|
||||
<view class="content flex-sub margin-lr-sm">
|
||||
<view class="text-black">{{shopInfo.name}}</view>
|
||||
<uni-rate :size="15" :readonly="true" allow-half :value="shopInfo.totalScore" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="text-sm" @click="showShopDetail(shopInfo)">店铺查看<text class="text-bold text-gray cuIcon-right"></text></view>
|
||||
</view>
|
||||
|
|
@ -129,7 +133,7 @@
|
|||
<!-- <view class="action">
|
||||
<view class=" cuIcon-shop"></view> 店铺
|
||||
</view> -->
|
||||
<view class="action">
|
||||
<view class="action" @click="showCart">
|
||||
<view class="cuIcon-cart">
|
||||
<view class="cu-tag badge" v-if="totalPickCount > 0">{{totalPickCount}}</view>
|
||||
</view>
|
||||
|
|
@ -180,6 +184,9 @@
|
|||
this.loadData();
|
||||
this.bindEvent();
|
||||
},
|
||||
onUnload() {
|
||||
this.offBindEvent();
|
||||
},
|
||||
onReady() {
|
||||
this.productVideoContext = uni.createVideoContext('productVideo');
|
||||
},
|
||||
|
|
@ -201,6 +208,9 @@
|
|||
bindEvent() {
|
||||
uni.$on('product-detail_add2Cart', this.add2Cart);
|
||||
},
|
||||
offBindEvent() {
|
||||
uni.$off('product-detail_add2Cart');
|
||||
},
|
||||
chooseSpecs(item) {
|
||||
this.curProductSpecs = item;
|
||||
},
|
||||
|
|
@ -250,7 +260,13 @@
|
|||
},
|
||||
showShopDetail(shopInfo) {
|
||||
uni.navigateTo({
|
||||
url: '../product/shop-detail?shopInfo='+ encodeURIComponent(JSON.stringify(shopInfo))
|
||||
url: '../product/shop-detail?shopInfo=' + encodeURIComponent(JSON.stringify(shopInfo))
|
||||
});
|
||||
},
|
||||
showCart() {
|
||||
let myCartInfo = {};
|
||||
uni.navigateTo({
|
||||
url: '/pages/my/my-cart?myCartInfo=' + encodeURIComponent(JSON.stringify(myCartInfo))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -258,10 +274,6 @@
|
|||
</script>
|
||||
|
||||
<style scoped>
|
||||
.text-del {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.certern-height {
|
||||
height: 300rpx;
|
||||
overflow: hidden;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
<view>购买型号</view>
|
||||
<view>购买数量</view>
|
||||
</view>
|
||||
<view class="certern-height-with-scroll">
|
||||
<scroll-view class="certern-height-with-scroll" :scroll-y="true" :scroll-with-animation="true">
|
||||
<view class="flex justify-between margin-lr-sm margin-tb-sm" v-for="(item,index) in specsList"
|
||||
:key="item.id">
|
||||
<view class='cu-tag padding' :class="curSpec.id === item.id ? 'line-main-color' : 'line-default'"
|
||||
|
|
@ -25,7 +25,7 @@
|
|||
<uni-number-box :min="0" :max="item.maxPieces" :value="0" @change="changePiecesNum($event, index)">
|
||||
</uni-number-box>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<!-- 底部操作条 -->
|
||||
<view class="cu-bar bg-white tabbar border shop fixed-bottom-bar">
|
||||
|
|
@ -120,7 +120,6 @@
|
|||
.certern-height-with-scroll {
|
||||
height: 600rpx;
|
||||
margin-bottom: calc(100rpx - env(safe-area-inset-bottom)/2);
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
.main-container {
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
<template>
|
||||
<view>
|
||||
<!-- 顶部操作条 -->
|
||||
<cu-custom :bgColor="'bg-white'" :isBack="true">
|
||||
<cu-custom :bgColor="'bg-main-color'" :isBack="true">
|
||||
<block slot="backText">返回</block>
|
||||
<block slot="content">店铺主页</block>
|
||||
</cu-custom>
|
||||
<!-- 店铺介绍 -->
|
||||
<view class="bg-white padding">
|
||||
<view class="bg-white padding solid-bottom">
|
||||
<horizontal-name-card :vCard="shopInfo"></horizontal-name-card>
|
||||
</view>
|
||||
<!-- 店铺评分 -->
|
||||
<view class="bg-white padding text-sm padding-top-xs solid-bottom">
|
||||
<!-- <view class="bg-white padding text-sm padding-top-xs solid-bottom">
|
||||
<view class="flex justify-between">
|
||||
<text>总评分:<text class="text-red text-xl">{{shopInfo.totalScore}}</text> / 5.0分</text>
|
||||
<uni-rate :readonly="true" allow-half :value="shopInfo.totalScore" />
|
||||
|
|
@ -20,7 +20,7 @@
|
|||
<text>态度</text><text class="margin-lr-xs">{{shopInfo.attitudeScore}}</text>
|
||||
<text>技能</text><text class="margin-lr-xs">{{shopInfo.skillScore}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view> -->
|
||||
<!-- 店铺服务说明 -->
|
||||
<view class="padding bg-white text-sm">
|
||||
<view>服务类目:<text>{{shopInfo.servType}}</text></view>
|
||||
|
|
|
|||
|
|
@ -32,3 +32,8 @@ radio.main-color.checked .uni-radio-input {
|
|||
border-color: #0081ff !important;
|
||||
color: #ffffff !important;
|
||||
}
|
||||
|
||||
.oper-bar button:last-child {
|
||||
background-color: #0081ff;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
|
@ -10,6 +10,10 @@
|
|||
z-index: 98;
|
||||
}
|
||||
|
||||
.cu-bar.tabbar.border .action checkbox {
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.fixed-top-bar {
|
||||
position: fixed !important;
|
||||
z-index: 98;
|
||||
|
|
@ -21,3 +25,61 @@
|
|||
position: sticky;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.text-del {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.long-btn {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.flex-column-between {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.flex-column-around {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.cu-form-group .title {
|
||||
flex-basis: 23%;
|
||||
text-align: justify;
|
||||
padding-right: 30rpx;
|
||||
font-size: 30rpx;
|
||||
position: relative;
|
||||
height: 60rpx;
|
||||
line-height: 60rpx;
|
||||
}
|
||||
|
||||
.cu-form-group picker .picker {
|
||||
line-height: 100rpx;
|
||||
font-size: 28rpx;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.cu-form-group input {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #555;
|
||||
padding-right: 20rpx;
|
||||
}
|
||||
|
||||
.uni-forms-item__inner {
|
||||
display: flex !important;
|
||||
padding: 22rpx !important;
|
||||
border-top: 1rpx solid #eee !important;
|
||||
}
|
||||
|
||||
.is-input-border {
|
||||
border: none !important;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue