版本迭代

This commit is contained in:
yangdanqi 2022-04-23 23:13:29 +08:00
parent eec23581e1
commit a5aab460c6
41 changed files with 6120 additions and 918 deletions

16
App.vue
View File

@ -1,15 +1,22 @@
<script> <script>
import Vue from 'vue' import Vue from 'vue';
export default { export default {
data() {
return {
modalContent: '',
cancelMsg: '取消',
confirmMsg: '确定'
}
},
onLaunch: function() { onLaunch: function() {
uni.getSystemInfo({ uni.getSystemInfo({
success: function(e) { success: function(e) {
// #ifndef MP // #ifndef MP
Vue.prototype.StatusBar = e.statusBarHeight; Vue.prototype.StatusBar = e.statusBarHeight;
if (e.platform == 'android') { if (e.platform == 'android') {
Vue.prototype.CustomBar = e.statusBarHeight + 50; Vue.prototype.CustomBar = e.statusBarHeight + 50;
} else { } else {
Vue.prototype.CustomBar = e.statusBarHeight + 45; Vue.prototype.CustomBar = e.statusBarHeight + 45;
}; };
// #endif // #endif
// #ifdef MP-WEIXIN // #ifdef MP-WEIXIN
@ -103,7 +110,7 @@
] ]
}, },
onShow: function() { onShow: function(data) {
console.log('App Show') console.log('App Show')
}, },
onHide: function() { onHide: function() {
@ -124,6 +131,7 @@
@import '@/uni_modules/uni-scss/index.scss'; @import '@/uni_modules/uni-scss/index.scss';
/* #ifndef APP-NVUE */ /* #ifndef APP-NVUE */
@import '@/static/customicons.css'; @import '@/static/customicons.css';
// //
page { page {
background-color: #f5f5f5; background-color: #f5f5f5;

View File

@ -2,9 +2,16 @@
<view> <view>
<view class="cu-custom" :style="[{height:CustomBar + 'px'}]"> <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="cu-bar fixed" :style="style" :class="[bgImage!=''?'none-bg text-white bg-img':'',bgColor]">
<view class="action" @tap="BackPage" v-if="isBack"> <view class="flex justify-start">
<text class="cuIcon-back"></text> <view class="action" @tap="BackPage" v-if="isBack">
<slot name="backText"></slot> <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>
<view class="content" :style="[{top:StatusBar + 'px'}]"> <view class="content" :style="[{top:StatusBar + 'px'}]">
<slot name="content"></slot> <slot name="content"></slot>
@ -45,6 +52,14 @@
type: [Boolean, String], type: [Boolean, String],
default: false default: false
}, },
isBackHome: {
type: [Boolean, String],
default: false
},
homePageUrl: {
type: [String],
default: ''
},
bgImage: { bgImage: {
type: String, type: String,
default: '' default: ''
@ -55,11 +70,22 @@
uni.navigateBack({ uni.navigateBack({
delta: 1 delta: 1
}); });
},
BackHomePage() {
uni.reLaunch({
url: this.homePageUrl
})
} }
} }
} }
</script> </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> </style>

1403
common/js/data.js Normal file

File diff suppressed because it is too large Load Diff

3
common/js/glogalFun.js Normal file
View File

@ -0,0 +1,3 @@
export default {
CONFIRM: 'confirmCallback'
}

23
common/js/validate.js Normal file
View File

@ -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);
}
}

View File

@ -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,
//app30
//appmargin-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>

View File

@ -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
}
})();

View File

@ -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

View File

@ -1,20 +1,40 @@
<template> <template>
<view class="product-item flex justify-start"> <view>
<view class="cu-avatar xl-view" :style="'background-image:url(' + vCard.picUrl + ');'"> <view class="flex justify-start">
</view> <view class="cu-avatar" :class="avatarPubClass" :style="'background-image:url(' + vCard.picUrl + '); width: ' + avatarWidth + '; height: ' + avatarHeight + ';'">
<view class="margin-left-sm product-content"> </view>
<view> <view class="margin-left-sm product-content">
<view class="text-black text-xl">{{vCard.name}}</view>
<view> <view>
<text v-if="vCard.comments.icon" :class="'cuIcon-' + vCard.comments.icon" class="margin-right-xs text-main-color"></text> <view class="text-black text-xl">{{vCard.name}}</view>
<text>{{vCard.comments.desc}}</text> <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> </view>
<view v-for="(item, index) in vCard.extraInfos"> </view>
<view class="text-sm"> <view class="text-sm padding-top" v-if="vCard.rateInfo">
<text v-if="item.icon" :class="'cuIcon-' + item.icon" class="margin-right-xs text-main-color"></text> <view class="flex justify-between">
<text>{{item.desc}}</text> <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>
<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> </view>
</view> </view>
@ -27,6 +47,18 @@
vCard: { vCard: {
type: Object, type: Object,
default: {} default: {}
},
avatarWidth: {
type: String,
default: '150rpx'
},
avatarHeight: {
type: String,
default: '150rpx'
},
avatarPubClass: {
type: String,
default: ''
} }
}, },
data() { data() {
@ -38,11 +70,6 @@
</script> </script>
<style scoped> <style scoped>
.xl-view {
min-width: 150rpx;
min-height: 150rpx;
}
.product-content { .product-content {
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View File

@ -1,18 +1,21 @@
<template> <template>
<!-- 底部fixed操作条包含发布选项普通文字加icon加标签选项 --> <!-- 底部fixed操作条包含发布选项普通文字加icon加标签选项 -->
<view class="cu-bar tabbar margin-bottom-xl bg-white fixed-bottom-bar"> <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" <view class="action add-action"
v-if="item.action === 'add'"> v-for="(item, index) in moduleBarInfos" :key="index"
<button class="cu-btn bg-main-color shadow" :class="'cuIcon-' + item.cuIcon"></button> 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}} {{item.name}}
</view> </view>
<view class="action text-main-color" v-else-if="index === 0"> <view class="action" v-else
<view :class="'cuIcon-' + item.cuIcon"> :data-cur="item.pageCode"
<view class="cu-tag badge" v-if="item.countTag">{{item.countTag > 99 ? '99+' : item.countTag}}</view> :class="curPageCode===item.pageCode ? 'text-main-color' : 'text-gray'"
</view> @click="navChange($event, true)">
{{item.name}}
</view>
<view class="action text-gray" v-else-if="index > 0">
<view :class="'cuIcon-' + item.cuIcon"> <view :class="'cuIcon-' + item.cuIcon">
<view class="cu-tag badge" v-if="item.countTag">{{item.countTag > 99 ? '99+' : item.countTag}}</view> <view class="cu-tag badge" v-if="item.countTag">{{item.countTag > 99 ? '99+' : item.countTag}}</view>
</view> </view>
@ -31,10 +34,24 @@
} }
}, },
data() { data() {
return {}; return {
curPageCode: ''
};
},
onReady() {
this.loadData();
}, },
methods: { 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> </script>

View File

@ -4,7 +4,7 @@
<view class="cu-item shadow"> <view class="cu-item shadow">
<view class="cu-list menu-avatar no-border"> <view class="cu-list menu-avatar no-border">
<view class="cu-item"> <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>
<view class="content flex-sub"> <view class="content flex-sub">
<view>{{reviewer.name}}</view> <view>{{reviewer.name}}</view>

View File

@ -1,13 +1,21 @@
<template> <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 class="cu-avatar xxl-view" :style="'background-image:url(' + product.picUrl + ');'">
</view> </view>
<view class="margin-left-sm product-content"> <view class="margin-left-sm product-content">
<view> <view>
<view class="text-black">{{product.name}}</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>
<view class="text-price text-red text-bold text-xl" v-if="ifShowPrice">{{product.salePrice}}</view>
<view v-if="ifShowServArea"> <view v-if="ifShowServArea">
<view class="cu-capsule"> <view class="cu-capsule">
<view class='cu-tag bg-main-color sm'> <view class='cu-tag bg-main-color sm'>
@ -17,7 +25,7 @@
服务区域 服务区域
</view> </view>
</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> </view>
</view> </view>
@ -31,7 +39,7 @@
type: Boolean, type: Boolean,
default: false default: false
}, },
ifShowPrice: { ifShowComments: {
type: Boolean, type: Boolean,
default: true default: true
}, },
@ -58,6 +66,7 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: space-between; justify-content: space-between;
width: 100%;
} }
.cu-list.menu-avatar>.cu-item .content .cu-tag.sm { .cu-list.menu-avatar>.cu-item .content .cu-tag.sm {

View File

@ -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>

View File

@ -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
View File

@ -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
View File

@ -1,38 +1,47 @@
// #ifndef VUE3 // #ifndef VUE3
import Vue from 'vue' import Vue from 'vue';
import App from './App' import App from './App';
import cuCustom from 'colorui/components/cu-custom.vue' import CuCustom from 'colorui/components/cu-custom.vue';
import Data from './data.js' 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) Vue.component('cu-custom', CuCustom)
const data = type=>{ Vue.component('confirm-modal', ConfirmModal);
const data = type => {
//模拟异步请求数据 //模拟异步请求数据
return new Promise(resolve=>{ return new Promise(resolve => {
setTimeout(()=>{ setTimeout(() => {
resolve(Data[type]); resolve(Data[type]);
}, 0) }, 0)
}) })
} }
Vue.prototype.$api = {data} Vue.prototype.$api = {
data
}
Vue.prototype.$globalFun = globalFun;
Vue.prototype.$validate = validate;
Vue.config.productionTip = false Vue.config.productionTip = false
App.mpType = 'app' App.mpType = 'app'
const app = new Vue({ const app = new Vue({
...App ...App
}) })
app.$mount() app.$mount()
// #endif // #endif
// #ifdef VUE3 // #ifdef VUE3
import { createSSRApp } from 'vue' import {
createSSRApp
} from 'vue'
import App from './App.vue' import App from './App.vue'
export function createApp() { export function createApp() {
const app = createSSRApp(App) const app = createSSRApp(App)
return { return {
app app
} }
} }
// #endif // #endif

View File

@ -52,7 +52,7 @@
"appid" : "wxc39c2af3ea24cd37", "appid" : "wxc39c2af3ea24cd37",
"setting" : { "setting" : {
"urlCheck" : false, "urlCheck" : false,
"minified" : false, "minified" : true,
"es6" : false "es6" : false
}, },
"usingComponents" : true, "usingComponents" : true,

13
package.json Normal file
View File

@ -0,0 +1,13 @@
{
"id": "ay-qrcode",
"name": "生成二维码。传入链接,即可使用,可快速扫出链接",
"version": "1.0.7",
"description": "生成二维码。传入链接即可使用可快速扫出链接可自定义宽高适用于APP与H5、微信小程序",
"keywords": [
"生成二维码",
"二维码",
"即可使用",
"可快速扫出链接",
"已解决部分华为荣耀手机缺角问题"
]
}

View File

@ -1,39 +1,56 @@
{ {
"pages": [{ "pages": [{
"path": "pages/index/index" "path": "pages/index/index"
}, }],
{ "subPackages": [{
"path": "pages/product/product-detail", "root": "pages/order/",
"style": { "pages": [{
"navigationBarTitleText": "" "path": "order-detail"
} }]
}, }, {
{ "root": "pages/product/",
"path": "pages/product/product-pick", "pages": [{
"style": { "path": "product-detail"
"navigationBarTitleText": "", }, {
"enablePullDownRefresh": false "path": "product-pick"
} }, {
}, "path": "shop-detail"
{ }]
"path": "pages/order/order-detail", }, {
"style": { "root": "pages/my/",
"navigationBarTitleText": "", "pages": [{
"enablePullDownRefresh": false "path": "my-order"
} }, {
}, "path": "my-cart"
{ }, {
"path": "pages/product/shop-detail" "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": { "globalStyle": {
"navigationStyle": "custom", "navigationStyle": "custom",
"navigationBarTextStyle": "black", "navigationBarTextStyle": "black"
// "navigationBarTitleText": "uni-app", // "navigationBarTitleText": "uni-app",
// "navigationBarBackgroundColor": "#F8F8F8", // "navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8", // "backgroundColor": "#F8F8F8",
"app-plus": { // "app-plus": {
"background": "#efeff4" // "background": "#efeff4"
} // }
} }
} }

153
pages/index/home.vue Normal file
View File

@ -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>

View File

@ -1,148 +1,156 @@
<template> <template>
<view> <view>
<!-- 轮播图--> <index v-if="curPageCode === 'indexPage'"></index>
<swiper class="screen-swiper" :class="dotStyle?'square-dot':'round-dot'" :indicator-dots="true" :circular="true" <worker-circle v-if="curPageCode === 'workerCirclePage'"></worker-circle>
:autoplay="true" interval="5000" duration="500"> <personal-center v-if="curPageCode === 'myPage'"></personal-center>
<swiper-item v-for="(item,index) in swiperList" :key="item.id"> <!-- <publish-home v-if="curPageCode === 'publishPage'"></publish-home> -->
<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>
<module-bar ref="moduleBar" :moduleBarInfos="moduleBarInfos"></module-bar> <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> </view>
</template> </template>
<script> <script>
import moduleBar from '@/components/custom-bar/module-bar.vue'; 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 { export default {
components: { components: {
moduleBar, moduleBar,
verticalGoodsCard index,
workerCircle,
personalCenter,
publishHome
}, },
data() { data() {
return { return {
dotStyle: true,
swiperList: [],
tabCur: 0,
categories: [],
subCategories: [],
moduleBarInfos: [], moduleBarInfos: [],
hotGoods: {}, curPageCode: 'indexPage',
discountGoods: {}, isShowPublish: false
InputBottom: 0
} }
}, },
onLoad() { onLoad() {
this.loadData(); this.loadData();
this.bindEvent(); this.bindEvent();
}, },
onUnload() {
this.offEvent();
},
methods: { methods: {
async loadData() { 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.moduleBarInfos = await this.$api.data('moduleBarInfos');
this.hotGoods = await this.$api.data('hotGoods');
this.discountGoods = await this.$api.data('discountGoods');
}, },
bindEvent() { 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) { offEvent() {
this.tabCur = e.currentTarget.dataset.id; uni.$off('getCurPageInfo')
//
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) { hidePublish() {
console.log("搜索条件信息: " + item) this.isShowPublish = false;
console.log("商品搜索中...");
},
showDetails(productItem) {
uni.navigateTo({
url: '../product/product-detail'
});
} }
} }
} }
</script> </script>
<style scoped> <style scoped>
.cu-list+.cu-list { .content-mask {
margin-top: 0; z-index: 9999;
background: rgba(0, 0, 0, 0.9);
} }
.cu-list.grid.no-border { .mask-close-text {
padding: 0 10rpx; visibility: hidden;
} }
.hot-sub-category .cu-item .hot-sub-category-icon { .middle-avatar {
font-size: 80rpx; 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> </style>

104
pages/index/msg-home.vue Normal file
View File

@ -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>

361
pages/index/my-home.vue Normal file
View File

@ -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>

147
pages/index/worker-home.vue Normal file
View File

@ -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>

284
pages/my/Certification.vue Normal file
View File

@ -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>

209
pages/my/apply-operator.vue Normal file
View File

@ -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>

27
pages/my/contract.vue Normal file
View File

@ -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>

102
pages/my/edit-address.vue Normal file
View File

@ -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>

96
pages/my/my-address.vue Normal file
View File

@ -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>

166
pages/my/my-cart.vue Normal file
View File

@ -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) {
// ListindexPath
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>

189
pages/my/my-operator.vue Normal file
View File

@ -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>

183
pages/my/my-order.vue Normal file
View File

@ -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>

View File

@ -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>

155
pages/my/serv-detail.vue Normal file
View File

@ -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>

View File

@ -25,11 +25,24 @@
class="cuIcon-question">选择的为期望上门时间稍后工程师将与你确认具体上门时间</text></view> class="cuIcon-question">选择的为期望上门时间稍后工程师将与你确认具体上门时间</text></view>
</view> </view>
<!-- 选购的商品列表 --> <!-- 选购的商品列表 -->
<view class="margin-lr-sm margin-top-sm bg-white padding"> <view class="margin-lr-sm margin-top-sm bg-white">
<view class="solid-bottom" v-for="(item, index) in pickedProductList"> <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 :columnTitleArr="columnTitleArr" :product="item.product" :pickedList="item.pickedList">
</product-picked> </product-picked>
</view> </view> -->
</view> </view>
<!-- 支付方式 --> <!-- 支付方式 -->
<view class="margin-lr-sm margin-top-sm bg-white padding"> <view class="margin-lr-sm margin-top-sm bg-white padding">
@ -78,7 +91,7 @@
</template> </template>
<script> <script>
import productPicked from '@/pages/order/product-picked.vue'; import productPicked from '@/components/goods-card/product-picked.vue';
export default { export default {
components: { components: {
@ -121,4 +134,10 @@
width: 55% !important; width: 55% !important;
text-align: left; text-align: left;
} }
.bar-first-action {
margin-left: unset !important;
padding-left: 40rpx;
font-size: 30rpx !important;
}
</style> </style>

View File

@ -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>

View File

@ -2,8 +2,9 @@
<page-meta :page-style="'overflow:'+(ifShowPageMeta?'hidden':'visible')"></page-meta> <page-meta :page-style="'overflow:'+(ifShowPageMeta?'hidden':'visible')"></page-meta>
<view> <view>
<!-- 顶部操作条 --> <!-- 顶部操作条 -->
<cu-custom :bgColor="'bg-white'" :isBack="true"> <cu-custom :bgColor="'bg-white'" :isBack="true" :isBackHome="true" :homePageUrl="'/pages/index/index'">
<block slot="backText">返回</block> <!-- <block slot="backText">返回</block> -->
<!-- <block slot="backHomeText">首页</block> -->
<!-- <block slot="content">商品详情</block> --> <!-- <block slot="content">商品详情</block> -->
</cu-custom> </cu-custom>
<!-- 导航栏 --> <!-- 导航栏 -->
@ -107,8 +108,11 @@
<view class="margin-lr-sm margin-top-sm padding bg-white"> <view class="margin-lr-sm margin-top-sm padding bg-white">
<view class="flex justify-between align-center"> <view class="flex justify-between align-center">
<view class="flex justify-start align-center"> <view class="flex justify-start align-center">
<view class="cu-avatar" :style="'background-image:url(' + shopInfo.avatarUrl + ');'"></view> <view class="cu-avatar round" :style="'background-image:url(' + shopInfo.avatarUrl + ');'"></view>
<view class="margin-lr-sm text-lg text-black">{{shopInfo.name}}</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>
<view class="text-sm" @click="showShopDetail(shopInfo)">店铺查看<text class="text-bold text-gray cuIcon-right"></text></view> <view class="text-sm" @click="showShopDetail(shopInfo)">店铺查看<text class="text-bold text-gray cuIcon-right"></text></view>
</view> </view>
@ -129,7 +133,7 @@
<!-- <view class="action"> <!-- <view class="action">
<view class=" cuIcon-shop"></view> 店铺 <view class=" cuIcon-shop"></view> 店铺
</view> --> </view> -->
<view class="action"> <view class="action" @click="showCart">
<view class="cuIcon-cart"> <view class="cuIcon-cart">
<view class="cu-tag badge" v-if="totalPickCount > 0">{{totalPickCount}}</view> <view class="cu-tag badge" v-if="totalPickCount > 0">{{totalPickCount}}</view>
</view> </view>
@ -180,6 +184,9 @@
this.loadData(); this.loadData();
this.bindEvent(); this.bindEvent();
}, },
onUnload() {
this.offBindEvent();
},
onReady() { onReady() {
this.productVideoContext = uni.createVideoContext('productVideo'); this.productVideoContext = uni.createVideoContext('productVideo');
}, },
@ -201,6 +208,9 @@
bindEvent() { bindEvent() {
uni.$on('product-detail_add2Cart', this.add2Cart); uni.$on('product-detail_add2Cart', this.add2Cart);
}, },
offBindEvent() {
uni.$off('product-detail_add2Cart');
},
chooseSpecs(item) { chooseSpecs(item) {
this.curProductSpecs = item; this.curProductSpecs = item;
}, },
@ -250,7 +260,13 @@
}, },
showShopDetail(shopInfo) { showShopDetail(shopInfo) {
uni.navigateTo({ 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> </script>
<style scoped> <style scoped>
.text-del {
text-decoration: line-through;
}
.certern-height { .certern-height {
height: 300rpx; height: 300rpx;
overflow: hidden; overflow: hidden;

View File

@ -17,7 +17,7 @@
<view>购买型号</view> <view>购买型号</view>
<view>购买数量</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" <view class="flex justify-between margin-lr-sm margin-tb-sm" v-for="(item,index) in specsList"
:key="item.id"> :key="item.id">
<view class='cu-tag padding' :class="curSpec.id === item.id ? 'line-main-color' : 'line-default'" <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 :min="0" :max="item.maxPieces" :value="0" @change="changePiecesNum($event, index)">
</uni-number-box> </uni-number-box>
</view> </view>
</view> </scroll-view>
</view> </view>
<!-- 底部操作条 --> <!-- 底部操作条 -->
<view class="cu-bar bg-white tabbar border shop fixed-bottom-bar"> <view class="cu-bar bg-white tabbar border shop fixed-bottom-bar">
@ -120,7 +120,6 @@
.certern-height-with-scroll { .certern-height-with-scroll {
height: 600rpx; height: 600rpx;
margin-bottom: calc(100rpx - env(safe-area-inset-bottom)/2); margin-bottom: calc(100rpx - env(safe-area-inset-bottom)/2);
overflow: scroll;
} }
.main-container { .main-container {

View File

@ -1,16 +1,16 @@
<template> <template>
<view> <view>
<!-- 顶部操作条 --> <!-- 顶部操作条 -->
<cu-custom :bgColor="'bg-white'" :isBack="true"> <cu-custom :bgColor="'bg-main-color'" :isBack="true">
<block slot="backText">返回</block> <block slot="backText">返回</block>
<block slot="content">店铺主页</block> <block slot="content">店铺主页</block>
</cu-custom> </cu-custom>
<!-- 店铺介绍 --> <!-- 店铺介绍 -->
<view class="bg-white padding"> <view class="bg-white padding solid-bottom">
<horizontal-name-card :vCard="shopInfo"></horizontal-name-card> <horizontal-name-card :vCard="shopInfo"></horizontal-name-card>
</view> </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"> <view class="flex justify-between">
<text>总评分<text class="text-red text-xl">{{shopInfo.totalScore}}</text> / 5.0</text> <text>总评分<text class="text-red text-xl">{{shopInfo.totalScore}}</text> / 5.0</text>
<uni-rate :readonly="true" allow-half :value="shopInfo.totalScore" /> <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.attitudeScore}}</text>
<text>技能</text><text class="margin-lr-xs">{{shopInfo.skillScore}}</text> <text>技能</text><text class="margin-lr-xs">{{shopInfo.skillScore}}</text>
</view> </view>
</view> </view> -->
<!-- 店铺服务说明 --> <!-- 店铺服务说明 -->
<view class="padding bg-white text-sm"> <view class="padding bg-white text-sm">
<view>服务类目<text>{{shopInfo.servType}}</text></view> <view>服务类目<text>{{shopInfo.servType}}</text></view>

View File

@ -32,3 +32,8 @@ radio.main-color.checked .uni-radio-input {
border-color: #0081ff !important; border-color: #0081ff !important;
color: #ffffff !important; color: #ffffff !important;
} }
.oper-bar button:last-child {
background-color: #0081ff;
color: #ffffff;
}

View File

@ -10,6 +10,10 @@
z-index: 98; z-index: 98;
} }
.cu-bar.tabbar.border .action checkbox {
z-index: 3;
}
.fixed-top-bar { .fixed-top-bar {
position: fixed !important; position: fixed !important;
z-index: 98; z-index: 98;
@ -21,3 +25,61 @@
position: sticky; position: sticky;
top: 0; 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;
}