Kaynağa Gözat

feat:协议 登陆 及其他优化

DaMowang 3 yıl önce
ebeveyn
işleme
2332efada0

+ 634 - 0
src/components/jyf-parser/jyf-parser.vue

@@ -0,0 +1,634 @@
+<template>
+	<view>
+		<slot v-if="!nodes.length" />
+		<!--#ifdef APP-PLUS-NVUE-->
+		<web-view id="_top" ref="web" :style="'margin-top:-2px;height:'+height+'px'" @onPostMessage="_message" />
+		<!--#endif-->
+		<!--#ifndef APP-PLUS-NVUE-->
+		<view id="_top" :style="showAm+(selectable?';user-select:text;-webkit-user-select:text':'')">
+			<!--#ifdef H5 || MP-360-->
+			<div :id="'rtf'+uid"></div>
+			<!--#endif-->
+			<!--#ifndef H5 || MP-360-->
+			<trees :nodes="nodes" :lazyLoad="lazyLoad" :loading="loadingImg" />
+			<!--#endif-->
+		</view>
+		<!--#endif-->
+	</view>
+</template>
+
+<script>
+	// #ifndef H5 || APP-PLUS-NVUE || MP-360
+	import trees from './libs/trees';
+	var cache = {},
+		// #ifdef MP-WEIXIN || MP-TOUTIAO
+		fs = uni.getFileSystemManager ? uni.getFileSystemManager() : null,
+		// #endif
+		Parser = require('./libs/MpHtmlParser.js');
+	var dom;
+	// 计算 cache 的 key
+	function hash(str) {
+		for (var i = str.length, val = 5381; i--;)
+			val += (val << 5) + str.charCodeAt(i);
+		return val;
+	}
+	// #endif
+	// #ifdef H5 || APP-PLUS-NVUE || MP-360
+	var {
+		windowWidth,
+		platform
+	} = uni.getSystemInfoSync(),
+		cfg = require('./libs/config.js');
+	// #endif
+	// #ifdef APP-PLUS-NVUE
+	var weexDom = weex.requireModule('dom');
+	// #endif
+	/**
+	 * Parser 富文本组件
+	 * @tutorial https://github.com/jin-yufeng/Parser
+	 * @property {String} html 富文本数据
+	 * @property {Boolean} autopause 是否在播放一个视频时自动暂停其他视频
+	 * @property {Boolean} autoscroll 是否自动给所有表格添加一个滚动层
+	 * @property {Boolean} autosetTitle 是否自动将 title 标签中的内容设置到页面标题
+	 * @property {Number} compress 压缩等级
+	 * @property {String} domain 图片、视频等链接的主域名
+	 * @property {Boolean} lazyLoad 是否开启图片懒加载
+	 * @property {String} loadingImg 图片加载完成前的占位图
+	 * @property {Boolean} selectable 是否开启长按复制
+	 * @property {Object} tagStyle 标签的默认样式
+	 * @property {Boolean} showWithAnimation 是否使用渐显动画
+	 * @property {Boolean} useAnchor 是否使用锚点
+	 * @property {Boolean} useCache 是否缓存解析结果
+	 * @event {Function} parse 解析完成事件
+	 * @event {Function} load dom 加载完成事件
+	 * @event {Function} ready 所有图片加载完毕事件
+	 * @event {Function} error 错误事件
+	 * @event {Function} imgtap 图片点击事件
+	 * @event {Function} linkpress 链接点击事件
+	 * @author JinYufeng
+	 * @version 20200828
+	 * @listens MIT
+	 */
+	export default {
+		name: 'parser',
+		data() {
+			return {
+				// #ifdef H5 || MP-360
+				uid: this._uid,
+				// #endif
+				// #ifdef APP-PLUS-NVUE
+				height: 1,
+				// #endif
+				// #ifndef APP-PLUS-NVUE
+				showAm: '',
+				// #endif
+				nodes: []
+			}
+		},
+		// #ifndef H5 || APP-PLUS-NVUE || MP-360
+		components: {
+			trees
+		},
+		// #endif
+		props: {
+			html: String,
+			autopause: {
+				type: Boolean,
+				default: true
+			},
+			autoscroll: Boolean,
+			autosetTitle: {
+				type: Boolean,
+				default: true
+			},
+			// #ifndef H5 || APP-PLUS-NVUE || MP-360
+			compress: Number,
+			loadingImg: String,
+			useCache: Boolean,
+			// #endif
+			domain: String,
+			lazyLoad: Boolean,
+			selectable: Boolean,
+			tagStyle: Object,
+			showWithAnimation: Boolean,
+			useAnchor: Boolean
+		},
+		watch: {
+			html(html) {
+				this.setContent(html);
+			}
+		},
+		created() {
+			// 图片数组
+			this.imgList = [];
+			this.imgList.each = function(f) {
+				for (var i = 0, len = this.length; i < len; i++)
+					this.setItem(i, f(this[i], i, this));
+			}
+			this.imgList.setItem = function(i, src) {
+				if (i == void 0 || !src) return;
+				// #ifndef MP-ALIPAY || APP-PLUS
+				// 去重
+				if (src.indexOf('http') == 0 && this.includes(src)) {
+					var newSrc = src.split('://')[0];
+					for (var j = newSrc.length, c; c = src[j]; j++) {
+						if (c == '/' && src[j - 1] != '/' && src[j + 1] != '/') break;
+						newSrc += Math.random() > 0.5 ? c.toUpperCase() : c;
+					}
+					newSrc += src.substr(j);
+					return this[i] = newSrc;
+				}
+				// #endif
+				this[i] = src;
+				// 暂存 data src
+				if (src.includes('data:image')) {
+					var filePath, info = src.match(/data:image\/(\S+?);(\S+?),(.+)/);
+					if (!info) return;
+					// #ifdef MP-WEIXIN || MP-TOUTIAO
+					filePath = `${wx.env.USER_DATA_PATH}/${Date.now()}.${info[1]}`;
+					fs && fs.writeFile({
+						filePath,
+						data: info[3],
+						encoding: info[2],
+						success: () => this[i] = filePath
+					})
+					// #endif
+					// #ifdef APP-PLUS
+					filePath = `_doc/parser_tmp/${Date.now()}.${info[1]}`;
+					var bitmap = new plus.nativeObj.Bitmap();
+					bitmap.loadBase64Data(src, () => {
+						bitmap.save(filePath, {}, () => {
+							bitmap.clear()
+							this[i] = filePath;
+						})
+					})
+					// #endif
+				}
+			}
+		},
+		mounted() {
+			// #ifdef H5 || MP-360
+			this.document = document.getElementById('rtf' + this._uid);
+			// #endif
+			// #ifndef H5 || APP-PLUS-NVUE || MP-360
+			if (dom) this.document = new dom(this);
+			// #endif
+			// #ifdef APP-PLUS-NVUE
+			this.document = this.$refs.web;
+			setTimeout(() => {
+				// #endif
+				if (this.html) this.setContent(this.html);
+				// #ifdef APP-PLUS-NVUE
+			}, 30)
+			// #endif
+		},
+		beforeDestroy() {
+			// #ifdef H5 || MP-360
+			if (this._observer) this._observer.disconnect();
+			// #endif
+			this.imgList.each(src => {
+				// #ifdef APP-PLUS
+				if (src && src.includes('_doc')) {
+					plus.io.resolveLocalFileSystemURL(src, entry => {
+						entry.remove();
+					});
+				}
+				// #endif
+				// #ifdef MP-WEIXIN || MP-TOUTIAO
+				if (src && src.includes(uni.env.USER_DATA_PATH))
+					fs && fs.unlink({
+						filePath: src
+					})
+				// #endif
+			})
+			clearInterval(this._timer);
+		},
+		methods: {
+			// 设置富文本内容
+			setContent(html, append) {
+				// #ifdef APP-PLUS-NVUE
+				if (!html)
+					return this.height = 1;
+				if (append)
+					this.$refs.web.evalJs("var b=document.createElement('div');b.innerHTML='" + html.replace(/'/g, "\\'") +
+						"';document.getElementById('parser').appendChild(b)");
+				else {
+					html =
+						'<meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"><style>html,body{width:100%;height:100%;overflow:hidden}body{margin:0}</style><base href="' +
+						this.domain + '"><div id="parser"' + (this.selectable ? '>' : ' style="user-select:none">') + this._handleHtml(html).replace(/\n/g, '\\n') +
+						'</div><script>"use strict";function e(e){if(window.__dcloud_weex_postMessage||window.__dcloud_weex_){var t={data:[e]};window.__dcloud_weex_postMessage?window.__dcloud_weex_postMessage(t):window.__dcloud_weex_.postMessage(JSON.stringify(t))}}document.body.onclick=function(){e({action:"click"})},' +
+						(this.showWithAnimation ? 'document.body.style.animation="_show .5s",' : '') +
+						'setTimeout(function(){e({action:"load",text:document.body.innerText,height:document.getElementById("parser").scrollHeight})},50);\x3c/script>';
+					if (platform == 'android') html = html.replace(/%/g, '%25');
+					this.$refs.web.evalJs("document.write('" + html.replace(/'/g, "\\'") + "');document.close()");
+				}
+				this.$refs.web.evalJs(
+					'var t=document.getElementsByTagName("title");t.length&&e({action:"getTitle",title:t[0].innerText});for(var o,n=document.getElementsByTagName("style"),r=1;o=n[r++];)o.innerHTML=o.innerHTML.replace(/body/g,"#parser");for(var a,c=document.getElementsByTagName("img"),s=[],i=0==c.length,d=0,l=0,g=0;a=c[l];l++)parseInt(a.style.width||a.getAttribute("width"))>' +
+					windowWidth + '&&(a.style.height="auto"),a.onload=function(){++d==c.length&&(i=!0)},a.onerror=function(){++d==c.length&&(i=!0),' + (cfg.errorImg ? 'this.src="' + cfg.errorImg + '",' : '') +
+					'e({action:"error",source:"img",target:this})},a.hasAttribute("ignore")||"A"==a.parentElement.nodeName||(a.i=g++,s.push(a.getAttribute("original-src")||a.src||a.getAttribute("data-src")),a.onclick=function(){e({action:"preview",img:{i:this.i,src:this.src}})});e({action:"getImgList",imgList:s});for(var u,m=document.getElementsByTagName("a"),f=0;u=m[f];f++)u.onclick=function(){var t,o=this.getAttribute("href");if("#"==o[0]){var n=document.getElementById(o.substr(1));n&&(t=n.offsetTop)}return e({action:"linkpress",href:o,offset:t}),!1};for(var h,y=document.getElementsByTagName("video"),v=0;h=y[v];v++)h.style.maxWidth="100%",h.onerror=function(){e({action:"error",source:"video",target:this})}' +
+					(this.autopause ? ',h.onplay=function(){for(var e,t=0;e=y[t];t++)e!=this&&e.pause()}' : '') +
+					';for(var _,p=document.getElementsByTagName("audio"),w=0;_=p[w];w++)_.onerror=function(){e({action:"error",source:"audio",target:this})};' +
+					(this.autoscroll ? 'for(var T,E=document.getElementsByTagName("table"),B=0;T=E[B];B++){var N=document.createElement("div");N.style.overflow="scroll",T.parentNode.replaceChild(N,T),N.appendChild(T)}' : '') +
+					'var x=document.getElementById("parser");clearInterval(window.timer),window.timer=setInterval(function(){i&&clearInterval(window.timer),e({action:"ready",ready:i,height:x.scrollHeight})},350)'
+				)
+				this.nodes = [1];
+				// #endif
+				// #ifdef H5 || MP-360
+				if (!html) {
+					if (this.rtf && !append) this.rtf.parentNode.removeChild(this.rtf);
+					return;
+				}
+				var div = document.createElement('div');
+				if (!append) {
+					if (this.rtf) this.rtf.parentNode.removeChild(this.rtf);
+					this.rtf = div;
+				} else {
+					if (!this.rtf) this.rtf = div;
+					else this.rtf.appendChild(div);
+				}
+				div.innerHTML = this._handleHtml(html, append);
+				for (var styles = this.rtf.getElementsByTagName('style'), i = 0, style; style = styles[i++];) {
+					style.innerHTML = style.innerHTML.replace(/body/g, '#rtf' + this._uid);
+					style.setAttribute('scoped', 'true');
+				}
+				// 懒加载
+				if (!this._observer && this.lazyLoad && IntersectionObserver) {
+					this._observer = new IntersectionObserver(changes => {
+						for (let item, i = 0; item = changes[i++];) {
+							if (item.isIntersecting) {
+								item.target.src = item.target.getAttribute('data-src');
+								item.target.removeAttribute('data-src');
+								this._observer.unobserve(item.target);
+							}
+						}
+					}, {
+						rootMargin: '500px 0px 500px 0px'
+					})
+				}
+				var _ts = this;
+				// 获取标题
+				var title = this.rtf.getElementsByTagName('title');
+				if (title.length && this.autosetTitle)
+					uni.setNavigationBarTitle({
+						title: title[0].innerText
+					})
+				// 图片处理
+				this.imgList.length = 0;
+				var imgs = this.rtf.getElementsByTagName('img');
+				for (let i = 0, j = 0, img; img = imgs[i]; i++) {
+					if (parseInt(img.style.width || img.getAttribute('width')) > windowWidth)
+						img.style.height = 'auto';
+					var src = img.getAttribute('src');
+					if (this.domain && src) {
+						if (src[0] == '/') {
+							if (src[1] == '/')
+								img.src = (this.domain.includes('://') ? this.domain.split('://')[0] : '') + ':' + src;
+							else img.src = this.domain + src;
+						} else if (!src.includes('://')) img.src = this.domain + '/' + src;
+					}
+					if (!img.hasAttribute('ignore') && img.parentElement.nodeName != 'A') {
+						img.i = j++;
+						_ts.imgList.push(img.getAttribute('original-src') || img.src || img.getAttribute('data-src'));
+						img.onclick = function() {
+							var preview = true;
+							this.ignore = () => preview = false;
+							_ts.$emit('imgtap', this);
+							if (preview) {
+								uni.previewImage({
+									current: this.i,
+									urls: _ts.imgList
+								});
+							}
+						}
+					}
+					img.onerror = function() {
+						if (cfg.errorImg)
+							_ts.imgList[this.i] = this.src = cfg.errorImg;
+						_ts.$emit('error', {
+							source: 'img',
+							target: this
+						});
+					}
+					if (_ts.lazyLoad && this._observer && img.src && img.i != 0) {
+						img.setAttribute('data-src', img.src);
+						img.removeAttribute('src');
+						this._observer.observe(img);
+					}
+				}
+				// 链接处理
+				var links = this.rtf.getElementsByTagName('a');
+				for (var link of links) {
+					link.onclick = function() {
+						var jump = true,
+							href = this.getAttribute('href');
+						_ts.$emit('linkpress', {
+							href,
+							ignore: () => jump = false
+						});
+						if (jump && href) {
+							if (href[0] == '#') {
+								if (_ts.useAnchor) {
+									_ts.navigateTo({
+										id: href.substr(1)
+									})
+								}
+							} else if (href.indexOf('http') == 0 || href.indexOf('//') == 0)
+								return true;
+							else
+								uni.navigateTo({
+									url: href
+								})
+						}
+						return false;
+					}
+				}
+				// 视频处理
+				var videos = this.rtf.getElementsByTagName('video');
+				_ts.videoContexts = videos;
+				for (let video, i = 0; video = videos[i++];) {
+					video.style.maxWidth = '100%';
+					video.onerror = function() {
+						_ts.$emit('error', {
+							source: 'video',
+							target: this
+						});
+					}
+					video.onplay = function() {
+						if (_ts.autopause)
+							for (let item, i = 0; item = _ts.videoContexts[i++];)
+								if (item != this) item.pause();
+					}
+				}
+				// 音频处理
+				var audios = this.rtf.getElementsByTagName('audio');
+				for (var audio of audios)
+					audio.onerror = function() {
+						_ts.$emit('error', {
+							source: 'audio',
+							target: this
+						});
+					}
+				// 表格处理
+				if (this.autoscroll) {
+					var tables = this.rtf.getElementsByTagName('table');
+					for (var table of tables) {
+						let div = document.createElement('div');
+						div.style.overflow = 'scroll';
+						table.parentNode.replaceChild(div, table);
+						div.appendChild(table);
+					}
+				}
+				if (!append) this.document.appendChild(this.rtf);
+				this.$nextTick(() => {
+					this.nodes = [1];
+					this.$emit('load');
+				});
+				setTimeout(() => this.showAm = '', 500);
+				// #endif
+				// #ifndef APP-PLUS-NVUE
+				// #ifndef H5 || MP-360
+				var nodes;
+				if (!html) return this.nodes = [];
+				var parser = new Parser(html, this);
+				// 缓存读取
+				if (this.useCache) {
+					var hashVal = hash(html);
+					if (cache[hashVal])
+						nodes = cache[hashVal];
+					else {
+						nodes = parser.parse();
+						cache[hashVal] = nodes;
+					}
+				} else nodes = parser.parse();
+				this.$emit('parse', nodes);
+				if (append) this.nodes = this.nodes.concat(nodes);
+				else this.nodes = nodes;
+				if (nodes.length && nodes.title && this.autosetTitle)
+					uni.setNavigationBarTitle({
+						title: nodes.title
+					})
+				if (this.imgList) this.imgList.length = 0;
+				this.videoContexts = [];
+				this.$nextTick(() => {
+					(function f(cs) {
+						for (var i = cs.length; i--;) {
+							if (cs[i].top) {
+								cs[i].controls = [];
+								cs[i].init();
+								f(cs[i].$children);
+							}
+						}
+					})(this.$children)
+					this.$emit('load');
+				})
+				// #endif
+				var height;
+				clearInterval(this._timer);
+				this._timer = setInterval(() => {
+					// #ifdef H5 || MP-360
+					this.rect = this.rtf.getBoundingClientRect();
+					// #endif
+					// #ifndef H5 || MP-360
+					uni.createSelectorQuery().in(this)
+						.select('#_top').boundingClientRect().exec(res => {
+							if (!res) return;
+							this.rect = res[0];
+							// #endif
+							if (this.rect.height == height) {
+								this.$emit('ready', this.rect)
+								clearInterval(this._timer);
+							}
+							height = this.rect.height;
+							// #ifndef H5 || MP-360
+						});
+					// #endif
+				}, 350);
+				if (this.showWithAnimation && !append) this.showAm = 'animation:_show .5s';
+				// #endif
+			},
+			// 获取文本内容
+			getText(ns = this.nodes) {
+				var txt = '';
+				// #ifdef APP-PLUS-NVUE
+				txt = this._text;
+				// #endif
+				// #ifdef H5 || MP-360
+				txt = this.rtf.innerText;
+				// #endif
+				// #ifndef H5 || APP-PLUS-NVUE || MP-360
+				for (var i = 0, n; n = ns[i++];) {
+					if (n.type == 'text') txt += n.text.replace(/&nbsp;/g, '\u00A0').replace(/&lt;/g, '<').replace(/&gt;/g, '>')
+						.replace(/&amp;/g, '&');
+					else if (n.type == 'br') txt += '\n';
+					else {
+						// 块级标签前后加换行
+						var block = n.name == 'p' || n.name == 'div' || n.name == 'tr' || n.name == 'li' || (n.name[0] == 'h' && n.name[1] >
+							'0' && n.name[1] < '7');
+						if (block && txt && txt[txt.length - 1] != '\n') txt += '\n';
+						if (n.children) txt += this.getText(n.children);
+						if (block && txt[txt.length - 1] != '\n') txt += '\n';
+						else if (n.name == 'td' || n.name == 'th') txt += '\t';
+					}
+				}
+				// #endif
+				return txt;
+			},
+			// 锚点跳转
+			in (obj) {
+				if (obj.page && obj.selector && obj.scrollTop) this._in = obj;
+			},
+			navigateTo(obj) {
+				if (!this.useAnchor) return obj.fail && obj.fail('Anchor is disabled');
+				// #ifdef APP-PLUS-NVUE
+				if (!obj.id)
+					weexDom.scrollToElement(this.$refs.web);
+				else
+					this.$refs.web.evalJs('var pos=document.getElementById("' + obj.id +
+						'");if(pos)post({action:"linkpress",href:"#",offset:pos.offsetTop+' + (obj.offset || 0) + '})');
+				obj.success && obj.success();
+				// #endif
+				// #ifndef APP-PLUS-NVUE
+				var d = ' ';
+				// #ifdef MP-WEIXIN || MP-QQ || MP-TOUTIAO
+				d = '>>>';
+				// #endif
+				var selector = uni.createSelectorQuery().in(this._in ? this._in.page : this).select((this._in ? this._in.selector :
+					'#_top') + (obj.id ? `${d}#${obj.id},${this._in?this._in.selector:'#_top'}${d}.${obj.id}` : '')).boundingClientRect();
+				if (this._in) selector.select(this._in.selector).scrollOffset().select(this._in.selector).boundingClientRect();
+				else selector.selectViewport().scrollOffset();
+				selector.exec(res => {
+					if (!res[0]) return obj.fail && obj.fail('Label not found')
+					var scrollTop = res[1].scrollTop + res[0].top - (res[2] ? res[2].top : 0) + (obj.offset || 0);
+					if (this._in) this._in.page[this._in.scrollTop] = scrollTop;
+					else uni.pageScrollTo({
+						scrollTop,
+						duration: 300
+					})
+					obj.success && obj.success();
+				})
+				// #endif
+			},
+			// 获取视频对象
+			getVideoContext(id) {
+				// #ifndef APP-PLUS-NVUE
+				if (!id) return this.videoContexts;
+				else
+					for (var i = this.videoContexts.length; i--;)
+						if (this.videoContexts[i].id == id) return this.videoContexts[i];
+				// #endif
+			},
+			// #ifdef H5 || APP-PLUS-NVUE || MP-360
+			_handleHtml(html, append) {
+				if (!append) {
+					// 处理 tag-style 和 userAgentStyles
+					var style = '<style>@keyframes _show{0%{opacity:0}100%{opacity:1}}img{max-width:100%}';
+					for (var item in cfg.userAgentStyles)
+						style += `${item}{${cfg.userAgentStyles[item]}}`;
+					for (item in this.tagStyle)
+						style += `${item}{${this.tagStyle[item]}}`;
+					style += '</style>';
+					html = style + html;
+				}
+				// 处理 rpx
+				if (html.includes('rpx'))
+					html = html.replace(/[0-9.]+\s*rpx/g, $ => (parseFloat($) * windowWidth / 750) + 'px');
+				return html;
+			},
+			// #endif
+			// #ifdef APP-PLUS-NVUE
+			_message(e) {
+				// 接收 web-view 消息
+				var d = e.detail.data[0];
+				switch (d.action) {
+					case 'load':
+						this.$emit('load');
+						this.height = d.height;
+						this._text = d.text;
+						break;
+					case 'getTitle':
+						if (this.autosetTitle)
+							uni.setNavigationBarTitle({
+								title: d.title
+							})
+						break;
+					case 'getImgList':
+						this.imgList.length = 0;
+						for (var i = d.imgList.length; i--;)
+							this.imgList.setItem(i, d.imgList[i]);
+						break;
+					case 'preview':
+						var preview = true;
+						d.img.ignore = () => preview = false;
+						this.$emit('imgtap', d.img);
+						if (preview)
+							uni.previewImage({
+								current: d.img.i,
+								urls: this.imgList
+							})
+						break;
+					case 'linkpress':
+						var jump = true,
+							href = d.href;
+						this.$emit('linkpress', {
+							href,
+							ignore: () => jump = false
+						})
+						if (jump && href) {
+							if (href[0] == '#') {
+								if (this.useAnchor)
+									weexDom.scrollToElement(this.$refs.web, {
+										offset: d.offset
+									})
+							} else if (href.includes('://'))
+								plus.runtime.openWeb(href);
+							else
+								uni.navigateTo({
+									url: href
+								})
+						}
+						break;
+					case 'error':
+						if (d.source == 'img' && cfg.errorImg)
+							this.imgList.setItem(d.target.i, cfg.errorImg);
+						this.$emit('error', {
+							source: d.source,
+							target: d.target
+						})
+						break;
+					case 'ready':
+						this.height = d.height;
+						if (d.ready) uni.createSelectorQuery().in(this).select('#_top').boundingClientRect().exec(res => {
+							this.rect = res[0];
+							this.$emit('ready', res[0]);
+						})
+						break;
+					case 'click':
+						this.$emit('click');
+						this.$emit('tap');
+				}
+			},
+			// #endif
+		}
+	}
+</script>
+
+<style>
+	@keyframes _show {
+		0% {
+			opacity: 0;
+		}
+
+		100% {
+			opacity: 1;
+		}
+	}
+
+	/* #ifdef MP-WEIXIN */
+	:host {
+		display: block;
+		overflow: scroll;
+		-webkit-overflow-scrolling: touch;
+	}
+
+	/* #endif */
+</style>

+ 97 - 0
src/components/jyf-parser/libs/CssHandler.js

@@ -0,0 +1,97 @@
+const cfg = require('./config.js'),
+	isLetter = c => (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+
+function CssHandler(tagStyle) {
+	var styles = Object.assign(Object.create(null), cfg.userAgentStyles);
+	for (var item in tagStyle)
+		styles[item] = (styles[item] ? styles[item] + ';' : '') + tagStyle[item];
+	this.styles = styles;
+}
+CssHandler.prototype.getStyle = function(data) {
+	this.styles = new parser(data, this.styles).parse();
+}
+CssHandler.prototype.match = function(name, attrs) {
+	var tmp, matched = (tmp = this.styles[name]) ? tmp + ';' : '';
+	if (attrs.class) {
+		var items = attrs.class.split(' ');
+		for (var i = 0, item; item = items[i]; i++)
+			if (tmp = this.styles['.' + item])
+				matched += tmp + ';';
+	}
+	if (tmp = this.styles['#' + attrs.id])
+		matched += tmp + ';';
+	return matched;
+}
+module.exports = CssHandler;
+
+function parser(data, init) {
+	this.data = data;
+	this.floor = 0;
+	this.i = 0;
+	this.list = [];
+	this.res = init;
+	this.state = this.Space;
+}
+parser.prototype.parse = function() {
+	for (var c; c = this.data[this.i]; this.i++)
+		this.state(c);
+	return this.res;
+}
+parser.prototype.section = function() {
+	return this.data.substring(this.start, this.i);
+}
+// 状态机
+parser.prototype.Space = function(c) {
+	if (c == '.' || c == '#' || isLetter(c)) {
+		this.start = this.i;
+		this.state = this.Name;
+	} else if (c == '/' && this.data[this.i + 1] == '*')
+		this.Comment();
+	else if (!cfg.blankChar[c] && c != ';')
+		this.state = this.Ignore;
+}
+parser.prototype.Comment = function() {
+	this.i = this.data.indexOf('*/', this.i) + 1;
+	if (!this.i) this.i = this.data.length;
+	this.state = this.Space;
+}
+parser.prototype.Ignore = function(c) {
+	if (c == '{') this.floor++;
+	else if (c == '}' && !--this.floor) this.state = this.Space;
+}
+parser.prototype.Name = function(c) {
+	if (cfg.blankChar[c]) {
+		this.list.push(this.section());
+		this.state = this.NameSpace;
+	} else if (c == '{') {
+		this.list.push(this.section());
+		this.Content();
+	} else if (c == ',') {
+		this.list.push(this.section());
+		this.Comma();
+	} else if (!isLetter(c) && (c < '0' || c > '9') && c != '-' && c != '_')
+		this.state = this.Ignore;
+}
+parser.prototype.NameSpace = function(c) {
+	if (c == '{') this.Content();
+	else if (c == ',') this.Comma();
+	else if (!cfg.blankChar[c]) this.state = this.Ignore;
+}
+parser.prototype.Comma = function() {
+	while (cfg.blankChar[this.data[++this.i]]);
+	if (this.data[this.i] == '{') this.Content();
+	else {
+		this.start = this.i--;
+		this.state = this.Name;
+	}
+}
+parser.prototype.Content = function() {
+	this.start = ++this.i;
+	if ((this.i = this.data.indexOf('}', this.i)) == -1) this.i = this.data.length;
+	var content = this.section();
+	for (var i = 0, item; item = this.list[i++];)
+		if (this.res[item]) this.res[item] += ';' + content;
+		else this.res[item] = content;
+	this.list = [];
+	this.state = this.Space;
+}

+ 535 - 0
src/components/jyf-parser/libs/MpHtmlParser.js

@@ -0,0 +1,535 @@
+/**
+ * html 解析器
+ * @tutorial https://github.com/jin-yufeng/Parser
+ * @version 20200828
+ * @author JinYufeng
+ * @listens MIT
+ */
+const cfg = require('./config.js'),
+	blankChar = cfg.blankChar,
+	CssHandler = require('./CssHandler.js'),
+	windowWidth = uni.getSystemInfoSync().windowWidth;
+var emoji;
+
+function MpHtmlParser(data, options = {}) {
+	this.attrs = {};
+	this.CssHandler = new CssHandler(options.tagStyle, windowWidth);
+	this.data = data;
+	this.domain = options.domain;
+	this.DOM = [];
+	this.i = this.start = this.audioNum = this.imgNum = this.videoNum = 0;
+	options.prot = (this.domain || '').includes('://') ? this.domain.split('://')[0] : 'http';
+	this.options = options;
+	this.state = this.Text;
+	this.STACK = [];
+	// 工具函数
+	this.bubble = () => {
+		for (var i = this.STACK.length, item; item = this.STACK[--i];) {
+			if (cfg.richOnlyTags[item.name]) {
+				if (item.name == 'table' && !Object.hasOwnProperty.call(item, 'c')) item.c = 1;
+				return false;
+			}
+			item.c = 1;
+		}
+		return true;
+	}
+	this.decode = (val, amp) => {
+		var i = -1,
+			j, en;
+		while (1) {
+			if ((i = val.indexOf('&', i + 1)) == -1) break;
+			if ((j = val.indexOf(';', i + 2)) == -1) break;
+			if (val[i + 1] == '#') {
+				en = parseInt((val[i + 2] == 'x' ? '0' : '') + val.substring(i + 2, j));
+				if (!isNaN(en)) val = val.substr(0, i) + String.fromCharCode(en) + val.substr(j + 1);
+			} else {
+				en = val.substring(i + 1, j);
+				if (cfg.entities[en] || en == amp)
+					val = val.substr(0, i) + (cfg.entities[en] || '&') + val.substr(j + 1);
+			}
+		}
+		return val;
+	}
+	this.getUrl = url => {
+		if (url[0] == '/') {
+			if (url[1] == '/') url = this.options.prot + ':' + url;
+			else if (this.domain) url = this.domain + url;
+		} else if (this.domain && url.indexOf('data:') != 0 && !url.includes('://'))
+			url = this.domain + '/' + url;
+		return url;
+	}
+	this.isClose = () => this.data[this.i] == '>' || (this.data[this.i] == '/' && this.data[this.i + 1] == '>');
+	this.section = () => this.data.substring(this.start, this.i);
+	this.parent = () => this.STACK[this.STACK.length - 1];
+	this.siblings = () => this.STACK.length ? this.parent().children : this.DOM;
+}
+MpHtmlParser.prototype.parse = function() {
+	if (emoji) this.data = emoji.parseEmoji(this.data);
+	for (var c; c = this.data[this.i]; this.i++)
+		this.state(c);
+	if (this.state == this.Text) this.setText();
+	while (this.STACK.length) this.popNode(this.STACK.pop());
+	return this.DOM;
+}
+// 设置属性
+MpHtmlParser.prototype.setAttr = function() {
+	var name = this.attrName.toLowerCase(),
+		val = this.attrVal;
+	if (cfg.boolAttrs[name]) this.attrs[name] = 'T';
+	else if (val) {
+		if (name == 'src' || (name == 'data-src' && !this.attrs.src)) this.attrs.src = this.getUrl(this.decode(val, 'amp'));
+		else if (name == 'href' || name == 'style') this.attrs[name] = this.decode(val, 'amp');
+		else if (name.substr(0, 5) != 'data-') this.attrs[name] = val;
+	}
+	this.attrVal = '';
+	while (blankChar[this.data[this.i]]) this.i++;
+	if (this.isClose()) this.setNode();
+	else {
+		this.start = this.i;
+		this.state = this.AttrName;
+	}
+}
+// 设置文本节点
+MpHtmlParser.prototype.setText = function() {
+	var back, text = this.section();
+	if (!text) return;
+	text = (cfg.onText && cfg.onText(text, () => back = true)) || text;
+	if (back) {
+		this.data = this.data.substr(0, this.start) + text + this.data.substr(this.i);
+		let j = this.start + text.length;
+		for (this.i = this.start; this.i < j; this.i++) this.state(this.data[this.i]);
+		return;
+	}
+	if (!this.pre) {
+		// 合并空白符
+		var flag, tmp = [];
+		for (let i = text.length, c; c = text[--i];)
+			if (!blankChar[c]) {
+				tmp.unshift(c);
+				if (!flag) flag = 1;
+			} else {
+				if (tmp[0] != ' ') tmp.unshift(' ');
+				if (c == '\n' && flag == void 0) flag = 0;
+			}
+		if (flag == 0) return;
+		text = tmp.join('');
+	}
+	this.siblings().push({
+		type: 'text',
+		text: this.decode(text)
+	});
+}
+// 设置元素节点
+MpHtmlParser.prototype.setNode = function() {
+	var node = {
+			name: this.tagName.toLowerCase(),
+			attrs: this.attrs
+		},
+		close = cfg.selfClosingTags[node.name];
+	if (this.options.nodes.length) node.type = 'node';
+	this.attrs = {};
+	if (!cfg.ignoreTags[node.name]) {
+		// 处理属性
+		var attrs = node.attrs,
+			style = this.CssHandler.match(node.name, attrs, node) + (attrs.style || ''),
+			styleObj = {};
+		if (attrs.id) {
+			if (this.options.compress & 1) attrs.id = void 0;
+			else if (this.options.useAnchor) this.bubble();
+		}
+		if ((this.options.compress & 2) && attrs.class) attrs.class = void 0;
+		switch (node.name) {
+			case 'a':
+			case 'ad': // #ifdef APP-PLUS
+			case 'iframe':
+				// #endif
+				this.bubble();
+				break;
+			case 'font':
+				if (attrs.color) {
+					styleObj['color'] = attrs.color;
+					attrs.color = void 0;
+				}
+				if (attrs.face) {
+					styleObj['font-family'] = attrs.face;
+					attrs.face = void 0;
+				}
+				if (attrs.size) {
+					var size = parseInt(attrs.size);
+					if (size < 1) size = 1;
+					else if (size > 7) size = 7;
+					var map = ['xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large'];
+					styleObj['font-size'] = map[size - 1];
+					attrs.size = void 0;
+				}
+				break;
+			case 'embed':
+				// #ifndef APP-PLUS
+				var src = node.attrs.src || '',
+					type = node.attrs.type || '';
+				if (type.includes('video') || src.includes('.mp4') || src.includes('.3gp') || src.includes('.m3u8'))
+					node.name = 'video';
+				else if (type.includes('audio') || src.includes('.m4a') || src.includes('.wav') || src.includes('.mp3') || src.includes(
+						'.aac'))
+					node.name = 'audio';
+				else break;
+				if (node.attrs.autostart)
+					node.attrs.autoplay = 'T';
+				node.attrs.controls = 'T';
+				// #endif
+				// #ifdef APP-PLUS
+				this.bubble();
+				break;
+				// #endif
+			case 'video':
+			case 'audio':
+				if (!attrs.id) attrs.id = node.name + (++this[`${node.name}Num`]);
+				else this[`${node.name}Num`]++;
+				if (node.name == 'video') {
+					if (this.videoNum > 3)
+						node.lazyLoad = 1;
+					if (attrs.width) {
+						styleObj.width = parseFloat(attrs.width) + (attrs.width.includes('%') ? '%' : 'px');
+						attrs.width = void 0;
+					}
+					if (attrs.height) {
+						styleObj.height = parseFloat(attrs.height) + (attrs.height.includes('%') ? '%' : 'px');
+						attrs.height = void 0;
+					}
+				}
+				if (!attrs.controls && !attrs.autoplay) attrs.controls = 'T';
+				attrs.source = [];
+				if (attrs.src) {
+					attrs.source.push(attrs.src);
+					attrs.src = void 0;
+				}
+				this.bubble();
+				break;
+			case 'td':
+			case 'th':
+				if (attrs.colspan || attrs.rowspan)
+					for (var k = this.STACK.length, item; item = this.STACK[--k];)
+						if (item.name == 'table') {
+							item.c = void 0;
+							break;
+						}
+		}
+		if (attrs.align) {
+			styleObj['text-align'] = attrs.align;
+			attrs.align = void 0;
+		}
+		// 压缩 style
+		var styles = style.split(';');
+		style = '';
+		for (var i = 0, len = styles.length; i < len; i++) {
+			var info = styles[i].split(':');
+			if (info.length < 2) continue;
+			let key = info[0].trim().toLowerCase(),
+				value = info.slice(1).join(':').trim();
+			if (value[0] == '-' || value.includes('safe'))
+				style += `;${key}:${value}`;
+			else if (!styleObj[key] || value.includes('import') || !styleObj[key].includes('import'))
+				styleObj[key] = value;
+		}
+		if (node.name == 'img') {
+			if (attrs.src && !attrs.ignore) {
+				if (this.bubble())
+					attrs.i = (this.imgNum++).toString();
+				else attrs.ignore = 'T';
+			}
+			if (attrs.ignore) {
+				style += ';-webkit-touch-callout:none';
+				styleObj['max-width'] = '100%';
+			}
+			var width;
+			if (styleObj.width) width = styleObj.width;
+			else if (attrs.width) width = attrs.width.includes('%') ? attrs.width : parseFloat(attrs.width) + 'px';
+			if (width) {
+				styleObj.width = width;
+				attrs.width = '100%';
+				if (parseInt(width) > windowWidth) {
+					styleObj.height = '';
+					if (attrs.height) attrs.height = void 0;
+				}
+			}
+			if (styleObj.height) {
+				attrs.height = styleObj.height;
+				styleObj.height = '';
+			} else if (attrs.height && !attrs.height.includes('%'))
+				attrs.height = parseFloat(attrs.height) + 'px';
+		}
+		for (var key in styleObj) {
+			var value = styleObj[key];
+			if (!value) continue;
+			if (key.includes('flex') || key == 'order' || key == 'self-align') node.c = 1;
+			// 填充链接
+			if (value.includes('url')) {
+				var j = value.indexOf('(');
+				if (j++ != -1) {
+					while (value[j] == '"' || value[j] == "'" || blankChar[value[j]]) j++;
+					value = value.substr(0, j) + this.getUrl(value.substr(j));
+				}
+			}
+			// 转换 rpx
+			else if (value.includes('rpx'))
+				value = value.replace(/[0-9.]+\s*rpx/g, $ => parseFloat($) * windowWidth / 750 + 'px');
+			else if (key == 'white-space' && value.includes('pre') && !close)
+				this.pre = node.pre = true;
+			style += `;${key}:${value}`;
+		}
+		style = style.substr(1);
+		if (style) attrs.style = style;
+		if (!close) {
+			node.children = [];
+			if (node.name == 'pre' && cfg.highlight) {
+				this.remove(node);
+				this.pre = node.pre = true;
+			}
+			this.siblings().push(node);
+			this.STACK.push(node);
+		} else if (!cfg.filter || cfg.filter(node, this) != false)
+			this.siblings().push(node);
+	} else {
+		if (!close) this.remove(node);
+		else if (node.name == 'source') {
+			var parent = this.parent();
+			if (parent && (parent.name == 'video' || parent.name == 'audio') && node.attrs.src)
+				parent.attrs.source.push(node.attrs.src);
+		} else if (node.name == 'base' && !this.domain) this.domain = node.attrs.href;
+	}
+	if (this.data[this.i] == '/') this.i++;
+	this.start = this.i + 1;
+	this.state = this.Text;
+}
+// 移除标签
+MpHtmlParser.prototype.remove = function(node) {
+	var name = node.name,
+		j = this.i;
+	// 处理 svg
+	var handleSvg = () => {
+		var src = this.data.substring(j, this.i + 1);
+		if (!node.attrs.xmlns) src = ' xmlns="http://www.w3.org/2000/svg"' + src;
+		var i = j;
+		while (this.data[j] != '<') j--;
+		src = this.data.substring(j, i).replace("viewbox", "viewBox") + src;
+		var parent = this.parent();
+		if (node.attrs.width == '100%' && parent && (parent.attrs.style || '').includes('inline'))
+			parent.attrs.style = 'width:300px;max-width:100%;' + parent.attrs.style;
+		this.siblings().push({
+			name: 'img',
+			attrs: {
+				src: 'data:image/svg+xml;utf8,' + src.replace(/#/g, '%23'),
+				style: (/vertical[^;]+/.exec(node.attrs.style) || []).shift(),
+				ignore: 'T'
+			}
+		})
+	}
+	if (node.name == 'svg' && this.data[j] == '/') return handleSvg(this.i++);
+	while (1) {
+		if ((this.i = this.data.indexOf('</', this.i + 1)) == -1) {
+			if (name == 'pre' || name == 'svg') this.i = j;
+			else this.i = this.data.length;
+			return;
+		}
+		this.start = (this.i += 2);
+		while (!blankChar[this.data[this.i]] && !this.isClose()) this.i++;
+		if (this.section().toLowerCase() == name) {
+			// 代码块高亮
+			if (name == 'pre') {
+				this.data = this.data.substr(0, j + 1) + cfg.highlight(this.data.substring(j + 1, this.i - 5), node.attrs) + this.data
+					.substr(this.i - 5);
+				return this.i = j;
+			} else if (name == 'style')
+				this.CssHandler.getStyle(this.data.substring(j + 1, this.i - 7));
+			else if (name == 'title')
+				this.DOM.title = this.data.substring(j + 1, this.i - 7);
+			if ((this.i = this.data.indexOf('>', this.i)) == -1) this.i = this.data.length;
+			if (name == 'svg') handleSvg();
+			return;
+		}
+	}
+}
+// 节点出栈处理
+MpHtmlParser.prototype.popNode = function(node) {
+	// 空白符处理
+	if (node.pre) {
+		node.pre = this.pre = void 0;
+		for (let i = this.STACK.length; i--;)
+			if (this.STACK[i].pre)
+				this.pre = true;
+	}
+	var siblings = this.siblings(),
+		len = siblings.length,
+		childs = node.children;
+	if (node.name == 'head' || (cfg.filter && cfg.filter(node, this) == false))
+		return siblings.pop();
+	var attrs = node.attrs;
+	// 替换一些标签名
+	if (cfg.blockTags[node.name]) node.name = 'div';
+	else if (!cfg.trustTags[node.name]) node.name = 'span';
+	// 处理列表
+	if (node.c && (node.name == 'ul' || node.name == 'ol')) {
+		if ((node.attrs.style || '').includes('list-style:none')) {
+			for (let i = 0, child; child = childs[i++];)
+				if (child.name == 'li')
+					child.name = 'div';
+		} else if (node.name == 'ul') {
+			var floor = 1;
+			for (let i = this.STACK.length; i--;)
+				if (this.STACK[i].name == 'ul') floor++;
+			if (floor != 1)
+				for (let i = childs.length; i--;)
+					childs[i].floor = floor;
+		} else {
+			for (let i = 0, num = 1, child; child = childs[i++];)
+				if (child.name == 'li') {
+					child.type = 'ol';
+					child.num = ((num, type) => {
+						if (type == 'a') return String.fromCharCode(97 + (num - 1) % 26);
+						if (type == 'A') return String.fromCharCode(65 + (num - 1) % 26);
+						if (type == 'i' || type == 'I') {
+							num = (num - 1) % 99 + 1;
+							var one = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'],
+								ten = ['X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC'],
+								res = (ten[Math.floor(num / 10) - 1] || '') + (one[num % 10 - 1] || '');
+							if (type == 'i') return res.toLowerCase();
+							return res;
+						}
+						return num;
+					})(num++, attrs.type) + '.';
+				}
+		}
+	}
+	// 处理表格的边框
+	if (node.name == 'table') {
+		var padding = attrs.cellpadding,
+			spacing = attrs.cellspacing,
+			border = attrs.border;
+		if (node.c) {
+			this.bubble();
+			attrs.style = (attrs.style || '') + ';display:table';
+			if (!padding) padding = 2;
+			if (!spacing) spacing = 2;
+		}
+		if (border) attrs.style = `border:${border}px solid gray;${attrs.style || ''}`;
+		if (spacing) attrs.style = `border-spacing:${spacing}px;${attrs.style || ''}`;
+		if (border || padding || node.c)
+			(function f(ns) {
+				for (var i = 0, n; n = ns[i]; i++) {
+					if (n.type == 'text') continue;
+					var style = n.attrs.style || '';
+					if (node.c && n.name[0] == 't') {
+						n.c = 1;
+						style += ';display:table-' + (n.name == 'th' || n.name == 'td' ? 'cell' : (n.name == 'tr' ? 'row' : 'row-group'));
+					}
+					if (n.name == 'th' || n.name == 'td') {
+						if (border) style = `border:${border}px solid gray;${style}`;
+						if (padding) style = `padding:${padding}px;${style}`;
+					} else f(n.children || []);
+					if (style) n.attrs.style = style;
+				}
+			})(childs)
+		if (this.options.autoscroll) {
+			var table = Object.assign({}, node);
+			node.name = 'div';
+			node.attrs = {
+				style: 'overflow:scroll'
+			}
+			node.children = [table];
+		}
+	}
+	this.CssHandler.pop && this.CssHandler.pop(node);
+	// 自动压缩
+	if (node.name == 'div' && !Object.keys(attrs).length && childs.length == 1 && childs[0].name == 'div')
+		siblings[len - 1] = childs[0];
+}
+// 状态机
+MpHtmlParser.prototype.Text = function(c) {
+	if (c == '<') {
+		var next = this.data[this.i + 1],
+			isLetter = c => (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+		if (isLetter(next)) {
+			this.setText();
+			this.start = this.i + 1;
+			this.state = this.TagName;
+		} else if (next == '/') {
+			this.setText();
+			if (isLetter(this.data[++this.i + 1])) {
+				this.start = this.i + 1;
+				this.state = this.EndTag;
+			} else this.Comment();
+		} else if (next == '!' || next == '?') {
+			this.setText();
+			this.Comment();
+		}
+	}
+}
+MpHtmlParser.prototype.Comment = function() {
+	var key;
+	if (this.data.substring(this.i + 2, this.i + 4) == '--') key = '-->';
+	else if (this.data.substring(this.i + 2, this.i + 9) == '[CDATA[') key = ']]>';
+	else key = '>';
+	if ((this.i = this.data.indexOf(key, this.i + 2)) == -1) this.i = this.data.length;
+	else this.i += key.length - 1;
+	this.start = this.i + 1;
+	this.state = this.Text;
+}
+MpHtmlParser.prototype.TagName = function(c) {
+	if (blankChar[c]) {
+		this.tagName = this.section();
+		while (blankChar[this.data[this.i]]) this.i++;
+		if (this.isClose()) this.setNode();
+		else {
+			this.start = this.i;
+			this.state = this.AttrName;
+		}
+	} else if (this.isClose()) {
+		this.tagName = this.section();
+		this.setNode();
+	}
+}
+MpHtmlParser.prototype.AttrName = function(c) {
+	if (c == '=' || blankChar[c] || this.isClose()) {
+		this.attrName = this.section();
+		if (blankChar[c])
+			while (blankChar[this.data[++this.i]]);
+		if (this.data[this.i] == '=') {
+			while (blankChar[this.data[++this.i]]);
+			this.start = this.i--;
+			this.state = this.AttrValue;
+		} else this.setAttr();
+	}
+}
+MpHtmlParser.prototype.AttrValue = function(c) {
+	if (c == '"' || c == "'") {
+		this.start++;
+		if ((this.i = this.data.indexOf(c, this.i + 1)) == -1) return this.i = this.data.length;
+		this.attrVal = this.section();
+		this.i++;
+	} else {
+		for (; !blankChar[this.data[this.i]] && !this.isClose(); this.i++);
+		this.attrVal = this.section();
+	}
+	this.setAttr();
+}
+MpHtmlParser.prototype.EndTag = function(c) {
+	if (blankChar[c] || c == '>' || c == '/') {
+		var name = this.section().toLowerCase();
+		for (var i = this.STACK.length; i--;)
+			if (this.STACK[i].name == name) break;
+		if (i != -1) {
+			var node;
+			while ((node = this.STACK.pop()).name != name) this.popNode(node);
+			this.popNode(node);
+		} else if (name == 'p' || name == 'br')
+			this.siblings().push({
+				name,
+				attrs: {}
+			});
+		this.i = this.data.indexOf('>', this.i);
+		this.start = this.i + 1;
+		if (this.i == -1) this.i = this.data.length;
+		else this.state = this.Text;
+	}
+}
+module.exports = MpHtmlParser;

+ 80 - 0
src/components/jyf-parser/libs/config.js

@@ -0,0 +1,80 @@
+/* 配置文件 */
+var cfg = {
+	// 出错占位图
+	errorImg: null,
+	// 过滤器函数
+	filter: null,
+	// 代码高亮函数
+	highlight: null,
+	// 文本处理函数
+	onText: null,
+	// 实体编码列表
+	entities: {
+		quot: '"',
+		apos: "'",
+		semi: ';',
+		nbsp: '\xA0',
+		ensp: '\u2002',
+		emsp: '\u2003',
+		ndash: '–',
+		mdash: '—',
+		middot: '·',
+		lsquo: '‘',
+		rsquo: '’',
+		ldquo: '“',
+		rdquo: '”',
+		bull: '•',
+		hellip: '…'
+	},
+	blankChar: makeMap(' ,\xA0,\t,\r,\n,\f'),
+	boolAttrs: makeMap('allowfullscreen,autoplay,autostart,controls,ignore,loop,muted'),
+	// 块级标签,将被转为 div
+	blockTags: makeMap('address,article,aside,body,caption,center,cite,footer,header,html,nav,pre,section'),
+	// 将被移除的标签
+	ignoreTags: makeMap('area,base,canvas,frame,iframe,input,link,map,meta,param,script,source,style,svg,textarea,title,track,wbr'),
+	// 只能被 rich-text 显示的标签
+	richOnlyTags: makeMap('a,colgroup,fieldset,legend,table'),
+	// 自闭合的标签
+	selfClosingTags: makeMap('area,base,br,col,circle,ellipse,embed,frame,hr,img,input,line,link,meta,param,path,polygon,rect,source,track,use,wbr'),
+	// 信任的标签
+	trustTags: makeMap('a,abbr,ad,audio,b,blockquote,br,code,col,colgroup,dd,del,dl,dt,div,em,fieldset,h1,h2,h3,h4,h5,h6,hr,i,img,ins,label,legend,li,ol,p,q,source,span,strong,sub,sup,table,tbody,td,tfoot,th,thead,tr,title,ul,video'),
+	// 默认的标签样式
+	userAgentStyles: {
+		address: 'font-style:italic',
+		big: 'display:inline;font-size:1.2em',
+		blockquote: 'background-color:#f6f6f6;border-left:3px solid #dbdbdb;color:#6c6c6c;padding:5px 0 5px 10px',
+		caption: 'display:table-caption;text-align:center',
+		center: 'text-align:center',
+		cite: 'font-style:italic',
+		dd: 'margin-left:40px',
+		mark: 'background-color:yellow',
+		pre: 'font-family:monospace;white-space:pre;overflow:scroll',
+		s: 'text-decoration:line-through',
+		small: 'display:inline;font-size:0.8em',
+		u: 'text-decoration:underline'
+	}
+}
+
+function makeMap(str) {
+	var map = Object.create(null),
+		list = str.split(',');
+	for (var i = list.length; i--;)
+		map[list[i]] = true;
+	return map;
+}
+
+// #ifdef MP-WEIXIN
+if (wx.canIUse('editor')) {
+	cfg.blockTags.pre = void 0;
+	cfg.ignoreTags.rp = true;
+	Object.assign(cfg.richOnlyTags, makeMap('bdi,bdo,caption,rt,ruby'));
+	Object.assign(cfg.trustTags, makeMap('bdi,bdo,caption,pre,rt,ruby'));
+}
+// #endif
+
+// #ifdef APP-PLUS
+cfg.ignoreTags.iframe = void 0;
+Object.assign(cfg.trustTags, makeMap('embed,iframe'));
+// #endif
+
+module.exports = cfg;

+ 22 - 0
src/components/jyf-parser/libs/handler.wxs

@@ -0,0 +1,22 @@
+var inline = {
+	abbr: 1,
+	b: 1,
+	big: 1,
+	code: 1,
+	del: 1,
+	em: 1,
+	i: 1,
+	ins: 1,
+	label: 1,
+	q: 1,
+	small: 1,
+	span: 1,
+	strong: 1,
+	sub: 1,
+	sup: 1
+}
+module.exports = {
+	use: function(item) {
+		return !item.c && !inline[item.name] && (item.attrs.style || '').indexOf('display:inline') == -1
+	}
+}

+ 501 - 0
src/components/jyf-parser/libs/trees.vue

@@ -0,0 +1,501 @@
+<template>
+	<view :class="'interlayer '+(c||'')" :style="s">
+		<block v-for="(n, i) in nodes" v-bind:key="i">
+			<!--图片-->
+			<view v-if="n.name=='img'" :class="'_img '+n.attrs.class" :style="n.attrs.style" :data-attrs="n.attrs" @tap="imgtap">
+				<rich-text v-if="ctrl[i]!=0" :nodes="[{attrs:{src:loading&&(ctrl[i]||0)<2?loading:(lazyLoad&&!ctrl[i]?placeholder:(ctrl[i]==3?errorImg:n.attrs.src||'')),alt:n.attrs.alt||'',width:n.attrs.width||'',style:'-webkit-touch-callout:none;max-width:100%;display:block'+(n.attrs.height?';height:'+n.attrs.height:'')},name:'img'}]" />
+				<image class="_image" :src="lazyLoad&&!ctrl[i]?placeholder:n.attrs.src" :lazy-load="lazyLoad"
+				 :show-menu-by-longpress="!n.attrs.ignore" :data-i="i" :data-index="n.attrs.i" data-source="img" @load="loadImg"
+				 @error="error" />
+			</view>
+			<!--文本-->
+			<text v-else-if="n.type=='text'" decode>{{n.text}}</text>
+			<!--#ifndef MP-BAIDU-->
+			<text v-else-if="n.name=='br'">\n</text>
+			<!--#endif-->
+			<!--视频-->
+			<view v-else-if="((n.lazyLoad&&!n.attrs.autoplay)||(n.name=='video'&&!loadVideo))&&ctrl[i]==undefined" :id="n.attrs.id" :class="'_video '+(n.attrs.class||'')"
+			 :style="n.attrs.style" :data-i="i" @tap="_loadVideo" />
+			<video v-else-if="n.name=='video'" :id="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :autoplay="n.attrs.autoplay||ctrl[i]==0"
+			 :controls="n.attrs.controls" :loop="n.attrs.loop" :muted="n.attrs.muted" :poster="n.attrs.poster" :src="n.attrs.source[ctrl[i]||0]"
+			 :unit-id="n.attrs['unit-id']" :data-id="n.attrs.id" :data-i="i" data-source="video" @error="error" @play="play" />
+			<!--音频-->
+			<audio v-else-if="n.name=='audio'" :ref="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :author="n.attrs.author"
+			 :autoplay="n.attrs.autoplay" :controls="n.attrs.controls" :loop="n.attrs.loop" :name="n.attrs.name" :poster="n.attrs.poster"
+			 :src="n.attrs.source[ctrl[i]||0]" :data-i="i" :data-id="n.attrs.id" data-source="audio"
+			 @error.native="error" @play.native="play" />
+			<!--链接-->
+			<view v-else-if="n.name=='a'" :id="n.attrs.id" :class="'_a '+(n.attrs.class||'')" hover-class="_hover" :style="n.attrs.style"
+			 :data-attrs="n.attrs" @tap="linkpress">
+				<trees class="_span" c="_span" :nodes="n.children" />
+			</view>
+			<!--广告-->
+			<!--<ad v-else-if="n.name=='ad'" :class="n.attrs.class" :style="n.attrs.style" :unit-id="n.attrs['unit-id']" :appid="n.attrs.appid" :apid="n.attrs.apid" :type="n.attrs.type" :adpid="n.attrs.adpid" data-source="ad" @error="error" />-->
+			<!--列表-->
+			<view v-else-if="n.name=='li'" :id="n.attrs.id" :class="n.attrs.class" :style="(n.attrs.style||'')+';display:flex;flex-direction:row'">
+				<view v-if="n.type=='ol'" class="_ol-bef">{{n.num}}</view>
+				<view v-else class="_ul-bef">
+					<view v-if="n.floor%3==0" class="_ul-p1">█</view>
+					<view v-else-if="n.floor%3==2" class="_ul-p2" />
+					<view v-else class="_ul-p1" style="border-radius:50%">█</view>
+				</view>
+				<trees class="_li" c="_li" :nodes="n.children" :lazyLoad="lazyLoad" :loading="loading" />
+			</view>
+			<!--表格-->
+			<view v-else-if="n.name=='table'&&n.c" :id="n.attrs.id" :class="n.attrs.class" :style="(n.attrs.style||'')+';display:table'">
+				<view v-for="(tbody, o) in n.children" v-bind:key="o" :class="tbody.attrs.class" :style="(tbody.attrs.style||'')+(tbody.name[0]=='t'?';display:table-'+(tbody.name=='tr'?'row':'row-group'):'')">
+					<view v-for="(tr, p) in tbody.children" v-bind:key="p" :class="tr.attrs.class" :style="(tr.attrs.style||'')+(tr.name[0]=='t'?';display:table-'+(tr.name=='tr'?'row':'cell'):'')">
+						<trees v-if="tr.name=='td'" :nodes="tr.children" />
+						<trees v-else v-for="(td, q) in tr.children" v-bind:key="q" :class="td.attrs.class" :c="td.attrs.class" :style="(td.attrs.style||'')+(td.name[0]=='t'?';display:table-'+(td.name=='tr'?'row':'cell'):'')"
+						 :s="(td.attrs.style||'')+(td.name[0]=='t'?';display:table-'+(td.name=='tr'?'row':'cell'):'')" :nodes="td.children" />
+					</view>
+				</view>
+			</view>
+			<!--#ifdef APP-PLUS-->
+			<iframe v-else-if="n.name=='iframe'" :style="n.attrs.style" :allowfullscreen="n.attrs.allowfullscreen" :frameborder="n.attrs.frameborder"
+			 :width="n.attrs.width" :height="n.attrs.height" :src="n.attrs.src" />
+			<embed v-else-if="n.name=='embed'" :style="n.attrs.style" :width="n.attrs.width" :height="n.attrs.height" :src="n.attrs.src" />
+			<!--#endif-->
+			<!--富文本-->
+			<!--#ifdef MP-WEIXIN || MP-QQ || APP-PLUS-->
+			<rich-text v-else-if="handler.use(n)" :id="n.attrs.id" :class="'_p __'+n.name" :nodes="[n]" />
+			<!--#endif-->
+			<!--#ifndef MP-WEIXIN || MP-QQ || APP-PLUS-->
+			<rich-text v-else-if="!n.c" :id="n.attrs.id" :nodes="[n]" style="display:inline" />
+			<!--#endif-->
+			<trees v-else :class="(n.attrs.id||'')+' _'+n.name+' '+(n.attrs.class||'')" :c="(n.attrs.id||'')+' _'+n.name+' '+(n.attrs.class||'')"
+			 :style="n.attrs.style" :s="n.attrs.style" :nodes="n.children" :lazyLoad="lazyLoad" :loading="loading" />
+		</block>
+	</view>
+</template>
+<script module="handler" lang="wxs" src="./handler.wxs"></script>
+<script>
+	global.Parser = {};
+	import trees from './trees'
+	const errorImg = require('../libs/config.js').errorImg;
+	export default {
+		components: {
+			trees
+		},
+		name: 'trees',
+		data() {
+			return {
+				ctrl: [],
+				placeholder: 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="300" height="225"/>',
+				errorImg,
+				loadVideo: typeof plus == 'undefined',
+				// #ifndef MP-ALIPAY
+				c: '',
+				s: ''
+				// #endif
+			}
+		},
+		props: {
+			nodes: Array,
+			lazyLoad: Boolean,
+			loading: String,
+			// #ifdef MP-ALIPAY
+			c: String,
+			s: String
+			// #endif
+		},
+		mounted() {
+			for (this.top = this.$parent; this.top.$options.name != 'parser'; this.top = this.top.$parent);
+			this.init();
+		},
+		// #ifdef APP-PLUS
+		beforeDestroy() {
+			this.observer && this.observer.disconnect();
+		},
+		// #endif
+		methods: {
+			init() {
+				for (var i = this.nodes.length, n; n = this.nodes[--i];) {
+					if (n.name == 'img') {
+						this.top.imgList.setItem(n.attrs.i, n.attrs['original-src'] || n.attrs.src);
+						// #ifdef APP-PLUS
+						if (this.lazyLoad && !this.observer) {
+							this.observer = uni.createIntersectionObserver(this).relativeToViewport({
+								top: 500,
+								bottom: 500
+							});
+							setTimeout(() => {
+								this.observer.observe('._img', res => {
+									if (res.intersectionRatio) {
+										for (var j = this.nodes.length; j--;)
+											if (this.nodes[j].name == 'img')
+												this.$set(this.ctrl, j, 1);
+										this.observer.disconnect();
+									}
+								})
+							}, 0)
+						}
+						// #endif
+					} else if (n.name == 'video' || n.name == 'audio') {
+						var ctx;
+						if (n.name == 'video') {
+							ctx = uni.createVideoContext(n.attrs.id
+								// #ifndef MP-BAIDU
+								, this
+								// #endif
+							);
+						} else if (this.$refs[n.attrs.id])
+							ctx = this.$refs[n.attrs.id][0];
+						if (ctx) {
+							ctx.id = n.attrs.id;
+							this.top.videoContexts.push(ctx);
+						}
+					}
+				}
+				// #ifdef APP-PLUS
+				// APP 上避免 video 错位需要延时渲染
+				setTimeout(() => {
+					this.loadVideo = true;
+				}, 1000)
+				// #endif
+			},
+			play(e) {
+				var contexts = this.top.videoContexts;
+				if (contexts.length > 1 && this.top.autopause)
+					for (var i = contexts.length; i--;)
+						if (contexts[i].id != e.currentTarget.dataset.id)
+							contexts[i].pause();
+			},
+			imgtap(e) {
+				var attrs = e.currentTarget.dataset.attrs;
+				if (!attrs.ignore) {
+					var preview = true,
+						data = {
+							id: e.target.id,
+							src: attrs.src,
+							ignore: () => preview = false
+						};
+					global.Parser.onImgtap && global.Parser.onImgtap(data);
+					this.top.$emit('imgtap', data);
+					if (preview) {
+						var urls = this.top.imgList,
+							current = urls[attrs.i] ? parseInt(attrs.i) : (urls = [attrs.src], 0);
+						uni.previewImage({
+							current,
+							urls
+						})
+					}
+				}
+			},
+			loadImg(e) {
+				var i = e.currentTarget.dataset.i;
+				if (this.lazyLoad && !this.ctrl[i]) {
+					// #ifdef QUICKAPP-WEBVIEW
+					this.$set(this.ctrl, i, 0);
+					this.$nextTick(function() {
+						// #endif
+						// #ifndef APP-PLUS
+						this.$set(this.ctrl, i, 1);
+						// #endif
+						// #ifdef QUICKAPP-WEBVIEW
+					})
+					// #endif
+				} else if (this.loading && this.ctrl[i] != 2) {
+					// #ifdef QUICKAPP-WEBVIEW
+					this.$set(this.ctrl, i, 0);
+					this.$nextTick(function() {
+						// #endif
+						this.$set(this.ctrl, i, 2);
+						// #ifdef QUICKAPP-WEBVIEW
+					})
+					// #endif
+				}
+			},
+			linkpress(e) {
+				var jump = true,
+					attrs = e.currentTarget.dataset.attrs;
+				attrs.ignore = () => jump = false;
+				global.Parser.onLinkpress && global.Parser.onLinkpress(attrs);
+				this.top.$emit('linkpress', attrs);
+				if (jump) {
+					// #ifdef MP
+					if (attrs['app-id']) {
+						return uni.navigateToMiniProgram({
+							appId: attrs['app-id'],
+							path: attrs.path
+						})
+					}
+					// #endif
+					if (attrs.href) {
+						if (attrs.href[0] == '#') {
+							if (this.top.useAnchor)
+								this.top.navigateTo({
+									id: attrs.href.substring(1)
+								})
+						} else if (attrs.href.indexOf('http') == 0 || attrs.href.indexOf('//') == 0) {
+							// #ifdef APP-PLUS
+							plus.runtime.openWeb(attrs.href);
+							// #endif
+							// #ifndef APP-PLUS
+							uni.setClipboardData({
+								data: attrs.href,
+								success: () =>
+									uni.showToast({
+										title: '链接已复制'
+									})
+							})
+							// #endif
+						} else
+							uni.navigateTo({
+								url: attrs.href,
+								fail() {
+									uni.switchTab({
+										url: attrs.href,
+									})
+								}
+							})
+					}
+				}
+			},
+			error(e) {
+				var target = e.currentTarget,
+					source = target.dataset.source,
+					i = target.dataset.i;
+				if (source == 'video' || source == 'audio') {
+					// 加载其他 source
+					var index = this.ctrl[i] ? this.ctrl[i].i + 1 : 1;
+					if (index < this.nodes[i].attrs.source.length)
+						this.$set(this.ctrl, i, index);
+					if (e.detail.__args__)
+						e.detail = e.detail.__args__[0];
+				} else if (errorImg && source == 'img') {
+					this.top.imgList.setItem(target.dataset.index, errorImg);
+					this.$set(this.ctrl, i, 3);
+				}
+				this.top && this.top.$emit('error', {
+					source,
+					target,
+					errMsg: e.detail.errMsg
+				});
+			},
+			_loadVideo(e) {
+				this.$set(this.ctrl, e.target.dataset.i, 0);
+			}
+		}
+	}
+</script>
+
+<style>
+	/* 在这里引入自定义样式 */
+
+	/* 链接和图片效果 */
+	._a {
+		display: inline;
+		padding: 1.5px 0 1.5px 0;
+		color: #366092;
+		word-break: break-all;
+	}
+
+	._hover {
+		text-decoration: underline;
+		opacity: 0.7;
+	}
+
+	._img {
+		display: inline-block;
+		max-width: 100%;
+		overflow: hidden;
+	}
+
+	/* #ifdef MP-WEIXIN */
+	:host {
+		display: inline;
+	}
+
+	/* #endif */
+
+	/* #ifndef MP-ALIPAY || APP-PLUS */
+	.interlayer {
+		display: inherit;
+		flex-direction: inherit;
+		flex-wrap: inherit;
+		align-content: inherit;
+		align-items: inherit;
+		justify-content: inherit;
+		width: 100%;
+		white-space: inherit;
+	}
+
+	/* #endif */
+
+	._b,
+	._strong {
+		font-weight: bold;
+	}
+
+	/* #ifndef MP-ALIPAY */
+	._blockquote,
+	._div,
+	._p,
+	._ol,
+	._ul,
+	._li {
+		display: block;
+	}
+	
+	/* #endif */
+
+	._code {
+		font-family: monospace;
+	}
+
+	._del {
+		text-decoration: line-through;
+	}
+
+	._em,
+	._i {
+		font-style: italic;
+	}
+
+	._h1 {
+		font-size: 2em;
+	}
+
+	._h2 {
+		font-size: 1.5em;
+	}
+
+	._h3 {
+		font-size: 1.17em;
+	}
+
+	._h5 {
+		font-size: 0.83em;
+	}
+
+	._h6 {
+		font-size: 0.67em;
+	}
+
+	._h1,
+	._h2,
+	._h3,
+	._h4,
+	._h5,
+	._h6 {
+		display: block;
+		font-weight: bold;
+	}
+
+	._image {
+		display: block;
+		width: 100%;
+		height: 360px;
+		margin-top: -360px;
+		opacity: 0;
+	}
+
+	._ins {
+		text-decoration: underline;
+	}
+
+	._li {
+		flex: 1;
+		width: 0;
+	}
+
+	._ol-bef {
+		width: 36px;
+		margin-right: 5px;
+		text-align: right;
+	}
+
+	._ul-bef {
+		display: block;
+		margin: 0 12px 0 23px;
+		line-height: normal;
+	}
+
+	._ol-bef,
+	._ul-bef {
+		flex: none;
+		user-select: none;
+	}
+
+	._ul-p1 {
+		display: inline-block;
+		width: 0.3em;
+		height: 0.3em;
+		overflow: hidden;
+		line-height: 0.3em;
+	}
+
+	._ul-p2 {
+		display: inline-block;
+		width: 0.23em;
+		height: 0.23em;
+		border: 0.05em solid black;
+		border-radius: 50%;
+	}
+
+	._q::before {
+		content: '"';
+	}
+
+	._q::after {
+		content: '"';
+	}
+
+	._sub {
+		font-size: smaller;
+		vertical-align: sub;
+	}
+
+	._sup {
+		font-size: smaller;
+		vertical-align: super;
+	}
+
+	/* #ifdef MP-ALIPAY || APP-PLUS || QUICKAPP-WEBVIEW */
+	._abbr,
+	._b,
+	._code,
+	._del,
+	._em,
+	._i,
+	._ins,
+	._label,
+	._q,
+	._span,
+	._strong,
+	._sub,
+	._sup {
+		display: inline;
+	}
+
+	/* #endif */
+
+	/* #ifdef MP-WEIXIN || MP-QQ */
+	.__bdo,
+	.__bdi,
+	.__ruby,
+	.__rt {
+		display: inline-block;
+	}
+
+	/* #endif */
+	._video {
+		position: relative;
+		display: inline-block;
+		width: 300px;
+		height: 225px;
+		background-color: black;
+	}
+
+	._video::after {
+		position: absolute;
+		top: 50%;
+		left: 50%;
+		margin: -15px 0 0 -15px;
+		content: '';
+		border-color: transparent transparent transparent white;
+		border-style: solid;
+		border-width: 15px 0 15px 30px;
+	}
+</style>

+ 6 - 0
src/pages.json

@@ -29,6 +29,12 @@
 			"style":{
 				"navigationBarTitleText": "登录"
 			}
+		},
+		{
+			"path": "pages/protocol/index",
+			"style":{
+				"navigationBarTitleText": "购买协议"
+			}
 		}
 	],
 	"tabBar": {

+ 209 - 219
src/pages/index/index.vue

@@ -1,254 +1,244 @@
 <template>
-  <div class="Appindex">
-    <!-- 顶部 -->
-    <view class="head">
-      <!-- 搜索框 -->
-      <view class="head_search">
-        <text class="iconfont">&#xe661;</text>
-        <text class="search_text">请输入搜索关键字</text>
-      </view>
-      <!-- 搜索框-end -->
-
-      <!-- 轮播图 -->
-      <swiper-banner
-        :radius="1"
-        imgScale="5:2"
-        :imgArr="BannerImg"
-        :duration="1000"
-        :interval="5000"
-        :circular="true"
-        :autoplay="true"
-        @goList="goList"
-        :indicator-dots="true"
-        indicator-active-color="#12B280"
-        indicator-color="rgba(255, 255, 255, .82)"
-      ></swiper-banner>
-      <!-- 轮播图-end -->
-
-      <!-- 公告 -->
-      <view class="head_notice clearfix">
-        <view class="notice_title"
-          ><image class="gg_img" src="@/static/img/gg.png"></image
-        ></view>
-        <swiper
-          class="notice_swiper"
-          vertical
-          autoplay
-          circular
-          :interval="5000"
-          :duration="1000"
-        >
-          <swiper-item v-for="(item, index) in not_list" :key="index">
-            <text class="not_list ellipsis1">{{ item.contentTitle }}</text>
-            <text class="not_ico iconfont">&#xe62e;</text>
-          </swiper-item>
-        </swiper>
-      </view>
-      <!-- 公告-end -->
-
-      <!-- 金刚区 -->
-      <view class="head_area">
-        <view class="area_list" v-for="(item, index) in area_list" :key="index">
-          <image class="area_img" :src="item.url"></image>
-          <view class="area_name">{{ item.name }}</view>
+    <div class="Appindex">
+        <!-- 顶部 -->
+        <view class="head">
+            <!-- 搜索框 -->
+            <view class="head_search">
+                <text class="iconfont">&#xe661;</text>
+                <text class="search_text">请输入搜索关键字</text>
+            </view>
+            <!-- 搜索框-end -->
+            <!-- 轮播图 -->
+            <swiper-banner :radius="1" imgScale="5:2" :imgArr="BannerImg" :duration="1000" :interval="5000" :circular="true" :autoplay="true" @goList="goList" :indicator-dots="true" indicator-active-color="#12B280" indicator-color="rgba(255, 255, 255, .82)"></swiper-banner>
+            <!-- 轮播图-end -->
+            <!-- 公告 -->
+            <view class="head_notice clearfix">
+                <view class="notice_title">
+                    <image class="gg_img" src="@/static/img/gg.png"></image>
+                </view>
+                <swiper class="notice_swiper" vertical autoplay circular :interval="5000" :duration="1000">
+                    <swiper-item v-for="(item, index) in not_list" :key="index">
+                        <text class="not_list ellipsis1">{{ item.contentTitle }}</text>
+                        <text class="not_ico iconfont">&#xe62e;</text>
+                    </swiper-item>
+                </swiper>
+            </view>
+            <!-- 公告-end -->
+            <!-- 金刚区 -->
+            <view class="head_area">
+                <view class="area_list" v-for="(item, index) in area_list" :key="index">
+                    <image class="area_img" :src="item.url"></image>
+                    <view class="area_name">{{ item.name }}</view>
+                </view>
+            </view>
+            <!-- 金刚区-end -->
+            <!-- 活动 -->
+            <view class="activity" v-if="spc_list.length > 0">
+                <image class="act_one_img" :src="spc_list[0].url" mode=""></image>
+                <view class="act_other">
+                    <image class="act_two_img" :src="spc_list[1].url" mode=""></image>
+                    <image class="act_two_img" :src="spc_list[2].url" mode=""></image>
+                </view>
+            </view>
+            <!-- 活动-end -->
         </view>
-      </view>
-      <!-- 金刚区-end -->
-
-      <!-- 活动 -->
-      <view class="activity" v-if="spc_list.length > 0">
-        <image class="act_one_img" :src="spc_list[0].url" mode=""></image>
-        <view class="act_other">
-          <image class="act_two_img" :src="spc_list[1].url" mode=""></image>
-          <image class="act_two_img" :src="spc_list[2].url" mode=""></image>
-        </view>
-      </view>
-      <!-- 活动-end -->
-    </view>
-
-    <goodslist :url="goodslistUrl" :long="1" />
-  </div>
+        <goodslist :url="goodslistUrl" :long="1" />
+    </div>
 </template>
-
 <script>
 import goodslist from "@/components/goodsList"; //商品列表
 import swiperBanner from "@/components/swiperBanner"; //轮播
 import { get, post } from "@/request/api.js";
 export default {
-  name: "Appindex",
-  components: {
-    goodslist, //商品列表
-    swiperBanner, //轮播
-  },
-  data() {
-    return {
-      BannerImg: [], // 轮播图列表
-      not_list: [], // 公告列表
-      area_list: [], // 金刚区
-	  spc_list: [], //活动列表
-      goodslistUrl: "ShuZiTeaYW/shop/getGoodsLikeByUserId", //首页商品列表
-    };
-  },
-  onLoad(option) {
-    this.getBanner(); //获取轮播图
-    this.getAnnounce(); //获取公告列表
-    this.getImageTwo(); //金刚区
-	this.getImage(); //获取活动列表
-  },
-  onLaunch() {},
-  onShow() {},
-  onHide() {},
-  methods: {
-    // 获取轮播图
-    getBanner() {
-      post("ShuZiTeaYW/shop/play").then((res) => {
-        if (res.status == 200) {
-          this.BannerImg = res.list;
-        }
-      });
-    },
-    // 获取公告列表
-    getAnnounce() {
-      post("ShuZiTeaYW/announce/getAnnounce", {
-        status: 2,
-      }).then((res) => {
-        if (res.status == 200) {
-          this.not_list = res.announce;
-        }
-      });
+    name: "Appindex",
+    components: {
+        goodslist, //商品列表
+        swiperBanner, //轮播
     },
-    // 获取公告列表
-    getAnnounce() {
-      post("ShuZiTeaYW/announce/getAnnounce", {
-        status: 2,
-      }).then((res) => {
-        if (res.status == 200) {
-          this.not_list = res.announce;
-        }
-      });
-    },
-    // 获取金刚区列表
-    getImageTwo() {
-      post("ShuZiTeaSpecial/special/imageTwo").then((res) => {
-        if (res.status == 200) {
-          this.area_list = res.data;
-        }
-      });
+    data() {
+        return {
+            BannerImg: [], // 轮播图列表
+            not_list: [], // 公告列表
+            area_list: [], // 金刚区
+            spc_list: [], //活动列表
+            goodslistUrl: "ShuZiTeaYW/shop/getGoodsLikeByUserId", //首页商品列表
+        };
     },
-    // 获取活动区列表
-    getImage() {
-      post("ShuZiTeaSpecial/special/image").then((res) => {
-        if (res.status == 200) {
-          this.spc_list = res.data;
-        }
-      });
+    onLoad(option) {
+        this.getBanner(); //获取轮播图
+        this.getAnnounce(); //获取公告列表
+        this.getImageTwo(); //金刚区
+        this.getImage(); //获取活动列表
     },
-    // 轮播图跳转
-    goList: function (e) {
-      let id = e.id;
-      uni.navigateTo({
-        url: "/pages/prefecture-list/index?id=" + id + "&type=1",
-      });
+    onLaunch() {},
+    onShow() {},
+    onHide() {},
+    methods: {
+        // 获取轮播图
+        getBanner() {
+            post("ShuZiTeaYW/shop/play").then((res) => {
+                if (res.status == 200) {
+                    this.BannerImg = res.list;
+                }
+            });
+        },
+        // 获取公告列表
+        getAnnounce() {
+            post("ShuZiTeaYW/announce/getAnnounce", {
+                status: 2,
+            }).then((res) => {
+                if (res.status == 200) {
+                    this.not_list = res.announce;
+                }
+            });
+        },
+        // 获取公告列表
+        getAnnounce() {
+            post("ShuZiTeaYW/announce/getAnnounce", {
+                status: 2,
+            }).then((res) => {
+                if (res.status == 200) {
+                    this.not_list = res.announce;
+                }
+            });
+        },
+        // 获取金刚区列表
+        getImageTwo() {
+            post("ShuZiTeaSpecial/special/imageTwo").then((res) => {
+                if (res.status == 200) {
+                    this.area_list = res.data;
+                }
+            });
+        },
+        // 获取活动区列表
+        getImage() {
+            post("ShuZiTeaSpecial/special/image").then((res) => {
+                if (res.status == 200) {
+                    this.spc_list = res.data;
+                }
+            });
+        },
+        // 轮播图跳转
+        goList: function(e) {
+            let id = e.id;
+            uni.navigateTo({
+                url: "/pages/prefecture-list/index?id=" + id + "&type=1",
+            });
+        },
     },
-  },
-  computed: {},
-  watch: {},
+    computed: {},
+    watch: {},
 };
 </script>
-
 <style scoped lang='scss'>
 .head {
-  padding: 12rpx 28rpx;
+    padding: 12rpx 28rpx;
 }
+
 .head_search {
-  width: 100%;
-  height: 64rpx;
-  line-height: 64rpx;
-  background: #f3f5f7;
-  border-radius: 32rpx;
-  text-align: center;
-  font-size: 28rpx;
-  color: #bbbbbb;
-  margin-bottom: 26rpx;
-  .search_text {
-    margin-left: 14rpx;
-  }
-}
-.head_notice {
-  margin: 30rpx 0;
-  .notice_title {
-    width: 130rpx;
-    height: 40rpx;
-    float: left;
-    .gg_img {
-      width: 100%;
-      height: 40rpx;
-    }
-  }
-  .notice_swiper {
-    height: 40rpx;
-    padding-left: 20rpx;
+    width: 100%;
+    height: 64rpx;
+    line-height: 64rpx;
+    background: #f3f5f7;
+    border-radius: 32rpx;
+    text-align: center;
     font-size: 28rpx;
-    float: left;
-    box-sizing: border-box;
-    width: calc(100% - 130rpx);
-    .not_list {
-      width: calc(100% - 50rpx);
+    color: #bbbbbb;
+    margin-bottom: 26rpx;
+
+    .search_text {
+        margin-left: 14rpx;
     }
-    .not_ico {
-      width: 30rpx;
-      font-size: 28rpx;
-      color: #999;
+}
+
+.head_notice {
+    margin: 30rpx 0;
+
+    .notice_title {
+        width: 130rpx;
+        height: 40rpx;
+        float: left;
+
+        .gg_img {
+            width: 100%;
+            height: 40rpx;
+        }
     }
-    .not_list,
-    .not_ico {
-      display: inline-block;
-      vertical-align: middle;
-      height: 40rpx;
-      line-height: 40rpx;
+
+    .notice_swiper {
+        height: 40rpx;
+        padding-left: 20rpx;
+        font-size: 28rpx;
+        float: left;
+        box-sizing: border-box;
+        width: calc(100% - 130rpx);
+
+        .not_list {
+            width: calc(100% - 50rpx);
+        }
+
+        .not_ico {
+            width: 30rpx;
+            font-size: 28rpx;
+            color: #999;
+        }
+
+        .not_list,
+        .not_ico {
+            display: inline-block;
+            vertical-align: middle;
+            height: 40rpx;
+            line-height: 40rpx;
+        }
     }
-  }
 }
 
 // 金刚区
 .head_area {
-  margin: 20rpx 0 20rpx;
-  padding: 20rpx 0;
-  border-radius: 18rpx;
-  box-shadow: 2px 2px 13px 1px rgba(17, 18, 29, 0.08);
-  .area_list {
-    display: inline-block;
-    width: 25%;
-    text-align: center;
-    .area_img {
-      width: 46rpx;
-      height: 46rpx;
-      margin-bottom: 12rpx;
-    }
-    .area_name {
-      font-size: 24rpx;
-      color: #474747;
+    margin: 20rpx 0 20rpx;
+    padding: 20rpx 0;
+    border-radius: 18rpx;
+    box-shadow: 2px 2px 13px 1px rgba(17, 18, 29, 0.08);
+
+    .area_list {
+        display: inline-block;
+        width: 25%;
+        text-align: center;
+
+        .area_img {
+            width: 46rpx;
+            height: 46rpx;
+            margin-bottom: 12rpx;
+        }
+
+        .area_name {
+            font-size: 24rpx;
+            color: #474747;
+        }
     }
-  }
 }
+
 // 金刚区-end
 
 // 活动
 .activity {
-  .act_one_img {
-	display: inline-block;
-    width: 300rpx;
-    height: 378rpx;
-    margin-right: 10rpx;
-  }
-  .act_other {
-	display: inline-block;
-    width: calc(100% - 300rpx - 10rpx);
-  }
-  .act_two_img {
-    width: 100%;
-    height: 185rpx;
-  }
+    .act_one_img {
+        display: inline-block;
+        width: 300rpx;
+        height: 378rpx;
+        margin-right: 10rpx;
+    }
+
+    .act_other {
+        display: inline-block;
+        width: calc(100% - 300rpx - 10rpx);
+    }
+
+    .act_two_img {
+        width: 100%;
+        height: 185rpx;
+    }
 }
+
 // 活动-end
 </style>

+ 250 - 244
src/pages/my/login.vue

@@ -1,287 +1,293 @@
 <template>
-  <view class="login">
-    <view class="HLogo">
-      <img src="@/static/img/ycjs.png" alt="" />
-      <p>欢迎登录一茶酒社</p>
-    </view>
-    <view class="phoneL" v-if="LoginType == 1">
-      <view class="clearfix"><input v-model="formD2.mobile" placeholder="请输入手机号" type="number" maxlength="11" /></view>
-      <view class="clearfix">
-        <input v-model="formD2.verifyCode" placeholder="请输入验证码" confirm-type="go" type="number" maxlength="4" class="w70" />
-        <view @click="getVerifyCode" :class="{w30:true,corb:msgNum!=='获取验证码'}">{{msgNum}}</view>
-      </view>
-    </view>
-    <view class="numberL" v-else>
-      <view class="clearfix">
-        <input placeholder="请输入账号" v-model="formD.username" />
-      </view>
-      <view class="clearfix">
-        <input placeholder="请输入密码" v-model="formD.password" password />
-      </view>
-      <view class="clearfix">
-        <input placeholder="请输入验证码" confirm-type="go" maxlength="4" class="w70" v-model="formD.verifyCode" />
-        <img :src="verifyimage" @click="changVerifyimage" class="w30 verifyImg" alt="" />
-      </view>
-    </view>
-    <view @click="login" :class="{bagBtn:true,corg:ISFill}">登录</view>
-    <view class="btnTxt" @click="LoginType = LoginType == 1 ? 0 : 1">
+    <view class="login">
+        <view class="HLogo">
+            <img src="@/static/img/ycjs.png" alt="" />
+            <p>欢迎登录一茶酒社</p>
+        </view>
+        <view class="phoneL" v-if="LoginType == 1">
+            <view class="clearfix"><input v-model="formD2.mobile" placeholder="请输入手机号" type="number" maxlength="11" /></view>
+            <view class="clearfix">
+                <input v-model="formD2.verifyCode" placeholder="请输入验证码" confirm-type="go" type="number" maxlength="4" class="w70" />
+                <view @click="getVerifyCode" :class="{w30:true,corb:msgNum!=='获取验证码'}">{{msgNum}}</view>
+            </view>
+        </view>
+        <view class="numberL" v-else>
+            <view class="clearfix">
+                <input placeholder="请输入账号" v-model="formD.username" />
+            </view>
+            <view class="clearfix">
+                <input placeholder="请输入密码" v-model="formD.password" password />
+            </view>
+            <view class="clearfix">
+                <input placeholder="请输入验证码" confirm-type="go" maxlength="4" class="w70" v-model="formD.verifyCode" />
+                <img :src="verifyimage" @click="changVerifyimage" class="w30 verifyImg" alt="" />
+            </view>
+        </view>
+        <view @click="login" :class="{bagBtn:true,corg:ISFill}">登录</view>
+        <!-- <view class="btnTxt" @click="LoginType = LoginType == 1 ? 0 : 1">
       {{ LoginType == 1 ? "密码登录" : "验证码登录" }}
+    </view> -->
     </view>
-  </view>
 </template>
 <script>
 import { get, post } from "@/request/api.js";
 export default {
-  name: "login",
-  data() {
-    return {
-      LoginType: 1,
-      timestamp: parseInt((new Date()) / 1),
-      formD: {
-        username: "",
-        password: "",
-        verifyCode: "",
-      },
-      formD2: {
-        mobile: '',
-        verifyCode: "",
-        nationCode: "86",
-      },
-      verifyimage: "",
+    name: "login",
+    data() {
+        return {
+            LoginType: 1,
+            timestamp: parseInt((new Date()) / 1),
+            formD: {
+                username: "",
+                password: "",
+                verifyCode: "",
+            },
+            formD2: {
+                mobile: '',
+                verifyCode: "",
+                nationCode: "86",
+            },
+            verifyimage: "",
 
-      msgNum: "获取验证码",
+            msgNum: "获取验证码",
 
-      signKey: '',
-      messageId: "",
+            signKey: '',
+            messageId: "",
 
-      ISFill: false,
-    };
-  },
-  onLoad(option) {
-    this.changVerifyimage(); //获取图形验证码
-    this.getKey();
-  },
-  onLaunch() {},
-  onShow() {},
-  onHide() {},
-  methods: {
-    login() {
-      if (!this.ISFill) {
-        uni.showToast({
-          title: "登录信息填写有误哦",
-          duration: 2000,
-          icon: "none",
-        });
-        return
-      }
-      if (this.LoginType == 1) {
-        post("login/login/verifyCode.do?fd=3", {
-          params: {
-            ...this.formD2,
-            messageId: this.messageId
-          }
-        }).then((res) => {
-          if (res.resultCode == 1) {
-            this.getuserInfo();
-          }
-        });
-      } else {
-        post("login/login/password.do?fd=3", {
-          params: {
-            ...this.formD,
-            password: this.$md5(this.$md5(this.formD.password)),
-          },
-          timestamp: parseInt((new Date()) / 1000)
-        }).then((res) => {
-          if (res.resultCode == 1) {
-            this.getuserInfo();
-          } else {
-            if (res.errorMessage == "验证码不正确") this.changVerifyimage();
-          }
-        });
-      }
-    },
-    getuserInfo(){
-        post("srjywxservice/user2/myInfo.do").then((res) => {
-          if (res.resultCode == 1) {
-            uni.setStorageSync('userinfo', res.data.myInfo);
-            uni.setStorageSync('isvip', res.data.vip);
-            uni.navigateBack();
-          }
-        });
-    },
-    
-    changVerifyimage() {
-      let MathRandom = Math.random();
-      this.verifyimage = this.$hosts.Hhost + "login/login/verifyimage.do?random=" + MathRandom;
+            ISFill: false,
+        };
     },
-    getKey() {
-      get("login/login/getKey.do").then(res => {
-        if (res.resultCode == 1) {
-          this.signKey = res.data.key
-        }
-      })
+    onLoad(option) {
+        this.changVerifyimage(); //获取图形验证码
+        this.getKey();
     },
-    getVerifyCode() {
-      post("login/login/getVerifyCodeWithSign.do?fd=3", {
-        params: {
-          ...this.formD2,
-          randomStr: this.signKey,
-          timeStamp: this.timestamp,
-          sign: this.$md5(this.$md5("99D8EDED73FFCE0981E19D7CA1A58FF3" + this.signKey + this.timestamp)),
+    onLaunch() {},
+    onShow() {},
+    onHide() {},
+    methods: {
+        login() {
+            if (!this.ISFill) {
+                uni.showToast({
+                    title: "登录信息填写有误哦",
+                    duration: 2000,
+                    icon: "none",
+                });
+                return
+            }
+            if (this.LoginType == 1) {
+                post("login/login/verifyCode.do?fd=3", {
+                    params: {
+                        ...this.formD2,
+                        messageId: this.messageId
+                    }
+                }).then((res) => {
+                    if (res.resultCode == 1) {
+                        this.getuserInfo();
+                    }
+                });
+            } else {
+                post("login/login/password.do?fd=3", {
+                    params: {
+                        ...this.formD,
+                        password: this.$md5(this.$md5(this.formD.password)),
+                    },
+                    timestamp: parseInt((new Date()) / 1000)
+                }).then((res) => {
+                    if (res.resultCode == 1) {
+                        this.getuserInfo();
+                    } else {
+                        if (res.errorMessage == "验证码不正确") this.changVerifyimage();
+                    }
+                });
+            }
         },
-        timestamp: this.timestamp
-      }).then((res) => {
-        if (res.resultCode == 1) {
-          this.messageId = res.data.messageId;
-          let number = 60;
-          let as = setInterval(() => {
-            this.msgNum = number + "s后重发"
-            number--;
-            if (number == 0) {
-              this.msgNum = "重发验证码"
-              clearTimeout(as);
+        getuserInfo() {
+            post("srjywxservice/user2/myInfo.do").then((res) => {
+                if (res.resultCode == 1) {
+                    uni.setStorageSync('userinfo', res.data.myInfo);
+                    uni.setStorageSync('isvip', res.data.vip);
+                    uni.navigateBack();
+                }
+            });
+        },
+
+        changVerifyimage() {
+            let MathRandom = Math.random();
+            this.verifyimage = this.$hosts.Hhost + "login/login/verifyimage.do?random=" + MathRandom;
+        },
+        getKey() {
+            get("login/login/getKey.do").then(res => {
+                if (res.resultCode == 1) {
+                    this.signKey = res.data.key
+                }
+            })
+        },
+        getVerifyCode() {
+            post("login/login/getVerifyCodeWithSign.do?fd=3", {
+                params: {
+                    ...this.formD2,
+                    randomStr: this.signKey,
+                    timeStamp: this.timestamp,
+                    sign: this.$md5(this.$md5("99D8EDED73FFCE0981E19D7CA1A58FF3" + this.signKey + this.timestamp)),
+                },
+                timestamp: this.timestamp
+            }).then((res) => {
+                if (res.resultCode == 1) {
+                    this.messageId = res.data.messageId;
+                    let number = 60;
+                    let as = setInterval(() => {
+                        this.msgNum = number + "s后重发"
+                        number--;
+                        if (number == 0) {
+                            this.msgNum = "重发验证码"
+                            clearTimeout(as);
+                        }
+                    }, 1000);
+                }
+            });
+        },
+        isPhone(s) {
+            return /^1[0-9]{10}$/.test(s)
+        },
+        FillIn() {
+            if (this.LoginType == 1) {
+                let m = this.formD2.mobile
+                let v = this.formD2.verifyCode
+                if (m && v && v.length == 4 && this.isPhone(m)) this.ISFill = true
+                else this.ISFill = false
+            } else {
+                let u = this.formD.username
+                let p = this.formD.password
+                let v = this.formD.verifyCode
+                if (u && p && v && v.length == 4) this.ISFill = true
+                else this.ISFill = false
             }
-          }, 1000);
         }
-      });
-    },
-    isPhone(s) {
-      return /^1[0-9]{10}$/.test(s)
     },
-    FillIn() {
-      if (this.LoginType == 1) {
-        let m = this.formD2.mobile
-        let v = this.formD2.verifyCode
-        if (m && v && v.length == 4 && this.isPhone(m)) this.ISFill = true
-        else this.ISFill = false
-      } else {
-        let u = this.formD.username
-        let p = this.formD.password
-        let v = this.formD.verifyCode
-        if (u && p && v && v.length == 4) this.ISFill = true
-        else this.ISFill = false
-      }
-    }
-  },
-  computed: {},
+    computed: {},
 
-  watch: {
-    formD: {
-      deep: true,
-      handler(val) {
-        this.FillIn()
-      }
-    },
-    formD2: {
-      deep: true,
-      handler(val) {
-        this.FillIn()
-      }
+    watch: {
+        formD: {
+            deep: true,
+            handler(val) {
+                this.FillIn()
+            }
+        },
+        formD2: {
+            deep: true,
+            handler(val) {
+                this.FillIn()
+            }
+        },
     },
-  },
 };
 </script>
 <style scoped lang='scss'>
 @font-face {
-  font-family: 'webfont'; //欢迎登录单仁教育 标题文字字体
-  font-display: swap;
-  src: url('//at.alicdn.com/t/webfont_8g34jazbwuj.eot'); /* IE9*/
-  src: url('//at.alicdn.com/t/webfont_8g34jazbwuj.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
-  url('//at.alicdn.com/t/webfont_8g34jazbwuj.woff2') format('woff2'),
-  url('//at.alicdn.com/t/webfont_8g34jazbwuj.woff') format('woff'), /* chrome、firefox */
-  url('//at.alicdn.com/t/webfont_8g34jazbwuj.ttf') format('truetype'), /* chrome、firefox、opera、Safari, Android, iOS 4.2+*/
-  url('//at.alicdn.com/t/webfont_8g34jazbwuj.svg#思源黑体-粗') format('svg'); /* iOS 4.1- */
+    font-family: 'webfont'; //欢迎登录单仁教育 标题文字字体
+    font-display: swap;
+    src: url('//at.alicdn.com/t/webfont_8g34jazbwuj.eot');
+    /* IE9*/
+    src: url('//at.alicdn.com/t/webfont_8g34jazbwuj.eot?#iefix') format('embedded-opentype'),
+        /* IE6-IE8 */
+        url('//at.alicdn.com/t/webfont_8g34jazbwuj.woff2') format('woff2'),
+        url('//at.alicdn.com/t/webfont_8g34jazbwuj.woff') format('woff'),
+        /* chrome、firefox */
+        url('//at.alicdn.com/t/webfont_8g34jazbwuj.ttf') format('truetype'),
+        /* chrome、firefox、opera、Safari, Android, iOS 4.2+*/
+        url('//at.alicdn.com/t/webfont_8g34jazbwuj.svg#思源黑体-粗') format('svg');
+    /* iOS 4.1- */
 }
+
 .login {
-  text-align: center;
+    text-align: center;
 
-  .HLogo {
-    padding-top: 80rpx;
-    margin-bottom: 60rpx;
+    .HLogo {
+        padding-top: 80rpx;
+        margin-bottom: 60rpx;
 
-    img {
-      width: 120rpx;
-      height: 120rpx;
-      border-radius: 50%;
-      background: #ffffff;
-      border: 1px solid #e6e6e6;
-    }
+        img {
+            width: 120rpx;
+            height: 120rpx;
+            border-radius: 50%;
+            background: #ffffff;
+            border: 1px solid #e6e6e6;
+        }
 
-    P {
-      // font-weight: 500;
-      font-size: 40rpx;
-      margin-top: 16rpx;
-      font-family: "webfont" !important;
+        P {
+            // font-weight: 500;
+            font-size: 40rpx;
+            margin-top: 16rpx;
+            font-family: "webfont" !important;
+        }
     }
-  }
 
-  input {
-    width: 100%;
-    padding: 20rpx 0;
-    font-size: 32rpx;
-    text-align: left;
-  }
+    input {
+        width: 100%;
+        padding: 20rpx 0;
+        font-size: 32rpx;
+        text-align: left;
+    }
 
-  .phoneL,
-  .numberL {
-    padding: 0 40rpx;
-    margin-bottom: 80rpx;
+    .phoneL,
+    .numberL {
+        padding: 0 40rpx;
+        margin-bottom: 80rpx;
 
-    .clearfix {
-      border-bottom: 1px solid #d9d9d9;
-      margin-bottom: 40rpx;
+        .clearfix {
+            border-bottom: 1px solid #d9d9d9;
+            margin-bottom: 40rpx;
 
-      .w70 {
-        width: 70%;
-        float: left;
-      }
+            .w70 {
+                width: 70%;
+                float: left;
+            }
 
-      .w30 {
-        width: 30%;
-        float: right;
-        text-align: right;
-        padding: 22rpx 0;
-        color: #2e997f;
-      }
+            .w30 {
+                width: 30%;
+                float: right;
+                text-align: right;
+                padding: 22rpx 0;
+                color: #2e997f;
+            }
 
-      .verifyImg {
-        width: 162rpx;
-        height: 56rpx;
-        padding: 0;
-        margin: 14rpx 0;
-      }
+            .verifyImg {
+                width: 162rpx;
+                height: 56rpx;
+                padding: 0;
+                margin: 14rpx 0;
+            }
 
-      &:last-child {
-        margin-bottom: 0;
-      }
+            &:last-child {
+                margin-bottom: 0;
+            }
 
-      .corb {
-        color: #999;
-      }
+            .corb {
+                color: #999;
+            }
+        }
     }
-  }
 
-  .bagBtn {
-    width: 620rpx;
-    height: 100rpx;
-    line-height: 100rpx;
-    text-align: center;
-    color: #fff;
-    font-size: 36rpx;
-    background: #cde9e3;
-    border-radius: 50rpx;
-    margin: 0 auto;
+    .bagBtn {
+        width: 620rpx;
+        height: 100rpx;
+        line-height: 100rpx;
+        text-align: center;
+        color: #fff;
+        font-size: 36rpx;
+        background: #cde9e3;
+        border-radius: 50rpx;
+        margin: 0 auto;
 
-    &.corg {
-      background: #58B8A1;
+        &.corg {
+            background: #58B8A1;
+        }
     }
-  }
 
-  .btnTxt {
-    color: #2e997f;
-    font-size: 32rpx;
-    margin-top: 30rpx;
-  }
+    .btnTxt {
+        color: #2e997f;
+        font-size: 32rpx;
+        margin-top: 30rpx;
+    }
 }
 </style>

+ 68 - 0
src/pages/protocol/index.vue

@@ -0,0 +1,68 @@
+<template>
+	<view class="container">
+		
+		<!-- 顶部 -->
+		<!-- <view class="head mar_t20">
+			
+		</view> -->
+		<!-- 顶部-end -->
+		
+		<!-- 内容 -->
+		<view class="content mar_t20">
+			<jyf-parser :html="detail.cont"></jyf-parser>
+			<jyf-parser :html="detail.content"></jyf-parser>
+		</view>
+		<!-- 内容-end -->
+	</view>
+</template>
+
+<script>
+// let app=getApp();
+// let reqApi = new ReqApi();
+// var appEv = app.$vm.$options;
+// import { ReqApi } from "@/utils/reqTools.js";
+import jyfParser from '@/components/jyf-parser/jyf-parser.vue'
+import { get, post } from "@/request/api.js";
+	export default {
+		components:{
+			jyfParser
+		},
+		data() {
+			return {
+				detail:'',
+				type:''
+			};
+		},
+		onLoad:function(e){
+			this.type = e.type
+			this.loadData()
+		},
+		methods:{
+			loadData:function(){
+				let that = this;
+				let data = {
+					type:this.type
+				}
+				post("ShuZiTeaYW/shop/getPurchaseAgreement",data).then(res => {
+					if(res.status == 200){
+						that.detail = res.data
+					}
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+// 页面配置
+page{background: #f5f5f5;}
+// 页面配置-end
+
+// 顶部
+.head{width: 100%;overflow: hidden;background: #fff;padding:40rpx 20rpx;box-sizing: border-box;font-size: 26rpx;color:#232323;font-family: "SourceHanSansCN-Medium";font-weight: 500;}
+// 顶部-end
+
+// 内容
+.content{width: 100%;overflow: hidden;background: #fff;padding:40rpx 20rpx;box-sizing: border-box;font-size: 24rpx;color:#363636;font-family: "SourceHanSansCN-Medium";}
+// 内容-end
+</style>

+ 803 - 464
src/pages/sign/index.vue

@@ -1,134 +1,127 @@
 <template>
-	<view class="container">
-		<!-- 页面标题 -->
-		<!-- <view class="pageTitle flex_r flex_ac flex_jc">签到</view> -->
-		<!-- 页面标题-end -->
-		
-		<!-- 用户信息 -->
-		<view class="userinfo flex_r flex_ac">
-			<image class="user_img" :src="userInof.headimgurl ? userInof.headimgurl : 'https://tea.soowin.com/mnt/image/m_avar.jpg'" mode=""></image>
-			<view class="user_info flex_c flex_jc">
-				<view class="user_name">{{userinfo.headimgurl}}</view>
-				<view class="level_con flex_r flex_ac">
-					<view class="level">{{userInof.level}}</view>
-				</view>
-			</view>
-			<!-- <view class="record flex_r flex_ac flex_jc" @tap="NavToSignList">积分记录</view> -->
-		</view>
-		<!-- 用户信息-end -->
-		
-		<!-- 签到信息 -->
-		<view class="sign_info flex_c">
-			<view class="info flex_r flex_ac flex_jb">
-				<view class="info_today flex_c flex_ac">
-					<view class="today_text g_color">{{integerInfo.todaySignIn || 0}}</view>
-					<view class="info_text">今日签到</view>
-				</view>
-				<view class="info_today flex_c flex_ac">
-					<view class="today_text">{{integerInfo.continueCount || 0}}</view>
-					<view class="info_text">累计签到({{integerInfo.continueCount || 0}}次)</view>
-				</view>
-				<view class="info_con">
-					<image class="info_img" :src="integerInfo.time > 0 ? '/static/sgin/p_back2.png' : '/static/sgin/p_back.png'" mode=""></image>
-					<view class="info_texts flex_r flex_ac flex_jc" @tap="setSignIn">{{integerInfo.time > 0 ? timer : ''}}<text v-if="integerInfo.time <= 0">立即签到</text></view>
-				</view>
-			</view>
-			<view class="sign_time flex_r flex_ac flex_je mar_t20">
-				<text></text>
-			</view>
-		</view>
-		<!-- 签到信息-end -->
-		
-		<!-- 积分兑好礼 -->
-		<view class="integral mar_t30" v-if="list.length != 0 && list[0] != ''">
-			<view class="inte_title flex_r flex_ae flex_jb">
-				积分兑好礼
-				<view class="more flex_r flex_ac" @tap="goToIntegralList">更多
-          <text class="not_ico iconfont">&#xe62e;</text>
-					<!-- <image class="more_img" src="/static/sgin/more.png" mode=""></image> -->
-				</view>
-			</view>
-			<view class="inte_con mar_t30 flex_r flex_ac">
-				<view class="inte_goods" v-for="(item,index) in list" :key="index" @tap="openConversion(item.goodsId)">
-					<image class="goods_img" :src="item.goodsThumbnailUrl" mode=""></image>
-					<view class="goods_name ellipsis">{{item.goodsName}}</view>
-					<view class="goods_price">{{item.integral}}<text>积分</text></view>
-				</view>
-			</view>
-		</view>
-		<!-- 积分兑好礼-end -->
-		
-		<!-- 精品推荐 -->
-		<view class="Boutique" v-if="goods.length != 0 && goods[0] != ''">
-			<view class="bou_head flex_r flex_ac flex_jc">
-				<image class="bou_img" src="/static/sgin/left.png" mode=""></image>
-				<view class="bou_title">精品推荐</view>
-				<image class="bou_img" src="/static/sgin/right.png" mode=""></image>
-			</view>
-			<view class="bou_con flex_r flex_ac flex_wrap">
-				<view class="bou_list" v-for="(item,index) in goods" :key="index" @tap="openConversion(item.goodsId)">
-					<image class="bou_l_img" :src="item.goodsThumbnailUrl" mode=""></image>
-					<view class="bou_l_con">
-						<view class="bou_l_name ellipsis">{{item.goodsName}}</view>
-						<!-- <view class="bou_l_info flex_r flex_ae mar_t16">
+    <view class="container">
+        <!-- 页面标题 -->
+        <!-- <view class="pageTitle flex_r flex_ac flex_jc">签到</view> -->
+        <!-- 页面标题-end -->
+        <!-- 用户信息 -->
+        <view class="userinfo flex_r flex_ac">
+            <image class="user_img" :src="userInof.headimgurl ? userInof.headimgurl : 'https://tea.soowin.com/mnt/image/m_avar.jpg'" mode=""></image>
+            <view class="user_info flex_c flex_jc">
+                <view class="user_name">{{userinfo.headimgurl}}</view>
+                <view class="level_con flex_r flex_ac">
+                    <view class="level">{{userInof.level}}</view>
+                </view>
+            </view>
+            <!-- <view class="record flex_r flex_ac flex_jc" @tap="NavToSignList">积分记录</view> -->
+        </view>
+        <!-- 用户信息-end -->
+        <!-- 签到信息 -->
+        <view class="sign_info flex_c">
+            <view class="info flex_r flex_ac flex_jb">
+                <view class="info_today flex_c flex_ac">
+                    <view class="today_text g_color">{{integerInfo.todaySignIn || 0}}</view>
+                    <view class="info_text">今日签到</view>
+                </view>
+                <view class="info_today flex_c flex_ac">
+                    <view class="today_text">{{integerInfo.continueCount || 0}}</view>
+                    <view class="info_text">累计签到({{integerInfo.continueCount || 0}}次)</view>
+                </view>
+                <view class="info_con">
+                    <image class="info_img" :src="integerInfo.time > 0 ? '/static/sgin/p_back2.png' : '/static/sgin/p_back.png'" mode=""></image>
+                    <view class="info_texts flex_r flex_ac flex_jc" @tap="setSignIn">{{integerInfo.time > 0 ? timer : ''}}<text v-if="integerInfo.time <= 0">立即签到</text></view>
+                </view>
+            </view>
+            <view class="sign_time flex_r flex_ac flex_je mar_t20">
+                <text></text>
+            </view>
+        </view>
+        <!-- 签到信息-end -->
+        <!-- 积分兑好礼 -->
+        <view class="integral mar_t30" v-if="list.length != 0 && list[0] != ''">
+            <view class="inte_title flex_r flex_ae flex_jb">
+                积分兑好礼
+                <view class="more flex_r flex_ac" @tap="goToIntegralList">更多
+                    <text class="not_ico iconfont">&#xe62e;</text>
+                    <!-- <image class="more_img" src="/static/sgin/more.png" mode=""></image> -->
+                </view>
+            </view>
+            <view class="inte_con mar_t30 flex_r flex_ac">
+                <view class="inte_goods" v-for="(item,index) in list" :key="index" @tap="openConversion(item.goodsId)">
+                    <image class="goods_img" :src="item.goodsThumbnailUrl" mode=""></image>
+                    <view class="goods_name ellipsis">{{item.goodsName}}</view>
+                    <view class="goods_price">{{item.integral}}<text>积分</text></view>
+                </view>
+            </view>
+        </view>
+        <!-- 积分兑好礼-end -->
+        <!-- 精品推荐 -->
+        <view class="Boutique" v-if="goods.length != 0 && goods[0] != ''">
+            <view class="bou_head flex_r flex_ac flex_jc">
+                <image class="bou_img" src="/static/sgin/left.png" mode=""></image>
+                <view class="bou_title">精品推荐</view>
+                <image class="bou_img" src="/static/sgin/right.png" mode=""></image>
+            </view>
+            <view class="bou_con flex_r flex_ac flex_wrap">
+                <view class="bou_list" v-for="(item,index) in goods" :key="index" @tap="openConversion(item.goodsId)">
+                    <image class="bou_l_img" :src="item.goodsThumbnailUrl" mode=""></image>
+                    <view class="bou_l_con">
+                        <view class="bou_l_name ellipsis">{{item.goodsName}}</view>
+                        <!-- <view class="bou_l_info flex_r flex_ae mar_t16">
 							<view class="bou_l_price flex_r flex_ae"><text>¥</text>450</view>
 							<view class="bou_l_cost">¥414</view>
 						</view> -->
-						<view class="bou_l_msg">{{item.integral}}积分可兑换</view>
-					</view>
-				</view>
-			</view>
-		</view>
-		<view class='fz_w_text mar_b20 mar_t20'>茶,让生活更美好!</view>
-		<!-- 精品推荐-end -->
-		
-		<!-- 兑换弹窗 -->
-		<uni-popup type="center" ref="conversion">
-			<view class="const_con">
-				<image class="closePopup" src="/static/sgin/f_close.png" mode="" @tap="closePopup"></image>
-				<view class="const_head flex_r flex_ac flex_jc">请选择兑换方式</view>
-				<view class="const_info">
-					<view class="frist_info flex_r flex_wrap">
-						<view class="frist_list flex_c mar_b30" v-for="(item,index) in way_list" :key="index" @tap="setCurrent(index)">
-							<view class="flex_r flex_ac">
-								<image class="frist_img" :src="currrent == index ? '/static/sgin/xuanzhong_icon.png' : '/static/sgin/weixuanzhong_icon.png'" mode=""></image>
-								<view class="frist_text">{{item.name}}</view>
-							</view>
-							<view class="surplus">剩余({{item.Integral}}积分)</view>
-						</view>
-					</view>
-					<view class="hint" v-if="isShow">积分不足请用余额或现金支付</view>
-					<view class="pay_way flex_r flex_ac flex_wrap mar_t30" v-if="isShow">
-						<view class="frist_list flex_c">
-							<view class="flex_r flex_ac" @tap="setPayWay(0)">
-								<image class="frist_img" :src="pay_way == 0 ? '/static/sgin/xuanzhong_icon.png' : '/static/sgin/weixuanzhong_icon.png'" mode=""></image>
-								<view class="frist_text">余额</view>
-							</view>
-						</view>
-						<view class="frist_list flex_c">
-							<view class="flex_r flex_ac" @tap="setPayWay(1)">
-								<image class="frist_img" :src="pay_way == 1 ? '/static/sgin/xuanzhong_icon.png' : '/static/sgin/weixuanzhong_icon.png'" mode=""></image>
-								<view class="frist_text">现金</view>
-							</view>
-						</view>
-					</view>
-					<checkbox-group class="flex_r flex_ac flex_jc" @change="checkboxChange">
-						<label class="option_box mar_t30">
-							<checkbox value="1" :checked="checked" color="#2DB389" style="transform:scale(0.7)" /> 我已阅读同意<text @tap.stop="getProPage">《购买协议》</text>
-						</label>
-					</checkbox-group>
-					<view class="conversion flex_r flex_ac flex_jc" @tap="confimConver">确认兑换</view>
-				</view>
-			</view>
-		</uni-popup>
-		<!-- 兑换弹窗-end -->
-		
-		<!-- 授权 -->
-		<authorize-module v-if="showAuth" :shopInfo="shopInfo" @authSuccess="onAuthSuccess" @onGotUserInfo="onGotUserInfo" ></authorize-module>
-		<!-- 授权-end -->
-	</view>
+                        <view class="bou_l_msg">{{item.integral}}积分可兑换</view>
+                    </view>
+                </view>
+            </view>
+        </view>
+        <view class='fz_w_text mar_b20 mar_t20'>茶,让生活更美好!</view>
+        <!-- 精品推荐-end -->
+        <!-- 兑换弹窗 -->
+        <uni-popup type="center" ref="conversion">
+            <view class="const_con">
+                <image class="closePopup" src="/static/sgin/f_close.png" mode="" @tap="closePopup"></image>
+                <view class="const_head flex_r flex_ac flex_jc">请选择兑换方式</view>
+                <view class="const_info">
+                    <view class="frist_info flex_r flex_wrap">
+                        <view class="frist_list flex_c mar_b30" v-for="(item,index) in way_list" :key="index" @tap="setCurrent(index)">
+                            <view class="flex_r flex_ac">
+                                <image class="frist_img" :src="currrent == index ? '/static/sgin/xuanzhong_icon.png' : '/static/sgin/weixuanzhong_icon.png'" mode=""></image>
+                                <view class="frist_text">{{item.name}}</view>
+                            </view>
+                            <view class="surplus">剩余({{item.Integral}}积分)</view>
+                        </view>
+                    </view>
+                    <view class="hint" v-if="isShow">积分不足请用余额或现金支付</view>
+                    <view class="pay_way flex_r flex_ac flex_wrap mar_t30" v-if="isShow">
+                        <view class="frist_list flex_c">
+                            <view class="flex_r flex_ac" @tap="setPayWay(0)">
+                                <image class="frist_img" :src="pay_way == 0 ? '/static/sgin/xuanzhong_icon.png' : '/static/sgin/weixuanzhong_icon.png'" mode=""></image>
+                                <view class="frist_text">余额</view>
+                            </view>
+                        </view>
+                        <view class="frist_list flex_c">
+                            <view class="flex_r flex_ac" @tap="setPayWay(1)">
+                                <image class="frist_img" :src="pay_way == 1 ? '/static/sgin/xuanzhong_icon.png' : '/static/sgin/weixuanzhong_icon.png'" mode=""></image>
+                                <view class="frist_text">现金</view>
+                            </view>
+                        </view>
+                    </view>
+                    <checkbox-group class="flex_r flex_ac flex_jc" @change="checkboxChange">
+                        <label class="option_box mar_t30">
+                            <checkbox value="1" :checked="checked" color="#2DB389" style="transform:scale(0.7)" /> 我已阅读同意<text @tap.stop="getProPage">《购买协议》</text>
+                        </label>
+                    </checkbox-group>
+                    <view class="conversion flex_r flex_ac flex_jc" @tap="confimConver">确认兑换</view>
+                </view>
+            </view>
+        </uni-popup>
+        <!-- 兑换弹窗-end -->
+        <!-- 授权 -->
+        <authorize-module v-if="showAuth" :shopInfo="shopInfo" @authSuccess="onAuthSuccess" @onGotUserInfo="onGotUserInfo"></authorize-module>
+        <!-- 授权-end -->
+    </view>
 </template>
-
 <script>
 var tim
 let page = 1;
@@ -137,371 +130,717 @@ var appEv = app.$vm.$options;
 import uniPopup from '@/components/uni-popup/uni-popup.vue'
 import authorizeModule from '@/components/authorize-module/index'
 import { get, post } from "@/request/api.js";
-	export default {
-		components:{uniPopup,authorizeModule},
-		data() {
-			return {
-				integerInfo:{}, // 积分详情
-				userInof:{} ,// 用户详情
-				timer:'00:00:00' ,// 倒计时
-				list:[] ,// 积分兑好礼
-				goods:[] ,// 精品推荐
-				haveGoods:false ,// 是否有商品
-				way_list:[] ,//兑换方式
-				checked:false, //是否选中协议
-				currrent:0 ,// 选中的兑换方式
-				pay_way:0 ,//选中的支付方式
-				isShow: false ,// 是否显示现金支付
-				goodsId:'' ,// 选中的商品Id
-				showAuth:true, //是否显示授权弹窗
-				shopInfo:{} // 商户信息
-			};
-		},
-		onShow:function(){
-			this.timer = '00:00:00'
-			this.loadData()
-			this.goodsDay()
-			this.getInteGoods()
-			this.integralMethodChange()
-			let that = this;
-			let userId = app.globalData.systemUserInfo && app.globalData.systemUserInfo.userId ? app.globalData.systemUserInfo.userId : '';
-			if (!userId || userId == '' || userId==undefined) {
-				that.showAuth=true
-				appEv.authorizeUserInfo(res=>{
-					if(res){
-						that.showAuth=false
-						that.shopInfo=app.globalData.shopInfo
-					}
-				},true)
-			}else{
-				that.showAuth=false
-				that.shopInfo=app.globalData.shopInfo
-			}
-		},
-		onHide:function(){
-			clearInterval(tim)
-		},
-		methods:{
-			loadData:function(){
-				let that = this;
-        post("ShuZiTeaIntegral/integral/integralInfoNew",{
-          userId: 2064
-        }).then(res => {
-          if(res.status == 200){
-            that.integerInfo = res.integerInfo
-            that.userInof = res.userInof
-            that.setTime()
-          }
-        })
-			},
-			//授权并登录
-			onAuthSuccess:function() {
-			    var that = this;
-			    uni.showLoading({ mask: true })
-			    appEv.setData((res) => {
-					uni.hideLoading()
-					that.loadData()
-					that.showAuth = false
-			    });
-			},
-			// 距可以签到倒计时
-			setTime:function(){
-				var date;
-				let that = this;
-				let timer = that.integerInfo.time / 1000
-				tim = setInterval(()=>{
-					if(timer>=1){
-						timer --
-					}else{
-						clearInterval(tim)
-					}
-					
-					let hour = parseInt(timer/3600) > 9 ? parseInt(timer/3600) : '0' + parseInt(timer/3600)
-					let min = parseInt(timer / 60 % 60) > 9 ? parseInt(timer / 60 % 60) : '0' + parseInt(timer / 60 % 60)
-					let sec = parseInt(timer % 60) > 9 ? parseInt(timer % 60) : '0' + parseInt(timer % 60)
-					
-					date = hour + ':' + min + ':' + sec;
-					this.timer = date
-				},999)
-			},
-			// 签到
-			setSignIn:function(){
-				let that = this;
-        post("ShuZiTeaIntegral/integral/reportNew",{
-          userId: 2064
-        }).then(res => {
-          if(res.status == 200){
-            console.log(res)
-            appEv.errTips(res.msg)
-            that.loadData()
-          }else{
-            appEv.errTips(res.msg)
-          }
-        })
-			},
-			// 获取积分兑好礼商品列表
-			getInteGoods:function(){
-				let that = this;
-				let data = {
-					page:1,
-					limit:3
-				}
-        post("ShuZiTeaIntegral/integral/goods",data).then(res => {
-          if(res.status == 200){
-            that.list = res.goods
-          }else{
-            appEv.errTips(res.msg)
-          }
-        })
-			},
-			// 获取精品推荐
-			goodsDay:function(){
-				let that = this;
-				let data = {
-					page: page,
-					limit: 10
-				}
-        post("/ShuZiTeaIntegral/integral/goodsDay",data).then(res => {
-          if(res.status == 200){
-            let obj = res.goods
-            that.goods = []
-            if(obj.length>0){
-              for(var i in obj){
-                that.goods.push(obj[i])
-              }
-            }else{
-              if(page == 1){
-                that.haveGoods = true
-                page = -1
-              }else{
-                page = -1
-                appEv.errTips('暂无更多')
-              }
+export default {
+    components: { uniPopup, authorizeModule },
+    data() {
+        return {
+            integerInfo: {}, // 积分详情
+            userInof: {}, // 用户详情
+            timer: '00:00:00', // 倒计时
+            list: [], // 积分兑好礼
+            goods: [], // 精品推荐
+            haveGoods: false, // 是否有商品
+            way_list: [], //兑换方式
+            checked: false, //是否选中协议
+            currrent: 0, // 选中的兑换方式
+            pay_way: 0, //选中的支付方式
+            isShow: false, // 是否显示现金支付
+            goodsId: '', // 选中的商品Id
+            showAuth: true, //是否显示授权弹窗
+            shopInfo: {} // 商户信息
+        };
+    },
+    onShow: function() {
+        this.timer = '00:00:00'
+        this.loadData()
+        this.goodsDay()
+        this.getInteGoods()
+        this.integralMethodChange()
+        let that = this;
+        let userId = app.globalData.systemUserInfo && app.globalData.systemUserInfo.userId ? app.globalData.systemUserInfo.userId : '';
+        if (!userId || userId == '' || userId == undefined) {
+            that.showAuth = true
+            appEv.authorizeUserInfo(res => {
+                if (res) {
+                    that.showAuth = false
+                    that.shopInfo = app.globalData.shopInfo
+                }
+            }, true)
+        } else {
+            that.showAuth = false
+            that.shopInfo = app.globalData.shopInfo
+        }
+    },
+    onHide: function() {
+        clearInterval(tim)
+    },
+    methods: {
+        loadData: function() {
+            let that = this;
+            post("ShuZiTeaIntegral/integral/integralInfoNew", {
+                userId: 2064
+            }).then(res => {
+                if (res.status == 200) {
+                    that.integerInfo = res.integerInfo
+                    that.userInof = res.userInof
+                    that.setTime()
+                }
+            })
+        },
+        //授权并登录
+        onAuthSuccess: function() {
+            var that = this;
+            uni.showLoading({ mask: true })
+            appEv.setData((res) => {
+                uni.hideLoading()
+                that.loadData()
+                that.showAuth = false
+            });
+        },
+        // 距可以签到倒计时
+        setTime: function() {
+            var date;
+            let that = this;
+            let timer = that.integerInfo.time / 1000
+            tim = setInterval(() => {
+                if (timer >= 1) {
+                    timer--
+                } else {
+                    clearInterval(tim)
+                }
+
+                let hour = parseInt(timer / 3600) > 9 ? parseInt(timer / 3600) : '0' + parseInt(timer / 3600)
+                let min = parseInt(timer / 60 % 60) > 9 ? parseInt(timer / 60 % 60) : '0' + parseInt(timer / 60 % 60)
+                let sec = parseInt(timer % 60) > 9 ? parseInt(timer % 60) : '0' + parseInt(timer % 60)
+
+                date = hour + ':' + min + ':' + sec;
+                this.timer = date
+            }, 999)
+        },
+        // 签到
+        setSignIn: function() {
+            let that = this;
+            post("ShuZiTeaIntegral/integral/reportNew", {
+                userId: 2064
+            }).then(res => {
+                if (res.status == 200) {
+                    console.log(res)
+                    appEv.errTips(res.msg)
+                    that.loadData()
+                } else {
+                    appEv.errTips(res.msg)
+                }
+            })
+        },
+        // 获取积分兑好礼商品列表
+        getInteGoods: function() {
+            let that = this;
+            let data = {
+                page: 1,
+                limit: 3
             }
-          }else{
-            if(page == 1){
-              that.haveGoods = true
-              page = -1
-            }else{
-              page = -1
-              appEv.errTips('暂无更多')
+            post("ShuZiTeaIntegral/integral/goods", data).then(res => {
+                if (res.status == 200) {
+                    that.list = res.goods
+                } else {
+                    appEv.errTips(res.msg)
+                }
+            })
+        },
+        // 获取精品推荐
+        goodsDay: function() {
+            let that = this;
+            let data = {
+                page: page,
+                limit: 10
+            }
+            post("/ShuZiTeaIntegral/integral/goodsDay", data).then(res => {
+                if (res.status == 200) {
+                    let obj = res.goods
+                    that.goods = []
+                    if (obj.length > 0) {
+                        for (var i in obj) {
+                            that.goods.push(obj[i])
+                        }
+                    } else {
+                        if (page == 1) {
+                            that.haveGoods = true
+                            page = -1
+                        } else {
+                            page = -1
+                            appEv.errTips('暂无更多')
+                        }
+                    }
+                } else {
+                    if (page == 1) {
+                        that.haveGoods = true
+                        page = -1
+                    } else {
+                        page = -1
+                        appEv.errTips('暂无更多')
+                    }
+                }
+            })
+        },
+        // 获取兑换方式
+        integralMethodChange: function() {
+            let that = this;
+            post("ShuZiTeaIntegral/integral/integralMethodChange").then(res => {
+                if (res.status == 200) {
+                    that.way_list = res.data
+                }
+            })
+        },
+        // 更改方式
+        setCurrent: function(e) {
+            this.currrent = e;
+            this.pay_way = '';
+            this.isShow = false;
+        },
+        // 更改支付方式
+        setPayWay: function(e) {
+            this.pay_way = e;
+        },
+        // 确认兑换
+        confimConver: function() {
+            let that = this;
+            let isShow = this.isShow;
+            let pay_way = this.pay_way;
+            let checked = this.checked;
+            let currrent = this.currrent;
+            if (currrent === '') {
+                appEv.errTips('请选择兑换方式')
+                return false;
+            }
+            if (isShow && pay_way === '') {
+                appEv.errTips('请选择支付方式')
+                return false;
+            }
+            if (!checked) {
+                appEv.errTips('请阅读并同意购买协议')
+                return false;
+            }
+            let data = {
+                goodsId: this.goodsId,
+                xyType: 1,
+                integralType: this.way_list[this.currrent].type,
+                count: 1
+            }
+            if (isShow) {
+                data.jeType = this.pay_way == 0 ? 4 : 5
+            } else {
+                data.jeType = 3
             }
-          }
-        })
-			},
-			// 获取兑换方式
-			integralMethodChange:function(){
-				let that = this;
-        post("ShuZiTeaIntegral/integral/integralMethodChange").then(res => {
-          if(res.status == 200){
-            that.way_list = res.data
-          }
-        })
-			},
-			// 更改方式
-			setCurrent:function(e){
-				this.currrent = e;
-				this.pay_way = '';
-				this.isShow = false;
-			},
-			// 更改支付方式
-			setPayWay:function(e){
-				this.pay_way = e;
-			},
-			// 确认兑换
-			confimConver:function(){
-				let that = this;
-				let isShow = this.isShow;
-				let pay_way = this.pay_way;
-				let checked = this.checked;
-				let currrent = this.currrent;
-				if(currrent === ''){
-					appEv.errTips('请选择兑换方式')
-					return false;
-				}
-				if(isShow && pay_way === ''){
-					appEv.errTips('请选择支付方式')
-					return false;
-				}
-				if(!checked){
-					appEv.errTips('请阅读并同意购买协议')
-					return false;
-				}
-				let data = {
-					goodsId:this.goodsId,
-					xyType:1,
-					integralType:this.way_list[this.currrent].type,
-					count:1
-				}
-				if(isShow){
-					data.jeType = this.pay_way == 0 ? 4 : 5
-				}else{
-					data.jeType = 3
-				}
-				
-				const info = reqApi.integralClickExchange(data)
-				if(info){
-					info.then(res => {
-						if(res.status == 200){
-							appEv.errTips(res.msg)
-							let goodsId = that.goodsId;
-							let count = 1;
-							let goodsType = 5;
-							let ojsType = 1;
-							let payType = !isShow ? 3 : isShow && pay_way == 0 ? 4 : isShow && pay_way == 1 ? 5 : isShow && that.way_list[that.currrent].Integral == 0 ? 6 : ''
-							setTimeout(() => {
-								uni.navigateTo({
-									url:'/pages/to-pay-list/index?goodsId=' + goodsId + "&count=" + count + '&goodsType=' + goodsType + '&ojsType=' + ojsType + '&payType=' + payType
-								})
-							},800)
-						}else{
-							appEv.errTips(res.msg)
-							that.isShow = true;
-						}
-					})
-				}
-			},
-			// 更改协议选中情况
-			checkboxChange:function(e){
-				let index = e.detail.value.indexOf('1');
-				if(index != -1){
-					this.checked = true
-				}else{
-					this.checked = false
-				}
-			},
-			// 点击立即兑换打开弹窗
-			openConversion:function(e){
-				this.goodsId = e
-				this.$refs.conversion.open()
-			},
-			// 关闭立即兑换弹窗
-			closePopup:function(){
-				this.$refs.conversion.close()
-			},
-			// 跳转到积分明细列表
-			NavToSignList:function(){
-				uni.navigateTo({
-					url:'/pages/sign-list/index'
-				})
-			},
-			// 跳转到积分列表页面
-			goToIntegralList:function(){
-				uni.navigateTo({
-					url:'/pages/integral-list/index'
-				})
-			},
-			getProPage:function(){
-				uni.navigateTo({
-					url:'/pages/protocol/index?type=' + 4
-				})
-			}
-		}
-	}
-</script>
 
+            const info = reqApi.integralClickExchange(data)
+            if (info) {
+                info.then(res => {
+                    if (res.status == 200) {
+                        appEv.errTips(res.msg)
+                        let goodsId = that.goodsId;
+                        let count = 1;
+                        let goodsType = 5;
+                        let ojsType = 1;
+                        let payType = !isShow ? 3 : isShow && pay_way == 0 ? 4 : isShow && pay_way == 1 ? 5 : isShow && that.way_list[that.currrent].Integral == 0 ? 6 : ''
+                        setTimeout(() => {
+                            uni.navigateTo({
+                                url: '/pages/to-pay-list/index?goodsId=' + goodsId + "&count=" + count + '&goodsType=' + goodsType + '&ojsType=' + ojsType + '&payType=' + payType
+                            })
+                        }, 800)
+                    } else {
+                        appEv.errTips(res.msg)
+                        that.isShow = true;
+                    }
+                })
+            }
+        },
+        // 更改协议选中情况
+        checkboxChange: function(e) {
+            let index = e.detail.value.indexOf('1');
+            if (index != -1) {
+                this.checked = true
+            } else {
+                this.checked = false
+            }
+        },
+        // 点击立即兑换打开弹窗
+        openConversion: function(e) {
+            this.goodsId = e
+            this.$refs.conversion.open()
+        },
+        // 关闭立即兑换弹窗
+        closePopup: function() {
+            this.$refs.conversion.close()
+        },
+        // 跳转到积分明细列表
+        NavToSignList: function() {
+            uni.navigateTo({
+                url: '/pages/sign-list/index'
+            })
+        },
+        // 跳转到积分列表页面
+        goToIntegralList: function() {
+            uni.navigateTo({
+                url: '/pages/integral-list/index'
+            })
+        },
+        getProPage: function() {
+            uni.navigateTo({
+                url: '/pages/protocol/index?type=' + 4
+            })
+        }
+    }
+}
+</script>
 <style lang="scss">
 // 页面配置
-page{background: #f5f5f5;}
-.container{padding:var(--status-bar-height) 30rpx 30rpx;box-sizing: border-box;background: url('https://tea.soowin.com/mnt/image/sign_back.png');background-repeat: no-repeat;background-size: 100% 427rpx;}
+page {
+    background: #f5f5f5;
+}
+
+.container {
+    padding: var(--status-bar-height) 30rpx 30rpx;
+    box-sizing: border-box;
+    background: url('https://tea.soowin.com/mnt/image/sign_back.png');
+    background-repeat: no-repeat;
+    background-size: 100% 427rpx;
+}
+
 // 页面配置-end
 
 // 页面标题
-.pageTitle{font-size: 28rpx;color:#fff;height: 64rpx;}
+.pageTitle {
+    font-size: 28rpx;
+    color: #fff;
+    height: 64rpx;
+}
+
 // 页面标题-end
 
 // 用户信息
-.userinfo{
-  width: 100%;
-  // margin-top: 24rpx;
-  position: relative;
-}
-.user_img{width: 101.5rpx;height: 101.5rpx;margin-right: 20rpx;border-radius: 50%;}
-.level{background: rgba(0,0,0,.18);padding:6rpx 24rpx;font-size: 24rpx;color:#fff;border-radius: 100rpx;}
-.user_name{font-size: 30rpx;color:#fff;font-family: "SourceHanSansSC-Medium";font-weight: 500;margin-bottom: 18rpx;line-height: 1;}
-.record{width: 136rpx;height: 54rpx;background: rgba(0,0,0,.18);color:#fff;font-size: 24rpx;border-radius: 27rpx 0 0 27rpx;position: absolute;bottom:calc(50% - 27rpx);right:-30rpx;}
+.userinfo {
+    width: 100%;
+    // margin-top: 24rpx;
+    position: relative;
+}
+
+.user_img {
+    width: 101.5rpx;
+    height: 101.5rpx;
+    margin-right: 20rpx;
+    border-radius: 50%;
+}
+
+.level {
+    background: rgba(0, 0, 0, .18);
+    padding: 6rpx 24rpx;
+    font-size: 24rpx;
+    color: #fff;
+    border-radius: 100rpx;
+}
+
+.user_name {
+    font-size: 30rpx;
+    color: #fff;
+    font-family: "SourceHanSansSC-Medium";
+    font-weight: 500;
+    margin-bottom: 18rpx;
+    line-height: 1;
+}
+
+.record {
+    width: 136rpx;
+    height: 54rpx;
+    background: rgba(0, 0, 0, .18);
+    color: #fff;
+    font-size: 24rpx;
+    border-radius: 27rpx 0 0 27rpx;
+    position: absolute;
+    bottom: calc(50% - 27rpx);
+    right: -30rpx;
+}
+
 // 用户信息-end
 
 // 签到信息
-.info{width: 100%;overflow: hidden;}
-.info_text{font-size: 24rpx;color:#404040;}
-.info_con{width: 185rpx;height: 185rpx;position: relative;}
-.info_img{width: 100%;height: 185rpx;animation: myfirst 1s infinite;}
-.info_texts{width:100%;height: 100%;position: absolute;top: 0;left: 0;}
-.today_text{font-family: "SourceHanSansCN-Medium";font-size: 53rpx;color:#373737;}
-.info_texts text{width: 56rpx;text-align: justify;font-size: 28rpx;color:#12B381;}
-.sign_time text{width: 185rpx;overflow: hidden;font-size: 36rpx;color:#353535;font-family: "SourceHanSansCN-Bold";font-weight: bold;}
-.sign_info{width: 100%;overflow: hidden;background: #fff;border-radius: 16rpx;box-shadow: 0px 3px 0px 0px rgba(16, 178, 127, 0.36), 0px 6px 10px 0px rgba(17, 179, 129, 0.2);padding:24rpx 40rpx;box-sizing: border-box;margin-top: 44rpx;}
-
-.g_color{color:#12B381;}
-.gr_color{color:#999 !important;}
+.info {
+    width: 100%;
+    overflow: hidden;
+}
+
+.info_text {
+    font-size: 24rpx;
+    color: #404040;
+}
+
+.info_con {
+    width: 185rpx;
+    height: 185rpx;
+    position: relative;
+}
+
+.info_img {
+    width: 100%;
+    height: 185rpx;
+    animation: myfirst 1s infinite;
+}
+
+.info_texts {
+    width: 100%;
+    height: 100%;
+    position: absolute;
+    top: 0;
+    left: 0;
+}
+
+.today_text {
+    font-family: "SourceHanSansCN-Medium";
+    font-size: 53rpx;
+    color: #373737;
+}
+
+.info_texts text {
+    width: 56rpx;
+    text-align: justify;
+    font-size: 28rpx;
+    color: #12B381;
+}
+
+.sign_time text {
+    width: 185rpx;
+    overflow: hidden;
+    font-size: 36rpx;
+    color: #353535;
+    font-family: "SourceHanSansCN-Bold";
+    font-weight: bold;
+}
+
+.sign_info {
+    width: 100%;
+    overflow: hidden;
+    background: #fff;
+    border-radius: 16rpx;
+    box-shadow: 0px 3px 0px 0px rgba(16, 178, 127, 0.36), 0px 6px 10px 0px rgba(17, 179, 129, 0.2);
+    padding: 24rpx 40rpx;
+    box-sizing: border-box;
+    margin-top: 44rpx;
+}
+
+.g_color {
+    color: #12B381;
+}
+
+.gr_color {
+    color: #999 !important;
+}
+
 // 签到信息-end
 
 
 // 动画效果
-@keyframes myfirst
-{
-	0%   {transform: rotate(0);}
-	10%  {transform: rotate(-36deg);}
-	20%  {transform: rotate(-72deg);}
-	30%  {transform: rotate(-108deg);}
-	40%  {transform: rotate(-144deg);}
-	50%  {transform: rotate(-180deg);}
-	60%  {transform: rotate(-216deg);}
-	70%  {transform: rotate(-252deg);}
-	80%  {transform: rotate(-288deg);}
-	90%  {transform: rotate(-324deg);}
-	100% {transform: rotate(-360deg);}
+@keyframes myfirst {
+    0% {
+        transform: rotate(0);
+    }
+
+    10% {
+        transform: rotate(-36deg);
+    }
+
+    20% {
+        transform: rotate(-72deg);
+    }
+
+    30% {
+        transform: rotate(-108deg);
+    }
+
+    40% {
+        transform: rotate(-144deg);
+    }
+
+    50% {
+        transform: rotate(-180deg);
+    }
+
+    60% {
+        transform: rotate(-216deg);
+    }
+
+    70% {
+        transform: rotate(-252deg);
+    }
+
+    80% {
+        transform: rotate(-288deg);
+    }
+
+    90% {
+        transform: rotate(-324deg);
+    }
+
+    100% {
+        transform: rotate(-360deg);
+    }
 }
+
 // 动画效果-end
 
 // 积分兑好礼
-.more{font-size: 24rpx;color:#313131;}
-.inte_con{width: 100%;overflow: hidden;}
-.goods_price{font-size: 30rpx;color:#F15C21;}
-.inte_goods:nth-last-child(1){margin-right: 0;}
-.goods_price text{font-size: 18rpx;color:#F15C21;}
-.more_img{width: 9rpx;height: 16rpx;margin-left: 10rpx;}
-.goods_img{width: 100%;height: 141rpx;margin-bottom: 16rpx;}
-.goods_name{width: 100%;overflow: hidden;color:#1D1D1D;font-size: 24rpx;}
-.inte_goods{width: calc((100% - 28rpx) / 3);margin-right: 14rpx;overflow: hidden;}
-.inte_title{font-size: 36rpx;color:#2A2A2A;font-family: "SourceHanSansSC-Bold";font-weight: bold;}
-.integral{width: 100%;overflow: hidden;background:#fff;padding: 30rpx;box-sizing: border-box;border-radius: 20rpx;}
+.more {
+    font-size: 24rpx;
+    color: #313131;
+}
+
+.inte_con {
+    width: 100%;
+    overflow: hidden;
+}
+
+.goods_price {
+    font-size: 30rpx;
+    color: #F15C21;
+}
+
+.inte_goods:nth-last-child(1) {
+    margin-right: 0;
+}
+
+.goods_price text {
+    font-size: 18rpx;
+    color: #F15C21;
+}
+
+.more_img {
+    width: 9rpx;
+    height: 16rpx;
+    margin-left: 10rpx;
+}
+
+.goods_img {
+    width: 100%;
+    height: 141rpx;
+    margin-bottom: 16rpx;
+}
+
+.goods_name {
+    width: 100%;
+    overflow: hidden;
+    color: #1D1D1D;
+    font-size: 24rpx;
+}
+
+.inte_goods {
+    width: calc((100% - 28rpx) / 3);
+    margin-right: 14rpx;
+    overflow: hidden;
+}
+
+.inte_title {
+    font-size: 36rpx;
+    color: #2A2A2A;
+    font-family: "SourceHanSansSC-Bold";
+    font-weight: bold;
+}
+
+.integral {
+    width: 100%;
+    overflow: hidden;
+    background: #fff;
+    padding: 30rpx;
+    box-sizing: border-box;
+    border-radius: 20rpx;
+}
+
 // 积分兑好礼-end
 
 // 精品推荐
-.bou_img{width: 89rpx;height: 30rpx;}
-.bou_head{width: 100%;height: 114rpx;}
-.bou_con{width: 100%;overflow: hidden;}
-.Boutique{width: 100%;overflow: hidden;}
-.bou_list:nth-child(2n){margin-right: 0;}
-.bou_l_info{width: 100%;overflow: hidden;}
-.bou_l_img{width: 100%;height: 238rpx;display: block;}
-.bou_l_price text{font-size: 24rpx;color:#F15C21;line-height: 1;}
-.bou_l_name{width: 100%;overflow: hidden;font-size: 28rpx;color:#121212;}
-.bou_l_con{width: 100%;overflow: hidden;padding: 20rpx;box-sizing: border-box;}
-.bou_l_msg{width: 100%;overflow: hidden;font-size: 22rpx;color:#F15C21;margin-top: 10rpx;}
-.bou_l_cost{font-size: 24rpx;color:#CCCCCC;text-decoration: line-through;line-height: 1;margin-left: 11rpx;}
-.bou_l_price{font-size: 32rpx;color:#F15C21;font-size:"SourceHanSansSC-Bold";font-weight: bold;line-height: 1;}
-.bou_title{font-size: 36rpx;color:#121212;font-family: "SourceHanSansSC-Bold";font-weight: bold;margin: 0 49rpx;}
-.bou_list{width: calc((100% - 10rpx) / 2);margin-right: 10rpx;margin-bottom: 30rpx;background: #fff;border-radius: 6rpx;overflow: hidden;}
+.bou_img {
+    width: 89rpx;
+    height: 30rpx;
+}
+
+.bou_head {
+    width: 100%;
+    height: 114rpx;
+}
+
+.bou_con {
+    width: 100%;
+    overflow: hidden;
+}
+
+.Boutique {
+    width: 100%;
+    overflow: hidden;
+}
+
+.bou_list:nth-child(2n) {
+    margin-right: 0;
+}
+
+.bou_l_info {
+    width: 100%;
+    overflow: hidden;
+}
+
+.bou_l_img {
+    width: 100%;
+    height: 238rpx;
+    display: block;
+}
+
+.bou_l_price text {
+    font-size: 24rpx;
+    color: #F15C21;
+    line-height: 1;
+}
+
+.bou_l_name {
+    width: 100%;
+    overflow: hidden;
+    font-size: 28rpx;
+    color: #121212;
+}
+
+.bou_l_con {
+    width: 100%;
+    overflow: hidden;
+    padding: 20rpx;
+    box-sizing: border-box;
+}
+
+.bou_l_msg {
+    width: 100%;
+    overflow: hidden;
+    font-size: 22rpx;
+    color: #F15C21;
+    margin-top: 10rpx;
+}
+
+.bou_l_cost {
+    font-size: 24rpx;
+    color: #CCCCCC;
+    text-decoration: line-through;
+    line-height: 1;
+    margin-left: 11rpx;
+}
+
+.bou_l_price {
+    font-size: 32rpx;
+    color: #F15C21;
+    font-size: "SourceHanSansSC-Bold";
+    font-weight: bold;
+    line-height: 1;
+}
+
+.bou_title {
+    font-size: 36rpx;
+    color: #121212;
+    font-family: "SourceHanSansSC-Bold";
+    font-weight: bold;
+    margin: 0 49rpx;
+}
+
+.bou_list {
+    width: calc((100% - 10rpx) / 2);
+    margin-right: 10rpx;
+    margin-bottom: 30rpx;
+    background: #fff;
+    border-radius: 6rpx;
+    overflow: hidden;
+}
+
 // 精品推荐-end
 
 
 // 兑换弹窗
-.option_box{font-size: 26rpx;}
-.option_box text{color:#2DB389;}
-.hint{font-size: 20rpx;color:#D54912;}
-.pay_way{width: 100%;overflow: hidden;}
-.frist_list{width: 50%;overflow: hidden;}
-.surplus{font-size: 22rpx;color:#A8A8A8;}
-.frist_text{font-size: 28rpx;color:#302F2F;}
-.frist_img{width: 35rpx;height: 35rpx;margin-right: 32rpx;}
-.frist_info{width: 100%;overflow: hidden;align-items: initial;}
-.closePopup{width: 42rpx;height: 42rpx;position: absolute;right: 0;top: -65rpx;}
-.const_con{width: 689rpx;border-radius: 10rpx;background: #fff;position: relative;}
-.const_info{width: 100%;overflow: hidden;padding:30rpx 50rpx;box-sizing: border-box;}
-.const_head{width: 100%;height: 97rpx;border-bottom:3rpx solid rgba(0,0,0,.15);font-size: 40rpx;color:#1BBD89;font-family: "SourceHanSansCN-Medium";}
-.conversion{width: 269rpx;height: 68rpx;background: #1BBE8A;font-family: "SourceHanSansCN-Medium";color:#fff;font-size: 32rpx;border-radius: 34rpx;margin: 40rpx auto 0;}
+.option_box {
+    font-size: 26rpx;
+}
+
+.option_box text {
+    color: #2DB389;
+}
+
+.hint {
+    font-size: 20rpx;
+    color: #D54912;
+}
+
+.pay_way {
+    width: 100%;
+    overflow: hidden;
+}
+
+.frist_list {
+    width: 50%;
+    overflow: hidden;
+}
+
+.surplus {
+    font-size: 22rpx;
+    color: #A8A8A8;
+}
+
+.frist_text {
+    font-size: 28rpx;
+    color: #302F2F;
+}
+
+.frist_img {
+    width: 35rpx;
+    height: 35rpx;
+    margin-right: 32rpx;
+}
+
+.frist_info {
+    width: 100%;
+    overflow: hidden;
+    align-items: initial;
+}
+
+.closePopup {
+    width: 42rpx;
+    height: 42rpx;
+    position: absolute;
+    right: 0;
+    top: -65rpx;
+}
+
+.const_con {
+    width: 689rpx;
+    border-radius: 10rpx;
+    background: #fff;
+    position: relative;
+}
+
+.const_info {
+    width: 100%;
+    overflow: hidden;
+    padding: 30rpx 50rpx;
+    box-sizing: border-box;
+}
+
+.const_head {
+    width: 100%;
+    height: 97rpx;
+    border-bottom: 3rpx solid rgba(0, 0, 0, .15);
+    font-size: 40rpx;
+    color: #1BBD89;
+    font-family: "SourceHanSansCN-Medium";
+}
+
+.conversion {
+    width: 269rpx;
+    height: 68rpx;
+    background: #1BBE8A;
+    font-family: "SourceHanSansCN-Medium";
+    color: #fff;
+    font-size: 32rpx;
+    border-radius: 34rpx;
+    margin: 40rpx auto 0;
+}
+
 // 兑换弹窗-end
-</style>
+</style>