瀏覽代碼

Merge branch 'deploy' of http://git.chelingzhu.com/chelingzhu-web/storeCheck-app into deploy

lilei 4 年之前
父節點
當前提交
88c45f657d

+ 257 - 0
components/autograph-to-pic/autograph-to-pic.vue

@@ -0,0 +1,257 @@
+<template>
+	<view class="autograph-wrap">
+		<!-- <view class="handRight">
+			<view class="handTitle">手写板</view>
+		</view>	
+		<view class="handBtn">
+			<view class="slide-wrapper">
+				<text>选择粗细</text>
+				<slider @change="updateValue" value="50" show-value class="slider" step="25" />
+			</view>
+			<view class="color">
+				<text>选择颜色</text>
+				<image @click="selectColorEvent('black')" :src="selectColor === 'black' ? require('./img/color_black_selected.png') : require('./img/color_black.png')" :class="selectColor === 'black' ? 'color_select' : ''" class="black-select"></image>
+				<image @click="selectColorEvent('red')" :src="selectColor === 'red' ? require('./img/color_red_selected.png') : require('./img/color_red.png') " :class="selectColor === 'red' ? 'color_select' : ''"  class="red-select" ></image>
+			</view>
+		</view> -->
+		<view class="handCenter">
+			<canvas class="handWriting" disable-scroll="true" @touchstart="uploadScaleStart" @touchmove="uploadScaleMove" @touchend="uploadScaleEnd" :id="canvasId" :canvas-id="canvasId"></canvas>
+		</view>
+		<!-- <view class="showimg">
+			<image v-if="showimg" :src="showimg" mode=""></image>
+			<text v-else >图片展示</text>
+		</view> -->
+		<view class="buttons">
+			<!-- <button @click="retDraw" class="delBtn">重写</button> -->
+			<u-button size="mini" @click="retDraw" class="delBtn">重写</u-button>
+			<!-- <button @click="subCanvas" class="subBtn">保存</button> -->
+		</view>
+	</view>
+</template>
+
+<script>
+import Handwriting from './js/signature.js'
+export default {
+	props: {
+		//  签字画布id
+		canvasId: {
+			type: String,
+			default: ''
+		},
+		//  是否为空校验
+		isEmpty: {
+			type: Array,
+			default: []
+		}
+	},
+	data(){
+		return{
+			lineColor:'black',
+			slideValue:50,
+			handwriting:'',
+			selectColor:'black',
+			color:'',
+			showimg:'',
+			share_popup:false,
+		}
+	},
+	watch: {
+		isEmpty: {
+			handler(value) {
+				this.checkEmpty(value)
+			},
+			deep: true
+		}
+	},
+	mounted() {
+		this.handwriting = new Handwriting({
+		  lineColor: this.lineColor,
+		  slideValue: this.slideValue, // 0, 25, 50, 75, 100
+		  canvasName: this.canvasId,
+		})
+		console.log(this.handwriting)
+	},
+	methods:{
+		//  为空校验
+		checkEmpty(arr){
+			console.log(arr)
+			let isCheck = []
+			arr.map(item => {
+				if(item.state){
+					isCheck.push(item.name)
+				}
+			})
+			console.log(isCheck)
+			isCheck.map(item => {
+				const c = document.getElementById(item); // 获取html的canvas对象,我这个id="canvas"
+				if(this.isCanvasBlank(c)){
+					// alert("请绘制草图后再上传!")
+					// return
+					item.empty = true
+				}else{
+					item.empty = false
+				}
+			})
+			console.log(isCheck,'===空空kong')
+		},
+		//	验证canvas画布是否为空函数
+		isCanvasBlank(canvas) {
+			console.log(canvas.width,canvas.height)
+		 //    var blank = document.createElement('canvas');//系统获取一个空canvas对象
+		 //    blank.width = canvas.width;
+		 //    blank.height = canvas.height;
+			// console.log(blank.toDataURL(),blank)
+		 //    return canvas.toDataURL() == blank.toDataURL()//比较值相等则为空
+		},
+		// 选择画笔颜色
+		selectColorEvent(event) {
+			this.selectColor = event
+			if(event=='black'){
+				this.color= '#1A1A1A'
+			}else if(event=='red'){
+				this.color= '#ca262a'
+			} 
+			this.handwriting.selectColorEvent(this.color)
+		},
+		//  重写
+		retDraw() {
+			this.handwriting.retDraw()
+		},
+		// 笔迹粗细滑块
+		updateValue(e) {
+			this.slideValue = e.detail.value
+			this.handwriting.selectSlideValue(this.slideValue)
+		},
+		// 绑定到canvas的touchstart事件
+		uploadScaleStart(event){
+			this.handwriting.uploadScaleStart(event)
+		},
+		// 绑定到canvas的touchmove事件
+		uploadScaleMove(event){
+			this.handwriting.uploadScaleMove(event)
+		},
+		// 绑定到canvas的uploadScaleEnd事件
+		uploadScaleEnd(event){
+			this.handwriting.uploadScaleEnd(event)
+		},
+		// 保存  生成图片
+		subCanvas(){
+			this.handwriting.saveCanvas().then(res=>{
+				this.showimg = res
+				console.log(res)
+			}).catch(err=>{
+				console.log(err)
+			})
+		},
+	}
+}
+</script>
+
+<style lang="scss" scoped>
+.autograph-wrap {
+	width: 100%;
+	height: 100%;
+	overflow: hidden;
+	display: flex;
+	align-content: center;
+	flex-direction: column;
+	justify-content: center;
+	font-size: 28upx;
+	.handRight {
+		align-items: center;
+		.handTitle {
+			flex: 1;
+			color: #666;
+			justify-content: center;
+			font-size: 30upx;
+		}
+	}
+	.handBtn {
+		flex-direction: column;
+		padding: 40upx 20upx;
+		.slide-wrapper {
+			align-items: center;
+			margin-bottom: 20upx;
+			.slider{
+				width: 400upx;
+				padding-left: 20upx;
+			}
+		}
+		.color{
+			align-items: center;
+			text{
+				margin-right: 20upx;
+			}
+			.black-select, .red-select {
+			  width: 60upx;
+			  height: 60upx;
+			  vertical-align: super;
+			}
+			.black-select.color_select, .red-select.color_select {
+			  width: 90upx;
+			  height: 90upx;
+			  vertical-align: sub;
+			}
+		}
+	}
+	.handCenter {
+		border: 4upx dashed #e9e9e9;
+		flex: 5;
+		overflow: hidden;
+		box-sizing: border-box;
+		width: 90%;
+		margin: 0 auto;
+		.handWriting {
+			background: #fff;
+			width: 100%;
+			height: 300upx;
+		}
+	}
+	.showimg{
+		border: 4upx solid #e9e9e9;
+		overflow: hidden;
+		width: 90%;
+		margin: 0 auto;
+		background: #eee;
+		height: 350upx;
+		margin-top: 40upx;
+		align-items: center;
+		justify-content: center;
+		image{
+			width: 100%;
+			height: 100%;	
+		}
+		text{
+			font-size: 40upx;
+			color: #888;
+		}
+	}
+	.buttons{
+		margin: 20upx 5%;
+		text-align: right;
+		.delBtn {
+			color: #666;
+		}
+		.subBtn {
+			background: #008ef6;
+			color: #fff;
+			text-align: center;
+			justify-content: center;
+		}
+	}
+}
+.drop {
+	width: 50upx;
+	height: 50upx;
+	border-radius: 50%;
+	background: #FFF;
+	position: absolute;
+	left: 0upx;
+	top: -10upx;
+	box-shadow: 0px 1px 5px #888888;
+}
+.slide {
+	width: 250upx;
+	height: 30upx;
+}
+</style>

二進制
components/autograph-to-pic/img/color_black.png


二進制
components/autograph-to-pic/img/color_black_selected.png


二進制
components/autograph-to-pic/img/color_red.png


二進制
components/autograph-to-pic/img/color_red_selected.png


+ 396 - 0
components/autograph-to-pic/js/signature.js

@@ -0,0 +1,396 @@
+class Handwriting {
+  // 内置数据
+  ctx = '';
+  canvasWidth = 300;
+  canvasHeight = 900;
+  linePrack = []; //划线轨迹 ; 生成线条的实际点
+  currentLine = [];
+  transparent = 1; // 透明度
+  pressure = 0.5; // 默认压力
+  smoothness = 100; //顺滑度,用60的距离来计算速度
+  lineSize = 1.5; // 笔记倍数
+  lineMin = 0.5; // 最小笔画半径
+  lineMax = 2; // 最大笔画半径
+  currentPoint = {};
+  firstTouch = true; // 第一次触发
+  radius = 1; //画圆的半径
+  cutArea = {
+    top: 0,
+    right: 0,
+    bottom: 0,
+    left: 0
+  }; //裁剪区域
+  lastPoint = 0;
+  chirography = []; //笔迹
+  startY = 0;
+  deltaY = 0;
+  startValue = 0;
+  constructor(opts) {
+		console.log(opts);
+    this.lineColor = opts.lineColor || '#1A1A1A' // 颜色
+    this.slideValue = opts.slideValue || 50
+		this.canvasName = opts.canvasName || 'handWriting'
+    this.init()
+  }
+  init() {
+    this.ctx = uni.createCanvasContext(this.canvasName)
+    var query = uni.createSelectorQuery();
+    query.select('.handCenter').boundingClientRect(rect => {
+      console.log(rect)
+      this.canvasWidth = rect.width;
+      this.canvasHeight = rect.height;
+    }).exec();
+    this.selectSlideValue(this.slideValue);
+  }
+
+  // 笔迹开始
+  uploadScaleStart(event) {
+		console.log('start');
+		let e = event.mp
+    console.log(e.touches[0])
+    if (e.type != 'touchstart') return false;
+    this.ctx.setFillStyle(this.lineColor); // 初始线条设置颜色
+    this.ctx.setGlobalAlpha(this.transparent); // 设置半透明
+    this.currentPoint = {
+      x: e.touches[0].x,
+      y: e.touches[0].y
+    }
+    this.currentLine.unshift({
+      time: new Date().getTime(),
+      dis: 0,
+      x: this.currentPoint.x,
+      y: this.currentPoint.y
+    })
+    if (this.firstTouch) {
+      this.cutArea = {
+        top: this.currentPoint.y,
+        right: this.currentPoint.x,
+        bottom: this.currentPoint.y,
+        left: this.currentPoint.x
+      }
+      this.firstTouch = false
+    }
+    this.pointToLine(this.currentLine);
+  }
+  // 笔迹移动
+  uploadScaleMove(event) {
+		console.log('move');
+		let e = event.mp
+    if (e.type != 'touchmove') return false;
+    if (e.cancelable) {
+      // 判断默认行为是否已经被禁用
+      if (!e.defaultPrevented) {
+        e.preventDefault();
+      }
+    }
+    let point = {
+      x: e.touches[0].x,
+      y: e.touches[0].y
+    }
+    //测试裁剪
+    if (point.y < this.cutArea.top) {
+      this.cutArea.top = point.y;
+    }
+    if (point.y < 0) this.cutArea.top = 0;
+
+    if (point.x > this.cutArea.right) {
+      this.cutArea.right = point.x;
+    }
+    if (this.canvasWidth - point.x <= 0) {
+      this.cutArea.right = this.canvasWidth;
+    }
+    if (point.y > this.cutArea.bottom) {
+      this.cutArea.bottom = point.y;
+    }
+    if (this.canvasHeight - point.y <= 0) {
+      this.cutArea.bottom = this.canvasHeight;
+    }
+    if (point.x < this.cutArea.left) {
+      this.cutArea.left = point.x;
+    }
+    if (point.x < 0) this.cutArea.left = 0;
+
+    this.lastPoint = this.currentPoint;
+    this.currentPoint = point
+    this.currentLine.unshift({
+      time: new Date().getTime(),
+      dis: this.distance(this.currentPoint, this.lastPoint, 'move'),
+      x: point.x,
+      y: point.y
+    })
+    this.pointToLine(this.currentLine);
+  }
+  // 笔迹结束
+  uploadScaleEnd(event) {
+		let e = event.mp
+    if (e.type != 'touchend') return 0;
+		console.log(e);
+    let point = {
+      x: e.changedTouches[0].x,
+      y: e.changedTouches[0].y
+    }
+		
+    this.lastPoint = this.currentPoint;
+    this.currentPoint = point
+    this.currentLine.unshift({
+      time: new Date().getTime(),
+      dis: this.distance(this.currentPoint, this.lastPoint, 'end'),
+      x: point.x,
+      y: point.y
+    })
+    if (this.currentLine.length > 2) {
+      var info = (this.currentLine[0].time - this.currentLine[this.currentLine.length - 1].time) / this.currentLine.length;
+      //$("#info").text(info.toFixed(2));
+    }
+    //一笔结束,保存笔迹的坐标点,清空,当前笔迹
+    //增加判断是否在手写区域;
+    this.pointToLine(this.currentLine);
+    var currentChirography = {
+      lineSize: this.lineSize,
+      lineColor: this.lineColor
+    };
+    this.chirography.unshift(currentChirography);
+    this.linePrack.unshift(this.currentLine);
+    this.currentLine = []
+  }
+  retDraw() {
+    this.ctx.clearRect(0, 0, 700, 730)
+    this.ctx.draw()
+  }
+
+  //画两点之间的线条;参数为:line,会绘制最近的开始的两个点;
+  pointToLine(line) {
+    this.calcBethelLine(line);
+    // this.calcBethelLine1(line);
+    return;
+  }
+  //计算插值的方式;
+  calcBethelLine(line) {
+    if (line.length <= 1) {
+      line[0].r = this.radius;
+      return;
+    }
+    let x0, x1, x2, y0, y1, y2, r0, r1, r2, len, lastRadius, dis = 0,
+      time = 0,
+      curveValue = 0.5;
+    if (line.length <= 2) {
+      x0 = line[1].x
+      y0 = line[1].y
+      x2 = line[1].x + (line[0].x - line[1].x) * curveValue;
+      y2 = line[1].y + (line[0].y - line[1].y) * curveValue;
+      //x2 = line[1].x;
+      //y2 = line[1].y;
+      x1 = x0 + (x2 - x0) * curveValue;
+      y1 = y0 + (y2 - y0) * curveValue;;
+
+    } else {
+      x0 = line[2].x + (line[1].x - line[2].x) * curveValue;
+      y0 = line[2].y + (line[1].y - line[2].y) * curveValue;
+      x1 = line[1].x;
+      y1 = line[1].y;
+      x2 = x1 + (line[0].x - x1) * curveValue;
+      y2 = y1 + (line[0].y - y1) * curveValue;
+    }
+    //从计算公式看,三个点分别是(x0,y0),(x1,y1),(x2,y2) ;(x1,y1)这个是控制点,控制点不会落在曲线上;实际上,这个点还会手写获取的实际点,却落在曲线上
+    len = this.distance({
+      x: x2,
+      y: y2
+    }, {
+      x: x0,
+      y: y0
+    }, 'calc');
+    lastRadius = this.radius;
+    for (let n = 0; n < line.length - 1; n++) {
+      dis += line[n].dis;
+      time += line[n].time - line[n + 1].time;
+      if (dis > this.smoothness) break;
+    }
+    this.radius = Math.min(time / len * this.pressure + this.lineMin, this.lineMax) * this.lineSize
+    line[0].r = this.radius;
+    //计算笔迹半径;
+    if (line.length <= 2) {
+      r0 = (lastRadius + this.radius) / 2;
+      r1 = r0;
+      r2 = r1;
+      //return;
+    } else {
+      r0 = (line[2].r + line[1].r) / 2;
+      r1 = line[1].r;
+      r2 = (line[1].r + line[0].r) / 2;
+    }
+    let n = 5;
+    let point = [];
+    for (let i = 0; i < n; i++) {
+      let t = i / (n - 1);
+      let x = (1 - t) * (1 - t) * x0 + 2 * t * (1 - t) * x1 + t * t * x2;
+      let y = (1 - t) * (1 - t) * y0 + 2 * t * (1 - t) * y1 + t * t * y2;
+      let r = lastRadius + (this.radius - lastRadius) / n * i;
+      point.push({
+        x: x,
+        y: y,
+        r: r
+      });
+      if (point.length == 3) {
+        let a = this.ctaCalc(point[0].x, point[0].y, point[0].r, point[1].x, point[1].y, point[1].r, point[2].x, point[2].y, point[2].r);
+        a[0].color = this.lineColor;
+        this.bethelDraw(a, 1);
+        point = [{
+          x: x,
+          y: y,
+          r: r
+        }];
+      }
+    }
+  }
+  //求两点之间距离
+  distance(a, b, type) {
+    let x = b.x - a.x;
+    let y = b.y - a.y;
+    return Math.sqrt(x * x + y * y) * 5;
+  }
+  ctaCalc(x0, y0, r0, x1, y1, r1, x2, y2, r2) {
+    let a = [],
+      vx01, vy01, norm, n_x0, n_y0, vx21, vy21, n_x2, n_y2;
+    vx01 = x1 - x0;
+    vy01 = y1 - y0;
+    norm = Math.sqrt(vx01 * vx01 + vy01 * vy01 + 0.0001) * 2;
+    vx01 = vx01 / norm * r0;
+    vy01 = vy01 / norm * r0;
+    n_x0 = vy01;
+    n_y0 = -vx01;
+    vx21 = x1 - x2;
+    vy21 = y1 - y2;
+    norm = Math.sqrt(vx21 * vx21 + vy21 * vy21 + 0.0001) * 2;
+    vx21 = vx21 / norm * r2;
+    vy21 = vy21 / norm * r2;
+    n_x2 = -vy21;
+    n_y2 = vx21;
+    a.push({
+      mx: x0 + n_x0,
+      my: y0 + n_y0,
+      color: "#1A1A1A"
+    });
+    a.push({
+      c1x: x1 + n_x0,
+      c1y: y1 + n_y0,
+      c2x: x1 + n_x2,
+      c2y: y1 + n_y2,
+      ex: x2 + n_x2,
+      ey: y2 + n_y2
+    });
+    a.push({
+      c1x: x2 + n_x2 - vx21,
+      c1y: y2 + n_y2 - vy21,
+      c2x: x2 - n_x2 - vx21,
+      c2y: y2 - n_y2 - vy21,
+      ex: x2 - n_x2,
+      ey: y2 - n_y2
+    });
+    a.push({
+      c1x: x1 - n_x2,
+      c1y: y1 - n_y2,
+      c2x: x1 - n_x0,
+      c2y: y1 - n_y0,
+      ex: x0 - n_x0,
+      ey: y0 - n_y0
+    });
+    a.push({
+      c1x: x0 - n_x0 - vx01,
+      c1y: y0 - n_y0 - vy01,
+      c2x: x0 + n_x0 - vx01,
+      c2y: y0 + n_y0 - vy01,
+      ex: x0 + n_x0,
+      ey: y0 + n_y0
+    });
+    a[0].mx = a[0].mx.toFixed(1);
+    a[0].mx = parseFloat(a[0].mx);
+    a[0].my = a[0].my.toFixed(1);
+    a[0].my = parseFloat(a[0].my);
+    for (let i = 1; i < a.length; i++) {
+      a[i].c1x = a[i].c1x.toFixed(1);
+      a[i].c1x = parseFloat(a[i].c1x);
+      a[i].c1y = a[i].c1y.toFixed(1);
+      a[i].c1y = parseFloat(a[i].c1y);
+      a[i].c2x = a[i].c2x.toFixed(1);
+      a[i].c2x = parseFloat(a[i].c2x);
+      a[i].c2y = a[i].c2y.toFixed(1);
+      a[i].c2y = parseFloat(a[i].c2y);
+      a[i].ex = a[i].ex.toFixed(1);
+      a[i].ex = parseFloat(a[i].ex);
+      a[i].ey = a[i].ey.toFixed(1);
+      a[i].ey = parseFloat(a[i].ey);
+    }
+    return a;
+  }
+  bethelDraw(point, is_fill, color) {
+    this.ctx.beginPath();
+    this.ctx.moveTo(point[0].mx, point[0].my);
+    if (undefined != color) {
+      this.ctx.setFillStyle(color);
+      this.ctx.setStrokeStyle(color);
+    } else {
+      this.ctx.setFillStyle(point[0].color);
+      this.ctx.setStrokeStyle(point[0].color);
+    }
+    for (let i = 1; i < point.length; i++) {
+      this.ctx.bezierCurveTo(point[i].c1x, point[i].c1y, point[i].c2x, point[i].c2y, point[i].ex, point[i].ey);
+    }
+    this.ctx.stroke();
+    if (undefined != is_fill) {
+      this.ctx.fill(); //填充图形 ( 后绘制的图形会覆盖前面的图形, 绘制时注意先后顺序 )
+    }
+    this.ctx.draw(true)
+  }
+
+  selectColorEvent(lineColor) {
+    this.lineColor = lineColor;
+  }
+
+  selectSlideValue(slideValue) {
+    switch (slideValue) {
+      case 0:
+        this.lineSize = 0.1;
+        this.lineMin = 0.1;
+        this.lineMax = 0.1;
+        break;
+      case 25:
+        this.lineSize = 1;
+        this.lineMin = 0.5;
+        this.lineMax = 2;
+        break;
+      case 50:
+        this.lineSize = 1.5;
+        this.lineMin = 1;
+        this.lineMax = 3;
+        break;
+      case 75:
+        this.lineSize = 1.5;
+        this.lineMin = 2;
+        this.lineMax = 3.5;
+        break;
+      case 100:
+        this.lineSize = 3;
+        this.lineMin = 2;
+        this.lineMax = 3.5;
+        break;
+    }
+  }
+	
+	saveCanvas(){
+		 return new Promise((resolve,rej) => {
+			uni.canvasToTempFilePath({
+				canvasId: this.canvasName,
+				success: function(res) {
+					console.log(res, res.tempFilePath)
+					resolve(res.tempFilePath);
+				},
+				 fail:function(err){
+					 console.log('图片生成失败:'+err)
+					 rej(err);
+				 }
+			})
+		})	
+	}	
+}
+
+export default Handwriting;

+ 1 - 1
libs/tools.js

@@ -261,7 +261,7 @@ export const clzConfirm = function(opts){
 		uni.showModal({
 			title: opts.title,
 			content: opts.content,
-			showCancel: opts.showCancel || true,
+			showCancel: opts.showCancel == false ? false : true,
 			confirmText: opts.confirmText || '确定',
 			cancelText: opts.cancelText || '取消',
 			success: opts.success,

+ 35 - 3
pages.json

@@ -41,7 +41,7 @@
 		    "path" : "pages/shopTour/shopTour",
 		    "style" : {
 				"navigationBarTitleText": "远程巡店",
-				 "app-plus": {
+				"app-plus": {
 						"bounce": "none", //关闭窗口回弹效果
 						"titleNView": {
 							"buttons": [ //原生标题栏按钮配置,
@@ -61,8 +61,40 @@
             "style": {
             	"navigationBarTitleText": "工作台"
             }
-        }
-        ,{
+        },
+		{
+		    "path" : "pages/siteInspection/siteInspection",
+		    "style" : {
+				"navigationBarTitleText": "现场巡店"
+			}
+		},
+		{
+		    "path" : "pages/signIn/signIn",
+		    "style" : {
+				"navigationBarTitleText": "拍照签到"
+			}
+		},
+		{
+		    "path" : "pages/shopTourOver/shopTourOver",  //  现场巡店结束签字
+		    "style" : {
+				"navigationBarTitleText": "现场巡店"
+			}
+		},
+		{
+		    "path" : "pages/shopTourCompleted/shopTourCompleted",  //  现场巡店-巡店完成
+		    "style" : {
+				"navigationBarTitleText": "现场巡店"
+			}
+		},
+		{
+		    "path" : "pages/myShopTour/myShopTour",  //  我的巡店
+		    "style": {
+		    	"navigationStyle": "custom" ,// 隐藏系统导航栏
+		    	"navigationBarTextStyle": "white", // 状态栏字体为白色,只能为 white-白色,black-黑色 二选一
+		    	"navigationBarTitleText": "预览"
+		    }
+		},
+		{
             "path" : "pages/userCenter/userCenter",
             "style" : {
 				"navigationBarTitleText": "个人中心"

+ 158 - 0
pages/myShopTour/myShopTour.vue

@@ -0,0 +1,158 @@
+<template>
+	<view class="myShopTour-wrap">
+		<!-- 自定义标题 -->
+		<u-navbar :is-back="false" :border-bottom="false" :background="background" id="navbar">
+			<view class="slot-wrap">
+				<view class="back-icon" @click="goBack">
+					<u-icon name="arrow-left" color="#fff" size="32"></u-icon>
+				</view>
+				<view class="left-icon">我的巡店</view>
+				<view class="right-icon">
+					<u-icon name="more-dot-fill" color="#fff" size="28"></u-icon>
+				</view>
+			</view>
+		</u-navbar>
+		<!-- 内容 -->
+		<view class="myShopTour-con">
+			<u-tabs-swiper ref="uTabs" :list="tabList" name="dispName" :current="current" @change="tabsChange" :is-scroll="false" swiperWidth="750"></u-tabs-swiper>
+			<swiper class="data-list" :current="swiperCurrent" @transition="transition" @change="swiperChange" @animationfinish="animationfinish">
+				<swiper-item class="swiper-item" v-for="(tabs, index) in tabList" :key="index">
+					<scroll-view scroll-y class="scroll-con" @scrolltolower="onreachBottom">
+						<view class="record-con">
+							<view class="record-item">
+								<view class="item-head"></view>
+							</view>
+						</view>
+						<u-empty text="暂无数据" img-width="120" v-if="list.length == 0 && status != 'loading'" mode="list"></u-empty>
+						<u-loadmore bg-color="#f8f8f8" v-if="list.length < total || status == 'loading'" :status="status" class="loadmore" />
+					</scroll-view>
+				</swiper-item>
+			</swiper>
+		</view>
+	</view>
+</template>
+
+<script>
+export default {
+	data() {
+		return {
+			background: {
+				// 渐变色
+				backgroundImage: 'linear-gradient(45deg, rgb(85, 170, 255), rgb(21, 102, 223))'
+			},
+			tabList: [  //  tab切换  类型
+				{ dispName: '全部', code:'' },
+				{ dispName: '进行中', code:'1' },
+				{ dispName: '已完成', code:'2' },
+				{ dispName: '已过期', code:'3' }
+			],
+			current: 0,  //  tabs组件的current值,表示当前活动的tab选项
+			swiperCurrent: 0,  //  swiper组件的current值,表示当前那个swiper-item是活动的
+			pageNo: 1,  //  当前页码
+			pageSize: 15,  //  一页多少条
+			total: 0,  //  总条数
+			// status: 'loading',  //  加载状态
+			status: 'loadmore',  //  加载状态
+			noDataText: '暂无数据',  //  列表数据为空时提示文字
+			list: [],  //  数据列表
+		}
+	},
+	onLoad() {
+		this.pageInit()
+	},
+	methods: {
+		//  返回
+		goBack() {
+			uni.navigateBack({
+				delta: 1
+			});
+		},
+		pageInit(){
+			this.total = 0
+			this.pageNo = 1
+		},
+		// tabs通知swiper切换
+		tabsChange(index) {
+			this.swiperCurrent = index
+			this.list = []
+			this.status = "loading"
+		},
+		swiperChange(event){
+			this.list = []
+			this.status = "loading"
+		},
+		// swiper-item左右移动,通知tabs的滑块跟随移动
+		transition(e) {
+			let dx = e.detail.dx;
+			this.$refs.uTabs.setDx(dx);
+		},
+		// 由于swiper的内部机制问题,快速切换swiper不会触发dx的连续变化,需要在结束时重置状态
+		// swiper滑动结束,分别设置tabs和swiper的状态
+		animationfinish(e) {
+			let current = e.detail.current
+			if(current != this.current){
+				this.$refs.uTabs.setFinishCurrent(current)
+				this.swiperCurrent = current
+				this.current = current
+				this.pageInit()
+			}
+		},
+		// scroll-view到底部加载更多
+		onreachBottom() {
+			if(this.list.length < this.total){
+				this.pageNo += 1
+				this.pageInit()
+			}else{
+				this.status = "nomore"
+			}
+		},
+	}
+};
+</script>
+
+<style lang="scss" scoped>
+page {
+	background-color: #f8f8f8;
+	height: calc(100vh - 44px);
+}
+.myShopTour-wrap {
+	height: 100%;
+	/* 自定义导航栏样式 */
+	.slot-wrap {
+		display: flex;
+		align-items: center;
+		/* 如果您想让slot内容占满整个导航栏的宽度 */
+		flex: 1;
+		/* 如果您想让slot内容与导航栏左右有空隙 */
+		padding: 0 30rpx;
+		color: #fff;
+		font-size: 28upx;
+		.left-icon {
+			flex-grow: 1;
+			font-size: 32upx;
+			margin-right: 10upx;
+			text-align: center;
+		}
+		.right-icon {
+			padding-left: 50upx;
+		}
+		.uni-icons {
+			margin-right: 10upx;
+		}
+	}
+	// 内容
+	.myShopTour-con{
+		.data-list{
+			height: calc(100vh - 84px);
+			.swiper-item{
+				.scroll-con{
+					height: 100%;
+					.loadmore{
+						padding: 30upx;
+					}
+				}
+			}
+		}
+	}
+}
+</style>

+ 132 - 0
pages/shopTourCompleted/shopTourCompleted.vue

@@ -0,0 +1,132 @@
+<template>
+	<view class="shopTourCompleted-wrap">
+		<view class="info-con">
+			<view class="inspection-info">
+				<view class="info-main">
+					<text class="info-tit">门店:</text>
+					<text class="info-val">常青二路店常青二路店常青二路店常青二路店常青二路店常青二路店常青二路店常青二路店常青二路店常青二路店常青二路店常青二路店常青二路店</text>
+				</view>
+				<view class="info-main">
+					<text class="info-tit">巡店人:</text>
+					<text class="info-val">常青二路店</text>
+				</view>
+				<view class="info-main">
+					<text class="info-tit">创建时间:</text>
+					<text class="info-val">2020-9-7 11:12</text>
+				</view>
+				<view class="info-main">
+					<text class="info-tit">完成时间:</text>
+					<text class="info-val">2020-9-7 16:20</text>
+				</view>
+				<view class="info-main">
+					<text class="info-tit">耗时:</text>
+					<text class="info-val">5小时8分</text>
+				</view>
+			</view>
+			<view class="inspection-items">
+				<u-grid :col="4" :hover-class="none">
+					<u-grid-item>
+						<text class="grid-num text-blue">18</text>
+						<text class="grid-text">检查项</text>
+					</u-grid-item>
+					<u-grid-item>
+						<text class="grid-num text-green">13</text>
+						<text class="grid-text">合格</text>
+					</u-grid-item>
+					<u-grid-item>
+						<text class="grid-num text-red">3</text>
+						<text class="grid-text">不合格</text>
+					</u-grid-item>
+					<u-grid-item>
+						<text class="grid-num text-yellow">2</text>
+						<text class="grid-text">不适用</text>
+					</u-grid-item>
+				</u-grid>
+			</view>
+		</view>
+		<view class="btn-con">
+			<u-button type="primary" shape="circle" class="btn">查看明细</u-button>
+			<u-button shape="circle" class="btn" @click="goMyShopTour">我的巡店记录</u-button>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default{
+		data(){
+			return{
+				
+			}
+		},
+		methods: {
+			goMyShopTour(){
+				uni.navigateTo({
+					url: '/pages/myShopTour/myShopTour'
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	page{
+		background-color: #f8f8f8;
+		height: calc(100vh - 44px);
+	}
+	.shopTourCompleted-wrap{
+		height: 100%;
+		padding: 20upx 30upx 0;
+		box-sizing: border-box;
+		.info-con{
+			.inspection-info{
+				background-color: #fff;
+				padding: 20upx 30upx;
+				.info-main{
+					font-size: 28upx;
+					line-height: 48upx;
+					padding: 10upx 0;
+					position: relative;
+					.info-tit{
+						display: inline-block;
+						position: absolute;
+						left: 0;
+						top: 10upx;
+					}
+					.info-val{
+						display: inline-block;
+						padding-left: 150upx;
+					}
+				}
+			}
+			.inspection-items{
+				.text-blue{
+					color: #2979ff;
+				}
+				.text-green{
+					color: #19be6b;
+				}
+				.text-red{
+					color: #fa3534;
+				}
+				.text-yellow{
+					color: #ff9900;
+				}
+				.grid-num{
+					font-weight: bold;
+				}
+				.grid-text{
+					font-size: 26upx;
+					padding-top: 10upx;
+					color: #666;
+				}
+			}
+		}
+		.btn-con{
+			margin-top: 90upx;
+			.btn{
+				width: 60%;
+				margin-top: 40upx;
+			}
+		}
+	}
+</style>

+ 71 - 0
pages/shopTourOver/shopTourOver.vue

@@ -0,0 +1,71 @@
+<template>
+	<view class="shopTourOver-wrap">
+		<!-- 店长签名 -->
+		<view class="autograph-con">
+			<text class="autograph-tit">店长签名:</text>
+			<view class="autograph-main">
+				<autograph-to-pic canvasId="handWriting-dz" :isEmpty="isEmpty" />
+			</view>
+		</view>
+		<!-- 巡店人签名 -->
+		<view class="autograph-con">
+			<text class="autograph-tit">巡店人签名:</text>
+			<view class="autograph-main">
+				<autograph-to-pic canvasId="handWriting-xd" :isEmpty="isEmpty" />
+			</view>
+		</view>
+		<u-button type="primary" shape="circle" class="submit-btn" @click="submitFun">提交</u-button>
+	</view>
+</template>
+
+<script>
+	import AutographToPic from '@/components/autograph-to-pic/autograph-to-pic.vue'
+	export default{
+		components: {
+			AutographToPic
+		},
+		data(){
+			return{
+				isEmpty: [  //  是否为空判断
+					{name: 'handWriting-dz', state: false},
+					{name: 'handWriting-xd', state: false}
+				]
+			}
+		},
+		methods: {
+			//  提交
+			submitFun(){
+				// this.isEmpty = [
+				// 	{name: 'handWriting-dz', state: true},
+				// 	{name: 'handWriting-xd', state: true},
+				// ]
+				uni.navigateTo({
+					url: '/pages/shopTourCompleted/shopTourCompleted'
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	page{
+		background-color: #f8f8f8;
+		height: calc(100vh - 44px);
+	}
+	.shopTourOver-wrap{
+		height: 100%;
+		.autograph-con{
+			margin: 30upx 30upx 0;
+			border-radius: 12upx;
+			background-color: #fff;
+			.autograph-tit{
+				display: block;
+				padding:  20upx 30upx;
+			}
+		}
+		.submit-btn{
+			width: 80%;
+			margin: 60upx auto 40upx;
+		}
+	}
+</style>

+ 171 - 0
pages/signIn/signIn.vue

@@ -0,0 +1,171 @@
+<template>
+	<view class="signIn-wrap">
+		<!-- 门店名称 -->
+		<view class="module-con first-con">
+			<text class="info-tit">门店名称:</text>
+			<view class="info-main">
+				<text class="location-addr">常青二路店</text>
+			</view>
+		</view>
+		<!-- 定位 -->
+		<view class="module-con">
+			<text class="info-tit">当前位置:</text>
+			<view class="info-main" @click="getLocation">
+				<text class="location-addr">{{location}}</text>
+				<u-icon name="map" color="#2979ff" size="34" class="location-icon"></u-icon>
+			</view>
+		</view>
+		<!-- 拍照签到 -->
+		<view class="module-con">
+			<text class="info-tit">拍照签到:</text>
+			<view class="info-main">
+				<view class="photograph-con" @click="photograph ? null : goPhotograph()">
+					<u-icon v-show="photograph" name="close-circle-fill" color="#fa3534" size="50" class="close-circle-icon" @click="cancelPhotograph"></u-icon>
+					<u-icon v-show="!photograph" name="camera" color="#bfbfbf" size="60" class="photograph-icon"></u-icon>
+					<u-image v-show="photograph" width="100%" height="100%" :src="photograph" @click="previewPictures"></u-image>
+				</view>
+			</view>
+		</view>
+		<u-button type="primary" class="submit-btn" @click="signInFun">签到并开始巡店</u-button>
+	</view>
+</template>
+
+<script>
+	import { clzConfirm } from '@/libs/tools.js'
+	export default{
+		data(){
+			return{
+				location: '',  //  当前位置
+				photograph: '',  //  拍照
+			}
+		},
+		onShow() {
+			this.init()
+		},
+		methods: {
+			// 初始化
+			init(){
+				this.getLocation()
+			},
+			// 获取当前位置
+			getLocation(){
+				const _this = this
+				uni.getLocation({
+				    type: 'gcj02',
+					geocode: true,
+				    success: function (res) {
+						console.log(res)
+						_this.location = res.address.province + res.address.city + res.address.district + res.address.street + res.address.streetNum +'靠近' + res.address.poiName
+						console.log(_this.location, '城市编码 ', res.address.cityCode)
+				    }
+				})
+			},
+			//  签到拍照
+			goPhotograph(){
+				const _this = this
+				uni.chooseImage({
+				    count: 1, //最多可以选择的图片张数,默认9
+				    sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
+				    sourceType: ['camera'], //album 从相册选图,camera 使用相机,默认二者都有
+				    success: function (res) {
+						// tempFilePaths 图片的本地文件路径列表,tempFiles 图片的本地文件列表,每一项是一个 File 对象
+				        console.log(JSON.stringify(res.tempFilePaths))
+						_this.photograph = res.tempFilePaths[0]
+				    }
+				})
+			},
+			//  签到
+			signInFun(){
+				//  判断是否超出签到范围
+				const outRange = false
+				if(outRange){
+					this.isOutRange()
+				}else{
+					//  跳转  开始巡店
+					uni.redirectTo({
+						url: '/pages/shopTourOver/shopTourOver'
+					})
+				}
+			},
+			// 超出范围 提示
+			isOutRange(){
+				clzConfirm({
+				    title: '提示',
+				    content: '您所在的位置超出门店签到范围,无法开启巡店!',
+					showCancel: false,
+				    success: function (res) {
+				        if (res.confirm||res.index==0) {
+				           
+				        }
+				    }
+				})
+			},
+			//  预览签到图
+			previewPictures(){
+				const photograph = [this.photograph]
+				uni.previewImage({
+					urls: photograph
+				})
+			},
+			//  删除签到图
+			cancelPhotograph(){
+				setTimeout(()=>{
+					this.photograph = ''
+				},500)
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	page{
+		background-color: #f8f8f8;
+		height: calc(100vh - 44px);
+	}
+	.signIn-wrap{
+		height: 100%;
+		.module-con{
+			padding: 0 30upx 20upx;
+			.info-main{
+				margin-top: 14upx;
+				padding: 20upx;
+				border-radius: 12upx;
+				background-color: #fff;
+				.location-addr{
+					font-size: 24upx;
+				}
+				.location-icon{
+					padding-left: 10upx;
+					vertical-align: bottom;
+				}
+				.photograph-con{
+					border: 2upx dashed #bfbfbf;
+					border-radius: 12upx;
+					width: 160upx;
+					height: 160upx;
+					text-align: center;
+					position: relative;
+					.photograph-icon{
+						display: inline-block;
+						padding-top: 48upx;
+					}
+					.close-circle-icon{
+						background-color: #fff;
+						border-radius: 50%;
+						position: absolute;
+						right: -23upx;
+						top: -23upx;
+						z-index: 9;
+					}
+				}
+			}
+		}
+		.first-con{
+			padding-top: 30upx;
+		}
+		.submit-btn{
+			width: 80%;
+			margin-top: 50upx;
+		}
+	}
+</style>

+ 179 - 0
pages/siteInspection/siteInspection.vue

@@ -0,0 +1,179 @@
+<template>
+	<view class="siteInspection-wrap">
+		<!-- 搜索框 -->
+		<view class="search-con">
+			<u-search placeholder="查找全部门店" v-model="queryValue" @custom="searchHandle(1)" @search="searchHandle(1)" bg-color="#fff" :action-style="{background: '#2979ff',color: '#fff', borderRadius: '6upx',padding: '6upx 0', fontSize: '26upx'}"></u-search>
+		</view>
+		<!-- 定位 -->
+		<view class="location-con">
+			<text class="location-tit">当前位置:</text>
+			<view class="location-main" @click="getLocation">
+				<text class="location-addr">{{location}}</text>
+				<u-icon name="map" color="#2979ff" size="34" class="location-icon"></u-icon>
+			</view>
+		</view>
+		<!-- 附近的门店 -->
+		<view class="store-con">
+			<text class="store-tit">附近的门店:</text>
+			<scroll-view class="scroll-con" scroll-y @scrolltolower="onreachBottom">
+				<!-- 列表数据 -->
+				<view class="list-con">
+					<view class="list-item" v-for="(item,index) in listdata" :key="index" @click="chooseStore(item)">
+						<view class="item-main">
+							<u-icon name="home-fill" size="34" color="#2979ff" class="company-icon"></u-icon>
+							{{item.name}}
+						</view>
+						<u-icon name="rewind-right-fill" size="34" color="#2979ff" class="company-icon"></u-icon>
+					</view>
+				</view>
+				<u-empty class="nodata" :text="noDataText" v-if="listdata.length==0 && status!='loading'" mode="list"></u-empty>
+				<view class="loadmore">
+					<u-loadmore v-if="total>pageSize || status=='loading'" :status="status" />
+				</view>
+			</scroll-view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default{
+		data(){
+			return{
+				queryValue: '',
+				location: '',
+				noDataText: '未查找到附近门店',  //  列表请求状态提示语
+				status: 'loadmore',  //  加载中状态
+				// status: 'loading',  //  加载中状态
+				listdata: [
+					{name: '常青二路店'},
+					{name: '兰州通达街店'},
+					{name: '科技西路店'},
+					{name: '常青二路店'},
+				],  //  列表数据
+				pageNo: 1,  //  当前页码
+				pageSize: 10,  //  每页条数
+				total: 0,  //  数据总条数
+			}
+		},
+		onShow() {
+			this.init()
+		},
+		methods: {
+			// 初始化
+			init(){
+				this.getLocation()
+			},
+			// 获取当前位置
+			getLocation(){
+				const _this = this
+				uni.getLocation({
+				    type: 'gcj02',
+					geocode: true,
+				    success: function (res) {
+						console.log(res)
+						_this.location = res.address.province + res.address.city + res.address.district + res.address.street + res.address.streetNum +'靠近' + res.address.poiName
+						console.log(_this.location, '城市编码 ', res.address.cityCode)
+				    }
+				})
+			},
+			//  
+			searchHandle(pageNo){
+				// this.status = "loading"
+				pageNo ? this.pageNo = pageNo : null
+				// searchSuppliers({
+				// 	pageNo: this.pageNo,
+				// 	pageSize: this.pageSize,
+				// 	queryWord: this.queryValue
+				// }).then(res => {
+				// 	if (res.status == 200) {
+				// 		if(this.pageNo>1){
+				// 			this.listdata = this.listdata.concat(res.data.list || [])
+				// 		}else{
+				// 			this.listdata = res.data.list || []
+				// 		}
+				// 		this.total = res.data.count || 0
+				// 		this.listdata.length == 0 && this.queryValue != '' ? this.noDataText = '没有搜索到相关结果' : this.noDataText = '暂无数据'
+				// 	} else {
+				// 		this.noDataText = res.message
+				// 		this.listdata = []
+				// 		this.total = 0
+				// 	}
+				// 	this.status = "loadmore"
+				// })
+			},
+			// scroll-view到底部加载更多
+			onreachBottom() {
+				if(this.listdata.length < this.total){
+					this.pageNo += 1
+					this.searchHandle()
+				}else{
+					this.status = "nomore"
+				}
+			},
+			//  选择门店
+			chooseStore(item){
+				uni.navigateTo({
+					url:"/pages/signIn/signIn"
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.siteInspection-wrap{
+		background-color: #f8f8f8;
+		.search-con{
+			padding: 30upx 30upx;
+		}
+		// 定位
+		.location-con{
+			padding: 0 30upx;
+			.location-main{
+				margin-top: 14upx;
+				padding: 20upx;
+				border-radius: 12upx;
+				background-color: #fff;
+				.location-addr{
+					font-size: 24upx;
+				}
+				.location-icon{
+					padding-left: 10upx;
+					vertical-align: bottom;
+				}
+			}
+		}
+		// 附近的门店
+		.store-con{
+			.store-tit{
+				display: block;
+				padding: 30upx 30upx 20upx;
+			}
+			//  列表
+			.scroll-con{
+				height: calc(100vh - 215px);
+				width: 100%;
+				overflow: auto;
+				.list-con{
+					padding: 0 30upx;
+					.list-item{
+						background-color: #fff;
+						border-radius: 16upx;
+						padding: 20upx 30upx 18upx;
+						margin-bottom: 20upx;
+						display: flex;
+						justify-content: space-between;
+						align-items: center;
+						.item-main{
+							font-size: 15px;
+							color: rgb(48, 49, 51);
+							.company-icon{
+								margin-right: 6upx;
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+</style>

+ 9 - 2
pages/work/work.vue

@@ -1,6 +1,8 @@
 <template>
 	<view>
-		
+		<button @click="openSiteInspection">
+			现场巡店
+		</button>
 	</view>
 </template>
 
@@ -12,7 +14,12 @@
 			}
 		},
 		methods: {
-			
+			// 现场巡店
+			openSiteInspection() {
+				 uni.navigateTo({
+				 	url:"/pages/siteInspection/siteInspection"
+				 })
+			}
 		}
 	}
 </script>