App.vue
<script>
export default {
onLaunch() {
// 获取店铺配置信息 全局只请求一次
this.$api.shopConfig(res => {
this.$store.commit('config', res)
// #ifdef H5
//百度统计
if (res.statistics) {
var script = document.createElement("script");
script.innerHTML = res.statistics;
document.getElementsByTagName("body")[0].appendChild(script);
}
// #endif
})
//获取地区信息
this.$api.getAreaList({}, res => {
if (res.status) {
this.$db.set('areaList', res.data)
}
});
// #ifdef APP-PLUS
this.checkVersion()
// #endif
},
onShow: function() {
//console.log('App Show')
},
onHide: function() {
//console.log('App Hide')
},
methods: {
// #ifdef APP-PLUS
// app更新检测
checkVersion() {
// 获取应用版本号
let version = plus.runtime.version
//检测当前平台,如果是安卓则启动安卓更新
uni.getSystemInfo({
success: res => {
this.updateHandler(res.platform, version)
}
})
},
// 更新操作
updateHandler(platform, version) {
let data = {
platform: platform,
version: version
}
let _this = this;
this.$api.getAppVersion(data,
res => {
if (res.status && res.data.lengh > 0) {
const info = res.data[0]
if (info.version !== '' && info.version > version) {
uni.showModal({
//提醒用户更新
title: '更新提示',
content: info.note,
success: res => {
if (res.confirm) {
plus.runtime.openURL(info.download_url)
}
}
})
}
}
}
)
}
// #endif
}
}
</script>
<style lang="scss">
/*每个页面公共css */
@import './static/css/style.css';
.bgf {
background: #FFF;
}
.flc {
display: flex;
justify-content: space-between;
align-items: center;
}
.flc-inline {
display: inline-flex;
align-items: center;
}
.g5 {
color: $g5;
}
.fz12 {
font-size: $fz12;
}
</style>
<style>
@import url("/components/gaoyia-parse/parse.css");
</style>
cli
<?php
define('dir', __DIR__);
$dirArr = explode('\\', dir);
$md = dir . '\\' . $dirArr[count($dirArr) - 1] . '.md';
if (is_file($md))
unlink($md);
// 生成md文件
// file_put_contents($md, listdir(dir, '', 0));
$listArr = listdir(dir);
$content = getContent($listArr);
$tree = "###目录###" . PHP_EOL . "```package" . PHP_EOL . listTree($listArr) . PHP_EOL . '```';
file_put_contents($md, $content . PHP_EOL . $tree);
function getContent($arr, $level = 0)
{
$content = '';
foreach ($arr as $k => $v) {
if (is_array($v)) {
$content .= '###' . getPlaceholder($level, '#') . $k . "###" . getPlaceholder($level, '#') . PHP_EOL;
$content .= getContent($v, $level + 1);
} else if(!in_array(getExt($file),['.gif','.jpg','.png'])){
echo getExt($file);
$fileArr = explode('/', str_replace('\\', '/', $v));
$file = $fileArr[count($fileArr) - 1];
$content .= '###' . getPlaceholder($level, '#') . $file . "###" . getPlaceholder($level, '#') . PHP_EOL;
$content .= '```' . str_replace('.', '', getExt($file)) . PHP_EOL .mb_convert_encoding( file_get_contents($v), 'UTF-8', 'UTF-8,GBK,GB2312,BIG5' ). PHP_EOL . '```' . PHP_EOL;
}
}
return $content;
}
function listTree($arr, $level = 0)
{
$content = '';
$placeholder = getPlaceholder($level);
foreach ($arr as $k => $v) {
if (is_array($v)) {
$content .= $placeholder . '└── ' . $k . PHP_EOL;
$content .= listTree($v, $level + 1);
} else {
$fileArr = explode('/', str_replace('\\', '/', $v));
$file = $fileArr[count($fileArr) - 1];
$content .= $placeholder . '├── ' . $file . PHP_EOL;
}
}
return $content;
}
function listdir($dir)
{
//定义一个数组
$files = array();
$notInArr = ['.', '..', '.git', '.idea', '.DS_Store', 'MD', 'MD.php', '.gitignore', '.gitignore'];
$notExt = ['.exe', '.doc', '.docx', '.pdf', '.sh~', '.rar', '.zip', '.tar','.gif','.jpg','.png'];
//检测是否存在文件
if (is_dir($dir)) {
//打开目录
if ($handle = opendir($dir)) {
//返回当前文件的条目
while (($file = readdir($handle)) !== false) {
//去除特殊目录
if (!in_array($file, $notInArr)) {
//判断子目录是否还存在子目录
if (is_dir($dir . "/" . $file)) {
// 递归调用本函数,再次获取目录
$files[$file] = listdir($dir . "/" . $file);
} else {
if (in_array(getExt($file), $notExt))
continue;
// 获取目录数组
$files[] = $dir . "/" . $file;
}
}
}
//关闭文件夹
closedir($handle);
//返回文件夹数组
return $files;
}
}
}
/**
* 获取占位符
* @param $level
* @param string $placeholder
* @return string
*/
function getPlaceholder($level, $placeholder = ' ')
{
for ($i = 0; $i < $level; $i++) {
$placeholder .= $placeholder;
}
return substr($placeholder, 0, strlen($placeholder) - 1);
}
/**
* 获取文件后戳
* @param $filename
* @return bool|string
*/
function getExt($filename)
{
$pos = strrpos($filename, '.');
$ext = substr($filename, $pos);
return $ext;
}
common
html-parser.js
/*
* HTML5 Parser By Sam Blowes
*
* Designed for HTML5 documents
*
* Original code by John Resig (ejohn.org)
* http://ejohn.org/blog/pure-javascript-html-parser/
* Original code by Erik Arvidsson, Mozilla Public License
* http://erik.eae.net/simplehtmlparser/simplehtmlparser.js
*
* ----------------------------------------------------------------------------
* License
* ----------------------------------------------------------------------------
*
* This code is triple licensed using Apache Software License 2.0,
* Mozilla Public License or GNU Public License
*
* ////////////////////////////////////////////////////////////////////////////
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* ////////////////////////////////////////////////////////////////////////////
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Simple HTML Parser.
*
* The Initial Developer of the Original Code is Erik Arvidsson.
* Portions created by Erik Arvidssson are Copyright (C) 2004. All Rights
* Reserved.
*
* ////////////////////////////////////////////////////////////////////////////
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ----------------------------------------------------------------------------
* Usage
* ----------------------------------------------------------------------------
*
* // Use like so:
* HTMLParser(htmlString, {
* start: function(tag, attrs, unary) {},
* end: function(tag) {},
* chars: function(text) {},
* comment: function(text) {}
* });
*
* // or to get an XML string:
* HTMLtoXML(htmlString);
*
* // or to get an XML DOM Document
* HTMLtoDOM(htmlString);
*
* // or to inject into an existing document/DOM node
* HTMLtoDOM(htmlString, document);
* HTMLtoDOM(htmlString, document.body);
*
*/
// Regular Expressions for parsing tags and attributes
var startTag = /^<([-A-Za-z0-9_]+)((?:\s+[a-zA-Z_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/;
var endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/;
var attr = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g; // Empty Elements - HTML 5
var empty = makeMap('area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr'); // Block Elements - HTML 5
// fixed by xxx 将 ins 标签从块级名单中移除
var block = makeMap('a,address,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video'); // Inline Elements - HTML 5
var inline = makeMap('abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var'); // Elements that you can, intentionally, leave open
// (and which close themselves)
var closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr'); // Attributes that have their values filled in disabled="disabled"
var fillAttrs = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected'); // Special Elements (can contain anything)
var special = makeMap('script,style');
function HTMLParser(html, handler) {
var index;
var chars;
var match;
var stack = [];
var last = html;
stack.last = function () {
return this[this.length - 1];
};
while (html) {
chars = true; // Make sure we're not in a script or style element
if (!stack.last() || !special[stack.last()]) {
// Comment
if (html.indexOf('<!--') == 0) {
index = html.indexOf('-->');
if (index >= 0) {
if (handler.comment) {
handler.comment(html.substring(4, index));
}
html = html.substring(index + 3);
chars = false;
} // end tag
} else if (html.indexOf('</') == 0) {
match = html.match(endTag);
if (match) {
html = html.substring(match[0].length);
match[0].replace(endTag, parseEndTag);
chars = false;
} // start tag
} else if (html.indexOf('<') == 0) {
match = html.match(startTag);
if (match) {
html = html.substring(match[0].length);
match[0].replace(startTag, parseStartTag);
chars = false;
}
}
if (chars) {
index = html.indexOf('<');
var text = index < 0 ? html : html.substring(0, index);
html = index < 0 ? '' : html.substring(index);
if (handler.chars) {
handler.chars(text);
}
}
} else {
html = html.replace(new RegExp('([\\s\\S]*?)<\/' + stack.last() + '[^>]*>'), function (all, text) {
text = text.replace(/<!--([\s\S]*?)-->|<!\[CDATA\[([\s\S]*?)]]>/g, '$1$2');
if (handler.chars) {
handler.chars(text);
}
return '';
});
parseEndTag('', stack.last());
}
if (html == last) {
throw 'Parse Error: ' + html;
}
last = html;
} // Clean up any remaining tags
parseEndTag();
function parseStartTag(tag, tagName, rest, unary) {
tagName = tagName.toLowerCase();
if (block[tagName]) {
while (stack.last() && inline[stack.last()]) {
parseEndTag('', stack.last());
}
}
if (closeSelf[tagName] && stack.last() == tagName) {
parseEndTag('', tagName);
}
unary = empty[tagName] || !!unary;
if (!unary) {
stack.push(tagName);
}
if (handler.start) {
var attrs = [];
rest.replace(attr, function (match, name) {
var value = arguments[2] ? arguments[2] : arguments[3] ? arguments[3] : arguments[4] ? arguments[4] : fillAttrs[name] ? name : '';
attrs.push({
name: name,
value: value,
escaped: value.replace(/(^|[^\\])"/g, '$1\\\"') // "
});
});
if (handler.start) {
handler.start(tagName, attrs, unary);
}
}
}
function parseEndTag(tag, tagName) {
// If no tag name is provided, clean shop
if (!tagName) {
var pos = 0;
} // Find the closest opened tag of the same type
else {
for (var pos = stack.length - 1; pos >= 0; pos--) {
if (stack[pos] == tagName) {
break;
}
}
}
if (pos >= 0) {
// Close all the open elements, up the stack
for (var i = stack.length - 1; i >= pos; i--) {
if (handler.end) {
handler.end(stack[i]);
}
} // Remove the open elements from the stack
stack.length = pos;
}
}
}
function makeMap(str) {
var obj = {};
var items = str.split(',');
for (var i = 0; i < items.length; i++) {
obj[items[i]] = true;
}
return obj;
}
function removeDOCTYPE(html) {
return html.replace(/<\?xml.*\?>\n/, '').replace(/<!doctype.*>\n/, '').replace(/<!DOCTYPE.*>\n/, '');
}
function parseAttrs(attrs) {
return attrs.reduce(function (pre, attr) {
var value = attr.value;
var name = attr.name;
if (pre[name]) {
pre[name] = pre[name] + " " + value;
} else {
pre[name] = value;
}
return pre;
}, {});
}
function parseHtml(html) {
html = removeDOCTYPE(html);
var stacks = [];
var results = {
node: 'root',
children: []
};
HTMLParser(html, {
start: function start(tag, attrs, unary) {
var node = {
name: tag
};
if (attrs.length !== 0) {
node.attrs = parseAttrs(attrs);
}
if (unary) {
var parent = stacks[0] || results;
if (!parent.children) {
parent.children = [];
}
parent.children.push(node);
} else {
stacks.unshift(node);
}
},
end: function end(tag) {
var node = stacks.shift();
if (node.name !== tag) console.error('invalid state: mismatch end tag');
if (stacks.length === 0) {
results.children.push(node);
} else {
var parent = stacks[0];
if (!parent.children) {
parent.children = [];
}
parent.children.push(node);
}
},
chars: function chars(text) {
var node = {
type: 'text',
text: text
};
if (stacks.length === 0) {
results.children.push(node);
} else {
var parent = stacks[0];
if (!parent.children) {
parent.children = [];
}
parent.children.push(node);
}
},
comment: function comment(text) {
var node = {
node: 'comment',
text: text
};
var parent = stacks[0];
if (!parent.children) {
parent.children = [];
}
parent.children.push(node);
}
});
return results.children;
}
export default parseHtml;
uni-H5Api.js
//#ifdef H5
/** clipboard.js v2.0.4**/
!function(t,e){try{window.ClipboardJS=e();}catch(e){};"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return function(n){var o={};function r(t){if(o[t])return o[t].exports;var e=o[t]={i:t,l:!1,exports:{}};return n[t].call(e.exports,e,e.exports,r),e.l=!0,e.exports}
return r.m=n,r.c=o,r.d=function(t,e,n){r.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},r.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s=0)}([function(t,e,n){"use strict";var r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i=function(){function o(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}
return function(t,e,n){return e&&o(t.prototype,e),n&&o(t,n),t}}(),a=o(n(1)),c=o(n(3)),u=o(n(4));function o(t){return t&&t.__esModule?t:{default:t}}
var l=function(t){function o(t,e){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,o);var n=function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}(this,(o.__proto__||Object.getPrototypeOf(o)).call(this));return n.resolveOptions(e),n.listenClick(t),n}
return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(o,c.default),i(o,[{key:"resolveOptions",value:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};this.action="function"==typeof t.action?t.action:this.defaultAction,this.target="function"==typeof t.target?t.target:this.defaultTarget,this.text="function"==typeof t.text?t.text:this.defaultText,this.container="object"===r(t.container)?t.container:document.body}},{key:"listenClick",value:function(t){var e=this;this.listener=(0,u.default)(t,"click",function(t){return e.onClick(t)})}},{key:"onClick",value:function(t){var e=t.delegateTarget||t.currentTarget;this.clipboardAction&&(this.clipboardAction=null),this.clipboardAction=new a.default({action:this.action(e),target:this.target(e),text:this.text(e),container:this.container,trigger:e,emitter:this})}},{key:"defaultAction",value:function(t){return s("action",t)||'copy'}},{key:"defaultTarget",value:function(t){var e=s("target",t);if(e){return document.querySelector(e)}}},{key:"defaultText",value:function(t){return s("text",t)||this.text}},{key:"destroy",value:function(){this.listener.destroy(),this.clipboardAction&&(this.clipboardAction.destroy(),this.clipboardAction=null)}}],[{key:"isSupported",value:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:["copy","cut"],e="string"==typeof t?[t]:t,n=!!document.queryCommandSupported;return e.forEach(function(t){n=n&&!!document.queryCommandSupported(t)}),n}}]),o}();function s(t,e){var n="data-clipboard-"+t;let isFun=e&&typeof e.hasAttribute==='function';if(isFun&&e.hasAttribute(n)){return e.getAttribute(n)}}
t.exports=l},function(t,e,n){"use strict";var o,r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i=function(){function o(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}
return function(t,e,n){return e&&o(t.prototype,e),n&&o(t,n),t}}(),a=n(2),c=(o=a)&&o.__esModule?o:{default:o};var u=function(){function e(t){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,e),this.resolveOptions(t),this.initSelection()}
return i(e,[{key:"resolveOptions",value:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};this.action=t.action,this.container=t.container,this.emitter=t.emitter,this.target=t.target,this.text=t.text,this.trigger=t.trigger,this.selectedText=""}},{key:"initSelection",value:function(){this.text?this.selectFake():this.target&&this.selectTarget()}},{key:"selectFake",value:function(){var t=this,e="rtl"==document.documentElement.getAttribute("dir");this.removeFake(),this.fakeHandlerCallback=function(){return t.removeFake()},this.fakeHandler=this.container.addEventListener("click",this.fakeHandlerCallback)||!0,this.fakeElem=document.createElement("textarea"),this.fakeElem.style.fontSize="12pt",this.fakeElem.style.border="0",this.fakeElem.style.padding="0",this.fakeElem.style.margin="0",this.fakeElem.style.position="absolute",this.fakeElem.style[e?"right":"left"]="-9999px";var n=window.pageYOffset||document.documentElement.scrollTop;this.fakeElem.style.top=n+"px",this.fakeElem.setAttribute("readonly",""),this.fakeElem.value=this.text,this.container.appendChild(this.fakeElem),this.selectedText=(0,c.default)(this.fakeElem),this.copyText()}},{key:"removeFake",value:function(){this.fakeHandler&&(this.container.removeEventListener("click",this.fakeHandlerCallback),this.fakeHandler=null,this.fakeHandlerCallback=null),this.fakeElem&&(this.container.removeChild(this.fakeElem),this.fakeElem=null)}},{key:"selectTarget",value:function(){this.selectedText=(0,c.default)(this.target),this.copyText()}},{key:"copyText",value:function(){var e=void 0;try{e=document.execCommand(this.action)}catch(t){e=!1}
this.handleResult(e)}},{key:"handleResult",value:function(t){this.emitter.emit(t?"success":"error",{action:this.action,text:this.selectedText,trigger:this.trigger,clearSelection:this.clearSelection.bind(this)})}},{key:"clearSelection",value:function(){this.trigger&&this.trigger.focus(),window.getSelection().removeAllRanges()}},{key:"destroy",value:function(){this.removeFake()}},{key:"action",set:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:"copy";if(this._action=t,"copy"!==this._action&&"cut"!==this._action)throw new Error('Invalid "action" value, use either "copy" or "cut"')},get:function(){return this._action}},{key:"target",set:function(t){if(void 0!==t){if(!t||"object"!==(void 0===t?"undefined":r(t))||1!==t.nodeType)throw new Error('Invalid "target" value, use a valid Element');if("copy"===this.action&&t.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if("cut"===this.action&&(t.hasAttribute("readonly")||t.hasAttribute("disabled")))throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes');this._target=t}},get:function(){return this._target}}]),e}();t.exports=u},function(t,e){t.exports=function(t){var e;if("SELECT"===t.nodeName)t.focus(),e=t.value;else if("INPUT"===t.nodeName||"TEXTAREA"===t.nodeName){var n=t.hasAttribute("readonly");n||t.setAttribute("readonly",""),t.select(),t.setSelectionRange(0,t.value.length),n||t.removeAttribute("readonly"),e=t.value}else{t.hasAttribute("contenteditable")&&t.focus();var o=window.getSelection(),r=document.createRange();r.selectNodeContents(t),o.removeAllRanges(),o.addRange(r),e=o.toString()}
return e}},function(t,e){function n(){}
n.prototype={on:function(t,e,n){var o=this.e||(this.e={});return(o[t]||(o[t]=[])).push({fn:e,ctx:n}),this},once:function(t,e,n){var o=this;function r(){o.off(t,r),e.apply(n,arguments)}
return r._=e,this.on(t,r,n)},emit:function(t){for(var e=[].slice.call(arguments,1),n=((this.e||(this.e={}))[t]||[]).slice(),o=0,r=n.length;o<r;o++)n[o].fn.apply(n[o].ctx,e);return this},off:function(t,e){var n=this.e||(this.e={}),o=n[t],r=[];if(o&&e)for(var i=0,a=o.length;i<a;i++)o[i].fn!==e&&o[i].fn._!==e&&r.push(o[i]);return r.length?n[t]=r:delete n[t],this}},t.exports=n},function(t,e,n){var d=n(5),h=n(6);t.exports=function(t,e,n){if(!t&&!e&&!n)throw new Error("Missing required arguments");if(!d.string(e))throw new TypeError("Second argument must be a String");if(!d.fn(n))throw new TypeError("Third argument must be a Function");if(d.node(t))return s=e,f=n,(l=t).addEventListener(s,f),{destroy:function(){l.removeEventListener(s,f)}};if(d.nodeList(t))return a=t,c=e,u=n,Array.prototype.forEach.call(a,function(t){t.addEventListener(c,u)}),{destroy:function(){Array.prototype.forEach.call(a,function(t){t.removeEventListener(c,u)})}};if(d.string(t))return o=t,r=e,i=n,h(document.body,o,r,i);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList");var o,r,i,a,c,u,l,s,f}},function(t,n){n.node=function(t){return void 0!==t&&t instanceof HTMLElement&&1===t.nodeType},n.nodeList=function(t){var e=Object.prototype.toString.call(t);return void 0!==t&&("[object NodeList]"===e||"[object HTMLCollection]"===e)&&"length"in t&&(0===t.length||n.node(t[0]))},n.string=function(t){return"string"==typeof t||t instanceof String},n.fn=function(t){return"[object Function]"===Object.prototype.toString.call(t)}},function(t,e,n){var a=n(7);function i(t,e,n,o,r){var i=function(e,n,t,o){return function(t){t.delegateTarget=a(t.target,n),t.delegateTarget&&o.call(e,t)}}.apply(this,arguments);return t.addEventListener(n,i,r),{destroy:function(){t.removeEventListener(n,i,r)}}}
t.exports=function(t,e,n,o,r){return"function"==typeof t.addEventListener?i.apply(null,arguments):"function"==typeof n?i.bind(null,document).apply(null,arguments):("string"==typeof t&&(t=document.querySelectorAll(t)),Array.prototype.map.call(t,function(t){return i(t,e,n,o,r)}))}},function(t,e){if("undefined"!=typeof Element&&!Element.prototype.matches){var n=Element.prototype;n.matches=n.matchesSelector||n.mozMatchesSelector||n.msMatchesSelector||n.oMatchesSelector||n.webkitMatchesSelector}
t.exports=function(t,e){for(;t&&9!==t.nodeType;){if("function"==typeof t.matches&&t.matches(e))return t;t=t.parentNode}}}])});let Types={isFunction:function(obj){var type=Object.prototype.toString.call(obj)
return type=='[object Function]'},isObject:function(obj){var type=Object.prototype.toString.call(obj)
return type=='[object Object]'},isString:function(obj){var type=Object.prototype.toString.call(obj)
return type=='[object String]'}}
uni.setClipboardData=function(options){let emptyFun=function(){}
let config={data:null,event:null,success:emptyFun,fail:emptyFun,complete:emptyFun}
if(options&&Types.isObject(options)){config=Object.assign({},config,options)}
if(options&&Types.isString(options)){config=Object.assign({},config,{data:options})}
let data=config.data
let success=config.success||emptyFun
let fail=config.fail||emptyFun
let complete=config.complete||emptyFun
let e=config.event||window.event||{}
let cb=new ClipboardJS('.null',{text:()=>data})
cb.on('success',function(res){
window.__clipboard__=data;
success&&Types.isFunction(success)&&success({data:res.text})
complete&&Types.isFunction(complete)&&complete()
cb.off('error')
cb.off('success')
cb.destroy()})
cb.on('error',function(err){fail&&Types.isFunction(fail)&&fail(err)
complete&&Types.isFunction(complete)&&complete()
cb.off('error')
cb.off('success')
cb.destroy()})
cb.onClick(e)};
uni.getClipboardData=function(options){let emptyFun=function(){}
let config={data:null,event:null,success:emptyFun,fail:emptyFun,complete:emptyFun}
if(options&&Types.isObject(options)){config=Object.assign({},config,options)}
let success=config.success||emptyFun
let fail=config.fail||emptyFun
let complete=config.complete||emptyFun
if(window.__clipboard__!==undefined){success&&Types.isFunction(success)&&success({data:window.__clipboard__})}else{fail&&Types.isFunction(fail)&&fail({data:null})}
complete&&Types.isFunction(complete)&&complete()};
function fileDownLoad(data){var linkElement=document.createElement('a')
linkElement.setAttribute('href',data.blob)
linkElement.setAttribute('downLoad',data.name)
linkElement.click()}
uni.saveImageToPhotosAlbum=uni.saveVideoToPhotosAlbum=function(options){let emptyFun=function(){}
let config={filePath:null,success:emptyFun,fail:emptyFun,complete:emptyFun}
if(options&&Types.isObject(options)){config=Object.assign({},config,options)}
if(options&&Types.isString(options)){config=Object.assign({},config,{filePath:options})}
let filePath=config.filePath
let success=config.success||emptyFun
let fail=config.fail||emptyFun
let complete=config.complete||emptyFun
if(!filePath){fail&&Types.isFunction(fail)&&fail({msg:'no File'})
complete&&Types.isFunction(complete)&&complete()
return}
let names=filePath.split('/')
let name=names[names.length-1]
uni.downloadFile({url:filePath,success:function(res){let tempFilePath=res.tempFilePath
fileDownLoad({name:name,blob:tempFilePath})
success&&Types.isFunction(success)&&success({filePath:filePath})},fail:function(err){fail&&Types.isFunction(fail)&&fail({msg:err})},complete:function(){complete&&Types.isFunction(complete)&&complete()}})}
//#endif
components
area-picker
areaPicker.vue
<template>
<view>
<view class="picker-mask" @click="closePicker" catchtouchmove="true" v-show="pickerShow" ></view>
<view class="picker-content" :class="{'pickerShow':pickerShow}" >
<view class="picker-button">
<text @click="closePicker">取消</text>
<text @click="confirm">确定</text>
</view>
<!-- 三列选择-联动 -->
<picker-view class="picker-view" indicator-class="picker-view-selected-three" :value="pickerIndex" @change="pickerViewChangeThree">
<picker-view-column>
<view class="picker-item" v-for="(item, index) in pickerList" :key="index">{{item.label}}</view>
</picker-view-column>
<picker-view-column >
<view class="picker-item" v-for="(item, index) in pickerList[pickerIndex[0]].children" :key="index">{{item.label}}</view>
</picker-view-column>
<picker-view-column>
<view class="picker-item" v-for="(item, index) in pickerList[pickerIndex[0]].children[pickerIndex[1]].children"
:key="index">{{item.label}}</view>
</picker-view-column>
</picker-view>
</view>
</view>
</template>
<script>
// mode所有类型
let pickerModeArray = ["one", "two_linkage", "two_nolinkage", "three"];
export default {
name: "area-picker",
props: {
areaId:{
type: Number,
required: true,
},
// 默认picker选中项索引
defaultIndex: {
type: Array,
required: true,
validator: (value) => {
if (value.length > 0 && value.length <= 3) {
return true;
}
return false;
}
}
},
data() {
return {
pickerIndex: [0,0,0], // picker索引值
pickerShow: false,
region: ['河南省', '郑州市', '中原区'], //开户行地区
provinceKey:-1,//省份id
cityKey:-1,//市id
areaKey:-1,//区域id
selectedData:[],
pickerList:this.$db.get("areaList"),
province:this.$db.get("areaList"),
};
},
created() {
this.init();
},
watch: {
// 匹配选中索引
mode() {
this.pickerIndex = this.defaultIndex;
}
},
methods: {
init(){
this.province = this.$db.get("areaList");
//查找省市区 id
this.getFullPath(this.areaId,this.province);
this.pickerIndex = [this.provinceKey,this.cityKey,this.areaKey];
},
//倒查城市信息
getFullPath(id,data){
for(var i = 0;i<data.length;i++){
if(id == data[i].value){
if(!data[i].children){
this.areaKey = i;
return true;
}else if(data[i].hasOwnProperty("children")){
if(data[i].children[0] && !data[i].children[0].children){
this.cityKey = i;
return true;
}else{
this.provinceKey = i;
return true;
}
}
}else{
if(data[i].hasOwnProperty("children")){
if(data[i].children[0]!==undefined){
if(data[i].children[0].hasOwnProperty("children")){
this.provinceKey = i;
}else{
this.cityKey = i;
}
}
if(typeof data[i].children !='undefined' ){
var res = this.getFullPath(id,data[i].children);
if(res){
return true;
}
}
}
}
}
},
// 三列联动选项变化
pickerViewChangeThree(e) {
let changeValue = e.detail.value;
// 超规处理
if (this.pickerList[changeValue[0]].children.length - 1 < changeValue[1]) {
changeValue[1] = this.pickerList[changeValue[0]].children.length - 1;
}
if (this.pickerList[changeValue[0]].children[changeValue[1]].children.length - 1 < changeValue[2]) {
changeValue[2] = this.pickerList[changeValue[0]].children[changeValue[1]].children.length - 1;
}
this.pickerIndex = changeValue;
},
// 显示组件
showPicker() {
// 隐藏软件盘
uni.hideKeyboard();
this.init();
this.pickerShow = true;
},
// 确定事件——返回选中项的数组索引(也可以自定义其他返回数据,不过返回索引通用性更强)
confirm() {
this.pickerShow = false;
this.selectedData = [
{
id:this.province[this.pickerIndex[0]].value,
name:this.province[this.pickerIndex[0]].label,
},
{
id:this.province[this.pickerIndex[0]].children[this.pickerIndex[1]].value,
name:this.province[this.pickerIndex[0]].children[this.pickerIndex[1]].label,
},
{
id:this.province[this.pickerIndex[0]].children[this.pickerIndex[1]].children[this.pickerIndex[2]].value,
name:this.province[this.pickerIndex[0]].children[this.pickerIndex[1]].children[this.pickerIndex[2]].label,
},
];
this.$emit("onConfirm", this.selectedData);
},
// 隐藏组件
closePicker() {
this.pickerShow = false;
}
}
}
</script>
<style>
.picker-mask {
position: fixed;
top: 0;
right: 0;
left: 0;
bottom: 0;
z-index: 50;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.3);
}
.picker-content {
flex-direction: column;
position: fixed;
bottom: 0;
left: 0;
z-index: 100;
width: 100%;
height: 600upx;
background-color: #FFFFFF;
transform: translateY(100%);
transition: all 200ms ease;
}
.pickerShow {
transform: translateY(0) !important;
}
.picker-content .picker-button {
justify-content: space-between;
height: 80upx;
line-height: 80upx;
}
.picker-button text {
width: 180upx;
font-size: 28upx;
font-weight: 500;
display: block;
text-align: center;
overflow: hidden;
}
.picker-button text:first-child {
color: #A1A1A1;
float: left;
}
.picker-button text:last-child {
color: #FF7159;
float: right;
}
.picker-content .picker-view {
width: 100%;
height: 500upx;
}
.picker-content .picker-view-selected-one,
.picker-content .picker-view-selected-two,
.picker-content .picker-view-selected-three {
height: 68upx;
line-height: 68upx;
border-top: #1AAD19 1upx solid;
border-bottom: #1AAD19 1upx solid;
}
.picker-content .picker-view-selected-one {
position: relative;
left: 25%;
width: 50%;
}
.picker-content .picker-view-selected-two {
position: relative;
left: 15%;
width: 70%;
}
.picker-content .picker-view-selected-three {
position: relative;
left: 5%;
width: 90%;
}
.picker-view .picker-item {
width: 100%;
height: 34px;
line-height: 34px;
font-size: 15px;
font-weight: 600;
display: block;
text-align: center;
}
</style>
cmd-progress
cmd-progress.vue
<template>
<view class="cmd-progress cmd-progress-default" :class="setStatusClass">
<block v-if="type == 'circle' || type == 'dashboard'">
<view class="cmd-progress cmd-progress-default" :class="setStatusClass">
<view class="cmd-progress-inner" :style="setCircleStyle">
<!-- 绘制圈 start -->
<!-- #ifdef H5 -->
<svg viewBox="0 0 100 100" class="cmd-progress-circle">
<path :d="setCirclePath" stroke="#f3f3f3" :stroke-linecap="strokeShape" :stroke-width="strokeWidth"
fill-opacity="0" class="cmd-progress-circle-trail" :style="setCircleTrailStyle"></path>
<path :d="setCirclePath" :stroke-linecap="strokeShape" :stroke-width="strokeWidth" fill-opacity="0" class="cmd-progress-circle-path"
:style="setCirclePathStyle"></path>
</svg>
<!-- #endif -->
<!-- #ifndef H5 -->
<text :style="setCircle"></text>
<!-- #endif -->
<!-- 绘制圈 end -->
<!-- 状态文本 start -->
<block v-if="showInfo && !custom">
<text class="cmd-progress-text" :title="setFormat">
<block v-if="status != 'success' && status != 'exception' && setProgress < 100">{{setFormat}}</block>
<!-- #ifdef H5 -->
<svg v-if="status == 'exception'" viewBox="64 64 896 896" data-icon="close" width="1.5em" height="1.5em" fill="currentColor"
aria-hidden="true">
<path d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 0 0 203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"></path>
</svg>
<svg v-if="status == 'success' || setProgress == 100" viewBox="64 64 896 896" data-icon="check" width="1.5em"
height="1.5em" fill="currentColor" aria-hidden="true" :style="{'color': strokeColor ? strokeColor : ''}">
<path d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 0 0-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"></path>
</svg>
<!-- #endif -->
<!-- #ifndef H5 -->
<text v-if="status == 'exception' || status == 'success' || setProgress == 100" :style="setCircleIcon"></text>
<!-- #endif -->
</text>
</block>
<block v-else>
<view class="cmd-progress-custom">
<slot></slot>
</view>
</block>
<!-- 状态文本 end -->
</view>
</view>
</block>
<block v-if="type == 'line'">
<!-- 进度条 start -->
<view class="cmd-progress-outer">
<view class="cmd-progress-inner" :style="{'border-radius': strokeShape == 'square' ? 0 : '100px'}">
<view class="cmd-progress-bg" :style="setLineStyle"></view>
<view v-if="successPercent" class="cmd-progress-success-bg" :style="setLineSuccessStyle"></view>
</view>
</view>
<!-- 进度条 end -->
<!-- 进度条是否显示信息 start -->
<block v-if="showInfo && !custom">
<text class="cmd-progress-text" :title="setFormat">
<block v-if="status != 'success' && status != 'exception' && setProgress < 100">{{setFormat}}</block>
<!-- #ifdef H5 -->
<svg v-if="status == 'exception'" viewBox="64 64 896 896" data-icon="close-circle" width="1.5em" height="1.5em"
fill="currentColor" aria-hidden="true">
<path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 0 1-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"></path>
</svg>
<svg v-if="status == 'success' || setProgress == 100" viewBox="64 64 896 896" data-icon="check-circle" width="1.5em"
height="1.5em" fill="currentColor" aria-hidden="true" :style="{'color': strokeColor ? strokeColor : ''}">
<path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm193.5 301.7l-210.6 292a31.8 31.8 0 0 1-51.7 0L318.5 484.9c-3.8-5.3 0-12.7 6.5-12.7h46.9c10.2 0 19.9 4.9 25.9 13.3l71.2 98.8 157.2-218c6-8.3 15.6-13.3 25.9-13.3H699c6.5 0 10.3 7.4 6.5 12.7z"></path>
</svg>
<!-- #endif -->
<!-- #ifndef H5 -->
<text v-if="status == 'exception' || status == 'success' || setProgress == 100" :style="setLineStatusIcon"></text>
<!-- #endif -->
</text>
</block>
<block v-else>
<view class="cmd-progress-custom">
<slot></slot>
</view>
</block>
<!-- 进度条是否显示信息 end -->
</block>
</view>
</template>
<script>
/**
* 进度条组件
* @description 显示一个操作完成的百分比时,为用户显示该操作的当前进度和状态。
* @tutorial https://ext.dcloud.net.cn/plugin?id=259
* @property {String} type 进度类型 - 线型:line、圆圈形:circle、仪表盘:dashboard,默认线型:line
* @property {Number} percent 进度百分比值 - 显示范围0-100 ,可能数比较大就需要自己转成百分比的值
* @property {Number} success-percent 进度已完成的百分几 - 仅支持进度线型:line
* @property {String} status 进度状态 - 涌动:active(仅支持线型:line)、正常:normal、完成:success、失败:exception,默认正常:normal
* @property {Boolean} show-info 进度状态信息 - 是否显示进度数值或状态图标,默认true
* @property {Number} stroke-width 进度线条的宽度 - 建议在条线的宽度范围:1-50,与进度条显示宽度有关,默认8
* @property {String} stroke-color 进度线条的颜色 - 渐变色仅支持线型:line
* @property {String} stroke-shape 进度线条两端的形状 - 圆:round、方块直角:square,默认圆:round
* @property {Number} width 进度画布宽度 - 仅支持圆圈形:circle、仪表盘:dashboard,默认80
* @property {String} gap-degree 进度圆形缺口角度 - 可取值 0 ~ 360,仅支持圆圈形:circle、仪表盘:dashboard
* @property {String} gap-position 进度圆形缺口位置 - 可取值'top', 'bottom', 'left', 'right',仅支持圆圈形:circle、仪表盘:dashboard
* @property {Boolean} custom 自定义文本格式插槽,条line:圈circle 仪表板dashboard
* @example <cmd-progress :percent="30"></cmd-progress>
*/
export default {
name: 'cmd-progress',
props: {
/**
* 类型默认:line,可选 line circle dashboard
*/
type: {
validator: val => {
return ['line', 'circle', 'dashboard'].includes(val);
},
default: 'line'
},
/**
* 百分比
*/
percent: {
type: Number,
default: 0
},
/**
* 已完成的分段百分,仅支持类型line
*/
successPercent: {
type: Number,
default: 0
},
/**
* 是否显示进度数值或状态图标
*/
showInfo: {
type: Boolean,
default: true
},
/**
* 自定义文本格式插槽,条line:圈circle 仪表板dashboard
*/
custom: {
type: Boolean,
default: false
},
/**
* 进度状态,可选:normal success exception (active仅支持类型line
*/
status: {
validator: val => {
return ['normal', 'success', 'exception', 'active'].includes(val);
},
default: 'normal'
},
/**
* 条线的宽度1-50,与width有关
*/
strokeWidth: {
type: Number,
default: 6
},
/**
* 条线的颜色,渐变色仅支持类型line
*/
strokeColor: {
type: String,
default: ''
},
/**
* 条线两端的形状 可选:'round', 'square'
*/
strokeShape: {
validator: val => {
return ['round', 'square'].includes(val);
},
default: 'round'
},
/**
* 圆形进度条画布宽度,支持类型circle dashboard
*/
width: {
type: Number,
default: 80
},
/**
* 圆形进度条缺口角度,可取值 0 ~ 360,支持类型circle dashboard
*/
gapDegree: {
type: Number,
default: 0
},
/**
* 圆形进度条缺口位置,可取值'top', 'bottom', 'left', 'right' ,支持类型circle dashboard
*/
gapPosition: {
validator: val => {
return ['top', 'bottom', 'left', 'right'].includes(val);
},
default: 'top'
}
},
computed: {
/**
* 百分比格式
*/
setFormat() {
return `${this.setProgress}%`;
},
/**
* 设置显示进度值,禁止小于0和超过100
*/
setProgress() {
let percent = this.percent;
if (!this.percent || this.percent < 0) {
percent = 0;
} else if (this.percent >= 100) {
percent = 100;
}
return percent;
},
/**
* 进度圈svg大小
*/
setCircleStyle() {
return `width: ${this.width}px;
height: ${this.width}px;
fontSize: ${this.width * 0.15 + 6}px;`
},
/**
* 圈底色
*/
setCircleTrailStyle() {
const radius = 50 - this.strokeWidth / 2;
const len = Math.PI * 2 * radius;
const gapDeg = this.gapDegree || (this.type === 'dashboard' && 75);
return `stroke-dasharray: ${len - (gapDeg||0)}px, ${len}px;
stroke-dashoffset: -${(gapDeg||0) / 2}px;
transition: stroke-dashoffset 0.3s ease 0s, stroke-dasharray 0.3s ease 0s, stroke 0.3s;`
},
/**
* 圈进度
*/
setCirclePathStyle() {
const radius = 50 - this.strokeWidth / 2;
const len = Math.PI * 2 * radius;
const gapDeg = this.gapDegree || (this.type === 'dashboard' && 75);
return `stroke: ${this.strokeColor};
stroke-dasharray: ${(this.setProgress / 100) * (len - (gapDeg||0))}px, ${len}px;
stroke-dashoffset: -${(gapDeg||0) / 2}px;
transition: stroke-dashoffset 0.3s ease 0s, stroke-dasharray 0.3s ease 0s, stroke 0.3s, stroke-width 0.06s ease 0.3s;`
},
/**
* 绘制圈
*/
setCirclePath() {
const radius = 50 - this.strokeWidth / 2;
let beginPositionX = 0;
let beginPositionY = -radius;
let endPositionX = 0;
let endPositionY = -2 * radius;
const gapPos = (this.type === 'dashboard' && 'bottom') || this.gapPosition || 'top';
switch (gapPos) {
case 'left':
beginPositionX = -radius;
beginPositionY = 0;
endPositionX = 2 * radius;
endPositionY = 0;
break;
case 'right':
beginPositionX = radius;
beginPositionY = 0;
endPositionX = -2 * radius;
endPositionY = 0;
break;
case 'bottom':
beginPositionY = radius;
endPositionY = 2 * radius;
break;
default:
break;
}
return `M 50,50 m ${beginPositionX},${beginPositionY} a ${radius},${radius} 0 1 1 ${endPositionX},${-endPositionY} a ${radius},${radius} 0 1 1 ${-endPositionX},${endPositionY}`;
},
// #ifndef H5
/**
* 非H5端,绘制进度圈svg转base URL
*/
setCircle() {
const radius = 50 - this.strokeWidth / 2;
const len = Math.PI * 2 * radius;
const gapDeg = this.gapDegree || (this.type === 'dashboard' && 75);
let currentColor = '#108ee9'
// 异常进度
if (this.status == 'exception') {
currentColor = '#f5222d'
}
// 完成进度
if (this.status == 'success' || this.setProgress >= 100 || this.strokeColor) {
currentColor = this.strokeColor || '#fff'
}
let svgToBase =
`data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' class='cmd-progress-circle'%3E%3Cpath d='${this.setCirclePath}' stroke='%23f3f3f3' stroke-linecap='${this.strokeShape}' stroke-width='${this.strokeWidth}' fill-opacity='0' class='cmd-progress-circle-trail' style='stroke-dasharray: ${len - (gapDeg||0)}px, ${len}px;stroke-dashoffset: -${(gapDeg||0) / 2}px;transition: stroke-dashoffset 0.3s ease 0s, stroke-dasharray 0.3s ease 0s, stroke 0.3s;'%3E%3C/path%3E%3Cpath d='${this.setCirclePath}' stroke-linecap='${this.strokeShape}' stroke-width='${this.strokeWidth}' fill-opacity='0' class='cmd-progress-circle-path' style='stroke: ${currentColor};stroke-dasharray: ${(this.setProgress / 100) * (len - (gapDeg||0))}px, ${len}px;stroke-dashoffset: -${(gapDeg||0) / 2}px;transition: stroke-dashoffset 0.3s ease 0s, stroke-dasharray 0.3s ease 0s, stroke 0.3s, stroke-width 0.06s ease 0.3s;'%3E%3C/path%3E%3C/svg%3E`
return `background-image: url("${svgToBase}");
background-size: cover;
display: inline-block;
${this.setCircleStyle}`;
},
/**
* 设置进度圈状态图标
*/
setCircleIcon() {
let currentColor = '#108ee9'
let svgToBase = ''
// 异常进度
if (this.status == 'exception') {
currentColor = '#f5222d'
svgToBase =
`data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='64 64 896 896' data-icon='close' width='1.5em' height='1.5em' fill='${currentColor}' aria-hidden='true'%3E %3Cpath d='M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 0 0 203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z'%3E%3C/path%3E %3C/svg%3E`;
}
// 完成进度
if (this.status == 'success' || this.setProgress >= 100) {
currentColor = this.strokeColor || '#fff'
svgToBase =
`data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='64 64 896 896' data-icon='check' width='1.5em' height='1.5em' fill='${currentColor}' aria-hidden='true'%3E %3Cpath d='M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 0 0-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z'%3E%3C/path%3E %3C/svg%3E`;
}
return `background-image: url("${svgToBase}");
background-size: cover;
display: inline-block;
width: 1.5em;
height: 1.5em;`;
},
// #endif
/**
* 设置进度条样式
*/
setLineStyle() {
return `width: ${this.setProgress}%;
height: ${this.strokeWidth}px;
background: ${this.strokeColor};
border-radius: ${this.strokeShape === 'square' ? 0 : '100px'};`;
},
/**
* 设置已完成分段进度
*/
setLineSuccessStyle() {
let successPercent = this.successPercent;
if (!this.successPercent || this.successPercent < 0 || this.setProgress < this.successPercent) {
successPercent = 0;
} else if (this.successPercent >= 100) {
successPercent = 100;
}
return `width: ${successPercent}%;
height: ${this.strokeWidth}px;
border-radius: ${this.strokeShape === 'square' ? 0 : '100px'};`;
},
// #ifndef H5
/**
* 设置进度条状态图标
*/
setLineStatusIcon() {
let currentColor = '#108ee9'
let svgToBase = ''
// 异常进度
if (this.status == 'exception') {
currentColor = '#f5222d'
svgToBase =
`data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='64 64 896 896' data-icon='close-circle' width='1.5em' height='1.5em' fill='${currentColor}' aria-hidden='true'%3E %3Cpath d='M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 0 1-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z'%3E%3C/path%3E %3C/svg%3E`;
}
// 完成进度
if (this.status == 'success' || this.setProgress >= 100) {
currentColor = this.strokeColor || '#fff'
svgToBase =
`data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='64 64 896 896' data-icon='check-circle' width='1.5em' height='1.5em' fill='${currentColor}' aria-hidden='true'%3E %3Cpath d='M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm193.5 301.7l-210.6 292a31.8 31.8 0 0 1-51.7 0L318.5 484.9c-3.8-5.3 0-12.7 6.5-12.7h46.9c10.2 0 19.9 4.9 25.9 13.3l71.2 98.8 157.2-218c6-8.3 15.6-13.3 25.9-13.3H699c6.5 0 10.3 7.4 6.5 12.7z'%3E%3C/path%3E %3C/svg%3E`;
}
return `background-image: url("${svgToBase}");
background-size: cover;
display: inline-block;
width: 1.5em;
height: 1.5em;`;
},
// #endif
/**
* 状态样式
*/
setStatusClass() {
let statusClass = [];
// 异常进度
if (this.status == 'exception') {
statusClass.push('cmd-progress-status-exception')
}
// 完成进度
if (this.status == 'success' || this.setProgress >= 100) {
statusClass.push('cmd-progress-status-success')
}
// 活动进度条
if (this.status == 'active') {
statusClass.push('cmd-progress-status-active')
}
// 是否显示信息
if (this.showInfo) {
statusClass.push('cmd-progress-show-info')
}
// 进度条类型
if (this.type === 'line') {
statusClass.push('cmd-progress-line')
}
// 进度圈、仪表盘类型
if (this.type === 'circle' || this.type === 'dashboard') {
statusClass.push('cmd-progress-circle')
}
statusClass.push('cmd-progress-status-normal')
return statusClass;
}
}
}
</script>
<style>
.cmd-progress {
font-family: "Chinese Quote", -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-size: 28upx;
font-variant: tabular-nums;
line-height: 1.5;
color: rgba(0, 0, 0, 0.65);
box-sizing: border-box;
margin: 0;
padding: 0;
list-style: none;
display: inline-block;
}
.cmd-progress-line {
width: 100%;
font-size: 28upx;
position: relative;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
.cmd-progress-outer {
display: inline-block;
width: 100%;
margin-right: 0;
padding-right: 0;
}
.cmd-progress-show-info .cmd-progress-outer {
flex: 1;
}
.cmd-progress-inner {
display: inline-block;
width: 100%;
background-color: #f5f5f5;
border-radius: 200upx;
vertical-align: middle;
position: relative;
}
.cmd-progress-circle-trail {
stroke: #f5f5f5;
}
.cmd-progress-circle-path {
stroke: #1890ff;
animation: appear 0.3s;
}
.cmd-progress-success-bg,
.cmd-progress-bg {
background-color: #1890ff;
transition: all 0.4s cubic-bezier(0.08, 0.82, 0.17, 1) 0s;
position: relative;
}
.cmd-progress-success-bg {
background-color: #fff;
position: absolute;
top: 0;
left: 0;
}
.cmd-progress-custom {
max-width: 50%;
margin-left: 16upx;
vertical-align: middle;
display: inline-block;
white-space: normal;
word-wrap: break-word;
word-break: break-all;
line-height: 1;
}
.cmd-progress-text {
min-width: 60upx;
text-align: left;
margin-left: 16upx;
vertical-align: middle;
display: inline-block;
white-space: normal;
color: rgba(255, 255, 255, 0.8);
line-height: 1;
}
.cmd-progress-status-active .cmd-progress-bg:before {
content: "";
opacity: 0;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: #fff;
border-radius: 20upx;
-webkit-animation: cmd-progress-active 2.4s cubic-bezier(0.23, 1, 0.32, 1) infinite;
animation: cmd-progress-active 2.4s cubic-bezier(0.23, 1, 0.32, 1) infinite;
}
.cmd-progress-status-exception .cmd-progress-bg {
background-color: #f5222d;
}
.cmd-progress-status-exception .cmd-progress-text {
color: #f5222d;
}
.cmd-progress-status-exception .cmd-progress-circle-path {
stroke: #f5222d;
}
.cmd-progress-status-success .cmd-progress-bg {
background-color: #fff;
}
.cmd-progress-status-success .cmd-progress-text {
color: #fff;
}
.cmd-progress-status-success .cmd-progress-circle-path {
stroke: #fff;
}
.cmd-progress-circle .cmd-progress-inner {
position: relative;
line-height: 1;
background-color: transparent;
}
.cmd-progress-circle .cmd-progress-custom {
display: block;
position: absolute;
line-height: 1;
top: 50%;
-webkit-transform: translateY(-50%);
transform: translateY(-50%);
left: 25%;
right: 25%;
margin: 0;
overflow: hidden;
white-space: normal;
word-wrap: break-word;
word-break: break-all;
}
.cmd-progress-circle .cmd-progress-text {
display: block;
position: absolute;
width: 100%;
text-align: center;
line-height: 1;
top: 50%;
-webkit-transform: translateY(-50%);
transform: translateY(-50%);
left: 0;
margin: 0;
color: rgba(0, 0, 0, 0.65);
white-space: normal;
}
.cmd-progress-circle .cmd-progress-status-exception .cmd-progress-text {
color: #f5222d;
}
.cmd-progress-circle .cmd-progress-status-success .cmd-progress-text {
color: #fff;
}
@keyframes cmd-progress-active {
0% {
opacity: 0.1;
width: 0;
}
20% {
opacity: 0.5;
width: 0;
}
100% {
opacity: 0;
width: 100%;
}
}
</style>
gaoyia-parse
components
wxParseAudio.vue
<template>
<!-- '<audio/>' 组件不再维护,建议使用能力更强的 'uni.createInnerAudioContext' 接口 有时间再改-->
<!--增加audio标签支持-->
<audio
:id="node.attr.id"
:class="node.classStr"
:style="node.styleStr"
:src="node.attr.src"
:loop="node.attr.loop"
:poster="node.attr.poster"
:name="node.attr.name"
:author="node.attr.author"
controls></audio>
</template>
<script>
export default {
name: 'wxParseAudio',
props: {
node: {
type: Object,
default() {
return {};
},
},
},
};
</script>
wxParseImg.vue
<template>
<image
:mode="node.attr.mode"
:lazy-load="node.attr.lazyLoad"
:class="node.classStr"
:style="newStyleStr || node.styleStr"
:data-src="node.attr.src"
:src="node.attr.src"
@tap="wxParseImgTap"
@load="wxParseImgLoad"
/>
</template>
<script>
export default {
name: 'wxParseImg',
data() {
return {
newStyleStr: '',
preview: true
};
},
inject: ['parseWidth'],
mounted() {},
props: {
node: {
type: Object,
default() {
return {};
}
}
},
methods: {
wxParseImgTap(e) {
if (!this.preview) return;
const { src } = e.currentTarget.dataset;
if (!src) return;
let parent = this.$parent;
while (!parent.preview || typeof parent.preview !== 'function') {
// TODO 遍历获取父节点执行方法
parent = parent.$parent;
}
parent.preview(src, e);
},
// 图片视觉宽高计算函数区
wxParseImgLoad(e) {
const { src } = e.currentTarget.dataset;
if (!src) return;
let { width, height } = e.mp.detail;
const recal = this.wxAutoImageCal(width, height);
const { imageheight, imageWidth } = recal;
const { padding, mode } = this.node.attr;//删除padding
// const { mode } = this.node.attr;
const { styleStr } = this.node;
const imageHeightStyle = mode === 'widthFix' ? '' : `height: ${imageheight}px;`;
this.newStyleStr = `${styleStr}; ${imageHeightStyle}; width: ${imageWidth}px; padding: 0 ${+padding}px;`;//删除padding
// this.newStyleStr = `${styleStr}; ${imageHeightStyle}; width: ${imageWidth}px;`;
},
// 计算视觉优先的图片宽高
wxAutoImageCal(originalWidth, originalHeight) {
// 获取图片的原始长宽
const windowWidth = this.parseWidth.value;
const results = {};
if (originalWidth < 60 || originalHeight < 60) {
const { src } = this.node.attr;
let parent = this.$parent;
while (!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.removeImageUrl(src);
this.preview = false;
}
// 判断按照那种方式进行缩放
if (originalWidth > windowWidth) {
// 在图片width大于手机屏幕width时候
results.imageWidth = windowWidth;
results.imageheight = windowWidth * (originalHeight / originalWidth);
} else {
// 否则展示原来的数据
results.imageWidth = originalWidth;
results.imageheight = originalHeight;
}
return results;
}
}
};
</script>
wxParseTable.vue
<template>
<rich-text :nodes="nodes"></rich-text>
</template>
<script>
export default {
name: 'wxParseTable',
props: {
node: {
type: Object,
default() {
return {};
},
},
},
data() {
return {
nodes:[]
};
},
mounted() {
this.nodes=this.loadNode([this.node]);
},
methods: {
loadNode(node) {
let obj = [];
for (let children of node) {
// console.log(children)
if (children.node=='element') {
let t = {
name:children.tag,
attrs: {
class: children.classStr,
// style: children.styleStr,
},
children: children.nodes?this.loadNode(children.nodes):[]
}
obj.push(t)
} else if(children.node=='text'){
obj.push({
type: 'text',
text: children.text
})
}
}
return obj
}
}
};
</script>
wxParseTemplate0.vue
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate1';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate0',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;// TODO currentTarget才有dataset
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {// TODO 遍历获取父节点执行方法
parent = parent.$parent;
}
parent.navigate(href, e);
},
}
};
</script>
wxParseTemplate1.vue
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate2';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate1',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>
wxParseTemplate10.vue
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate11';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate10',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>
wxParseTemplate11.vue
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</template>
<script>
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate11',
props: {
node: {},
},
components: {
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>
wxParseTemplate2.vue
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate3';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate2',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>
wxParseTemplate3.vue
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate4';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate3',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>
wxParseTemplate4.vue
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate5';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate4',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>
wxParseTemplate5.vue
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate6';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate5',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>
wxParseTemplate6.vue
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate7';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate6',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>
wxParseTemplate7.vue
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate8';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate7',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>
wxParseTemplate8.vue
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate9';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate8',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>
wxParseTemplate9.vue
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate10';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate9',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>
wxParseVideo.vue
<template>
<!--增加video标签支持,并循环添加-->
<view :class="node.classStr" :style="node.styleStr">
<video :class="node.classStr" :style="node.styleStr" class="video-video" :src="node.attr.src" :poster="node.attr.poster"></video>
</view>
</template>
<script>
export default {
name: 'wxParseVideo',
props: {
node: {},
},
};
</script>
libs
html2json.js
/**
* html2Json 改造来自: https://github.com/Jxck/html2json
*
*
* author: Di (微信小程序开发工程师)
* organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
* 垂直微信小程序开发交流社区
*
* github地址: https://github.com/icindy/wxParse
*
* for: 微信小程序富文本解析
* detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
*/
import wxDiscode from './wxDiscode';
import HTMLParser from './htmlparser';
function makeMap(str) {
const obj = {};
const items = str.split(',');
for (let i = 0; i < items.length; i += 1) obj[items[i]] = true;
return obj;
}
// Block Elements - HTML 5
const block = makeMap('br,code,address,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video');
// Inline Elements - HTML 5
const inline = makeMap('a,abbr,acronym,applet,b,basefont,bdo,big,button,cite,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var');
// Elements that you can, intentionally, leave open
// (and which close themselves)
const closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr');
function removeDOCTYPE(html) {
const isDocument = /<body.*>([^]*)<\/body>/.test(html);
return isDocument ? RegExp.$1 : html;
}
function trimHtml(html) {
return html
.replace(/<!--.*?-->/gi, '')
.replace(/\/\*.*?\*\//gi, '')
.replace(/[ ]+</gi, '<')
.replace(/<script[^]*<\/script>/gi, '')
.replace(/<style[^]*<\/style>/gi, '');
}
function getScreenInfo() {
const screen = {};
wx.getSystemInfo({
success: (res) => {
screen.width = res.windowWidth;
screen.height = res.windowHeight;
},
});
return screen;
}
function html2json(html, customHandler, imageProp, host) {
// 处理字符串
html = removeDOCTYPE(html);
html = trimHtml(html);
html = wxDiscode.strDiscode(html);
// 生成node节点
const bufArray = [];
const results = {
nodes: [],
imageUrls: [],
};
const screen = getScreenInfo();
function Node(tag) {
this.node = 'element';
this.tag = tag;
this.$screen = screen;
}
HTMLParser(html, {
start(tag, attrs, unary) {
// node for this element
const node = new Node(tag);
if (bufArray.length !== 0) {
const parent = bufArray[0];
if (parent.nodes === undefined) {
parent.nodes = [];
}
}
if (block[tag]) {
node.tagType = 'block';
} else if (inline[tag]) {
node.tagType = 'inline';
} else if (closeSelf[tag]) {
node.tagType = 'closeSelf';
}
node.attr = attrs.reduce((pre, attr) => {
const { name } = attr;
let { value } = attr;
if (name === 'class') {
node.classStr = value;
}
// has multi attibutes
// make it array of attribute
if (name === 'style') {
node.styleStr = value;
}
if (value.match(/ /)) {
value = value.split(' ');
}
// if attr already exists
// merge it
if (pre[name]) {
if (Array.isArray(pre[name])) {
// already array, push to last
pre[name].push(value);
} else {
// single value, make it array
pre[name] = [pre[name], value];
}
} else {
// not exist, put it
pre[name] = value;
}
return pre;
}, {});
// 优化样式相关属性
if (node.classStr) {
node.classStr += ` ${node.tag}`;
} else {
node.classStr = node.tag;
}
if (node.tagType === 'inline') {
node.classStr += ' inline';
}
// 对img添加额外数据
if (node.tag === 'img') {
let imgUrl = node.attr.src;
imgUrl = wxDiscode.urlToHttpUrl(imgUrl, imageProp.domain);
Object.assign(node.attr, imageProp, {
src: imgUrl || '',
});
if (imgUrl) {
results.imageUrls.push(imgUrl);
}
}
// 处理a标签属性
if (node.tag === 'a') {
node.attr.href = node.attr.href || '';
}
// 处理font标签样式属性
if (node.tag === 'font') {
const fontSize = [
'x-small',
'small',
'medium',
'large',
'x-large',
'xx-large',
'-webkit-xxx-large',
];
const styleAttrs = {
color: 'color',
face: 'font-family',
size: 'font-size',
};
if (!node.styleStr) node.styleStr = '';
Object.keys(styleAttrs).forEach((key) => {
if (node.attr[key]) {
const value = key === 'size' ? fontSize[node.attr[key] - 1] : node.attr[key];
node.styleStr += `${styleAttrs[key]}: ${value};`;
}
});
}
// 临时记录source资源
if (node.tag === 'source') {
results.source = node.attr.src;
}
if (customHandler.start) {
customHandler.start(node, results);
}
if (unary) {
// if this tag doesn't have end tag
// like <img src="hoge.png"/>
// add to parents
const parent = bufArray[0] || results;
if (parent.nodes === undefined) {
parent.nodes = [];
}
parent.nodes.push(node);
} else {
bufArray.unshift(node);
}
},
end(tag) {
// merge into parent tag
const node = bufArray.shift();
if (node.tag !== tag) {
console.error('invalid state: mismatch end tag');
}
// 当有缓存source资源时于于video补上src资源
if (node.tag === 'video' && results.source) {
node.attr.src = results.source;
delete results.source;
}
if (customHandler.end) {
customHandler.end(node, results);
}
if (bufArray.length === 0) {
results.nodes.push(node);
} else {
const parent = bufArray[0];
if (!parent.nodes) {
parent.nodes = [];
}
parent.nodes.push(node);
}
},
chars(text) {
if (!text.trim()) return;
const node = {
node: 'text',
text,
};
if (customHandler.chars) {
customHandler.chars(node, results);
}
if (bufArray.length === 0) {
results.nodes.push(node);
} else {
const parent = bufArray[0];
if (parent.nodes === undefined) {
parent.nodes = [];
}
parent.nodes.push(node);
}
},
});
return results;
}
export default html2json;
htmlparser.js
/**
*
* htmlParser改造自: https://github.com/blowsie/Pure-JavaScript-HTML5-Parser
*
* author: Di (微信小程序开发工程师)
* organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
* 垂直微信小程序开发交流社区
*
* github地址: https://github.com/icindy/wxParse
*
* for: 微信小程序富文本解析
* detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
*/
// Regular Expressions for parsing tags and attributes
const startTag = /^<([-A-Za-z0-9_]+)((?:\s+[a-zA-Z0-9_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/;
const endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/;
const attr = /([a-zA-Z0-9_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g;
function makeMap(str) {
const obj = {};
const items = str.split(',');
for (let i = 0; i < items.length; i += 1) obj[items[i]] = true;
return obj;
}
// Empty Elements - HTML 5
const empty = makeMap('area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr');
// Block Elements - HTML 5
const block = makeMap('address,code,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video');
// Inline Elements - HTML 5
const inline = makeMap('a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var');
// Elements that you can, intentionally, leave open
// (and which close themselves)
const closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr');
// Attributes that have their values filled in disabled="disabled"
const fillAttrs = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected');
function HTMLParser(html, handler) {
let index;
let chars;
let match;
let last = html;
const stack = [];
stack.last = () => stack[stack.length - 1];
function parseEndTag(tag, tagName) {
// If no tag name is provided, clean shop
let pos;
if (!tagName) {
pos = 0;
} else {
// Find the closest opened tag of the same type
tagName = tagName.toLowerCase();
for (pos = stack.length - 1; pos >= 0; pos -= 1) {
if (stack[pos] === tagName) break;
}
}
if (pos >= 0) {
// Close all the open elements, up the stack
for (let i = stack.length - 1; i >= pos; i -= 1) {
if (handler.end) handler.end(stack[i]);
}
// Remove the open elements from the stack
stack.length = pos;
}
}
function parseStartTag(tag, tagName, rest, unary) {
tagName = tagName.toLowerCase();
if (block[tagName]) {
while (stack.last() && inline[stack.last()]) {
parseEndTag('', stack.last());
}
}
if (closeSelf[tagName] && stack.last() === tagName) {
parseEndTag('', tagName);
}
unary = empty[tagName] || !!unary;
if (!unary) stack.push(tagName);
if (handler.start) {
const attrs = [];
rest.replace(attr, function genAttr(matches, name) {
const value = arguments[2] || arguments[3] || arguments[4] || (fillAttrs[name] ? name : '');
attrs.push({
name,
value,
escaped: value.replace(/(^|[^\\])"/g, '$1\\"'), // "
});
});
if (handler.start) {
handler.start(tagName, attrs, unary);
}
}
}
while (html) {
chars = true;
if (html.indexOf('</') === 0) {
match = html.match(endTag);
if (match) {
html = html.substring(match[0].length);
match[0].replace(endTag, parseEndTag);
chars = false;
}
// start tag
} else if (html.indexOf('<') === 0) {
match = html.match(startTag);
if (match) {
html = html.substring(match[0].length);
match[0].replace(startTag, parseStartTag);
chars = false;
}
}
if (chars) {
index = html.indexOf('<');
let text = '';
while (index === 0) {
text += '<';
html = html.substring(1);
index = html.indexOf('<');
}
text += index < 0 ? html : html.substring(0, index);
html = index < 0 ? '' : html.substring(index);
if (handler.chars) handler.chars(text);
}
if (html === last) throw new Error(`Parse Error: ${html}`);
last = html;
}
// Clean up any remaining tags
parseEndTag();
}
export default HTMLParser;
wxDiscode.js
// HTML 支持的数学符号
function strNumDiscode(str) {
str = str.replace(/∀/g, '∀');
str = str.replace(/∂/g, '∂');
str = str.replace(/∃/g, '∃');
str = str.replace(/∅/g, '∅');
str = str.replace(/∇/g, '∇');
str = str.replace(/∈/g, '∈');
str = str.replace(/∉/g, '∉');
str = str.replace(/∋/g, '∋');
str = str.replace(/∏/g, '∏');
str = str.replace(/∑/g, '∑');
str = str.replace(/−/g, '−');
str = str.replace(/∗/g, '∗');
str = str.replace(/√/g, '√');
str = str.replace(/∝/g, '∝');
str = str.replace(/∞/g, '∞');
str = str.replace(/∠/g, '∠');
str = str.replace(/∧/g, '∧');
str = str.replace(/∨/g, '∨');
str = str.replace(/∩/g, '∩');
str = str.replace(/∪/g, '∪');
str = str.replace(/∫/g, '∫');
str = str.replace(/∴/g, '∴');
str = str.replace(/∼/g, '∼');
str = str.replace(/≅/g, '≅');
str = str.replace(/≈/g, '≈');
str = str.replace(/≠/g, '≠');
str = str.replace(/≤/g, '≤');
str = str.replace(/≥/g, '≥');
str = str.replace(/⊂/g, '⊂');
str = str.replace(/⊃/g, '⊃');
str = str.replace(/⊄/g, '⊄');
str = str.replace(/⊆/g, '⊆');
str = str.replace(/⊇/g, '⊇');
str = str.replace(/⊕/g, '⊕');
str = str.replace(/⊗/g, '⊗');
str = str.replace(/⊥/g, '⊥');
str = str.replace(/⋅/g, '⋅');
return str;
}
// HTML 支持的希腊字母
function strGreeceDiscode(str) {
str = str.replace(/Α/g, 'Α');
str = str.replace(/Β/g, 'Β');
str = str.replace(/Γ/g, 'Γ');
str = str.replace(/Δ/g, 'Δ');
str = str.replace(/Ε/g, 'Ε');
str = str.replace(/Ζ/g, 'Ζ');
str = str.replace(/Η/g, 'Η');
str = str.replace(/Θ/g, 'Θ');
str = str.replace(/Ι/g, 'Ι');
str = str.replace(/Κ/g, 'Κ');
str = str.replace(/Λ/g, 'Λ');
str = str.replace(/Μ/g, 'Μ');
str = str.replace(/Ν/g, 'Ν');
str = str.replace(/Ξ/g, 'Ν');
str = str.replace(/Ο/g, 'Ο');
str = str.replace(/Π/g, 'Π');
str = str.replace(/Ρ/g, 'Ρ');
str = str.replace(/Σ/g, 'Σ');
str = str.replace(/Τ/g, 'Τ');
str = str.replace(/Υ/g, 'Υ');
str = str.replace(/Φ/g, 'Φ');
str = str.replace(/Χ/g, 'Χ');
str = str.replace(/Ψ/g, 'Ψ');
str = str.replace(/Ω/g, 'Ω');
str = str.replace(/α/g, 'α');
str = str.replace(/β/g, 'β');
str = str.replace(/γ/g, 'γ');
str = str.replace(/δ/g, 'δ');
str = str.replace(/ε/g, 'ε');
str = str.replace(/ζ/g, 'ζ');
str = str.replace(/η/g, 'η');
str = str.replace(/θ/g, 'θ');
str = str.replace(/ι/g, 'ι');
str = str.replace(/κ/g, 'κ');
str = str.replace(/λ/g, 'λ');
str = str.replace(/μ/g, 'μ');
str = str.replace(/ν/g, 'ν');
str = str.replace(/ξ/g, 'ξ');
str = str.replace(/ο/g, 'ο');
str = str.replace(/π/g, 'π');
str = str.replace(/ρ/g, 'ρ');
str = str.replace(/ς/g, 'ς');
str = str.replace(/σ/g, 'σ');
str = str.replace(/τ/g, 'τ');
str = str.replace(/υ/g, 'υ');
str = str.replace(/φ/g, 'φ');
str = str.replace(/χ/g, 'χ');
str = str.replace(/ψ/g, 'ψ');
str = str.replace(/ω/g, 'ω');
str = str.replace(/ϑ/g, 'ϑ');
str = str.replace(/ϒ/g, 'ϒ');
str = str.replace(/ϖ/g, 'ϖ');
str = str.replace(/·/g, '·');
return str;
}
function strcharacterDiscode(str) {
// 加入常用解析
str = str.replace(/ /g, ' ');
str = str.replace(/ /g, ' ');
str = str.replace(/ /g, ' ');
str = str.replace(/"/g, "'");
str = str.replace(/&/g, '&');
str = str.replace(/</g, '<');
str = str.replace(/>/g, '>');
str = str.replace(/•/g, '•');
return str;
}
// HTML 支持的其他实体
function strOtherDiscode(str) {
str = str.replace(/Œ/g, 'Œ');
str = str.replace(/œ/g, 'œ');
str = str.replace(/Š/g, 'Š');
str = str.replace(/š/g, 'š');
str = str.replace(/Ÿ/g, 'Ÿ');
str = str.replace(/ƒ/g, 'ƒ');
str = str.replace(/ˆ/g, 'ˆ');
str = str.replace(/˜/g, '˜');
str = str.replace(/ /g, '');
str = str.replace(/ /g, '');
str = str.replace(/ /g, '');
str = str.replace(/‌/g, '');
str = str.replace(/‍/g, '');
str = str.replace(/‎/g, '');
str = str.replace(/‏/g, '');
str = str.replace(/–/g, '–');
str = str.replace(/—/g, '—');
str = str.replace(/‘/g, '‘');
str = str.replace(/’/g, '’');
str = str.replace(/‚/g, '‚');
str = str.replace(/“/g, '“');
str = str.replace(/”/g, '”');
str = str.replace(/„/g, '„');
str = str.replace(/†/g, '†');
str = str.replace(/‡/g, '‡');
str = str.replace(/•/g, '•');
str = str.replace(/…/g, '…');
str = str.replace(/‰/g, '‰');
str = str.replace(/′/g, '′');
str = str.replace(/″/g, '″');
str = str.replace(/‹/g, '‹');
str = str.replace(/›/g, '›');
str = str.replace(/‾/g, '‾');
str = str.replace(/€/g, '€');
str = str.replace(/™/g, '™');
str = str.replace(/←/g, '←');
str = str.replace(/↑/g, '↑');
str = str.replace(/→/g, '→');
str = str.replace(/↓/g, '↓');
str = str.replace(/↔/g, '↔');
str = str.replace(/↵/g, '↵');
str = str.replace(/⌈/g, '⌈');
str = str.replace(/⌉/g, '⌉');
str = str.replace(/⌊/g, '⌊');
str = str.replace(/⌋/g, '⌋');
str = str.replace(/◊/g, '◊');
str = str.replace(/♠/g, '♠');
str = str.replace(/♣/g, '♣');
str = str.replace(/♥/g, '♥');
str = str.replace(/♦/g, '♦');
str = str.replace(/'/g, "'");
return str;
}
function strDiscode(str) {
str = strNumDiscode(str);
str = strGreeceDiscode(str);
str = strcharacterDiscode(str);
str = strOtherDiscode(str);
return str;
}
function urlToHttpUrl(url, domain) {
if (/^\/\//.test(url)) {
return `https:${url}`;
} else if (/^\//.test(url)) {
return `https://${domain}${url}`;
}
return url;
}
export default {
strDiscode,
urlToHttpUrl,
};
parse.css
/**
* author: Di (微信小程序开发工程师)
* organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
* 垂直微信小程序开发交流社区
*
* github地址: https://github.com/icindy/wxParse
*
* for: 微信小程序富文本解析
* detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
*/
/**
* 请在全局下引入该文件,@import '/static/wxParse.css';
*/
.wxParse {
user-select:none;
width: 100%;
font-family: Helvetica, "PingFangSC", 'Microsoft Yahei', '微软雅黑', Arial, sans-serif;
color: #333;
line-height: 1.5;
font-size: 1em;
text-align:justify;/* //左右两端对齐 */
word-wrap: break-word;/*超出自动换行*/
}
.wxParse view ,.wxParse uni-view{
word-break: break-word;
}
.wxParse .p {
padding-bottom: 1em;
clear: both;
/* letter-spacing: 0;//字间距 */
}
.wxParse .inline {
display: inline;
margin: 0;
padding: 0;
}
.wxParse .div {
margin: 0;
padding: 0;
display: block;
}
.wxParse .h1{
font-size: 2em;
line-height: 1.2em;
margin: 0.67em 0;
}
.wxParse .h2{
font-size: 1.5em;
margin: 0.83em 0;
}
.wxParse .h3{
font-size: 1.17em;
margin: 1em 0;
}
.wxParse .h4{
margin: 1.33em 0;
}
.wxParse .h5{
font-size: 0.83em;
margin: 1.67em 0;
}
.wxParse .h6{
font-size: 0.83em;
margin: 1.67em 0;
}
.wxParse .h1,
.wxParse .h2,
.wxParse .h3,
.wxParse .h4,
.wxParse .h5,
.wxParse .h6,
.wxParse .b,
.wxParse .strong{
font-weight: bolder;
}
.wxParse .i,
.wxParse .cite,
.wxParse .em,
.wxParse .var,
.wxParse .address {
font-style: italic;
}
.wxParse .pre,
.wxParse .tt,
.wxParse .code,
.wxParse .kbd,
.wxParse .samp {
font-family: monospace;
}
.wxParse .pre {
overflow: auto;
background: #f5f5f5;
padding: 16upx;
white-space: pre;
margin: 1em 0upx;
}
.wxParse .code {
display: inline;
background: #f5f5f5;
}
.wxParse .big {
font-size: 1.17em;
}
.wxParse .small,
.wxParse .sub,
.wxParse .sup {
font-size: 0.83em;
}
.wxParse .sub {
vertical-align: sub;
}
.wxParse .sup {
vertical-align: super;
}
.wxParse .s,
.wxParse .strike,
.wxParse .del {
text-decoration: line-through;
}
.wxParse .strong,
.wxParse .s {
display: inline;
}
.wxParse .a {
color: deepskyblue;
}
.wxParse .video {
text-align: center;
margin: 22upx 0;
}
.wxParse .video-video {
width: 100%;
}
.wxParse .uni-image{
max-width: 100%;
}
.wxParse .img {
display: block;
max-width: 100%;
margin-bottom: -1em;/* //与p标签底部padding同时修改 */
overflow: hidden;
}
.wxParse .blockquote {
margin: 10upx 0;
padding: 22upx 0 22upx 22upx;
font-family: Courier, Calibri, "宋体";
background: #f5f5f5;
border-left: 6upx solid #dbdbdb;
}
.wxParse .blockquote .p {
margin: 0;
}
.wxParse .ul, .wxParse .ol {
display: block;
margin: 1em 0;
padding-left: 2em;
}
.wxParse .ol {
list-style-type: disc;
}
.wxParse .ol {
list-style-type: decimal;
}
.wxParse .ol>weixin-parse-template,.wxParse .ul>weixin-parse-template {
display: list-item;
align-items: baseline;
text-align: match-parent;
}
.wxParse .ol>.li,.wxParse .ul>.li {
display: list-item;
align-items: baseline;
text-align: match-parent;
}
.wxParse .ul .ul, .wxParse .ol .ul {
list-style-type: circle;
}
.wxParse .ol .ol .ul, .wxParse .ol .ul .ul, .wxParse .ul .ol .ul, .wxParse .ul .ul .ul {
list-style-type: square;
}
.wxParse .u {
text-decoration: underline;
}
.wxParse .hide {
display: none;
}
.wxParse .del {
display: inline;
}
.wxParse .figure {
overflow: hidden;
}
.wxParse .table {
border-collapse:collapse;
box-sizing: border-box;
/* 内边框 */
border: 1px solid #dadada;
width: 100%;
}
.wxParse .tbody{
border-collapse:collapse;
box-sizing: border-box;
/* 内边框 */
border: 1px solid #dadada;
}
.wxParse .thead, .wxParse .tfoot, .wxParse .th{
border-collapse:collapse;
box-sizing: border-box;
background: #ececec;
font-weight: 40;
}
.wxParse .tr {
border-collapse:collapse;
box-sizing: border-box;
/* border: 2px solid #F0AD4E; */
overflow:auto;
}
.wxParse .th,
.wxParse .td{
border-collapse:collapse;
box-sizing: border-box;
border: 2upx solid #dadada;
overflow:auto;
}
.wxParse .audio, .wxParse .uni-audio-default{
display: block;
}
.textarea ._div{
background-color:#fff !important;
}
parse.vue
<!--**
* forked from:https://github.com/F-loat/mpvue-wxParse
*
* github地址: https://github.com/dcloudio/uParse
*
* for: uni-app框架下 富文本解析
*
* 优化 by gaoyia@qq.com https://github.com/gaoyia/parse
*/-->
<template>
<!--基础元素-->
<div class="wxParse" :class="className" :style="'user-select:' + userSelect">
<block v-for="(node, index) of nodes" :key="index" v-if="!loading">
<wxParseTemplate :node="node" />
</block>
</div>
</template>
<script>
import HtmlToJson from './libs/html2json';
import wxParseTemplate from './components/wxParseTemplate0';
export default {
name: 'wxParse',
props: {
// user-select:none;
userSelect: {
type: String,
default: 'text' //none |text| all | element
},
imgOptions: {
type: [Object, Boolean],
default: function() {
return {
loop: false,
indicator: 'number',
longPressActions: false
// longPressActions: {
// itemList: ['发送给朋友', '保存图片', '收藏'],
// success: function (res) {
// console.log('选中了第' + (res.tapIndex + 1) + '个按钮');
// },
// fail: function (res) {
// console.log(res.errMsg);
// }
// }
// }
}
}
},
loading: {
type: Boolean,
default: false
},
className: {
type: String,
default: ''
},
content: {
type: String,
default: ''
},
noData: {
type: String,
default: '<div style="color: red;">数据不能为空</div>'
},
startHandler: {
type: Function,
default () {
return node => {
node.attr.class = null;
node.attr.style = null;
};
}
},
endHandler: {
type: Function,
default: null
},
charsHandler: {
type: Function,
default: null
},
imageProp: {
type: Object,
default () {
return {
mode: 'aspectFit',
padding: 0,
lazyLoad: false,
domain: ''
};
}
}
},
components: {
wxParseTemplate
},
data() {
return {
nodes: {},
imageUrls: [],
wxParseWidth: {
value: 0
}
};
},
computed: {},
mounted() {
let that = this
this.getWidth().then(function(data) {
that.wxParseWidth.value = data;
})
this.setHtml()
},
methods: {
setHtml() {
let {
content,
noData,
imageProp,
startHandler,
endHandler,
charsHandler
} = this;
let parseData = content || noData;
let customHandler = {
start: startHandler,
end: endHandler,
chars: charsHandler
};
let results = HtmlToJson(parseData, customHandler, imageProp, this);
this.imageUrls = results.imageUrls;
this.nodes = results.nodes;
},
getWidth() {
return new Promise((res, rej) => {
// #ifndef MP-ALIPAY || MP-BAIDU
var view = uni.createSelectorQuery().select(".content");
view.boundingClientRect(data => {
if(data.width){
res(data.width);
}else{
res('100%');
}
}).exec();
/* uni.createSelectorQuery()
.in(this)
.select('.wxParse')
.fields({size: true,scrollOffset: true},data => {
console.log(data);
//res(data.width);
}
).exec(); */
// #endif
// #ifdef MP-BAIDU
swan.createSelectorQuery().select('.wxParse').boundingClientRect(function(rect) {
rect[0].width
}).exec()
// #endif
// #ifdef MP-ALIPAY
my.createSelectorQuery()
.select('.wxParse')
.boundingClientRect().exec((ret) => {
res(ret[0].width);
});
// #endif
});
},
navigate(href, $event) {
this.$emit('navigate', href, $event);
},
preview(src, $event) {
if (!this.imageUrls.length || typeof this.imgOptions === 'boolean') {
} else {
uni.previewImage({
current: src,
urls: this.imageUrls,
loop: this.imgOptions.loop,
indicator: this.imgOptions.indicator,
longPressActions: this.imgOptions.longPressActions
});
}
this.$emit('preview', src, $event);
},
removeImageUrl(src) {
const {
imageUrls
} = this;
imageUrls.splice(imageUrls.indexOf(src), 1);
}
},
// 父组件中提供
provide() {
return {
parseWidth: this.wxParseWidth
// 提示:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的。
};
},
watch: {
content() {
this.setHtml()
}
}
};
</script>
jihai-copyright
jihaiCopyright.vue
<template>
<view class="cpr">
<view class="color-9">
吉海科技 © jihainet.com
</view>
<view class="color-9">
版权所有
</view>
</view>
</template>
<script>
</script>
<style>
.cpr{
text-align: center;
font-size: 24upx;
margin: 20upx 0;
}
</style>
jihai-lable.vue
<template>
<view>
<radio-group class="uni-list" @change="radioChange">
<label class="uni-list-cell uni-list-cell-pd" v-for="(item, index) in type_list" :key="index">
<view class="invoice-type-icon">
<radio class="a-radio" :id="item.name" :value="item.value" :checked="item.checked" :disabled="item.disabled"></radio>
</view>
<view class="invoice-type-c">
<label class="label-2-text" :for="item.name">
<text>{{item.name}}</text>
</label>
</view>
</label>
</radio-group>
</view>
</template>
<script>
export default {
data() {
return {
type_list: [
{ value: '1', name: '仅退款', checked: true, disabled: false },
{ value: '2', name: '退货退款', checked: false, disabled:false },
],
};
},
methods:{
radioChange: function(evt) {
this.type_list.forEach(item => {
if (item.value === evt.target.value) {
item.checked = true;
this.aftersale_type = evt.target.value;
}else{
item.checked = false;
}
});
if(this.type_list[0].checked){
this.refund_input_noedit = true;
}else{
this.refund_input_noedit = false;
}
},
}
}
</script>
<style>
</style>
jshop
image
jshop-article.vue
<template>
<view class='index-article cell-group bottom-cell-group' v-if="data.params.list && data.params.list.length > 0">
<view class='cell-item'
v-for="item in data.params.list"
:key="item.id"
@click="articleDetail(item.id)"
>
<view class="cell-item-bd">
<view class="article-title ">
{{ item.title }}
</view>
<view class="article-time">
{{ item.ctime }}
</view>
</view>
<view class="cell-title-img">
<image :src="item.cover" mode="aspectFill"></image>
</view>
</view>
</view>
</template>
<script>
export default {
name: "jshoparticle",
props: {
data:{
// type: Array,
required: true,
}
},
methods: {
// 查看文章详情
articleDetail (articleId) {
this.$common.navigateTo('/pages/article/index?id=' + articleId+'&id_type=1')
}
}
}
</script>
<style>
.index-article .cell-title-img{
width: 160upx;
height: 160upx;
float: right;
}
.index-article .cell-title-img image{
width: 100%;
height: 100%;
}
.index-article .cell-item-bd{
padding-right: 0;
vertical-align: top;
position: relative;
}
.index-article .article-title{
font-size: 28upx;
color: #333;
width: 100%;
min-height: 80upx;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
.index-article .article-time{
font-size: 24upx;
color: #999;
display: inline-block;
min-width: 220upx;
min-height: 32upx;
position: absolute;
bottom: 0;
}
</style>
jshop-articleClassify.vue
<template>
<view class='index-article cell-group bottom-cell-group' v-if="data.params.list && data.params.list.length > 0">
<view class='cell-item'
v-for="item in data.params.list"
:key="item.id"
@click="articleDetail(item.id)"
>
<view class="cell-item-bd">
<view class="article-title ">
{{ item.title }}
</view>
<view class="article-time">
{{ item.ctime }}
</view>
</view>
<view class="cell-title-img">
<image :src="item.cover" mode="aspectFill"></image>
</view>
</view>
</view>
</template>
<script>
export default {
name: "jshoparticleclassify",
props: {
data:{
// type: Array,
required: true,
}
},
methods: {
// 查看文章详情
articleDetail (articleId) {
this.$common.navigateTo('/pages/article/index?id=' + articleId+'&id_type=1')
}
}
}
</script>
<style>
.index-article .cell-title-img{
width: 160upx;
height: 160upx;
float: right;
}
.index-article .cell-title-img image{
width: 100%;
height: 100%;
}
.index-article .cell-item-bd{
padding-right: 0;
vertical-align: top;
position: relative;
}
.index-article .article-title{
font-size: 28upx;
color: #333;
width: 100%;
min-height: 80upx;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
.index-article .article-time{
font-size: 24upx;
color: #999;
display: inline-block;
min-width: 220upx;
min-height: 32upx;
position: absolute;
bottom: 0;
}
</style>
jshop-blank.vue
<template>
<view class="blank" :style="{background:data.params.backgroundColor,height:data.params.height*2+'rpx'}"></view>
</template>
<script>
export default {
name: "jshopblank",
props: {
data:{
// type: Array,
required: true,
}
},
methods: {
}
}
</script>
<style>
</style>
jshop-content.vue
<template>
<view class="content">
<u-parse :content="content" @preview="preview" @navigate="navigate" />
</view>
</template>
<script>
//视频和文本解析组件
import uParse from '@/components/gaoyia-parse/parse.vue'
export default {
name: 'jshop-content',
components: {
uParse
},
props: {
content: {}
},
created() {},
methods: {
preview(src, e) {
// do something
},
navigate(href, e) {
// do something
}
}
}
</script>
jshop-coupon.vue
<template>
<view class="coupon bottom-cell-group" v-if="data.params.list.length > 0">
<view class="coupon-item" v-for="item in data.params.list" :key="item.id" @click="receiveCoupon(item.id)">
<view class="coupon-i-l">
<view class="coupon-i-l-t">
<image class="icon" src="/static/image/element-ic.png" mode=""></image>
<text>{{ item.name }}</text>
</view>
<view class="coupon-i-l-b">
{{ item.expression1 + item.expression2 }}
</view>
</view>
<view class="coupon-i-r">
<image class="coupon-logo" src="/static/image/coupon-element.png" mode=""></image>
</view>
</view>
</view>
</template>
<script>
export default {
name: "jshopcoupon",
props: {
data:{
// type: Array,
required: true,
}
},
methods: {
// 用户领取优惠券
receiveCoupon(couponId) {
let data = {
promotion_id: couponId
}
this.$api.getCoupon(data, res => {
if (res.status) {
this.$common.successToShow(res.msg)
} else {
this.$common.errorToShow(res.msg)
}
})
},
}
}
</script>
<style>
.coupon {
padding: 0 26upx;
background-color: #f8f8f8;
}
.coupon-item {
padding: 20upx;
margin-bottom: 20upx;
background-color: #fff;
}
.coupon-i-l {
width: 400upx;
display: inline-block;
}
.coupon-i-l-t {
font-size: 32upx;
position: relative;
margin-bottom: 10upx;
}
.coupon-i-l-t .icon {
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.coupon-i-l-t text {
margin-left: 60upx;
}
.coupon-i-l-b {
font-size: 24upx;
color: #999;
}
.coupon-i-r {
width: 258upx;
display: inline-block;
text-align: center;
}
.coupon-logo {
width: 130upx;
height: 100upx;
}
</style>
jshop-goods.vue
<template>
<view class="index-goods">
<!-- 列表平铺两列三列 -->
<view class='img-grids bottom-cell-group'
v-if="data.params.column == '2' && data.params.display == 'list' || data.params.column == '3' && data.params.display == 'list'"
v-bind:class="'column'+data.params.column">
<view class='cell-item right-img' v-if="data.params.title != ''">
<view class='cell-item-hd'>
<view class='cell-hd-title'>{{data.params.title}}</view>
</view>
<view class='cell-item-bd'>
</view>
<view class='cell-item-ft' v-if="data.params.lookMore == 'true'">
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
<text class='cell-ft-text' @click="goodsList({cat_id: data.params.classifyId,brand_id:data.params.brandId})">查看更多</text>
</view>
</view>
<!-- <view class='img-grids'> -->
<view class="" v-if="data.params.list.length">
<view class="img-grids-item" v-for="item in data.params.list" :key="item.id" @click="goodsDetail(item.id)">
<image
class="img-grids-item-t have-none"
:src="item.image_url"
mode='aspectFill'
></image>
<view class="img-grids-item-b">
<view class="goods-name grids-goods-name">
{{item.name}}
</view>
<view class="goods-item-c">
<view class="goods-price red-price">¥{{item.price}}</view>
</view>
</view>
</view>
</view>
<view v-else-if="!data.params.list.length && !data.params.listAjax">
<view class='img-grids-item'>
<image class='img-grids-item-t have-none' src='' mode=''></image>
<view class='img-grids-item-b'>
<view class='goods-name grids-goods-name have-none'></view>
<view class='goods-item-c'>
<view class='goods-price red-price have-none'></view>
</view>
</view>
</view>
<view class='img-grids-item'>
<image class='img-grids-item-t have-none' src='' mode=''></image>
<view class='img-grids-item-b'>
<view class='goods-name grids-goods-name have-none'></view>
<view class='goods-item-c'>
<view class='goods-price red-price have-none'></view>
</view>
</view>
</view>
<view class='img-grids-item'>
<image class='img-grids-item-t have-none' src='' mode=''></image>
<view class='img-grids-item-b'>
<view class='goods-name grids-goods-name have-none'></view>
<view class='goods-item-c'>
<view class='goods-price red-price have-none'></view>
</view>
</view>
</view>
</view>
<!-- <view v-else="">
<scroll-view class='swiper-list' scroll-x="true"></scroll-view>
</view> -->
<!-- </view> -->
</view>
<!-- 列表平铺单列 -->
<view class="img-list bottom-cell-group"
v-if="data.params.column == '1' && data.params.display == 'list'" >
<view class='cell-item right-img' v-if="data.params.title != ''">
<view class='cell-item-hd'>
<view class='cell-hd-title'>{{data.params.title}}</view>
</view>
<view class='cell-item-bd'>
</view>
<view class='cell-item-ft' v-if="data.params.lookMore == 'true'">
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
<text class='cell-ft-text' @click="goodsList({cat_id: data.params.classifyId,brand_id:data.params.brandId})">查看更多</text>
</view>
</view>
<view v-if="data.params.list.length>0">
<view class="img-list-item" v-for="(item, index) in data.params.list" :key="index" @click="goodsDetail(item.id)">
<image class="img-list-item-l have-none" :src="item.image_url" mode='aspectFill'></image>
<view class="img-list-item-r">
<view class="goods-name list-goods-name">
{{item.name}}
</view>
<view class="goods-item-c">
<view class="goods-price red-price">¥{{item.price}}</view>
<view class="goods-buy">
<view class="goods-salesvolume" v-if="item.comments_count > 0">{{item.comments_count}}条评论</view>
<view class="goods-salesvolume" v-else-if="item.comments_count <= 0">暂无评论</view>
<image class="goods-cart" src="/static/image/ic-car.png"></image>
</view>
</view>
</view>
</view>
</view>
<view class="order-none" v-else>
<image class="order-none-img" src="/static/image/order.png" mode=""></image>
</view>
</view>
<!-- 横向滚动 -->
<view class='img-grids bottom-cell-group'
v-if="data.params.column == '2' && data.params.display == 'slide' || data.params.column == '3' && data.params.display == 'slide'"
v-bind:class="'slide'+data.params.column">
<view class='cell-item right-img' v-if="data.params.title != ''">
<view class='cell-item-hd'>
<view class='cell-hd-title'>{{data.params.title}}</view>
</view>
<view class='cell-item-bd'>
</view>
<view class='cell-item-ft' v-if="data.params.lookMore == 'true'">
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
<text class='cell-ft-text' @click="goodsList({cat_id: data.params.classifyId,brand_id:data.params.brandId})">查看更多</text>
</view>
</view>
<view class='swiper-grids'>
<scroll-view class='swiper-list' scroll-x="true" v-if="data.params.list.length">
<view class='img-grids-item' v-for="item in data.params.list" :key="item.id" @click="goodsDetail(item.id)">
<image class='img-grids-item-t have-none' :src='item.image_url' mode='aspectFill'></image>
<view class='img-grids-item-b'>
<view class='goods-name grids-goods-name'>{{ item.name }}</view>
<view class='goods-item-c'>
<view class='goods-price red-price'>¥{{ item.price }}</view>
</view>
</view>
</view>
</scroll-view>
<view v-else-if="!goodsListOfHotAjax && !goodsListOfHot.length">
<scroll-view class='swiper-list' scroll-x="true">
<view class='img-grids-item'>
<image class='img-grids-item-t have-none' src='' mode='aspectFill'></image>
<view class='img-grids-item-b'>
<view class='goods-name grids-goods-name have-none'></view>
<view class='goods-item-c'>
<view class='goods-price red-price have-none'></view>
</view>
</view>
</view>
<view class='img-grids-item'>
<image class='img-grids-item-t have-none' src='' mode='aspectFill'></image>
<view class='img-grids-item-b'>
<view class='goods-name grids-goods-name have-none'></view>
<view class='goods-item-c'>
<view class='goods-price red-price have-none'></view>
</view>
</view>
</view>
<view class='img-grids-item'>
<image class='img-grids-item-t have-none' src='' mode=''></image>
<view class='img-grids-item-b'>
<view class='goods-name grids-goods-name have-none'></view>
<view class='goods-item-c'>
<view class='goods-price red-price have-none'></view>
</view>
</view>
</view>
</scroll-view>
</view>
<view v-else="">
<scroll-view class='swiper-list' scroll-x="true"></scroll-view>
</view>
</view>
</view>
</view>
</template>
<script>
import {goods} from '@/config/mixins.js'
export default {
mixins: [goods],
name: "jshopgoods",
props: {
data:{
// type: Array,
required: true,
}
},
methods: {
//跳转到商品详情页面
goodsDetail: function(id) {
let url = '/pages/goods/index/index?id=' + id;
this.$common.navigateTo(url);
},
},
}
</script>
<style>
.cell-item {
border: none;
/* padding-bottom: 0; */
}
.cell-ft-text {
font-size: 22upx;
color: #999;
}
.img-grids,.img-list{
/* margin-top: 20upx; */
background-color: #fff;
}
.img-grids-item{
display: inline-table;
margin-top: 0;
margin-bottom: 14upx;
}
.column3 .img-grids-item{
width: 230upx;
margin: 15upx;
margin-right: 0;
margin-top: 0;
margin-bottom: 6upx;
}
.column3 .img-grids-item:nth-child(3n){
margin-right: 15upx;
}
.column3 .img-grids-item-t{
width: 230upx;
height: 230upx;
}
.column3 .grids-goods-name{
font-size: 24upx;
height: 68upx;
}
.column3 .img-grids-item-b{
padding: 0 8upx 8upx;
}
.column3 .goods-price{
font-size: 26upx;
}
.slide3 .img-grids-item{
width: 200upx;
}
.slide3 .img-grids-item-t{
width: 200upx;
height: 200upx;
}
.slide3 .grids-goods-name{
font-size: 24upx;
}
.index-goods .img-grids-item{
display: inline-block;
margin-top: 0;
}
.index-goods .img-list-item{
padding: 0upx 26upx;
margin-bottom: 14upx;
}
.index-goods .img-list{
padding-bottom: 10upx;
}
</style>
jshop-groupPurchase.vue
<template>
<!-- 团购秒杀 -->
<view class="img-list bottom-cell-group group-buying" v-if="data.params.list && data.params.list.length > 0">
<view class='cell-item right-img'>
<view class='cell-item-hd group-title'>
{{data.params.title}}
<!-- <view class='cell-hd-title'></view> -->
</view>
</view>
<view class='swiper-grids'>
<scroll-view class='swiper-list' scroll-x="true">
<view class="img-list-item" v-if="item.goods !== 'undefined' && item.goods" v-for="(item, key) in data.params.list"
:key="key">
<image class="img-list-item-l medium-img have-none" :src="item.goods.image_url" mode='aspectFill' @click="groupDetail(item.goods.id, item.goods.group_id)"></image>
<view class="img-list-item-r medium-right">
<view class="goods-name list-goods-name" @click="groupDetail(item.goods.id, item.goods.group_id)">{{item.goods.name}}</view>
<view class="goods-item-c">
<view class="goods-price red-price">¥{{item.goods.product.price}}</view>
<view class="goods-buy">
<view class="goods-salesvolume red-price" v-if="(item.goods.lasttime != '已经结束' || item.goods.lasttime != '即将开始') && item.goods.lasttime">剩余:<uni-countdown
:show-day="false" :hour="item.goods.lasttime.hour" :minute="item.goods.lasttime.minute" :second="item.goods.lasttime.second"></uni-countdown>
</view>
<view class="goods-salesvolume red-price" v-if="item.goods.lasttime == '已经结束'">已结束</view>
<view class="goods-salesvolume red-price" v-if="item.goods.lasttime == '即将开始'">即将开始</view>
<image class="goods-cart" src="/static/image/ic-car.png" @click="groupDetail(item.goods.id, item.goods.group_id)"></image>
</view>
</view>
</view>
</view>
</scroll-view>
</view>
</view>
</template>
<script>
import uniCountdown from "@/components/uni-countdown/uni-countdown.vue"
import {
goods
} from '@/config/mixins.js'
export default {
mixins: [goods],
components: {
uniCountdown
},
name: "jshopgrouppurchase",
props: {
data: {
// type: Array,
required: false,
}
},
methods: {
showSliderInfo(type, val) {
if (type == 1) {
if (val.indexOf('http') != -1) {
// #ifdef H5
window.location.href = val
// #endif
} else {
// #ifdef H5 || APP-PLUS || APP-PLUS-NVUE || MP
if (val == '/pages/classify/classify' || val == '/pages/cart/index/index' || val == '/pages/member/index/index') {
uni.switchTab({
url: val
});
return;
} else {
this.$common.navigateTo(val);
return;
}
// #endif
}
} else if (type == 2) {
// 商品详情
this.goodsDetail(val)
} else if (type == 3) {
// 文章详情
this.$common.navigateTo('/pages/article/index?id=' + val +'&id_type=1')
} else if (type == 4) {
// 文章列表
this.$common.navigateTo('/pages/article/list?cid=' + val)
} else if (type == 5) {
//智能表单
this.$common.navigateTo('/pages/form/detail/form?id=' + val)
}
},
//跳转到商品详情页面
// goodsDetail: function(id) {
// let url = '/pages/goods/index/index?id=' + id;
// this.$common.navigateTo(url);
// },
},
}
</script>
<style>
.img-list,
.img-grids {
background-color: #fff;
}
.cell-item {
border: none;
}
.group-buying .img-list-item {
min-height: 236upx;
padding: 20upx;
margin-left: 26upx;
margin-bottom: 26upx;
display: inline-table;
background-color: #f9f9f9;
}
.swiper-grids .img-list-item:last-child {
margin-right: 26upx;
}
/* .group-buying .goods-name{
min-height: 74upx;
} */
.group-buying .group-title {
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>
jshop-imgSingle.vue
<template>
<!-- 单图 -->
<view class="ad jshop-imgsingle" v-if="data.params.list && data.params.list.length > 0">
<view class="" v-for="item in data.params.list" :key="item.id">
<image class="ad-img" :src="item.image" mode="widthFix" @click="showSliderInfo(item.linkType, item.linkValue)"></image>
<view class="imgup-btn" v-if="item.buttonText != ''" @click="showSliderInfo(item.linkType, item.linkValue)">
<button class="btn btn-fillet" :style="{background:item.buttonColor,color:item.textColor}">{{item.buttonText}}</button>
</view>
</view>
</view>
</template>
<script>
export default {
name: "jshopimgsingle",
props: {
data: {
// type: Object,
required: true,
}
},
methods: {
showSliderInfo(type, val) {
if (!val) {
return;
}
if (type == 1) {
if (val.indexOf('http') != -1) {
// #ifdef H5
window.location.href = val
// #endif
} else {
// #ifdef H5 || APP-PLUS || APP-PLUS-NVUE || MP
if (val == '/pages/index/index' || val == '/pages/classify/classify' || val == '/pages/cart/index/index' || val == '/pages/member/index/index') {
uni.switchTab({
url: val
});
return;
} else {
this.$common.navigateTo(val);
return;
}
// #endif
}
} else if (type == 2) {
// 商品详情
this.goodsDetail(val)
} else if (type == 3) {
// 文章详情
this.$common.navigateTo('/pages/article/index?id=' + val + '&id_type=1')
} else if (type == 4) {
// 文章列表
this.$common.navigateTo('/pages/article/list?cid=' + val)
} else if (type == 5) {
//智能表单
this.$common.navigateTo('/pages/form/detail/form?id=' + val)
}
},
//跳转到商品详情页面
goodsDetail: function(id) {
// let ins = encodeURIComponent('id='+id);
let url = '/pages/goods/index/index?id=' + id;
this.$common.navigateTo(url);
},
},
}
</script>
<style>
/* .ad {
width: 100%;
overflow: hidden;
}
.ad-img{
width: 100%;
float: left;
margin-bottom: 20upx;
}
.ad-img:last-child{
margin-bottom: 0;
} */
.jshop-imgsingle.ad {
width: 100%;
overflow: hidden;
position: relative;
}
.jshop-imgsingle .ad-img {
width: 100%;
float: left;
position: relative;
z-index: 667;
/* margin-bottom: 20upx; */
}
.jshop-imgsingle .ad-img:last-child {
margin-bottom: 0;
}
.jshop-imgsingle .imgup-btn {
position: absolute;
z-index: 668;
bottom: 80upx;
left: 40upx;
}
.jshop-imgsingle .imgup-btn .btn {
line-height: 2;
font-size: 28upx;
padding: 0 50upx;
}
</style>
jshop-imgSlide.vue
<template>
<view class='swiper bottom-cell-group' v-if="data.params.list && data.params.list.length > 0">
<swiper class="swiper-c" :indicator-dots="swiper.indicatorDots" :autoplay="swiper.autoplay" :interval="data.params.duration"
:duration="swiper.duration">
<swiper-item class="have-none" v-for="(item, index) in data.params.list" :key="index">
<image class='' :src="item.image" @click="showSliderInfo(item.linkType, item.linkValue)" mode="aspectFill"></image>
</swiper-item>
</swiper>
</view>
</template>
<script>
export default {
name: "jshopimgSlide",
props: {
data: {
// type: Object,
required: true,
}
},
data() {
return {
swiper: {
indicatorDots: true,
autoplay: true,
// interval: 2000,
duration: 500,
},
};
},
created() {},
watch: {},
methods: {
// 广告点击查看详情
showSliderInfo(type, val) {
if (!val) {
return;
}
if (type == 1) {
if (val.indexOf('http') != -1) {
// #ifdef H5
window.location.href = val
// #endif
} else {
// #ifdef H5 || APP-PLUS || APP-PLUS-NVUE || MP
if (val == '/pages/index/index' || val == '/pages/classify/classify' || val == '/pages/cart/index/index' || val == '/pages/member/index/index') {
uni.switchTab({
url: val
});
return;
} else {
this.$common.navigateTo(val);
return;
}
// #endif
}
} else if (type == 2) {
// 商品详情
this.goodsDetail(val)
} else if (type == 3) {
// 文章详情
this.$common.navigateTo('/pages/article/index?id=' + val + '&id_type=1')
} else if (type == 4) {
// 文章列表
this.$common.navigateTo('/pages/article/list?cid=' + val)
} else if (type == 5) {
//智能表单
this.$common.navigateTo('/pages/form/detail/form?id=' + val)
}
},
//跳转到商品详情页面
goodsDetail: function(id) {
let url = '/pages/goods/index/index?id=' + id;
this.$common.navigateTo(url);
},
}
}
</script>
<style>
.swiper {
height: 340upx;
}
</style>
jshop-imgWindow.vue
<template>
<view class="imgwindow bottom-cell-group">
<view class="imgwindow-list" v-if="data.params.style == '2' ||data.params.style == '3' ||data.params.style == '4'"
v-bind:class="'row'+data.params.style" :style="{margin:-data.params.margin+'px'}">
<view class="imgwindow-item" ref="imgwitem" :style="{height:height+'px',padding:data.params.margin+'px'}" v-for="(item, index) in data.params.list"
:key="index">
<image :src="item.image" mode="aspectFill" @click="showSliderInfo(item.linkType, item.linkValue)"></image>
</view>
</view>
<view class="imgwindow-list" v-if="data.params.style == '0'" v-bind:class="'row'+data.params.style" :style="{margin:-data.params.margin+'px'}">
<view class="imgwindow-item" ref="imgwitem" :style="{height:height+'px',padding:data.params.margin+'px'}" v-for="(item, index) in data.params.list"
:key="index" v-if="index == 0">
<image :src="item.image" mode="aspectFill" @click="showSliderInfo(item.linkType, item.linkValue)"></image>
</view>
<view class="imgwindow-item" ref="imgwitem" :style="{height:height1+'px',padding:data.params.margin+'px'}" v-for="(item, index) in data.params.list"
:key="index" v-if="index !== 0">
<image :src="item.image" mode="aspectFill" @click="showSliderInfo(item.linkType, item.linkValue)"></image>
</view>
</view>
</view>
</template>
<script>
export default {
name: "jshopimgwindow",
props: {
data: {
// type: Object,
required: true,
}
},
data() {
return {
height: '',
height1: '',
padding: '3'
}
},
mounted() {
// #ifdef H5 || APP-PLUS || APP-PLUS-NVUE
var view = uni.createSelectorQuery().in(this).select(".imgwindow-item");
view.boundingClientRect(data => {
this.height = data.width;
// 橱窗小图高度
this.height1 = data.width / 2;
}).exec();
// #endif
// #ifdef MP-ALIPAY
var view = uni.createSelectorQuery().select(".content").boundingClientRect().exec(data => {
this.height1 = data[0].width / 4;
if (this.data.params.style == '3') {
this.height = data[0].width / 3;
} else if (this.data.params.style == '2') {
this.height = data[0].width / 2;
} else if (this.data.params.style == '4') {
this.height = data[0].width / 4;
} else if (this.data.params.style == '0') {
this.height = data[0].width / 2;
}
});
// #endif
// #ifdef MP-WEIXIN
var view = uni.createSelectorQuery().select(".content");
view.boundingClientRect(data => {
this.height1 = data.width / 4;
if (this.data.params.style == '3') {
this.height = data.width / 3;
} else if (this.data.params.style == '2') {
this.height = data.width / 2;
} else if (this.data.params.style == '4') {
this.height = data.width / 4;
} else if (this.data.params.style == '0') {
this.height = data.width / 2;
}
}).exec();
// #endif
},
methods: {
showSliderInfo(type, val) {
if (!val) {
return;
}
if (type == 1) {
if (val.indexOf('http') != -1) {
// #ifdef H5
window.location.href = val
// #endif
} else {
// #ifdef H5 || APP-PLUS || APP-PLUS-NVUE || MP
if (val == '/pages/index/index' || val == '/pages/classify/classify' || val == '/pages/cart/index/index' || val ==
'/pages/member/index/index') {
uni.switchTab({
url: val
});
return;
} else {
this.$common.navigateTo(val);
return;
}
// #endif
}
} else if (type == 2) {
// 商品详情
this.goodsDetail(val)
} else if (type == 3) {
// 文章详情
this.$common.navigateTo('/pages/article/index?id=' + val + '&id_type=1')
} else if (type == 4) {
// 文章列表
this.$common.navigateTo('/pages/article/list?cid=' + val)
} else if (type == 5) {
//智能表单
this.$common.navigateTo('/pages/form/detail/form?id=' + val)
}
},
//跳转到商品详情页面
goodsDetail: function(id) {
let url = '/pages/goods/index/index?id=' + id;
this.$common.navigateTo(url);
},
}
}
</script>
<style>
.imgwindow {
width: 100%;
}
.imgwindow-list {
overflow: hidden;
/* margin: -16upx; */
}
/* 堆积两列 */
.imgwindow-list .imgwindow-item {
height: auto;
float: left;
/* padding: 8upx; */
}
.imgwindow-list .imgwindow-item image {
width: 100%;
height: 100%;
}
.imgwindow-list.row0 .imgwindow-item:first-child {
width: 50%;
}
.imgwindow-list.row0 .imgwindow-item:nth-child(2) {
width: 50%;
}
.imgwindow-list.row0 .imgwindow-item:nth-child(3),
.imgwindow-list.row0 .imgwindow-item:nth-child(4) {
width: 25%;
}
.imgwindow-list.row2 .imgwindow-item {
width: 50%;
}
.imgwindow-list.row3 .imgwindow-item {
width: 33.3%;
}
.imgwindow-list.row4 .imgwindow-item {
width: 25%;
}
</style>
jshop-navBar.vue
<template>
<view class="imgnavbar bottom-cell-group">
<view class="imgnavbar-list" v-if="data.params.limit == '3' ||data.params.limit == '4' ||data.params.limit == '5'"
v-bind:class="'row'+data.params.limit">
<view class="imgnavbar-item" ref="imgwitem" v-for="(item, index) in data.params.list" :key="index">
<image class="imgnavbar-item-img" :src="item.image" mode="aspectFill" @click="showSliderInfo(item.linkType, item.linkValue)"></image>
<view class="imgnavbar-item-text">{{item.text}}</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: "jshopnavbar",
props: {
data: {
// type: Object,
required: true,
}
},
data() {
return {
height: '',
height1: ''
}
},
onLoad() {
},
mounted() {
},
methods: {
showSliderInfo(type, val) {
if (!val) {
return;
}
if (type == 1) {
if (val.indexOf('http') != -1) {
// #ifdef H5
window.location.href = val
// #endif
} else {
// #ifdef H5 || APP-PLUS || APP-PLUS-NVUE || MP
if (val == '/pages/index/index' || val == '/pages/classify/classify' || val == '/pages/cart/index/index' || val == '/pages/member/index/index') {
uni.switchTab({
url: val
});
return;
} else {
this.$common.navigateTo(val);
return;
}
// #endif
}
} else if (type == 2) {
// 商品详情
this.goodsDetail(val)
} else if (type == 3) {
// 文章详情
this.$common.navigateTo('/pages/article/index?id=' + val + '&id_type=1')
} else if (type == 4) {
// 文章列表
this.$common.navigateTo('/pages/article/list?cid=' + val)
} else if (type == 5) {
//智能表单
this.$common.navigateTo('/pages/form/detail/form?id=' + val)
}
},
//跳转到商品详情页面
goodsDetail: function(id) {
let url = '/pages/goods/index/index?id=' + id;
this.$common.navigateTo(url);
},
}
}
</script>
<style>
.imgnavbar {
width: 100%;
background-color: #fff;
}
.imgnavbar-list {
overflow: hidden;
padding: 24upx 0 0;
}
/* 堆积两列 */
.imgnavbar-list .imgnavbar-item {
height: auto;
float: left;
padding: 0upx 10upx;
margin-bottom: 20upx;
text-align: center;
}
.imgnavbar-list .imgnavbar-item image {
width: 90upx;
height: 90upx;
margin-bottom: 6upx;
}
.imgnavbar-item-text {
font-size: 26upx;
color: #666;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.imgnavbar-list.row3 .imgnavbar-item {
width: 33.3%;
}
.imgnavbar-list.row4 .imgnavbar-item {
width: 25%;
}
.imgnavbar-list.row5 .imgnavbar-item {
width: 20%;
}
.imgnavbar-list.row5 .imgnavbar-item .imgnavbar-item-text {
font-size: 24upx;
}
</style>
jshop-notice.vue
<template>
<view class="notice bottom-cell-group" v-if="data.params.list && data.params.list.length > 0">
<view class="notice-icon">
<image class="icon news-icon" src="/static/image/news.png" mode=""></image>
</view>
<swiper class="notice-c" :indicator-dots="false" :autoplay="true" :interval="3000" :duration="1000" :vertical="true" :circular="true">
<swiper-item v-for="item in data.params.list" :key="item.id">
<view class="swiper-item" @click="goNotice(item.id)">{{ item.title }}</view>
</swiper-item>
</swiper>
</view>
</template>
<script>
export default {
name: "jshopnotice",
props: {
data:{
// type: Object,
required: true,
}
},
methods: {
// 点击公告
goNotice(id) {
// 文章详情
this.$common.navigateTo('/pages/article/index?id=' + id+'&id_type=2')
},
},
}
</script>
<style>
.notice {
padding: 6upx 26upx 6upx 60upx;
position: relative;
overflow: hidden;
background-color: #fff;
color: #333;
}
.notice-icon {
display: inline-block;
height: 40upx;
position: absolute;
top: 59%;
left: 26upx;
transform: translateY(-50%);
overflow: hidden;
}
.news-icon {
width: 30upx;
height: 30upx;
float: left;
}
.notice-c {
margin-left: 10upx;
height: 50upx;
line-height: 50upx;
width: 630upx;
display: inline-block;
font-size: 28upx;
float: left;
}
</style>
jshop-pintuan.vue
<template>
<!-- 拼团 -->
<view class="img-list bottom-cell-group group-buying" v-if="data.params.list && data.params.list.length > 0">
<view class='cell-item right-img'>
<view class='cell-item-hd group-title'>
{{data.params.title}}
</view>
</view>
<view class='swiper-grids' >
<scroll-view class='swiper-list' scroll-x="true">
<view class="img-list-item" v-if="item.goods_id !== 'undefined' && item.goods_id" v-for="(item, key) in data.params.list" :key="key">
<image class="img-list-item-l medium-img have-none" :src="item.goods_image" mode='aspectFill' @click="pintuanDetail(item.goods_id)"></image>
<view class="img-list-item-r medium-right">
<view class="goods-name list-goods-name" @click="pintuanDetail(item.goods_id)">{{item.goods_name}}</view>
<view class="goods-item-c">
<view class="goods-price red-price">¥{{item.pintuan_price}}</view>
<view class="goods-buy">
<view class="goods-salesvolume red-price" v-if="(item.pintuan_start_status == 1) && item.lasttime">剩余:<uni-countdown :show-day="false" :hour="item.lasttime.hour" :minute="item.lasttime.minute" :second="item.lasttime.second"></uni-countdown></view>
<view class="goods-salesvolume red-price" v-if="item.pintuan_start_status == 3">已结束</view>
<view class="goods-salesvolume red-price" v-if="item.pintuan_start_status == 2">即将开团</view>
<image class="goods-cart" src="/static/image/ic-car.png" @click="pintuanDetail(item.goods.id)"></image>
</view>
</view>
</view>
</view>
</scroll-view>
</view>
</view>
</template>
<script>
import uniCountdown from "@/components/uni-countdown/uni-countdown.vue"
import {goods} from '@/config/mixins.js'
export default {
mixins: [goods],
components:{uniCountdown},
name: "jshoppintuan",
props: {
data:{
// type: Array,
required: false,
}
},
methods: {
},
}
</script>
<style>
.img-list, .img-grids {
background-color: #fff;
}
.cell-item{
border: none;
}
.group-buying .img-list-item{
min-height: 236upx;
padding: 20upx;
margin-left: 26upx;
margin-bottom: 26upx;
display: inline-table;
background-color: #f9f9f9;
}
.swiper-grids .img-list-item:last-child{
margin-right: 26upx;
}
/* .group-buying .goods-name{
min-height: 74upx;
} */
.group-buying .group-title{
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>
jshop-record.vue
<template>
<view class="adbrathing"
v-show="adbshow"
v-bind:class="['adbrathing'+data.params.style.align,!hideanimation?'pc':hideanimation?'hc':'']"
:style="{top:data.params.style.top+'%'}" >
<view class="adbrathing-c">
<view class="adbrathing-l">
<image class="user-head-img" :src="log.avatar" mode="aspectFill"></image>
<view class="user-name">
{{log.nickname}}
</view>
</view>
<view class="adbrathing-r">
{{log.ctime}}{{log.desc}}
</view>
</view>
</view>
</template>
<script>
import { apiBaseUrl } from '@/config/config.js';
export default {
name: "jshoprecord",
props: {
data:{
// type: Object,
required: true,
},
//记录显示的位置类型
ltype:{
type: String,
required: false,
default:'home',
},
//记录显示的位置的值
lvalue:{
type: String,
required: false,
default:'0',
}
},
data() {
return {
adbshow:false,
hideanimation: true,
log:{
avatar:'/static/demo-img/user-head.jpg',
nickname:'',
desc:'',
ctime:'',
},
times:{},//定时器
};
},
methods:{
//隐藏
hideLog(){
var _this = this;
_this.times = setInterval(function(){
_this.adbshow = !_this.adbshow;
_this.hideanimation = !_this.hideanimation;
clearInterval(_this.times);
_this.times = setInterval(function(){
_this.getRecod();
},5000);
},3000)
},
//获取日志
getRecod(){
var _this = this;
if(_this.times !={}){
clearInterval(_this.times);
}
var data = {
type:_this.ltype,
value:_this.lvalue,
method:'pages.getrecod',
};
uni.request({
url: apiBaseUrl+'api.html',
data: data,
header: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
method: 'POST',
success: (response) => {
var res = response.data;
if(res.status == true){
if(res.data){
_this.log = res.data;
_this.adbshow = true;
_this.hideanimation = false;
_this.hideLog();
}
}
}
});
}
},
mounted() {
this.getRecod();
}
}
</script>
<style lang="scss">
.adbrathing{
position: fixed;
// top: 100px;
// right: 30upx;
// max-width: 400upx;
height: 70upx;
background-color: rgba(0,0,0,.5);
border-radius: 10upx;
padding: 10upx;
z-index: 666;
.adbrathing-c{
width: 100%;
height: 100%;
overflow: hidden;
color: #fff;
font-size: 24upx;
.adbrathing-l{
display: inline-block;
height: 100%;
float: left;
overflow: hidden;
.user-head-img{
width: 50upx;
height: 50upx;
border-radius: 50%;
float: left;
}
.user-name{
float: left;
display: inline-block;
height: 100%;
line-height: 50upx;
margin: 0 4upx 0 10upx;
max-width: 120upx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.adbrathing-r{
float: left;
height: 100%;
display: inline-block;
line-height: 50upx;
}
}
}
.adbrathingleft{
left: 30upx
}
.adbrathingright{
right: 30upx
}
.pc{
animation: showcenter .55s;
}
.hc{
animation: hidecenter .55s;
}
@keyframes showcenter{
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes hidecenter{
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
</style>
jshop-search.vue
<template>
<view class="" >
<!-- 搜索框 -->
<view class="search" ref="searchBar" id="search">
<view class='search-c' @click='goSearch()'>
<view class='search-input search-input-p' v-bind:class="data.params.style">
<view class="search-input-p-c">
{{data.params.keywords}}
</view>
</view>
<image class='icon search-icon' src='/static/image/zoom.png'></image>
</view>
</view>
<!-- 搜索框 -->
<view class="search search-fixed" v-show="searchFixed">
<view class='search-c' @click='goSearch()'>
<view class='search-input search-input-p' v-bind:class="data.params.style">
<view class="search-input-p-c">
{{data.params.keywords}}
</view>
</view>
<image class='icon search-icon' src='/static/image/zoom.png'></image>
</view>
</view>
</view>
</template>
<script>
export default {
name: "jshopsearch",
props: {
data:{
// type: Object,
required: true,
}
},
data() {
return {
keyword:'',
searchTop: 0,
scrollTop: 0,
searchFixed: false
};
},
onLoad() {
},
created() {
//#ifdef H5
this.$nextTick(() => {
this.searchTop = this.$refs.searchBar.$el.offsetTop;
})
// #endif
this.searchStyle()
},
mounted() {
// #ifdef H5
window.addEventListener('scroll', this.handleScroll)
// #endif
},
methods: {
searchStyle (){
this.$store.commit('searchStyle',this.data.params.style)
// console.log(this.data.params.style)
},
goSearch() {
uni.navigateTo({
url: '/pages/index/search'
});
},
handleScroll() {
this.scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
this.scrollTop >= this.searchTop? this.searchFixed = true : this.searchFixed = false;
},
},
onPageScroll(){
var _this = this;
// #ifdef MP-WEIXIN || APP-PLUS
const query = uni.createSelectorQuery().in(this)
query.select('.search').boundingClientRect(function(res){
if(res.top<0){
_this.searchFixed = true ;
}else{
_this.searchFixed = false;
}
}).exec()
// #endif
}
}
</script>
<style>
.search-input-p {
color: #888;
}
.square{
border-radius: 0;
}
.radius{
border-radius: 12upx;
}
.search-fixed{
position: fixed;
top: 0;
/* background: linear-gradient(rgba(0, 0, 0, .5), rgba(0, 0, 0, 0)); */
transition: all .5s;
}
/* .isOpacity {
background: linear-gradient(rgba(0, 0, 0, .5), rgba(0, 0, 0, 0));
transition: all .5s;
}
.isOpacity .search-input {
background-color: rgba(255, 255, 255, .5);
transition: all .5s;
} */
</style>
jshop-textarea.vue
<template>
<view class="textarea bottom-cell-group" >
<jshopContent :content="data.params" v-if="data.params"></jshopContent>
</view>
</template>
<script>
import htmlParser from '@/common/html-parser'
import jshopContent from '@/components/jshop/jshop-content.vue'//视频和文本解析组件
export default {
components: {
jshopContent
},
name: "jshoptextarea",
props: {
data:{
// type: Object,
required: true,
}
},
created() {
//this.data.params = htmlParser(this.data.params)
},
onLoad() {
},
methods: {
}
}
</script>
<style>
.textarea{
width: 100%;
background-color: #fff;
padding: 10upx 26upx;
/* height: 40upx; */
}
.textarea p img{
width: 100% !important;
}
.textarea div{
background-color: #000;
}
.textarea p {
background-color: #000;
}
</style>
jshop-video.vue
<template>
<view class="video bottom-cell-group" >
<video :src="data.params.list[0].url" :poster="data.params.list[0].image" controls :autoplay='data.params.autoplay'></video>
</view>
</template>
<script>
export default {
name: "jshopvideo",
props: {
data:{
type: Object,
required: true,
}
},
onLoad(){
},
methods: {
}
}
</script>
<style>
.video video{
width: 100%;
min-height: 200upx;
}
</style>
jshop.vue
<template>
<view>
<block v-for="(item,index) in data" :key="index">
<jshopsearch :data="item" v-if="item.widget_code=='search' "></jshopsearch>
<jshopnotice :data="item" v-if="item.widget_code=='notice' "></jshopnotice>
<jshopimgSlide :data="item" v-if="item.widget_code=='imgSlide' "></jshopimgSlide>
<jshopcoupon :data="item" v-if="item.widget_code=='coupon' "></jshopcoupon>
<jshopblank :data="item" v-if="item.widget_code=='blank' "></jshopblank>
<jshoptextarea :data="item" v-if="item.widget_code=='textarea' "></jshoptextarea>
<jshopvideo :data="item" v-if="item.widget_code=='video' "></jshopvideo>
<jshopimgWindow :data="item" v-if="item.widget_code=='imgWindow' "></jshopimgWindow>
<jshopimgSingle :data="item" v-if="item.widget_code=='imgSingle' "></jshopimgSingle>
<jshopgoods :data="item" v-if="item.widget_code=='goods' "></jshopgoods>
<jshoparticle :data="item" v-if="item.widget_code=='article' "></jshoparticle>
<jshoparticleClassify :data="item" v-if="item.widget_code=='articleClassify' "></jshoparticleClassify>
<jshopnavBar :data="item" v-if="item.widget_code=='navBar' "></jshopnavBar>
<jshopgroupPurchase :data="item" v-if="item.widget_code=='groupPurchase' "></jshopgroupPurchase>
<jshoprecord :data="item" v-if="item.widget_code=='record' "></jshoprecord>
<jshoppintuan :data="item" v-if="item.widget_code=='pintuan' "></jshoppintuan>
</block>
</view>
</template>
<script>
/**
* 吉海科技jshop小程序插件集合。
* author:novice
* date:2019:05:20
*/
import uniCountdown from '@/components/uni-countdown/uni-countdown.vue'
import jshopimgSlide from '@/components/jshop/jshop-imgSlide.vue'
import jshopsearch from '@/components/jshop/jshop-search.vue'
import jshopnotice from '@/components/jshop/jshop-notice.vue'
import jshopcoupon from '@/components/jshop/jshop-coupon.vue'
import jshopblank from '@/components/jshop/jshop-blank.vue'
import jshoptextarea from '@/components/jshop/jshop-textarea.vue'
import jshopvideo from '@/components/jshop/jshop-video.vue'
import jshopimgWindow from '@/components/jshop/jshop-imgWindow.vue'
import jshopimgSingle from '@/components/jshop/jshop-imgSingle.vue'
import jshopgoods from '@/components/jshop/jshop-goods.vue'
import jshoparticle from '@/components/jshop/jshop-article.vue'
import jshoparticleClassify from '@/components/jshop/jshop-articleClassify.vue'
import jshopnavBar from '@/components/jshop/jshop-navBar.vue'
import jshopgroupPurchase from '@/components/jshop/jshop-groupPurchase.vue'
import jshoprecord from '@/components/jshop/jshop-record.vue'
import jshoppintuan from '@/components/jshop/jshop-pintuan.vue'
export default {
name: 'jshop',
components: {
jshopimgSlide,
jshopsearch,
jshopnotice,
jshopcoupon,
jshopblank,
jshoptextarea,
jshopvideo,
jshopimgWindow,
jshopimgSingle,
jshopgoods,
jshoparticle,
jshoparticleClassify,
jshopnavBar,
jshopgroupPurchase,
jshoprecord,
jshoppintuan
},
props: {
data: {
default: function() {
return []
}
}
}
}
</script>
lvv-popup
lvv-popup.vue
<template>
<view class="lvv-popup" v-show="popshow" @touchmove.prevent>
<view class="lvv-popupmark" :class="position=='top'&&!hideanimation?'pt':position=='left'&&!hideanimation?'pl':position=='right'&&!hideanimation?'pr':position=='bottom'&&!hideanimation?'pc':position=='top'&&hideanimation?'ht':position=='left'&&hideanimation?'hl':position=='right'&&hideanimation?'hr':position=='bottom'&&hideanimation?'hc':''" @click="close"></view>
<view class="lvv-popupcontent" @click="close" :class="position=='top'&&!hideanimation?'pt':position=='left'&&!hideanimation?'pl':position=='right'&&!hideanimation?'pr':position=='bottom'&&!hideanimation?'pb':position=='top'&&hideanimation?'ht':position=='left'&&hideanimation?'hl':position=='right'&&hideanimation?'hr':position=='bottom'&&hideanimation?'hb':''">
<view class="realcontent" @click.stop="">
<slot></slot>
</view>
</view>
</view>
</template>
<script>
export default {
props:{
position:{
type:String,
default:null
}
},
data() {
return {
popshow:false,
hideanimation:false,
};
},
methods:{
// Toshow popup page
show:function(){
this.popshow = true;
},
// Tohide popup page
close:function(){
let that = this;
this.$emit("close");
that.hideanimation = true;
if(that.position==null){
that.popshow = false;
}else{
setTimeout(function(){
that.popshow = false;
that.hideanimation = false;
},500)
}
}
},
}
</script>
<style lang="scss">
.lvv-popup{
top:0;
left: 0;
width: 100%;
height: 100%;
position: fixed;
z-index: 98;
.lvv-popupmark{
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 99;
position: absolute;
background: rgba(0,0,0,0.5);
}
.lvv-popupmark.pt,.lvv-popupmark.ht{
background: none
}
.lvv-popupcontent{
width: 100%;
height: 100%;
top:0;
left:0;
position: absolute;
z-index: 100;
// overflow-y:;
}
.pt{
animation: showtop 0.5s;
}
.pl{
animation: showleft 0.5s;
}
.pr{
animation: showright 0.5s;
}
.pb{
animation: showbottom .5s;
}
.ht{
animation: hidetop 0.5s;
}
.hl{
animation: hideleft 0.55s;
}
.hr{
animation: hideright 0.55s;
}
.hb{
animation: hidebottom 1s;
}
.pc{
animation: showcontent .55s;
}
.hc{
animation: hidecontent .55s;
}
}
@keyframes showtop{
0% {
// top: -0px;
transform: translateY(-100%);
// height: 0;
opacity: 1;
}
100% {
top: 0px;
// height: 100%;
transform: translateY(0%);
opacity: 1;
}
}
@keyframes showleft{
0% {
transform: translateX(-100%);
opacity: 1;
}
50% {
opacity: 0;
}
100% {
transform: translateX(0);
}
}
@keyframes showright{
0% {
transform: translateX(100%);
opacity: 1;
}
50% {
opacity: 0;
}
100% {
transform: translateX(0);
}
}
@keyframes showbottom{
0% {
transform: translateY(100%);
opacity: 1;
}
50% {
opacity: 0.5;
}
100% {
transform: translateY(0);
}
}
@keyframes hidetop{
0% {
transform: translateY(0%);
// height: 100%;
opacity: 1;
}
100% {
transform: translateY(-100%);
// height: 0;
opacity: 1;
}
}
@keyframes hideleft{
0% {
transform: translateX(0);
}
50% {
opacity: 0;
}
100% {
transform: translateX(-100%);
opacity: 1;
}
}
@keyframes hideright{
0% {
transform: translateX(0);
}
50% {
opacity: 0;
}
100% {
transform: translateX(100%);
opacity: 1;
}
}
@keyframes hidebottom{
0% {
transform: translateY(0);
}
50% {
opacity: 0;
}
100% {
transform: translateY(100%);
opacity: 1;
}
}
@keyframes showcontent{
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes hidecontent{
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
</style>
mpvue-citypicker
city-data
area.js
/* eslint-disable */
var areaData = [
[
[{
"label": "东城区",
"value": "110101"
}, {
"label": "西城区",
"value": "110102"
}, {
"label": "朝阳区",
"value": "110105"
}, {
"label": "丰台区",
"value": "110106"
}, {
"label": "石景山区",
"value": "110107"
}, {
"label": "海淀区",
"value": "110108"
}, {
"label": "门头沟区",
"value": "110109"
}, {
"label": "房山区",
"value": "110111"
}, {
"label": "通州区",
"value": "110112"
}, {
"label": "顺义区",
"value": "110113"
}, {
"label": "昌平区",
"value": "110114"
}, {
"label": "大兴区",
"value": "110115"
}, {
"label": "怀柔区",
"value": "110116"
}, {
"label": "平谷区",
"value": "110117"
}, {
"label": "密云区",
"value": "110118"
}, {
"label": "延庆区",
"value": "110119"
}]
],
[
[{
"label": "和平区",
"value": "120101"
}, {
"label": "河东区",
"value": "120102"
}, {
"label": "河西区",
"value": "120103"
}, {
"label": "南开区",
"value": "120104"
}, {
"label": "河北区",
"value": "120105"
}, {
"label": "红桥区",
"value": "120106"
}, {
"label": "东丽区",
"value": "120110"
}, {
"label": "西青区",
"value": "120111"
}, {
"label": "津南区",
"value": "120112"
}, {
"label": "北辰区",
"value": "120113"
}, {
"label": "武清区",
"value": "120114"
}, {
"label": "宝坻区",
"value": "120115"
}, {
"label": "滨海新区",
"value": "120116"
}, {
"label": "宁河区",
"value": "120117"
}, {
"label": "静海区",
"value": "120118"
}, {
"label": "蓟州区",
"value": "120119"
}]
],
[
[{
"label": "市辖区",
"value": "130101"
}, {
"label": "长安区",
"value": "130102"
}, {
"label": "桥西区",
"value": "130104"
}, {
"label": "新华区",
"value": "130105"
}, {
"label": "井陉矿区",
"value": "130107"
}, {
"label": "裕华区",
"value": "130108"
}, {
"label": "藁城区",
"value": "130109"
}, {
"label": "鹿泉区",
"value": "130110"
}, {
"label": "栾城区",
"value": "130111"
}, {
"label": "井陉县",
"value": "130121"
}, {
"label": "正定县",
"value": "130123"
}, {
"label": "行唐县",
"value": "130125"
}, {
"label": "灵寿县",
"value": "130126"
}, {
"label": "高邑县",
"value": "130127"
}, {
"label": "深泽县",
"value": "130128"
}, {
"label": "赞皇县",
"value": "130129"
}, {
"label": "无极县",
"value": "130130"
}, {
"label": "平山县",
"value": "130131"
}, {
"label": "元氏县",
"value": "130132"
}, {
"label": "赵县",
"value": "130133"
}, {
"label": "晋州市",
"value": "130183"
}, {
"label": "新乐市",
"value": "130184"
}],
[{
"label": "市辖区",
"value": "130201"
}, {
"label": "路南区",
"value": "130202"
}, {
"label": "路北区",
"value": "130203"
}, {
"label": "古冶区",
"value": "130204"
}, {
"label": "开平区",
"value": "130205"
}, {
"label": "丰南区",
"value": "130207"
}, {
"label": "丰润区",
"value": "130208"
}, {
"label": "曹妃甸区",
"value": "130209"
}, {
"label": "滦县",
"value": "130223"
}, {
"label": "滦南县",
"value": "130224"
}, {
"label": "乐亭县",
"value": "130225"
}, {
"label": "迁西县",
"value": "130227"
}, {
"label": "玉田县",
"value": "130229"
}, {
"label": "遵化市",
"value": "130281"
}, {
"label": "迁安市",
"value": "130283"
}],
[{
"label": "市辖区",
"value": "130301"
}, {
"label": "海港区",
"value": "130302"
}, {
"label": "山海关区",
"value": "130303"
}, {
"label": "北戴河区",
"value": "130304"
}, {
"label": "抚宁区",
"value": "130306"
}, {
"label": "青龙满族自治县",
"value": "130321"
}, {
"label": "昌黎县",
"value": "130322"
}, {
"label": "卢龙县",
"value": "130324"
}],
[{
"label": "市辖区",
"value": "130401"
}, {
"label": "邯山区",
"value": "130402"
}, {
"label": "丛台区",
"value": "130403"
}, {
"label": "复兴区",
"value": "130404"
}, {
"label": "峰峰矿区",
"value": "130406"
}, {
"label": "邯郸县",
"value": "130421"
}, {
"label": "临漳县",
"value": "130423"
}, {
"label": "成安县",
"value": "130424"
}, {
"label": "大名县",
"value": "130425"
}, {
"label": "涉县",
"value": "130426"
}, {
"label": "磁县",
"value": "130427"
}, {
"label": "肥乡县",
"value": "130428"
}, {
"label": "永年县",
"value": "130429"
}, {
"label": "邱县",
"value": "130430"
}, {
"label": "鸡泽县",
"value": "130431"
}, {
"label": "广平县",
"value": "130432"
}, {
"label": "馆陶县",
"value": "130433"
}, {
"label": "魏县",
"value": "130434"
}, {
"label": "曲周县",
"value": "130435"
}, {
"label": "武安市",
"value": "130481"
}],
[{
"label": "市辖区",
"value": "130501"
}, {
"label": "桥东区",
"value": "130502"
}, {
"label": "桥西区",
"value": "130503"
}, {
"label": "邢台县",
"value": "130521"
}, {
"label": "临城县",
"value": "130522"
}, {
"label": "内丘县",
"value": "130523"
}, {
"label": "柏乡县",
"value": "130524"
}, {
"label": "隆尧县",
"value": "130525"
}, {
"label": "任县",
"value": "130526"
}, {
"label": "南和县",
"value": "130527"
}, {
"label": "宁晋县",
"value": "130528"
}, {
"label": "巨鹿县",
"value": "130529"
}, {
"label": "新河县",
"value": "130530"
}, {
"label": "广宗县",
"value": "130531"
}, {
"label": "平乡县",
"value": "130532"
}, {
"label": "威县",
"value": "130533"
}, {
"label": "清河县",
"value": "130534"
}, {
"label": "临西县",
"value": "130535"
}, {
"label": "南宫市",
"value": "130581"
}, {
"label": "沙河市",
"value": "130582"
}],
[{
"label": "市辖区",
"value": "130601"
}, {
"label": "竞秀区",
"value": "130602"
}, {
"label": "莲池区",
"value": "130606"
}, {
"label": "满城区",
"value": "130607"
}, {
"label": "清苑区",
"value": "130608"
}, {
"label": "徐水区",
"value": "130609"
}, {
"label": "涞水县",
"value": "130623"
}, {
"label": "阜平县",
"value": "130624"
}, {
"label": "定兴县",
"value": "130626"
}, {
"label": "唐县",
"value": "130627"
}, {
"label": "高阳县",
"value": "130628"
}, {
"label": "容城县",
"value": "130629"
}, {
"label": "涞源县",
"value": "130630"
}, {
"label": "望都县",
"value": "130631"
}, {
"label": "安新县",
"value": "130632"
}, {
"label": "易县",
"value": "130633"
}, {
"label": "曲阳县",
"value": "130634"
}, {
"label": "蠡县",
"value": "130635"
}, {
"label": "顺平县",
"value": "130636"
}, {
"label": "博野县",
"value": "130637"
}, {
"label": "雄县",
"value": "130638"
}, {
"label": "涿州市",
"value": "130681"
}, {
"label": "安国市",
"value": "130683"
}, {
"label": "高碑店市",
"value": "130684"
}],
[{
"label": "市辖区",
"value": "130701"
}, {
"label": "桥东区",
"value": "130702"
}, {
"label": "桥西区",
"value": "130703"
}, {
"label": "宣化区",
"value": "130705"
}, {
"label": "下花园区",
"value": "130706"
}, {
"label": "万全区",
"value": "130708"
}, {
"label": "崇礼区",
"value": "130709"
}, {
"label": "张北县",
"value": "130722"
}, {
"label": "康保县",
"value": "130723"
}, {
"label": "沽源县",
"value": "130724"
}, {
"label": "尚义县",
"value": "130725"
}, {
"label": "蔚县",
"value": "130726"
}, {
"label": "阳原县",
"value": "130727"
}, {
"label": "怀安县",
"value": "130728"
}, {
"label": "怀来县",
"value": "130730"
}, {
"label": "涿鹿县",
"value": "130731"
}, {
"label": "赤城县",
"value": "130732"
}],
[{
"label": "市辖区",
"value": "130801"
}, {
"label": "双桥区",
"value": "130802"
}, {
"label": "双滦区",
"value": "130803"
}, {
"label": "鹰手营子矿区",
"value": "130804"
}, {
"label": "承德县",
"value": "130821"
}, {
"label": "兴隆县",
"value": "130822"
}, {
"label": "平泉县",
"value": "130823"
}, {
"label": "滦平县",
"value": "130824"
}, {
"label": "隆化县",
"value": "130825"
}, {
"label": "丰宁满族自治县",
"value": "130826"
}, {
"label": "宽城满族自治县",
"value": "130827"
}, {
"label": "围场满族蒙古族自治县",
"value": "130828"
}],
[{
"label": "市辖区",
"value": "130901"
}, {
"label": "新华区",
"value": "130902"
}, {
"label": "运河区",
"value": "130903"
}, {
"label": "沧县",
"value": "130921"
}, {
"label": "青县",
"value": "130922"
}, {
"label": "东光县",
"value": "130923"
}, {
"label": "海兴县",
"value": "130924"
}, {
"label": "盐山县",
"value": "130925"
}, {
"label": "肃宁县",
"value": "130926"
}, {
"label": "南皮县",
"value": "130927"
}, {
"label": "吴桥县",
"value": "130928"
}, {
"label": "献县",
"value": "130929"
}, {
"label": "孟村回族自治县",
"value": "130930"
}, {
"label": "泊头市",
"value": "130981"
}, {
"label": "任丘市",
"value": "130982"
}, {
"label": "黄骅市",
"value": "130983"
}, {
"label": "河间市",
"value": "130984"
}],
[{
"label": "市辖区",
"value": "131001"
}, {
"label": "安次区",
"value": "131002"
}, {
"label": "广阳区",
"value": "131003"
}, {
"label": "固安县",
"value": "131022"
}, {
"label": "永清县",
"value": "131023"
}, {
"label": "香河县",
"value": "131024"
}, {
"label": "大城县",
"value": "131025"
}, {
"label": "文安县",
"value": "131026"
}, {
"label": "大厂回族自治县",
"value": "131028"
}, {
"label": "霸州市",
"value": "131081"
}, {
"label": "三河市",
"value": "131082"
}],
[{
"label": "市辖区",
"value": "131101"
}, {
"label": "桃城区",
"value": "131102"
}, {
"label": "冀州区",
"value": "131103"
}, {
"label": "枣强县",
"value": "131121"
}, {
"label": "武邑县",
"value": "131122"
}, {
"label": "武强县",
"value": "131123"
}, {
"label": "饶阳县",
"value": "131124"
}, {
"label": "安平县",
"value": "131125"
}, {
"label": "故城县",
"value": "131126"
}, {
"label": "景县",
"value": "131127"
}, {
"label": "阜城县",
"value": "131128"
}, {
"label": "深州市",
"value": "131182"
}],
[{
"label": "市辖区",
"value": "139001"
}, {
"label": "辛集市",
"value": "139002"
}]
],
[
[{
"label": "市辖区",
"value": "140101"
}, {
"label": "小店区",
"value": "140105"
}, {
"label": "迎泽区",
"value": "140106"
}, {
"label": "杏花岭区",
"value": "140107"
}, {
"label": "尖草坪区",
"value": "140108"
}, {
"label": "万柏林区",
"value": "140109"
}, {
"label": "晋源区",
"value": "140110"
}, {
"label": "清徐县",
"value": "140121"
}, {
"label": "阳曲县",
"value": "140122"
}, {
"label": "娄烦县",
"value": "140123"
}, {
"label": "古交市",
"value": "140181"
}],
[{
"label": "市辖区",
"value": "140201"
}, {
"label": "城区",
"value": "140202"
}, {
"label": "矿区",
"value": "140203"
}, {
"label": "南郊区",
"value": "140211"
}, {
"label": "新荣区",
"value": "140212"
}, {
"label": "阳高县",
"value": "140221"
}, {
"label": "天镇县",
"value": "140222"
}, {
"label": "广灵县",
"value": "140223"
}, {
"label": "灵丘县",
"value": "140224"
}, {
"label": "浑源县",
"value": "140225"
}, {
"label": "左云县",
"value": "140226"
}, {
"label": "大同县",
"value": "140227"
}],
[{
"label": "市辖区",
"value": "140301"
}, {
"label": "城区",
"value": "140302"
}, {
"label": "矿区",
"value": "140303"
}, {
"label": "郊区",
"value": "140311"
}, {
"label": "平定县",
"value": "140321"
}, {
"label": "盂县",
"value": "140322"
}],
[{
"label": "市辖区",
"value": "140401"
}, {
"label": "城区",
"value": "140402"
}, {
"label": "郊区",
"value": "140411"
}, {
"label": "长治县",
"value": "140421"
}, {
"label": "襄垣县",
"value": "140423"
}, {
"label": "屯留县",
"value": "140424"
}, {
"label": "平顺县",
"value": "140425"
}, {
"label": "黎城县",
"value": "140426"
}, {
"label": "壶关县",
"value": "140427"
}, {
"label": "长子县",
"value": "140428"
}, {
"label": "武乡县",
"value": "140429"
}, {
"label": "沁县",
"value": "140430"
}, {
"label": "沁源县",
"value": "140431"
}, {
"label": "潞城市",
"value": "140481"
}],
[{
"label": "市辖区",
"value": "140501"
}, {
"label": "城区",
"value": "140502"
}, {
"label": "沁水县",
"value": "140521"
}, {
"label": "阳城县",
"value": "140522"
}, {
"label": "陵川县",
"value": "140524"
}, {
"label": "泽州县",
"value": "140525"
}, {
"label": "高平市",
"value": "140581"
}],
[{
"label": "市辖区",
"value": "140601"
}, {
"label": "朔城区",
"value": "140602"
}, {
"label": "平鲁区",
"value": "140603"
}, {
"label": "山阴县",
"value": "140621"
}, {
"label": "应县",
"value": "140622"
}, {
"label": "右玉县",
"value": "140623"
}, {
"label": "怀仁县",
"value": "140624"
}],
[{
"label": "市辖区",
"value": "140701"
}, {
"label": "榆次区",
"value": "140702"
}, {
"label": "榆社县",
"value": "140721"
}, {
"label": "左权县",
"value": "140722"
}, {
"label": "和顺县",
"value": "140723"
}, {
"label": "昔阳县",
"value": "140724"
}, {
"label": "寿阳县",
"value": "140725"
}, {
"label": "太谷县",
"value": "140726"
}, {
"label": "祁县",
"value": "140727"
}, {
"label": "平遥县",
"value": "140728"
}, {
"label": "灵石县",
"value": "140729"
}, {
"label": "介休市",
"value": "140781"
}],
[{
"label": "市辖区",
"value": "140801"
}, {
"label": "盐湖区",
"value": "140802"
}, {
"label": "临猗县",
"value": "140821"
}, {
"label": "万荣县",
"value": "140822"
}, {
"label": "闻喜县",
"value": "140823"
}, {
"label": "稷山县",
"value": "140824"
}, {
"label": "新绛县",
"value": "140825"
}, {
"label": "绛县",
"value": "140826"
}, {
"label": "垣曲县",
"value": "140827"
}, {
"label": "夏县",
"value": "140828"
}, {
"label": "平陆县",
"value": "140829"
}, {
"label": "芮城县",
"value": "140830"
}, {
"label": "永济市",
"value": "140881"
}, {
"label": "河津市",
"value": "140882"
}],
[{
"label": "市辖区",
"value": "140901"
}, {
"label": "忻府区",
"value": "140902"
}, {
"label": "定襄县",
"value": "140921"
}, {
"label": "五台县",
"value": "140922"
}, {
"label": "代县",
"value": "140923"
}, {
"label": "繁峙县",
"value": "140924"
}, {
"label": "宁武县",
"value": "140925"
}, {
"label": "静乐县",
"value": "140926"
}, {
"label": "神池县",
"value": "140927"
}, {
"label": "五寨县",
"value": "140928"
}, {
"label": "岢岚县",
"value": "140929"
}, {
"label": "河曲县",
"value": "140930"
}, {
"label": "保德县",
"value": "140931"
}, {
"label": "偏关县",
"value": "140932"
}, {
"label": "原平市",
"value": "140981"
}],
[{
"label": "市辖区",
"value": "141001"
}, {
"label": "尧都区",
"value": "141002"
}, {
"label": "曲沃县",
"value": "141021"
}, {
"label": "翼城县",
"value": "141022"
}, {
"label": "襄汾县",
"value": "141023"
}, {
"label": "洪洞县",
"value": "141024"
}, {
"label": "古县",
"value": "141025"
}, {
"label": "安泽县",
"value": "141026"
}, {
"label": "浮山县",
"value": "141027"
}, {
"label": "吉县",
"value": "141028"
}, {
"label": "乡宁县",
"value": "141029"
}, {
"label": "大宁县",
"value": "141030"
}, {
"label": "隰县",
"value": "141031"
}, {
"label": "永和县",
"value": "141032"
}, {
"label": "蒲县",
"value": "141033"
}, {
"label": "汾西县",
"value": "141034"
}, {
"label": "侯马市",
"value": "141081"
}, {
"label": "霍州市",
"value": "141082"
}],
[{
"label": "市辖区",
"value": "141101"
}, {
"label": "离石区",
"value": "141102"
}, {
"label": "文水县",
"value": "141121"
}, {
"label": "交城县",
"value": "141122"
}, {
"label": "兴县",
"value": "141123"
}, {
"label": "临县",
"value": "141124"
}, {
"label": "柳林县",
"value": "141125"
}, {
"label": "石楼县",
"value": "141126"
}, {
"label": "岚县",
"value": "141127"
}, {
"label": "方山县",
"value": "141128"
}, {
"label": "中阳县",
"value": "141129"
}, {
"label": "交口县",
"value": "141130"
}, {
"label": "孝义市",
"value": "141181"
}, {
"label": "汾阳市",
"value": "141182"
}]
],
[
[{
"label": "市辖区",
"value": "150101"
}, {
"label": "新城区",
"value": "150102"
}, {
"label": "回民区",
"value": "150103"
}, {
"label": "玉泉区",
"value": "150104"
}, {
"label": "赛罕区",
"value": "150105"
}, {
"label": "土默特左旗",
"value": "150121"
}, {
"label": "托克托县",
"value": "150122"
}, {
"label": "和林格尔县",
"value": "150123"
}, {
"label": "清水河县",
"value": "150124"
}, {
"label": "武川县",
"value": "150125"
}],
[{
"label": "市辖区",
"value": "150201"
}, {
"label": "东河区",
"value": "150202"
}, {
"label": "昆都仑区",
"value": "150203"
}, {
"label": "青山区",
"value": "150204"
}, {
"label": "石拐区",
"value": "150205"
}, {
"label": "白云鄂博矿区",
"value": "150206"
}, {
"label": "九原区",
"value": "150207"
}, {
"label": "土默特右旗",
"value": "150221"
}, {
"label": "固阳县",
"value": "150222"
}, {
"label": "达尔罕茂明安联合旗",
"value": "150223"
}],
[{
"label": "市辖区",
"value": "150301"
}, {
"label": "海勃湾区",
"value": "150302"
}, {
"label": "海南区",
"value": "150303"
}, {
"label": "乌达区",
"value": "150304"
}],
[{
"label": "市辖区",
"value": "150401"
}, {
"label": "红山区",
"value": "150402"
}, {
"label": "元宝山区",
"value": "150403"
}, {
"label": "松山区",
"value": "150404"
}, {
"label": "阿鲁科尔沁旗",
"value": "150421"
}, {
"label": "巴林左旗",
"value": "150422"
}, {
"label": "巴林右旗",
"value": "150423"
}, {
"label": "林西县",
"value": "150424"
}, {
"label": "克什克腾旗",
"value": "150425"
}, {
"label": "翁牛特旗",
"value": "150426"
}, {
"label": "喀喇沁旗",
"value": "150428"
}, {
"label": "宁城县",
"value": "150429"
}, {
"label": "敖汉旗",
"value": "150430"
}],
[{
"label": "市辖区",
"value": "150501"
}, {
"label": "科尔沁区",
"value": "150502"
}, {
"label": "科尔沁左翼中旗",
"value": "150521"
}, {
"label": "科尔沁左翼后旗",
"value": "150522"
}, {
"label": "开鲁县",
"value": "150523"
}, {
"label": "库伦旗",
"value": "150524"
}, {
"label": "奈曼旗",
"value": "150525"
}, {
"label": "扎鲁特旗",
"value": "150526"
}, {
"label": "霍林郭勒市",
"value": "150581"
}],
[{
"label": "市辖区",
"value": "150601"
}, {
"label": "东胜区",
"value": "150602"
}, {
"label": "康巴什区",
"value": "150603"
}, {
"label": "达拉特旗",
"value": "150621"
}, {
"label": "准格尔旗",
"value": "150622"
}, {
"label": "鄂托克前旗",
"value": "150623"
}, {
"label": "鄂托克旗",
"value": "150624"
}, {
"label": "杭锦旗",
"value": "150625"
}, {
"label": "乌审旗",
"value": "150626"
}, {
"label": "伊金霍洛旗",
"value": "150627"
}],
[{
"label": "市辖区",
"value": "150701"
}, {
"label": "海拉尔区",
"value": "150702"
}, {
"label": "扎赉诺尔区",
"value": "150703"
}, {
"label": "阿荣旗",
"value": "150721"
}, {
"label": "莫力达瓦达斡尔族自治旗",
"value": "150722"
}, {
"label": "鄂伦春自治旗",
"value": "150723"
}, {
"label": "鄂温克族自治旗",
"value": "150724"
}, {
"label": "陈巴尔虎旗",
"value": "150725"
}, {
"label": "新巴尔虎左旗",
"value": "150726"
}, {
"label": "新巴尔虎右旗",
"value": "150727"
}, {
"label": "满洲里市",
"value": "150781"
}, {
"label": "牙克石市",
"value": "150782"
}, {
"label": "扎兰屯市",
"value": "150783"
}, {
"label": "额尔古纳市",
"value": "150784"
}, {
"label": "根河市",
"value": "150785"
}],
[{
"label": "市辖区",
"value": "150801"
}, {
"label": "临河区",
"value": "150802"
}, {
"label": "五原县",
"value": "150821"
}, {
"label": "磴口县",
"value": "150822"
}, {
"label": "乌拉特前旗",
"value": "150823"
}, {
"label": "乌拉特中旗",
"value": "150824"
}, {
"label": "乌拉特后旗",
"value": "150825"
}, {
"label": "杭锦后旗",
"value": "150826"
}],
[{
"label": "市辖区",
"value": "150901"
}, {
"label": "集宁区",
"value": "150902"
}, {
"label": "卓资县",
"value": "150921"
}, {
"label": "化德县",
"value": "150922"
}, {
"label": "商都县",
"value": "150923"
}, {
"label": "兴和县",
"value": "150924"
}, {
"label": "凉城县",
"value": "150925"
}, {
"label": "察哈尔右翼前旗",
"value": "150926"
}, {
"label": "察哈尔右翼中旗",
"value": "150927"
}, {
"label": "察哈尔右翼后旗",
"value": "150928"
}, {
"label": "四子王旗",
"value": "150929"
}, {
"label": "丰镇市",
"value": "150981"
}],
[{
"label": "市辖区",
"value": "152201"
}, {
"label": "阿尔山市",
"value": "152202"
}, {
"label": "科尔沁右翼前旗",
"value": "152221"
}, {
"label": "科尔沁右翼中旗",
"value": "152222"
}, {
"label": "扎赉特旗",
"value": "152223"
}, {
"label": "突泉县",
"value": "152224"
}],
[{
"label": "市辖区",
"value": "152501"
}, {
"label": "锡林浩特市",
"value": "152502"
}, {
"label": "阿巴嘎旗",
"value": "152522"
}, {
"label": "苏尼特左旗",
"value": "152523"
}, {
"label": "苏尼特右旗",
"value": "152524"
}, {
"label": "东乌珠穆沁旗",
"value": "152525"
}, {
"label": "西乌珠穆沁旗",
"value": "152526"
}, {
"label": "太仆寺旗",
"value": "152527"
}, {
"label": "镶黄旗",
"value": "152528"
}, {
"label": "正镶白旗",
"value": "152529"
}, {
"label": "正蓝旗",
"value": "152530"
}, {
"label": "多伦县",
"value": "152531"
}],
[{
"label": "阿拉善左旗",
"value": "152921"
}, {
"label": "阿拉善右旗",
"value": "152922"
}, {
"label": "额济纳旗",
"value": "152923"
}]
],
[
[{
"label": "市辖区",
"value": "210101"
}, {
"label": "和平区",
"value": "210102"
}, {
"label": "沈河区",
"value": "210103"
}, {
"label": "大东区",
"value": "210104"
}, {
"label": "皇姑区",
"value": "210105"
}, {
"label": "铁西区",
"value": "210106"
}, {
"label": "苏家屯区",
"value": "210111"
}, {
"label": "浑南区",
"value": "210112"
}, {
"label": "沈北新区",
"value": "210113"
}, {
"label": "于洪区",
"value": "210114"
}, {
"label": "辽中区",
"value": "210115"
}, {
"label": "康平县",
"value": "210123"
}, {
"label": "法库县",
"value": "210124"
}, {
"label": "新民市",
"value": "210181"
}],
[{
"label": "市辖区",
"value": "210201"
}, {
"label": "中山区",
"value": "210202"
}, {
"label": "西岗区",
"value": "210203"
}, {
"label": "沙河口区",
"value": "210204"
}, {
"label": "甘井子区",
"value": "210211"
}, {
"label": "旅顺口区",
"value": "210212"
}, {
"label": "金州区",
"value": "210213"
}, {
"label": "普兰店区",
"value": "210214"
}, {
"label": "长海县",
"value": "210224"
}, {
"label": "瓦房店市",
"value": "210281"
}, {
"label": "庄河市",
"value": "210283"
}],
[{
"label": "市辖区",
"value": "210301"
}, {
"label": "铁东区",
"value": "210302"
}, {
"label": "铁西区",
"value": "210303"
}, {
"label": "立山区",
"value": "210304"
}, {
"label": "千山区",
"value": "210311"
}, {
"label": "台安县",
"value": "210321"
}, {
"label": "岫岩满族自治县",
"value": "210323"
}, {
"label": "海城市",
"value": "210381"
}],
[{
"label": "市辖区",
"value": "210401"
}, {
"label": "新抚区",
"value": "210402"
}, {
"label": "东洲区",
"value": "210403"
}, {
"label": "望花区",
"value": "210404"
}, {
"label": "顺城区",
"value": "210411"
}, {
"label": "抚顺县",
"value": "210421"
}, {
"label": "新宾满族自治县",
"value": "210422"
}, {
"label": "清原满族自治县",
"value": "210423"
}],
[{
"label": "市辖区",
"value": "210501"
}, {
"label": "平山区",
"value": "210502"
}, {
"label": "溪湖区",
"value": "210503"
}, {
"label": "明山区",
"value": "210504"
}, {
"label": "南芬区",
"value": "210505"
}, {
"label": "本溪满族自治县",
"value": "210521"
}, {
"label": "桓仁满族自治县",
"value": "210522"
}],
[{
"label": "市辖区",
"value": "210601"
}, {
"label": "元宝区",
"value": "210602"
}, {
"label": "振兴区",
"value": "210603"
}, {
"label": "振安区",
"value": "210604"
}, {
"label": "宽甸满族自治县",
"value": "210624"
}, {
"label": "东港市",
"value": "210681"
}, {
"label": "凤城市",
"value": "210682"
}],
[{
"label": "市辖区",
"value": "210701"
}, {
"label": "古塔区",
"value": "210702"
}, {
"label": "凌河区",
"value": "210703"
}, {
"label": "太和区",
"value": "210711"
}, {
"label": "黑山县",
"value": "210726"
}, {
"label": "义县",
"value": "210727"
}, {
"label": "凌海市",
"value": "210781"
}, {
"label": "北镇市",
"value": "210782"
}],
[{
"label": "市辖区",
"value": "210801"
}, {
"label": "站前区",
"value": "210802"
}, {
"label": "西市区",
"value": "210803"
}, {
"label": "鲅鱼圈区",
"value": "210804"
}, {
"label": "老边区",
"value": "210811"
}, {
"label": "盖州市",
"value": "210881"
}, {
"label": "大石桥市",
"value": "210882"
}],
[{
"label": "市辖区",
"value": "210901"
}, {
"label": "海州区",
"value": "210902"
}, {
"label": "新邱区",
"value": "210903"
}, {
"label": "太平区",
"value": "210904"
}, {
"label": "清河门区",
"value": "210905"
}, {
"label": "细河区",
"value": "210911"
}, {
"label": "阜新蒙古族自治县",
"value": "210921"
}, {
"label": "彰武县",
"value": "210922"
}],
[{
"label": "市辖区",
"value": "211001"
}, {
"label": "白塔区",
"value": "211002"
}, {
"label": "文圣区",
"value": "211003"
}, {
"label": "宏伟区",
"value": "211004"
}, {
"label": "弓长岭区",
"value": "211005"
}, {
"label": "太子河区",
"value": "211011"
}, {
"label": "辽阳县",
"value": "211021"
}, {
"label": "灯塔市",
"value": "211081"
}],
[{
"label": "市辖区",
"value": "211101"
}, {
"label": "双台子区",
"value": "211102"
}, {
"label": "兴隆台区",
"value": "211103"
}, {
"label": "大洼区",
"value": "211104"
}, {
"label": "盘山县",
"value": "211122"
}],
[{
"label": "市辖区",
"value": "211201"
}, {
"label": "银州区",
"value": "211202"
}, {
"label": "清河区",
"value": "211204"
}, {
"label": "铁岭县",
"value": "211221"
}, {
"label": "西丰县",
"value": "211223"
}, {
"label": "昌图县",
"value": "211224"
}, {
"label": "调兵山市",
"value": "211281"
}, {
"label": "开原市",
"value": "211282"
}],
[{
"label": "市辖区",
"value": "211301"
}, {
"label": "双塔区",
"value": "211302"
}, {
"label": "龙城区",
"value": "211303"
}, {
"label": "朝阳县",
"value": "211321"
}, {
"label": "建平县",
"value": "211322"
}, {
"label": "喀喇沁左翼蒙古族自治县",
"value": "211324"
}, {
"label": "北票市",
"value": "211381"
}, {
"label": "凌源市",
"value": "211382"
}],
[{
"label": "市辖区",
"value": "211401"
}, {
"label": "连山区",
"value": "211402"
}, {
"label": "龙港区",
"value": "211403"
}, {
"label": "南票区",
"value": "211404"
}, {
"label": "绥中县",
"value": "211421"
}, {
"label": "建昌县",
"value": "211422"
}, {
"label": "兴城市",
"value": "211481"
}]
],
[
[{
"label": "市辖区",
"value": "220101"
}, {
"label": "南关区",
"value": "220102"
}, {
"label": "宽城区",
"value": "220103"
}, {
"label": "朝阳区",
"value": "220104"
}, {
"label": "二道区",
"value": "220105"
}, {
"label": "绿园区",
"value": "220106"
}, {
"label": "双阳区",
"value": "220112"
}, {
"label": "九台区",
"value": "220113"
}, {
"label": "农安县",
"value": "220122"
}, {
"label": "榆树市",
"value": "220182"
}, {
"label": "德惠市",
"value": "220183"
}],
[{
"label": "市辖区",
"value": "220201"
}, {
"label": "昌邑区",
"value": "220202"
}, {
"label": "龙潭区",
"value": "220203"
}, {
"label": "船营区",
"value": "220204"
}, {
"label": "丰满区",
"value": "220211"
}, {
"label": "永吉县",
"value": "220221"
}, {
"label": "蛟河市",
"value": "220281"
}, {
"label": "桦甸市",
"value": "220282"
}, {
"label": "舒兰市",
"value": "220283"
}, {
"label": "磐石市",
"value": "220284"
}],
[{
"label": "市辖区",
"value": "220301"
}, {
"label": "铁西区",
"value": "220302"
}, {
"label": "铁东区",
"value": "220303"
}, {
"label": "梨树县",
"value": "220322"
}, {
"label": "伊通满族自治县",
"value": "220323"
}, {
"label": "公主岭市",
"value": "220381"
}, {
"label": "双辽市",
"value": "220382"
}],
[{
"label": "市辖区",
"value": "220401"
}, {
"label": "龙山区",
"value": "220402"
}, {
"label": "西安区",
"value": "220403"
}, {
"label": "东丰县",
"value": "220421"
}, {
"label": "东辽县",
"value": "220422"
}],
[{
"label": "市辖区",
"value": "220501"
}, {
"label": "东昌区",
"value": "220502"
}, {
"label": "二道江区",
"value": "220503"
}, {
"label": "通化县",
"value": "220521"
}, {
"label": "辉南县",
"value": "220523"
}, {
"label": "柳河县",
"value": "220524"
}, {
"label": "梅河口市",
"value": "220581"
}, {
"label": "集安市",
"value": "220582"
}],
[{
"label": "市辖区",
"value": "220601"
}, {
"label": "浑江区",
"value": "220602"
}, {
"label": "江源区",
"value": "220605"
}, {
"label": "抚松县",
"value": "220621"
}, {
"label": "靖宇县",
"value": "220622"
}, {
"label": "长白朝鲜族自治县",
"value": "220623"
}, {
"label": "临江市",
"value": "220681"
}],
[{
"label": "市辖区",
"value": "220701"
}, {
"label": "宁江区",
"value": "220702"
}, {
"label": "前郭尔罗斯蒙古族自治县",
"value": "220721"
}, {
"label": "长岭县",
"value": "220722"
}, {
"label": "乾安县",
"value": "220723"
}, {
"label": "扶余市",
"value": "220781"
}],
[{
"label": "市辖区",
"value": "220801"
}, {
"label": "洮北区",
"value": "220802"
}, {
"label": "镇赉县",
"value": "220821"
}, {
"label": "通榆县",
"value": "220822"
}, {
"label": "洮南市",
"value": "220881"
}, {
"label": "大安市",
"value": "220882"
}],
[{
"label": "市辖区",
"value": "222401"
}, {
"label": "图们市",
"value": "222402"
}, {
"label": "敦化市",
"value": "222403"
}, {
"label": "珲春市",
"value": "222404"
}, {
"label": "龙井市",
"value": "222405"
}, {
"label": "和龙市",
"value": "222406"
}, {
"label": "汪清县",
"value": "222424"
}, {
"label": "安图县",
"value": "222426"
}]
],
[
[{
"label": "市辖区",
"value": "230101"
}, {
"label": "道里区",
"value": "230102"
}, {
"label": "南岗区",
"value": "230103"
}, {
"label": "道外区",
"value": "230104"
}, {
"label": "平房区",
"value": "230108"
}, {
"label": "松北区",
"value": "230109"
}, {
"label": "香坊区",
"value": "230110"
}, {
"label": "呼兰区",
"value": "230111"
}, {
"label": "阿城区",
"value": "230112"
}, {
"label": "双城区",
"value": "230113"
}, {
"label": "依兰县",
"value": "230123"
}, {
"label": "方正县",
"value": "230124"
}, {
"label": "宾县",
"value": "230125"
}, {
"label": "巴彦县",
"value": "230126"
}, {
"label": "木兰县",
"value": "230127"
}, {
"label": "通河县",
"value": "230128"
}, {
"label": "延寿县",
"value": "230129"
}, {
"label": "尚志市",
"value": "230183"
}, {
"label": "五常市",
"value": "230184"
}],
[{
"label": "市辖区",
"value": "230201"
}, {
"label": "龙沙区",
"value": "230202"
}, {
"label": "建华区",
"value": "230203"
}, {
"label": "铁锋区",
"value": "230204"
}, {
"label": "昂昂溪区",
"value": "230205"
}, {
"label": "富拉尔基区",
"value": "230206"
}, {
"label": "碾子山区",
"value": "230207"
}, {
"label": "梅里斯达斡尔族区",
"value": "230208"
}, {
"label": "龙江县",
"value": "230221"
}, {
"label": "依安县",
"value": "230223"
}, {
"label": "泰来县",
"value": "230224"
}, {
"label": "甘南县",
"value": "230225"
}, {
"label": "富裕县",
"value": "230227"
}, {
"label": "克山县",
"value": "230229"
}, {
"label": "克东县",
"value": "230230"
}, {
"label": "拜泉县",
"value": "230231"
}, {
"label": "讷河市",
"value": "230281"
}],
[{
"label": "市辖区",
"value": "230301"
}, {
"label": "鸡冠区",
"value": "230302"
}, {
"label": "恒山区",
"value": "230303"
}, {
"label": "滴道区",
"value": "230304"
}, {
"label": "梨树区",
"value": "230305"
}, {
"label": "城子河区",
"value": "230306"
}, {
"label": "麻山区",
"value": "230307"
}, {
"label": "鸡东县",
"value": "230321"
}, {
"label": "虎林市",
"value": "230381"
}, {
"label": "密山市",
"value": "230382"
}],
[{
"label": "市辖区",
"value": "230401"
}, {
"label": "向阳区",
"value": "230402"
}, {
"label": "工农区",
"value": "230403"
}, {
"label": "南山区",
"value": "230404"
}, {
"label": "兴安区",
"value": "230405"
}, {
"label": "东山区",
"value": "230406"
}, {
"label": "兴山区",
"value": "230407"
}, {
"label": "萝北县",
"value": "230421"
}, {
"label": "绥滨县",
"value": "230422"
}],
[{
"label": "市辖区",
"value": "230501"
}, {
"label": "尖山区",
"value": "230502"
}, {
"label": "岭东区",
"value": "230503"
}, {
"label": "四方台区",
"value": "230505"
}, {
"label": "宝山区",
"value": "230506"
}, {
"label": "集贤县",
"value": "230521"
}, {
"label": "友谊县",
"value": "230522"
}, {
"label": "宝清县",
"value": "230523"
}, {
"label": "饶河县",
"value": "230524"
}],
[{
"label": "市辖区",
"value": "230601"
}, {
"label": "萨尔图区",
"value": "230602"
}, {
"label": "龙凤区",
"value": "230603"
}, {
"label": "让胡路区",
"value": "230604"
}, {
"label": "红岗区",
"value": "230605"
}, {
"label": "大同区",
"value": "230606"
}, {
"label": "肇州县",
"value": "230621"
}, {
"label": "肇源县",
"value": "230622"
}, {
"label": "林甸县",
"value": "230623"
}, {
"label": "杜尔伯特蒙古族自治县",
"value": "230624"
}],
[{
"label": "市辖区",
"value": "230701"
}, {
"label": "伊春区",
"value": "230702"
}, {
"label": "南岔区",
"value": "230703"
}, {
"label": "友好区",
"value": "230704"
}, {
"label": "西林区",
"value": "230705"
}, {
"label": "翠峦区",
"value": "230706"
}, {
"label": "新青区",
"value": "230707"
}, {
"label": "美溪区",
"value": "230708"
}, {
"label": "金山屯区",
"value": "230709"
}, {
"label": "五营区",
"value": "230710"
}, {
"label": "乌马河区",
"value": "230711"
}, {
"label": "汤旺河区",
"value": "230712"
}, {
"label": "带岭区",
"value": "230713"
}, {
"label": "乌伊岭区",
"value": "230714"
}, {
"label": "红星区",
"value": "230715"
}, {
"label": "上甘岭区",
"value": "230716"
}, {
"label": "嘉荫县",
"value": "230722"
}, {
"label": "铁力市",
"value": "230781"
}],
[{
"label": "市辖区",
"value": "230801"
}, {
"label": "向阳区",
"value": "230803"
}, {
"label": "前进区",
"value": "230804"
}, {
"label": "东风区",
"value": "230805"
}, {
"label": "郊区",
"value": "230811"
}, {
"label": "桦南县",
"value": "230822"
}, {
"label": "桦川县",
"value": "230826"
}, {
"label": "汤原县",
"value": "230828"
}, {
"label": "同江市",
"value": "230881"
}, {
"label": "富锦市",
"value": "230882"
}, {
"label": "抚远市",
"value": "230883"
}],
[{
"label": "市辖区",
"value": "230901"
}, {
"label": "新兴区",
"value": "230902"
}, {
"label": "桃山区",
"value": "230903"
}, {
"label": "茄子河区",
"value": "230904"
}, {
"label": "勃利县",
"value": "230921"
}],
[{
"label": "市辖区",
"value": "231001"
}, {
"label": "东安区",
"value": "231002"
}, {
"label": "阳明区",
"value": "231003"
}, {
"label": "爱民区",
"value": "231004"
}, {
"label": "西安区",
"value": "231005"
}, {
"label": "林口县",
"value": "231025"
}, {
"label": "绥芬河市",
"value": "231081"
}, {
"label": "海林市",
"value": "231083"
}, {
"label": "宁安市",
"value": "231084"
}, {
"label": "穆棱市",
"value": "231085"
}, {
"label": "东宁市",
"value": "231086"
}],
[{
"label": "市辖区",
"value": "231101"
}, {
"label": "爱辉区",
"value": "231102"
}, {
"label": "嫩江县",
"value": "231121"
}, {
"label": "逊克县",
"value": "231123"
}, {
"label": "孙吴县",
"value": "231124"
}, {
"label": "北安市",
"value": "231181"
}, {
"label": "五大连池市",
"value": "231182"
}],
[{
"label": "市辖区",
"value": "231201"
}, {
"label": "北林区",
"value": "231202"
}, {
"label": "望奎县",
"value": "231221"
}, {
"label": "兰西县",
"value": "231222"
}, {
"label": "青冈县",
"value": "231223"
}, {
"label": "庆安县",
"value": "231224"
}, {
"label": "明水县",
"value": "231225"
}, {
"label": "绥棱县",
"value": "231226"
}, {
"label": "安达市",
"value": "231281"
}, {
"label": "肇东市",
"value": "231282"
}, {
"label": "海伦市",
"value": "231283"
}],
[{
"label": "呼玛县",
"value": "232721"
}, {
"label": "塔河县",
"value": "232722"
}, {
"label": "漠河县",
"value": "232723"
}]
],
[
[{
"label": "黄浦区",
"value": "310101"
}, {
"label": "徐汇区",
"value": "310104"
}, {
"label": "长宁区",
"value": "310105"
}, {
"label": "静安区",
"value": "310106"
}, {
"label": "普陀区",
"value": "310107"
}, {
"label": "虹口区",
"value": "310109"
}, {
"label": "杨浦区",
"value": "310110"
}, {
"label": "闵行区",
"value": "310112"
}, {
"label": "宝山区",
"value": "310113"
}, {
"label": "嘉定区",
"value": "310114"
}, {
"label": "浦东新区",
"value": "310115"
}, {
"label": "金山区",
"value": "310116"
}, {
"label": "松江区",
"value": "310117"
}, {
"label": "青浦区",
"value": "310118"
}, {
"label": "奉贤区",
"value": "310120"
}, {
"label": "崇明区",
"value": "310151"
}]
],
[
[{
"label": "市辖区",
"value": "320101"
}, {
"label": "玄武区",
"value": "320102"
}, {
"label": "秦淮区",
"value": "320104"
}, {
"label": "建邺区",
"value": "320105"
}, {
"label": "鼓楼区",
"value": "320106"
}, {
"label": "浦口区",
"value": "320111"
}, {
"label": "栖霞区",
"value": "320113"
}, {
"label": "雨花台区",
"value": "320114"
}, {
"label": "江宁区",
"value": "320115"
}, {
"label": "六合区",
"value": "320116"
}, {
"label": "溧水区",
"value": "320117"
}, {
"label": "高淳区",
"value": "320118"
}],
[{
"label": "市辖区",
"value": "320201"
}, {
"label": "锡山区",
"value": "320205"
}, {
"label": "惠山区",
"value": "320206"
}, {
"label": "滨湖区",
"value": "320211"
}, {
"label": "梁溪区",
"value": "320213"
}, {
"label": "新吴区",
"value": "320214"
}, {
"label": "江阴市",
"value": "320281"
}, {
"label": "宜兴市",
"value": "320282"
}],
[{
"label": "市辖区",
"value": "320301"
}, {
"label": "鼓楼区",
"value": "320302"
}, {
"label": "云龙区",
"value": "320303"
}, {
"label": "贾汪区",
"value": "320305"
}, {
"label": "泉山区",
"value": "320311"
}, {
"label": "铜山区",
"value": "320312"
}, {
"label": "丰县",
"value": "320321"
}, {
"label": "沛县",
"value": "320322"
}, {
"label": "睢宁县",
"value": "320324"
}, {
"label": "新沂市",
"value": "320381"
}, {
"label": "邳州市",
"value": "320382"
}],
[{
"label": "市辖区",
"value": "320401"
}, {
"label": "天宁区",
"value": "320402"
}, {
"label": "钟楼区",
"value": "320404"
}, {
"label": "新北区",
"value": "320411"
}, {
"label": "武进区",
"value": "320412"
}, {
"label": "金坛区",
"value": "320413"
}, {
"label": "溧阳市",
"value": "320481"
}],
[{
"label": "市辖区",
"value": "320501"
}, {
"label": "虎丘区",
"value": "320505"
}, {
"label": "吴中区",
"value": "320506"
}, {
"label": "相城区",
"value": "320507"
}, {
"label": "姑苏区",
"value": "320508"
}, {
"label": "吴江区",
"value": "320509"
}, {
"label": "常熟市",
"value": "320581"
}, {
"label": "张家港市",
"value": "320582"
}, {
"label": "昆山市",
"value": "320583"
}, {
"label": "太仓市",
"value": "320585"
}],
[{
"label": "市辖区",
"value": "320601"
}, {
"label": "崇川区",
"value": "320602"
}, {
"label": "港闸区",
"value": "320611"
}, {
"label": "通州区",
"value": "320612"
}, {
"label": "海安县",
"value": "320621"
}, {
"label": "如东县",
"value": "320623"
}, {
"label": "启东市",
"value": "320681"
}, {
"label": "如皋市",
"value": "320682"
}, {
"label": "海门市",
"value": "320684"
}],
[{
"label": "市辖区",
"value": "320701"
}, {
"label": "连云区",
"value": "320703"
}, {
"label": "海州区",
"value": "320706"
}, {
"label": "赣榆区",
"value": "320707"
}, {
"label": "东海县",
"value": "320722"
}, {
"label": "灌云县",
"value": "320723"
}, {
"label": "灌南县",
"value": "320724"
}],
[{
"label": "市辖区",
"value": "320801"
}, {
"label": "淮安区",
"value": "320803"
}, {
"label": "淮阴区",
"value": "320804"
}, {
"label": "清江浦区",
"value": "320812"
}, {
"label": "洪泽区",
"value": "320813"
}, {
"label": "涟水县",
"value": "320826"
}, {
"label": "盱眙县",
"value": "320830"
}, {
"label": "金湖县",
"value": "320831"
}],
[{
"label": "市辖区",
"value": "320901"
}, {
"label": "亭湖区",
"value": "320902"
}, {
"label": "盐都区",
"value": "320903"
}, {
"label": "大丰区",
"value": "320904"
}, {
"label": "响水县",
"value": "320921"
}, {
"label": "滨海县",
"value": "320922"
}, {
"label": "阜宁县",
"value": "320923"
}, {
"label": "射阳县",
"value": "320924"
}, {
"label": "建湖县",
"value": "320925"
}, {
"label": "东台市",
"value": "320981"
}],
[{
"label": "市辖区",
"value": "321001"
}, {
"label": "广陵区",
"value": "321002"
}, {
"label": "邗江区",
"value": "321003"
}, {
"label": "江都区",
"value": "321012"
}, {
"label": "宝应县",
"value": "321023"
}, {
"label": "仪征市",
"value": "321081"
}, {
"label": "高邮市",
"value": "321084"
}],
[{
"label": "市辖区",
"value": "321101"
}, {
"label": "京口区",
"value": "321102"
}, {
"label": "润州区",
"value": "321111"
}, {
"label": "丹徒区",
"value": "321112"
}, {
"label": "丹阳市",
"value": "321181"
}, {
"label": "扬中市",
"value": "321182"
}, {
"label": "句容市",
"value": "321183"
}],
[{
"label": "市辖区",
"value": "321201"
}, {
"label": "海陵区",
"value": "321202"
}, {
"label": "高港区",
"value": "321203"
}, {
"label": "姜堰区",
"value": "321204"
}, {
"label": "兴化市",
"value": "321281"
}, {
"label": "靖江市",
"value": "321282"
}, {
"label": "泰兴市",
"value": "321283"
}],
[{
"label": "市辖区",
"value": "321301"
}, {
"label": "宿城区",
"value": "321302"
}, {
"label": "宿豫区",
"value": "321311"
}, {
"label": "沭阳县",
"value": "321322"
}, {
"label": "泗阳县",
"value": "321323"
}, {
"label": "泗洪县",
"value": "321324"
}]
],
[
[{
"label": "市辖区",
"value": "330101"
}, {
"label": "上城区",
"value": "330102"
}, {
"label": "下城区",
"value": "330103"
}, {
"label": "江干区",
"value": "330104"
}, {
"label": "拱墅区",
"value": "330105"
}, {
"label": "西湖区",
"value": "330106"
}, {
"label": "滨江区",
"value": "330108"
}, {
"label": "萧山区",
"value": "330109"
}, {
"label": "余杭区",
"value": "330110"
}, {
"label": "富阳区",
"value": "330111"
}, {
"label": "桐庐县",
"value": "330122"
}, {
"label": "淳安县",
"value": "330127"
}, {
"label": "建德市",
"value": "330182"
}, {
"label": "临安市",
"value": "330185"
}, {
"label": "富阳市",
"value": "920001"
}],
[{
"label": "市辖区",
"value": "330201"
}, {
"label": "海曙区",
"value": "330203"
}, {
"label": "江东区",
"value": "330204"
}, {
"label": "江北区",
"value": "330205"
}, {
"label": "北仑区",
"value": "330206"
}, {
"label": "镇海区",
"value": "330211"
}, {
"label": "鄞州区",
"value": "330212"
}, {
"label": "象山县",
"value": "330225"
}, {
"label": "宁海县",
"value": "330226"
}, {
"label": "余姚市",
"value": "330281"
}, {
"label": "慈溪市",
"value": "330282"
}, {
"label": "奉化市",
"value": "330283"
}],
[{
"label": "市辖区",
"value": "330301"
}, {
"label": "鹿城区",
"value": "330302"
}, {
"label": "龙湾区",
"value": "330303"
}, {
"label": "瓯海区",
"value": "330304"
}, {
"label": "洞头区",
"value": "330305"
}, {
"label": "永嘉县",
"value": "330324"
}, {
"label": "平阳县",
"value": "330326"
}, {
"label": "苍南县",
"value": "330327"
}, {
"label": "文成县",
"value": "330328"
}, {
"label": "泰顺县",
"value": "330329"
}, {
"label": "瑞安市",
"value": "330381"
}, {
"label": "乐清市",
"value": "330382"
}],
[{
"label": "市辖区",
"value": "330401"
}, {
"label": "南湖区",
"value": "330402"
}, {
"label": "秀洲区",
"value": "330411"
}, {
"label": "嘉善县",
"value": "330421"
}, {
"label": "海盐县",
"value": "330424"
}, {
"label": "海宁市",
"value": "330481"
}, {
"label": "平湖市",
"value": "330482"
}, {
"label": "桐乡市",
"value": "330483"
}],
[{
"label": "市辖区",
"value": "330501"
}, {
"label": "吴兴区",
"value": "330502"
}, {
"label": "南浔区",
"value": "330503"
}, {
"label": "德清县",
"value": "330521"
}, {
"label": "长兴县",
"value": "330522"
}, {
"label": "安吉县",
"value": "330523"
}],
[{
"label": "市辖区",
"value": "330601"
}, {
"label": "越城区",
"value": "330602"
}, {
"label": "柯桥区",
"value": "330603"
}, {
"label": "上虞区",
"value": "330604"
}, {
"label": "新昌县",
"value": "330624"
}, {
"label": "诸暨市",
"value": "330681"
}, {
"label": "嵊州市",
"value": "330683"
}],
[{
"label": "市辖区",
"value": "330701"
}, {
"label": "婺城区",
"value": "330702"
}, {
"label": "金东区",
"value": "330703"
}, {
"label": "武义县",
"value": "330723"
}, {
"label": "浦江县",
"value": "330726"
}, {
"label": "磐安县",
"value": "330727"
}, {
"label": "兰溪市",
"value": "330781"
}, {
"label": "义乌市",
"value": "330782"
}, {
"label": "东阳市",
"value": "330783"
}, {
"label": "永康市",
"value": "330784"
}],
[{
"label": "市辖区",
"value": "330801"
}, {
"label": "柯城区",
"value": "330802"
}, {
"label": "衢江区",
"value": "330803"
}, {
"label": "常山县",
"value": "330822"
}, {
"label": "开化县",
"value": "330824"
}, {
"label": "龙游县",
"value": "330825"
}, {
"label": "江山市",
"value": "330881"
}],
[{
"label": "市辖区",
"value": "330901"
}, {
"label": "定海区",
"value": "330902"
}, {
"label": "普陀区",
"value": "330903"
}, {
"label": "岱山县",
"value": "330921"
}, {
"label": "嵊泗县",
"value": "330922"
}],
[{
"label": "市辖区",
"value": "331001"
}, {
"label": "椒江区",
"value": "331002"
}, {
"label": "黄岩区",
"value": "331003"
}, {
"label": "路桥区",
"value": "331004"
}, {
"label": "玉环县",
"value": "331021"
}, {
"label": "三门县",
"value": "331022"
}, {
"label": "天台县",
"value": "331023"
}, {
"label": "仙居县",
"value": "331024"
}, {
"label": "温岭市",
"value": "331081"
}, {
"label": "临海市",
"value": "331082"
}],
[{
"label": "市辖区",
"value": "331101"
}, {
"label": "莲都区",
"value": "331102"
}, {
"label": "青田县",
"value": "331121"
}, {
"label": "缙云县",
"value": "331122"
}, {
"label": "遂昌县",
"value": "331123"
}, {
"label": "松阳县",
"value": "331124"
}, {
"label": "云和县",
"value": "331125"
}, {
"label": "庆元县",
"value": "331126"
}, {
"label": "景宁畲族自治县",
"value": "331127"
}, {
"label": "龙泉市",
"value": "331181"
}]
],
[
[{
"label": "市辖区",
"value": "340101"
}, {
"label": "瑶海区",
"value": "340102"
}, {
"label": "庐阳区",
"value": "340103"
}, {
"label": "蜀山区",
"value": "340104"
}, {
"label": "包河区",
"value": "340111"
}, {
"label": "长丰县",
"value": "340121"
}, {
"label": "肥东县",
"value": "340122"
}, {
"label": "肥西县",
"value": "340123"
}, {
"label": "庐江县",
"value": "340124"
}, {
"label": "巢湖市",
"value": "340181"
}],
[{
"label": "市辖区",
"value": "340201"
}, {
"label": "镜湖区",
"value": "340202"
}, {
"label": "弋江区",
"value": "340203"
}, {
"label": "鸠江区",
"value": "340207"
}, {
"label": "三山区",
"value": "340208"
}, {
"label": "芜湖县",
"value": "340221"
}, {
"label": "繁昌县",
"value": "340222"
}, {
"label": "南陵县",
"value": "340223"
}, {
"label": "无为县",
"value": "340225"
}],
[{
"label": "市辖区",
"value": "340301"
}, {
"label": "龙子湖区",
"value": "340302"
}, {
"label": "蚌山区",
"value": "340303"
}, {
"label": "禹会区",
"value": "340304"
}, {
"label": "淮上区",
"value": "340311"
}, {
"label": "怀远县",
"value": "340321"
}, {
"label": "五河县",
"value": "340322"
}, {
"label": "固镇县",
"value": "340323"
}],
[{
"label": "市辖区",
"value": "340401"
}, {
"label": "大通区",
"value": "340402"
}, {
"label": "田家庵区",
"value": "340403"
}, {
"label": "谢家集区",
"value": "340404"
}, {
"label": "八公山区",
"value": "340405"
}, {
"label": "潘集区",
"value": "340406"
}, {
"label": "凤台县",
"value": "340421"
}, {
"label": "寿县",
"value": "340422"
}],
[{
"label": "市辖区",
"value": "340501"
}, {
"label": "花山区",
"value": "340503"
}, {
"label": "雨山区",
"value": "340504"
}, {
"label": "博望区",
"value": "340506"
}, {
"label": "当涂县",
"value": "340521"
}, {
"label": "含山县",
"value": "340522"
}, {
"label": "和县",
"value": "340523"
}],
[{
"label": "市辖区",
"value": "340601"
}, {
"label": "杜集区",
"value": "340602"
}, {
"label": "相山区",
"value": "340603"
}, {
"label": "烈山区",
"value": "340604"
}, {
"label": "濉溪县",
"value": "340621"
}],
[{
"label": "市辖区",
"value": "340701"
}, {
"label": "铜官区",
"value": "340705"
}, {
"label": "义安区",
"value": "340706"
}, {
"label": "郊区",
"value": "340711"
}, {
"label": "枞阳县",
"value": "340722"
}],
[{
"label": "市辖区",
"value": "340801"
}, {
"label": "迎江区",
"value": "340802"
}, {
"label": "大观区",
"value": "340803"
}, {
"label": "宜秀区",
"value": "340811"
}, {
"label": "怀宁县",
"value": "340822"
}, {
"label": "潜山县",
"value": "340824"
}, {
"label": "太湖县",
"value": "340825"
}, {
"label": "宿松县",
"value": "340826"
}, {
"label": "望江县",
"value": "340827"
}, {
"label": "岳西县",
"value": "340828"
}, {
"label": "桐城市",
"value": "340881"
}],
[{
"label": "市辖区",
"value": "341001"
}, {
"label": "屯溪区",
"value": "341002"
}, {
"label": "黄山区",
"value": "341003"
}, {
"label": "徽州区",
"value": "341004"
}, {
"label": "歙县",
"value": "341021"
}, {
"label": "休宁县",
"value": "341022"
}, {
"label": "黟县",
"value": "341023"
}, {
"label": "祁门县",
"value": "341024"
}],
[{
"label": "市辖区",
"value": "341101"
}, {
"label": "琅琊区",
"value": "341102"
}, {
"label": "南谯区",
"value": "341103"
}, {
"label": "来安县",
"value": "341122"
}, {
"label": "全椒县",
"value": "341124"
}, {
"label": "定远县",
"value": "341125"
}, {
"label": "凤阳县",
"value": "341126"
}, {
"label": "天长市",
"value": "341181"
}, {
"label": "明光市",
"value": "341182"
}],
[{
"label": "市辖区",
"value": "341201"
}, {
"label": "颍州区",
"value": "341202"
}, {
"label": "颍东区",
"value": "341203"
}, {
"label": "颍泉区",
"value": "341204"
}, {
"label": "临泉县",
"value": "341221"
}, {
"label": "太和县",
"value": "341222"
}, {
"label": "阜南县",
"value": "341225"
}, {
"label": "颍上县",
"value": "341226"
}, {
"label": "界首市",
"value": "341282"
}],
[{
"label": "市辖区",
"value": "341301"
}, {
"label": "埇桥区",
"value": "341302"
}, {
"label": "砀山县",
"value": "341321"
}, {
"label": "萧县",
"value": "341322"
}, {
"label": "灵璧县",
"value": "341323"
}, {
"label": "泗县",
"value": "341324"
}],
[{
"label": "市辖区",
"value": "341501"
}, {
"label": "金安区",
"value": "341502"
}, {
"label": "裕安区",
"value": "341503"
}, {
"label": "叶集区",
"value": "341504"
}, {
"label": "霍邱县",
"value": "341522"
}, {
"label": "舒城县",
"value": "341523"
}, {
"label": "金寨县",
"value": "341524"
}, {
"label": "霍山县",
"value": "341525"
}],
[{
"label": "市辖区",
"value": "341601"
}, {
"label": "谯城区",
"value": "341602"
}, {
"label": "涡阳县",
"value": "341621"
}, {
"label": "蒙城县",
"value": "341622"
}, {
"label": "利辛县",
"value": "341623"
}],
[{
"label": "市辖区",
"value": "341701"
}, {
"label": "贵池区",
"value": "341702"
}, {
"label": "东至县",
"value": "341721"
}, {
"label": "石台县",
"value": "341722"
}, {
"label": "青阳县",
"value": "341723"
}],
[{
"label": "市辖区",
"value": "341801"
}, {
"label": "宣州区",
"value": "341802"
}, {
"label": "郎溪县",
"value": "341821"
}, {
"label": "广德县",
"value": "341822"
}, {
"label": "泾县",
"value": "341823"
}, {
"label": "绩溪县",
"value": "341824"
}, {
"label": "旌德县",
"value": "341825"
}, {
"label": "宁国市",
"value": "341881"
}]
],
[
[{
"label": "市辖区",
"value": "350101"
}, {
"label": "鼓楼区",
"value": "350102"
}, {
"label": "台江区",
"value": "350103"
}, {
"label": "仓山区",
"value": "350104"
}, {
"label": "马尾区",
"value": "350105"
}, {
"label": "晋安区",
"value": "350111"
}, {
"label": "闽侯县",
"value": "350121"
}, {
"label": "连江县",
"value": "350122"
}, {
"label": "罗源县",
"value": "350123"
}, {
"label": "闽清县",
"value": "350124"
}, {
"label": "永泰县",
"value": "350125"
}, {
"label": "平潭县",
"value": "350128"
}, {
"label": "福清市",
"value": "350181"
}, {
"label": "长乐市",
"value": "350182"
}],
[{
"label": "市辖区",
"value": "350201"
}, {
"label": "思明区",
"value": "350203"
}, {
"label": "海沧区",
"value": "350205"
}, {
"label": "湖里区",
"value": "350206"
}, {
"label": "集美区",
"value": "350211"
}, {
"label": "同安区",
"value": "350212"
}, {
"label": "翔安区",
"value": "350213"
}],
[{
"label": "市辖区",
"value": "350301"
}, {
"label": "城厢区",
"value": "350302"
}, {
"label": "涵江区",
"value": "350303"
}, {
"label": "荔城区",
"value": "350304"
}, {
"label": "秀屿区",
"value": "350305"
}, {
"label": "仙游县",
"value": "350322"
}],
[{
"label": "市辖区",
"value": "350401"
}, {
"label": "梅列区",
"value": "350402"
}, {
"label": "三元区",
"value": "350403"
}, {
"label": "明溪县",
"value": "350421"
}, {
"label": "清流县",
"value": "350423"
}, {
"label": "宁化县",
"value": "350424"
}, {
"label": "大田县",
"value": "350425"
}, {
"label": "尤溪县",
"value": "350426"
}, {
"label": "沙县",
"value": "350427"
}, {
"label": "将乐县",
"value": "350428"
}, {
"label": "泰宁县",
"value": "350429"
}, {
"label": "建宁县",
"value": "350430"
}, {
"label": "永安市",
"value": "350481"
}],
[{
"label": "市辖区",
"value": "350501"
}, {
"label": "鲤城区",
"value": "350502"
}, {
"label": "丰泽区",
"value": "350503"
}, {
"label": "洛江区",
"value": "350504"
}, {
"label": "泉港区",
"value": "350505"
}, {
"label": "惠安县",
"value": "350521"
}, {
"label": "安溪县",
"value": "350524"
}, {
"label": "永春县",
"value": "350525"
}, {
"label": "德化县",
"value": "350526"
}, {
"label": "金门县",
"value": "350527"
}, {
"label": "石狮市",
"value": "350581"
}, {
"label": "晋江市",
"value": "350582"
}, {
"label": "南安市",
"value": "350583"
}],
[{
"label": "市辖区",
"value": "350601"
}, {
"label": "芗城区",
"value": "350602"
}, {
"label": "龙文区",
"value": "350603"
}, {
"label": "云霄县",
"value": "350622"
}, {
"label": "漳浦县",
"value": "350623"
}, {
"label": "诏安县",
"value": "350624"
}, {
"label": "长泰县",
"value": "350625"
}, {
"label": "东山县",
"value": "350626"
}, {
"label": "南靖县",
"value": "350627"
}, {
"label": "平和县",
"value": "350628"
}, {
"label": "华安县",
"value": "350629"
}, {
"label": "龙海市",
"value": "350681"
}],
[{
"label": "市辖区",
"value": "350701"
}, {
"label": "延平区",
"value": "350702"
}, {
"label": "建阳区",
"value": "350703"
}, {
"label": "顺昌县",
"value": "350721"
}, {
"label": "浦城县",
"value": "350722"
}, {
"label": "光泽县",
"value": "350723"
}, {
"label": "松溪县",
"value": "350724"
}, {
"label": "政和县",
"value": "350725"
}, {
"label": "邵武市",
"value": "350781"
}, {
"label": "武夷山市",
"value": "350782"
}, {
"label": "建瓯市",
"value": "350783"
}],
[{
"label": "市辖区",
"value": "350801"
}, {
"label": "新罗区",
"value": "350802"
}, {
"label": "永定区",
"value": "350803"
}, {
"label": "长汀县",
"value": "350821"
}, {
"label": "上杭县",
"value": "350823"
}, {
"label": "武平县",
"value": "350824"
}, {
"label": "连城县",
"value": "350825"
}, {
"label": "漳平市",
"value": "350881"
}],
[{
"label": "市辖区",
"value": "350901"
}, {
"label": "蕉城区",
"value": "350902"
}, {
"label": "霞浦县",
"value": "350921"
}, {
"label": "古田县",
"value": "350922"
}, {
"label": "屏南县",
"value": "350923"
}, {
"label": "寿宁县",
"value": "350924"
}, {
"label": "周宁县",
"value": "350925"
}, {
"label": "柘荣县",
"value": "350926"
}, {
"label": "福安市",
"value": "350981"
}, {
"label": "福鼎市",
"value": "350982"
}]
],
[
[{
"label": "市辖区",
"value": "360101"
}, {
"label": "东湖区",
"value": "360102"
}, {
"label": "西湖区",
"value": "360103"
}, {
"label": "青云谱区",
"value": "360104"
}, {
"label": "湾里区",
"value": "360105"
}, {
"label": "青山湖区",
"value": "360111"
}, {
"label": "新建区",
"value": "360112"
}, {
"label": "南昌县",
"value": "360121"
}, {
"label": "安义县",
"value": "360123"
}, {
"label": "进贤县",
"value": "360124"
}],
[{
"label": "市辖区",
"value": "360201"
}, {
"label": "昌江区",
"value": "360202"
}, {
"label": "珠山区",
"value": "360203"
}, {
"label": "浮梁县",
"value": "360222"
}, {
"label": "乐平市",
"value": "360281"
}],
[{
"label": "市辖区",
"value": "360301"
}, {
"label": "安源区",
"value": "360302"
}, {
"label": "湘东区",
"value": "360313"
}, {
"label": "莲花县",
"value": "360321"
}, {
"label": "上栗县",
"value": "360322"
}, {
"label": "芦溪县",
"value": "360323"
}],
[{
"label": "市辖区",
"value": "360401"
}, {
"label": "濂溪区",
"value": "360402"
}, {
"label": "浔阳区",
"value": "360403"
}, {
"label": "九江县",
"value": "360421"
}, {
"label": "武宁县",
"value": "360423"
}, {
"label": "修水县",
"value": "360424"
}, {
"label": "永修县",
"value": "360425"
}, {
"label": "德安县",
"value": "360426"
}, {
"label": "都昌县",
"value": "360428"
}, {
"label": "湖口县",
"value": "360429"
}, {
"label": "彭泽县",
"value": "360430"
}, {
"label": "瑞昌市",
"value": "360481"
}, {
"label": "共青城市",
"value": "360482"
}, {
"label": "庐山市",
"value": "360483"
}],
[{
"label": "市辖区",
"value": "360501"
}, {
"label": "渝水区",
"value": "360502"
}, {
"label": "分宜县",
"value": "360521"
}],
[{
"label": "市辖区",
"value": "360601"
}, {
"label": "月湖区",
"value": "360602"
}, {
"label": "余江县",
"value": "360622"
}, {
"label": "贵溪市",
"value": "360681"
}],
[{
"label": "市辖区",
"value": "360701"
}, {
"label": "章贡区",
"value": "360702"
}, {
"label": "南康区",
"value": "360703"
}, {
"label": "赣县",
"value": "360721"
}, {
"label": "信丰县",
"value": "360722"
}, {
"label": "大余县",
"value": "360723"
}, {
"label": "上犹县",
"value": "360724"
}, {
"label": "崇义县",
"value": "360725"
}, {
"label": "安远县",
"value": "360726"
}, {
"label": "龙南县",
"value": "360727"
}, {
"label": "定南县",
"value": "360728"
}, {
"label": "全南县",
"value": "360729"
}, {
"label": "宁都县",
"value": "360730"
}, {
"label": "于都县",
"value": "360731"
}, {
"label": "兴国县",
"value": "360732"
}, {
"label": "会昌县",
"value": "360733"
}, {
"label": "寻乌县",
"value": "360734"
}, {
"label": "石城县",
"value": "360735"
}, {
"label": "瑞金市",
"value": "360781"
}],
[{
"label": "市辖区",
"value": "360801"
}, {
"label": "吉州区",
"value": "360802"
}, {
"label": "青原区",
"value": "360803"
}, {
"label": "吉安县",
"value": "360821"
}, {
"label": "吉水县",
"value": "360822"
}, {
"label": "峡江县",
"value": "360823"
}, {
"label": "新干县",
"value": "360824"
}, {
"label": "永丰县",
"value": "360825"
}, {
"label": "泰和县",
"value": "360826"
}, {
"label": "遂川县",
"value": "360827"
}, {
"label": "万安县",
"value": "360828"
}, {
"label": "安福县",
"value": "360829"
}, {
"label": "永新县",
"value": "360830"
}, {
"label": "井冈山市",
"value": "360881"
}],
[{
"label": "市辖区",
"value": "360901"
}, {
"label": "袁州区",
"value": "360902"
}, {
"label": "奉新县",
"value": "360921"
}, {
"label": "万载县",
"value": "360922"
}, {
"label": "上高县",
"value": "360923"
}, {
"label": "宜丰县",
"value": "360924"
}, {
"label": "靖安县",
"value": "360925"
}, {
"label": "铜鼓县",
"value": "360926"
}, {
"label": "丰城市",
"value": "360981"
}, {
"label": "樟树市",
"value": "360982"
}, {
"label": "高安市",
"value": "360983"
}],
[{
"label": "市辖区",
"value": "361001"
}, {
"label": "临川区",
"value": "361002"
}, {
"label": "南城县",
"value": "361021"
}, {
"label": "黎川县",
"value": "361022"
}, {
"label": "南丰县",
"value": "361023"
}, {
"label": "崇仁县",
"value": "361024"
}, {
"label": "乐安县",
"value": "361025"
}, {
"label": "宜黄县",
"value": "361026"
}, {
"label": "金溪县",
"value": "361027"
}, {
"label": "资溪县",
"value": "361028"
}, {
"label": "东乡县",
"value": "361029"
}, {
"label": "广昌县",
"value": "361030"
}],
[{
"label": "市辖区",
"value": "361101"
}, {
"label": "信州区",
"value": "361102"
}, {
"label": "广丰区",
"value": "361103"
}, {
"label": "上饶县",
"value": "361121"
}, {
"label": "玉山县",
"value": "361123"
}, {
"label": "铅山县",
"value": "361124"
}, {
"label": "横峰县",
"value": "361125"
}, {
"label": "弋阳县",
"value": "361126"
}, {
"label": "余干县",
"value": "361127"
}, {
"label": "鄱阳县",
"value": "361128"
}, {
"label": "万年县",
"value": "361129"
}, {
"label": "婺源县",
"value": "361130"
}, {
"label": "德兴市",
"value": "361181"
}]
],
[
[{
"label": "市辖区",
"value": "370101"
}, {
"label": "历下区",
"value": "370102"
}, {
"label": "市中区",
"value": "370103"
}, {
"label": "槐荫区",
"value": "370104"
}, {
"label": "天桥区",
"value": "370105"
}, {
"label": "历城区",
"value": "370112"
}, {
"label": "长清区",
"value": "370113"
}, {
"label": "平阴县",
"value": "370124"
}, {
"label": "济阳县",
"value": "370125"
}, {
"label": "商河县",
"value": "370126"
}, {
"label": "章丘市",
"value": "370181"
}],
[{
"label": "市辖区",
"value": "370201"
}, {
"label": "市南区",
"value": "370202"
}, {
"label": "市北区",
"value": "370203"
}, {
"label": "黄岛区",
"value": "370211"
}, {
"label": "崂山区",
"value": "370212"
}, {
"label": "李沧区",
"value": "370213"
}, {
"label": "城阳区",
"value": "370214"
}, {
"label": "胶州市",
"value": "370281"
}, {
"label": "即墨市",
"value": "370282"
}, {
"label": "平度市",
"value": "370283"
}, {
"label": "莱西市",
"value": "370285"
}],
[{
"label": "市辖区",
"value": "370301"
}, {
"label": "淄川区",
"value": "370302"
}, {
"label": "张店区",
"value": "370303"
}, {
"label": "博山区",
"value": "370304"
}, {
"label": "临淄区",
"value": "370305"
}, {
"label": "周村区",
"value": "370306"
}, {
"label": "桓台县",
"value": "370321"
}, {
"label": "高青县",
"value": "370322"
}, {
"label": "沂源县",
"value": "370323"
}],
[{
"label": "市辖区",
"value": "370401"
}, {
"label": "市中区",
"value": "370402"
}, {
"label": "薛城区",
"value": "370403"
}, {
"label": "峄城区",
"value": "370404"
}, {
"label": "台儿庄区",
"value": "370405"
}, {
"label": "山亭区",
"value": "370406"
}, {
"label": "滕州市",
"value": "370481"
}],
[{
"label": "市辖区",
"value": "370501"
}, {
"label": "东营区",
"value": "370502"
}, {
"label": "河口区",
"value": "370503"
}, {
"label": "垦利区",
"value": "370505"
}, {
"label": "利津县",
"value": "370522"
}, {
"label": "广饶县",
"value": "370523"
}],
[{
"label": "市辖区",
"value": "370601"
}, {
"label": "芝罘区",
"value": "370602"
}, {
"label": "福山区",
"value": "370611"
}, {
"label": "牟平区",
"value": "370612"
}, {
"label": "莱山区",
"value": "370613"
}, {
"label": "长岛县",
"value": "370634"
}, {
"label": "龙口市",
"value": "370681"
}, {
"label": "莱阳市",
"value": "370682"
}, {
"label": "莱州市",
"value": "370683"
}, {
"label": "蓬莱市",
"value": "370684"
}, {
"label": "招远市",
"value": "370685"
}, {
"label": "栖霞市",
"value": "370686"
}, {
"label": "海阳市",
"value": "370687"
}],
[{
"label": "市辖区",
"value": "370701"
}, {
"label": "潍城区",
"value": "370702"
}, {
"label": "寒亭区",
"value": "370703"
}, {
"label": "坊子区",
"value": "370704"
}, {
"label": "奎文区",
"value": "370705"
}, {
"label": "临朐县",
"value": "370724"
}, {
"label": "昌乐县",
"value": "370725"
}, {
"label": "青州市",
"value": "370781"
}, {
"label": "诸城市",
"value": "370782"
}, {
"label": "寿光市",
"value": "370783"
}, {
"label": "安丘市",
"value": "370784"
}, {
"label": "高密市",
"value": "370785"
}, {
"label": "昌邑市",
"value": "370786"
}],
[{
"label": "市辖区",
"value": "370801"
}, {
"label": "任城区",
"value": "370811"
}, {
"label": "兖州区",
"value": "370812"
}, {
"label": "微山县",
"value": "370826"
}, {
"label": "鱼台县",
"value": "370827"
}, {
"label": "金乡县",
"value": "370828"
}, {
"label": "嘉祥县",
"value": "370829"
}, {
"label": "汶上县",
"value": "370830"
}, {
"label": "泗水县",
"value": "370831"
}, {
"label": "梁山县",
"value": "370832"
}, {
"label": "曲阜市",
"value": "370881"
}, {
"label": "邹城市",
"value": "370883"
}],
[{
"label": "市辖区",
"value": "370901"
}, {
"label": "泰山区",
"value": "370902"
}, {
"label": "岱岳区",
"value": "370911"
}, {
"label": "宁阳县",
"value": "370921"
}, {
"label": "东平县",
"value": "370923"
}, {
"label": "新泰市",
"value": "370982"
}, {
"label": "肥城市",
"value": "370983"
}],
[{
"label": "市辖区",
"value": "371001"
}, {
"label": "环翠区",
"value": "371002"
}, {
"label": "文登区",
"value": "371003"
}, {
"label": "荣成市",
"value": "371082"
}, {
"label": "乳山市",
"value": "371083"
}],
[{
"label": "市辖区",
"value": "371101"
}, {
"label": "东港区",
"value": "371102"
}, {
"label": "岚山区",
"value": "371103"
}, {
"label": "五莲县",
"value": "371121"
}, {
"label": "莒县",
"value": "371122"
}],
[{
"label": "市辖区",
"value": "371201"
}, {
"label": "莱城区",
"value": "371202"
}, {
"label": "钢城区",
"value": "371203"
}],
[{
"label": "市辖区",
"value": "371301"
}, {
"label": "兰山区",
"value": "371302"
}, {
"label": "罗庄区",
"value": "371311"
}, {
"label": "河东区",
"value": "371312"
}, {
"label": "沂南县",
"value": "371321"
}, {
"label": "郯城县",
"value": "371322"
}, {
"label": "沂水县",
"value": "371323"
}, {
"label": "兰陵县",
"value": "371324"
}, {
"label": "费县",
"value": "371325"
}, {
"label": "平邑县",
"value": "371326"
}, {
"label": "莒南县",
"value": "371327"
}, {
"label": "蒙阴县",
"value": "371328"
}, {
"label": "临沭县",
"value": "371329"
}],
[{
"label": "市辖区",
"value": "371401"
}, {
"label": "德城区",
"value": "371402"
}, {
"label": "陵城区",
"value": "371403"
}, {
"label": "宁津县",
"value": "371422"
}, {
"label": "庆云县",
"value": "371423"
}, {
"label": "临邑县",
"value": "371424"
}, {
"label": "齐河县",
"value": "371425"
}, {
"label": "平原县",
"value": "371426"
}, {
"label": "夏津县",
"value": "371427"
}, {
"label": "武城县",
"value": "371428"
}, {
"label": "乐陵市",
"value": "371481"
}, {
"label": "禹城市",
"value": "371482"
}],
[{
"label": "市辖区",
"value": "371501"
}, {
"label": "东昌府区",
"value": "371502"
}, {
"label": "阳谷县",
"value": "371521"
}, {
"label": "莘县",
"value": "371522"
}, {
"label": "茌平县",
"value": "371523"
}, {
"label": "东阿县",
"value": "371524"
}, {
"label": "冠县",
"value": "371525"
}, {
"label": "高唐县",
"value": "371526"
}, {
"label": "临清市",
"value": "371581"
}],
[{
"label": "市辖区",
"value": "371601"
}, {
"label": "滨城区",
"value": "371602"
}, {
"label": "沾化区",
"value": "371603"
}, {
"label": "惠民县",
"value": "371621"
}, {
"label": "阳信县",
"value": "371622"
}, {
"label": "无棣县",
"value": "371623"
}, {
"label": "博兴县",
"value": "371625"
}, {
"label": "邹平县",
"value": "371626"
}],
[{
"label": "市辖区",
"value": "371701"
}, {
"label": "牡丹区",
"value": "371702"
}, {
"label": "定陶区",
"value": "371703"
}, {
"label": "曹县",
"value": "371721"
}, {
"label": "单县",
"value": "371722"
}, {
"label": "成武县",
"value": "371723"
}, {
"label": "巨野县",
"value": "371724"
}, {
"label": "郓城县",
"value": "371725"
}, {
"label": "鄄城县",
"value": "371726"
}, {
"label": "东明县",
"value": "371728"
}]
],
[
[{
"label": "市辖区",
"value": "410101"
}, {
"label": "中原区",
"value": "410102"
}, {
"label": "二七区",
"value": "410103"
}, {
"label": "管城回族区",
"value": "410104"
}, {
"label": "金水区",
"value": "410105"
}, {
"label": "上街区",
"value": "410106"
}, {
"label": "惠济区",
"value": "410108"
}, {
"label": "中牟县",
"value": "410122"
}, {
"label": "巩义市",
"value": "410181"
}, {
"label": "荥阳市",
"value": "410182"
}, {
"label": "新密市",
"value": "410183"
}, {
"label": "新郑市",
"value": "410184"
}, {
"label": "登封市",
"value": "410185"
}, {
"label": "郑东新区",
"value": "920002"
}],
[{
"label": "市辖区",
"value": "410201"
}, {
"label": "龙亭区",
"value": "410202"
}, {
"label": "顺河回族区",
"value": "410203"
}, {
"label": "鼓楼区",
"value": "410204"
}, {
"label": "禹王台区",
"value": "410205"
}, {
"label": "金明区",
"value": "410211"
}, {
"label": "祥符区",
"value": "410212"
}, {
"label": "杞县",
"value": "410221"
}, {
"label": "通许县",
"value": "410222"
}, {
"label": "尉氏县",
"value": "410223"
}, {
"label": "兰考县",
"value": "410225"
}],
[{
"label": "市辖区",
"value": "410301"
}, {
"label": "老城区",
"value": "410302"
}, {
"label": "西工区",
"value": "410303"
}, {
"label": "瀍河回族区",
"value": "410304"
}, {
"label": "涧西区",
"value": "410305"
}, {
"label": "吉利区",
"value": "410306"
}, {
"label": "洛龙区",
"value": "410311"
}, {
"label": "孟津县",
"value": "410322"
}, {
"label": "新安县",
"value": "410323"
}, {
"label": "栾川县",
"value": "410324"
}, {
"label": "嵩县",
"value": "410325"
}, {
"label": "汝阳县",
"value": "410326"
}, {
"label": "宜阳县",
"value": "410327"
}, {
"label": "洛宁县",
"value": "410328"
}, {
"label": "伊川县",
"value": "410329"
}, {
"label": "偃师市",
"value": "410381"
}],
[{
"label": "市辖区",
"value": "410401"
}, {
"label": "新华区",
"value": "410402"
}, {
"label": "卫东区",
"value": "410403"
}, {
"label": "石龙区",
"value": "410404"
}, {
"label": "湛河区",
"value": "410411"
}, {
"label": "宝丰县",
"value": "410421"
}, {
"label": "叶县",
"value": "410422"
}, {
"label": "鲁山县",
"value": "410423"
}, {
"label": "郏县",
"value": "410425"
}, {
"label": "舞钢市",
"value": "410481"
}, {
"label": "汝州市",
"value": "410482"
}],
[{
"label": "市辖区",
"value": "410501"
}, {
"label": "文峰区",
"value": "410502"
}, {
"label": "北关区",
"value": "410503"
}, {
"label": "殷都区",
"value": "410505"
}, {
"label": "龙安区",
"value": "410506"
}, {
"label": "安阳县",
"value": "410522"
}, {
"label": "汤阴县",
"value": "410523"
}, {
"label": "滑县",
"value": "410526"
}, {
"label": "内黄县",
"value": "410527"
}, {
"label": "林州市",
"value": "410581"
}],
[{
"label": "市辖区",
"value": "410601"
}, {
"label": "鹤山区",
"value": "410602"
}, {
"label": "山城区",
"value": "410603"
}, {
"label": "淇滨区",
"value": "410611"
}, {
"label": "浚县",
"value": "410621"
}, {
"label": "淇县",
"value": "410622"
}],
[{
"label": "市辖区",
"value": "410701"
}, {
"label": "红旗区",
"value": "410702"
}, {
"label": "卫滨区",
"value": "410703"
}, {
"label": "凤泉区",
"value": "410704"
}, {
"label": "牧野区",
"value": "410711"
}, {
"label": "新乡县",
"value": "410721"
}, {
"label": "获嘉县",
"value": "410724"
}, {
"label": "原阳县",
"value": "410725"
}, {
"label": "延津县",
"value": "410726"
}, {
"label": "封丘县",
"value": "410727"
}, {
"label": "长垣县",
"value": "410728"
}, {
"label": "卫辉市",
"value": "410781"
}, {
"label": "辉县市",
"value": "410782"
}],
[{
"label": "市辖区",
"value": "410801"
}, {
"label": "解放区",
"value": "410802"
}, {
"label": "中站区",
"value": "410803"
}, {
"label": "马村区",
"value": "410804"
}, {
"label": "山阳区",
"value": "410811"
}, {
"label": "修武县",
"value": "410821"
}, {
"label": "博爱县",
"value": "410822"
}, {
"label": "武陟县",
"value": "410823"
}, {
"label": "温县",
"value": "410825"
}, {
"label": "沁阳市",
"value": "410882"
}, {
"label": "孟州市",
"value": "410883"
}],
[{
"label": "市辖区",
"value": "410901"
}, {
"label": "华龙区",
"value": "410902"
}, {
"label": "清丰县",
"value": "410922"
}, {
"label": "南乐县",
"value": "410923"
}, {
"label": "范县",
"value": "410926"
}, {
"label": "台前县",
"value": "410927"
}, {
"label": "濮阳县",
"value": "410928"
}],
[{
"label": "市辖区",
"value": "411001"
}, {
"label": "魏都区",
"value": "411002"
}, {
"label": "许昌县",
"value": "411023"
}, {
"label": "鄢陵县",
"value": "411024"
}, {
"label": "襄城县",
"value": "411025"
}, {
"label": "禹州市",
"value": "411081"
}, {
"label": "长葛市",
"value": "411082"
}],
[{
"label": "市辖区",
"value": "411101"
}, {
"label": "源汇区",
"value": "411102"
}, {
"label": "郾城区",
"value": "411103"
}, {
"label": "召陵区",
"value": "411104"
}, {
"label": "舞阳县",
"value": "411121"
}, {
"label": "临颍县",
"value": "411122"
}],
[{
"label": "市辖区",
"value": "411201"
}, {
"label": "湖滨区",
"value": "411202"
}, {
"label": "陕州区",
"value": "411203"
}, {
"label": "渑池县",
"value": "411221"
}, {
"label": "卢氏县",
"value": "411224"
}, {
"label": "义马市",
"value": "411281"
}, {
"label": "灵宝市",
"value": "411282"
}],
[{
"label": "市辖区",
"value": "411301"
}, {
"label": "宛城区",
"value": "411302"
}, {
"label": "卧龙区",
"value": "411303"
}, {
"label": "南召县",
"value": "411321"
}, {
"label": "方城县",
"value": "411322"
}, {
"label": "西峡县",
"value": "411323"
}, {
"label": "镇平县",
"value": "411324"
}, {
"label": "内乡县",
"value": "411325"
}, {
"label": "淅川县",
"value": "411326"
}, {
"label": "社旗县",
"value": "411327"
}, {
"label": "唐河县",
"value": "411328"
}, {
"label": "新野县",
"value": "411329"
}, {
"label": "桐柏县",
"value": "411330"
}, {
"label": "邓州市",
"value": "411381"
}],
[{
"label": "市辖区",
"value": "411401"
}, {
"label": "梁园区",
"value": "411402"
}, {
"label": "睢阳区",
"value": "411403"
}, {
"label": "民权县",
"value": "411421"
}, {
"label": "睢县",
"value": "411422"
}, {
"label": "宁陵县",
"value": "411423"
}, {
"label": "柘城县",
"value": "411424"
}, {
"label": "虞城县",
"value": "411425"
}, {
"label": "夏邑县",
"value": "411426"
}, {
"label": "永城市",
"value": "411481"
}],
[{
"label": "市辖区",
"value": "411501"
}, {
"label": "浉河区",
"value": "411502"
}, {
"label": "平桥区",
"value": "411503"
}, {
"label": "罗山县",
"value": "411521"
}, {
"label": "光山县",
"value": "411522"
}, {
"label": "新县",
"value": "411523"
}, {
"label": "商城县",
"value": "411524"
}, {
"label": "固始县",
"value": "411525"
}, {
"label": "潢川县",
"value": "411526"
}, {
"label": "淮滨县",
"value": "411527"
}, {
"label": "息县",
"value": "411528"
}],
[{
"label": "市辖区",
"value": "411601"
}, {
"label": "川汇区",
"value": "411602"
}, {
"label": "扶沟县",
"value": "411621"
}, {
"label": "西华县",
"value": "411622"
}, {
"label": "商水县",
"value": "411623"
}, {
"label": "沈丘县",
"value": "411624"
}, {
"label": "郸城县",
"value": "411625"
}, {
"label": "淮阳县",
"value": "411626"
}, {
"label": "太康县",
"value": "411627"
}, {
"label": "鹿邑县",
"value": "411628"
}, {
"label": "项城市",
"value": "411681"
}],
[{
"label": "市辖区",
"value": "411701"
}, {
"label": "驿城区",
"value": "411702"
}, {
"label": "西平县",
"value": "411721"
}, {
"label": "上蔡县",
"value": "411722"
}, {
"label": "平舆县",
"value": "411723"
}, {
"label": "正阳县",
"value": "411724"
}, {
"label": "确山县",
"value": "411725"
}, {
"label": "泌阳县",
"value": "411726"
}, {
"label": "汝南县",
"value": "411727"
}, {
"label": "遂平县",
"value": "411728"
}, {
"label": "新蔡县",
"value": "411729"
}],
[{
"label": "市辖区",
"value": "419001"
}]
],
[
[{
"label": "市辖区",
"value": "420101"
}, {
"label": "江岸区",
"value": "420102"
}, {
"label": "江汉区",
"value": "420103"
}, {
"label": "硚口区",
"value": "420104"
}, {
"label": "汉阳区",
"value": "420105"
}, {
"label": "武昌区",
"value": "420106"
}, {
"label": "青山区",
"value": "420107"
}, {
"label": "洪山区",
"value": "420111"
}, {
"label": "东西湖区",
"value": "420112"
}, {
"label": "汉南区",
"value": "420113"
}, {
"label": "蔡甸区",
"value": "420114"
}, {
"label": "江夏区",
"value": "420115"
}, {
"label": "黄陂区",
"value": "420116"
}, {
"label": "新洲区",
"value": "420117"
}],
[{
"label": "市辖区",
"value": "420201"
}, {
"label": "黄石港区",
"value": "420202"
}, {
"label": "西塞山区",
"value": "420203"
}, {
"label": "下陆区",
"value": "420204"
}, {
"label": "铁山区",
"value": "420205"
}, {
"label": "阳新县",
"value": "420222"
}, {
"label": "大冶市",
"value": "420281"
}],
[{
"label": "市辖区",
"value": "420301"
}, {
"label": "茅箭区",
"value": "420302"
}, {
"label": "张湾区",
"value": "420303"
}, {
"label": "郧阳区",
"value": "420304"
}, {
"label": "郧西县",
"value": "420322"
}, {
"label": "竹山县",
"value": "420323"
}, {
"label": "竹溪县",
"value": "420324"
}, {
"label": "房县",
"value": "420325"
}, {
"label": "丹江口市",
"value": "420381"
}],
[{
"label": "市辖区",
"value": "420501"
}, {
"label": "西陵区",
"value": "420502"
}, {
"label": "伍家岗区",
"value": "420503"
}, {
"label": "点军区",
"value": "420504"
}, {
"label": "猇亭区",
"value": "420505"
}, {
"label": "夷陵区",
"value": "420506"
}, {
"label": "远安县",
"value": "420525"
}, {
"label": "兴山县",
"value": "420526"
}, {
"label": "秭归县",
"value": "420527"
}, {
"label": "长阳土家族自治县",
"value": "420528"
}, {
"label": "五峰土家族自治县",
"value": "420529"
}, {
"label": "宜都市",
"value": "420581"
}, {
"label": "当阳市",
"value": "420582"
}, {
"label": "枝江市",
"value": "420583"
}],
[{
"label": "市辖区",
"value": "420601"
}, {
"label": "襄城区",
"value": "420602"
}, {
"label": "樊城区",
"value": "420606"
}, {
"label": "襄州区",
"value": "420607"
}, {
"label": "南漳县",
"value": "420624"
}, {
"label": "谷城县",
"value": "420625"
}, {
"label": "保康县",
"value": "420626"
}, {
"label": "老河口市",
"value": "420682"
}, {
"label": "枣阳市",
"value": "420683"
}, {
"label": "宜城市",
"value": "420684"
}],
[{
"label": "市辖区",
"value": "420701"
}, {
"label": "梁子湖区",
"value": "420702"
}, {
"label": "华容区",
"value": "420703"
}, {
"label": "鄂城区",
"value": "420704"
}],
[{
"label": "市辖区",
"value": "420801"
}, {
"label": "东宝区",
"value": "420802"
}, {
"label": "掇刀区",
"value": "420804"
}, {
"label": "京山县",
"value": "420821"
}, {
"label": "沙洋县",
"value": "420822"
}, {
"label": "钟祥市",
"value": "420881"
}],
[{
"label": "市辖区",
"value": "420901"
}, {
"label": "孝南区",
"value": "420902"
}, {
"label": "孝昌县",
"value": "420921"
}, {
"label": "大悟县",
"value": "420922"
}, {
"label": "云梦县",
"value": "420923"
}, {
"label": "应城市",
"value": "420981"
}, {
"label": "安陆市",
"value": "420982"
}, {
"label": "汉川市",
"value": "420984"
}],
[{
"label": "市辖区",
"value": "421001"
}, {
"label": "沙市区",
"value": "421002"
}, {
"label": "荆州区",
"value": "421003"
}, {
"label": "公安县",
"value": "421022"
}, {
"label": "监利县",
"value": "421023"
}, {
"label": "江陵县",
"value": "421024"
}, {
"label": "石首市",
"value": "421081"
}, {
"label": "洪湖市",
"value": "421083"
}, {
"label": "松滋市",
"value": "421087"
}],
[{
"label": "市辖区",
"value": "421101"
}, {
"label": "黄州区",
"value": "421102"
}, {
"label": "团风县",
"value": "421121"
}, {
"label": "红安县",
"value": "421122"
}, {
"label": "罗田县",
"value": "421123"
}, {
"label": "英山县",
"value": "421124"
}, {
"label": "浠水县",
"value": "421125"
}, {
"label": "蕲春县",
"value": "421126"
}, {
"label": "黄梅县",
"value": "421127"
}, {
"label": "麻城市",
"value": "421181"
}, {
"label": "武穴市",
"value": "421182"
}],
[{
"label": "市辖区",
"value": "421201"
}, {
"label": "咸安区",
"value": "421202"
}, {
"label": "嘉鱼县",
"value": "421221"
}, {
"label": "通城县",
"value": "421222"
}, {
"label": "崇阳县",
"value": "421223"
}, {
"label": "通山县",
"value": "421224"
}, {
"label": "赤壁市",
"value": "421281"
}],
[{
"label": "市辖区",
"value": "421301"
}, {
"label": "曾都区",
"value": "421303"
}, {
"label": "随县",
"value": "421321"
}, {
"label": "广水市",
"value": "421381"
}],
[{
"label": "市辖区",
"value": "422801"
}, {
"label": "利川市",
"value": "422802"
}, {
"label": "建始县",
"value": "422822"
}, {
"label": "巴东县",
"value": "422823"
}, {
"label": "宣恩县",
"value": "422825"
}, {
"label": "咸丰县",
"value": "422826"
}, {
"label": "来凤县",
"value": "422827"
}, {
"label": "鹤峰县",
"value": "422828"
}],
[{
"label": "仙桃市",
"value": "429004"
}, {
"label": "潜江市",
"value": "429005"
}, {
"label": "天门市",
"value": "429006"
}, {
"label": "神农架林区",
"value": "429021"
}]
],
[
[{
"label": "市辖区",
"value": "430101"
}, {
"label": "芙蓉区",
"value": "430102"
}, {
"label": "天心区",
"value": "430103"
}, {
"label": "岳麓区",
"value": "430104"
}, {
"label": "开福区",
"value": "430105"
}, {
"label": "雨花区",
"value": "430111"
}, {
"label": "望城区",
"value": "430112"
}, {
"label": "长沙县",
"value": "430121"
}, {
"label": "宁乡县",
"value": "430124"
}, {
"label": "浏阳市",
"value": "430181"
}],
[{
"label": "市辖区",
"value": "430201"
}, {
"label": "荷塘区",
"value": "430202"
}, {
"label": "芦淞区",
"value": "430203"
}, {
"label": "石峰区",
"value": "430204"
}, {
"label": "天元区",
"value": "430211"
}, {
"label": "株洲县",
"value": "430221"
}, {
"label": "攸县",
"value": "430223"
}, {
"label": "茶陵县",
"value": "430224"
}, {
"label": "炎陵县",
"value": "430225"
}, {
"label": "醴陵市",
"value": "430281"
}],
[{
"label": "市辖区",
"value": "430301"
}, {
"label": "雨湖区",
"value": "430302"
}, {
"label": "岳塘区",
"value": "430304"
}, {
"label": "湘潭县",
"value": "430321"
}, {
"label": "湘乡市",
"value": "430381"
}, {
"label": "韶山市",
"value": "430382"
}],
[{
"label": "市辖区",
"value": "430401"
}, {
"label": "珠晖区",
"value": "430405"
}, {
"label": "雁峰区",
"value": "430406"
}, {
"label": "石鼓区",
"value": "430407"
}, {
"label": "蒸湘区",
"value": "430408"
}, {
"label": "南岳区",
"value": "430412"
}, {
"label": "衡阳县",
"value": "430421"
}, {
"label": "衡南县",
"value": "430422"
}, {
"label": "衡山县",
"value": "430423"
}, {
"label": "衡东县",
"value": "430424"
}, {
"label": "祁东县",
"value": "430426"
}, {
"label": "耒阳市",
"value": "430481"
}, {
"label": "常宁市",
"value": "430482"
}],
[{
"label": "市辖区",
"value": "430501"
}, {
"label": "双清区",
"value": "430502"
}, {
"label": "大祥区",
"value": "430503"
}, {
"label": "北塔区",
"value": "430511"
}, {
"label": "邵东县",
"value": "430521"
}, {
"label": "新邵县",
"value": "430522"
}, {
"label": "邵阳县",
"value": "430523"
}, {
"label": "隆回县",
"value": "430524"
}, {
"label": "洞口县",
"value": "430525"
}, {
"label": "绥宁县",
"value": "430527"
}, {
"label": "新宁县",
"value": "430528"
}, {
"label": "城步苗族自治县",
"value": "430529"
}, {
"label": "武冈市",
"value": "430581"
}],
[{
"label": "市辖区",
"value": "430601"
}, {
"label": "岳阳楼区",
"value": "430602"
}, {
"label": "云溪区",
"value": "430603"
}, {
"label": "君山区",
"value": "430611"
}, {
"label": "岳阳县",
"value": "430621"
}, {
"label": "华容县",
"value": "430623"
}, {
"label": "湘阴县",
"value": "430624"
}, {
"label": "平江县",
"value": "430626"
}, {
"label": "汨罗市",
"value": "430681"
}, {
"label": "临湘市",
"value": "430682"
}],
[{
"label": "市辖区",
"value": "430701"
}, {
"label": "武陵区",
"value": "430702"
}, {
"label": "鼎城区",
"value": "430703"
}, {
"label": "安乡县",
"value": "430721"
}, {
"label": "汉寿县",
"value": "430722"
}, {
"label": "澧县",
"value": "430723"
}, {
"label": "临澧县",
"value": "430724"
}, {
"label": "桃源县",
"value": "430725"
}, {
"label": "石门县",
"value": "430726"
}, {
"label": "津市市",
"value": "430781"
}],
[{
"label": "市辖区",
"value": "430801"
}, {
"label": "永定区",
"value": "430802"
}, {
"label": "武陵源区",
"value": "430811"
}, {
"label": "慈利县",
"value": "430821"
}, {
"label": "桑植县",
"value": "430822"
}],
[{
"label": "市辖区",
"value": "430901"
}, {
"label": "资阳区",
"value": "430902"
}, {
"label": "赫山区",
"value": "430903"
}, {
"label": "南县",
"value": "430921"
}, {
"label": "桃江县",
"value": "430922"
}, {
"label": "安化县",
"value": "430923"
}, {
"label": "沅江市",
"value": "430981"
}],
[{
"label": "市辖区",
"value": "431001"
}, {
"label": "北湖区",
"value": "431002"
}, {
"label": "苏仙区",
"value": "431003"
}, {
"label": "桂阳县",
"value": "431021"
}, {
"label": "宜章县",
"value": "431022"
}, {
"label": "永兴县",
"value": "431023"
}, {
"label": "嘉禾县",
"value": "431024"
}, {
"label": "临武县",
"value": "431025"
}, {
"label": "汝城县",
"value": "431026"
}, {
"label": "桂东县",
"value": "431027"
}, {
"label": "安仁县",
"value": "431028"
}, {
"label": "资兴市",
"value": "431081"
}],
[{
"label": "市辖区",
"value": "431101"
}, {
"label": "零陵区",
"value": "431102"
}, {
"label": "冷水滩区",
"value": "431103"
}, {
"label": "祁阳县",
"value": "431121"
}, {
"label": "东安县",
"value": "431122"
}, {
"label": "双牌县",
"value": "431123"
}, {
"label": "道县",
"value": "431124"
}, {
"label": "江永县",
"value": "431125"
}, {
"label": "宁远县",
"value": "431126"
}, {
"label": "蓝山县",
"value": "431127"
}, {
"label": "新田县",
"value": "431128"
}, {
"label": "江华瑶族自治县",
"value": "431129"
}],
[{
"label": "市辖区",
"value": "431201"
}, {
"label": "鹤城区",
"value": "431202"
}, {
"label": "中方县",
"value": "431221"
}, {
"label": "沅陵县",
"value": "431222"
}, {
"label": "辰溪县",
"value": "431223"
}, {
"label": "溆浦县",
"value": "431224"
}, {
"label": "会同县",
"value": "431225"
}, {
"label": "麻阳苗族自治县",
"value": "431226"
}, {
"label": "新晃侗族自治县",
"value": "431227"
}, {
"label": "芷江侗族自治县",
"value": "431228"
}, {
"label": "靖州苗族侗族自治县",
"value": "431229"
}, {
"label": "通道侗族自治县",
"value": "431230"
}, {
"label": "洪江市",
"value": "431281"
}],
[{
"label": "市辖区",
"value": "431301"
}, {
"label": "娄星区",
"value": "431302"
}, {
"label": "双峰县",
"value": "431321"
}, {
"label": "新化县",
"value": "431322"
}, {
"label": "冷水江市",
"value": "431381"
}, {
"label": "涟源市",
"value": "431382"
}],
[{
"label": "市辖区",
"value": "433101"
}, {
"label": "泸溪县",
"value": "433122"
}, {
"label": "凤凰县",
"value": "433123"
}, {
"label": "花垣县",
"value": "433124"
}, {
"label": "保靖县",
"value": "433125"
}, {
"label": "古丈县",
"value": "433126"
}, {
"label": "永顺县",
"value": "433127"
}, {
"label": "龙山县",
"value": "433130"
}]
], {
"0": [{
"label": "市辖区",
"value": "440101"
}, {
"label": "荔湾区",
"value": "440103"
}, {
"label": "越秀区",
"value": "440104"
}, {
"label": "海珠区",
"value": "440105"
}, {
"label": "天河区",
"value": "440106"
}, {
"label": "白云区",
"value": "440111"
}, {
"label": "黄埔区",
"value": "440112"
}, {
"label": "番禺区",
"value": "440113"
}, {
"label": "花都区",
"value": "440114"
}, {
"label": "南沙区",
"value": "440115"
}, {
"label": "从化区",
"value": "440117"
}, {
"label": "增城区",
"value": "440118"
}, {
"label": "萝岗区",
"value": "920003"
}],
"1": [{
"label": "市辖区",
"value": "440201"
}, {
"label": "武江区",
"value": "440203"
}, {
"label": "浈江区",
"value": "440204"
}, {
"label": "曲江区",
"value": "440205"
}, {
"label": "始兴县",
"value": "440222"
}, {
"label": "仁化县",
"value": "440224"
}, {
"label": "翁源县",
"value": "440229"
}, {
"label": "乳源瑶族自治县",
"value": "440232"
}, {
"label": "新丰县",
"value": "440233"
}, {
"label": "乐昌市",
"value": "440281"
}, {
"label": "南雄市",
"value": "440282"
}],
"2": [{
"label": "市辖区",
"value": "440301"
}, {
"label": "罗湖区",
"value": "440303"
}, {
"label": "福田区",
"value": "440304"
}, {
"label": "南山区",
"value": "440305"
}, {
"label": "宝安区",
"value": "440306"
}, {
"label": "龙岗区",
"value": "440307"
}, {
"label": "盐田区",
"value": "440308"
}],
"3": [{
"label": "市辖区",
"value": "440401"
}, {
"label": "香洲区",
"value": "440402"
}, {
"label": "斗门区",
"value": "440403"
}, {
"label": "金湾区",
"value": "440404"
}],
"4": [{
"label": "市辖区",
"value": "440501"
}, {
"label": "龙湖区",
"value": "440507"
}, {
"label": "金平区",
"value": "440511"
}, {
"label": "濠江区",
"value": "440512"
}, {
"label": "潮阳区",
"value": "440513"
}, {
"label": "潮南区",
"value": "440514"
}, {
"label": "澄海区",
"value": "440515"
}, {
"label": "南澳县",
"value": "440523"
}],
"5": [{
"label": "市辖区",
"value": "440601"
}, {
"label": "禅城区",
"value": "440604"
}, {
"label": "南海区",
"value": "440605"
}, {
"label": "顺德区",
"value": "440606"
}, {
"label": "三水区",
"value": "440607"
}, {
"label": "高明区",
"value": "440608"
}],
"6": [{
"label": "市辖区",
"value": "440701"
}, {
"label": "蓬江区",
"value": "440703"
}, {
"label": "江海区",
"value": "440704"
}, {
"label": "新会区",
"value": "440705"
}, {
"label": "台山市",
"value": "440781"
}, {
"label": "开平市",
"value": "440783"
}, {
"label": "鹤山市",
"value": "440784"
}, {
"label": "恩平市",
"value": "440785"
}],
"7": [{
"label": "市辖区",
"value": "440801"
}, {
"label": "赤坎区",
"value": "440802"
}, {
"label": "霞山区",
"value": "440803"
}, {
"label": "坡头区",
"value": "440804"
}, {
"label": "麻章区",
"value": "440811"
}, {
"label": "遂溪县",
"value": "440823"
}, {
"label": "徐闻县",
"value": "440825"
}, {
"label": "廉江市",
"value": "440881"
}, {
"label": "雷州市",
"value": "440882"
}, {
"label": "吴川市",
"value": "440883"
}],
"8": [{
"label": "市辖区",
"value": "440901"
}, {
"label": "茂南区",
"value": "440902"
}, {
"label": "电白区",
"value": "440904"
}, {
"label": "高州市",
"value": "440981"
}, {
"label": "化州市",
"value": "440982"
}, {
"label": "信宜市",
"value": "440983"
}],
"9": [{
"label": "市辖区",
"value": "441201"
}, {
"label": "端州区",
"value": "441202"
}, {
"label": "鼎湖区",
"value": "441203"
}, {
"label": "高要区",
"value": "441204"
}, {
"label": "广宁县",
"value": "441223"
}, {
"label": "怀集县",
"value": "441224"
}, {
"label": "封开县",
"value": "441225"
}, {
"label": "德庆县",
"value": "441226"
}, {
"label": "四会市",
"value": "441284"
}],
"10": [{
"label": "市辖区",
"value": "441301"
}, {
"label": "惠城区",
"value": "441302"
}, {
"label": "惠阳区",
"value": "441303"
}, {
"label": "博罗县",
"value": "441322"
}, {
"label": "惠东县",
"value": "441323"
}, {
"label": "龙门县",
"value": "441324"
}],
"11": [{
"label": "市辖区",
"value": "441401"
}, {
"label": "梅江区",
"value": "441402"
}, {
"label": "梅县区",
"value": "441403"
}, {
"label": "大埔县",
"value": "441422"
}, {
"label": "丰顺县",
"value": "441423"
}, {
"label": "五华县",
"value": "441424"
}, {
"label": "平远县",
"value": "441426"
}, {
"label": "蕉岭县",
"value": "441427"
}, {
"label": "兴宁市",
"value": "441481"
}],
"12": [{
"label": "市辖区",
"value": "441501"
}, {
"label": "城区",
"value": "441502"
}, {
"label": "海丰县",
"value": "441521"
}, {
"label": "陆河县",
"value": "441523"
}, {
"label": "陆丰市",
"value": "441581"
}],
"13": [{
"label": "市辖区",
"value": "441601"
}, {
"label": "源城区",
"value": "441602"
}, {
"label": "紫金县",
"value": "441621"
}, {
"label": "龙川县",
"value": "441622"
}, {
"label": "连平县",
"value": "441623"
}, {
"label": "和平县",
"value": "441624"
}, {
"label": "东源县",
"value": "441625"
}],
"14": [{
"label": "市辖区",
"value": "441701"
}, {
"label": "江城区",
"value": "441702"
}, {
"label": "阳东区",
"value": "441704"
}, {
"label": "阳西县",
"value": "441721"
}, {
"label": "阳春市",
"value": "441781"
}],
"15": [{
"label": "市辖区",
"value": "441801"
}, {
"label": "清城区",
"value": "441802"
}, {
"label": "清新区",
"value": "441803"
}, {
"label": "佛冈县",
"value": "441821"
}, {
"label": "阳山县",
"value": "441823"
}, {
"label": "连山壮族瑶族自治县",
"value": "441825"
}, {
"label": "连南瑶族自治县",
"value": "441826"
}, {
"label": "英德市",
"value": "441881"
}, {
"label": "连州市",
"value": "441882"
}],
"18": [{
"label": "市辖区",
"value": "445101"
}, {
"label": "湘桥区",
"value": "445102"
}, {
"label": "潮安区",
"value": "445103"
}, {
"label": "饶平县",
"value": "445122"
}],
"19": [{
"label": "市辖区",
"value": "445201"
}, {
"label": "榕城区",
"value": "445202"
}, {
"label": "揭东区",
"value": "445203"
}, {
"label": "揭西县",
"value": "445222"
}, {
"label": "惠来县",
"value": "445224"
}, {
"label": "普宁市",
"value": "445281"
}],
"20": [{
"label": "市辖区",
"value": "445301"
}, {
"label": "云城区",
"value": "445302"
}, {
"label": "云安区",
"value": "445303"
}, {
"label": "新兴县",
"value": "445321"
}, {
"label": "郁南县",
"value": "445322"
}, {
"label": "罗定市",
"value": "445381"
}]
},
[
[{
"label": "市辖区",
"value": "450101"
}, {
"label": "兴宁区",
"value": "450102"
}, {
"label": "青秀区",
"value": "450103"
}, {
"label": "江南区",
"value": "450105"
}, {
"label": "西乡塘区",
"value": "450107"
}, {
"label": "良庆区",
"value": "450108"
}, {
"label": "邕宁区",
"value": "450109"
}, {
"label": "武鸣区",
"value": "450110"
}, {
"label": "隆安县",
"value": "450123"
}, {
"label": "马山县",
"value": "450124"
}, {
"label": "上林县",
"value": "450125"
}, {
"label": "宾阳县",
"value": "450126"
}, {
"label": "横县",
"value": "450127"
}],
[{
"label": "市辖区",
"value": "450201"
}, {
"label": "城中区",
"value": "450202"
}, {
"label": "鱼峰区",
"value": "450203"
}, {
"label": "柳南区",
"value": "450204"
}, {
"label": "柳北区",
"value": "450205"
}, {
"label": "柳江区",
"value": "450206"
}, {
"label": "柳城县",
"value": "450222"
}, {
"label": "鹿寨县",
"value": "450223"
}, {
"label": "融安县",
"value": "450224"
}, {
"label": "融水苗族自治县",
"value": "450225"
}, {
"label": "三江侗族自治县",
"value": "450226"
}],
[{
"label": "市辖区",
"value": "450301"
}, {
"label": "秀峰区",
"value": "450302"
}, {
"label": "叠彩区",
"value": "450303"
}, {
"label": "象山区",
"value": "450304"
}, {
"label": "七星区",
"value": "450305"
}, {
"label": "雁山区",
"value": "450311"
}, {
"label": "临桂区",
"value": "450312"
}, {
"label": "阳朔县",
"value": "450321"
}, {
"label": "灵川县",
"value": "450323"
}, {
"label": "全州县",
"value": "450324"
}, {
"label": "兴安县",
"value": "450325"
}, {
"label": "永福县",
"value": "450326"
}, {
"label": "灌阳县",
"value": "450327"
}, {
"label": "龙胜各族自治县",
"value": "450328"
}, {
"label": "资源县",
"value": "450329"
}, {
"label": "平乐县",
"value": "450330"
}, {
"label": "荔浦县",
"value": "450331"
}, {
"label": "恭城瑶族自治县",
"value": "450332"
}],
[{
"label": "市辖区",
"value": "450401"
}, {
"label": "万秀区",
"value": "450403"
}, {
"label": "长洲区",
"value": "450405"
}, {
"label": "龙圩区",
"value": "450406"
}, {
"label": "苍梧县",
"value": "450421"
}, {
"label": "藤县",
"value": "450422"
}, {
"label": "蒙山县",
"value": "450423"
}, {
"label": "岑溪市",
"value": "450481"
}],
[{
"label": "市辖区",
"value": "450501"
}, {
"label": "海城区",
"value": "450502"
}, {
"label": "银海区",
"value": "450503"
}, {
"label": "铁山港区",
"value": "450512"
}, {
"label": "合浦县",
"value": "450521"
}],
[{
"label": "市辖区",
"value": "450601"
}, {
"label": "港口区",
"value": "450602"
}, {
"label": "防城区",
"value": "450603"
}, {
"label": "上思县",
"value": "450621"
}, {
"label": "东兴市",
"value": "450681"
}],
[{
"label": "市辖区",
"value": "450701"
}, {
"label": "钦南区",
"value": "450702"
}, {
"label": "钦北区",
"value": "450703"
}, {
"label": "灵山县",
"value": "450721"
}, {
"label": "浦北县",
"value": "450722"
}],
[{
"label": "市辖区",
"value": "450801"
}, {
"label": "港北区",
"value": "450802"
}, {
"label": "港南区",
"value": "450803"
}, {
"label": "覃塘区",
"value": "450804"
}, {
"label": "平南县",
"value": "450821"
}, {
"label": "桂平市",
"value": "450881"
}],
[{
"label": "市辖区",
"value": "450901"
}, {
"label": "玉州区",
"value": "450902"
}, {
"label": "福绵区",
"value": "450903"
}, {
"label": "容县",
"value": "450921"
}, {
"label": "陆川县",
"value": "450922"
}, {
"label": "博白县",
"value": "450923"
}, {
"label": "兴业县",
"value": "450924"
}, {
"label": "北流市",
"value": "450981"
}],
[{
"label": "市辖区",
"value": "451001"
}, {
"label": "右江区",
"value": "451002"
}, {
"label": "田阳县",
"value": "451021"
}, {
"label": "田东县",
"value": "451022"
}, {
"label": "平果县",
"value": "451023"
}, {
"label": "德保县",
"value": "451024"
}, {
"label": "那坡县",
"value": "451026"
}, {
"label": "凌云县",
"value": "451027"
}, {
"label": "乐业县",
"value": "451028"
}, {
"label": "田林县",
"value": "451029"
}, {
"label": "西林县",
"value": "451030"
}, {
"label": "隆林各族自治县",
"value": "451031"
}, {
"label": "靖西市",
"value": "451081"
}],
[{
"label": "市辖区",
"value": "451101"
}, {
"label": "八步区",
"value": "451102"
}, {
"label": "平桂区",
"value": "451103"
}, {
"label": "昭平县",
"value": "451121"
}, {
"label": "钟山县",
"value": "451122"
}, {
"label": "富川瑶族自治县",
"value": "451123"
}],
[{
"label": "市辖区",
"value": "451201"
}, {
"label": "金城江区",
"value": "451202"
}, {
"label": "南丹县",
"value": "451221"
}, {
"label": "天峨县",
"value": "451222"
}, {
"label": "凤山县",
"value": "451223"
}, {
"label": "东兰县",
"value": "451224"
}, {
"label": "罗城仫佬族自治县",
"value": "451225"
}, {
"label": "环江毛南族自治县",
"value": "451226"
}, {
"label": "巴马瑶族自治县",
"value": "451227"
}, {
"label": "都安瑶族自治县",
"value": "451228"
}, {
"label": "大化瑶族自治县",
"value": "451229"
}, {
"label": "宜州市",
"value": "451281"
}],
[{
"label": "市辖区",
"value": "451301"
}, {
"label": "兴宾区",
"value": "451302"
}, {
"label": "忻城县",
"value": "451321"
}, {
"label": "象州县",
"value": "451322"
}, {
"label": "武宣县",
"value": "451323"
}, {
"label": "金秀瑶族自治县",
"value": "451324"
}, {
"label": "合山市",
"value": "451381"
}],
[{
"label": "市辖区",
"value": "451401"
}, {
"label": "江州区",
"value": "451402"
}, {
"label": "扶绥县",
"value": "451421"
}, {
"label": "宁明县",
"value": "451422"
}, {
"label": "龙州县",
"value": "451423"
}, {
"label": "大新县",
"value": "451424"
}, {
"label": "天等县",
"value": "451425"
}, {
"label": "凭祥市",
"value": "451481"
}]
], {
"0": [{
"label": "市辖区",
"value": "460101"
}, {
"label": "秀英区",
"value": "460105"
}, {
"label": "龙华区",
"value": "460106"
}, {
"label": "琼山区",
"value": "460107"
}, {
"label": "美兰区",
"value": "460108"
}],
"1": [{
"label": "市辖区",
"value": "460201"
}, {
"label": "海棠区",
"value": "460202"
}, {
"label": "吉阳区",
"value": "460203"
}, {
"label": "天涯区",
"value": "460204"
}, {
"label": "崖州区",
"value": "460205"
}],
"4": [{
"label": "市辖区",
"value": "469001"
}, {
"label": "琼海市",
"value": "469002"
}, {
"label": "文昌市",
"value": "469005"
}, {
"label": "万宁市",
"value": "469006"
}, {
"label": "东方市",
"value": "469007"
}, {
"label": "定安县",
"value": "469021"
}, {
"label": "屯昌县",
"value": "469022"
}, {
"label": "澄迈县",
"value": "469023"
}, {
"label": "临高县",
"value": "469024"
}, {
"label": "白沙黎族自治县",
"value": "469025"
}, {
"label": "昌江黎族自治县",
"value": "469026"
}, {
"label": "乐东黎族自治县",
"value": "469027"
}, {
"label": "陵水黎族自治县",
"value": "469028"
}, {
"label": "保亭黎族苗族自治县",
"value": "469029"
}, {
"label": "琼中黎族苗族自治县",
"value": "469030"
}]
},
[
[{
"label": "万州区",
"value": "500101"
}, {
"label": "涪陵区",
"value": "500102"
}, {
"label": "渝中区",
"value": "500103"
}, {
"label": "大渡口区",
"value": "500104"
}, {
"label": "江北区",
"value": "500105"
}, {
"label": "沙坪坝区",
"value": "500106"
}, {
"label": "九龙坡区",
"value": "500107"
}, {
"label": "南岸区",
"value": "500108"
}, {
"label": "北碚区",
"value": "500109"
}, {
"label": "綦江区",
"value": "500110"
}, {
"label": "大足区",
"value": "500111"
}, {
"label": "渝北区",
"value": "500112"
}, {
"label": "巴南区",
"value": "500113"
}, {
"label": "黔江区",
"value": "500114"
}, {
"label": "长寿区",
"value": "500115"
}, {
"label": "江津区",
"value": "500116"
}, {
"label": "合川区",
"value": "500117"
}, {
"label": "永川区",
"value": "500118"
}, {
"label": "南川区",
"value": "500119"
}, {
"label": "璧山区",
"value": "500120"
}, {
"label": "铜梁区",
"value": "500151"
}, {
"label": "潼南区",
"value": "500152"
}, {
"label": "荣昌区",
"value": "500153"
}, {
"label": "开州区",
"value": "500154"
}],
[{
"label": "梁平县",
"value": "500228"
}, {
"label": "城口县",
"value": "500229"
}, {
"label": "丰都县",
"value": "500230"
}, {
"label": "垫江县",
"value": "500231"
}, {
"label": "武隆县",
"value": "500232"
}, {
"label": "忠县",
"value": "500233"
}, {
"label": "云阳县",
"value": "500235"
}, {
"label": "奉节县",
"value": "500236"
}, {
"label": "巫山县",
"value": "500237"
}, {
"label": "巫溪县",
"value": "500238"
}, {
"label": "石柱土家族自治县",
"value": "500240"
}, {
"label": "秀山土家族苗族自治县",
"value": "500241"
}, {
"label": "酉阳土家族苗族自治县",
"value": "500242"
}, {
"label": "彭水苗族土家族自治县",
"value": "500243"
}, {
"label": "静海县",
"value": "920000"
}]
],
[
[{
"label": "市辖区",
"value": "510101"
}, {
"label": "锦江区",
"value": "510104"
}, {
"label": "青羊区",
"value": "510105"
}, {
"label": "金牛区",
"value": "510106"
}, {
"label": "武侯区",
"value": "510107"
}, {
"label": "成华区",
"value": "510108"
}, {
"label": "龙泉驿区",
"value": "510112"
}, {
"label": "青白江区",
"value": "510113"
}, {
"label": "新都区",
"value": "510114"
}, {
"label": "温江区",
"value": "510115"
}, {
"label": "双流区",
"value": "510116"
}, {
"label": "金堂县",
"value": "510121"
}, {
"label": "郫县",
"value": "510124"
}, {
"label": "大邑县",
"value": "510129"
}, {
"label": "蒲江县",
"value": "510131"
}, {
"label": "新津县",
"value": "510132"
}, {
"label": "都江堰市",
"value": "510181"
}, {
"label": "彭州市",
"value": "510182"
}, {
"label": "邛崃市",
"value": "510183"
}, {
"label": "崇州市",
"value": "510184"
}, {
"label": "简阳市",
"value": "510185"
}],
[{
"label": "市辖区",
"value": "510301"
}, {
"label": "自流井区",
"value": "510302"
}, {
"label": "贡井区",
"value": "510303"
}, {
"label": "大安区",
"value": "510304"
}, {
"label": "沿滩区",
"value": "510311"
}, {
"label": "荣县",
"value": "510321"
}, {
"label": "富顺县",
"value": "510322"
}],
[{
"label": "市辖区",
"value": "510401"
}, {
"label": "东区",
"value": "510402"
}, {
"label": "西区",
"value": "510403"
}, {
"label": "仁和区",
"value": "510411"
}, {
"label": "米易县",
"value": "510421"
}, {
"label": "盐边县",
"value": "510422"
}],
[{
"label": "市辖区",
"value": "510501"
}, {
"label": "江阳区",
"value": "510502"
}, {
"label": "纳溪区",
"value": "510503"
}, {
"label": "龙马潭区",
"value": "510504"
}, {
"label": "泸县",
"value": "510521"
}, {
"label": "合江县",
"value": "510522"
}, {
"label": "叙永县",
"value": "510524"
}, {
"label": "古蔺县",
"value": "510525"
}],
[{
"label": "市辖区",
"value": "510601"
}, {
"label": "旌阳区",
"value": "510603"
}, {
"label": "中江县",
"value": "510623"
}, {
"label": "罗江县",
"value": "510626"
}, {
"label": "广汉市",
"value": "510681"
}, {
"label": "什邡市",
"value": "510682"
}, {
"label": "绵竹市",
"value": "510683"
}],
[{
"label": "市辖区",
"value": "510701"
}, {
"label": "涪城区",
"value": "510703"
}, {
"label": "游仙区",
"value": "510704"
}, {
"label": "安州区",
"value": "510705"
}, {
"label": "三台县",
"value": "510722"
}, {
"label": "盐亭县",
"value": "510723"
}, {
"label": "梓潼县",
"value": "510725"
}, {
"label": "北川羌族自治县",
"value": "510726"
}, {
"label": "平武县",
"value": "510727"
}, {
"label": "江油市",
"value": "510781"
}],
[{
"label": "市辖区",
"value": "510801"
}, {
"label": "利州区",
"value": "510802"
}, {
"label": "昭化区",
"value": "510811"
}, {
"label": "朝天区",
"value": "510812"
}, {
"label": "旺苍县",
"value": "510821"
}, {
"label": "青川县",
"value": "510822"
}, {
"label": "剑阁县",
"value": "510823"
}, {
"label": "苍溪县",
"value": "510824"
}],
[{
"label": "市辖区",
"value": "510901"
}, {
"label": "船山区",
"value": "510903"
}, {
"label": "安居区",
"value": "510904"
}, {
"label": "蓬溪县",
"value": "510921"
}, {
"label": "射洪县",
"value": "510922"
}, {
"label": "大英县",
"value": "510923"
}],
[{
"label": "市辖区",
"value": "511001"
}, {
"label": "市中区",
"value": "511002"
}, {
"label": "东兴区",
"value": "511011"
}, {
"label": "威远县",
"value": "511024"
}, {
"label": "资中县",
"value": "511025"
}, {
"label": "隆昌县",
"value": "511028"
}],
[{
"label": "市辖区",
"value": "511101"
}, {
"label": "市中区",
"value": "511102"
}, {
"label": "沙湾区",
"value": "511111"
}, {
"label": "五通桥区",
"value": "511112"
}, {
"label": "金口河区",
"value": "511113"
}, {
"label": "犍为县",
"value": "511123"
}, {
"label": "井研县",
"value": "511124"
}, {
"label": "夹江县",
"value": "511126"
}, {
"label": "沐川县",
"value": "511129"
}, {
"label": "峨边彝族自治县",
"value": "511132"
}, {
"label": "马边彝族自治县",
"value": "511133"
}, {
"label": "峨眉山市",
"value": "511181"
}],
[{
"label": "市辖区",
"value": "511301"
}, {
"label": "顺庆区",
"value": "511302"
}, {
"label": "高坪区",
"value": "511303"
}, {
"label": "嘉陵区",
"value": "511304"
}, {
"label": "南部县",
"value": "511321"
}, {
"label": "营山县",
"value": "511322"
}, {
"label": "蓬安县",
"value": "511323"
}, {
"label": "仪陇县",
"value": "511324"
}, {
"label": "西充县",
"value": "511325"
}, {
"label": "阆中市",
"value": "511381"
}],
[{
"label": "市辖区",
"value": "511401"
}, {
"label": "东坡区",
"value": "511402"
}, {
"label": "彭山区",
"value": "511403"
}, {
"label": "仁寿县",
"value": "511421"
}, {
"label": "洪雅县",
"value": "511423"
}, {
"label": "丹棱县",
"value": "511424"
}, {
"label": "青神县",
"value": "511425"
}],
[{
"label": "市辖区",
"value": "511501"
}, {
"label": "翠屏区",
"value": "511502"
}, {
"label": "南溪区",
"value": "511503"
}, {
"label": "宜宾县",
"value": "511521"
}, {
"label": "江安县",
"value": "511523"
}, {
"label": "长宁县",
"value": "511524"
}, {
"label": "高县",
"value": "511525"
}, {
"label": "珙县",
"value": "511526"
}, {
"label": "筠连县",
"value": "511527"
}, {
"label": "兴文县",
"value": "511528"
}, {
"label": "屏山县",
"value": "511529"
}],
[{
"label": "市辖区",
"value": "511601"
}, {
"label": "广安区",
"value": "511602"
}, {
"label": "前锋区",
"value": "511603"
}, {
"label": "岳池县",
"value": "511621"
}, {
"label": "武胜县",
"value": "511622"
}, {
"label": "邻水县",
"value": "511623"
}, {
"label": "华蓥市",
"value": "511681"
}],
[{
"label": "市辖区",
"value": "511701"
}, {
"label": "通川区",
"value": "511702"
}, {
"label": "达川区",
"value": "511703"
}, {
"label": "宣汉县",
"value": "511722"
}, {
"label": "开江县",
"value": "511723"
}, {
"label": "大竹县",
"value": "511724"
}, {
"label": "渠县",
"value": "511725"
}, {
"label": "万源市",
"value": "511781"
}],
[{
"label": "市辖区",
"value": "511801"
}, {
"label": "雨城区",
"value": "511802"
}, {
"label": "名山区",
"value": "511803"
}, {
"label": "荥经县",
"value": "511822"
}, {
"label": "汉源县",
"value": "511823"
}, {
"label": "石棉县",
"value": "511824"
}, {
"label": "天全县",
"value": "511825"
}, {
"label": "芦山县",
"value": "511826"
}, {
"label": "宝兴县",
"value": "511827"
}],
[{
"label": "市辖区",
"value": "511901"
}, {
"label": "巴州区",
"value": "511902"
}, {
"label": "恩阳区",
"value": "511903"
}, {
"label": "通江县",
"value": "511921"
}, {
"label": "南江县",
"value": "511922"
}, {
"label": "平昌县",
"value": "511923"
}],
[{
"label": "市辖区",
"value": "512001"
}, {
"label": "雁江区",
"value": "512002"
}, {
"label": "安岳县",
"value": "512021"
}, {
"label": "乐至县",
"value": "512022"
}],
[{
"label": "市辖区",
"value": "513201"
}, {
"label": "汶川县",
"value": "513221"
}, {
"label": "理县",
"value": "513222"
}, {
"label": "茂县",
"value": "513223"
}, {
"label": "松潘县",
"value": "513224"
}, {
"label": "九寨沟县",
"value": "513225"
}, {
"label": "金川县",
"value": "513226"
}, {
"label": "小金县",
"value": "513227"
}, {
"label": "黑水县",
"value": "513228"
}, {
"label": "壤塘县",
"value": "513230"
}, {
"label": "阿坝县",
"value": "513231"
}, {
"label": "若尔盖县",
"value": "513232"
}, {
"label": "红原县",
"value": "513233"
}],
[{
"label": "市辖区",
"value": "513301"
}, {
"label": "泸定县",
"value": "513322"
}, {
"label": "丹巴县",
"value": "513323"
}, {
"label": "九龙县",
"value": "513324"
}, {
"label": "雅江县",
"value": "513325"
}, {
"label": "道孚县",
"value": "513326"
}, {
"label": "炉霍县",
"value": "513327"
}, {
"label": "甘孜县",
"value": "513328"
}, {
"label": "新龙县",
"value": "513329"
}, {
"label": "德格县",
"value": "513330"
}, {
"label": "白玉县",
"value": "513331"
}, {
"label": "石渠县",
"value": "513332"
}, {
"label": "色达县",
"value": "513333"
}, {
"label": "理塘县",
"value": "513334"
}, {
"label": "巴塘县",
"value": "513335"
}, {
"label": "乡城县",
"value": "513336"
}, {
"label": "稻城县",
"value": "513337"
}, {
"label": "得荣县",
"value": "513338"
}],
[{
"label": "市辖区",
"value": "513401"
}, {
"label": "木里藏族自治县",
"value": "513422"
}, {
"label": "盐源县",
"value": "513423"
}, {
"label": "德昌县",
"value": "513424"
}, {
"label": "会理县",
"value": "513425"
}, {
"label": "会东县",
"value": "513426"
}, {
"label": "宁南县",
"value": "513427"
}, {
"label": "普格县",
"value": "513428"
}, {
"label": "布拖县",
"value": "513429"
}, {
"label": "金阳县",
"value": "513430"
}, {
"label": "昭觉县",
"value": "513431"
}, {
"label": "喜德县",
"value": "513432"
}, {
"label": "冕宁县",
"value": "513433"
}, {
"label": "越西县",
"value": "513434"
}, {
"label": "甘洛县",
"value": "513435"
}, {
"label": "美姑县",
"value": "513436"
}, {
"label": "雷波县",
"value": "513437"
}]
],
[
[{
"label": "市辖区",
"value": "520101"
}, {
"label": "南明区",
"value": "520102"
}, {
"label": "云岩区",
"value": "520103"
}, {
"label": "花溪区",
"value": "520111"
}, {
"label": "乌当区",
"value": "520112"
}, {
"label": "白云区",
"value": "520113"
}, {
"label": "观山湖区",
"value": "520115"
}, {
"label": "开阳县",
"value": "520121"
}, {
"label": "息烽县",
"value": "520122"
}, {
"label": "修文县",
"value": "520123"
}, {
"label": "清镇市",
"value": "520181"
}],
[{
"label": "钟山区",
"value": "520201"
}, {
"label": "六枝特区",
"value": "520203"
}, {
"label": "水城县",
"value": "520221"
}, {
"label": "盘县",
"value": "520222"
}],
[{
"label": "市辖区",
"value": "520301"
}, {
"label": "红花岗区",
"value": "520302"
}, {
"label": "汇川区",
"value": "520303"
}, {
"label": "播州区",
"value": "520304"
}, {
"label": "桐梓县",
"value": "520322"
}, {
"label": "绥阳县",
"value": "520323"
}, {
"label": "正安县",
"value": "520324"
}, {
"label": "道真仡佬族苗族自治县",
"value": "520325"
}, {
"label": "务川仡佬族苗族自治县",
"value": "520326"
}, {
"label": "凤冈县",
"value": "520327"
}, {
"label": "湄潭县",
"value": "520328"
}, {
"label": "余庆县",
"value": "520329"
}, {
"label": "习水县",
"value": "520330"
}, {
"label": "赤水市",
"value": "520381"
}, {
"label": "仁怀市",
"value": "520382"
}],
[{
"label": "市辖区",
"value": "520401"
}, {
"label": "西秀区",
"value": "520402"
}, {
"label": "平坝区",
"value": "520403"
}, {
"label": "普定县",
"value": "520422"
}, {
"label": "镇宁布依族苗族自治县",
"value": "520423"
}, {
"label": "关岭布依族苗族自治县",
"value": "520424"
}, {
"label": "紫云苗族布依族自治县",
"value": "520425"
}],
[{
"label": "市辖区",
"value": "520501"
}, {
"label": "七星关区",
"value": "520502"
}, {
"label": "大方县",
"value": "520521"
}, {
"label": "黔西县",
"value": "520522"
}, {
"label": "金沙县",
"value": "520523"
}, {
"label": "织金县",
"value": "520524"
}, {
"label": "纳雍县",
"value": "520525"
}, {
"label": "威宁彝族回族苗族自治县",
"value": "520526"
}, {
"label": "赫章县",
"value": "520527"
}],
[{
"label": "市辖区",
"value": "520601"
}, {
"label": "碧江区",
"value": "520602"
}, {
"label": "万山区",
"value": "520603"
}, {
"label": "江口县",
"value": "520621"
}, {
"label": "玉屏侗族自治县",
"value": "520622"
}, {
"label": "石阡县",
"value": "520623"
}, {
"label": "思南县",
"value": "520624"
}, {
"label": "印江土家族苗族自治县",
"value": "520625"
}, {
"label": "德江县",
"value": "520626"
}, {
"label": "沿河土家族自治县",
"value": "520627"
}, {
"label": "松桃苗族自治县",
"value": "520628"
}],
[{
"label": "市辖区",
"value": "522301"
}, {
"label": "兴仁县",
"value": "522322"
}, {
"label": "普安县",
"value": "522323"
}, {
"label": "晴隆县",
"value": "522324"
}, {
"label": "贞丰县",
"value": "522325"
}, {
"label": "望谟县",
"value": "522326"
}, {
"label": "册亨县",
"value": "522327"
}, {
"label": "安龙县",
"value": "522328"
}],
[{
"label": "市辖区",
"value": "522601"
}, {
"label": "黄平县",
"value": "522622"
}, {
"label": "施秉县",
"value": "522623"
}, {
"label": "三穗县",
"value": "522624"
}, {
"label": "镇远县",
"value": "522625"
}, {
"label": "岑巩县",
"value": "522626"
}, {
"label": "天柱县",
"value": "522627"
}, {
"label": "锦屏县",
"value": "522628"
}, {
"label": "剑河县",
"value": "522629"
}, {
"label": "台江县",
"value": "522630"
}, {
"label": "黎平县",
"value": "522631"
}, {
"label": "榕江县",
"value": "522632"
}, {
"label": "从江县",
"value": "522633"
}, {
"label": "雷山县",
"value": "522634"
}, {
"label": "麻江县",
"value": "522635"
}, {
"label": "丹寨县",
"value": "522636"
}],
[{
"label": "市辖区",
"value": "522701"
}, {
"label": "福泉市",
"value": "522702"
}, {
"label": "荔波县",
"value": "522722"
}, {
"label": "贵定县",
"value": "522723"
}, {
"label": "瓮安县",
"value": "522725"
}, {
"label": "独山县",
"value": "522726"
}, {
"label": "平塘县",
"value": "522727"
}, {
"label": "罗甸县",
"value": "522728"
}, {
"label": "长顺县",
"value": "522729"
}, {
"label": "龙里县",
"value": "522730"
}, {
"label": "惠水县",
"value": "522731"
}, {
"label": "三都水族自治县",
"value": "522732"
}]
],
[
[{
"label": "市辖区",
"value": "530101"
}, {
"label": "五华区",
"value": "530102"
}, {
"label": "盘龙区",
"value": "530103"
}, {
"label": "官渡区",
"value": "530111"
}, {
"label": "西山区",
"value": "530112"
}, {
"label": "东川区",
"value": "530113"
}, {
"label": "呈贡区",
"value": "530114"
}, {
"label": "晋宁县",
"value": "530122"
}, {
"label": "富民县",
"value": "530124"
}, {
"label": "宜良县",
"value": "530125"
}, {
"label": "石林彝族自治县",
"value": "530126"
}, {
"label": "嵩明县",
"value": "530127"
}, {
"label": "禄劝彝族苗族自治县",
"value": "530128"
}, {
"label": "寻甸回族彝族自治县",
"value": "530129"
}, {
"label": "安宁市",
"value": "530181"
}],
[{
"label": "市辖区",
"value": "530301"
}, {
"label": "麒麟区",
"value": "530302"
}, {
"label": "沾益区",
"value": "530303"
}, {
"label": "马龙县",
"value": "530321"
}, {
"label": "陆良县",
"value": "530322"
}, {
"label": "师宗县",
"value": "530323"
}, {
"label": "罗平县",
"value": "530324"
}, {
"label": "富源县",
"value": "530325"
}, {
"label": "会泽县",
"value": "530326"
}, {
"label": "宣威市",
"value": "530381"
}],
[{
"label": "市辖区",
"value": "530401"
}, {
"label": "红塔区",
"value": "530402"
}, {
"label": "江川区",
"value": "530403"
}, {
"label": "澄江县",
"value": "530422"
}, {
"label": "通海县",
"value": "530423"
}, {
"label": "华宁县",
"value": "530424"
}, {
"label": "易门县",
"value": "530425"
}, {
"label": "峨山彝族自治县",
"value": "530426"
}, {
"label": "新平彝族傣族自治县",
"value": "530427"
}, {
"label": "元江哈尼族彝族傣族自治县",
"value": "530428"
}],
[{
"label": "市辖区",
"value": "530501"
}, {
"label": "隆阳区",
"value": "530502"
}, {
"label": "施甸县",
"value": "530521"
}, {
"label": "龙陵县",
"value": "530523"
}, {
"label": "昌宁县",
"value": "530524"
}, {
"label": "腾冲市",
"value": "530581"
}],
[{
"label": "市辖区",
"value": "530601"
}, {
"label": "昭阳区",
"value": "530602"
}, {
"label": "鲁甸县",
"value": "530621"
}, {
"label": "巧家县",
"value": "530622"
}, {
"label": "盐津县",
"value": "530623"
}, {
"label": "大关县",
"value": "530624"
}, {
"label": "永善县",
"value": "530625"
}, {
"label": "绥江县",
"value": "530626"
}, {
"label": "镇雄县",
"value": "530627"
}, {
"label": "彝良县",
"value": "530628"
}, {
"label": "威信县",
"value": "530629"
}, {
"label": "水富县",
"value": "530630"
}],
[{
"label": "市辖区",
"value": "530701"
}, {
"label": "古城区",
"value": "530702"
}, {
"label": "玉龙纳西族自治县",
"value": "530721"
}, {
"label": "永胜县",
"value": "530722"
}, {
"label": "华坪县",
"value": "530723"
}, {
"label": "宁蒗彝族自治县",
"value": "530724"
}],
[{
"label": "市辖区",
"value": "530801"
}, {
"label": "思茅区",
"value": "530802"
}, {
"label": "宁洱哈尼族彝族自治县",
"value": "530821"
}, {
"label": "墨江哈尼族自治县",
"value": "530822"
}, {
"label": "景东彝族自治县",
"value": "530823"
}, {
"label": "景谷傣族彝族自治县",
"value": "530824"
}, {
"label": "镇沅彝族哈尼族拉祜族自治县",
"value": "530825"
}, {
"label": "江城哈尼族彝族自治县",
"value": "530826"
}, {
"label": "孟连傣族拉祜族佤族自治县",
"value": "530827"
}, {
"label": "澜沧拉祜族自治县",
"value": "530828"
}, {
"label": "西盟佤族自治县",
"value": "530829"
}],
[{
"label": "市辖区",
"value": "530901"
}, {
"label": "临翔区",
"value": "530902"
}, {
"label": "凤庆县",
"value": "530921"
}, {
"label": "云县",
"value": "530922"
}, {
"label": "永德县",
"value": "530923"
}, {
"label": "镇康县",
"value": "530924"
}, {
"label": "双江拉祜族佤族布朗族傣族自治县",
"value": "530925"
}, {
"label": "耿马傣族佤族自治县",
"value": "530926"
}, {
"label": "沧源佤族自治县",
"value": "530927"
}],
[{
"label": "市辖区",
"value": "532301"
}, {
"label": "双柏县",
"value": "532322"
}, {
"label": "牟定县",
"value": "532323"
}, {
"label": "南华县",
"value": "532324"
}, {
"label": "姚安县",
"value": "532325"
}, {
"label": "大姚县",
"value": "532326"
}, {
"label": "永仁县",
"value": "532327"
}, {
"label": "元谋县",
"value": "532328"
}, {
"label": "武定县",
"value": "532329"
}, {
"label": "禄丰县",
"value": "532331"
}],
[{
"label": "市辖区",
"value": "532501"
}, {
"label": "开远市",
"value": "532502"
}, {
"label": "蒙自市",
"value": "532503"
}, {
"label": "弥勒市",
"value": "532504"
}, {
"label": "屏边苗族自治县",
"value": "532523"
}, {
"label": "建水县",
"value": "532524"
}, {
"label": "石屏县",
"value": "532525"
}, {
"label": "泸西县",
"value": "532527"
}, {
"label": "元阳县",
"value": "532528"
}, {
"label": "红河县",
"value": "532529"
}, {
"label": "金平苗族瑶族傣族自治县",
"value": "532530"
}, {
"label": "绿春县",
"value": "532531"
}, {
"label": "河口瑶族自治县",
"value": "532532"
}],
[{
"label": "市辖区",
"value": "532601"
}, {
"label": "砚山县",
"value": "532622"
}, {
"label": "西畴县",
"value": "532623"
}, {
"label": "麻栗坡县",
"value": "532624"
}, {
"label": "马关县",
"value": "532625"
}, {
"label": "丘北县",
"value": "532626"
}, {
"label": "广南县",
"value": "532627"
}, {
"label": "富宁县",
"value": "532628"
}],
[{
"label": "市辖区",
"value": "532801"
}, {
"label": "勐海县",
"value": "532822"
}, {
"label": "勐腊县",
"value": "532823"
}],
[{
"label": "市辖区",
"value": "532901"
}, {
"label": "漾濞彝族自治县",
"value": "532922"
}, {
"label": "祥云县",
"value": "532923"
}, {
"label": "宾川县",
"value": "532924"
}, {
"label": "弥渡县",
"value": "532925"
}, {
"label": "南涧彝族自治县",
"value": "532926"
}, {
"label": "巍山彝族回族自治县",
"value": "532927"
}, {
"label": "永平县",
"value": "532928"
}, {
"label": "云龙县",
"value": "532929"
}, {
"label": "洱源县",
"value": "532930"
}, {
"label": "剑川县",
"value": "532931"
}, {
"label": "鹤庆县",
"value": "532932"
}],
[{
"label": "瑞丽市",
"value": "533102"
}, {
"label": "芒市",
"value": "533103"
}, {
"label": "梁河县",
"value": "533122"
}, {
"label": "盈江县",
"value": "533123"
}, {
"label": "陇川县",
"value": "533124"
}],
[{
"label": "市辖区",
"value": "533301"
}, {
"label": "福贡县",
"value": "533323"
}, {
"label": "贡山独龙族怒族自治县",
"value": "533324"
}, {
"label": "兰坪白族普米族自治县",
"value": "533325"
}],
[{
"label": "市辖区",
"value": "533401"
}, {
"label": "德钦县",
"value": "533422"
}, {
"label": "维西傈僳族自治县",
"value": "533423"
}]
],
[
[{
"label": "市辖区",
"value": "540101"
}, {
"label": "城关区",
"value": "540102"
}, {
"label": "堆龙德庆区",
"value": "540103"
}, {
"label": "林周县",
"value": "540121"
}, {
"label": "当雄县",
"value": "540122"
}, {
"label": "尼木县",
"value": "540123"
}, {
"label": "曲水县",
"value": "540124"
}, {
"label": "达孜县",
"value": "540126"
}, {
"label": "墨竹工卡县",
"value": "540127"
}],
[{
"label": "桑珠孜区",
"value": "540202"
}, {
"label": "南木林县",
"value": "540221"
}, {
"label": "江孜县",
"value": "540222"
}, {
"label": "定日县",
"value": "540223"
}, {
"label": "萨迦县",
"value": "540224"
}, {
"label": "拉孜县",
"value": "540225"
}, {
"label": "昂仁县",
"value": "540226"
}, {
"label": "谢通门县",
"value": "540227"
}, {
"label": "白朗县",
"value": "540228"
}, {
"label": "仁布县",
"value": "540229"
}, {
"label": "康马县",
"value": "540230"
}, {
"label": "定结县",
"value": "540231"
}, {
"label": "仲巴县",
"value": "540232"
}, {
"label": "亚东县",
"value": "540233"
}, {
"label": "吉隆县",
"value": "540234"
}, {
"label": "聂拉木县",
"value": "540235"
}, {
"label": "萨嘎县",
"value": "540236"
}, {
"label": "岗巴县",
"value": "540237"
}],
[{
"label": "卡若区",
"value": "540302"
}, {
"label": "江达县",
"value": "540321"
}, {
"label": "贡觉县",
"value": "540322"
}, {
"label": "类乌齐县",
"value": "540323"
}, {
"label": "丁青县",
"value": "540324"
}, {
"label": "察雅县",
"value": "540325"
}, {
"label": "八宿县",
"value": "540326"
}, {
"label": "左贡县",
"value": "540327"
}, {
"label": "芒康县",
"value": "540328"
}, {
"label": "洛隆县",
"value": "540329"
}, {
"label": "边坝县",
"value": "540330"
}],
[{
"label": "巴宜区",
"value": "540402"
}, {
"label": "工布江达县",
"value": "540421"
}, {
"label": "米林县",
"value": "540422"
}, {
"label": "墨脱县",
"value": "540423"
}, {
"label": "波密县",
"value": "540424"
}, {
"label": "察隅县",
"value": "540425"
}, {
"label": "朗县",
"value": "540426"
}],
[{
"label": "市辖区",
"value": "540501"
}, {
"label": "乃东区",
"value": "540502"
}, {
"label": "扎囊县",
"value": "540521"
}, {
"label": "贡嘎县",
"value": "540522"
}, {
"label": "桑日县",
"value": "540523"
}, {
"label": "琼结县",
"value": "540524"
}, {
"label": "曲松县",
"value": "540525"
}, {
"label": "措美县",
"value": "540526"
}, {
"label": "洛扎县",
"value": "540527"
}, {
"label": "加查县",
"value": "540528"
}, {
"label": "隆子县",
"value": "540529"
}, {
"label": "错那县",
"value": "540530"
}, {
"label": "浪卡子县",
"value": "540531"
}],
[{
"label": "那曲县",
"value": "542421"
}, {
"label": "嘉黎县",
"value": "542422"
}, {
"label": "比如县",
"value": "542423"
}, {
"label": "聂荣县",
"value": "542424"
}, {
"label": "安多县",
"value": "542425"
}, {
"label": "申扎县",
"value": "542426"
}, {
"label": "索县",
"value": "542427"
}, {
"label": "班戈县",
"value": "542428"
}, {
"label": "巴青县",
"value": "542429"
}, {
"label": "尼玛县",
"value": "542430"
}, {
"label": "双湖县",
"value": "542431"
}],
[{
"label": "普兰县",
"value": "542521"
}, {
"label": "札达县",
"value": "542522"
}, {
"label": "噶尔县",
"value": "542523"
}, {
"label": "日土县",
"value": "542524"
}, {
"label": "革吉县",
"value": "542525"
}, {
"label": "改则县",
"value": "542526"
}, {
"label": "措勤县",
"value": "542527"
}]
],
[
[{
"label": "市辖区",
"value": "610101"
}, {
"label": "新城区",
"value": "610102"
}, {
"label": "碑林区",
"value": "610103"
}, {
"label": "莲湖区",
"value": "610104"
}, {
"label": "灞桥区",
"value": "610111"
}, {
"label": "未央区",
"value": "610112"
}, {
"label": "雁塔区",
"value": "610113"
}, {
"label": "阎良区",
"value": "610114"
}, {
"label": "临潼区",
"value": "610115"
}, {
"label": "长安区",
"value": "610116"
}, {
"label": "高陵区",
"value": "610117"
}, {
"label": "蓝田县",
"value": "610122"
}, {
"label": "周至县",
"value": "610124"
}, {
"label": "户县",
"value": "610125"
}],
[{
"label": "市辖区",
"value": "610201"
}, {
"label": "王益区",
"value": "610202"
}, {
"label": "印台区",
"value": "610203"
}, {
"label": "耀州区",
"value": "610204"
}, {
"label": "宜君县",
"value": "610222"
}],
[{
"label": "市辖区",
"value": "610301"
}, {
"label": "渭滨区",
"value": "610302"
}, {
"label": "金台区",
"value": "610303"
}, {
"label": "陈仓区",
"value": "610304"
}, {
"label": "凤翔县",
"value": "610322"
}, {
"label": "岐山县",
"value": "610323"
}, {
"label": "扶风县",
"value": "610324"
}, {
"label": "眉县",
"value": "610326"
}, {
"label": "陇县",
"value": "610327"
}, {
"label": "千阳县",
"value": "610328"
}, {
"label": "麟游县",
"value": "610329"
}, {
"label": "凤县",
"value": "610330"
}, {
"label": "太白县",
"value": "610331"
}],
[{
"label": "市辖区",
"value": "610401"
}, {
"label": "秦都区",
"value": "610402"
}, {
"label": "杨陵区",
"value": "610403"
}, {
"label": "渭城区",
"value": "610404"
}, {
"label": "三原县",
"value": "610422"
}, {
"label": "泾阳县",
"value": "610423"
}, {
"label": "乾县",
"value": "610424"
}, {
"label": "礼泉县",
"value": "610425"
}, {
"label": "永寿县",
"value": "610426"
}, {
"label": "彬县",
"value": "610427"
}, {
"label": "长武县",
"value": "610428"
}, {
"label": "旬邑县",
"value": "610429"
}, {
"label": "淳化县",
"value": "610430"
}, {
"label": "武功县",
"value": "610431"
}, {
"label": "兴平市",
"value": "610481"
}],
[{
"label": "市辖区",
"value": "610501"
}, {
"label": "临渭区",
"value": "610502"
}, {
"label": "华州区",
"value": "610503"
}, {
"label": "潼关县",
"value": "610522"
}, {
"label": "大荔县",
"value": "610523"
}, {
"label": "合阳县",
"value": "610524"
}, {
"label": "澄城县",
"value": "610525"
}, {
"label": "蒲城县",
"value": "610526"
}, {
"label": "白水县",
"value": "610527"
}, {
"label": "富平县",
"value": "610528"
}, {
"label": "韩城市",
"value": "610581"
}, {
"label": "华阴市",
"value": "610582"
}],
[{
"label": "市辖区",
"value": "610601"
}, {
"label": "宝塔区",
"value": "610602"
}, {
"label": "安塞区",
"value": "610603"
}, {
"label": "延长县",
"value": "610621"
}, {
"label": "延川县",
"value": "610622"
}, {
"label": "子长县",
"value": "610623"
}, {
"label": "志丹县",
"value": "610625"
}, {
"label": "吴起县",
"value": "610626"
}, {
"label": "甘泉县",
"value": "610627"
}, {
"label": "富县",
"value": "610628"
}, {
"label": "洛川县",
"value": "610629"
}, {
"label": "宜川县",
"value": "610630"
}, {
"label": "黄龙县",
"value": "610631"
}, {
"label": "黄陵县",
"value": "610632"
}],
[{
"label": "市辖区",
"value": "610701"
}, {
"label": "汉台区",
"value": "610702"
}, {
"label": "南郑县",
"value": "610721"
}, {
"label": "城固县",
"value": "610722"
}, {
"label": "洋县",
"value": "610723"
}, {
"label": "西乡县",
"value": "610724"
}, {
"label": "勉县",
"value": "610725"
}, {
"label": "宁强县",
"value": "610726"
}, {
"label": "略阳县",
"value": "610727"
}, {
"label": "镇巴县",
"value": "610728"
}, {
"label": "留坝县",
"value": "610729"
}, {
"label": "佛坪县",
"value": "610730"
}],
[{
"label": "市辖区",
"value": "610801"
}, {
"label": "榆阳区",
"value": "610802"
}, {
"label": "横山区",
"value": "610803"
}, {
"label": "神木县",
"value": "610821"
}, {
"label": "府谷县",
"value": "610822"
}, {
"label": "靖边县",
"value": "610824"
}, {
"label": "定边县",
"value": "610825"
}, {
"label": "绥德县",
"value": "610826"
}, {
"label": "米脂县",
"value": "610827"
}, {
"label": "佳县",
"value": "610828"
}, {
"label": "吴堡县",
"value": "610829"
}, {
"label": "清涧县",
"value": "610830"
}, {
"label": "子洲县",
"value": "610831"
}],
[{
"label": "市辖区",
"value": "610901"
}, {
"label": "汉滨区",
"value": "610902"
}, {
"label": "汉阴县",
"value": "610921"
}, {
"label": "石泉县",
"value": "610922"
}, {
"label": "宁陕县",
"value": "610923"
}, {
"label": "紫阳县",
"value": "610924"
}, {
"label": "岚皋县",
"value": "610925"
}, {
"label": "平利县",
"value": "610926"
}, {
"label": "镇坪县",
"value": "610927"
}, {
"label": "旬阳县",
"value": "610928"
}, {
"label": "白河县",
"value": "610929"
}],
[{
"label": "市辖区",
"value": "611001"
}, {
"label": "商州区",
"value": "611002"
}, {
"label": "洛南县",
"value": "611021"
}, {
"label": "丹凤县",
"value": "611022"
}, {
"label": "商南县",
"value": "611023"
}, {
"label": "山阳县",
"value": "611024"
}, {
"label": "镇安县",
"value": "611025"
}, {
"label": "柞水县",
"value": "611026"
}]
],
[
[{
"label": "市辖区",
"value": "620101"
}, {
"label": "城关区",
"value": "620102"
}, {
"label": "七里河区",
"value": "620103"
}, {
"label": "西固区",
"value": "620104"
}, {
"label": "安宁区",
"value": "620105"
}, {
"label": "红古区",
"value": "620111"
}, {
"label": "永登县",
"value": "620121"
}, {
"label": "皋兰县",
"value": "620122"
}, {
"label": "榆中县",
"value": "620123"
}],
[{
"label": "市辖区",
"value": "620201"
}],
[{
"label": "市辖区",
"value": "620301"
}, {
"label": "金川区",
"value": "620302"
}, {
"label": "永昌县",
"value": "620321"
}],
[{
"label": "市辖区",
"value": "620401"
}, {
"label": "白银区",
"value": "620402"
}, {
"label": "平川区",
"value": "620403"
}, {
"label": "靖远县",
"value": "620421"
}, {
"label": "会宁县",
"value": "620422"
}, {
"label": "景泰县",
"value": "620423"
}],
[{
"label": "市辖区",
"value": "620501"
}, {
"label": "秦州区",
"value": "620502"
}, {
"label": "麦积区",
"value": "620503"
}, {
"label": "清水县",
"value": "620521"
}, {
"label": "秦安县",
"value": "620522"
}, {
"label": "甘谷县",
"value": "620523"
}, {
"label": "武山县",
"value": "620524"
}, {
"label": "张家川回族自治县",
"value": "620525"
}],
[{
"label": "市辖区",
"value": "620601"
}, {
"label": "凉州区",
"value": "620602"
}, {
"label": "民勤县",
"value": "620621"
}, {
"label": "古浪县",
"value": "620622"
}, {
"label": "天祝藏族自治县",
"value": "620623"
}],
[{
"label": "市辖区",
"value": "620701"
}, {
"label": "甘州区",
"value": "620702"
}, {
"label": "肃南裕固族自治县",
"value": "620721"
}, {
"label": "民乐县",
"value": "620722"
}, {
"label": "临泽县",
"value": "620723"
}, {
"label": "高台县",
"value": "620724"
}, {
"label": "山丹县",
"value": "620725"
}],
[{
"label": "市辖区",
"value": "620801"
}, {
"label": "崆峒区",
"value": "620802"
}, {
"label": "泾川县",
"value": "620821"
}, {
"label": "灵台县",
"value": "620822"
}, {
"label": "崇信县",
"value": "620823"
}, {
"label": "华亭县",
"value": "620824"
}, {
"label": "庄浪县",
"value": "620825"
}, {
"label": "静宁县",
"value": "620826"
}],
[{
"label": "市辖区",
"value": "620901"
}, {
"label": "肃州区",
"value": "620902"
}, {
"label": "金塔县",
"value": "620921"
}, {
"label": "瓜州县",
"value": "620922"
}, {
"label": "肃北蒙古族自治县",
"value": "620923"
}, {
"label": "阿克塞哈萨克族自治县",
"value": "620924"
}, {
"label": "玉门市",
"value": "620981"
}, {
"label": "敦煌市",
"value": "620982"
}],
[{
"label": "市辖区",
"value": "621001"
}, {
"label": "西峰区",
"value": "621002"
}, {
"label": "庆城县",
"value": "621021"
}, {
"label": "环县",
"value": "621022"
}, {
"label": "华池县",
"value": "621023"
}, {
"label": "合水县",
"value": "621024"
}, {
"label": "正宁县",
"value": "621025"
}, {
"label": "宁县",
"value": "621026"
}, {
"label": "镇原县",
"value": "621027"
}],
[{
"label": "市辖区",
"value": "621101"
}, {
"label": "安定区",
"value": "621102"
}, {
"label": "通渭县",
"value": "621121"
}, {
"label": "陇西县",
"value": "621122"
}, {
"label": "渭源县",
"value": "621123"
}, {
"label": "临洮县",
"value": "621124"
}, {
"label": "漳县",
"value": "621125"
}, {
"label": "岷县",
"value": "621126"
}],
[{
"label": "市辖区",
"value": "621201"
}, {
"label": "武都区",
"value": "621202"
}, {
"label": "成县",
"value": "621221"
}, {
"label": "文县",
"value": "621222"
}, {
"label": "宕昌县",
"value": "621223"
}, {
"label": "康县",
"value": "621224"
}, {
"label": "西和县",
"value": "621225"
}, {
"label": "礼县",
"value": "621226"
}, {
"label": "徽县",
"value": "621227"
}, {
"label": "两当县",
"value": "621228"
}],
[{
"label": "市辖区",
"value": "622901"
}, {
"label": "临夏县",
"value": "622921"
}, {
"label": "康乐县",
"value": "622922"
}, {
"label": "永靖县",
"value": "622923"
}, {
"label": "广河县",
"value": "622924"
}, {
"label": "和政县",
"value": "622925"
}, {
"label": "东乡族自治县",
"value": "622926"
}, {
"label": "积石山保安族东乡族撒拉族自治县",
"value": "622927"
}],
[{
"label": "市辖区",
"value": "623001"
}, {
"label": "临潭县",
"value": "623021"
}, {
"label": "卓尼县",
"value": "623022"
}, {
"label": "舟曲县",
"value": "623023"
}, {
"label": "迭部县",
"value": "623024"
}, {
"label": "玛曲县",
"value": "623025"
}, {
"label": "碌曲县",
"value": "623026"
}, {
"label": "夏河县",
"value": "623027"
}]
],
[
[{
"label": "市辖区",
"value": "630101"
}, {
"label": "城东区",
"value": "630102"
}, {
"label": "城中区",
"value": "630103"
}, {
"label": "城西区",
"value": "630104"
}, {
"label": "城北区",
"value": "630105"
}, {
"label": "大通回族土族自治县",
"value": "630121"
}, {
"label": "湟中县",
"value": "630122"
}, {
"label": "湟源县",
"value": "630123"
}],
[{
"label": "乐都区",
"value": "630202"
}, {
"label": "平安区",
"value": "630203"
}, {
"label": "民和回族土族自治县",
"value": "630222"
}, {
"label": "互助土族自治县",
"value": "630223"
}, {
"label": "化隆回族自治县",
"value": "630224"
}, {
"label": "循化撒拉族自治县",
"value": "630225"
}],
[{
"label": "门源回族自治县",
"value": "632221"
}, {
"label": "祁连县",
"value": "632222"
}, {
"label": "海晏县",
"value": "632223"
}, {
"label": "刚察县",
"value": "632224"
}],
[{
"label": "同仁县",
"value": "632321"
}, {
"label": "尖扎县",
"value": "632322"
}, {
"label": "泽库县",
"value": "632323"
}, {
"label": "河南蒙古族自治县",
"value": "632324"
}],
[{
"label": "共和县",
"value": "632521"
}, {
"label": "同德县",
"value": "632522"
}, {
"label": "贵德县",
"value": "632523"
}, {
"label": "兴海县",
"value": "632524"
}, {
"label": "贵南县",
"value": "632525"
}],
[{
"label": "玛沁县",
"value": "632621"
}, {
"label": "班玛县",
"value": "632622"
}, {
"label": "甘德县",
"value": "632623"
}, {
"label": "达日县",
"value": "632624"
}, {
"label": "久治县",
"value": "632625"
}, {
"label": "玛多县",
"value": "632626"
}],
[{
"label": "市辖区",
"value": "632701"
}, {
"label": "杂多县",
"value": "632722"
}, {
"label": "称多县",
"value": "632723"
}, {
"label": "治多县",
"value": "632724"
}, {
"label": "囊谦县",
"value": "632725"
}, {
"label": "曲麻莱县",
"value": "632726"
}],
[{
"label": "市辖区",
"value": "632801"
}, {
"label": "德令哈市",
"value": "632802"
}, {
"label": "乌兰县",
"value": "632821"
}, {
"label": "都兰县",
"value": "632822"
}, {
"label": "天峻县",
"value": "632823"
}]
],
[
[{
"label": "市辖区",
"value": "640101"
}, {
"label": "兴庆区",
"value": "640104"
}, {
"label": "西夏区",
"value": "640105"
}, {
"label": "金凤区",
"value": "640106"
}, {
"label": "永宁县",
"value": "640121"
}, {
"label": "贺兰县",
"value": "640122"
}, {
"label": "灵武市",
"value": "640181"
}],
[{
"label": "市辖区",
"value": "640201"
}, {
"label": "大武口区",
"value": "640202"
}, {
"label": "惠农区",
"value": "640205"
}, {
"label": "平罗县",
"value": "640221"
}],
[{
"label": "市辖区",
"value": "640301"
}, {
"label": "利通区",
"value": "640302"
}, {
"label": "红寺堡区",
"value": "640303"
}, {
"label": "盐池县",
"value": "640323"
}, {
"label": "同心县",
"value": "640324"
}, {
"label": "青铜峡市",
"value": "640381"
}],
[{
"label": "市辖区",
"value": "640401"
}, {
"label": "原州区",
"value": "640402"
}, {
"label": "西吉县",
"value": "640422"
}, {
"label": "隆德县",
"value": "640423"
}, {
"label": "泾源县",
"value": "640424"
}, {
"label": "彭阳县",
"value": "640425"
}],
[{
"label": "市辖区",
"value": "640501"
}, {
"label": "沙坡头区",
"value": "640502"
}, {
"label": "中宁县",
"value": "640521"
}, {
"label": "海原县",
"value": "640522"
}]
],
[
[{
"label": "市辖区",
"value": "650101"
}, {
"label": "天山区",
"value": "650102"
}, {
"label": "沙依巴克区",
"value": "650103"
}, {
"label": "新市区",
"value": "650104"
}, {
"label": "水磨沟区",
"value": "650105"
}, {
"label": "头屯河区",
"value": "650106"
}, {
"label": "达坂城区",
"value": "650107"
}, {
"label": "米东区",
"value": "650109"
}, {
"label": "乌鲁木齐县",
"value": "650121"
}],
[{
"label": "市辖区",
"value": "650201"
}, {
"label": "独山子区",
"value": "650202"
}, {
"label": "克拉玛依区",
"value": "650203"
}, {
"label": "白碱滩区",
"value": "650204"
}, {
"label": "乌尔禾区",
"value": "650205"
}],
[{
"label": "高昌区",
"value": "650402"
}, {
"label": "鄯善县",
"value": "650421"
}, {
"label": "托克逊县",
"value": "650422"
}],
[{
"label": "伊州区",
"value": "650502"
}, {
"label": "巴里坤哈萨克自治县",
"value": "650521"
}, {
"label": "伊吾县",
"value": "650522"
}],
[{
"label": "市辖区",
"value": "652301"
}, {
"label": "阜康市",
"value": "652302"
}, {
"label": "呼图壁县",
"value": "652323"
}, {
"label": "玛纳斯县",
"value": "652324"
}, {
"label": "奇台县",
"value": "652325"
}, {
"label": "吉木萨尔县",
"value": "652327"
}, {
"label": "木垒哈萨克自治县",
"value": "652328"
}],
[{
"label": "市辖区",
"value": "652701"
}, {
"label": "阿拉山口市",
"value": "652702"
}, {
"label": "精河县",
"value": "652722"
}, {
"label": "温泉县",
"value": "652723"
}],
[{
"label": "市辖区",
"value": "652801"
}, {
"label": "轮台县",
"value": "652822"
}, {
"label": "尉犁县",
"value": "652823"
}, {
"label": "若羌县",
"value": "652824"
}, {
"label": "且末县",
"value": "652825"
}, {
"label": "焉耆回族自治县",
"value": "652826"
}, {
"label": "和静县",
"value": "652827"
}, {
"label": "和硕县",
"value": "652828"
}, {
"label": "博湖县",
"value": "652829"
}],
[{
"label": "市辖区",
"value": "652901"
}, {
"label": "温宿县",
"value": "652922"
}, {
"label": "库车县",
"value": "652923"
}, {
"label": "沙雅县",
"value": "652924"
}, {
"label": "新和县",
"value": "652925"
}, {
"label": "拜城县",
"value": "652926"
}, {
"label": "乌什县",
"value": "652927"
}, {
"label": "阿瓦提县",
"value": "652928"
}, {
"label": "柯坪县",
"value": "652929"
}],
[{
"label": "市辖区",
"value": "653001"
}, {
"label": "阿克陶县",
"value": "653022"
}, {
"label": "阿合奇县",
"value": "653023"
}, {
"label": "乌恰县",
"value": "653024"
}],
[{
"label": "市辖区",
"value": "653101"
}, {
"label": "疏附县",
"value": "653121"
}, {
"label": "疏勒县",
"value": "653122"
}, {
"label": "英吉沙县",
"value": "653123"
}, {
"label": "泽普县",
"value": "653124"
}, {
"label": "莎车县",
"value": "653125"
}, {
"label": "叶城县",
"value": "653126"
}, {
"label": "麦盖提县",
"value": "653127"
}, {
"label": "岳普湖县",
"value": "653128"
}, {
"label": "伽师县",
"value": "653129"
}, {
"label": "巴楚县",
"value": "653130"
}, {
"label": "塔什库尔干塔吉克自治县",
"value": "653131"
}],
[{
"label": "市辖区",
"value": "653201"
}, {
"label": "和田县",
"value": "653221"
}, {
"label": "墨玉县",
"value": "653222"
}, {
"label": "皮山县",
"value": "653223"
}, {
"label": "洛浦县",
"value": "653224"
}, {
"label": "策勒县",
"value": "653225"
}, {
"label": "于田县",
"value": "653226"
}, {
"label": "民丰县",
"value": "653227"
}],
[{
"label": "伊宁市",
"value": "654002"
}, {
"label": "奎屯市",
"value": "654003"
}, {
"label": "霍尔果斯市",
"value": "654004"
}, {
"label": "伊宁县",
"value": "654021"
}, {
"label": "察布查尔锡伯自治县",
"value": "654022"
}, {
"label": "霍城县",
"value": "654023"
}, {
"label": "巩留县",
"value": "654024"
}, {
"label": "新源县",
"value": "654025"
}, {
"label": "昭苏县",
"value": "654026"
}, {
"label": "特克斯县",
"value": "654027"
}, {
"label": "尼勒克县",
"value": "654028"
}],
[{
"label": "市辖区",
"value": "654201"
}, {
"label": "乌苏市",
"value": "654202"
}, {
"label": "额敏县",
"value": "654221"
}, {
"label": "沙湾县",
"value": "654223"
}, {
"label": "托里县",
"value": "654224"
}, {
"label": "裕民县",
"value": "654225"
}, {
"label": "和布克赛尔蒙古自治县",
"value": "654226"
}],
[{
"label": "市辖区",
"value": "654301"
}, {
"label": "布尔津县",
"value": "654321"
}, {
"label": "富蕴县",
"value": "654322"
}, {
"label": "福海县",
"value": "654323"
}, {
"label": "哈巴河县",
"value": "654324"
}, {
"label": "青河县",
"value": "654325"
}, {
"label": "吉木乃县",
"value": "654326"
}],
[{
"label": "市辖区",
"value": "659001"
}, {
"label": "阿拉尔市",
"value": "659002"
}, {
"label": "图木舒克市",
"value": "659003"
}, {
"label": "五家渠市",
"value": "659004"
}, {
"label": "铁门关市",
"value": "659006"
}]
]
]
export default areaData;
city.js
/* eslint-disable */
var cityData = [
[{
"label": "北京市",
"value": "110100"
}],
[{
"label": "天津市",
"value": "120100"
}],
[{
"label": "石家庄市",
"value": "130100"
}, {
"label": "唐山市",
"value": "130200"
}, {
"label": "秦皇岛市",
"value": "130300"
}, {
"label": "邯郸市",
"value": "130400"
}, {
"label": "邢台市",
"value": "130500"
}, {
"label": "保定市",
"value": "130600"
}, {
"label": "张家口市",
"value": "130700"
}, {
"label": "承德市",
"value": "130800"
}, {
"label": "沧州市",
"value": "130900"
}, {
"label": "廊坊市",
"value": "131000"
}, {
"label": "衡水市",
"value": "131100"
}, {
"label": "省直辖县级行政区划",
"value": "139000"
}],
[{
"label": "太原市",
"value": "140100"
}, {
"label": "大同市",
"value": "140200"
}, {
"label": "阳泉市",
"value": "140300"
}, {
"label": "长治市",
"value": "140400"
}, {
"label": "晋城市",
"value": "140500"
}, {
"label": "朔州市",
"value": "140600"
}, {
"label": "晋中市",
"value": "140700"
}, {
"label": "运城市",
"value": "140800"
}, {
"label": "忻州市",
"value": "140900"
}, {
"label": "临汾市",
"value": "141000"
}, {
"label": "吕梁市",
"value": "141100"
}],
[{
"label": "呼和浩特市",
"value": "150100"
}, {
"label": "包头市",
"value": "150200"
}, {
"label": "乌海市",
"value": "150300"
}, {
"label": "赤峰市",
"value": "150400"
}, {
"label": "通辽市",
"value": "150500"
}, {
"label": "鄂尔多斯市",
"value": "150600"
}, {
"label": "呼伦贝尔市",
"value": "150700"
}, {
"label": "巴彦淖尔市",
"value": "150800"
}, {
"label": "乌兰察布市",
"value": "150900"
}, {
"label": "兴安盟",
"value": "152200"
}, {
"label": "锡林郭勒盟",
"value": "152500"
}, {
"label": "阿拉善盟",
"value": "152900"
}],
[{
"label": "沈阳市",
"value": "210100"
}, {
"label": "大连市",
"value": "210200"
}, {
"label": "鞍山市",
"value": "210300"
}, {
"label": "抚顺市",
"value": "210400"
}, {
"label": "本溪市",
"value": "210500"
}, {
"label": "丹东市",
"value": "210600"
}, {
"label": "锦州市",
"value": "210700"
}, {
"label": "营口市",
"value": "210800"
}, {
"label": "阜新市",
"value": "210900"
}, {
"label": "辽阳市",
"value": "211000"
}, {
"label": "盘锦市",
"value": "211100"
}, {
"label": "铁岭市",
"value": "211200"
}, {
"label": "朝阳市",
"value": "211300"
}, {
"label": "葫芦岛市",
"value": "211400"
}],
[{
"label": "长春市",
"value": "220100"
}, {
"label": "吉林市",
"value": "220200"
}, {
"label": "四平市",
"value": "220300"
}, {
"label": "辽源市",
"value": "220400"
}, {
"label": "通化市",
"value": "220500"
}, {
"label": "白山市",
"value": "220600"
}, {
"label": "松原市",
"value": "220700"
}, {
"label": "白城市",
"value": "220800"
}, {
"label": "延边朝鲜族自治州",
"value": "222400"
}],
[{
"label": "哈尔滨市",
"value": "230100"
}, {
"label": "齐齐哈尔市",
"value": "230200"
}, {
"label": "鸡西市",
"value": "230300"
}, {
"label": "鹤岗市",
"value": "230400"
}, {
"label": "双鸭山市",
"value": "230500"
}, {
"label": "大庆市",
"value": "230600"
}, {
"label": "伊春市",
"value": "230700"
}, {
"label": "佳木斯市",
"value": "230800"
}, {
"label": "七台河市",
"value": "230900"
}, {
"label": "牡丹江市",
"value": "231000"
}, {
"label": "黑河市",
"value": "231100"
}, {
"label": "绥化市",
"value": "231200"
}, {
"label": "大兴安岭地区",
"value": "232700"
}],
[{
"label": "上海市",
"value": "310100"
}],
[{
"label": "南京市",
"value": "320100"
}, {
"label": "无锡市",
"value": "320200"
}, {
"label": "徐州市",
"value": "320300"
}, {
"label": "常州市",
"value": "320400"
}, {
"label": "苏州市",
"value": "320500"
}, {
"label": "南通市",
"value": "320600"
}, {
"label": "连云港市",
"value": "320700"
}, {
"label": "淮安市",
"value": "320800"
}, {
"label": "盐城市",
"value": "320900"
}, {
"label": "扬州市",
"value": "321000"
}, {
"label": "镇江市",
"value": "321100"
}, {
"label": "泰州市",
"value": "321200"
}, {
"label": "宿迁市",
"value": "321300"
}],
[{
"label": "杭州市",
"value": "330100"
}, {
"label": "宁波市",
"value": "330200"
}, {
"label": "温州市",
"value": "330300"
}, {
"label": "嘉兴市",
"value": "330400"
}, {
"label": "湖州市",
"value": "330500"
}, {
"label": "绍兴市",
"value": "330600"
}, {
"label": "金华市",
"value": "330700"
}, {
"label": "衢州市",
"value": "330800"
}, {
"label": "舟山市",
"value": "330900"
}, {
"label": "台州市",
"value": "331000"
}, {
"label": "丽水市",
"value": "331100"
}],
[{
"label": "合肥市",
"value": "340100"
}, {
"label": "芜湖市",
"value": "340200"
}, {
"label": "蚌埠市",
"value": "340300"
}, {
"label": "淮南市",
"value": "340400"
}, {
"label": "马鞍山市",
"value": "340500"
}, {
"label": "淮北市",
"value": "340600"
}, {
"label": "铜陵市",
"value": "340700"
}, {
"label": "安庆市",
"value": "340800"
}, {
"label": "黄山市",
"value": "341000"
}, {
"label": "滁州市",
"value": "341100"
}, {
"label": "阜阳市",
"value": "341200"
}, {
"label": "宿州市",
"value": "341300"
}, {
"label": "六安市",
"value": "341500"
}, {
"label": "亳州市",
"value": "341600"
}, {
"label": "池州市",
"value": "341700"
}, {
"label": "宣城市",
"value": "341800"
}],
[{
"label": "福州市",
"value": "350100"
}, {
"label": "厦门市",
"value": "350200"
}, {
"label": "莆田市",
"value": "350300"
}, {
"label": "三明市",
"value": "350400"
}, {
"label": "泉州市",
"value": "350500"
}, {
"label": "漳州市",
"value": "350600"
}, {
"label": "南平市",
"value": "350700"
}, {
"label": "龙岩市",
"value": "350800"
}, {
"label": "宁德市",
"value": "350900"
}],
[{
"label": "南昌市",
"value": "360100"
}, {
"label": "景德镇市",
"value": "360200"
}, {
"label": "萍乡市",
"value": "360300"
}, {
"label": "九江市",
"value": "360400"
}, {
"label": "新余市",
"value": "360500"
}, {
"label": "鹰潭市",
"value": "360600"
}, {
"label": "赣州市",
"value": "360700"
}, {
"label": "吉安市",
"value": "360800"
}, {
"label": "宜春市",
"value": "360900"
}, {
"label": "抚州市",
"value": "361000"
}, {
"label": "上饶市",
"value": "361100"
}],
[{
"label": "济南市",
"value": "370100"
}, {
"label": "青岛市",
"value": "370200"
}, {
"label": "淄博市",
"value": "370300"
}, {
"label": "枣庄市",
"value": "370400"
}, {
"label": "东营市",
"value": "370500"
}, {
"label": "烟台市",
"value": "370600"
}, {
"label": "潍坊市",
"value": "370700"
}, {
"label": "济宁市",
"value": "370800"
}, {
"label": "泰安市",
"value": "370900"
}, {
"label": "威海市",
"value": "371000"
}, {
"label": "日照市",
"value": "371100"
}, {
"label": "莱芜市",
"value": "371200"
}, {
"label": "临沂市",
"value": "371300"
}, {
"label": "德州市",
"value": "371400"
}, {
"label": "聊城市",
"value": "371500"
}, {
"label": "滨州市",
"value": "371600"
}, {
"label": "菏泽市",
"value": "371700"
}],
[{
"label": "郑州市",
"value": "410100"
}, {
"label": "开封市",
"value": "410200"
}, {
"label": "洛阳市",
"value": "410300"
}, {
"label": "平顶山市",
"value": "410400"
}, {
"label": "安阳市",
"value": "410500"
}, {
"label": "鹤壁市",
"value": "410600"
}, {
"label": "新乡市",
"value": "410700"
}, {
"label": "焦作市",
"value": "410800"
}, {
"label": "濮阳市",
"value": "410900"
}, {
"label": "许昌市",
"value": "411000"
}, {
"label": "漯河市",
"value": "411100"
}, {
"label": "三门峡市",
"value": "411200"
}, {
"label": "南阳市",
"value": "411300"
}, {
"label": "商丘市",
"value": "411400"
}, {
"label": "信阳市",
"value": "411500"
}, {
"label": "周口市",
"value": "411600"
}, {
"label": "驻马店市",
"value": "411700"
}, {
"label": "省直辖县级行政区划",
"value": "419000"
}],
[{
"label": "武汉市",
"value": "420100"
}, {
"label": "黄石市",
"value": "420200"
}, {
"label": "十堰市",
"value": "420300"
}, {
"label": "宜昌市",
"value": "420500"
}, {
"label": "襄阳市",
"value": "420600"
}, {
"label": "鄂州市",
"value": "420700"
}, {
"label": "荆门市",
"value": "420800"
}, {
"label": "孝感市",
"value": "420900"
}, {
"label": "荆州市",
"value": "421000"
}, {
"label": "黄冈市",
"value": "421100"
}, {
"label": "咸宁市",
"value": "421200"
}, {
"label": "随州市",
"value": "421300"
}, {
"label": "恩施土家族苗族自治州",
"value": "422800"
}, {
"label": "省直辖县级行政区划",
"value": "429000"
}],
[{
"label": "长沙市",
"value": "430100"
}, {
"label": "株洲市",
"value": "430200"
}, {
"label": "湘潭市",
"value": "430300"
}, {
"label": "衡阳市",
"value": "430400"
}, {
"label": "邵阳市",
"value": "430500"
}, {
"label": "岳阳市",
"value": "430600"
}, {
"label": "常德市",
"value": "430700"
}, {
"label": "张家界市",
"value": "430800"
}, {
"label": "益阳市",
"value": "430900"
}, {
"label": "郴州市",
"value": "431000"
}, {
"label": "永州市",
"value": "431100"
}, {
"label": "怀化市",
"value": "431200"
}, {
"label": "娄底市",
"value": "431300"
}, {
"label": "湘西土家族苗族自治州",
"value": "433100"
}],
[{
"label": "广州市",
"value": "440100"
}, {
"label": "韶关市",
"value": "440200"
}, {
"label": "深圳市",
"value": "440300"
}, {
"label": "珠海市",
"value": "440400"
}, {
"label": "汕头市",
"value": "440500"
}, {
"label": "佛山市",
"value": "440600"
}, {
"label": "江门市",
"value": "440700"
}, {
"label": "湛江市",
"value": "440800"
}, {
"label": "茂名市",
"value": "440900"
}, {
"label": "肇庆市",
"value": "441200"
}, {
"label": "惠州市",
"value": "441300"
}, {
"label": "梅州市",
"value": "441400"
}, {
"label": "汕尾市",
"value": "441500"
}, {
"label": "河源市",
"value": "441600"
}, {
"label": "阳江市",
"value": "441700"
}, {
"label": "清远市",
"value": "441800"
}, {
"label": "东莞市",
"value": "441900"
}, {
"label": "中山市",
"value": "442000"
}, {
"label": "潮州市",
"value": "445100"
}, {
"label": "揭阳市",
"value": "445200"
}, {
"label": "云浮市",
"value": "445300"
}],
[{
"label": "南宁市",
"value": "450100"
}, {
"label": "柳州市",
"value": "450200"
}, {
"label": "桂林市",
"value": "450300"
}, {
"label": "梧州市",
"value": "450400"
}, {
"label": "北海市",
"value": "450500"
}, {
"label": "防城港市",
"value": "450600"
}, {
"label": "钦州市",
"value": "450700"
}, {
"label": "贵港市",
"value": "450800"
}, {
"label": "玉林市",
"value": "450900"
}, {
"label": "百色市",
"value": "451000"
}, {
"label": "贺州市",
"value": "451100"
}, {
"label": "河池市",
"value": "451200"
}, {
"label": "来宾市",
"value": "451300"
}, {
"label": "崇左市",
"value": "451400"
}],
[{
"label": "海口市",
"value": "460100"
}, {
"label": "三亚市",
"value": "460200"
}, {
"label": "三沙市",
"value": "460300"
}, {
"label": "儋州市",
"value": "460400"
}, {
"label": "省直辖县级行政区划",
"value": "469000"
}],
[{
"label": "重庆市",
"value": "500100"
}, {
"label": "县",
"value": "500200"
}],
[{
"label": "成都市",
"value": "510100"
}, {
"label": "自贡市",
"value": "510300"
}, {
"label": "攀枝花市",
"value": "510400"
}, {
"label": "泸州市",
"value": "510500"
}, {
"label": "德阳市",
"value": "510600"
}, {
"label": "绵阳市",
"value": "510700"
}, {
"label": "广元市",
"value": "510800"
}, {
"label": "遂宁市",
"value": "510900"
}, {
"label": "内江市",
"value": "511000"
}, {
"label": "乐山市",
"value": "511100"
}, {
"label": "南充市",
"value": "511300"
}, {
"label": "眉山市",
"value": "511400"
}, {
"label": "宜宾市",
"value": "511500"
}, {
"label": "广安市",
"value": "511600"
}, {
"label": "达州市",
"value": "511700"
}, {
"label": "雅安市",
"value": "511800"
}, {
"label": "巴中市",
"value": "511900"
}, {
"label": "资阳市",
"value": "512000"
}, {
"label": "阿坝藏族羌族自治州",
"value": "513200"
}, {
"label": "甘孜藏族自治州",
"value": "513300"
}, {
"label": "凉山彝族自治州",
"value": "513400"
}],
[{
"label": "贵阳市",
"value": "520100"
}, {
"label": "六盘水市",
"value": "520200"
}, {
"label": "遵义市",
"value": "520300"
}, {
"label": "安顺市",
"value": "520400"
}, {
"label": "毕节市",
"value": "520500"
}, {
"label": "铜仁市",
"value": "520600"
}, {
"label": "黔西南布依族苗族自治州",
"value": "522300"
}, {
"label": "黔东南苗族侗族自治州",
"value": "522600"
}, {
"label": "黔南布依族苗族自治州",
"value": "522700"
}],
[{
"label": "昆明市",
"value": "530100"
}, {
"label": "曲靖市",
"value": "530300"
}, {
"label": "玉溪市",
"value": "530400"
}, {
"label": "保山市",
"value": "530500"
}, {
"label": "昭通市",
"value": "530600"
}, {
"label": "丽江市",
"value": "530700"
}, {
"label": "普洱市",
"value": "530800"
}, {
"label": "临沧市",
"value": "530900"
}, {
"label": "楚雄彝族自治州",
"value": "532300"
}, {
"label": "红河哈尼族彝族自治州",
"value": "532500"
}, {
"label": "文山壮族苗族自治州",
"value": "532600"
}, {
"label": "西双版纳傣族自治州",
"value": "532800"
}, {
"label": "大理白族自治州",
"value": "532900"
}, {
"label": "德宏傣族景颇族自治州",
"value": "533100"
}, {
"label": "怒江傈僳族自治州",
"value": "533300"
}, {
"label": "迪庆藏族自治州",
"value": "533400"
}],
[{
"label": "拉萨市",
"value": "540100"
}, {
"label": "日喀则市",
"value": "540200"
}, {
"label": "昌都市",
"value": "540300"
}, {
"label": "林芝市",
"value": "540400"
}, {
"label": "山南市",
"value": "540500"
}, {
"label": "那曲地区",
"value": "542400"
}, {
"label": "阿里地区",
"value": "542500"
}],
[{
"label": "西安市",
"value": "610100"
}, {
"label": "铜川市",
"value": "610200"
}, {
"label": "宝鸡市",
"value": "610300"
}, {
"label": "咸阳市",
"value": "610400"
}, {
"label": "渭南市",
"value": "610500"
}, {
"label": "延安市",
"value": "610600"
}, {
"label": "汉中市",
"value": "610700"
}, {
"label": "榆林市",
"value": "610800"
}, {
"label": "安康市",
"value": "610900"
}, {
"label": "商洛市",
"value": "611000"
}],
[{
"label": "兰州市",
"value": "620100"
}, {
"label": "嘉峪关市",
"value": "620200"
}, {
"label": "金昌市",
"value": "620300"
}, {
"label": "白银市",
"value": "620400"
}, {
"label": "天水市",
"value": "620500"
}, {
"label": "武威市",
"value": "620600"
}, {
"label": "张掖市",
"value": "620700"
}, {
"label": "平凉市",
"value": "620800"
}, {
"label": "酒泉市",
"value": "620900"
}, {
"label": "庆阳市",
"value": "621000"
}, {
"label": "定西市",
"value": "621100"
}, {
"label": "陇南市",
"value": "621200"
}, {
"label": "临夏回族自治州",
"value": "622900"
}, {
"label": "甘南藏族自治州",
"value": "623000"
}],
[{
"label": "西宁市",
"value": "630100"
}, {
"label": "海东市",
"value": "630200"
}, {
"label": "海北藏族自治州",
"value": "632200"
}, {
"label": "黄南藏族自治州",
"value": "632300"
}, {
"label": "海南藏族自治州",
"value": "632500"
}, {
"label": "果洛藏族自治州",
"value": "632600"
}, {
"label": "玉树藏族自治州",
"value": "632700"
}, {
"label": "海西蒙古族藏族自治州",
"value": "632800"
}],
[{
"label": "银川市",
"value": "640100"
}, {
"label": "石嘴山市",
"value": "640200"
}, {
"label": "吴忠市",
"value": "640300"
}, {
"label": "固原市",
"value": "640400"
}, {
"label": "中卫市",
"value": "640500"
}],
[{
"label": "乌鲁木齐市",
"value": "650100"
}, {
"label": "克拉玛依市",
"value": "650200"
}, {
"label": "吐鲁番市",
"value": "650400"
}, {
"label": "哈密市",
"value": "650500"
}, {
"label": "昌吉回族自治州",
"value": "652300"
}, {
"label": "博尔塔拉蒙古自治州",
"value": "652700"
}, {
"label": "巴音郭楞蒙古自治州",
"value": "652800"
}, {
"label": "阿克苏地区",
"value": "652900"
}, {
"label": "克孜勒苏柯尔克孜自治州",
"value": "653000"
}, {
"label": "喀什地区",
"value": "653100"
}, {
"label": "和田地区",
"value": "653200"
}, {
"label": "伊犁哈萨克自治州",
"value": "654000"
}, {
"label": "塔城地区",
"value": "654200"
}, {
"label": "阿勒泰地区",
"value": "654300"
}, {
"label": "自治区直辖县级行政区划",
"value": "659000"
}]
]
export default cityData;
province.js
/* eslint-disable */
var provinceData = [{
"label": "北京市",
"value": "110000"
}, {
"label": "天津市",
"value": "120000"
}, {
"label": "河北省",
"value": "130000"
}, {
"label": "山西省",
"value": "140000"
}, {
"label": "内蒙古自治区",
"value": "150000"
}, {
"label": "辽宁省",
"value": "210000"
}, {
"label": "吉林省",
"value": "220000"
}, {
"label": "黑龙江省",
"value": "230000"
}, {
"label": "上海市",
"value": "310000"
}, {
"label": "江苏省",
"value": "320000"
}, {
"label": "浙江省",
"value": "330000"
}, {
"label": "安徽省",
"value": "340000"
}, {
"label": "福建省",
"value": "350000"
}, {
"label": "江西省",
"value": "360000"
}, {
"label": "山东省",
"value": "370000"
}, {
"label": "河南省",
"value": "410000"
}, {
"label": "湖北省",
"value": "420000"
}, {
"label": "湖南省",
"value": "430000"
}, {
"label": "广东省",
"value": "440000"
}, {
"label": "广西壮族自治区",
"value": "450000"
}, {
"label": "海南省",
"value": "460000"
}, {
"label": "重庆市",
"value": "500000"
}, {
"label": "四川省",
"value": "510000"
}, {
"label": "贵州省",
"value": "520000"
}, {
"label": "云南省",
"value": "530000"
}, {
"label": "西藏自治区",
"value": "540000"
}, {
"label": "陕西省",
"value": "610000"
}, {
"label": "甘肃省",
"value": "620000"
}, {
"label": "青海省",
"value": "630000"
}, {
"label": "宁夏回族自治区",
"value": "640000"
}, {
"label": "新疆维吾尔自治区",
"value": "650000"
}, {
"label": "台湾省",
"value": "710000"
}, {
"label": "香港特别行政区",
"value": "810000"
}, {
"label": "澳门特别行政区",
"value": "820000"
}]
export default provinceData;
mpvueCityPicker.vue
<template>
<div class="mpvue-picker">
<div :class="{'pickerMask':showPicker}" @click="maskClick" catchtouchmove="true"></div>
<div class="mpvue-picker-content " :class="{'mpvue-picker-view-show':showPicker}">
<div class="mpvue-picker__hd" catchtouchmove="true">
<div class="mpvue-picker__action" @click="pickerCancel">取消</div>
<div class="mpvue-picker__action" :style="{color:themeColor}" @click="pickerConfirm">确定</div>
</div>
<picker-view indicator-style="height: 40px;" class="mpvue-picker-view" :value="pickerValue" @change="pickerChange">
<block>
<picker-view-column>
<div class="picker-item" v-for="(item,index) in provinceDataList" :key="index">{{item.label}}</div>
</picker-view-column>
<picker-view-column>
<div class="picker-item" v-for="(item,index) in cityDataList" :key="index">{{item.label}}</div>
</picker-view-column>
<picker-view-column>
<div class="picker-item" v-for="(item,index) in areaDataList" :key="index">{{item.label}}</div>
</picker-view-column>
</block>
</picker-view>
</div>
</div>
</template>
<script>
import provinceData from './city-data/province.js';
import cityData from './city-data/city.js';
import areaData from './city-data/area.js';
export default {
data() {
return {
pickerValue: [0, 0, 0],
provinceDataList: [],
cityDataList: [],
areaDataList: [],
/* 是否显示控件 */
showPicker: false,
};
},
created() {
this.init()
},
props: {
/* 默认值 */
pickerValueDefault: {
type: Array,
default(){
return [0, 0, 0]
}
},
/* 主题色 */
themeColor: String
},
watch:{
pickerValueDefault(){
this.init();
}
},
methods: {
init() {
this.handPickValueDefault(); // 对 pickerValueDefault 做兼容处理
this.provinceDataList = provinceData;
this.cityDataList = cityData[this.pickerValueDefault[0]];
this.areaDataList = areaData[this.pickerValueDefault[0]][this.pickerValueDefault[1]];
this.pickerValue = this.pickerValueDefault;
},
show() {
setTimeout(() => {
this.showPicker = true;
}, 0);
},
maskClick() {
this.pickerCancel();
},
pickerCancel() {
this.showPicker = false;
this._$emit('onCancel');
},
pickerConfirm(e) {
this.showPicker = false;
this._$emit('onConfirm');
},
showPickerView() {
this.showPicker = true;
},
handPickValueDefault() {
if (this.pickerValueDefault !== [0, 0, 0]) {
if (this.pickerValueDefault[0] > provinceData.length - 1) {
this.pickerValueDefault[0] = provinceData.length - 1;
}
if (this.pickerValueDefault[1] > cityData[this.pickerValueDefault[0]].length - 1) {
this.pickerValueDefault[1] = cityData[this.pickerValueDefault[0]].length - 1;
}
if (this.pickerValueDefault[2] > areaData[this.pickerValueDefault[0]][this.pickerValueDefault[1]].length - 1) {
this.pickerValueDefault[2] = areaData[this.pickerValueDefault[0]][this.pickerValueDefault[1]].length - 1;
}
}
},
pickerChange(e) {
let changePickerValue = e.mp.detail.value;
if (this.pickerValue[0] !== changePickerValue[0]) {
// 第一级发生滚动
this.cityDataList = cityData[changePickerValue[0]];
this.areaDataList = areaData[changePickerValue[0]][0];
changePickerValue[1] = 0;
changePickerValue[2] = 0;
} else if (this.pickerValue[1] !== changePickerValue[1]) {
// 第二级滚动
this.areaDataList =
areaData[changePickerValue[0]][changePickerValue[1]];
changePickerValue[2] = 0;
}
this.pickerValue = changePickerValue;
this._$emit('onChange');
},
_$emit(emitName) {
let pickObj = {
label: this._getLabel(),
value: this.pickerValue,
cityCode: this._getCityCode()
};
this.$emit(emitName, pickObj);
},
_getLabel() {
let pcikerLabel =
this.provinceDataList[this.pickerValue[0]].label +
'-' +
this.cityDataList[this.pickerValue[1]].label +
'-' +
this.areaDataList[this.pickerValue[2]].label;
return pcikerLabel;
},
_getCityCode() {
return this.areaDataList[this.pickerValue[2]].value;
}
}
};
</script>
<style>
.pickerMask {
position: fixed;
z-index: 1000;
top: 0;
right: 0;
left: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
}
.mpvue-picker-content {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
transition: all 0.3s ease;
transform: translateY(100%);
z-index: 3000;
}
.mpvue-picker-view-show {
transform: translateY(0);
}
.mpvue-picker__hd {
display: flex;
padding: 9px 15px;
background-color: #fff;
position: relative;
text-align: center;
font-size: 17px;
}
.mpvue-picker__hd:after {
content: ' ';
position: absolute;
left: 0;
bottom: 0;
right: 0;
height: 1px;
border-bottom: 1px solid #e5e5e5;
color: #e5e5e5;
transform-origin: 0 100%;
transform: scaleY(0.5);
}
.mpvue-picker__action {
display: block;
flex: 1;
color: #1aad19;
}
.mpvue-picker__action:first-child {
text-align: left;
color: #888;
}
.mpvue-picker__action:last-child {
text-align: right;
}
.picker-item {
text-align: center;
line-height: 40px;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 16px;
}
.mpvue-picker-view {
position: relative;
bottom: 0;
left: 0;
width: 100%;
height: 238px;
background-color: rgba(255, 255, 255, 1);
}
</style>
mpvue-picker
mpvuePicker.vue
<template>
<view class="mpvue-picker">
<view :class="{'pickerMask':showPicker}" @click="maskClick" catchtouchmove="true"></view>
<view class="mpvue-picker-content " :class="{'mpvue-picker-view-show':showPicker}">
<view class="mpvue-picker__hd" catchtouchmove="true">
<view class="mpvue-picker__action" @click="pickerCancel">取消</view>
<view class="mpvue-picker__action" :style="{color:themeColor}" @click="pickerConfirm">确定</view>
</view>
<!-- 单列 -->
<picker-view indicator-style="height: 40px;" class="mpvue-picker-view" :value="pickerValue" @change="pickerChange" v-if="mode==='selector' && pickerValueSingleArray.length > 0">
<block>
<picker-view-column>
<view class="picker-item" v-for="(item,index) in pickerValueSingleArray" :key="index">{{item.label}}</view>
</picker-view-column>
</block>
</picker-view>
<!-- 时间选择器 -->
<picker-view indicator-style="height: 40px;" class="mpvue-picker-view" :value="pickerValue" @change="pickerChange" v-if="mode==='timeSelector'">
<block>
<picker-view-column>
<view class="picker-item" v-for="(item,index) in pickerValueHour" :key="index">{{item.label}}</view>
</picker-view-column>
<picker-view-column>
<view class="picker-item" v-for="(item,index) in pickerValueMinute" :key="index">{{item.label}}</view>
</picker-view-column>
</block>
</picker-view>
<!-- 多列选择 -->
<picker-view indicator-style="height: 40px;" class="mpvue-picker-view" :value="pickerValue" @change="pickerChange" v-if="mode==='multiSelector'">
<block v-for="(n,index) in pickerValueMulArray.length" :key="index">
<picker-view-column>
<view class="picker-item" v-for="(item,index1) in pickerValueMulArray[n]" :key="index1">{{item.label}}</view>
</picker-view-column>
</block>
</picker-view>
<!-- 二级联动 -->
<picker-view indicator-style="height: 40px;" class="mpvue-picker-view" :value="pickerValue" @change="pickerChangeMul" v-if="mode==='multiLinkageSelector' && deepLength===2">
<block>
<picker-view-column>
<view class="picker-item" v-for="(item,index) in pickerValueMulTwoOne" :key="index">{{item.label}}</view>
</picker-view-column>
<picker-view-column>
<view class="picker-item" v-for="(item,index) in pickerValueMulTwoTwo" :key="index">{{item.label}}</view>
</picker-view-column>
</block>
</picker-view>
<!-- 三级联动 -->
<picker-view indicator-style="height: 40px;" class="mpvue-picker-view" :value="pickerValue" @change="pickerChangeMul" v-if="mode==='multiLinkageSelector' && deepLength===3">
<block>
<picker-view-column>
<view class="picker-item" v-for="(item,index) in pickerValueMulThreeOne" :key="index">{{item.label}}</view>
</picker-view-column>
<picker-view-column>
<view class="picker-item" v-for="(item,index) in pickerValueMulThreeTwo" :key="index">{{item.label}}</view>
</picker-view-column>
<picker-view-column>
<view class="picker-item" v-for="(item,index) in pickerValueMulThreeThree" :key="index">{{item.label}}</view>
</picker-view-column>
</block>
</picker-view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
pickerChangeValue: [],
pickerValue: [],
pickerValueArrayChange: true,
modeChange: false,
pickerValueSingleArray: [],
pickerValueHour: [],
pickerValueMinute: [],
pickerValueMulArray: [],
pickerValueMulTwoOne: [],
pickerValueMulTwoTwo: [],
pickerValueMulThreeOne: [],
pickerValueMulThreeTwo: [],
pickerValueMulThreeThree: [],
/* 是否显示控件 */
showPicker: false,
};
},
props: {
/* mode */
mode: {
type: String,
default: 'selector'
},
/* picker 数值 */
pickerValueArray: {
type: Array,
default(){
return []
}
},
/* 默认值 */
pickerValueDefault: {
type: Array,
default(){
return []
}
},
/* 几级联动 */
deepLength: {
type: Number,
default: 2
},
/* 主题色 */
themeColor: String
},
watch: {
pickerValueArray(oldVal, newVal) {
this.pickerValueArrayChange = true;
},
mode(oldVal, newVal) {
this.modeChange = true;
},
pickerValueArray(val){
this.initPicker(val);
}
},
methods: {
initPicker(valueArray) {
let pickerValueArray = valueArray;
this.pickerValue = this.pickerValueDefault;
// 初始化多级联动
if (this.mode === 'selector') {
this.pickerValueSingleArray = valueArray;
} else if (this.mode === 'timeSelector') {
this.modeChange = false;
let hourArray = [];
let minuteArray = [];
for (let i = 0; i < 24; i++) {
hourArray.push({
value: i,
label: i > 9 ? `${i} 时` : `0${i} 时`
});
}
for (let i = 0; i < 60; i++) {
minuteArray.push({
value: i,
label: i > 9 ? `${i} 分` : `0${i} 分`
});
}
this.pickerValueHour = hourArray;
this.pickerValueMinute = minuteArray;
} else if (this.mode === 'multiSelector') {
this.pickerValueMulArray = valueArray;
} else if (this.mode === 'multiLinkageSelector' && this.deepLength === 2) {
// 两级联动
let pickerValueMulTwoOne = [];
let pickerValueMulTwoTwo = [];
// 第一列
for (let i = 0, length = pickerValueArray.length; i < length; i++) {
pickerValueMulTwoOne.push(pickerValueArray[i]);
}
// 渲染第二列
// 如果有设定的默认值
if (this.pickerValueDefault.length === 2) {
let num = this.pickerValueDefault[0];
for (
let i = 0, length = pickerValueArray[num].children.length; i < length; i++
) {
pickerValueMulTwoTwo.push(pickerValueArray[num].children[i]);
}
} else {
for (
let i = 0, length = pickerValueArray[0].children.length; i < length; i++
) {
pickerValueMulTwoTwo.push(pickerValueArray[0].children[i]);
}
}
this.pickerValueMulTwoOne = pickerValueMulTwoOne;
this.pickerValueMulTwoTwo = pickerValueMulTwoTwo;
} else if (
this.mode === 'multiLinkageSelector' &&
this.deepLength === 3
) {
let pickerValueMulThreeOne = [];
let pickerValueMulThreeTwo = [];
let pickerValueMulThreeThree = [];
// 第一列
for (let i = 0, length = pickerValueArray.length; i < length; i++) {
pickerValueMulThreeOne.push(pickerValueArray[i]);
}
// 渲染第二列
this.pickerValueDefault =
this.pickerValueDefault.length === 3 ?
this.pickerValueDefault :
[0, 0, 0];
if (this.pickerValueDefault.length === 3) {
let num = this.pickerValueDefault[0];
for (
let i = 0, length = pickerValueArray[num].children.length; i < length; i++
) {
pickerValueMulThreeTwo.push(pickerValueArray[num].children[i]);
}
// 第三列
let numSecond = this.pickerValueDefault[1];
for (let i = 0, length = pickerValueArray[num].children[numSecond].children.length; i < length; i++) {
pickerValueMulThreeThree.push(
pickerValueArray[num].children[numSecond].children[i]
);
}
}
this.pickerValueMulThreeOne = pickerValueMulThreeOne;
this.pickerValueMulThreeTwo = pickerValueMulThreeTwo;
this.pickerValueMulThreeThree = pickerValueMulThreeThree;
}
},
show() {
setTimeout(() => {
if (this.pickerValueArrayChange || this.modeChange) {
this.initPicker(this.pickerValueArray);
this.showPicker = true;
this.pickerValueArrayChange = false;
this.modeChange = false;
} else {
this.showPicker = true;
}
}, 0);
},
maskClick() {
this.pickerCancel();
},
pickerCancel() {
this.showPicker = false;
this._initPickerVale();
let pickObj = {
index: this.pickerValue,
value: this._getPickerLabelAndValue(this.pickerValue, this.mode).value,
label: this._getPickerLabelAndValue(this.pickerValue, this.mode).label
};
this.$emit('onCancel', pickObj);
},
pickerConfirm(e) {
this.showPicker = false;
this._initPickerVale();
let pickObj = {
index: this.pickerValue,
value: this._getPickerLabelAndValue(this.pickerValue, this.mode).value,
label: this._getPickerLabelAndValue(this.pickerValue, this.mode).label
};
this.$emit('onConfirm', pickObj);
},
showPickerView() {
this.showPicker = true;
},
pickerChange(e) {
this.pickerValue = e.mp.detail.value;
let pickObj = {
index: this.pickerValue,
value: this._getPickerLabelAndValue(this.pickerValue, this.mode).value,
label: this._getPickerLabelAndValue(this.pickerValue, this.mode).label
};
this.$emit('onChange', pickObj);
},
pickerChangeMul(e) {
if (this.deepLength === 2) {
let pickerValueArray = this.pickerValueArray;
let changeValue = e.mp.detail.value;
// 处理第一列滚动
if (changeValue[0] !== this.pickerValue[0]) {
let pickerValueMulTwoTwo = [];
// 第一列滚动第二列数据更新
for (let i = 0, length = pickerValueArray[changeValue[0]].children.length; i < length; i++) {
pickerValueMulTwoTwo.push(pickerValueArray[changeValue[0]].children[i]);
}
this.pickerValueMulTwoTwo = pickerValueMulTwoTwo;
// 第二列初始化为 0
changeValue[1] = 0;
}
this.pickerValue = changeValue;
} else if (this.deepLength === 3) {
let pickerValueArray = this.pickerValueArray;
let changeValue = e.mp.detail.value;
let pickerValueMulThreeTwo = [];
let pickerValueMulThreeThree = [];
// 重新渲染第二列
// 如果是第一列滚动
if (changeValue[0] !== this.pickerValue[0]) {
this.pickerValueMulThreeTwo = [];
for (let i = 0, length = pickerValueArray[changeValue[0]].children.length; i < length; i++) {
pickerValueMulThreeTwo.push(pickerValueArray[changeValue[0]].children[i]);
}
// 重新渲染第三列
for (let i = 0, length = pickerValueArray[changeValue[0]].children[0].children.length; i <
length; i++) {
pickerValueMulThreeThree.push(pickerValueArray[changeValue[0]].children[0].children[i]);
}
changeValue[1] = 0;
changeValue[2] = 0;
this.pickerValueMulThreeTwo = pickerValueMulThreeTwo;
this.pickerValueMulThreeThree = pickerValueMulThreeThree;
} else if (changeValue[1] !== this.pickerValue[1]) {
// 第二列滚动
// 重新渲染第三列
this.pickerValueMulThreeThree = [];
pickerValueMulThreeTwo = this.pickerValueMulThreeTwo;
for (let i = 0, length = pickerValueArray[changeValue[0]].children[changeValue[1]].children.length; i <
length; i++) {
pickerValueMulThreeThree.push(pickerValueArray[changeValue[0]].children[changeValue[1]].children[
i]);
}
changeValue[2] = 0;
this.pickerValueMulThreeThree = pickerValueMulThreeThree;
}
this.pickerValue = changeValue;
}
let pickObj = {
index: this.pickerValue,
value: this._getPickerLabelAndValue(this.pickerValue, this.mode).value,
label: this._getPickerLabelAndValue(this.pickerValue, this.mode).label
};
this.$emit('onChange', pickObj);
},
// 获取 pxikerLabel
_getPickerLabelAndValue(value, mode) {
let pickerLable;
let pickerGetValue = [];
// selector
if (mode === 'selector') {
pickerLable = this.pickerValueSingleArray[value].label;
pickerGetValue.push(this.pickerValueSingleArray[value].value);
} else if (mode === 'timeSelector') {
pickerLable = `${this.pickerValueHour[value[0]].label}-${this.pickerValueMinute[value[1]].label}`;
pickerGetValue.push(this.pickerValueHour[value[0]].value);
pickerGetValue.push(this.pickerValueHour[value[1]].value);
} else if (mode === 'multiSelector') {
for (let i = 0; i < value.length; i++) {
if (i > 0) {
pickerLable += this.pickerValueMulArray[i][value[i]].label + (i === value.length - 1 ? '' :
'-');
} else {
pickerLable = this.pickerValueMulArray[i][value[i]].label + '-';
}
pickerGetValue.push(this.pickerValueMulArray[i][value[i]].value);
}
} else if (mode === 'multiLinkageSelector') {
/* eslint-disable indent */
pickerLable =
this.deepLength === 2 ?
`${this.pickerValueMulTwoOne[value[0]].label}-${this.pickerValueMulTwoTwo[value[1]].label}` :
`${this.pickerValueMulThreeOne[value[0]].label}-${this.pickerValueMulThreeTwo[value[1]].label}-${this.pickerValueMulThreeThree[value[2]].label}`;
if (this.deepLength === 2) {
pickerGetValue.push(this.pickerValueMulTwoOne[value[0]].value);
pickerGetValue.push(this.pickerValueMulTwoTwo[value[1]].value);
} else {
pickerGetValue.push(this.pickerValueMulThreeOne[value[0]].value);
pickerGetValue.push(this.pickerValueMulThreeTwo[value[1]].value);
pickerGetValue.push(this.pickerValueMulThreeThree[value[2]].value);
}
/* eslint-enable indent */
}
return {
label: pickerLable,
value: pickerGetValue
};
},
// 初始化 pickerValue 默认值
_initPickerVale() {
if (this.pickerValue.length === 0) {
if (this.mode === 'selector') {
this.pickerValue = [0];
} else if (this.mode === 'multiSelector') {
this.pickerValue = new Int8Array(this.pickerValueArray.length);
} else if (
this.mode === 'multiLinkageSelector' &&
this.deepLength === 2
) {
this.pickerValue = [0, 0];
} else if (
this.mode === 'multiLinkageSelector' &&
this.deepLength === 3
) {
this.pickerValue = [0, 0, 0];
}
}
}
}
};
</script>
<style>
.pickerMask {
position: fixed;
z-index: 1000;
top: 0;
right: 0;
left: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
}
.mpvue-picker-content {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
transition: all 0.3s ease;
transform: translateY(100%);
z-index: 3000;
}
.mpvue-picker-view-show {
transform: translateY(0);
}
.mpvue-picker__hd {
display: flex;
padding: 9px 15px;
background-color: #fff;
position: relative;
text-align: center;
font-size: 17px;
}
.mpvue-picker__hd:after {
content: ' ';
position: absolute;
left: 0;
bottom: 0;
right: 0;
height: 1px;
border-bottom: 1px solid #e5e5e5;
color: #e5e5e5;
transform-origin: 0 100%;
transform: scaleY(0.5);
}
.mpvue-picker__action {
display: block;
flex: 1;
color: #1aad19;
}
.mpvue-picker__action:first-child {
text-align: left;
color: #888;
}
.mpvue-picker__action:last-child {
text-align: right;
}
.picker-item {
text-align: center;
line-height: 40px;
font-size: 16px;
}
.mpvue-picker-view {
position: relative;
bottom: 0;
left: 0;
width: 100%;
height: 238px;
background-color: rgba(255, 255, 255, 1);
}
</style>
payments
paymentsByAli.vue
<template>
<view class='cell-group payment-method'>
<view class='cell-item add-title-item' v-for="item in payments" :key="item.code" @click="toPayHandler(item.code)"
v-if="!(type == 2 && item.code == 'balancepay')">
<view class='cell-item-hd'>
<image class='cell-hd-icon' :src='item.icon'></image>
</view>
<view class='cell-item-bd'>
<view class="cell-bd-view">
<text class="cell-bd-text">{{ item.name }}</text>
</view>
<view class="cell-bd-view">
<text class="cell-bd-text address">{{ item.memo }}</text>
</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
<view class="payment-pop" v-show="popShow">
<view class="payment-pop-c">
<image src="/static/image/wait-pay.png" style="width: 30px;
height: 30px;"></image>
<view class="text">支付中,请稍后...</view>
</view>
<view class="payment-pop-b">
<button class="btn btn-c" @click="popBtn">支付失败</button>
<button class="btn btn-o" @click="popBtn">支付成功</button>
</view>
</view>
</view>
</template>
<script>
import {
apiBaseUrl
} from '@/config/config.js';
export default {
props: {
// 如果是商品订单此参数必须
orderId: {
type: String,
default () {
return '';
}
},
// 如果是充值订单此参数必须
recharge: {
type: Number,
default () {
return 0;
}
},
// 用户id
uid: {
type: Number,
default () {
return 0;
}
},
// 订单类型
type: {
type: Number,
default () {
return 1;
}
}
},
data() {
return {
payments: [],
popShow: false
}
},
mounted() {
this.getPayments();
},
methods: {
// 获取可用支付方式列表
getPayments() {
this.$api.paymentList({}, res => {
if (res.status) {
this.payments = this.formatPayments(res.data);
}
})
},
// 支付方式处理
formatPayments(payments) {
payments = payments.filter(item => item.code !== 'wechatpay');
// 如果是充值订单 过滤余额支付 过滤非线上支付方式
if (this.type === 2) {
payments = payments.filter(item => item.code !== 'balancepay' || item.is_online === 1)
}
// 设置logo图片
payments.forEach(item => {
this.$set(item, 'icon', '/static/image/' + item.code + '.png');
});
return payments;
},
// 用户点击支付方式处理
toPayHandler(code) {
this.popShow = true;
let data = {
payment_code: code,
payment_type: this.type
}
data['ids'] = (this.type == 1 || this.type == 5 || this.type == 6) ? this.orderId : this.uid
// 判断订单支付类型
if (this.type == 2 && this.recharge) {
data['params'] = {
money: this.recharge,
trade_type: 'JSAPI'
}
} else if ((this.type == 5 || this.type == 6) && this.recharge) {
data['params'] = {
trade_type: 'JSAPI',
formid: this.orderId
}
} else {
data['params'] = {
trade_type: 'JSAPI'
}
}
let _this = this;
switch (code) {
case 'alipay':
this.$api.pay(data, res => {
if (res.status) {
uni.requestPayment({
provider: 'alipay',
tradeNO: res.data.trade_no,
success: function(e) {
if (e.errMsg === 'requestPayment:ok') {
_this.$common.successToShow(res.msg, () => {
_this.$common.redirectTo('/pages/goods/payment/result?id=' + res.data.payment_id);
});
}
}
});
} else {
this.$common.errorToShow(res.msg);
}
})
break
case 'balancepay':
//用户余额支付
this.$api.pay(data, res => {
if (res.status) {
this.$common.redirectTo('/pages/goods/payment/result?id=' + res.data.payment_id);
} else {
this.$common.errorToShow(res.msg);
}
})
break;
case 'offline':
//线下支付
this.$common.modelShow('线下支付说明', '请联系客服进行线下支付', () => {}, false, '取消', '确定')
break;
}
},
,
// 支付中显示隐藏
popBtn() {
this.popShow = false
}
}
}
</script>
<style>
.payment-method .cell-item-hd {
min-width: 70upx;
}
.payment-method .cell-hd-icon {
width: 70upx;
height: 70upx;
}
.payment-method .cell-item-bd {
border-left: 2upx solid #F0F0F0;
padding-left: 30upx;
}
.payment-method .cell-bd-text {
font-size: 28upx;
color: #666;
}
.payment-method .address {
font-size: 24upx;
color: #999;
}
.payment-pop {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 400rpx;
height: 272rpx;
background-color: #fff;
text-align: center;
box-shadow: 0 0 20rpx #ccc;
/* border-radius: 10rpx; */
}
.payment-pop-c {
padding: 50rpx 30rpx;
/* line-height: 300rpx; */
font-size: 32rpx;
color: #999;
}
.payment-pop-b {
position: absolute;
bottom: 0;
display: flex;
width: 100%;
justify-content: space-between;
}
.payment-pop-b .btn {
flex: 1;
}
.payment-pop .text {
font-size: 24upx;
}
</style>
paymentsByApp.vue
<template>
<view class='cell-group payment-method'>
<view class='cell-item add-title-item' v-for="item in payments" :key="item.code" @click="toPayHandler(item.code)"
v-if="!(type == 2 && item.code == 'balancepay')">
<view class='cell-item-hd'>
<image class='cell-hd-icon' :src='item.icon'></image>
</view>
<view class='cell-item-bd'>
<view class="cell-bd-view">
<text class="cell-bd-text">{{ item.name }}</text>
</view>
<view class="cell-bd-view">
<text class="cell-bd-text address">{{ item.memo }}</text>
</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
<view class="payment-pop" v-show="popShow">
<view class="payment-pop-c">
<image src="/static/image/wait-pay.png" style="width: 30px;
height: 30px;"></image>
<view class="text">支付中,请稍后...</view>
</view>
<view class="payment-pop-b">
<button class="btn btn-c" @click="popBtn">支付失败</button>
<button class="btn btn-o" @click="popBtn">支付成功</button>
</view>
</view>
</view>
</template>
<script>
import {
apiBaseUrl
} from '@/config/config.js'
export default {
props: {
// 如果是商品订单此参数必须
orderId: {
type: String,
default () {
return ''
}
},
// 如果是充值订单此参数必须
recharge: {
type: Number,
default () {
return 0
}
},
// 用户id
uid: {
type: Number,
default () {
return 0
}
},
// 订单类型
type: {
type: Number,
default () {
return 1
}
}
},
data() {
return {
payments: [],
popShow: false
}
},
mounted() {
this.getPayments()
},
methods: {
// 获取可用支付方式列表
getPayments() {
this.$api.paymentList({}, res => {
if (res.status) {
this.payments = this.formatPayments(res.data)
}
})
},
// 支付方式处理
formatPayments(payments) {
// 如果是充值订单 过滤余额支付 过滤非线上支付方式
if (this.type === 2) {
payments = payments.filter(item => item.code !== 'balancepay' || item.is_online === 1)
}
// 设置logo图片
payments.forEach(item => {
this.$set(item, 'icon', '/static/image/' + item.code + '.png')
})
return payments
},
// 用户点击支付方式处理
toPayHandler(code) {
this.popShow = true;
let _this = this
let data = {
payment_code: code,
payment_type: _this.type
}
data['ids'] = (this.type == 1 || this.type == 5 || this.type == 6) ? this.orderId : this.uid
if ((this.type == 5 || this.type == 6) && this.recharge) {
data['params'] = {
trade_type: 'APP',
formid: this.orderId
}
}
switch (code) {
case 'alipay':
/**
* 支付宝支付需要模拟GET提交数据
*/
if (_this.type == 1 && _this.orderId) {
data['params'] = {
trade_type: 'APP'
}
} else if (_this.type == 2 && _this.recharge) {
data['params'] = {
trade_type: 'APP',
money: _this.recharge
}
}
_this.$api.pay(data, res => {
if (res.status) {
uni.requestPayment({
provider: "alipay",
orderInfo: res.data.data,
success: function(data) {
_this.$common.successToShow('支付成功', () => {
_this.redirectHandler(res.data.payment_id)
})
}
});
} else {
_this.$comon.errorToShow(res.msg)
}
})
break
case 'wechatpay':
// 微信 H5支付
if (_this.type == 1 && _this.orderId) {
data['params'] = {
trade_type: 'APP'
}
} else if (_this.type == 2 && _this.recharge) {
data['params'] = {
trade_type: 'APP',
money: _this.recharge
}
}
// 微信app支付
_this.$api.pay(data, res => {
if (res.status) {
console.log(JSON.stringify(res));
// 调用微信支付
uni.requestPayment({
provider: "wxpay",
orderInfo: {
appid: res.data.appid,
noncestr: res.data.noncestr,
package: res.data.package,
partnerid: res.data.partnerid,
prepayid: res.data.prepayid,
timestamp: res.data.timestamp,
sign: res.data.sign,
},
success: function(data) {
_this.$common.successToShow('支付成功', () => {
_this.redirectHandler(res.data.payment_id)
})
},
fail: function(res) {
console.log(JSON.stringify(res));
}
});
} else {
_this.$common.errorToShow(res.msg)
}
})
break
case 'balancepay':
/**
* 用户余额支付
*
*/
_this.$api.pay(data, res => {
if (res.status) {
_this.redirectHandler(res.data.payment_id)
} else {
_this.$common.errorToShow(res.msg)
}
})
break
case 'offline':
/**
* 线下支付
*/
_this.$common.modelShow('线下支付说明', '请联系客服进行线下支付', () => {}, false, '取消', '确定')
break
}
},
// 支付成功后跳转操作
redirectHandler(paymentId) {
this.$common.redirectTo('/pages/goods/payment/result?id=' + paymentId)
},
// 支付中显示隐藏
popBtn() {
this.popShow = false
}
}
}
</script>
<style>
.payment-method .cell-item-hd {
min-width: 70upx;
}
.payment-method .cell-hd-icon {
width: 70upx;
height: 70upx;
}
.payment-method .cell-item-bd {
border-left: 2upx solid #F0F0F0;
padding-left: 30upx;
}
.payment-method .cell-bd-text {
font-size: 28upx;
color: #666;
}
.payment-method .address {
font-size: 24upx;
color: #999;
}
.payment-pop {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 400rpx;
height: 272rpx;
background-color: #fff;
text-align: center;
box-shadow: 0 0 20rpx #ccc;
/* border-radius: 10rpx; */
}
.payment-pop-c {
padding: 50rpx 30rpx;
/* line-height: 300rpx; */
font-size: 32rpx;
color: #999;
}
.payment-pop-b {
position: absolute;
bottom: 0;
display: flex;
width: 100%;
justify-content: space-between;
}
.payment-pop-b .btn {
flex: 1;
}
.payment-pop .text {
font-size: 24upx;
}
</style>
paymentsByH5.vue
<template>
<view class='cell-group payment-method'>
<view class='cell-item add-title-item' v-for="item in payments" :key="item.code" @click="toPayHandler(item.code)"
v-if="!(type == 2 && item.code == 'balancepay')">
<view class='cell-item-hd'>
<image class='cell-hd-icon' :src='item.icon'></image>
</view>
<view class='cell-item-bd'>
<view class="cell-bd-view">
<text class="cell-bd-text">{{ item.name }}</text>
</view>
<view class="cell-bd-view">
<text class="cell-bd-text address">{{ item.memo }}</text>
</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
<view class="payment-pop" v-show="popShow">
<view class="payment-pop-c">
<image src="/static/image/wait-pay.png" style="width: 30px;
height: 30px;"></image>
<view class="text">支付中,请稍后...</view>
</view>
<view class="payment-pop-b">
<button class="btn btn-c" @click="popBtn">支付失败</button>
<button class="btn btn-o" @click="popBtn">支付成功</button>
</view>
</view>
</view>
</template>
<script>
import {
baseUrl
} from '@/config/config.js'
export default {
props: {
// 如果是商品订单此参数必须
orderId: {
type: String,
default () {
return ''
}
},
// 如果是充值订单此参数必须
recharge: {
type: Number,
default () {
return 0
}
},
// 用户id
uid: {
type: Number,
default () {
return 0
}
},
// 订单类型
type: {
type: Number,
default () {
return 1
}
}
},
data() {
return {
payments: [],
openid: '',
popShow: false
}
},
mounted() {
this.getPayments()
},
methods: {
// 获取可用支付方式列表
getPayments() {
this.$api.paymentList({}, res => {
if (res.status) {
this.payments = this.formatPayments(res.data)
}
})
},
// 支付方式处理
formatPayments(payments) {
// h5支付并且是在微信浏览器内 过滤支付宝支付
if (this.$common.isWeiXinBrowser()) {
payments = payments.filter(item => item.code !== 'alipay')
}
// 如果是充值订单 过滤余额支付 过滤非线上支付方式
if (this.type === 2) {
payments = payments.filter(
item => item.code !== 'balancepay' || item.is_online === 1
)
}
// 设置logo图片
payments.forEach(item => {
this.$set(item, 'icon', '/static/image/' + item.code + '.png')
})
return payments
},
checkWXJSBridge(data) {
let that = this
let interval = setInterval(() => {
if (typeof window.WeixinJSBridge != 'undefined') {
clearTimeout(interval)
that.onBridgeReady(data)
}
}, 200)
},
onBridgeReady(data) {
var _this = this
window.WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
appId: data.appid, // 公众号名称,由商户传入
timeStamp: data.timeStamp, // 时间戳,自1970年以来的秒数
nonceStr: data.nonceStr, // 随机串
package: data.package,
signType: data.signType, // 微信签名方式:
paySign: data.paySign // 微信签名
},
function(res) {
if (res.err_msg === 'get_brand_wcpay_request:ok') {
_this.$common.successToShow('支付成功')
} else if (res.err_msg === 'get_brand_wcpay_request:cancel') {
_this.$common.errorToShow('取消支付')
} else {
_this.$common.errorToShow('支付失败')
}
setTimeout(() => {
_this.$common.redirectTo(
'/pages/goods/payment/result?id=' + data.payment_id
)
}, 1000)
}
)
},
// 用户点击支付方式处理
toPayHandler(code) {
this.popShow = true;
let data = {
payment_code: code,
payment_type: this.type
}
data['ids'] = (this.type == 1 || this.type == 5 || this.type == 6) ? this.orderId : this.uid
switch (code) {
case 'alipay':
/**
* 支付宝支付需要模拟GET提交数据
*/
if (this.type == 1 && this.orderId) {
data['params'] = {
trade_type: 'WAP',
return_url: baseUrl +
'wap/pages/goods/payment/result'
}
} else if (this.type == 2 && this.recharge) {
data['params'] = {
money: this.recharge,
return_url: baseUrl + 'wap/pages/goods/payment/result'
}
} else if ((this.type == 5 || this.type == 6) && this.recharge) {
data['params'] = {
formid: this.orderId
}
}
this.$api.pay(data, res => {
if (res.status) {
const url = res.data.url
const data = res.data.data
// 模拟GET提交
let tempForm = document.createElement('form')
tempForm.id = 'aliPay'
tempForm.methods = 'post'
tempForm.action = url
tempForm.target = '_self'
let input = []
for (let k in data) {
input[k] = document.createElement('input')
input[k].type = 'hidden'
input[k].name = k
input[k].value = data[k]
tempForm.appendChild(input[k])
}
tempForm.addEventListener('submit', function() {}, false)
document.body.appendChild(tempForm)
tempForm.dispatchEvent(new Event('submit'))
tempForm.submit()
document.body.removeChild(tempForm)
}
})
break
case 'wechatpay':
/**
* 微信支付有两种
* 判断是否在微信浏览器
* 微信jsapi支付
*/
let isWeiXin = this.$common.isWeiXinBrowser()
if (isWeiXin) {
var transitUrl =
baseUrl +
'wap/pages/goods/payment/auth?order_id=' +
this.orderId +
'&type=' +
this.type;
if (this.type == 1 && this.orderId) {
// 微信jsapi支付
// if (this.openid) {
// data['params'] = {
// trade_type: 'JSAPI_OFFICIAL',
// openid: this.openid
// }
// } else {
// data['params'] = {
// trade_type: 'JSAPI_OFFICIAL',
// url: window.location.href
// }
// }
data['params'] = {
trade_type: 'JSAPI_OFFICIAL',
url: transitUrl
}
} else if (this.type == 2 && this.recharge) {
data['params'] = {
trade_type: 'JSAPI_OFFICIAL',
money: this.recharge,
url: transitUrl + '&uid=' + this.uid + '&money=' + this.recharge
}
// if (this.openid) {
// data['params'] = {
// money: this.recharge,
// openid: this.openid
// }
// } else {
// data['params'] = {
// money: this.recharge,
// url: window.location.href
// }
// }
} else if ((this.type == 5 || this.type == 6) && this.recharge) {
data['params'] = {
formid: this.orderId
}
}
this.$api.pay(data, res => {
if (!res.status && res.data == '10066') {
window.location.href = res.msg
return;
}
const data = res.data
this.checkWXJSBridge(data)
})
} else {
// 微信 H5支付
if (this.type == 1 && this.orderId) {
data['params'] = {
trade_type: 'MWEB',
return_url: baseUrl +
'wap/pages/goods/payment/result'
}
} else if (this.type == 2 && this.recharge) {
data['params'] = {
trade_type: 'MWEB',
money: this.recharge,
return_url: baseUrl + 'wap/pages/goods/payment/result'
}
} else if ((this.type == 5 || this.type == 6) && this.recharge) {
data['params'] = {
formid: this.orderId
}
}
// 微信h5支付
this.$api.pay(data, res => {
if (res.status) {
location.href = res.data.mweb_url
} else {
this.$common.errorToShow(res.msg)
}
})
}
break
case 'balancepay':
/**
* 用户余额支付
*
*/
if ((this.type == 5 || this.type == 6) && this.recharge) {
data['params'] = {
formid: this.orderId
}
}
this.$api.pay(data, res => {
if (res.status) {
this.$common.redirectTo(
'/pages/goods/payment/result?id=' + res.data.payment_id
)
} else {
this.$common.errorToShow(res.msg)
}
})
break
case 'offline':
/**
* 线下支付
*/
this.$common.modelShow(
'线下支付说明',
'请联系客服进行线下支付',
() => {},
false,
'取消',
'确定'
)
break
}
},
// 支付中显示隐藏
popBtn() {
this.popShow = false
}
}
}
</script>
<style>
.payment-method .cell-item-hd {
min-width: 70upx;
}
.payment-method .cell-hd-icon {
width: 70upx;
height: 70upx;
}
.payment-method .cell-item-bd {
border-left: 2upx solid #f0f0f0;
padding-left: 30upx;
}
.payment-method .cell-bd-text {
font-size: 28upx;
color: #666;
}
.payment-method .address {
font-size: 24upx;
color: #999;
}
.payment-pop {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 400rpx;
height: 272rpx;
background-color: #fff;
text-align: center;
box-shadow: 0 0 20rpx #ccc;
/* border-radius: 10rpx; */
}
.payment-pop-c {
padding: 50rpx 30rpx;
/* line-height: 300rpx; */
font-size: 32rpx;
color: #999;
}
.payment-pop-b {
position: absolute;
bottom: 0;
display: flex;
width: 100%;
justify-content: space-between;
}
.payment-pop-b .btn {
flex: 1;
}
.payment-pop .text {
font-size: 24upx;
}
</style>
paymentsByWx.vue
<template>
<view class='cell-group payment-method payment-wx'>
<form class='cell-item add-title-item' v-for="item in payments" :key="item.code" @submit="toPayHandler" report-submit="true"
v-if="!(type == 2 && item.code == 'balancepay')">
<input name="code" :value="item.code" class="no-show">
<button class="btn" form-type="submit">
<view class='cell-item-hd'>
<image class='cell-hd-icon' :src='item.icon'></image>
</view>
<view class='cell-item-bd'>
<view class="cell-bd-view">
<text class="cell-bd-text">{{ item.name }}</text>
</view>
<view class="cell-bd-view">
<text class="cell-bd-text address">{{ item.memo }}</text>
</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</button>
</form>
<view class="payment-pop" v-show="popShow">
<view class="payment-pop-c">
<image src="/static/image/wait-pay.png"></image>
<view class="text">支付中,请稍后...</view>
</view>
<view class="payment-pop-b">
<button class="btn btn-c" @click="popBtn">支付失败</button>
<button class="btn btn-o" @click="popBtn">支付成功</button>
</view>
</view>
</view>
</template>
<script>
import {
apiBaseUrl
} from '@/config/config.js'
export default {
props: {
// 如果是商品订单此参数必须
orderId: {
type: String,
default () {
return ''
}
},
// 如果是充值订单此参数必须
recharge: {
type: Number,
default () {
return 0
}
},
// 用户id
uid: {
type: Number,
default () {
return 0
}
},
// 订单类型
type: {
type: Number,
default () {
return 1
}
}
},
data() {
return {
payments: [],
popShow: false
}
},
mounted() {
this.getPayments()
},
methods: {
// 获取可用支付方式列表
getPayments() {
this.$api.paymentList({}, res => {
if (res.status) {
this.payments = this.formatPayments(res.data)
}
})
},
// 支付方式处理
formatPayments(payments) {
// 过滤支付宝支付
payments = payments.filter(item => item.code !== 'alipay')
// 如果是充值订单 过滤余额支付 过滤非线上支付方式
if (this.type === 2) {
payments = payments.filter(item => item.code !== 'balancepay' || item.is_online === 1)
}
// 设置logo图片
payments.forEach(item => {
this.$set(item, 'icon', '/static/image/' + item.code + '.png')
})
return payments
},
// 用户点击支付方式处理
toPayHandler(e) {
this.popShow = true;
let code = e.target.value.code;
let formId = e.detail.formId;
let data = {
payment_code: code,
payment_type: this.type,
params: {
formid: formId
}
}
data['ids'] = (this.type == 1 || this.type == 5 || this.type == 6) ? this.orderId : this.uid
// 判断订单支付类型
if (this.type == 2 && this.recharge) {
data['params'] = {
money: this.recharge
}
} else if ((this.type == 5 || this.type == 6) && this.recharge) {
data['params'] = {
formid: this.orderId
}
}
let _this = this
switch (code) {
case 'wechatpay':
this.$api.pay(data, res => {
if (res.status) {
uni.requestPayment({
provider: 'wxpay',
timeStamp: res.data.timeStamp,
nonceStr: res.data.nonceStr,
package: res.data.package,
signType: res.data.signType,
paySign: res.data.paySign,
success: function(e) {
if (e.errMsg === 'requestPayment:ok') {
_this.$common.successToShow(res.msg, () => {
_this.$common.redirectTo('/pages/goods/payment/result?id=' + res.data.payment_id)
})
}
}
});
} else {
this.$common.errorToShow(res.msg)
}
})
break
case 'balancepay':
/**
* 用户余额支付
*
*/
this.$api.pay(data, res => {
if (res.status) {
this.$common.redirectTo('/pages/goods/payment/result?id=' + res.data.payment_id)
} else {
this.$common.errorToShow(res.msg)
}
})
break
case 'offline':
/**
* 线下支付
*/
this.$common.modelShow('线下支付说明', '请联系客服进行线下支付', () => {}, false, '取消', '确定')
break
}
},
// 支付中显示隐藏
popBtn() {
this.popShow = false
}
}
}
</script>
<style>
.payment-method .cell-item-hd {
min-width: 70upx;
}
.payment-method .cell-hd-icon {
width: 70upx;
height: 70upx;
}
.payment-method .cell-item-bd {
border-left: 2upx solid #F0F0F0;
padding-left: 30upx;
}
.payment-method .cell-bd-text {
font-size: 28upx;
color: #666;
}
.payment-method .address {
font-size: 24upx;
color: #999;
}
.no-show {
display: none;
}
.payment-wx .btn {
background-color: #fff;
line-height: 1.7;
padding: 0;
width: 724upx;
position: relative;
overflow: hidden;
float: left;
}
.payment-wx .btn .cell-item-hd {
min-width: 100upx;
}
.payment-pop {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 400rpx;
height: 272rpx;
background-color: #fff;
text-align: center;
box-shadow: 0 0 20rpx #ccc;
/* border-radius: 10rpx; */
}
.payment-pop-c {
padding: 50rpx 30rpx;
/* line-height: 300rpx; */
font-size: 32rpx;
color: #999;
}
.payment-pop-c image {
width: 60upx;
height: 60upx;
}
.payment-pop-b {
position: absolute;
bottom: 0;
display: flex;
width: 100%;
justify-content: space-between;
}
.payment-pop-b .btn {
flex: 1;
}
.payment-pop-b .btn-o {
background-color: #FF7159;
}
.payment-pop .text {
font-size: 24upx;
}
</style>
posters-layer
index.vue
<style lang="less">
.posters-layer {
position: fixed;
top: -5000px;
left: -5000px;
// top: 0;
// left: 0;
}
</style>
<template>
<canvas
canvas-id="canvasdrawer"
:style="{width: width + 'px', height: height + 'px'}"
class="posters-layer">
</canvas>
</template>
<script>
const CACHE_KEYS = 'temp_canvasdrawer_pic_cache';
export default {
data() {
return {
width: 100,
height: 100,
paintingData: { views: [] },
index: 0,
imageList: [],
tempFileList: [],
isPainting: false,
ctx: null,
cache: {},
}
},
props: {
postersData: {
type: Object,
default() {
return { views: [] };
}
}
},
watch: {
postersData(newVal, oldVal) {
newVal = newVal || { views: [] };
this.createPosters(newVal);
}
},
mounted() {
uni.removeStorageSync('CACHE_KEYS');
this.cache = uni.getStorageSync('CACHE_KEYS') || {};
this.ctx = uni.createCanvasContext('canvasdrawer', this);
this.createPosters(this.postersData);
},
methods: {
createPosters(newVal) {
if (!newVal.width || !newVal.height) {
return;
};
// newVal = newVal || { views: [] };
newVal.views = newVal.views || [];
uni.removeStorageSync('CACHE_KEYS')
this.paintingData = newVal;
this.ctx && this.ctx.clearActions();
if (!this.isPainting) {
if (newVal.width && newVal.height) {
this.isPainting = true;
try {
this.readyPigment();
}
catch(err) {
this.$emit('error');
}
}
}
},
readyPigment() {
const { width, height, views, background, radius = 0 } = this.paintingData;
this.width = width;
this.height = height;
const inter = setInterval(() => {
if (this.ctx) {
clearInterval(inter);
this.ctx.clearActions();
this.ctx.closePath();
// begin another path
this.ctx.beginPath();
this.drawRect({
// || 'rgba(255, 255, 255, 0)'
background: background,
top: 0,
left: 0,
radius,
width,
height
})
this.getImageList(views);
this.downLoadImages(0);
}
}, 100);
},
getImageList(views) {
const imageList = [];
for (let i = 0; i < views.length; i++) {
if (views[i].type === 'image') {
imageList.push(views[i].url);
}
}
this.imageList = imageList;
},
downLoadImages(index) {
const imageList = this.imageList;
const tempFileList = this.tempFileList;
if (index < imageList.length) {
// console.log(imageList[index])
this.getImageInfo(imageList[index]).then(imgInfo => {
tempFileList.push(imgInfo)
this.tempFileList = tempFileList;
this.downLoadImages(index + 1);
})
} else {
this.startPainting();
}
},
tailorImageDraw(view, imgInfo) {
// _views.tailor == 'center'
let px = 1;
let wMultiple = (view.width * px) / imgInfo.originWidth;
let hMultiple = (view.height * px) / imgInfo.originHeight;
let sizeNormal = false;
if (wMultiple <= 1 && hMultiple <= 1) {
let multiple = wMultiple > hMultiple ? wMultiple : hMultiple;
// let tempW = imgInfo.originWidth * multiple;
// let tempH = imgInfo.originHeight * multiple;
let tempW = (view.width * px) / multiple;
let tempH = (view.height * px) / multiple;
let sx = (imgInfo.originWidth - tempW) / 2;
let sy = (imgInfo.originHeight - tempH) / 2;
let ex = sx + tempW;
let ey = sy + tempH;
view['sx'] = sx || 0;
view['sy'] = sy || 0;
view['ex'] = ex || 0;
view['ey'] = ey || 0;
sizeNormal = true;
}
const data = {
...view,
ow: imgInfo.originWidth,
oh: imgInfo.originHeight
};
// console.log(JSON.stringify(data));
if (!sizeNormal) {
delete data.tailor;
}
// this.drawImage(data);
return data;
},
async startPainting() {
const { tempFileList, paintingData: { views } } = this;
for (let i = 0, imageIndex = 0; i < views.length; i++) {
if (views[i].type === 'image') {
let _img = tempFileList[imageIndex];
let _views = views[i];
let drawData = {};
if (_views.tailor) {
_views = this.tailorImageDraw(_views, _img);
}
drawData = {
..._views,
url: _img.localPath
};
this.drawImage(drawData);
// if (_views.radius) {
// this.drawRoundRect(drawData);
// }
// else {
// }
imageIndex++;
} else if (views[i].type === 'text') {
if (!this.ctx.measureText) {
uni.showModal({
title: '提示',
content: '当前微信版本过低,无法使用 measureText 功能,请升级到最新微信版本后重试。'
});
} else {
this.drawText(views[i]);
}
} else if (views[i].type === 'rect') {
this.drawRect(views[i]);
}
else if (views[i].type === 'round') {
this.drawRound(views[i]);
}
}
this.ctx.draw(true, () => {
uni.setStorageSync('CACHE_KEYS', this.cache);
this.saveImageToLocal();
})
},
old_drawImage(params) {
// console.log(params)
const {
url,
top = 0,
left = 0,
width = 0,
height = 0,
sx = 0,
sy = 0,
ex = 0,
ey = 0
} = params;
if ('tailor' in params) {
this.ctx.drawImage(url, sx, sy, ex, ey, left, top, width, height);
}
else if (params.round === true) {
this.drawRoundImage(params);
}
else {
this.ctx.drawImage(url, left, top, width, height);
}
},
old_drawRoundImage(params) {
let ctx = this.ctx;
let x = params.left;
let y = params.top;
let w = params.width;
let h = params.height;
let url = params.url;
let r = w / 2;
ctx.save();
ctx.beginPath();
ctx.arc(x + r, y + r, r, 0, 2 * Math.PI);
ctx.setFillStyle(params.background || '#ffffff');
ctx.fill();
ctx.clip();
// 这个地方想要的是头像,简单点就放了个矩形
ctx.drawImage(url, x, y, w, h);
ctx.restore();
},
_drawRadiusRect(params) {
const {
top = 0,
left = 0,
width = 0,
height = 0,
radius = 0,
} = params;
let x = left;
let y = top;
let w = width;
let h = height;
// let bgc = background;
let r = radius;
// let br = radius;
this.ctx.beginPath();
this.ctx.moveTo(x + r, y); // 移动到左上角的点
this.ctx.lineTo(x + w - r, y);
this.ctx.arc(x + w - r, y + r, r, 2 * Math.PI * (3 / 4), 2 * Math.PI * (4 / 4));
this.ctx.lineTo(x + w, y + h - r);
this.ctx.arc(x + w - r, y + h - r, r, 0, 2 * Math.PI * (1 / 4));
this.ctx.lineTo(x + r, y + h);
this.ctx.arc(x + r, y + h - r, r, 2 * Math.PI * (1 / 4), 2 * Math.PI * (2 / 4));
this.ctx.lineTo((x), (y + r));
this.ctx.arc(x + r, y + r, r, 2 * Math.PI * (2 / 4), 2 * Math.PI * (3 / 4));
// this.ctx.moveTo(x + r, y);
// this.ctx.arcTo(x + w, y, x + w, y + h, r);
// this.ctx.arcTo(x + w, y + h, x, y + h, r);
// this.ctx.arcTo(x, y + h, x, y, r);
// this.ctx.arcTo(x, y, x + w, y, r);
},
drawImage(params) {
const {
type = '',
background,
top = 0,
left = 0,
width = 0,
height = 0,
radius = 0,
url = '',
sx = 0,
sy = 0,
ex = 0,
ey = 0
} = params;
let x = left;
let y = top;
let w = width;
let h = height;
let r = radius;
this.ctx.save();
if (radius) {
this.ctx.beginPath();
// if (radius === parseInt(width / 2)) {
// console.log('圆');
// this.ctx.beginPath();
// this.ctx.arc(left + radius, top + radius, radius, 0, 2 * Math.PI);
// this.ctx.setFillStyle(params.background || '#ffffff')
// this.ctx.fill()
// this.ctx.clip();
// this.ctx.drawImage(url, x, y, w, h);
// }
// else {
// }
this._drawRadiusRect(params);
this.ctx.fill();
this.ctx.clip();
}
if ('tailor' in params) {
this.ctx.drawImage(url, sx, sy, ex, ey, left, top, width, height);
}
else {
this.ctx.drawImage(url, left, top, width, height);
}
// this.drawImage(params);
this.ctx.restore();
},
old_drawRound(params) {
let ctx = this.ctx;
let x = params.left;
let y = params.top;
let w = params.width;
let h = params.height;
let r = params.radius;
ctx.save();
ctx.beginPath();
ctx.arc(x + r, y + r, r, 0, 2 * Math.PI);
ctx.setFillStyle(params.background || '#ffffff');
ctx.fill();
ctx.clip();
ctx.restore();
},
drawText(params) {
let {
MaxLineNumber = 2,
breakWord = false,
color = 'black',
content = '',
fontSize = 16,
top = 0,
left = 0,
lineHeight = 20,
textAlign = 'left',
width,
bolder = false,
textDecoration = 'none'
} = params;
if (bolder) {
top -= 0.3;
}
// this.ctx.save();
// this.ctx.beginPath();
// this.ctx.stroke();
let _setStyle = () => {
// this.ctx.save();
this.ctx.closePath();
this.ctx.beginPath();
this.ctx.setTextBaseline('top');
this.ctx.setFillStyle(color);
this.ctx.setFontSize(fontSize);
this.ctx.setTextAlign(textAlign);
}
_setStyle();
if (!breakWord) {
this.ctx.fillText(content, left, top);
this.drawTextLine(left, top, textDecoration, color, fontSize, content);
} else {
let fillText = '';
let fillTop = top;
let lineNum = 1;
for (let i = 0; i < content.length; i++) {
fillText += [content[i]];
// _setStyle();
if (this.ctx.measureText(fillText).width > width) {
if (lineNum === MaxLineNumber) {
if (i !== content.length) {
fillText = fillText.substring(0, fillText.length - 1) + '...';
// _setStyle();
this.ctx.fillText(fillText, left, fillTop);
this.drawTextLine(left, fillTop, textDecoration, color, fontSize, fillText);
fillText = '';
break;
}
}
// _setStyle();
this.ctx.fillText(fillText, left, fillTop);
this.drawTextLine(left, fillTop, textDecoration, color, fontSize, fillText);
fillText = '';
fillTop += lineHeight;
lineNum++;
}
}
// _setStyle();
this.ctx.fillText(fillText, left, fillTop);
this.drawTextLine(left, fillTop, textDecoration, color, fontSize, fillText);
}
// this.ctx.draw();
if (bolder) {
this.drawText({
...params,
left: left - 0.3,
top: top,
bolder: false,
textDecoration: 'none'
});
}
},
drawTextLine(left, top, textDecoration, color, fontSize, content) {
if (textDecoration === 'underline') {
this.drawRect({
background: color,
top: top + fontSize * 1.2,
left: left - 1,
width: this.ctx.measureText(content).width + 2,
height: 1
});
} else if (textDecoration === 'line-through') {
this.drawRect({
background: color,
top: top + fontSize * 0.6,
left: left - 1,
width: this.ctx.measureText(content).width + 2,
height: 1
});
}
},
drawRect(params) {
// console.log(params)
const { background, top = 0, left = 0, width = 0, height = 0 } = params
this.ctx.save();
this.ctx.setFillStyle(background);
if (params.radius) {
this._drawRadiusRect(params);
this.ctx.fill();
}
else {
this.ctx.setFillStyle(background);
this.ctx.fillRect(left, top, width, height);
}
this.ctx.restore();
},
getImageInfo(url) {
return new Promise((resolve, reject) => {
/* 获得要在画布上绘制的图片 */
if (this.cache[url]) {
resolve(this.cache[url]);
} else {
const objExp = new RegExp(/^http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w- .\/?%&=]*)?/);
if (objExp.test(url)) {
uni.getImageInfo({
src: url,
complete: res => {
if (res.errMsg === 'getImageInfo:ok') {
const img = {
url,
originWidth: res.width,
originHeight: res.height,
localPath: res.path
};
this.cache[url] = img;
// console.log(res);
// resolve(res.path)
resolve(img);
} else {
reject(new Error('getImageInfo fail'));
}
}
});
} else {
this.cache[url] = {
url,
originWidth: 0,
originHeight: 0,
localPath: url
};
resolve(url);
}
}
})
},
saveImageToLocal() {
const { width, height } = this;
uni.canvasToTempFilePath({
x: 0,
y: 0,
width,
height,
canvasId: 'canvasdrawer',
success: res => {
if (res.errMsg === 'canvasToTempFilePath:ok') {
this.isPainting = false;
this.imageList = [];
this.tempFileList = [];
this.$emit('success', {
width,
height,
path: res.tempFilePath
});
}
}
}, this);
}
}
}
</script>
README.md
# 海报生成组件
## 组件使用
> 运行下面demo时,主要图片路径
<template>
<view>
<posters-layer
:postersData="postersData"
@success="onSuccessCreatePosters"
@error="onPostersError">
</posters-layer>
<img :src="posterImg.path" />
</view>
</template>
<script>
import postersLayer from '../../components/posters-layer/index';
export default {
data() {
return {
postersData: {},
posterImg: {}
};
},
components: {
postersLayer
},
onLoad() {
this.initPostersConfig();
},
methods: {
initPostersConfig() {
const config = {
clear: true,
width: 660,
height: 850,
background: '#ffffff',
views: [
{
type: 'image',
width: 660,
height: 660,
top: 0,
left: 0,
// 封面图,测试的时候填上
url: 'http://127.0.0.1:8080/static/images/test/1.jpg'
},
{
type: 'text',
width: 400,
height: 50,
left: 20,
top: 680,
fontSize: 30,
lineHeight: 40,
bolder: true,
breakWord: true,
content: ' Apple/苹果 iPhone XR 移动联通电信全网通版 苹果xr iphonexr 苹果xr手机 iphone xr',
MaxLineNumber: 2
},
{
type: 'rect',
width: 70,
height: 34,
left: 20,
top: 684,
background: '#ff4201',
radius: 8
},
{
type: 'text',
width: 400,
height: 50,
left: 20,
top: 690,
fontSize: 24,
lineHeight: 40,
bolder: true,
breakWord: true,
content: ' 活动',
color: '#ffffff',
MaxLineNumber: 2
},
{
type: 'text',
width: 400,
left: 20,
top: 770,
fontSize: 54,
bolder: true,
breakWord: true,
content: '¥0.0',
color: '#F40',
MaxLineNumber: 2
},
{
type: 'image',
width: 140,
height: 140,
top: 680,
left: 500,
// 二维码图片路径,测试的时候填上
url: 'http://127.0.0.1:8080/static/images/test/qr.png'
},
]
};
this.postersData = config;
},
onSuccessCreatePosters(res) {
this.posterImg = res;
},
onPostersError(res) {}
}
}
</script>
## 组件参数解释
### config字段
| 字段 | 类型 | 必填 | 描述 |
| --------------- | ------------------------ | ---- | ------------------------------------------ |
| width | Number(单位:px) | 是 | 画布宽度 |
| height | Number(单位:px) | 是 | 画布高度 |
| background | String | 否 | 画布背景颜色 |
| radius | Number | 否 | 圆角 |
| views | Array | 否 | 海报的所有元素 |
### views字段
#### 文本
| 字段 | 类型 | 必填 | 描述 |
| --------------- | ------------------------ | ---- | ------------------------------------------ |
| type | String | 是 | 类型,值:text |
| width | Number(单位:px) | 是 | 宽度 |
| height | Number(单位:px) | 否 | 高度 |
| left | Number(单位:px) | 否 | 距离海报左边距 |
| top | Number(单位:px) | 否 | 距离海报上边距 |
| fontSize | Number(单位:px) | 否 | 字体大小,默认:16 |
| lineHeight | Number(单位:px) | 否 | 行高,默认:20 |
| breakWord | Boolean | 否 | 是否自动换行,默认:false |
| bolder | Boolean | 否 | 是否加粗,默认:false |
| textAlign | String | 否 | 对齐方式,可选值:left、center、right,默认:left |
| color | String | 否 | 字体颜色 |
| content | String | 是 | 文本内容 |
| MaxLineNumber | Number | 否 | 显示多少行,超出省略 |
### 矩形
| 字段 | 类型 | 必填 | 描述 |
| --------------- | ------------------------ | ---- | ------------------------------------------ |
| type | String | 是 | 类型,值:rect |
| width | Number(单位:px) | 是 | 宽度 |
| height | Number(单位:px) | 是 | 高度 |
| left | Number(单位:px) | 否 | 距离海报左边距 |
| top | Number(单位:px) | 否 | 距离海报上边距 |
| radius | Number(单位:px) | 否 | 圆角半径,如果radius === width / 2,则是个圆,和CSS一样 |
| background | String | 否 | 填充背景色 |
### 图片
| 字段 | 类型 | 必填 | 描述 |
| --------------- | ------------------------ | ---- | ------------------------------------------ |
| type | String | 是 | 类型,值:image |
| tailor | Number(单位:px) | 否 | 裁剪方式,可选值:center |
| radius | Number(单位:px) | 否 | 圆角半径,如果radius === width / 2,则是个圆,和CSS一样 |
| width | Number(单位:px) | 是 | 宽度 |
| height | Number(单位:px) | 是 | 高度 |
| left | Number(单位:px) | 否 | 距离海报左边距 |
| top | Number(单位:px) | 否 | 距离海报上边距 |
| url | String | 是 | 图片路径 |
## 事件
### `success` 海报生成成功时触发
### `error` 海报生成失败时触发
red-bag
index.vue
<template>
<view class="wrapper" v-show="redBagShow">
<view class="modal-bg" >
</view>
<view class="rb-wrapper">
<view class="rb-content" @click="handleBtn">
</view>
<view class="close" @click="handleClose">
<image src='../../static/image/close.png' class="img"></image>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'redBag',
components: {},
props: {
},
data() {
return {
redBagShow: true
}
},
watch: {},
computed: {},
methods: {
handleClose() {
this.redBagShow=false
},
handleBtn() {
this.$emit('click')
this.redBagShow=false
}
},
created() {},
mounted() {}
}
</script>
<style lang="scss" scoped>
.modal-bg {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background: rgba(0, 0, 0, 0.4);
}
.rb-wrapper {
position: absolute;
top: 50%;
left: 50%;
width: 60%;
height: 600upx;
transform: translate3d(-50%, -50%, 0);
background: red;
padding: 40upx;
.rb-content{
height: 100%;
}
.close {
position: absolute;
bottom: -120upx;
left: 50%;
margin-left: -30upx;
width: 60upx;
height: 60upx;
border-radius: 50%;
background: #ddd;
.img {
width: 100%;
height: 100%;
}
}
}
</style>
share
share.vue
<template>
<view style="width: 100%;height: 300upx;background: #FFFFFF;position: absolute;left:0;bottom: 0;">
<!-- #ifdef H5 || APP-PLUS || MP-ALIPAY -->
<view class="share-pop">
<view class="share-item"
v-for="(item, index) in providerList"
:key="index"
@click="clickHandler(item)">
<image :src="item.img" mode=""></image>
<view class="">{{ item.name }}</view>
</view>
</view>
<view class="button-bottom">
<button class="btn btn-w btn-square" @click="close()">关闭</button>
</view>
<!-- #endif -->
<!-- #ifdef MP-WEIXIN -->
<view class="share-pop">
<view class="share-item">
<button class="btn" open-type="share">
<image src="../../../static/image/share-f.png" mode=""></image>
<view class="">
分享微信好友
</view>
</button>
</view>
<view class="share-item" @click="createPoster()">
<image src="../../../static/image/poster.png" mode=""></image>
<view class="">生成海报</view>
</view>
</view>
<view class="button-bottom">
<button class="btn btn-w btn-square" @click="close()">关闭</button>
</view>
<!-- #endif -->
<!-- #ifdef MP-ALIPAY -->
<view class="share-pop">
<view class="share-item">
<image src="../../../static/image/share-f.png" mode=""></image>
<button class="btn" open-type="share">分享给好友</button>
</view>
<view class="share-item" @click="createPoster()">
<image src="../../../static/image/poster.png" mode=""></image>
<view class="">生成海报</view>
</view>
</view>
<view class="button-bottom">
<button class="btn btn-w btn-square" @click="close()">关闭</button>
</view>
<!-- #endif -->
</view>
</template>
<script>
import { apiBaseUrl } from '@/config/config.js'
export default {
props: {
// 商品id
goodsId: {
type: Number,
default: 0
},
// 分享的图片
shareImg: {
type: String,
default: ''
},
// 分享标题
shareTitle: {
type: String,
default: ''
},
// 分享内容
shareContent: {
type: String,
default: ''
},
// 分享链接
shareHref: {
type: String,
default: ''
}
},
data () {
return {
shareType: 0,
providerList: [] // 分享通道 包含生成海报
}
},
mounted () {
/**
*
* H5端分享两种 (微信浏览器内引导用户去分享, 其他浏览器)
*
*/
// #ifdef H5
if (this.$common.isWeiXinBrowser()) {
// 微信浏览器里面
} else {
// 其他浏览器里面
this.providerList = [
{
name: '分享给好友',
cate: 'share',
id: 'share',
img: '../../../static/image/share-f.png',
sort: 0
},
{
name: '生成海报',
cate: 'poster',
id: 'poster',
img: '../../../static/image/poster.png',
sort: 1
}
]
}
// #endif
/**
*
* 支付宝小程序中的分享
*
*/
// #ifdef MP-ALIPAY
this.providerList = [
{
name: '生成海报',
cate: 'poster',
id: 'poster',
img: '../../../static/image/ic-img.png',
sort: 1
}
]
// #endif
/**
*
* H5+ 获取分享通道
*
*/
// #ifdef APP-PLUS
uni.getProvider({
service: 'share',
success: (e) => {
let data = []
for (let i = 0; i < e.provider.length; i++) {
switch (e.provider[i]) {
case 'weixin':
data.push({
name: '分享到微信好友',
cate: 'share',
id: 'weixin',
img: '../../../static/image/ic-wechat.png',
sort: 0
})
data.push({
name: '分享到微信朋友圈',
cate: 'share',
id: 'weixin',
type:'WXSenceTimeline',
img: '../../../static/image/circle-of-friends.png',
sort:1
})
break;
// case 'sinaweibo':
// data.push({
// name: '分享到新浪微博',
// cate: 'share',
// id: 'sinaweibo',
// img: '../../../static/image/sina-weibo.png',
// sort:2
// })
// break;
case 'qq':
data.push({
name: '分享到QQ',
cate: 'share',
id: 'qq',
img: '../../../static/image/qq.png',
sort:3
})
break;
default:
break;
}
}
data.push({
name: '生成海报',
cate: 'poster',
id: 'poster',
img: '../../../static/image/poster.png',
sort: 5
})
this.providerList = data.sort((x,y) => {
return x.sort - y.sort
});
},
fail: (e) => {
// console.log('获取分享通道失败', e)
}
});
// #endif
},
methods: {
// 关闭弹出层
close () {
this.$emit('close')
},
// 点击操作
clickHandler (e) {
if (e.cate === 'poster') {
this.createPoster()
} else {
// 去分享
this.share(e)
}
},
// 生成海报
createPoster () {
let data = {
id: this.goodsId,
type: 1
}
let pages = getCurrentPages()
let page = pages[pages.length - 1]
// #ifdef H5
data.source = 1;
data.return_url = apiBaseUrl + 'wap/pages/share/jump';
// #endif
// #ifdef MP-WEIXIN
data.source = 2;
data.return_url = 'pages/share/jump'; //page.route;
// #endif
// #ifdef MP-ALIPAY
data.source = 3;
data.return_url = 'pages/share/jump';//page.__proto__.route;
// #endif
let userToken = this.$db.get('userToken')
if (userToken) {
data.user_id = userToken
}
this.$api.createPoster(data, res => {
if (res.status) {
this.close()
this.$common.navigateTo('/pages/share?poster=' + res.data)
} else {
this.$common.errorToShow(res.msg)
}
})
},
// 分享操作
async share (e) {
// console.log('分享通道:'+ e.id +'; 分享类型:' + this.shareType);
// if(!this.shareContent){
// uni.showModal({
// content:'分享内容不能为空',
// showCancel:false
// })
// return;
// }
//
// if(!this.shareImg){
// uni.showModal({
// content:'分享图片不能为空',
// showCancel:false
// })
// return;
// }
// #ifdef APP-PLUS
let shareOPtions = {
provider: e.id,
scene: e.type && e.type === 'WXSenceTimeline' ? 'WXSenceTimeline' : 'WXSceneSession', //WXSceneSession”分享到聊天界面,“WXSenceTimeline”分享到朋友圈,“WXSceneFavorite”分享到微信收藏
type: this.shareType,
success: (e) => {
uni.showModal({
content: '分享成功',
showCancel:false
})
},
fail: (e) => {
uni.showModal({
content: e.errMsg,
showCancel:false
})
},
complete:function(){
// console.log('分享操作结束!')
}
}
shareOPtions.summary = this.shareContent ? this.shareContent : ''
shareOPtions.imageUrl = this.shareImg ? this.shareImg : ''
shareOPtions.title = this.shareTitle ? this.shareTitle : ''
shareOPtions.href = this.shareHref ? this.shareHref : ''
if(shareOPtions.type === 0 && plus.os.name === 'iOS'){//如果是图文分享,且是ios平台,则压缩图片
shareOPtions.imageUrl = await this.compress()
}
if(shareOPtions.type === 1 && shareOPtions.provider === 'qq'){//如果是分享文字到qq,则必须加上href和title
shareOPtions.href = this.shareHref
shareOPtions.title = this.shareTitle
}
uni.share(shareOPtions);
// #endif
},
// 压缩图片 图文分享要求分享图片大小不能超过20Kb
compress () {
// console.log('开始压缩');
let img = this.shareImg;
return new Promise((res) => {
var localPath = plus.io.convertAbsoluteFileSystem(img.replace('file://', ''));
// console.log('after' + localPath);
// 压缩size
plus.io.resolveLocalFileSystemURL(localPath, (entry) => {
entry.file((file) => {// 可通过entry对象操作图片
// console.log('getFile:' + JSON.stringify(file));
if(file.size > 20480) {// 压缩后size 大于20Kb
plus.zip.compressImage({
src: img,
dst: img.replace('.jpg', '2222.jpg').replace('.JPG', '2222.JPG'),
width: '10%',
height: '10%',
quality: 1,
overwrite: true
}, (event) => {
// console.log('success zip****' + event.size);
let newImg = img.replace('.jpg', '2222.jpg').replace('.JPG', '2222.JPG');
res(newImg);
}, function(error) {
uni.showModal({
content:'分享图片太大,需要请重新选择图片!',
showCancel:false
})
});
}
});
}, (e) => {
// console.log('Resolve file URL failed: ' + e.message);
uni.showModal({
content:'分享图片太大,需要请重新选择图片!',
showCancel:false
})
});
})
}
}
}
</script>
<style>
.share-pop{
height: 300upx;
width: 100%;
display: flex;
}
.share-item{
flex: 1;
text-align: center;
font-size: 26upx;
color: #333;
padding: 20upx 0;
}
.share-item image{
width: 80upx;
height: 80upx;
margin: 20upx;
}
.share-item .btn{
line-height: 1;
display: block;
font-size: 26upx;
background-color: #fff;
}
</style>
shareByAli.vue
<template>
<view style="width: 100%;height: 300upx;background: #FFFFFF;position: absolute;left:0;bottom: 0;">
<view class="share-pop">
<view class="share-item">
<button class="btn" open-type="share">
<image src="../../../static/image/share-f.png" mode=""></image>
<button class="btn" open-type="share">分享给好友</button>
</button>
</view>
<view class="share-item" @click="createPoster()">
<image src="../../../static/image/poster.png" mode=""></image>
<view class="">生成海报</view>
</view>
</view>
<view class="button-bottom">
<button class="btn btn-w btn-square" @click="close()">关闭</button>
</view>
</view>
</template>
<script>
import { apiBaseUrl } from '@/config/config.js'
export default {
props: {
// 商品id
goodsId: {
type: Number,
default: 0
},
// 分享的图片
shareImg: {
type: String,
default: ''
},
// 分享标题
shareTitle: {
type: String,
default: ''
},
// 分享内容
shareContent: {
type: String,
default: ''
},
// 分享链接
shareHref: {
type: String,
default: ''
},
//分享类型
shareType:{
type:Number,
default:1
},
//拼团id
groupId:{
type:Number,
default:0
},
//拼团的团队id
teamId:{
type:Number,
default:0
}
},
data () {
return {
shareType: 0,
providerList: [] // 分享通道 包含生成海报
}
},
mounted () {
},
methods: {
// 关闭弹出层
close () {
this.$emit('close')
},
// 生成海报
createPoster () {
let data = {
id: this.goodsId,
type: this.shareType,
group_id :this.groupId,
team_id :this.teamId,
}
let pages = getCurrentPages()
let page = pages[pages.length - 1]
data.source = 3;
data.return_url = 'pages/share/jump';//page.__proto__.route;
let userToken = this.$db.get('userToken')
if (userToken) {
data.token = userToken
}
this.$api.createPoster(data, res => {
if (res.status) {
this.close()
this.$common.navigateTo('/pages/share?poster=' + res.data)
} else {
this.$common.errorToShow(res.msg)
}
})
},
// 分享操作
async share (e) {
}
}
}
</script>
<style>
.share-pop{
height: 300upx;
width: 100%;
display: flex;
}
.share-item{
flex: 1;
text-align: center;
font-size: 26upx;
color: #333;
padding: 20upx 0;
}
.share-item image{
width: 80upx;
height: 80upx;
margin: 20upx;
}
.share-item .btn{
line-height: 1;
display: block;
font-size: 26upx;
background-color: #fff;
}
</style>
shareByApp.vue
<template>
<view style="width: 100%;height: 300upx;background: #FFFFFF;position: absolute;left:0;bottom: 0;">
<view class="share-pop">
<view class="share-item"
v-for="(item, index) in providerList"
:key="index"
@click="clickHandler(item)">
<image :src="item.img" mode=""></image>
<view class="">{{ item.name }}</view>
</view>
</view>
<view class="button-bottom">
<button class="btn btn-w btn-square" @click="close()">关闭</button>
</view>
</view>
</template>
<script>
import { apiBaseUrl } from '@/config/config.js'
export default {
props: {
// 商品id
goodsId: {
type: Number,
default: 0
},
// 分享的图片
shareImg: {
type: String,
default: ''
},
// 分享标题
shareTitle: {
type: String,
default: ''
},
// 分享内容
shareContent: {
type: String,
default: ''
},
// 分享链接
shareHref: {
type: String,
default: ''
}
},
data () {
return {
shareType: 0,
providerList: [] // 分享通道 包含生成海报
}
},
mounted () {
/**
*
* H5+ 获取分享通道
*
*/
uni.getProvider({
service: 'share',
success: (e) => {
let data = []
for (let i = 0; i < e.provider.length; i++) {
switch (e.provider[i]) {
case 'weixin':
data.push({
name: '分享到微信好友',
cate: 'share',
id: 'weixin',
img: '../../../static/image/ic-wechat.png',
sort: 0
})
data.push({
name: '分享到微信朋友圈',
cate: 'share',
id: 'weixin',
type:'WXSenceTimeline',
img: '../../../static/image/circle-of-friends.png',
sort:1
})
break;
// case 'sinaweibo':
// data.push({
// name: '分享到新浪微博',
// cate: 'share',
// id: 'sinaweibo',
// img: '../../../static/image/sina-weibo.png',
// sort:2
// })
// break;
case 'qq':
data.push({
name: '分享到QQ',
cate: 'share',
id: 'qq',
img: '../../../static/image/qq.png',
sort:3
})
break;
default:
break;
}
}
data.push({
name: '生成海报',
cate: 'poster',
id: 'poster',
img: '../../../static/image/poster.png',
sort: 5
})
this.providerList = data.sort((x,y) => {
return x.sort - y.sort
});
},
fail: (e) => {
// console.log('获取分享通道失败', e)
}
});
},
methods: {
// 关闭弹出层
close () {
this.$emit('close')
},
// 点击操作
clickHandler (e) {
if (e.cate === 'poster') {
this.createPoster()
} else {
// 去分享
this.share(e)
}
},
// 生成海报
createPoster () {
let data = {
id: this.goodsId,
type: 1
}
let pages = getCurrentPages()
let page = pages[pages.length - 1]
data.source = 1;
data.return_url = apiBaseUrl + 'wap/' + page.route;
let userToken = this.$db.get('userToken')
if (userToken) {
data.token = userToken
}
this.$api.createPoster(data, res => {
if (res.status) {
this.close()
this.$common.navigateTo('/pages/share?poster=' + res.data)
} else {
this.$common.errorToShow(res.msg)
}
})
},
// 分享操作
async share (e) {
// console.log('分享通道:'+ e.id +'; 分享类型:' + this.shareType);
// if(!this.shareContent){
// uni.showModal({
// content:'分享内容不能为空',
// showCancel:false
// })
// return;
// }
//
// if(!this.shareImg){
// uni.showModal({
// content:'分享图片不能为空',
// showCancel:false
// })
// return;
// }
let shareOPtions = {
provider: e.id,
scene: e.type && e.type === 'WXSenceTimeline' ? 'WXSenceTimeline' : 'WXSceneSession', //WXSceneSession”分享到聊天界面,“WXSenceTimeline”分享到朋友圈,“WXSceneFavorite”分享到微信收藏
type: this.shareType,
success: (e) => {
uni.showModal({
content: '分享成功',
showCancel:false
})
},
fail: (e) => {
uni.showModal({
content: e.errMsg,
showCancel:false
})
},
complete:function(){
// console.log('分享操作结束!')
}
}
shareOPtions.summary = this.shareContent ? this.shareContent : ''
shareOPtions.imageUrl = this.shareImg ? this.shareImg : ''
shareOPtions.title = this.shareTitle ? this.shareTitle : ''
shareOPtions.href = this.shareHref ? this.shareHref : ''
if(shareOPtions.type === 0 && plus.os.name === 'iOS'){//如果是图文分享,且是ios平台,则压缩图片
shareOPtions.imageUrl = await this.compress()
}
if(shareOPtions.type === 1 && shareOPtions.provider === 'qq'){//如果是分享文字到qq,则必须加上href和title
shareOPtions.href = this.shareHref
shareOPtions.title = this.shareTitle
}
uni.share(shareOPtions);
},
// 压缩图片 图文分享要求分享图片大小不能超过20Kb
compress () {
// console.log('开始压缩');
let img = this.shareImg;
return new Promise((res) => {
var localPath = plus.io.convertAbsoluteFileSystem(img.replace('file://', ''));
// console.log('after' + localPath);
// 压缩size
plus.io.resolveLocalFileSystemURL(localPath, (entry) => {
entry.file((file) => {// 可通过entry对象操作图片
// console.log('getFile:' + JSON.stringify(file));
if(file.size > 20480) {// 压缩后size 大于20Kb
plus.zip.compressImage({
src: img,
dst: img.replace('.jpg', '2222.jpg').replace('.JPG', '2222.JPG'),
width: '10%',
height: '10%',
quality: 1,
overwrite: true
}, (event) => {
// console.log('success zip****' + event.size);
let newImg = img.replace('.jpg', '2222.jpg').replace('.JPG', '2222.JPG');
res(newImg);
}, function(error) {
uni.showModal({
content:'分享图片太大,需要请重新选择图片!',
showCancel:false
})
});
}
});
}, (e) => {
// console.log('Resolve file URL failed: ' + e.message);
uni.showModal({
content:'分享图片太大,需要请重新选择图片!',
showCancel:false
})
});
})
}
}
}
</script>
<style>
.share-pop{
height: 300upx;
width: 100%;
display: flex;
}
.share-item{
flex: 1;
text-align: center;
font-size: 26upx;
color: #333;
padding: 20upx 0;
}
.share-item image{
width: 80upx;
height: 80upx;
margin: 20upx;
}
.share-item .btn{
line-height: 1;
display: block;
font-size: 26upx;
background-color: #fff;
}
</style>
shareByh5.vue
<template>
<view style="width: 100%;height: 300upx;background: #FFFFFF;position: absolute;left:0;bottom: 0;">
<view class="share-pop">
<view class="share-item" @click="copyUrl()">
<image src="../../../static/image/share-f.png" mode=""></image>
<view class="">复制链接</view>
</view>
<view class="share-item" @click="createPoster()">
<image src="../../../static/image/poster.png" mode=""></image>
<view class="">生成海报</view>
</view>
</view>
<view class="button-bottom">
<button class="btn btn-w btn-square" @click="close()">关闭</button>
</view>
</view>
</template>
<script>
import { apiBaseUrl } from '@/config/config.js'
export default {
props: {
// 商品id
goodsId: {
type: Number,
default: 0
},
// 分享的图片
shareImg: {
type: String,
default: ''
},
// 分享标题
shareTitle: {
type: String,
default: ''
},
// 分享内容
shareContent: {
type: String,
default: ''
},
// 分享链接
shareHref: {
type: String,
default: ''
},
//分享类型
shareType:{
type:Number,
default:1
},
//拼团id
groupId:{
type:Number,
default:0
},
//拼团的团队id
teamId:{
type:Number,
default:0
}
},
mounted () {
/**
*
* H5端分享两种 (微信浏览器内引导用户去分享, 其他浏览器)
*
*/
},
methods: {
// 关闭弹出层
close () {
this.$emit('close')
},
// 生成海报
createPoster () {
let data = {
id: this.goodsId,
type: this.shareType,
group_id :this.groupId,
team_id :this.teamId,
}
data.return_url = apiBaseUrl + 'wap/pages/share/jump';
let userToken = this.$db.get('userToken')
if (userToken) {
data.token = userToken
}
this.$api.createPoster(data, res => {
if (res.status) {
this.close()
this.$common.navigateTo('/pages/share?poster=' + res.data)
} else {
this.$common.errorToShow(res.msg)
}
});
},
copyUrl () {
let data = {
id: this.goodsId,
type: this.shareType,
group_id :this.groupId,
team_id :this.teamId,
}
data.return_url = apiBaseUrl + 'wap/pages/share/jump';
let userToken = this.$db.get('userToken')
if (userToken) {
data.token = userToken
}
let _this = this;
_this.$api.createShareUrl(data, res => {
if(res.status) {
//todo::要复制的内容是 res.data
uni.setClipboardData({
data:res.data,
success:function(data){
_this.$common.successToShow('复制成功');
},
fail:function(err){
_this.$common.errorToShow('复制分享URL失败');
}
})
} else {
_this.$common.errorToShow('复制分享URL失败');
}
});
},
// 分享操作
share () {
// h5分享 判断是否是微信浏览器 引导用户完成分享操作
// 其他浏览器的分享
}
}
}
</script>
<style>
.share-pop{
height: 300upx;
width: 100%;
display: flex;
}
.share-item{
flex: 1;
text-align: center;
font-size: 26upx;
color: #333;
padding: 20upx 0;
}
.share-item image{
width: 80upx;
height: 80upx;
margin: 20upx;
}
.share-item .btn{
line-height: 1;
display: block;
font-size: 26upx;
background-color: #fff;
}
</style>
shareByWx.vue
<template>
<view style="width: 100%;height: 300upx;background: #FFFFFF;position: absolute;left:0;bottom: 0;">
<view class="share-pop">
<view class="share-item">
<button class="btn" open-type="share">
<image src="../../../static/image/share-f.png" mode=""></image>
<view class="">
分享微信好友
</view>
</button>
</view>
<view class="share-item" @click="createPoster()">
<image src="../../../static/image/poster.png" mode=""></image>
<view class="">生成海报</view>
</view>
</view>
<view class="button-bottom">
<button class="btn btn-w btn-square" @click="close()">关闭</button>
</view>
</view>
</template>
<script>
import { apiBaseUrl } from '@/config/config.js'
export default {
props: {
// 商品id
goodsId: {
type: Number,
default: 0
},
// 分享的图片
shareImg: {
type: String,
default: ''
},
// 分享标题
shareTitle: {
type: String,
default: ''
},
// 分享内容
shareContent: {
type: String,
default: ''
},
// 分享链接
shareHref: {
type: String,
default: ''
},
//分享类型
shareType:{
type:Number,
default:1
},
//拼团id
groupId:{
type:Number,
default:0
},
//拼团的团队id
teamId:{
type:Number,
default:0
}
},
data () {
return {
shareType: 0,
providerList: [] // 分享通道 包含生成海报
}
},
mounted () {
},
methods: {
// 关闭弹出层
close () {
this.$emit('close')
},
// 生成海报
createPoster () {
let data = {
id: this.goodsId,
type: this.shareType,
group_id :this.groupId,
team_id :this.teamId,
}
let pages = getCurrentPages()
let page = pages[pages.length - 1]
data.source = 2;
data.return_url = 'pages/share/jump';//page.route;
let userToken = this.$db.get('userToken')
if (userToken) {
data.token = userToken
}
this.$api.createPoster(data, res => {
if (res.status) {
this.close()
this.$common.navigateTo('/pages/share?poster=' + res.data)
} else {
this.$common.errorToShow(res.msg)
}
})
}
}
}
</script>
<style>
.share-pop{
height: 300upx;
width: 100%;
display: flex;
}
.share-item{
flex: 1;
text-align: center;
font-size: 26upx;
color: #333;
padding: 20upx 0;
}
.share-item image{
width: 80upx;
height: 80upx;
margin: 20upx;
}
.share-item .btn{
line-height: 1;
display: block;
font-size: 26upx;
background-color: #fff;
}
</style>
spec
spec.vue
<template>
<view>
<view class="goods-specs" v-for="(item, index) in spesData" :key="index">
<text class="pop-m-title">{{ index }}</text>
<view class="pop-m-bd">
<view :class="spes.cla" v-for="(spes, key) in item" :key="key" @click="specChangeSpes(index, key)">
{{ spes.name }}
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: "spec",
props: {
// 默认picker选中项索引
spesData: {
required: true
}
},
methods: {
specChangeSpes(v, k){
let newData = {
v: v,
k: k
}
this.$emit("changeSpes", newData);
}
}
}
</script>
<style>
.goods-specs,.goods-number{
padding: 26upx;
border-top: 1px solid #f3f3f3;
}
.goods-specs:first-child{
border: none;
}
.pop-m-title{
margin-right: 10upx;
color: #666;
}
.pop-m-item{
display: inline-block;
float: left;
padding: 6upx 16upx;
background-color: #fff;
color: #333;
margin-right: 16upx;
margin-bottom: 10upx;
}
.pop-m-bd{
overflow: hidden;
margin-top: 10upx;
}
.selected{
border: 2upx solid #333;
background-color: #333;
color: #fff;
}
.not-selected{
border: 2upx solid #ccc;
}
.none{
border: 2upx dashed #ccc;
color: #888;
}
</style>
tki-qrcode
qrcode.js
//---------------------------------------------------------------------
//
// QR Code Generator for JavaScript
//
// Copyright (c) 2009 Kazuhiko Arase
//
// URL: [url=http://www.d-project.com/]http://www.d-project.com/[/url]
//
// Licensed under the MIT license:
// [url=http://www.opensource.org/licenses/mit-license.php]http://www.opensource.org/licenses/mit-license.php[/url]
//
// The word 'QR Code' is registered trademark of
// DENSO WAVE INCORPORATED
// [url=http://www.denso-wave.com/qrcode/faqpatent-e.html]http://www.denso-wave.com/qrcode/faqpatent-e.html[/url]
//
//---------------------------------------------------------------------
//---------------------------------------------------------------------
// qrcode
//代码第1588行为补充代码
//修改人:chenxing
//2017-02-27 16:21:32
//---------------------------------------------------------------------
/**
* qrcode
* @param typeNumber 1 to 40
* @param errorCorrectLevel 'L','M','Q','H'
*/
var qrcode = function(typeNumber, errorCorrectLevel) {
var PAD0 = 0xEC;
var PAD1 = 0x11;
var _typeNumber = typeNumber;
var _errorCorrectLevel = QRErrorCorrectLevel[errorCorrectLevel];
var _modules = null;
var _moduleCount = 0;
var _dataCache = null;
var _dataList = new Array();
var _this = {};
var makeImpl = function(test, maskPattern) {
_moduleCount = _typeNumber * 4 + 17;
_modules = function(moduleCount) {
var modules = new Array(moduleCount);
for (var row = 0; row < moduleCount; row += 1) {
modules[row] = new Array(moduleCount);
for (var col = 0; col < moduleCount; col += 1) {
modules[row][col] = null;
}
}
return modules;
}(_moduleCount);
setupPositionProbePattern(0, 0);
setupPositionProbePattern(_moduleCount - 7, 0);
setupPositionProbePattern(0, _moduleCount - 7);
setupPositionAdjustPattern();
setupTimingPattern();
setupTypeInfo(test, maskPattern);
if (_typeNumber >= 7) {
setupTypeNumber(test);
}
if (_dataCache == null) {
_dataCache = createData(_typeNumber, _errorCorrectLevel, _dataList);
}
mapData(_dataCache, maskPattern);
};
var setupPositionProbePattern = function(row, col) {
for (var r = -1; r <= 7; r += 1) {
if (row + r <= -1 || _moduleCount <= row + r) continue;
for (var c = -1; c <= 7; c += 1) {
if (col + c <= -1 || _moduleCount <= col + c) continue;
if ( (0 <= r && r <= 6 && (c == 0 || c == 6) )
|| (0 <= c && c <= 6 && (r == 0 || r == 6) )
|| (2 <= r && r <= 4 && 2 <= c && c <= 4) ) {
_modules[row + r][col + c] = true;
} else {
_modules[row + r][col + c] = false;
}
}
}
};
var getBestMaskPattern = function() {
var minLostPoint = 0;
var pattern = 0;
for (var i = 0; i < 8; i += 1) {
makeImpl(true, i);
var lostPoint = QRUtil.getLostPoint(_this);
if (i == 0 || minLostPoint > lostPoint) {
minLostPoint = lostPoint;
pattern = i;
}
}
return pattern;
};
var setupTimingPattern = function() {
for (var r = 8; r < _moduleCount - 8; r += 1) {
if (_modules[r][6] != null) {
continue;
}
_modules[r][6] = (r % 2 == 0);
}
for (var c = 8; c < _moduleCount - 8; c += 1) {
if (_modules[6][c] != null) {
continue;
}
_modules[6][c] = (c % 2 == 0);
}
};
var setupPositionAdjustPattern = function() {
var pos = QRUtil.getPatternPosition(_typeNumber);
for (var i = 0; i < pos.length; i += 1) {
for (var j = 0; j < pos.length; j += 1) {
var row = pos[i];
var col = pos[j];
if (_modules[row][col] != null) {
continue;
}
for (var r = -2; r <= 2; r += 1) {
for (var c = -2; c <= 2; c += 1) {
if (r == -2 || r == 2 || c == -2 || c == 2
|| (r == 0 && c == 0) ) {
_modules[row + r][col + c] = true;
} else {
_modules[row + r][col + c] = false;
}
}
}
}
}
};
var setupTypeNumber = function(test) {
var bits = QRUtil.getBCHTypeNumber(_typeNumber);
for (var i = 0; i < 18; i += 1) {
var mod = (!test && ( (bits >> i) & 1) == 1);
_modules[Math.floor(i / 3)][i % 3 + _moduleCount - 8 - 3] = mod;
}
for (var i = 0; i < 18; i += 1) {
var mod = (!test && ( (bits >> i) & 1) == 1);
_modules[i % 3 + _moduleCount - 8 - 3][Math.floor(i / 3)] = mod;
}
};
var setupTypeInfo = function(test, maskPattern) {
var data = (_errorCorrectLevel << 3) | maskPattern;
var bits = QRUtil.getBCHTypeInfo(data);
// vertical
for (var i = 0; i < 15; i += 1) {
var mod = (!test && ( (bits >> i) & 1) == 1);
if (i < 6) {
_modules[i][8] = mod;
} else if (i < 8) {
_modules[i + 1][8] = mod;
} else {
_modules[_moduleCount - 15 + i][8] = mod;
}
}
// horizontal
for (var i = 0; i < 15; i += 1) {
var mod = (!test && ( (bits >> i) & 1) == 1);
if (i < 8) {
_modules[8][_moduleCount - i - 1] = mod;
} else if (i < 9) {
_modules[8][15 - i - 1 + 1] = mod;
} else {
_modules[8][15 - i - 1] = mod;
}
}
// fixed module
_modules[_moduleCount - 8][8] = (!test);
};
var mapData = function(data, maskPattern) {
var inc = -1;
var row = _moduleCount - 1;
var bitIndex = 7;
var byteIndex = 0;
var maskFunc = QRUtil.getMaskFunction(maskPattern);
for (var col = _moduleCount - 1; col > 0; col -= 2) {
if (col == 6) col -= 1;
while (true) {
for (var c = 0; c < 2; c += 1) {
if (_modules[row][col - c] == null) {
var dark = false;
if (byteIndex < data.length) {
dark = ( ( (data[byteIndex] >>> bitIndex) & 1) == 1);
}
var mask = maskFunc(row, col - c);
if (mask) {
dark = !dark;
}
_modules[row][col - c] = dark;
bitIndex -= 1;
if (bitIndex == -1) {
byteIndex += 1;
bitIndex = 7;
}
}
}
row += inc;
if (row < 0 || _moduleCount <= row) {
row -= inc;
inc = -inc;
break;
}
}
}
};
var createBytes = function(buffer, rsBlocks) {
var offset = 0;
var maxDcCount = 0;
var maxEcCount = 0;
var dcdata = new Array(rsBlocks.length);
var ecdata = new Array(rsBlocks.length);
for (var r = 0; r < rsBlocks.length; r += 1) {
var dcCount = rsBlocks[r].dataCount;
var ecCount = rsBlocks[r].totalCount - dcCount;
maxDcCount = Math.max(maxDcCount, dcCount);
maxEcCount = Math.max(maxEcCount, ecCount);
dcdata[r] = new Array(dcCount);
for (var i = 0; i < dcdata[r].length; i += 1) {
dcdata[r][i] = 0xff & buffer.getBuffer()[i + offset];
}
offset += dcCount;
var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
var rawPoly = qrPolynomial(dcdata[r], rsPoly.getLength() - 1);
var modPoly = rawPoly.mod(rsPoly);
ecdata[r] = new Array(rsPoly.getLength() - 1);
for (var i = 0; i < ecdata[r].length; i += 1) {
var modIndex = i + modPoly.getLength() - ecdata[r].length;
ecdata[r][i] = (modIndex >= 0)? modPoly.getAt(modIndex) : 0;
}
}
var totalCodeCount = 0;
for (var i = 0; i < rsBlocks.length; i += 1) {
totalCodeCount += rsBlocks[i].totalCount;
}
var data = new Array(totalCodeCount);
var index = 0;
for (var i = 0; i < maxDcCount; i += 1) {
for (var r = 0; r < rsBlocks.length; r += 1) {
if (i < dcdata[r].length) {
data[index] = dcdata[r][i];
index += 1;
}
}
}
for (var i = 0; i < maxEcCount; i += 1) {
for (var r = 0; r < rsBlocks.length; r += 1) {
if (i < ecdata[r].length) {
data[index] = ecdata[r][i];
index += 1;
}
}
}
return data;
};
var createData = function(typeNumber, errorCorrectLevel, dataList) {
var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
var buffer = qrBitBuffer();
for (var i = 0; i < dataList.length; i += 1) {
var data = dataList[i];
buffer.put(data.getMode(), 4);
buffer.put(data.getLength(), QRUtil.getLengthInBits(data.getMode(), typeNumber) );
data.write(buffer);
}
// calc num max data.
var totalDataCount = 0;
for (var i = 0; i < rsBlocks.length; i += 1) {
totalDataCount += rsBlocks[i].dataCount;
}
if (buffer.getLengthInBits() > totalDataCount * 8) {
throw new Error('code length overflow. ('
+ buffer.getLengthInBits()
+ '>'
+ totalDataCount * 8
+ ')');
}
// end code
if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
buffer.put(0, 4);
}
// padding
while (buffer.getLengthInBits() % 8 != 0) {
buffer.putBit(false);
}
// padding
while (true) {
if (buffer.getLengthInBits() >= totalDataCount * 8) {
break;
}
buffer.put(PAD0, 8);
if (buffer.getLengthInBits() >= totalDataCount * 8) {
break;
}
buffer.put(PAD1, 8);
}
return createBytes(buffer, rsBlocks);
};
_this.addData = function(data) {
var newData = qr8BitByte(data);
_dataList.push(newData);
_dataCache = null;
};
_this.isDark = function(row, col) {
if (row < 0 || _moduleCount <= row || col < 0 || _moduleCount <= col) {
throw new Error(row + ',' + col);
}
return _modules[row][col];
};
_this.getModuleCount = function() {
return _moduleCount;
};
_this.make = function() {
makeImpl(false, getBestMaskPattern() );
};
_this.createTableTag = function(cellSize, margin) {
cellSize = cellSize || 2;
margin = (typeof margin == 'undefined')? cellSize * 4 : margin;
var qrHtml = '';
qrHtml += '<table style="';
qrHtml += ' border-width: 0px; border-style: none;';
qrHtml += ' border-collapse: collapse;';
qrHtml += ' padding: 0px; margin: ' + margin + 'px;';
qrHtml += '">';
qrHtml += '<tbody>';
for (var r = 0; r < _this.getModuleCount(); r += 1) {
qrHtml += '<tr>';
for (var c = 0; c < _this.getModuleCount(); c += 1) {
qrHtml += '<td style="';
qrHtml += ' border-width: 0px; border-style: none;';
qrHtml += ' border-collapse: collapse;';
qrHtml += ' padding: 0px; margin: 0px;';
qrHtml += ' width: ' + cellSize + 'px;';
qrHtml += ' height: ' + cellSize + 'px;';
qrHtml += ' background-color: ';
qrHtml += _this.isDark(r, c)? '#000000' : '#ffffff';
qrHtml += ';';
qrHtml += '"/>';
}
qrHtml += '</tr>';
}
qrHtml += '</tbody>';
qrHtml += '</table>';
return qrHtml;
};
_this.createImgTag = function(cellSize, margin, size) {
cellSize = cellSize || 2;
margin = (typeof margin == 'undefined')? cellSize * 4 : margin;
var min = margin;
var max = _this.getModuleCount() * cellSize + margin;
return createImgTag(size, size, function(x, y) {
if (min <= x && x < max && min <= y && y < max) {
var c = Math.floor( (x - min) / cellSize);
var r = Math.floor( (y - min) / cellSize);
return _this.isDark(r, c)? 0 : 1;
} else {
return 1;
}
} );
};
return _this;
};
//---------------------------------------------------------------------
// qrcode.stringToBytes
//---------------------------------------------------------------------
qrcode.stringToBytes = function(s) {
var bytes = new Array();
for (var i = 0; i < s.length; i += 1) {
var c = s.charCodeAt(i);
bytes.push(c & 0xff);
}
return bytes;
};
//---------------------------------------------------------------------
// qrcode.createStringToBytes
//---------------------------------------------------------------------
/**
* @param unicodeData base64 string of byte array.
* [16bit Unicode],[16bit Bytes], ...
* @param numChars
*/
qrcode.createStringToBytes = function(unicodeData, numChars) {
// create conversion map.
var unicodeMap = function() {
var bin = base64DecodeInputStream(unicodeData);
var read = function() {
var b = bin.read();
if (b == -1) throw new Error();
return b;
};
var count = 0;
var unicodeMap = {};
while (true) {
var b0 = bin.read();
if (b0 == -1) break;
var b1 = read();
var b2 = read();
var b3 = read();
var k = String.fromCharCode( (b0 << 8) | b1);
var v = (b2 << 8) | b3;
unicodeMap[k] = v;
count += 1;
}
if (count != numChars) {
throw new Error(count + ' != ' + numChars);
}
return unicodeMap;
}();
var unknownChar = '?'.charCodeAt(0);
return function(s) {
var bytes = new Array();
for (var i = 0; i < s.length; i += 1) {
var c = s.charCodeAt(i);
if (c < 128) {
bytes.push(c);
} else {
var b = unicodeMap[s.charAt(i)];
if (typeof b == 'number') {
if ( (b & 0xff) == b) {
// 1byte
bytes.push(b);
} else {
// 2bytes
bytes.push(b >>> 8);
bytes.push(b & 0xff);
}
} else {
bytes.push(unknownChar);
}
}
}
return bytes;
};
};
//---------------------------------------------------------------------
// QRMode
//---------------------------------------------------------------------
var QRMode = {
MODE_NUMBER : 1 << 0,
MODE_ALPHA_NUM : 1 << 1,
MODE_8BIT_BYTE : 1 << 2,
MODE_KANJI : 1 << 3
};
//---------------------------------------------------------------------
// QRErrorCorrectLevel
//---------------------------------------------------------------------
var QRErrorCorrectLevel = {
L : 1,
M : 0,
Q : 3,
H : 2
};
//---------------------------------------------------------------------
// QRMaskPattern
//---------------------------------------------------------------------
var QRMaskPattern = {
PATTERN000 : 0,
PATTERN001 : 1,
PATTERN010 : 2,
PATTERN011 : 3,
PATTERN100 : 4,
PATTERN101 : 5,
PATTERN110 : 6,
PATTERN111 : 7
};
//---------------------------------------------------------------------
// QRUtil
//---------------------------------------------------------------------
var QRUtil = function() {
var PATTERN_POSITION_TABLE = [
[],
[6, 18],
[6, 22],
[6, 26],
[6, 30],
[6, 34],
[6, 22, 38],
[6, 24, 42],
[6, 26, 46],
[6, 28, 50],
[6, 30, 54],
[6, 32, 58],
[6, 34, 62],
[6, 26, 46, 66],
[6, 26, 48, 70],
[6, 26, 50, 74],
[6, 30, 54, 78],
[6, 30, 56, 82],
[6, 30, 58, 86],
[6, 34, 62, 90],
[6, 28, 50, 72, 94],
[6, 26, 50, 74, 98],
[6, 30, 54, 78, 102],
[6, 28, 54, 80, 106],
[6, 32, 58, 84, 110],
[6, 30, 58, 86, 114],
[6, 34, 62, 90, 118],
[6, 26, 50, 74, 98, 122],
[6, 30, 54, 78, 102, 126],
[6, 26, 52, 78, 104, 130],
[6, 30, 56, 82, 108, 134],
[6, 34, 60, 86, 112, 138],
[6, 30, 58, 86, 114, 142],
[6, 34, 62, 90, 118, 146],
[6, 30, 54, 78, 102, 126, 150],
[6, 24, 50, 76, 102, 128, 154],
[6, 28, 54, 80, 106, 132, 158],
[6, 32, 58, 84, 110, 136, 162],
[6, 26, 54, 82, 110, 138, 166],
[6, 30, 58, 86, 114, 142, 170]
];
var G15 = (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0);
var G18 = (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0);
var G15_MASK = (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1);
var _this = {};
var getBCHDigit = function(data) {
var digit = 0;
while (data != 0) {
digit += 1;
data >>>= 1;
}
return digit;
};
_this.getBCHTypeInfo = function(data) {
var d = data << 10;
while (getBCHDigit(d) - getBCHDigit(G15) >= 0) {
d ^= (G15 << (getBCHDigit(d) - getBCHDigit(G15) ) );
}
return ( (data << 10) | d) ^ G15_MASK;
};
_this.getBCHTypeNumber = function(data) {
var d = data << 12;
while (getBCHDigit(d) - getBCHDigit(G18) >= 0) {
d ^= (G18 << (getBCHDigit(d) - getBCHDigit(G18) ) );
}
return (data << 12) | d;
};
_this.getPatternPosition = function(typeNumber) {
return PATTERN_POSITION_TABLE[typeNumber - 1];
};
_this.getMaskFunction = function(maskPattern) {
switch (maskPattern) {
case QRMaskPattern.PATTERN000 :
return function(i, j) { return (i + j) % 2 == 0; };
case QRMaskPattern.PATTERN001 :
return function(i, j) { return i % 2 == 0; };
case QRMaskPattern.PATTERN010 :
return function(i, j) { return j % 3 == 0; };
case QRMaskPattern.PATTERN011 :
return function(i, j) { return (i + j) % 3 == 0; };
case QRMaskPattern.PATTERN100 :
return function(i, j) { return (Math.floor(i / 2) + Math.floor(j / 3) ) % 2 == 0; };
case QRMaskPattern.PATTERN101 :
return function(i, j) { return (i * j) % 2 + (i * j) % 3 == 0; };
case QRMaskPattern.PATTERN110 :
return function(i, j) { return ( (i * j) % 2 + (i * j) % 3) % 2 == 0; };
case QRMaskPattern.PATTERN111 :
return function(i, j) { return ( (i * j) % 3 + (i + j) % 2) % 2 == 0; };
default :
throw new Error('bad maskPattern:' + maskPattern);
}
};
_this.getErrorCorrectPolynomial = function(errorCorrectLength) {
var a = qrPolynomial([1], 0);
for (var i = 0; i < errorCorrectLength; i += 1) {
a = a.multiply(qrPolynomial([1, QRMath.gexp(i)], 0) );
}
return a;
};
_this.getLengthInBits = function(mode, type) {
if (1 <= type && type < 10) {
// 1 - 9
switch(mode) {
case QRMode.MODE_NUMBER : return 10;
case QRMode.MODE_ALPHA_NUM : return 9;
case QRMode.MODE_8BIT_BYTE : return 8;
case QRMode.MODE_KANJI : return 8;
default :
throw new Error('mode:' + mode);
}
} else if (type < 27) {
// 10 - 26
switch(mode) {
case QRMode.MODE_NUMBER : return 12;
case QRMode.MODE_ALPHA_NUM : return 11;
case QRMode.MODE_8BIT_BYTE : return 16;
case QRMode.MODE_KANJI : return 10;
default :
throw new Error('mode:' + mode);
}
} else if (type < 41) {
// 27 - 40
switch(mode) {
case QRMode.MODE_NUMBER : return 14;
case QRMode.MODE_ALPHA_NUM : return 13;
case QRMode.MODE_8BIT_BYTE : return 16;
case QRMode.MODE_KANJI : return 12;
default :
throw new Error('mode:' + mode);
}
} else {
throw new Error('type:' + type);
}
};
_this.getLostPoint = function(qrcode) {
var moduleCount = qrcode.getModuleCount();
var lostPoint = 0;
// LEVEL1
for (var row = 0; row < moduleCount; row += 1) {
for (var col = 0; col < moduleCount; col += 1) {
var sameCount = 0;
var dark = qrcode.isDark(row, col);
for (var r = -1; r <= 1; r += 1) {
if (row + r < 0 || moduleCount <= row + r) {
continue;
}
for (var c = -1; c <= 1; c += 1) {
if (col + c < 0 || moduleCount <= col + c) {
continue;
}
if (r == 0 && c == 0) {
continue;
}
if (dark == qrcode.isDark(row + r, col + c) ) {
sameCount += 1;
}
}
}
if (sameCount > 5) {
lostPoint += (3 + sameCount - 5);
}
}
};
// LEVEL2
for (var row = 0; row < moduleCount - 1; row += 1) {
for (var col = 0; col < moduleCount - 1; col += 1) {
var count = 0;
if (qrcode.isDark(row, col) ) count += 1;
if (qrcode.isDark(row + 1, col) ) count += 1;
if (qrcode.isDark(row, col + 1) ) count += 1;
if (qrcode.isDark(row + 1, col + 1) ) count += 1;
if (count == 0 || count == 4) {
lostPoint += 3;
}
}
}
// LEVEL3
for (var row = 0; row < moduleCount; row += 1) {
for (var col = 0; col < moduleCount - 6; col += 1) {
if (qrcode.isDark(row, col)
&& !qrcode.isDark(row, col + 1)
&& qrcode.isDark(row, col + 2)
&& qrcode.isDark(row, col + 3)
&& qrcode.isDark(row, col + 4)
&& !qrcode.isDark(row, col + 5)
&& qrcode.isDark(row, col + 6) ) {
lostPoint += 40;
}
}
}
for (var col = 0; col < moduleCount; col += 1) {
for (var row = 0; row < moduleCount - 6; row += 1) {
if (qrcode.isDark(row, col)
&& !qrcode.isDark(row + 1, col)
&& qrcode.isDark(row + 2, col)
&& qrcode.isDark(row + 3, col)
&& qrcode.isDark(row + 4, col)
&& !qrcode.isDark(row + 5, col)
&& qrcode.isDark(row + 6, col) ) {
lostPoint += 40;
}
}
}
// LEVEL4
var darkCount = 0;
for (var col = 0; col < moduleCount; col += 1) {
for (var row = 0; row < moduleCount; row += 1) {
if (qrcode.isDark(row, col) ) {
darkCount += 1;
}
}
}
var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
lostPoint += ratio * 10;
return lostPoint;
};
return _this;
}();
//---------------------------------------------------------------------
// QRMath
//---------------------------------------------------------------------
var QRMath = function() {
var EXP_TABLE = new Array(256);
var LOG_TABLE = new Array(256);
// initialize tables
for (var i = 0; i < 8; i += 1) {
EXP_TABLE[i] = 1 << i;
}
for (var i = 8; i < 256; i += 1) {
EXP_TABLE[i] = EXP_TABLE[i - 4]
^ EXP_TABLE[i - 5]
^ EXP_TABLE[i - 6]
^ EXP_TABLE[i - 8];
}
for (var i = 0; i < 255; i += 1) {
LOG_TABLE[EXP_TABLE[i] ] = i;
}
var _this = {};
_this.glog = function(n) {
if (n < 1) {
throw new Error('glog(' + n + ')');
}
return LOG_TABLE[n];
};
_this.gexp = function(n) {
while (n < 0) {
n += 255;
}
while (n >= 256) {
n -= 255;
}
return EXP_TABLE[n];
};
return _this;
}();
//---------------------------------------------------------------------
// qrPolynomial
//---------------------------------------------------------------------
function qrPolynomial(num, shift) {
if (typeof num.length == 'undefined') {
throw new Error(num.length + '/' + shift);
}
var _num = function() {
var offset = 0;
while (offset < num.length && num[offset] == 0) {
offset += 1;
}
var _num = new Array(num.length - offset + shift);
for (var i = 0; i < num.length - offset; i += 1) {
_num[i] = num[i + offset];
}
return _num;
}();
var _this = {};
_this.getAt = function(index) {
return _num[index];
};
_this.getLength = function() {
return _num.length;
};
_this.multiply = function(e) {
var num = new Array(_this.getLength() + e.getLength() - 1);
for (var i = 0; i < _this.getLength(); i += 1) {
for (var j = 0; j < e.getLength(); j += 1) {
num[i + j] ^= QRMath.gexp(QRMath.glog(_this.getAt(i) ) + QRMath.glog(e.getAt(j) ) );
}
}
return qrPolynomial(num, 0);
};
_this.mod = function(e) {
if (_this.getLength() - e.getLength() < 0) {
return _this;
}
var ratio = QRMath.glog(_this.getAt(0) ) - QRMath.glog(e.getAt(0) );
var num = new Array(_this.getLength() );
for (var i = 0; i < _this.getLength(); i += 1) {
num[i] = _this.getAt(i);
}
for (var i = 0; i < e.getLength(); i += 1) {
num[i] ^= QRMath.gexp(QRMath.glog(e.getAt(i) ) + ratio);
}
// recursive call
return qrPolynomial(num, 0).mod(e);
};
return _this;
};
//---------------------------------------------------------------------
// QRRSBlock
//---------------------------------------------------------------------
var QRRSBlock = function() {
// [1: [L, M, Q, H], ..]
var RS_BLOCK_TABLE=[[1,26,19],[1,26,16],[1,26,13],[1,26,9],[1,44,34],[1,44,28],[1,44,22],[1,44,16],[1,70,55],[1,70,44],[2,35,17],[2,35,13],[1,100,80],[2,50,32],[2,50,24],[4,25,9],[1,134,108],[2,67,43],[2,33,15,2,34,16],[2,33,11,2,34,12],[2,86,68],[4,43,27],[4,43,19],[4,43,15],[2,98,78],[4,49,31],[2,32,14,4,33,15],[4,39,13,1,40,14],[2,121,97],[2,60,38,2,61,39],[4,40,18,2,41,19],[4,40,14,2,41,15],[2,146,116],[3,58,36,2,59,37],[4,36,16,4,37,17],[4,36,12,4,37,13],[2,86,68,2,87,69],[4,69,43,1,70,44],[6,43,19,2,44,20],[6,43,15,2,44,16],[4,101,81],[1,80,50,4,81,51],[4,50,22,4,51,23],[3,36,12,8,37,13],[2,116,92,2,117,93],[6,58,36,2,59,37],[4,46,20,6,47,21],[7,42,14,4,43,15],[4,133,107],[8,59,37,1,60,38],[8,44,20,4,45,21],[12,33,11,4,34,12],[3,145,115,1,146,116],[4,64,40,5,65,41],[11,36,16,5,37,17],[11,36,12,5,37,13],[5,109,87,1,110,88],[5,65,41,5,66,42],[5,54,24,7,55,25],[11,36,12],[5,122,98,1,123,99],[7,73,45,3,74,46],[15,43,19,2,44,20],[3,45,15,13,46,16],[1,135,107,5,136,108],[10,74,46,1,75,47],[1,50,22,15,51,23],[2,42,14,17,43,15],[5,150,120,1,151,121],[9,69,43,4,70,44],[17,50,22,1,51,23],[2,42,14,19,43,15],[3,141,113,4,142,114],[3,70,44,11,71,45],[17,47,21,4,48,22],[9,39,13,16,40,14],[3,135,107,5,136,108],[3,67,41,13,68,42],[15,54,24,5,55,25],[15,43,15,10,44,16],[4,144,116,4,145,117],[17,68,42],[17,50,22,6,51,23],[19,46,16,6,47,17],[2,139,111,7,140,112],[17,74,46],[7,54,24,16,55,25],[34,37,13],[4,151,121,5,152,122],[4,75,47,14,76,48],[11,54,24,14,55,25],[16,45,15,14,46,16],[6,147,117,4,148,118],[6,73,45,14,74,46],[11,54,24,16,55,25],[30,46,16,2,47,17],[8,132,106,4,133,107],[8,75,47,13,76,48],[7,54,24,22,55,25],[22,45,15,13,46,16],[10,142,114,2,143,115],[19,74,46,4,75,47],[28,50,22,6,51,23],[33,46,16,4,47,17],[8,152,122,4,153,123],[22,73,45,3,74,46],[8,53,23,26,54,24],[12,45,15,28,46,16],[3,147,117,10,148,118],[3,73,45,23,74,46],[4,54,24,31,55,25],[11,45,15,31,46,16],[7,146,116,7,147,117],[21,73,45,7,74,46],[1,53,23,37,54,24],[19,45,15,26,46,16],[5,145,115,10,146,116],[19,75,47,10,76,48],[15,54,24,25,55,25],[23,45,15,25,46,16],[13,145,115,3,146,116],[2,74,46,29,75,47],[42,54,24,1,55,25],[23,45,15,28,46,16],[17,145,115],[10,74,46,23,75,47],[10,54,24,35,55,25],[19,45,15,35,46,16],[17,145,115,1,146,116],[14,74,46,21,75,47],[29,54,24,19,55,25],[11,45,15,46,46,16],[13,145,115,6,146,116],[14,74,46,23,75,47],[44,54,24,7,55,25],[59,46,16,1,47,17],[12,151,121,7,152,122],[12,75,47,26,76,48],[39,54,24,14,55,25],[22,45,15,41,46,16],[6,151,121,14,152,122],[6,75,47,34,76,48],[46,54,24,10,55,25],[2,45,15,64,46,16],[17,152,122,4,153,123],[29,74,46,14,75,47],[49,54,24,10,55,25],[24,45,15,46,46,16],[4,152,122,18,153,123],[13,74,46,32,75,47],[48,54,24,14,55,25],[42,45,15,32,46,16],[20,147,117,4,148,118],[40,75,47,7,76,48],[43,54,24,22,55,25],[10,45,15,67,46,16],[19,148,118,6,149,119],[18,75,47,31,76,48],[34,54,24,34,55,25],[20,45,15,61,46,16]];
var qrRSBlock = function(totalCount, dataCount) {
var _this = {};
_this.totalCount = totalCount;
_this.dataCount = dataCount;
return _this;
};
var _this = {};
var getRsBlockTable = function(typeNumber, errorCorrectLevel) {
switch(errorCorrectLevel) {
case QRErrorCorrectLevel.L :
return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
case QRErrorCorrectLevel.M :
return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
case QRErrorCorrectLevel.Q :
return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
case QRErrorCorrectLevel.H :
return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
default :
return undefined;
}
};
_this.getRSBlocks = function(typeNumber, errorCorrectLevel) {
var rsBlock = getRsBlockTable(typeNumber, errorCorrectLevel);
if (typeof rsBlock == 'undefined') {
throw new Error('bad rs block [url=home.php?mod=space&uid=5302]@[/url] typeNumber:' + typeNumber +
'/errorCorrectLevel:' + errorCorrectLevel);
}
var length = rsBlock.length / 3;
var list = new Array();
for (var i = 0; i < length; i += 1) {
var count = rsBlock[i * 3 + 0];
var totalCount = rsBlock[i * 3 + 1];
var dataCount = rsBlock[i * 3 + 2];
for (var j = 0; j < count; j += 1) {
list.push(qrRSBlock(totalCount, dataCount) );
}
}
return list;
};
return _this;
}();
//---------------------------------------------------------------------
// qrBitBuffer
//---------------------------------------------------------------------
var qrBitBuffer = function() {
var _buffer = new Array();
var _length = 0;
var _this = {};
_this.getBuffer = function() {
return _buffer;
};
_this.getAt = function(index) {
var bufIndex = Math.floor(index / 8);
return ( (_buffer[bufIndex] >>> (7 - index % 8) ) & 1) == 1;
};
_this.put = function(num, length) {
for (var i = 0; i < length; i += 1) {
_this.putBit( ( (num >>> (length - i - 1) ) & 1) == 1);
}
};
_this.getLengthInBits = function() {
return _length;
};
_this.putBit = function(bit) {
var bufIndex = Math.floor(_length / 8);
if (_buffer.length <= bufIndex) {
_buffer.push(0);
}
if (bit) {
_buffer[bufIndex] |= (0x80 >>> (_length % 8) );
}
_length += 1;
};
return _this;
};
//---------------------------------------------------------------------
// qr8BitByte
//---------------------------------------------------------------------
var qr8BitByte = function(data) {
var _mode = QRMode.MODE_8BIT_BYTE;
var _data = data;
var _parsedData = [];
var _this = {};
// Added to support UTF-8 Characters
for (var i = 0, l = _data.length; i < l; i++) {
var byteArray = [];
var code = _data.charCodeAt(i);
if (code > 0x10000) {
byteArray[0] = 0xF0 | ((code & 0x1C0000) >>> 18);
byteArray[1] = 0x80 | ((code & 0x3F000) >>> 12);
byteArray[2] = 0x80 | ((code & 0xFC0) >>> 6);
byteArray[3] = 0x80 | (code & 0x3F);
} else if (code > 0x800) {
byteArray[0] = 0xE0 | ((code & 0xF000) >>> 12);
byteArray[1] = 0x80 | ((code & 0xFC0) >>> 6);
byteArray[2] = 0x80 | (code & 0x3F);
} else if (code > 0x80) {
byteArray[0] = 0xC0 | ((code & 0x7C0) >>> 6);
byteArray[1] = 0x80 | (code & 0x3F);
} else {
byteArray[0] = code;
}
// Fix Unicode corruption bug
_parsedData.push(byteArray);
}
_parsedData = Array.prototype.concat.apply([], _parsedData);
if (_parsedData.length != _data.length) {
_parsedData.unshift(191);
_parsedData.unshift(187);
_parsedData.unshift(239);
}
var _bytes = _parsedData;
_this.getMode = function() {
return _mode;
};
_this.getLength = function(buffer) {
return _bytes.length;
};
_this.write = function(buffer) {
for (var i = 0; i < _bytes.length; i += 1) {
buffer.put(_bytes[i], 8);
}
};
return _this;
};
//=====================================================================
// GIF Support etc.
//
//---------------------------------------------------------------------
// byteArrayOutputStream
//---------------------------------------------------------------------
var byteArrayOutputStream = function() {
var _bytes = new Array();
var _this = {};
_this.writeByte = function(b) {
_bytes.push(b & 0xff);
};
_this.writeShort = function(i) {
_this.writeByte(i);
_this.writeByte(i >>> 8);
};
_this.writeBytes = function(b, off, len) {
off = off || 0;
len = len || b.length;
for (var i = 0; i < len; i += 1) {
_this.writeByte(b[i + off]);
}
};
_this.writeString = function(s) {
for (var i = 0; i < s.length; i += 1) {
_this.writeByte(s.charCodeAt(i) );
}
};
_this.toByteArray = function() {
return _bytes;
};
_this.toString = function() {
var s = '';
s += '[';
for (var i = 0; i < _bytes.length; i += 1) {
if (i > 0) {
s += ',';
}
s += _bytes[i];
}
s += ']';
return s;
};
return _this;
};
//---------------------------------------------------------------------
// base64EncodeOutputStream
//---------------------------------------------------------------------
var base64EncodeOutputStream = function() {
var _buffer = 0;
var _buflen = 0;
var _length = 0;
var _base64 = '';
var _this = {};
var writeEncoded = function(b) {
_base64 += String.fromCharCode(encode(b & 0x3f) );
};
var encode = function(n) {
if (n < 0) {
// error.
} else if (n < 26) {
return 0x41 + n;
} else if (n < 52) {
return 0x61 + (n - 26);
} else if (n < 62) {
return 0x30 + (n - 52);
} else if (n == 62) {
return 0x2b;
} else if (n == 63) {
return 0x2f;
}
throw new Error('n:' + n);
};
_this.writeByte = function(n) {
_buffer = (_buffer << 8) | (n & 0xff);
_buflen += 8;
_length += 1;
while (_buflen >= 6) {
writeEncoded(_buffer >>> (_buflen - 6) );
_buflen -= 6;
}
};
_this.flush = function() {
if (_buflen > 0) {
writeEncoded(_buffer << (6 - _buflen) );
_buffer = 0;
_buflen = 0;
}
if (_length % 3 != 0) {
// padding
var padlen = 3 - _length % 3;
for (var i = 0; i < padlen; i += 1) {
_base64 += '=';
}
}
};
_this.toString = function() {
return _base64;
};
return _this;
};
//---------------------------------------------------------------------
// base64DecodeInputStream
//---------------------------------------------------------------------
var base64DecodeInputStream = function(str) {
var _str = str;
var _pos = 0;
var _buffer = 0;
var _buflen = 0;
var _this = {};
_this.read = function() {
while (_buflen < 8) {
if (_pos >= _str.length) {
if (_buflen == 0) {
return -1;
}
throw new Error('unexpected end of file./' + _buflen);
}
var c = _str.charAt(_pos);
_pos += 1;
if (c == '=') {
_buflen = 0;
return -1;
} else if (c.match(/^\s$/) ) {
// ignore if whitespace.
continue;
}
_buffer = (_buffer << 6) | decode(c.charCodeAt(0) );
_buflen += 6;
}
var n = (_buffer >>> (_buflen - 8) ) & 0xff;
_buflen -= 8;
return n;
};
var decode = function(c) {
if (0x41 <= c && c <= 0x5a) {
return c - 0x41;
} else if (0x61 <= c && c <= 0x7a) {
return c - 0x61 + 26;
} else if (0x30 <= c && c <= 0x39) {
return c - 0x30 + 52;
} else if (c == 0x2b) {
return 62;
} else if (c == 0x2f) {
return 63;
} else {
throw new Error('c:' + c);
}
};
return _this;
};
//---------------------------------------------------------------------
// gifImage (B/W)
//---------------------------------------------------------------------
var gifImage = function(width, height) {
var _width = width;
var _height = height;
var _data = new Array(width * height);
var _this = {};
_this.setPixel = function(x, y, pixel) {
_data[y * _width + x] = pixel;
};
_this.write = function(out) {
//---------------------------------
// GIF Signature
out.writeString('GIF87a');
//---------------------------------
// Screen Descriptor
out.writeShort(_width);
out.writeShort(_height);
out.writeByte(0x80); // 2bit
out.writeByte(0);
out.writeByte(0);
//---------------------------------
// Global Color Map
// black
out.writeByte(0x00);
out.writeByte(0x00);
out.writeByte(0x00);
// white
out.writeByte(0xff);
out.writeByte(0xff);
out.writeByte(0xff);
//---------------------------------
// Image Descriptor
out.writeString(',');
out.writeShort(0);
out.writeShort(0);
out.writeShort(_width);
out.writeShort(_height);
out.writeByte(0);
//---------------------------------
// Local Color Map
//---------------------------------
// Raster Data
var lzwMinCodeSize = 2;
var raster = getLZWRaster(lzwMinCodeSize);
out.writeByte(lzwMinCodeSize);
var offset = 0;
while (raster.length - offset > 255) {
out.writeByte(255);
out.writeBytes(raster, offset, 255);
offset += 255;
}
out.writeByte(raster.length - offset);
out.writeBytes(raster, offset, raster.length - offset);
out.writeByte(0x00);
//---------------------------------
// GIF Terminator
out.writeString(';');
};
var bitOutputStream = function(out) {
var _out = out;
var _bitLength = 0;
var _bitBuffer = 0;
var _this = {};
_this.write = function(data, length) {
if ( (data >>> length) != 0) {
throw new Error('length over');
}
while (_bitLength + length >= 8) {
_out.writeByte(0xff & ( (data << _bitLength) | _bitBuffer) );
length -= (8 - _bitLength);
data >>>= (8 - _bitLength);
_bitBuffer = 0;
_bitLength = 0;
}
_bitBuffer = (data << _bitLength) | _bitBuffer;
_bitLength = _bitLength + length;
};
_this.flush = function() {
if (_bitLength > 0) {
_out.writeByte(_bitBuffer);
}
};
return _this;
};
var getLZWRaster = function(lzwMinCodeSize) {
var clearCode = 1 << lzwMinCodeSize;
var endCode = (1 << lzwMinCodeSize) + 1;
var bitLength = lzwMinCodeSize + 1;
// Setup LZWTable
var table = lzwTable();
for (var i = 0; i < clearCode; i += 1) {
table.add(String.fromCharCode(i) );
}
table.add(String.fromCharCode(clearCode) );
table.add(String.fromCharCode(endCode) );
var byteOut = byteArrayOutputStream();
var bitOut = bitOutputStream(byteOut);
// clear code
bitOut.write(clearCode, bitLength);
var dataIndex = 0;
var s = String.fromCharCode(_data[dataIndex]);
dataIndex += 1;
while (dataIndex < _data.length) {
var c = String.fromCharCode(_data[dataIndex]);
dataIndex += 1;
if (table.contains(s + c) ) {
s = s + c;
} else {
bitOut.write(table.indexOf(s), bitLength);
if (table.size() < 0xfff) {
if (table.size() == (1 << bitLength) ) {
bitLength += 1;
}
table.add(s + c);
}
s = c;
}
}
bitOut.write(table.indexOf(s), bitLength);
// end code
bitOut.write(endCode, bitLength);
bitOut.flush();
return byteOut.toByteArray();
};
var lzwTable = function() {
var _map = {};
var _size = 0;
var _this = {};
_this.add = function(key) {
if (_this.contains(key) ) {
throw new Error('dup key:' + key);
}
_map[key] = _size;
_size += 1;
};
_this.size = function() {
return _size;
};
_this.indexOf = function(key) {
return _map[key];
};
_this.contains = function(key) {
return typeof _map[key] != 'undefined';
};
return _this;
};
return _this;
};
var createImgTag = function(width, height, getPixel, alt) {
var gif = gifImage(width, height);
for (var y = 0; y < height; y += 1) {
for (var x = 0; x < width; x += 1) {
gif.setPixel(x, y, getPixel(x, y) );
}
}
var b = byteArrayOutputStream();
gif.write(b);
var base64 = base64EncodeOutputStream();
var bytes = b.toByteArray();
for (var i = 0; i < bytes.length; i += 1) {
base64.writeByte(bytes[i]);
}
base64.flush();
var img = '';
img += 'data:image/gif;base64,';
img += base64;
return img;
};
//---------------------------------------------------------------------
// returns qrcode function.
var createQrCodeImg = function(text, options) {
options = options || {};
var typeNumber = options.typeNumber || 4;
var errorCorrectLevel = options.errorCorrectLevel || 'M';
var size = options.size || 500;
var qr;
try {
qr = qrcode(typeNumber, errorCorrectLevel || 'M');
qr.addData(text);
qr.make();
} catch (e) {
if(typeNumber >= 40) {
throw new Error('Text too long to encode');
} else {
return gen(text, {
size: size,
errorCorrectLevel: errorCorrectLevel,
typeNumber: typeNumber + 1
});
}
}
// calc cellsize and margin
var cellsize = parseInt(size / qr.getModuleCount());
var margin = parseInt((size - qr.getModuleCount() * cellsize) / 2);
return qr.createImgTag(cellsize, margin, size);
};
// var module = {}; 需要注释这一行,否则微信小程序无法使用
export default {
createQrCodeImg
}
tki-qrcode.vue
<template xlang="wxml" minapp="mpvue">
<view class="_qrCode">
<canvas class="_qrCodeCanvas" id="_myQrCodeCanvas" canvas-id="_myQrCodeCanvas" :style="{width:cpSize+'px',height:cpSize+'px'}" />
<image v-show="show" :src="result" :style="{width:cpSize+'px',height:cpSize+'px'}" />
</view>
</template>
<script>
import QRCode from "./qrcode.js"
let qrcode
export default {
name: "tki-qrcode",
props: {
size: {
type: Number,
default: 200
},
unit: {
type: String,
default: 'upx'
},
show: {
type: Boolean,
default: true
},
val: {
type: String,
default: ''
},
background: {
type: String,
default: '#ffffff'
},
foreground: {
type: String,
default: '#000000'
},
pdground: {
type: String,
default: '#000000'
},
icon: {
type: String,
default: ''
},
iconSize: {
type: Number,
default: 40
},
lv: {
type: Number,
default: 3
},
onval: {
type: Boolean,
default: false
},
loadMake: {
type: Boolean,
default: false
},
},
data() {
return {
result: '',
}
},
methods: {
_makeCode() {
let that = this
if (!this._empty(this.val)) {
qrcode = new QRCode({
context: that,
text: that.val, // 生成内容
size: that.cpSize, // 二维码大小
background: that.background, // 背景色
foreground: that.foreground, // 前景色
pdground: that.pdground, // 定位角点颜色
correctLevel: that.lv, // 容错级别
image: that.icon, // 二维码图标
imageSize: that.iconSize,// 二维码图标大小
cbResult: function (res) { // 生成二维码的回调
that._result(res)
},
});
} else {
uni.showToast({
title: '二维码内容不能为空',
icon: 'none',
duration: 1000,
complete: function () {
setTimeout(function() {
uni.hideToast();
},1000);
}
});
}
},
_clearCode() {
this._result('')
qrcode.clear()
},
_saveCode() {
let that = this;
if (this.result != "") {
uni.saveImageToPhotosAlbum({
filePath: that.result,
success: function () {
uni.showToast({
title: '二维码保存成功',
icon: 'success',
duration: 1000,
complete: function () {
setTimeout(function() {
uni.hideToast();
},1000);
}
});
}
});
}
},
_result(res) {
this.result = res;
this.$emit('result', res)
},
_empty(v) {
let tp = typeof v,
rt = false;
if (tp == "number" && String(v) == "") {
rt = true
} else if (tp == "undefined") {
rt = true
} else if (tp == "object") {
if (JSON.stringify(v) == "{}" || JSON.stringify(v) == "[]" || v == null) rt = true
} else if (tp == "string") {
if (v == "" || v == "undefined" || v == "null" || v == "{}" || v == "[]") rt = true
} else if (tp == "function") {
rt = false
}
return rt
}
},
watch: {
size: function (n, o) {
if (n != o && !this._empty(n)) {
this.cSize = n
if (!this._empty(this.val)) {
setTimeout(() => {
this._makeCode()
}, 100);
}
}
},
val: function (n, o) {
if (this.onval) {
if (n != o && !this._empty(n)) {
setTimeout(() => {
this._makeCode()
}, 0);
}
}
}
},
computed: {
cpSize() {
if(this.unit == "upx"){
return uni.upx2px(this.size)
}else{
return this.size
}
}
},
mounted: function () {
if (this.loadMake) {
if (!this._empty(this.val)) {
setTimeout(() => {
this._makeCode()
}, 0);
}
}
},
}
</script>
<style>
._qrCode {
position: relative;
}
._qrCodeCanvas {
position: fixed;
top: -99999upx;
left: -99999upx;
z-index: -99999;
}
</style>
u-charts
component.vue
<template>
<canvas v-if="canvasId" :id="canvasId" :canvasId="canvasId" :style="{'width':cWidth*pixelRatio+'px','height':cHeight*pixelRatio+'px', 'transform': 'scale('+(1/pixelRatio)+')','margin-left':-cWidth*(pixelRatio-1)/2+'px','margin-top':-cHeight*(pixelRatio-1)/2+'px'}"
@touchstart="touchStart" @touchmove="touchMove" @touchend="touchEnd" @error="error">
</canvas>
</template>
<script>
import uCharts from './u-charts.js';
var canvases = {};
export default {
props: {
chartType: {
required: true,
type: String,
default: 'column'
},
opts: {
required: true,
type: Object,
default () {
return null;
},
},
canvasId: {
type: String,
default: 'u-canvas',
},
cWidth: {
default: 375,
},
cHeight: {
default: 250,
},
pixelRatio: {
type: Number,
default: 1,
},
},
mounted() {
this.init();
},
methods: {
init() {
switch (this.chartType) {
case 'column':
this.initColumnChart();
break;
case 'line':
this.initLineChart();
break;
default:
break;
}
},
initColumnChart() {
canvases[this.canvasId] = new uCharts({
$this: this,
canvasId: this.canvasId,
type: 'column',
legend: true,
fontSize: 11,
background: '#FFFFFF',
pixelRatio: this.pixelRatio,
animation: true,
categories: this.opts.categories,
series: this.opts.series,
enableScroll: true,
xAxis: {
disableGrid: true,
itemCount: 4,
scrollShow: true
},
yAxis: {
//disabled:true
},
dataLabel: true,
width: this.cWidth * this.pixelRatio,
height: this.cHeight * this.pixelRatio,
extra: {
column: {
type: 'group',
}
}
});
},
initLineChart() {
canvases[this.canvasId] = new uCharts({
$this: this,
canvasId: this.canvasId,
type: 'line',
fontSize: 11,
legend: true,
dataLabel: false,
dataPointShape: true,
background: '#FFFFFF',
pixelRatio: this.pixelRatio,
categories: this.opts.categories,
series: this.opts.series,
animation: true,
enableScroll: true,
xAxis: {
type: 'grid',
gridColor: '#CCCCCC',
gridType: 'dash',
dashLength: 8,
itemCount: 4,
scrollShow: true
},
yAxis: {
gridType: 'dash',
gridColor: '#CCCCCC',
dashLength: 8,
splitNumber: 5,
min: 10,
max: 180,
format: (val) => {
return val.toFixed(0) + '元'
}
},
width: this.cWidth * this.pixelRatio,
height: this.cHeight * this.pixelRatio,
extra: {
line: {
type: 'straight'
}
}
});
},
// 这里仅作为示例传入两个参数,cid为canvas-id,newdata为更新的数据,需要更多参数请自行修改
changeData(cid,newdata) {
canvases[cid].updateData({
series: newdata.series,
categories: newdata.categories
});
},
touchStart(e) {
canvases[this.canvasId].showToolTip(e, {
format: function(item, category) {
return category + ' ' + item.name + ':' + item.data
}
});
canvases[this.canvasId].scrollStart(e);
},
touchMove(e) {
canvases[this.canvasId].scroll(e);
},
touchEnd(e) {
canvases[this.canvasId].scrollEnd(e);
},
error(e) {
// console.log(e)
}
},
};
</script>
<style scoped>
.charts {
width: 100%;
height: 100%;
flex: 1;
background-color: #FFFFFF;
}
</style>
u-charts.js
/*
* uCharts v1.7.0.20190713
* uni-app平台高性能跨全端图表,支持H5、APP、小程序(微信/支付宝/百度/头条)
* Copyright (c) 2019 QIUN秋云 https://www.ucharts.cn All rights reserved.
* Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
*
* uCharts官方网站
* https://www.uCharts.cn
*
* 开源地址:
* https://gitee.com/uCharts/uCharts
*
* uni-app插件市场地址:
* http://ext.dcloud.net.cn/plugin?id=271
*
*
*/
'use strict';
var config = {
yAxisWidth: 15,
yAxisSplit: 5,
xAxisHeight: 15,
xAxisLineHeight: 15,
legendHeight: 15,
yAxisTitleWidth: 15,
padding: 12,
pixelRatio: 1, //适配H5高分屏
rotate: false, //横屏模式
columePadding: 3,
fontSize: 13,
//dataPointShape: ['diamond', 'circle', 'triangle', 'rect'],
dataPointShape: ['circle', 'circle', 'circle', 'circle'], //仿F2图例样式改为圆点
colors: ['#1890ff', '#2fc25b', '#facc14', '#f04864', '#8543e0', '#90ed7d'],
pieChartLinePadding: 15,
pieChartTextPadding: 5,
xAxisTextPadding: 3,
titleColor: '#333333',
titleFontSize: 20,
subtitleColor: '#999999',
subtitleFontSize: 15,
toolTipPadding: 3,
toolTipBackground: '#000000',
toolTipOpacity: 0.7,
toolTipLineHeight: 20,
radarGridCount: 3,
radarLabelTextMargin: 15,
gaugeLabelTextMargin: 15
};
// Object.assign polyfill
// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
function assign(target, varArgs) {
if (target == null) {
// TypeError if undefined or null
throw new TypeError('Cannot convert undefined or null to object');
}
var to = Object(target);
for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index];
if (nextSource != null) {
// Skip over if undefined or null
for (var nextKey in nextSource) {
// Avoid bugs when hasOwnProperty is shadowed
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
}
}
}
}
return to;
}
var util = {
toFixed: function toFixed(num, limit) {
limit = limit || 2;
if (this.isFloat(num)) {
num = num.toFixed(limit);
}
return num;
},
isFloat: function isFloat(num) {
return num % 1 !== 0;
},
approximatelyEqual: function approximatelyEqual(num1, num2) {
return Math.abs(num1 - num2) < 1e-10;
},
isSameSign: function isSameSign(num1, num2) {
return Math.abs(num1) === num1 && Math.abs(num2) === num2 || Math.abs(num1) !== num1 && Math.abs(num2) !== num2;
},
isSameXCoordinateArea: function isSameXCoordinateArea(p1, p2) {
return this.isSameSign(p1.x, p2.x);
},
isCollision: function isCollision(obj1, obj2) {
obj1.end = {};
obj1.end.x = obj1.start.x + obj1.width;
obj1.end.y = obj1.start.y - obj1.height;
obj2.end = {};
obj2.end.x = obj2.start.x + obj2.width;
obj2.end.y = obj2.start.y - obj2.height;
var flag = obj2.start.x > obj1.end.x || obj2.end.x < obj1.start.x || obj2.end.y > obj1.start.y || obj2.start.y <
obj1.end.y;
return !flag;
}
};
//兼容H5点击事件
function getH5Offset(e) {
e.mp={changedTouches:[]};
e.mp.changedTouches.push({x:e.offsetX,y:e.offsetY});
return e;
}
// hex 转 rgba
function hexToRgb(hexValue, opc) {
var rgx = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
var hex = hexValue.replace(rgx, function(m, r, g, b) {
return r + r + g + g + b + b;
});
var rgb = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
var r = parseInt(rgb[1], 16);
var g = parseInt(rgb[2], 16);
var b = parseInt(rgb[3], 16);
return 'rgba(' + r + ',' + g + ',' + b + ',' + opc + ')';
}
function findRange(num, type, limit) {
if (isNaN(num)) {
throw new Error('[wxCharts] unvalid series data!');
}
limit = limit || 10;
type = type ? type : 'upper';
var multiple = 1;
while (limit < 1) {
limit *= 10;
multiple *= 10;
}
if (type === 'upper') {
num = Math.ceil(num * multiple);
} else {
num = Math.floor(num * multiple);
}
while (num % limit !== 0) {
if (type === 'upper') {
num++;
} else {
num--;
}
}
return num / multiple;
}
function calCandleMA(dayArr, nameArr, colorArr, kdata) {
let seriesTemp = [];
for (let k = 0; k < dayArr.length; k++) {
let seriesItem = {
data: [],
name: nameArr[k],
color: colorArr[k]
};
for (let i = 0, len = kdata.length; i < len; i++) {
if (i < dayArr[k]) {
seriesItem.data.push(null);
continue;
}
let sum = 0;
for (let j = 0; j < dayArr[k]; j++) {
sum += kdata[i - j][1];
}
seriesItem.data.push(+(sum / dayArr[k]).toFixed(3));
}
seriesTemp.push(seriesItem);
}
return seriesTemp;
}
function calValidDistance(distance, chartData, config, opts) {
var dataChartAreaWidth = opts.width - config.padding - chartData.xAxisPoints[0];
var dataChartWidth = chartData.eachSpacing * opts.categories.length;
var validDistance = distance;
if (distance >= 0) {
validDistance = 0;
} else if (Math.abs(distance) >= dataChartWidth - dataChartAreaWidth) {
validDistance = dataChartAreaWidth - dataChartWidth;
}
return validDistance;
}
function isInAngleRange(angle, startAngle, endAngle) {
function adjust(angle) {
while (angle < 0) {
angle += 2 * Math.PI;
}
while (angle > 2 * Math.PI) {
angle -= 2 * Math.PI;
}
return angle;
}
angle = adjust(angle);
startAngle = adjust(startAngle);
endAngle = adjust(endAngle);
if (startAngle > endAngle) {
endAngle += 2 * Math.PI;
if (angle < startAngle) {
angle += 2 * Math.PI;
}
}
return angle >= startAngle && angle <= endAngle;
}
function calRotateTranslate(x, y, h) {
var xv = x;
var yv = h - y;
var transX = xv + (h - yv - xv) / Math.sqrt(2);
transX *= -1;
var transY = (h - yv) * (Math.sqrt(2) - 1) - (h - yv - xv) / Math.sqrt(2);
return {
transX: transX,
transY: transY
};
}
function createCurveControlPoints(points, i) {
function isNotMiddlePoint(points, i) {
if (points[i - 1] && points[i + 1]) {
return points[i].y >= Math.max(points[i - 1].y, points[i + 1].y) || points[i].y <= Math.min(points[i - 1].y, points[
i + 1].y);
} else {
return false;
}
}
var a = 0.2;
var b = 0.2;
var pAx = null;
var pAy = null;
var pBx = null;
var pBy = null;
if (i < 1) {
pAx = points[0].x + (points[1].x - points[0].x) * a;
pAy = points[0].y + (points[1].y - points[0].y) * a;
} else {
pAx = points[i].x + (points[i + 1].x - points[i - 1].x) * a;
pAy = points[i].y + (points[i + 1].y - points[i - 1].y) * a;
}
if (i > points.length - 3) {
var last = points.length - 1;
pBx = points[last].x - (points[last].x - points[last - 1].x) * b;
pBy = points[last].y - (points[last].y - points[last - 1].y) * b;
} else {
pBx = points[i + 1].x - (points[i + 2].x - points[i].x) * b;
pBy = points[i + 1].y - (points[i + 2].y - points[i].y) * b;
}
// fix issue https://github.com/xiaolin3303/wx-charts/issues/79
if (isNotMiddlePoint(points, i + 1)) {
pBy = points[i + 1].y;
}
if (isNotMiddlePoint(points, i)) {
pAy = points[i].y;
}
return {
ctrA: {
x: pAx,
y: pAy
},
ctrB: {
x: pBx,
y: pBy
}
};
}
function convertCoordinateOrigin(x, y, center) {
return {
x: center.x + x,
y: center.y - y
};
}
function avoidCollision(obj, target) {
if (target) {
// is collision test
while (util.isCollision(obj, target)) {
if (obj.start.x > 0) {
obj.start.y--;
} else if (obj.start.x < 0) {
obj.start.y++;
} else {
if (obj.start.y > 0) {
obj.start.y++;
} else {
obj.start.y--;
}
}
}
}
return obj;
}
function fillSeriesColor(series, config) {
var index = 0;
return series.map(function(item) {
if (!item.color) {
item.color = config.colors[index];
index = (index + 1) % config.colors.length;
}
return item;
});
}
function fillSeriesType(series, opts) {
return series.map(function(item) {
if (!item.type) {
item.type = opts.type;
}
return item;
});
}
function getDataRange(minData, maxData) {
var limit = 0;
var range = maxData - minData;
if (range >= 10000) {
limit = 1000;
} else if (range >= 1000) {
limit = 100;
} else if (range >= 100) {
limit = 10;
} else if (range >= 10) {
limit = 5;
} else if (range >= 1) {
limit = 1;
} else if (range >= 0.1) {
limit = 0.1;
} else {
limit = 0.01;
}
return {
minRange: findRange(minData, 'lower', limit),
maxRange: findRange(maxData, 'upper', limit)
};
}
function measureText(text) {
var fontSize = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : config.fontSize;
// wx canvas 未实现measureText方法, 此处自行实现
// 适配修改初始字体10px为其他大小的方法
text = String(text);
var text = text.split('');
var width = 0;
for (let i = 0; i < text.length; i++) {
let item = text[i];
if (/[a-zA-Z]/.test(item)) {
width += 7;
} else if (/[0-9]/.test(item)) {
width += 5.5;
} else if (/\./.test(item)) {
width += 2.7;
} else if (/-/.test(item)) {
width += 3.25;
} else if (/[\u4e00-\u9fa5]/.test(item)) {
width += 10;
} else if (/\(|\)/.test(item)) {
width += 3.73;
} else if (/\s/.test(item)) {
width += 2.5;
} else if (/%/.test(item)) {
width += 8;
} else {
width += 10;
}
}
return width * fontSize / 10;
}
function dataCombine(series) {
return series.reduce(function(a, b) {
return (a.data ? a.data : a).concat(b.data);
}, []);
}
function dataCombineStack(series) {
var sum = new Array(series[0].data.length);
for (var j = 0; j < sum.length; j++) {
sum[j] = 0;
}
for (var i = 0; i < series.length; i++) {
for (var j = 0; j < sum.length; j++) {
sum[j] += series[i].data[j];
}
}
return series.reduce(function(a, b) {
return (a.data ? a.data : a).concat(b.data).concat(sum);
}, []);
}
function getTouches(touches, opts, e) {
let x, y;
if (touches.clientX) {
if (opts.rotate) { //适配横屏
y = opts.height - touches.clientX * opts.pixelRatio;
x = (touches.pageY - e.currentTarget.offsetTop - (opts.height / opts.pixelRatio / 2) * (opts.pixelRatio - 1)) *
opts.pixelRatio;
} else {
x = touches.clientX * opts.pixelRatio;
y = (touches.pageY - e.currentTarget.offsetTop - (opts.height / opts.pixelRatio / 2) * (opts.pixelRatio - 1)) *
opts.pixelRatio;
}
} else {
if (opts.rotate) { //适配横屏
y = opts.height - touches.x * opts.pixelRatio;
x = touches.y * opts.pixelRatio;
} else {
x = touches.x * opts.pixelRatio;
y = touches.y * opts.pixelRatio;
}
}
return {
x: x,
y: y
}
}
function getSeriesDataItem(series, index) {
var data = [];
for (let i = 0; i < series.length; i++) {
let item = series[i];
if (item.data[index] !== null && typeof item.data[index] !== 'undefined') {
let seriesItem = {};
seriesItem.color = item.color;
seriesItem.type = item.type;
seriesItem.style = item.style;
seriesItem.shape = item.shape;
seriesItem.disableLegend = item.disableLegend;
seriesItem.name = item.name;
seriesItem.data = item.format ? item.format(item.data[index]) : item.data[index];
data.push(seriesItem);
}
}
return data;
}
function getMaxTextListLength(list) {
var lengthList = list.map(function(item) {
return measureText(item);
});
return Math.max.apply(null, lengthList);
}
function getRadarCoordinateSeries(length) {
var eachAngle = 2 * Math.PI / length;
var CoordinateSeries = [];
for (var i = 0; i < length; i++) {
CoordinateSeries.push(eachAngle * i);
}
return CoordinateSeries.map(function(item) {
return -1 * item + Math.PI / 2;
});
}
function getToolTipData(seriesData, calPoints, index, categories) {
var option = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
var textList = seriesData.map(function(item) {
return {
text: option.format ? option.format(item, categories[index]) : item.name + ': ' + item.data,
color: item.color
};
});
var validCalPoints = [];
var offset = {
x: 0,
y: 0
};
for (let i = 0; i < calPoints.length; i++) {
let points = calPoints[i];
if (typeof points[index] !== 'undefined' && points[index] !== null) {
validCalPoints.push(points[index]);
}
}
for (let i = 0; i < validCalPoints.length; i++) {
let item = validCalPoints[i];
offset.x = Math.round(item.x);
offset.y += item.y;
}
offset.y /= validCalPoints.length;
return {
textList: textList,
offset: offset
};
}
function getMixToolTipData(seriesData, calPoints, index, categories) {
var option = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
var textList = seriesData.map(function(item) {
return {
text: option.format ? option.format(item, categories[index]) : item.name + ': ' + item.data,
color: item.color,
disableLegend: item.disableLegend ? true : false
};
});
textList = textList.filter(function(item) {
if (item.disableLegend !== true) {
return item;
}
});
var validCalPoints = [];
var offset = {
x: 0,
y: 0
};
for (let i = 0; i < calPoints.length; i++) {
let points = calPoints[i];
if (typeof points[index] !== 'undefined' && points[index] !== null) {
validCalPoints.push(points[index]);
}
}
for (let i = 0; i < validCalPoints.length; i++) {
let item = validCalPoints[i];
offset.x = Math.round(item.x);
offset.y += item.y;
}
offset.y /= validCalPoints.length;
return {
textList: textList,
offset: offset
};
}
function getCandleToolTipData(series, seriesData, calPoints, index, categories, extra) {
var option = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : {};
let upColor = extra.color.upFill;
let downColor = extra.color.downFill;
//颜色顺序为开盘,收盘,最低,最高
let color = [upColor, upColor, downColor, upColor];
var textList = [];
let text0 = {
text: categories[index],
color: null
};
textList.push(text0);
seriesData.map(function(item) {
//console.log(color)
if (index == 0 && item.data[1] - item.data[0] < 0) {
color[1] = downColor;
} else {
if (item.data[0] < series[index - 1][1]) {
color[0] = downColor;
}
if (item.data[1] < item.data[0]) {
color[1] = downColor;
}
if (item.data[2] > series[index - 1][1]) {
color[2] = upColor;
}
if (item.data[3] < series[index - 1][1]) {
color[3] = downColor;
}
}
let text1 = {
text: '开盘:' + item.data[0],
color: color[0]
};
let text2 = {
text: '收盘:' + item.data[1],
color: color[1]
};
let text3 = {
text: '最低:' + item.data[2],
color: color[2]
};
let text4 = {
text: '最高:' + item.data[3],
color: color[3]
};
textList.push(text1, text2, text3, text4);
});
var validCalPoints = [];
var offset = {
x: 0,
y: 0
};
for (let i = 0; i < calPoints.length; i++) {
let points = calPoints[i];
if (typeof points[index] !== 'undefined' && points[index] !== null) {
validCalPoints.push(points[index]);
}
}
offset.x = Math.round(validCalPoints[0][0].x);
return {
textList: textList,
offset: offset
};
}
function findCurrentIndex(currentPoints, xAxisPoints, opts, config) {
var offset = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0;
var currentIndex = -1;
if (isInExactChartArea(currentPoints, opts, config)) {
xAxisPoints.forEach(function(item, index) {
if (currentPoints.x + offset > item) {
currentIndex = index;
}
});
}
return currentIndex;
}
function isInExactChartArea(currentPoints, opts, config) {
return currentPoints.x < opts.width - config.padding && currentPoints.x > config.padding + config.yAxisWidth + config.yAxisTitleWidth &&
currentPoints.y > config.padding && currentPoints.y < opts.height - config.legendHeight - config.xAxisHeight - config
.padding;
}
function findRadarChartCurrentIndex(currentPoints, radarData, count) {
var eachAngleArea = 2 * Math.PI / count;
var currentIndex = -1;
if (isInExactPieChartArea(currentPoints, radarData.center, radarData.radius)) {
var fixAngle = function fixAngle(angle) {
if (angle < 0) {
angle += 2 * Math.PI;
}
if (angle > 2 * Math.PI) {
angle -= 2 * Math.PI;
}
return angle;
};
var angle = Math.atan2(radarData.center.y - currentPoints.y, currentPoints.x - radarData.center.x);
angle = -1 * angle;
if (angle < 0) {
angle += 2 * Math.PI;
}
var angleList = radarData.angleList.map(function(item) {
item = fixAngle(-1 * item);
return item;
});
angleList.forEach(function(item, index) {
var rangeStart = fixAngle(item - eachAngleArea / 2);
var rangeEnd = fixAngle(item + eachAngleArea / 2);
if (rangeEnd < rangeStart) {
rangeEnd += 2 * Math.PI;
}
if (angle >= rangeStart && angle <= rangeEnd || angle + 2 * Math.PI >= rangeStart && angle + 2 * Math.PI <=
rangeEnd) {
currentIndex = index;
}
});
}
return currentIndex;
}
function findPieChartCurrentIndex(currentPoints, pieData) {
var currentIndex = -1;
if (isInExactPieChartArea(currentPoints, pieData.center, pieData.radius)) {
var angle = Math.atan2(pieData.center.y - currentPoints.y, currentPoints.x - pieData.center.x);
angle = -angle;
for (var i = 0, len = pieData.series.length; i < len; i++) {
var item = pieData.series[i];
if (isInAngleRange(angle, item._start_, item._start_ + item._proportion_ * 2 * Math.PI)) {
currentIndex = i;
break;
}
}
}
return currentIndex;
}
function isInExactPieChartArea(currentPoints, center, radius) {
return Math.pow(currentPoints.x - center.x, 2) + Math.pow(currentPoints.y - center.y, 2) <= Math.pow(radius, 2);
}
function splitPoints(points) {
var newPoints = [];
var items = [];
points.forEach(function(item, index) {
if (item !== null) {
items.push(item);
} else {
if (items.length) {
newPoints.push(items);
}
items = [];
}
});
if (items.length) {
newPoints.push(items);
}
return newPoints;
}
function calLegendData(series, opts, config) {
if (opts.legend === false) {
return {
legendList: [],
legendHeight: 0
};
}
//适配H5高分屏
var padding = 5 * opts.pixelRatio;
var marginTop = 8 * opts.pixelRatio;
var shapeWidth = 15 * opts.pixelRatio;
var legendList = [];
var widthCount = 0;
var currentRow = [];
for (let i = 0; i < series.length; i++) {
let item = series[i];
let itemWidth = 3 * padding + shapeWidth + measureText(item.name || 'undefined');
if (widthCount + itemWidth > opts.width) {
legendList.push(currentRow);
widthCount = itemWidth;
currentRow = [item];
} else {
widthCount += itemWidth;
currentRow.push(item);
}
}
if (currentRow.length) {
legendList.push(currentRow);
}
return {
legendList: legendList,
legendHeight: legendList.length * (config.fontSize + marginTop) + padding
};
}
function calCategoriesData(categories, opts, config) {
var result = {
angle: 0,
xAxisHeight: config.xAxisHeight
};
var _getXAxisPoints = getXAxisPoints(categories, opts, config),
eachSpacing = _getXAxisPoints.eachSpacing;
// get max length of categories text
var categoriesTextLenth = categories.map(function(item) {
return measureText(item);
});
var maxTextLength = Math.max.apply(this, categoriesTextLenth);
if (opts.xAxis.rotateLabel == true && maxTextLength + 2 * config.xAxisTextPadding > eachSpacing) {
result.angle = 45 * Math.PI / 180;
result.xAxisHeight = 2 * config.xAxisTextPadding + maxTextLength * Math.sin(result.angle);
}
return result;
}
function getRadarDataPoints(angleList, center, radius, series, opts) {
var process = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 1;
var radarOption = opts.extra.radar || {};
radarOption.max = radarOption.max || 0;
var maxData = Math.max(radarOption.max, Math.max.apply(null, dataCombine(series)));
var data = [];
for (let i = 0; i < series.length; i++) {
let each = series[i];
let listItem = {};
listItem.color = each.color;
listItem.data = [];
each.data.forEach(function(item, index) {
let tmp = {};
tmp.angle = angleList[index];
tmp.proportion = item / maxData;
tmp.position = convertCoordinateOrigin(radius * tmp.proportion * process * Math.cos(tmp.angle), radius * tmp.proportion *
process * Math.sin(tmp.angle), center);
listItem.data.push(tmp);
});
data.push(listItem);
}
return data;
}
function getPieDataPoints(series, radius) {
var process = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
var count = 0;
var _start_ = 0;
for (let i = 0; i < series.length; i++) {
let item = series[i];
item.data = item.data === null ? 0 : item.data;
count += item.data;
}
for (let i = 0; i < series.length; i++) {
let item = series[i];
item.data = item.data === null ? 0 : item.data;
if (count === 0) {
item._proportion_ = 1 / series.length * process;
} else {
item._proportion_ = item.data / count * process;
}
item._radius_=radius;
}
for (let i = 0; i < series.length; i++) {
let item = series[i];
item._start_ = _start_;
_start_ += 2 * item._proportion_ * Math.PI;
}
return series;
}
function getRoseDataPoints(series, type, minRadius, radius) {
var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
var count = 0;
var _start_ = 0;
var dataArr=[];
for (let i = 0; i < series.length; i++) {
let item = series[i];
item.data = item.data === null ? 0 : item.data;
count += item.data;
dataArr.push(item.data);
}
var minData = dataArr.pop();
var maxData = dataArr.shift();
var radiusLength = radius - minRadius;
for (let i = 0; i < series.length; i++) {
let item = series[i];
item.data = item.data === null ? 0 : item.data;
if (count === 0 || type == 'area') {
item._proportion_ = 1 / series.length * process;
} else {
item._proportion_ = item.data / count * process;
}
item._radius_ = minRadius + radiusLength * ( (item.data - minData)/(maxData-minData) );
}
for (let i = 0; i < series.length; i++) {
let item = series[i];
item._start_ = _start_;
_start_ += 2 * item._proportion_ * Math.PI;
}
return series;
}
function getArcbarDataPoints(series, arcbarOption) {
var process = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
if (process == 1) {
process = 0.999999;
}
for (let i = 0; i < series.length; i++) {
let item = series[i];
item.data = item.data === null ? 0 : item.data;
let totalAngle;
if (arcbarOption.type == 'default') {
totalAngle = arcbarOption.startAngle - arcbarOption.endAngle + 1;
} else {
totalAngle = 2;
}
item._proportion_ = totalAngle * item.data * process + arcbarOption.startAngle;
if (item._proportion_ >= 2) {
item._proportion_ = item._proportion_ % 2;
}
}
return series;
}
function getGaugeAxisPoints(categories, startAngle, endAngle) {
let totalAngle = startAngle - endAngle + 1;
let tempStartAngle = startAngle;
for (let i = 0; i < categories.length; i++) {
categories[i].value = categories[i].value === null ? 0 : categories[i].value;
categories[i]._startAngle_ = tempStartAngle;
categories[i]._endAngle_ = totalAngle * categories[i].value + startAngle;
if (categories[i]._endAngle_ >= 2) {
categories[i]._endAngle_ = categories[i]._endAngle_ % 2;
}
tempStartAngle = categories[i]._endAngle_;
}
return categories;
}
function getGaugeDataPoints(series, categories, gaugeOption) {
let process = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 1;
for (let i = 0; i < series.length; i++) {
let item = series[i];
item.data = item.data === null ? 0 : item.data;
if (gaugeOption.pointer.color == 'auto') {
for (let i = 0; i < categories.length; i++) {
if (item.data <= categories[i].value) {
item.color = categories[i].color;
break;
}
}
} else {
item.color = gaugeOption.pointer.color;
}
let totalAngle = gaugeOption.startAngle - gaugeOption.endAngle + 1;
item._endAngle_ = totalAngle * item.data + gaugeOption.startAngle;
item._oldAngle_ = gaugeOption.oldAngle;
if (gaugeOption.oldAngle < gaugeOption.endAngle) {
item._oldAngle_ += 2;
}
if (item.data >= gaugeOption.oldData) {
item._proportion_ = (item._endAngle_ - item._oldAngle_) * process + gaugeOption.oldAngle;
} else {
item._proportion_ = item._oldAngle_ - (item._oldAngle_ - item._endAngle_) * process;
}
if (item._proportion_ >= 2) {
item._proportion_ = item._proportion_ % 2;
}
}
return series;
}
function getPieTextMaxLength(series) {
series = getPieDataPoints(series);
let maxLength = 0;
for (let i = 0; i < series.length; i++) {
let item = series[i];
let text = item.format ? item.format(+item._proportion_.toFixed(2)) : util.toFixed(item._proportion_ * 100) + '%';
maxLength = Math.max(maxLength, measureText(text));
}
return maxLength;
}
function fixColumeData(points, eachSpacing, columnLen, index, config, opts) {
return points.map(function(item) {
if (item === null) {
return null;
}
item.width = Math.ceil((eachSpacing - 2 * config.columePadding) / columnLen);
if (opts.extra.column && opts.extra.column.width && +opts.extra.column.width > 0) {
item.width = Math.min(item.width, +opts.extra.column.width);
}
item.x += (index + 0.5 - columnLen / 2) * item.width;
return item;
});
}
function fixColumeMeterData(points, eachSpacing, columnLen, index, config, opts, border) {
return points.map(function(item) {
if (item === null) {
return null;
}
item.width = eachSpacing - 2 * config.columePadding;
if (opts.extra.column && opts.extra.column.width && +opts.extra.column.width > 0) {
item.width = Math.min(item.width, +opts.extra.column.width);
} else {
item.width = Math.min(item.width, 25);
}
if (index > 0) {
item.width -= 2 * border;
}
return item;
});
}
function fixColumeStackData(points, eachSpacing, columnLen, index, config, opts, series) {
return points.map(function(item, indexn) {
if (item === null) {
return null;
}
item.width = eachSpacing - 2 * config.columePadding;
if (opts.extra.column && opts.extra.column.width && +opts.extra.column.width > 0) {
item.width = Math.min(item.width, +opts.extra.column.width);
} else {
item.width = Math.min(item.width, 25);
}
return item;
});
}
function getXAxisPoints(categories, opts, config) {
var yAxisTotalWidth = config.yAxisWidth + config.yAxisTitleWidth;
var spacingValid = opts.width - 2 * config.padding - yAxisTotalWidth;
var dataCount = opts.enableScroll ? Math.min(opts.xAxis.itemCount, categories.length) : categories.length;
var eachSpacing = spacingValid / dataCount;
var xAxisPoints = [];
var startX = config.padding + yAxisTotalWidth;
var endX = opts.width - config.padding;
categories.forEach(function(item, index) {
xAxisPoints.push(startX + index * eachSpacing);
});
if (opts.enableScroll === true) {
xAxisPoints.push(startX + categories.length * eachSpacing);
} else {
xAxisPoints.push(endX);
}
return {
xAxisPoints: xAxisPoints,
startX: startX,
endX: endX,
eachSpacing: eachSpacing
};
}
function getCandleDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config) {
var process = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : 1;
var points = [];
var validHeight = opts.height - 2 * config.padding - config.xAxisHeight - config.legendHeight;
data.forEach(function(item, index) {
if (item === null) {
points.push(null);
} else {
var cPoints = [];
item.forEach(function(items, indexs) {
var point = {};
point.x = xAxisPoints[index] + Math.round(eachSpacing / 2);
var value = items.value || items;
var height = validHeight * (value - minRange) / (maxRange - minRange);
height *= process;
point.y = opts.height - config.xAxisHeight - config.legendHeight - Math.round(height) - config.padding;
cPoints.push(point);
});
points.push(cPoints);
}
});
return points;
}
function getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config) {
var process = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : 1;
var points = [];
var validHeight = opts.height - 2 * config.padding - config.xAxisHeight - config.legendHeight;
data.forEach(function(item, index) {
if (item === null) {
points.push(null);
} else {
var point = {};
point.color = item.color;
point.x = xAxisPoints[index] + Math.round(eachSpacing / 2);
var value = item;
if (typeof item === 'object' && item !== null) {
value = item.value
}
var height = validHeight * (value - minRange) / (maxRange - minRange);
height *= process;
point.y = opts.height - config.xAxisHeight - config.legendHeight - Math.round(height) - config.padding;
points.push(point);
}
});
return points;
}
function getStackDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, seriesIndex, stackSeries) {
var process = arguments.length > 9 && arguments[9] !== undefined ? arguments[9] : 1;
var points = [];
var validHeight = opts.height - 2 * config.padding - config.xAxisHeight - config.legendHeight;
data.forEach(function(item, index) {
if (item === null) {
points.push(null);
} else {
var point = {};
point.color = item.color;
point.x = xAxisPoints[index] + Math.round(eachSpacing / 2);
if (seriesIndex > 0) {
var value = 0;
for (let i = 0; i <= seriesIndex; i++) {
value += stackSeries[i].data[index];
}
var value0 = value - item;
var height = validHeight * (value - minRange) / (maxRange - minRange);
var height0 = validHeight * (value0 - minRange) / (maxRange - minRange);
} else {
var value = item;
var height = validHeight * (value - minRange) / (maxRange - minRange);
var height0 = 0;
}
var heightc = height0;
height *= process;
heightc *= process;
point.y = opts.height - config.xAxisHeight - config.legendHeight - Math.round(height) - config.padding;
point.y0 = opts.height - config.xAxisHeight - config.legendHeight - Math.round(heightc) - config.padding;
points.push(point);
}
});
return points;
}
function getYAxisTextList(series, opts, config, stack) {
var data;
if (stack == 'stack') {
//data = dataCombine(series);
data = dataCombineStack(series);
} else {
data = dataCombine(series);
}
var sorted = [];
// remove null from data
data = data.filter(function(item) {
//return item !== null;
if (typeof item === 'object' && item !== null) {
//判断是否为数组
if (item.constructor == Array) {
return item !== null;
} else {
return item.value !== null;
}
} else {
return item !== null;
}
});
//var minData = Math.min.apply(this, data);
//var maxData = Math.max.apply(this, data);
data.map(function(item) {
if (typeof item === 'object') {
if (item.constructor == Array) {
item.map(function(subitem) {
sorted.push(subitem);
})
} else {
sorted.push(item.value);
}
} else {
sorted.push(item);
}
//typeof item === 'object' ? sorted.push(item.value) : sorted.push(item)
})
var minData = 0;
var maxData = 0;
if (sorted.length > 0) {
minData = Math.min.apply(this, sorted);
maxData = Math.max.apply(this, sorted);
}
if (typeof opts.yAxis.min === 'number') {
minData = Math.min(opts.yAxis.min, minData);
}
if (typeof opts.yAxis.max === 'number') {
maxData = Math.max(opts.yAxis.max, maxData);
}
// fix issue https://github.com/xiaolin3303/wx-charts/issues/9
if (minData === maxData) {
var rangeSpan = maxData || 10;
//minData -= rangeSpan;
maxData += rangeSpan;
}
var dataRange = getDataRange(minData, maxData);
var minRange = dataRange.minRange;
var maxRange = dataRange.maxRange;
var range = [];
var eachRange = (maxRange - minRange) / config.yAxisSplit;
for (var i = 0; i <= config.yAxisSplit; i++) {
range.push(minRange + eachRange * i);
}
return range.reverse();
}
function calYAxisData(series, opts, config) {
//堆叠图重算Y轴
var columnstyle = assign({}, opts.extra.column || {
"type": ""
});
var ranges = getYAxisTextList(series, opts, config, columnstyle.type);
var yAxisWidth = config.yAxisWidth;
var rangesFormat = ranges.map(function(item) {
item = util.toFixed(item, 2);
item = opts.yAxis.format ? opts.yAxis.format(Number(item)) : item;
yAxisWidth = Math.max(yAxisWidth, measureText(item) + 5);
return item;
});
if (opts.yAxis.disabled === true) {
yAxisWidth = 0;
}
return {
rangesFormat: rangesFormat,
ranges: ranges,
yAxisWidth: yAxisWidth
};
}
function calTooltipYAxisData(point, series, opts, config, eachSpacing) {
var ranges = getYAxisTextList(series, opts, config);
var spacingValid = opts.height - 2 * config.padding - config.xAxisHeight - config.legendHeight;
let maxVal = ranges[0];
let minVal = ranges[ranges.length - 1];
let minAxis = config.padding;
let maxAxis = config.padding + spacingValid;
let item = maxVal - (maxVal - minVal) * (point - minAxis) / (maxAxis - minAxis);
item = opts.yAxis.format ? opts.yAxis.format(Number(item)) : item;
return item;
}
function contextRotate(context, opts) {
if (opts.rotateLock !== true) {
context.translate(opts.height, 0);
context.rotate(90 * Math.PI / 180);
} else if (opts._rotate_ !== true) {
context.translate(opts.height, 0);
context.rotate(90 * Math.PI / 180);
opts._rotate_ = true;
}
}
function drawPointShape(points, color, shape, context, opts) {
context.beginPath();
context.setStrokeStyle("#ffffff");
context.setLineWidth(1 * opts.pixelRatio);
context.setFillStyle(color);
if (shape === 'diamond') {
points.forEach(function(item, index) {
if (item !== null) {
context.moveTo(item.x, item.y - 4.5);
context.lineTo(item.x - 4.5, item.y);
context.lineTo(item.x, item.y + 4.5);
context.lineTo(item.x + 4.5, item.y);
context.lineTo(item.x, item.y - 4.5);
}
});
} else if (shape === 'circle') {
points.forEach(function(item, index) {
if (item !== null) {
context.moveTo(item.x + 3.5 * opts.pixelRatio, item.y);
context.arc(item.x, item.y, 4 * opts.pixelRatio, 0, 2 * Math.PI, false);
}
});
} else if (shape === 'rect') {
points.forEach(function(item, index) {
if (item !== null) {
context.moveTo(item.x - 3.5, item.y - 3.5);
context.rect(item.x - 3.5, item.y - 3.5, 7, 7);
}
});
} else if (shape === 'triangle') {
points.forEach(function(item, index) {
if (item !== null) {
context.moveTo(item.x, item.y - 4.5);
context.lineTo(item.x - 4.5, item.y + 4.5);
context.lineTo(item.x + 4.5, item.y + 4.5);
context.lineTo(item.x, item.y - 4.5);
}
});
}
context.closePath();
context.fill();
context.stroke();
}
function drawRingTitle(opts, config, context) {
var titlefontSize = opts.title.fontSize || config.titleFontSize;
var subtitlefontSize = opts.subtitle.fontSize || config.subtitleFontSize;
var title = opts.title.name || '';
var subtitle = opts.subtitle.name || '';
var titleFontColor = opts.title.color || config.titleColor;
var subtitleFontColor = opts.subtitle.color || config.subtitleColor;
var titleHeight = title ? titlefontSize : 0;
var subtitleHeight = subtitle ? subtitlefontSize : 0;
var margin = 5;
if (subtitle) {
var textWidth = measureText(subtitle, subtitlefontSize);
var startX = (opts.width - textWidth) / 2 + (opts.subtitle.offsetX || 0);
var startY = ((opts.height - config.legendHeight + subtitlefontSize) / 2) + (opts.subtitle.offsetY || 0);
if (title) {
startY -= (titleHeight + margin) / 2;
}
context.beginPath();
context.setFontSize(subtitlefontSize);
context.setFillStyle(subtitleFontColor);
context.fillText(subtitle, startX, startY);
context.closePath();
context.stroke();
}
if (title) {
var _textWidth = measureText(title, titlefontSize);
var _startX = (opts.width - _textWidth) / 2 + (opts.title.offsetX || 0);
var _startY = ((opts.height - config.legendHeight + titlefontSize) / 2) + (opts.title.offsetY || 0);
if (subtitle) {
_startY += (subtitleHeight + margin) / 2;
}
context.beginPath();
context.setFontSize(titlefontSize);
context.setFillStyle(titleFontColor);
context.fillText(title, _startX, _startY);
context.closePath();
context.stroke();
}
}
function drawPointText(points, series, config, context) {
// 绘制数据文案
var data = series.data;
points.forEach(function(item, index) {
if (item !== null) {
//var formatVal = series.format ? series.format(data[index]) : data[index];
context.beginPath();
context.setFontSize(series.textSize || config.fontSize);
context.setFillStyle(series.textColor || '#666666');
var value = data[index]
if (typeof data[index] === 'object' && data[index] !== null) {
value = data[index].value
}
var formatVal = series.format ? series.format(value) : value;
context.fillText(formatVal, item.x - measureText(formatVal,series.textSize || config.fontSize) / 2, item.y - 2);
context.closePath();
context.stroke();
}
});
}
function drawGaugeLabel(gaugeOption, radius, centerPosition, opts, config, context) {
radius -= gaugeOption.width / 2 + config.gaugeLabelTextMargin;
let totalAngle = gaugeOption.startAngle - gaugeOption.endAngle + 1;
let splitAngle = totalAngle / gaugeOption.splitLine.splitNumber;
let totalNumber = gaugeOption.endNumber - gaugeOption.startNumber;
let splitNumber = totalNumber / gaugeOption.splitLine.splitNumber;
let nowAngle = gaugeOption.startAngle;
let nowNumber = gaugeOption.startNumber;
for (let i = 0; i < gaugeOption.splitLine.splitNumber + 1; i++) {
var pos = {
x: radius * Math.cos(nowAngle * Math.PI),
y: radius * Math.sin(nowAngle * Math.PI)
};
var labelText = gaugeOption.labelFormat ? gaugeOption.labelFormat(nowNumber) : nowNumber;
pos.x += centerPosition.x - measureText(labelText) / 2;
pos.y += centerPosition.y;
var startX = pos.x;
var startY = pos.y;
context.beginPath();
context.setFontSize(config.fontSize);
context.setFillStyle(gaugeOption.labelColor || '#666666');
context.fillText(labelText, startX, startY + config.fontSize / 2);
context.closePath();
context.stroke();
nowAngle += splitAngle;
if (nowAngle >= 2) {
nowAngle = nowAngle % 2;
}
nowNumber += splitNumber;
}
}
function drawRadarLabel(angleList, radius, centerPosition, opts, config, context) {
var radarOption = opts.extra.radar || {};
radius += config.radarLabelTextMargin;
angleList.forEach(function(angle, index) {
var pos = {
x: radius * Math.cos(angle),
y: radius * Math.sin(angle)
};
var posRelativeCanvas = convertCoordinateOrigin(pos.x, pos.y, centerPosition);
var startX = posRelativeCanvas.x;
var startY = posRelativeCanvas.y;
if (util.approximatelyEqual(pos.x, 0)) {
startX -= measureText(opts.categories[index] || '') / 2;
} else if (pos.x < 0) {
startX -= measureText(opts.categories[index] || '');
}
context.beginPath();
context.setFontSize(config.fontSize);
context.setFillStyle(radarOption.labelColor || '#666666');
context.fillText(opts.categories[index] || '', startX, startY + config.fontSize / 2);
context.closePath();
context.stroke();
});
}
function drawPieText(series, opts, config, context, radius, center) {
var lineRadius = config.pieChartLinePadding;
var textObjectCollection = [];
var lastTextObject = null;
var seriesConvert = series.map(function(item) {
var arc = 2 * Math.PI - (item._start_ + 2 * Math.PI * item._proportion_ / 2);
var text = item.format ? item.format(+item._proportion_.toFixed(2)) : util.toFixed(item._proportion_ * 100) + '%';
var color = item.color;
var radius = item._radius_;
return {
arc: arc,
text: text,
color: color,
radius: radius,
textColor: item.textColor,
textSize: item.textSize,
};
});
for (let i = 0; i < seriesConvert.length; i++) {
let item = seriesConvert[i];
// line end
let orginX1 = Math.cos(item.arc) * (item.radius+lineRadius);
let orginY1 = Math.sin(item.arc) * (item.radius+lineRadius);
// line start
let orginX2 = Math.cos(item.arc) * item.radius;
let orginY2 = Math.sin(item.arc) * item.radius;
// text start
let orginX3 = orginX1 >= 0 ? orginX1 + config.pieChartTextPadding : orginX1 - config.pieChartTextPadding;
let orginY3 = orginY1;
let textWidth = measureText(item.text);
let startY = orginY3;
if (lastTextObject && util.isSameXCoordinateArea(lastTextObject.start, {
x: orginX3
})) {
if (orginX3 > 0) {
startY = Math.min(orginY3, lastTextObject.start.y);
} else if (orginX1 < 0) {
startY = Math.max(orginY3, lastTextObject.start.y);
} else {
if (orginY3 > 0) {
startY = Math.max(orginY3, lastTextObject.start.y);
} else {
startY = Math.min(orginY3, lastTextObject.start.y);
}
}
}
if (orginX3 < 0) {
orginX3 -= textWidth;
}
let textObject = {
lineStart: {
x: orginX2,
y: orginY2
},
lineEnd: {
x: orginX1,
y: orginY1
},
start: {
x: orginX3,
y: startY
},
width: textWidth,
height: config.fontSize,
text: item.text,
color: item.color,
textColor: item.textColor,
textSize: item.textSize
};
lastTextObject = avoidCollision(textObject, lastTextObject);
textObjectCollection.push(lastTextObject);
}
for (let i = 0; i < textObjectCollection.length; i++) {
let item = textObjectCollection[i];
let lineStartPoistion = convertCoordinateOrigin(item.lineStart.x, item.lineStart.y, center);
let lineEndPoistion = convertCoordinateOrigin(item.lineEnd.x, item.lineEnd.y, center);
let textPosition = convertCoordinateOrigin(item.start.x, item.start.y, center);
context.setLineWidth(1 * opts.pixelRatio);
context.setFontSize(config.fontSize);
context.beginPath();
context.setStrokeStyle(item.color);
context.setFillStyle(item.color);
context.moveTo(lineStartPoistion.x, lineStartPoistion.y);
let curveStartX = item.start.x < 0 ? textPosition.x + item.width : textPosition.x;
let textStartX = item.start.x < 0 ? textPosition.x - 5 : textPosition.x + 5;
context.quadraticCurveTo(lineEndPoistion.x, lineEndPoistion.y, curveStartX, textPosition.y);
context.moveTo(lineStartPoistion.x, lineStartPoistion.y);
context.stroke();
context.closePath();
context.beginPath();
context.moveTo(textPosition.x + item.width, textPosition.y);
context.arc(curveStartX, textPosition.y, 2, 0, 2 * Math.PI);
context.closePath();
context.fill();
context.beginPath();
context.setFontSize(item.textSize||config.fontSize);
context.setFillStyle(item.textColor||'#666666');
context.fillText(item.text, textStartX, textPosition.y + 3);
context.closePath();
context.stroke();
context.closePath();
}
}
function drawToolTipSplitLine(offsetX, opts, config, context) {
var toolTipOption = opts.extra.tooltip || {};
toolTipOption.gridType = toolTipOption.gridType == undefined ? 'solid' : toolTipOption.gridType;
toolTipOption.dashLength = toolTipOption.dashLength == undefined ? 4 : toolTipOption.dashLength;
var startY = config.padding;
var endY = opts.height - config.padding - config.xAxisHeight - config.legendHeight;
if (toolTipOption.gridType == 'dash') {
context.setLineDash([toolTipOption.dashLength, toolTipOption.dashLength]);
}
context.beginPath();
context.setStrokeStyle(toolTipOption.gridColor || '#cccccc');
context.setLineWidth(1 * opts.pixelRatio);
context.moveTo(offsetX, startY);
context.lineTo(offsetX, endY);
context.closePath();
context.stroke();
context.setLineDash([]);
if (toolTipOption.xAxisLabel) {
let labelText = opts.categories[opts.tooltip.index];
context.setFontSize(config.fontSize);
let textWidth = context.measureText(labelText).width;
let textX = offsetX - config.toolTipPadding - 0.5 * textWidth;
let textY = endY;
context.beginPath();
context.setFillStyle(hexToRgb(toolTipOption.labelBgColor || config.toolTipBackground, toolTipOption.labelBgOpacity ||
config.toolTipOpacity));
context.setStrokeStyle(toolTipOption.labelBgColor || config.toolTipBackground);
context.setLineWidth(1 * opts.pixelRatio);
context.rect(textX, textY, textWidth + 2 * config.toolTipPadding, config.fontSize + 2 * config.toolTipPadding);
context.closePath();
context.stroke();
context.fill();
context.beginPath();
context.setFontSize(config.fontSize);
context.setFillStyle(toolTipOption.labelFontColor || config.fontColor);
context.fillText(labelText, textX + 2 * config.toolTipPadding, textY + config.toolTipPadding + config.fontSize);
context.closePath();
context.stroke();
}
}
function drawToolTipHorizentalLine(opts, config, context, eachSpacing, xAxisPoints) {
var toolTipOption = opts.extra.tooltip || {};
toolTipOption.gridType = toolTipOption.gridType == undefined ? 'solid' : toolTipOption.gridType;
toolTipOption.dashLength = toolTipOption.dashLength == undefined ? 4 : toolTipOption.dashLength;
var startX = config.padding + config.yAxisWidth + config.yAxisTitleWidth;
var endX = opts.width - config.padding;
if (toolTipOption.gridType == 'dash') {
context.setLineDash([toolTipOption.dashLength, toolTipOption.dashLength]);
}
context.beginPath();
context.setStrokeStyle(toolTipOption.gridColor || '#cccccc');
context.setLineWidth(1 * opts.pixelRatio);
context.moveTo(startX, opts.tooltip.offset.y);
context.lineTo(endX, opts.tooltip.offset.y);
context.closePath();
context.stroke();
context.setLineDash([]);
if (toolTipOption.yAxisLabel) {
let labelText = calTooltipYAxisData(opts.tooltip.offset.y, opts.series, opts, config, eachSpacing);
context.setFontSize(config.fontSize);
let textWidth = context.measureText(labelText).width;
let textX = startX - 2 * config.toolTipPadding - textWidth;
let textY = opts.tooltip.offset.y;
context.beginPath();
context.setFillStyle(hexToRgb(toolTipOption.labelBgColor || config.toolTipBackground, toolTipOption.labelBgOpacity ||
config.toolTipOpacity));
context.setStrokeStyle(toolTipOption.labelBgColor || config.toolTipBackground);
context.setLineWidth(1 * opts.pixelRatio);
context.rect(textX, textY - 0.5 * config.fontSize - config.toolTipPadding, textWidth + 2 * config.toolTipPadding,
config.fontSize + 2 * config.toolTipPadding);
context.closePath();
context.stroke();
context.fill();
context.beginPath();
context.setFontSize(config.fontSize);
context.setFillStyle(toolTipOption.labelFontColor || config.fontColor);
context.fillText(labelText, textX + config.toolTipPadding, textY + 0.5 * config.fontSize);
context.closePath();
context.stroke();
}
}
function drawToolTipSplitArea(offsetX, opts, config, context, eachSpacing) {
var toolTipOption = opts.extra.tooltip || {
activeBgColor: '#000000',
activeBgOpacity: 0.08
};
toolTipOption.activeBgColor = toolTipOption.activeBgColor ? toolTipOption.activeBgColor : '#000000';
toolTipOption.activeBgOpacity = toolTipOption.activeBgOpacity ? toolTipOption.activeBgOpacity : 0.08;
var startY = config.padding;
var endY = opts.height - config.padding - config.xAxisHeight - config.legendHeight;
context.beginPath();
context.setFillStyle(hexToRgb(toolTipOption.activeBgColor, toolTipOption.activeBgOpacity));
context.rect(offsetX - eachSpacing / 2, startY, eachSpacing, endY - startY);
context.closePath();
context.fill();
}
function drawToolTip(textList, offset, opts, config, context, eachSpacing, xAxisPoints) {
var toolTipOption = opts.extra.tooltip || {
bgColor: '#000000',
bgOpacity: 0.7,
fontColor: '#FFFFFF'
};
toolTipOption.bgColor = toolTipOption.bgColor ? toolTipOption.bgColor : '#000000';
toolTipOption.bgOpacity = toolTipOption.bgOpacity ? toolTipOption.bgOpacity : 0.7;
toolTipOption.fontColor = toolTipOption.fontColor ? toolTipOption.fontColor : '#FFFFFF';
var legendWidth = 4 * opts.pixelRatio;
var legendMarginRight = 5 * opts.pixelRatio;
var arrowWidth = 8 * opts.pixelRatio;
var isOverRightBorder = false;
if (opts.type == 'line' || opts.type == 'area' || opts.type == 'candle' || opts.type == 'mix') {
drawToolTipSplitLine(opts.tooltip.offset.x, opts, config, context);
}
offset = assign({
x: 0,
y: 0
}, offset);
offset.y -= 8 * opts.pixelRatio;
var textWidth = textList.map(function(item) {
return measureText(item.text);
});
var toolTipWidth = legendWidth + legendMarginRight + 4 * config.toolTipPadding + Math.max.apply(null, textWidth);
var toolTipHeight = 2 * config.toolTipPadding + textList.length * config.toolTipLineHeight;
// if beyond the right border
if (offset.x - Math.abs(opts._scrollDistance_) + arrowWidth + toolTipWidth > opts.width) {
isOverRightBorder = true;
}
// draw background rect
context.beginPath();
context.setFillStyle(hexToRgb(toolTipOption.bgColor || config.toolTipBackground, toolTipOption.bgOpacity || config.toolTipOpacity));
if (isOverRightBorder) {
context.moveTo(offset.x, offset.y + 10 * opts.pixelRatio);
context.lineTo(offset.x - arrowWidth, offset.y + 10 * opts.pixelRatio - 5 * opts.pixelRatio);
context.lineTo(offset.x - arrowWidth, offset.y);
context.lineTo(offset.x - arrowWidth - Math.round(toolTipWidth), offset.y);
context.lineTo(offset.x - arrowWidth - Math.round(toolTipWidth), offset.y + toolTipHeight);
context.lineTo(offset.x - arrowWidth, offset.y + toolTipHeight);
context.lineTo(offset.x - arrowWidth, offset.y + 10 * opts.pixelRatio + 5 * opts.pixelRatio);
context.lineTo(offset.x, offset.y + 10 * opts.pixelRatio);
} else {
context.moveTo(offset.x, offset.y + 10 * opts.pixelRatio);
context.lineTo(offset.x + arrowWidth, offset.y + 10 * opts.pixelRatio - 5 * opts.pixelRatio);
context.lineTo(offset.x + arrowWidth, offset.y);
context.lineTo(offset.x + arrowWidth + Math.round(toolTipWidth), offset.y);
context.lineTo(offset.x + arrowWidth + Math.round(toolTipWidth), offset.y + toolTipHeight);
context.lineTo(offset.x + arrowWidth, offset.y + toolTipHeight);
context.lineTo(offset.x + arrowWidth, offset.y + 10 * opts.pixelRatio + 5 * opts.pixelRatio);
context.lineTo(offset.x, offset.y + 10 * opts.pixelRatio);
}
context.closePath();
context.fill();
// draw legend
textList.forEach(function(item, index) {
if (item.color !== null) {
context.beginPath();
context.setFillStyle(item.color);
var startX = offset.x + arrowWidth + 2 * config.toolTipPadding;
var startY = offset.y + (config.toolTipLineHeight - config.fontSize) / 2 + config.toolTipLineHeight * index +
config.toolTipPadding + 1;
if (isOverRightBorder) {
startX = offset.x - toolTipWidth - arrowWidth + 2 * config.toolTipPadding;
}
context.fillRect(startX, startY, legendWidth, config.fontSize);
context.closePath();
}
});
// draw text list
textList.forEach(function(item, index) {
var startX = offset.x + arrowWidth + 2 * config.toolTipPadding + legendWidth + legendMarginRight;
if (isOverRightBorder) {
startX = offset.x - toolTipWidth - arrowWidth + 2 * config.toolTipPadding + +legendWidth + legendMarginRight;
}
var startY = offset.y + (config.toolTipLineHeight - config.fontSize) / 2 + config.toolTipLineHeight * index +
config.toolTipPadding;
context.beginPath();
context.setFontSize(config.fontSize);
context.setFillStyle(toolTipOption.fontColor);
context.fillText(item.text, startX, startY + config.fontSize);
context.closePath();
context.stroke();
});
}
function drawYAxisTitle(title, opts, config, context) {
var startX = config.xAxisHeight + (opts.height - config.xAxisHeight - measureText(title)) / 2;
context.save();
context.beginPath();
context.setFontSize(config.fontSize);
context.setFillStyle(opts.yAxis.titleFontColor || '#333333');
context.translate(0, opts.height);
context.rotate(-90 * Math.PI / 180);
context.fillText(title, startX, config.padding + 0.5 * config.fontSize);
context.closePath();
context.stroke();
context.restore();
}
function drawColumnDataPoints(series, opts, config, context) {
var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
var columnOption = opts.extra.column || {
type: {},
meter: {}
};
columnOption.type = columnOption.type == undefined ? 'group' : columnOption.type;
columnOption.meter = columnOption.meter || {}
columnOption.meter.border = columnOption.meter.border == undefined ? 4 : columnOption.meter.border;
columnOption.meter.fillColor = columnOption.meter.fillColor == undefined ? '#FFFFFF' : columnOption.meter.fillColor;
var _calYAxisData = calYAxisData(series, opts, config),
ranges = _calYAxisData.ranges;
var _getXAxisPoints = getXAxisPoints(opts.categories, opts, config),
xAxisPoints = _getXAxisPoints.xAxisPoints,
eachSpacing = _getXAxisPoints.eachSpacing;
var minRange = ranges.pop();
var maxRange = ranges.shift();
var calPoints = [];
context.save();
if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) {
context.translate(opts._scrollDistance_, 0);
}
if (opts.tooltip && opts.tooltip.textList && opts.tooltip.textList.length && process === 1) {
drawToolTipSplitArea(opts.tooltip.offset.x, opts, config, context, eachSpacing);
}
series.forEach(function(eachSeries, seriesIndex) {
var data = eachSeries.data;
switch (columnOption.type) {
case 'group':
var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
var tooltipPoints = getStackDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config,
seriesIndex, series, process);
calPoints.push(tooltipPoints);
points = fixColumeData(points, eachSpacing, series.length, seriesIndex, config, opts);
points.forEach(function(item, index) {
if (item !== null) {
context.beginPath();
context.setFillStyle(item.color || eachSeries.color);
var startX = item.x - item.width / 2 + 1;
var height = opts.height - item.y - config.padding - config.xAxisHeight - config.legendHeight;
context.moveTo(startX, item.y);
context.fillRect(startX, item.y, item.width - 2, height);
context.closePath();
context.fill();
}
});
break;
case 'stack':
// 绘制堆叠数据图
var points = getStackDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, seriesIndex,
series, process);
calPoints.push(points);
points = fixColumeStackData(points, eachSpacing, series.length, seriesIndex, config, opts, series);
points.forEach(function(item, index) {
if (item !== null) {
context.beginPath();
context.setFillStyle(item.color || eachSeries.color);
var startX = item.x - item.width / 2 + 1;
var height = opts.height - item.y - config.padding - config.xAxisHeight - config.legendHeight;
var height0 = opts.height - item.y0 - config.padding - config.xAxisHeight - config.legendHeight;
if (seriesIndex > 0) {
height -= height0;
}
context.moveTo(startX, item.y);
context.fillRect(startX, item.y, item.width - 2, height);
context.closePath();
context.fill();
}
});
break;
case 'meter':
// 绘制温度计数据图
var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
calPoints.push(points);
points = fixColumeMeterData(points, eachSpacing, series.length, seriesIndex, config, opts, columnOption.meter.border);
if (seriesIndex == 0) {
points.forEach(function(item, index) {
if (item !== null) {
//画背景颜色
context.beginPath();
context.setFillStyle(columnOption.meter.fillColor);
var startX = item.x - item.width / 2 ;
var height = opts.height - item.y - config.padding - config.xAxisHeight - config.legendHeight;
context.moveTo(startX, item.y);
context.fillRect(startX, item.y, item.width, height);
context.closePath();
context.fill();
//画边框线
if(columnOption.meter.border>0){
context.beginPath();
context.setStrokeStyle(eachSeries.color);
context.setLineWidth(columnOption.meter.border * opts.pixelRatio);
context.moveTo(startX + columnOption.meter.border*0.5, item.y + height);
context.lineTo(startX + columnOption.meter.border*0.5, item.y + columnOption.meter.border*0.5);
context.lineTo(startX + item.width - columnOption.meter.border*0.5, item.y + columnOption.meter.border*0.5);
context.lineTo(startX + item.width - columnOption.meter.border*0.5, item.y + height);
context.stroke();
}
}
});
} else {
points.forEach(function(item, index) {
if (item !== null) {
context.beginPath();
context.setFillStyle(item.color || eachSeries.color);
var startX = item.x - item.width / 2;
var height = opts.height - item.y - config.padding - config.xAxisHeight - config.legendHeight;
context.moveTo(startX, item.y);
context.fillRect(startX, item.y, item.width, height);
context.closePath();
context.fill();
}
});
}
break;
}
});
if (opts.dataLabel !== false && process === 1) {
series.forEach(function(eachSeries, seriesIndex) {
var data = eachSeries.data;
switch (columnOption.type) {
case 'group':
var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
points = fixColumeData(points, eachSpacing, series.length, seriesIndex, config, opts);
drawPointText(points, eachSeries, config, context);
break;
case 'stack':
var points = getStackDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, seriesIndex,
series, process);
drawPointText(points, eachSeries, config, context);
break;
case 'meter':
var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
drawPointText(points, eachSeries, config, context);
break;
}
});
}
context.restore();
return {
xAxisPoints: xAxisPoints,
calPoints: calPoints,
eachSpacing: eachSpacing
};
}
function drawCandleDataPoints(series, seriesMA, opts, config, context) {
var process = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 1;
var candleOption = opts.extra.candle || {
color: {},
average: {}
};
candleOption.color.upLine = candleOption.color.upLine ? candleOption.color.upLine : '#f04864';
candleOption.color.upFill = candleOption.color.upFill ? candleOption.color.upFill : '#f04864';
candleOption.color.downLine = candleOption.color.downLine ? candleOption.color.downLine : '#2fc25b';
candleOption.color.downFill = candleOption.color.downFill ? candleOption.color.downFill : '#2fc25b';
candleOption.average.show = candleOption.average.show === true ? true : false;
candleOption.average.name = candleOption.average.name ? candleOption.average.name : [];
candleOption.average.day = candleOption.average.day ? candleOption.average.day : [];
candleOption.average.color = candleOption.average.color ? candleOption.average.color : ['#1890ff', '#2fc25b',
'#facc14', '#f04864', '#8543e0', '#90ed7d'
];
opts.extra.candle = candleOption;
var _calYAxisData5 = calYAxisData(series, opts, config),
ranges = _calYAxisData5.ranges;
var _getXAxisPoints5 = getXAxisPoints(opts.categories, opts, config),
xAxisPoints = _getXAxisPoints5.xAxisPoints,
eachSpacing = _getXAxisPoints5.eachSpacing;
var minRange = ranges.pop();
var maxRange = ranges.shift();
var calPoints = [];
context.save();
if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) {
context.translate(opts._scrollDistance_, 0);
}
//画均线
if (candleOption.average.show) {
seriesMA.forEach(function(eachSeries, seriesIndex) {
var data = eachSeries.data;
var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
//calPoints.push(points);
var splitPointList = splitPoints(points);
splitPointList.forEach(function(points, index) {
context.beginPath();
context.setStrokeStyle(eachSeries.color);
context.setLineWidth(1);
if (points.length === 1) {
context.moveTo(points[0].x, points[0].y);
context.arc(points[0].x, points[0].y, 1, 0, 2 * Math.PI);
} else {
context.moveTo(points[0].x, points[0].y);
points.forEach(function(item, index) {
if (index > 0) {
var ctrlPoint = createCurveControlPoints(points, index - 1);
context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y, item.x, item
.y);
}
});
context.moveTo(points[0].x, points[0].y);
}
context.closePath();
context.stroke();
});
});
}
//画K线
series.forEach(function(eachSeries, seriesIndex) {
var data = eachSeries.data;
var points = getCandleDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
calPoints.push(points);
var splitPointList = splitPoints(points);
splitPointList = splitPointList[0];
splitPointList.forEach(function(points, index) {
context.beginPath();
//如果上涨
if (data[index][1] - data[index][0] > 0) {
context.setStrokeStyle(candleOption.color.upLine);
context.setFillStyle(candleOption.color.upFill);
context.setLineWidth(1 * opts.pixelRatio);
context.moveTo(points[3].x, points[3].y); //顶点
context.lineTo(points[1].x, points[1].y); //收盘中间点
context.lineTo(points[1].x - eachSpacing / 4, points[1].y); //收盘左侧点
context.lineTo(points[0].x - eachSpacing / 4, points[0].y); //开盘左侧点
context.lineTo(points[0].x, points[0].y); //开盘中间点
context.lineTo(points[2].x, points[2].y); //底点
context.lineTo(points[0].x, points[0].y); //开盘中间点
context.lineTo(points[0].x + eachSpacing / 4, points[0].y); //开盘右侧点
context.lineTo(points[1].x + eachSpacing / 4, points[1].y); //收盘右侧点
context.lineTo(points[1].x, points[1].y); //收盘中间点
context.moveTo(points[3].x, points[3].y); //顶点
} else {
context.setStrokeStyle(candleOption.color.downLine);
context.setFillStyle(candleOption.color.downFill);
context.setLineWidth(1 * opts.pixelRatio);
context.moveTo(points[3].x, points[3].y); //顶点
context.lineTo(points[0].x, points[0].y); //开盘中间点
context.lineTo(points[0].x - eachSpacing / 4, points[0].y); //开盘左侧点
context.lineTo(points[1].x - eachSpacing / 4, points[1].y); //收盘左侧点
context.lineTo(points[1].x, points[1].y); //收盘中间点
context.lineTo(points[2].x, points[2].y); //底点
context.lineTo(points[1].x, points[1].y); //收盘中间点
context.lineTo(points[1].x + eachSpacing / 4, points[1].y); //收盘右侧点
context.lineTo(points[0].x + eachSpacing / 4, points[0].y); //开盘右侧点
context.lineTo(points[0].x, points[0].y); //开盘中间点
context.moveTo(points[3].x, points[3].y); //顶点
}
context.closePath();
context.fill();
context.stroke();
});
});
context.restore();
return {
xAxisPoints: xAxisPoints,
calPoints: calPoints,
eachSpacing: eachSpacing
};
}
function drawAreaDataPoints(series, opts, config, context) {
var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
var areaOption = opts.extra.area || {
type: 'straight',
opacity: 0.5,
addLine: false,
width: 2
};
areaOption.type = areaOption.type ? areaOption.type : 'straight';
areaOption.opacity = areaOption.opacity ? areaOption.opacity : 0.2;
areaOption.addLine = areaOption.addLine == true ? true : false;
areaOption.width = areaOption.width ? areaOption.width : 2;
var _calYAxisData2 = calYAxisData(series, opts, config),
ranges = _calYAxisData2.ranges;
var _getXAxisPoints2 = getXAxisPoints(opts.categories, opts, config),
xAxisPoints = _getXAxisPoints2.xAxisPoints,
eachSpacing = _getXAxisPoints2.eachSpacing;
var minRange = ranges.pop();
var maxRange = ranges.shift();
var endY = opts.height - config.padding - config.xAxisHeight - config.legendHeight;
var calPoints = [];
context.save();
if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) {
context.translate(opts._scrollDistance_, 0);
}
if (opts.tooltip && opts.tooltip.textList && opts.tooltip.textList.length && process === 1) {
drawToolTipSplitLine(opts.tooltip.offset.x, opts, config, context);
}
series.forEach(function(eachSeries, seriesIndex) {
let data = eachSeries.data;
let points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
calPoints.push(points);
let splitPointList = splitPoints(points);
for (let i = 0; i < splitPointList.length; i++) {
let points = splitPointList[i];
// 绘制区域数
context.beginPath();
context.setStrokeStyle(hexToRgb(eachSeries.color, areaOption.opacity));
context.setFillStyle(hexToRgb(eachSeries.color, areaOption.opacity));
context.setLineWidth(areaOption.width * opts.pixelRatio);
if (points.length > 1) {
let firstPoint = points[0];
let lastPoint = points[points.length - 1];
context.moveTo(firstPoint.x, firstPoint.y);
if (areaOption.type === 'curve') {
points.forEach(function(item, index) {
if (index > 0) {
let ctrlPoint = createCurveControlPoints(points, index - 1);
context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y, item.x, item
.y);
}
});
} else {
points.forEach(function(item, index) {
if (index > 0) {
context.lineTo(item.x, item.y);
}
});
}
context.lineTo(lastPoint.x, endY);
context.lineTo(firstPoint.x, endY);
context.lineTo(firstPoint.x, firstPoint.y);
} else {
let item = points[0];
context.moveTo(item.x - eachSpacing / 2, item.y);
context.lineTo(item.x + eachSpacing / 2, item.y);
context.lineTo(item.x + eachSpacing / 2, endY);
context.lineTo(item.x - eachSpacing / 2, endY);
context.moveTo(item.x - eachSpacing / 2, item.y);
}
context.closePath();
context.fill();
//画连线
if (areaOption.addLine) {
context.beginPath();
context.setStrokeStyle(eachSeries.color);
context.setLineWidth(areaOption.width * opts.pixelRatio);
if (points.length === 1) {
context.moveTo(points[0].x, points[0].y);
context.arc(points[0].x, points[0].y, 1, 0, 2 * Math.PI);
} else {
context.moveTo(points[0].x, points[0].y);
if (areaOption.type === 'curve') {
points.forEach(function(item, index) {
if (index > 0) {
let ctrlPoint = createCurveControlPoints(points, index - 1);
context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y, item.x,
item.y);
}
});
} else {
points.forEach(function(item, index) {
if (index > 0) {
context.lineTo(item.x, item.y);
}
});
}
context.moveTo(points[0].x, points[0].y);
}
context.closePath();
context.stroke();
}
}
//画点
if (opts.dataPointShape !== false) {
var shape = config.dataPointShape[seriesIndex % config.dataPointShape.length];
drawPointShape(points, eachSeries.color, shape, context, opts);
}
});
if (opts.dataLabel !== false && process === 1) {
series.forEach(function(eachSeries, seriesIndex) {
var data = eachSeries.data;
var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
drawPointText(points, eachSeries, config, context);
});
}
context.restore();
return {
xAxisPoints: xAxisPoints,
calPoints: calPoints,
eachSpacing: eachSpacing
};
}
function drawLineDataPoints(series, opts, config, context) {
var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
var lineOption = opts.extra.line || {
type: 'straight',
width: 2
};
lineOption.type = lineOption.type ? lineOption.type : 'straight';
lineOption.width = lineOption.width ? lineOption.width : 2;
var _calYAxisData3 = calYAxisData(series, opts, config),
ranges = _calYAxisData3.ranges;
var _getXAxisPoints3 = getXAxisPoints(opts.categories, opts, config),
xAxisPoints = _getXAxisPoints3.xAxisPoints,
eachSpacing = _getXAxisPoints3.eachSpacing;
var minRange = ranges.pop();
var maxRange = ranges.shift();
var calPoints = [];
context.save();
if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) {
context.translate(opts._scrollDistance_, 0);
}
if (opts.tooltip && opts.tooltip.textList && opts.tooltip.textList.length && process === 1) {
drawToolTipSplitLine(opts.tooltip.offset.x, opts, config, context);
}
series.forEach(function(eachSeries, seriesIndex) {
var data = eachSeries.data;
var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
calPoints.push(points);
var splitPointList = splitPoints(points);
splitPointList.forEach(function(points, index) {
context.beginPath();
context.setStrokeStyle(eachSeries.color);
context.setLineWidth(lineOption.width * opts.pixelRatio);
if (points.length === 1) {
context.moveTo(points[0].x, points[0].y);
context.arc(points[0].x, points[0].y, 1, 0, 2 * Math.PI);
} else {
context.moveTo(points[0].x, points[0].y);
if (lineOption.type === 'curve') {
points.forEach(function(item, index) {
if (index > 0) {
var ctrlPoint = createCurveControlPoints(points, index - 1);
context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y, item.x, item
.y);
}
});
} else {
points.forEach(function(item, index) {
if (index > 0) {
context.lineTo(item.x, item.y);
}
});
}
context.moveTo(points[0].x, points[0].y);
}
context.closePath();
context.stroke();
});
if (opts.dataPointShape !== false) {
var shape = config.dataPointShape[seriesIndex % config.dataPointShape.length];
drawPointShape(points, eachSeries.color, shape, context, opts);
}
});
if (opts.dataLabel !== false && process === 1) {
series.forEach(function(eachSeries, seriesIndex) {
var data = eachSeries.data;
var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
drawPointText(points, eachSeries, config, context);
});
}
context.restore();
return {
xAxisPoints: xAxisPoints,
calPoints: calPoints,
eachSpacing: eachSpacing
};
}
function drawMixDataPoints(series, opts, config, context) {
var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
var _calYAxisData6 = calYAxisData(series, opts, config),
ranges = _calYAxisData6.ranges;
var _getXAxisPoints6 = getXAxisPoints(opts.categories, opts, config),
xAxisPoints = _getXAxisPoints6.xAxisPoints,
eachSpacing = _getXAxisPoints6.eachSpacing;
var minRange = ranges.pop();
var maxRange = ranges.shift();
var endY = opts.height - config.padding - config.xAxisHeight - config.legendHeight;
var calPoints = [];
var columnIndex = 0;
var columnLength = 0;
series.forEach(function(eachSeries, seriesIndex) {
if (eachSeries.type == 'column') {
columnLength += 1;
}
});
context.save();
if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) {
context.translate(opts._scrollDistance_, 0);
}
if (opts.tooltip && opts.tooltip.textList && opts.tooltip.textList.length && process === 1) {
drawToolTipSplitLine(opts.tooltip.offset.x, opts, config, context);
}
series.forEach(function(eachSeries, seriesIndex) {
var data = eachSeries.data;
var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
calPoints.push(points);
// 绘制柱状数据图
if (eachSeries.type == 'column') {
points = fixColumeData(points, eachSpacing, columnLength, columnIndex, config, opts);
points.forEach(function(item, index) {
if (item !== null) {
context.beginPath();
context.setFillStyle(item.color || eachSeries.color);
var startX = item.x - item.width / 2 + 1;
var height = opts.height - item.y - config.padding - config.xAxisHeight - config.legendHeight;
context.moveTo(startX, item.y);
context.rect(startX, item.y, item.width - 2, height);
context.closePath();
context.fill();
}
});
columnIndex += 1;
}
//绘制区域图数据
if (eachSeries.type == 'area') {
let splitPointList = splitPoints(points);
for (let i = 0; i < splitPointList.length; i++) {
let points = splitPointList[i];
// 绘制区域数据
context.beginPath();
context.setStrokeStyle(eachSeries.color);
context.setFillStyle(eachSeries.color);
context.setGlobalAlpha(0.2);
context.setLineWidth(2 * opts.pixelRatio);
if (points.length > 1) {
var firstPoint = points[0];
let lastPoint = points[points.length - 1];
context.moveTo(firstPoint.x, firstPoint.y);
if (eachSeries.style === 'curve') {
points.forEach(function(item, index) {
if (index > 0) {
var ctrlPoint = createCurveControlPoints(points, index - 1);
context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y, item.x,
item.y);
}
});
} else {
points.forEach(function(item, index) {
if (index > 0) {
context.lineTo(item.x, item.y);
}
});
}
context.lineTo(lastPoint.x, endY);
context.lineTo(firstPoint.x, endY);
context.lineTo(firstPoint.x, firstPoint.y);
} else {
let item = points[0];
context.moveTo(item.x - eachSpacing / 2, item.y);
context.lineTo(item.x + eachSpacing / 2, item.y);
context.lineTo(item.x + eachSpacing / 2, endY);
context.lineTo(item.x - eachSpacing / 2, endY);
context.moveTo(item.x - eachSpacing / 2, item.y);
}
context.closePath();
context.fill();
context.setGlobalAlpha(1);
}
}
// 绘制折线数据图
if (eachSeries.type == 'line') {
var splitPointList = splitPoints(points);
splitPointList.forEach(function(points, index) {
context.beginPath();
context.setStrokeStyle(eachSeries.color);
context.setLineWidth(2 * opts.pixelRatio);
if (points.length === 1) {
context.moveTo(points[0].x, points[0].y);
context.arc(points[0].x, points[0].y, 1, 0, 2 * Math.PI);
} else {
context.moveTo(points[0].x, points[0].y);
if (eachSeries.style == 'curve') {
points.forEach(function(item, index) {
if (index > 0) {
var ctrlPoint = createCurveControlPoints(points, index - 1);
context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y, item.x,
item.y);
}
});
} else {
points.forEach(function(item, index) {
if (index > 0) {
context.lineTo(item.x, item.y);
}
});
}
context.moveTo(points[0].x, points[0].y);
}
context.closePath();
context.stroke();
});
}
// 绘制点数据图
if (eachSeries.type == 'point') {
points.forEach(function(pointsa, index) {
if(pointsa){
context.beginPath();
context.setFillStyle(eachSeries.color);
context.setStrokeStyle('#FFFFFF');
context.setLineWidth(1 * opts.pixelRatio);
context.moveTo(pointsa.x + 3.5 * opts.pixelRatio, pointsa.y);
context.arc(pointsa.x, pointsa.y, 4* opts.pixelRatio, 0, 2 * Math.PI);
context.closePath();
context.fill();
context.stroke();
}
});
}
if (eachSeries.addPoint == true && eachSeries.type !== 'column') {
var shape = config.dataPointShape[seriesIndex % config.dataPointShape.length];
drawPointShape(points, eachSeries.color, shape, context, opts);
}
});
if (opts.dataLabel !== false && process === 1) {
var columnIndex = 0;
series.forEach(function(eachSeries, seriesIndex) {
var data = eachSeries.data;
var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
if (eachSeries.type !== 'column') {
drawPointText(points, eachSeries, config, context);
} else {
points = fixColumeData(points, eachSpacing, columnLength, columnIndex, config, opts);
drawPointText(points, eachSeries, config, context);
columnIndex += 1;
}
});
}
context.restore();
return {
xAxisPoints: xAxisPoints,
calPoints: calPoints,
eachSpacing: eachSpacing
};
}
function drawToolTipBridge(opts, config, context, process, eachSpacing, xAxisPoints) {
var toolTipOption = opts.extra.tooltip || {};
if (toolTipOption.horizentalLine && opts.tooltip && process === 1 && (opts.type == 'line' || opts.type == 'area' ||
opts.type == 'column' || opts.type == 'candle' || opts.type == 'mix')) {
drawToolTipHorizentalLine(opts, config, context, eachSpacing, xAxisPoints)
}
context.save();
if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) {
context.translate(opts._scrollDistance_, 0);
}
if (opts.tooltip && opts.tooltip.textList && opts.tooltip.textList.length && process === 1) {
drawToolTip(opts.tooltip.textList, opts.tooltip.offset, opts, config, context, eachSpacing, xAxisPoints);
}
context.restore();
}
function drawXAxis(categories, opts, config, context) {
var _getXAxisPoints4 = getXAxisPoints(categories, opts, config),
xAxisPoints = _getXAxisPoints4.xAxisPoints,
startX = _getXAxisPoints4.startX,
endX = _getXAxisPoints4.endX,
eachSpacing = _getXAxisPoints4.eachSpacing;
var startY = opts.height - config.padding - config.xAxisHeight - config.legendHeight;
var endY = config.padding;
//绘制滚动条
if (opts.enableScroll && opts.xAxis.scrollShow) {
var scrollY = opts.height - config.padding - config.legendHeight + 6 * opts.pixelRatio;
var scrollScreenWidth = endX - startX;
var scrollTotalWidth = eachSpacing * (xAxisPoints.length - 1);
var scrollWidth = scrollScreenWidth * scrollScreenWidth / scrollTotalWidth;
var scrollLeft = 0;
if (opts._scrollDistance_) {
scrollLeft = -opts._scrollDistance_ * (scrollScreenWidth) / scrollTotalWidth;
}
context.beginPath();
context.setLineCap('round');
context.setLineWidth(6 * opts.pixelRatio);
context.setStrokeStyle(opts.xAxis.scrollBackgroundColor || "#EFEBEF");
context.moveTo(startX, scrollY);
context.lineTo(endX, scrollY);
context.stroke();
context.closePath();
context.beginPath();
context.setLineCap('round');
context.setLineWidth(6 * opts.pixelRatio);
context.setStrokeStyle(opts.xAxis.scrollColor || "#A6A6A6");
context.moveTo(startX + scrollLeft, scrollY);
context.lineTo(startX + scrollLeft + scrollWidth, scrollY);
context.stroke();
context.setLineCap('butt');
context.closePath();
}
context.save();
if (opts._scrollDistance_ && opts._scrollDistance_ !== 0) {
context.translate(opts._scrollDistance_, 0);
}
context.beginPath();
context.setStrokeStyle(opts.xAxis.gridColor || "#cccccc");
context.setLineCap('butt');
context.setLineWidth(1 * opts.pixelRatio);
if (opts.xAxis.gridType == 'dash') {
context.setLineDash([opts.xAxis.dashLength, opts.xAxis.dashLength]);
}
if (opts.xAxis.disableGrid !== true) {
if (opts.xAxis.type === 'calibration') {
xAxisPoints.forEach(function(item, index) {
if (index > 0) {
context.moveTo(item - eachSpacing / 2, startY);
context.lineTo(item - eachSpacing / 2, startY + 4 * opts.pixelRatio);
}
});
} else {
opts.xAxis.gridEval = opts.xAxis.gridEval || 1;
xAxisPoints.forEach(function(item, index) {
if(index % opts.xAxis.gridEval == 0){
context.moveTo(item, startY);
context.lineTo(item, endY);
}
});
}
}
context.closePath();
context.stroke();
context.setLineDash([]);
//不绘制X轴
if (opts.xAxis.disabled !== true) {
// 对X轴列表做抽稀处理
let validWidth = opts.width - 2 * config.padding - config.yAxisWidth - config.yAxisTitleWidth;
//默认全部显示X轴标签
let maxXAxisListLength = categories.length;
//如果设置了X轴单屏数量
if (opts.xAxis.labelCount) {
//如果设置X轴密度
if (opts.xAxis.itemCount) {
maxXAxisListLength = Math.ceil(categories.length / opts.xAxis.itemCount * opts.xAxis.labelCount);
} else {
maxXAxisListLength = opts.xAxis.labelCount;
}
maxXAxisListLength -= 1;
}
let ratio = Math.ceil(categories.length / maxXAxisListLength);
let newCategories = [];
let cgLength = categories.length;
for (let i = 0; i < cgLength; i++) {
if (i % ratio !== 0) {
newCategories.push("");
} else {
newCategories.push(categories[i]);
}
}
newCategories[cgLength - 1] = categories[cgLength - 1];
/*
categories = categories.map(function (item, index) {
return index % ratio !== 0 ? '' : item;
});*/
var xAxisFontSize = opts.xAxis.fontSize || config.fontSize;
if (config._xAxisTextAngle_ === 0) {
newCategories.forEach(function(item, index) {
var offset = eachSpacing / 2 - measureText(item,xAxisFontSize) / 2;
context.beginPath();
context.setFontSize(xAxisFontSize);
context.setFillStyle(opts.xAxis.fontColor || '#666666');
context.fillText(item, xAxisPoints[index] + offset, startY + xAxisFontSize + 5);
context.closePath();
context.stroke();
});
} else {
newCategories.forEach(function(item, index) {
context.save();
context.beginPath();
context.setFontSize(xAxisFontSize);
context.setFillStyle(opts.xAxis.fontColor || '#666666');
var textWidth = measureText(item);
var offset = eachSpacing / 2 - textWidth;
var _calRotateTranslate = calRotateTranslate(xAxisPoints[index] + eachSpacing / 2, startY + xAxisFontSize / 2 + 5, opts.height),
transX = _calRotateTranslate.transX,
transY = _calRotateTranslate.transY;
context.rotate(-1 * config._xAxisTextAngle_);
context.translate(transX, transY);
context.fillText(item, xAxisPoints[index] + offset, startY + xAxisFontSize + 5);
context.closePath();
context.stroke();
context.restore();
});
}
}
context.restore();
}
function drawYAxisGrid(categories, opts, config, context) {
if (opts.yAxis.disableGrid === true) {
return;
}
var spacingValid = opts.height - 2 * config.padding - config.xAxisHeight - config.legendHeight;
var eachSpacing = Math.floor(spacingValid / config.yAxisSplit);
var yAxisTotalWidth = config.yAxisWidth + config.yAxisTitleWidth;
var startX = config.padding + yAxisTotalWidth;
var _getXAxisPoints4 = getXAxisPoints(categories, opts, config),
xAxisPoints = _getXAxisPoints4.xAxisPoints,
xAxiseachSpacing = _getXAxisPoints4.eachSpacing;
var TotalWidth = xAxiseachSpacing * (xAxisPoints.length - 1);
var endX = startX + TotalWidth;
var points = [];
for (var i = 0; i < config.yAxisSplit; i++) {
points.push(config.padding + eachSpacing * i);
}
points.push(config.padding + eachSpacing * config.yAxisSplit + 2);
context.save();
if (opts._scrollDistance_ && opts._scrollDistance_ !== 0) {
context.translate(opts._scrollDistance_, 0);
}
if (opts.yAxis.gridType == 'dash') {
context.setLineDash([opts.yAxis.dashLength, opts.yAxis.dashLength]);
}
context.beginPath();
context.setStrokeStyle(opts.yAxis.gridColor || "#cccccc");
context.setLineWidth(1 * opts.pixelRatio);
points.forEach(function(item, index) {
context.moveTo(startX, item);
context.lineTo(endX, item);
});
context.closePath();
context.stroke();
context.setLineDash([]);
context.restore();
}
function drawYAxis(series, opts, config, context) {
if (opts.yAxis.disabled === true) {
return;
}
var _calYAxisData4 = calYAxisData(series, opts, config),
rangesFormat = _calYAxisData4.rangesFormat;
var yAxisTotalWidth = config.yAxisWidth + config.yAxisTitleWidth;
var spacingValid = opts.height - 2 * config.padding - config.xAxisHeight - config.legendHeight;
var eachSpacing = Math.floor(spacingValid / config.yAxisSplit);
var startX = config.padding + yAxisTotalWidth;
var endX = opts.width - config.padding;
var endY = opts.height - config.padding - config.xAxisHeight - config.legendHeight + config.xAxisTextPadding;
// set YAxis background
context.beginPath();
context.setFillStyle(opts.background || '#ffffff');
if (opts._scrollDistance_ < 0) {
context.fillRect(0, 0, startX, endY + config.xAxisHeight);
}
context.fillRect(endX, 0, opts.width, endY + config.xAxisHeight);
context.closePath();
context.stroke();
var points = [];
for (var i = 0; i <= config.yAxisSplit; i++) {
points.push(config.padding + eachSpacing * i);
}
var yAxisFontSize = opts.yAxis.fontSize || config.fontSize;
rangesFormat.forEach(function(item, index) {
var pos = points[index] ? points[index] : endY;
context.beginPath();
context.setFontSize(yAxisFontSize);
context.setFillStyle(opts.yAxis.fontColor || '#666666');
context.fillText(item, config.padding + config.yAxisTitleWidth, pos + yAxisFontSize / 2);
context.closePath();
context.stroke();
});
if (opts.yAxis.title) {
drawYAxisTitle(opts.yAxis.title, opts, config, context);
}
}
function drawLegend(series, opts, config, context) {
if (opts.legend === false) {
return;
}
// each legend shape width 15px
// the spacing between shape and text in each legend is the `padding`
// each legend spacing is the `padding`
// legend margin top `config.padding`
var _calLegendData = calLegendData(series, opts, config),
legendList = _calLegendData.legendList;
var padding = 5 * opts.pixelRatio;
var marginTop = 10 * opts.pixelRatio;
var shapeWidth = 15 * opts.pixelRatio;
legendList.forEach(function(itemList, listIndex) {
var width = 0;
for (let i = 0; i < itemList.length; i++) {
let item = itemList[i];
item.name = item.name || 'undefined';
width += 3 * padding + measureText(item.name) + shapeWidth;
}
var startX = (opts.width - width) / 2 + padding;
var startY = opts.height - config.padding - config.legendHeight + listIndex * (config.fontSize + marginTop) +
padding + marginTop;
context.setFontSize(config.fontSize);
for (let i = 0; i < itemList.length; i++) {
let item = itemList[i];
switch (opts.type) {
case 'line':
context.beginPath();
context.setLineWidth(1 * opts.pixelRatio);
context.setStrokeStyle(item.color);
context.setFillStyle(item.color);
context.moveTo(startX + 7.5 * opts.pixelRatio, startY + 5 * opts.pixelRatio);
context.arc(startX + 7.5 * opts.pixelRatio, startY + 5 * opts.pixelRatio, 6 * opts.pixelRatio, 0, 2 * Math.PI);
context.closePath();
context.fill();
context.stroke();
break;
case 'pie':
context.beginPath();
context.setLineWidth(1 * opts.pixelRatio);
context.setStrokeStyle(item.color);
context.setFillStyle(item.color);
context.moveTo(startX + 7.5 * opts.pixelRatio, startY + 5 * opts.pixelRatio);
context.arc(startX + 7.5 * opts.pixelRatio, startY + 5 * opts.pixelRatio, 6 * opts.pixelRatio, 0, 2 * Math.PI);
context.closePath();
context.fill();
context.stroke();
break;
case 'ring':
case 'rose':
context.beginPath();
context.setLineWidth(1 * opts.pixelRatio);
context.setStrokeStyle(item.color);
context.setFillStyle(item.color);
context.moveTo(startX + 7.5 * opts.pixelRatio, startY + 5 * opts.pixelRatio);
context.arc(startX + 7.5 * opts.pixelRatio, startY + 5 * opts.pixelRatio, 6 * opts.pixelRatio, 0, 2 * Math.PI);
context.closePath();
context.fill();
context.stroke();
break;
//圆弧进度图不显示图例
case 'gauge':
break;
case 'arcbar':
break;
default:
context.beginPath();
context.setLineWidth(1 * opts.pixelRatio);
context.setStrokeStyle(item.color);
context.setFillStyle(item.color);
context.moveTo(startX, startY);
context.fillRect(startX, startY, 15 * opts.pixelRatio, 10 * opts.pixelRatio);
context.closePath();
context.fill();
context.stroke();
}
startX += padding + shapeWidth;
context.beginPath();
context.setFontSize(config.fontSize);
context.setFillStyle(opts.extra.legendTextColor || '#333333');
context.fillText(item.name, startX, startY + 6 * opts.pixelRatio + 3 * opts.pixelRatio);
context.closePath();
context.stroke();
startX += measureText(item.name) + 2 * padding;
}
});
}
function drawPieDataPoints(series, opts, config, context) {
var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
var pieOption = opts.extra.pie || {};
var centerPosition = {
x: opts.width / 2,
y: (opts.height - config.legendHeight) / 2
};
var radius = Math.min(centerPosition.x - config.pieChartLinePadding - config.pieChartTextPadding - config._pieTextMaxLength_,
centerPosition.y - config.pieChartLinePadding - config.pieChartTextPadding);
if (opts.dataLabel) {
radius -= 10;
} else {
radius -= 2 * config.padding;
}
series = getPieDataPoints(series, radius, process);
var activeRadius = config.pieChartLinePadding / 2;
series = series.map(function(eachSeries) {
eachSeries._start_ += (pieOption.offsetAngle || 0) * Math.PI / 180;
return eachSeries;
});
series.forEach(function(eachSeries, seriesIndex) {
if (opts.tooltip) {
if (opts.tooltip.index == seriesIndex) {
context.beginPath();
context.setFillStyle(hexToRgb(eachSeries.color, opts.extra.pie.activeOpacity || 0.5));
context.moveTo(centerPosition.x, centerPosition.y);
context.arc(centerPosition.x, centerPosition.y, eachSeries._radius_+activeRadius, eachSeries._start_, eachSeries._start_ + 2 *
eachSeries._proportion_ * Math.PI);
context.closePath();
context.fill();
}
}
context.beginPath();
context.setLineWidth(2 * opts.pixelRatio);
context.lineJoin = "round";
context.setStrokeStyle('#ffffff');
context.setFillStyle(eachSeries.color);
context.moveTo(centerPosition.x, centerPosition.y);
context.arc(centerPosition.x, centerPosition.y, eachSeries._radius_, eachSeries._start_, eachSeries._start_ + 2 * eachSeries._proportion_ *
Math.PI);
context.closePath();
context.fill();
if (opts.disablePieStroke !== true) {
context.stroke();
}
});
if (opts.type === 'ring') {
var innerPieWidth = radius * 0.6;
if (typeof opts.extra.pie.ringWidth === 'number' && opts.extra.pie.ringWidth > 0) {
innerPieWidth = Math.max(0, radius - opts.extra.pie.ringWidth);
}
context.beginPath();
context.setFillStyle(opts.background || '#ffffff');
context.moveTo(centerPosition.x, centerPosition.y);
context.arc(centerPosition.x, centerPosition.y, innerPieWidth, 0, 2 * Math.PI);
context.closePath();
context.fill();
}
if (opts.dataLabel !== false && process === 1) {
var valid = false;
for (var i = 0, len = series.length; i < len; i++) {
if (series[i].data > 0) {
valid = true;
break;
}
}
if (valid) {
drawPieText(series, opts, config, context, radius, centerPosition);
}
}
if (process === 1 && opts.type === 'ring') {
drawRingTitle(opts, config, context);
}
return {
center: centerPosition,
radius: radius,
series: series
};
}
function drawRoseDataPoints(series, opts, config, context) {
var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
var roseOption = opts.extra.rose || {};
roseOption.type = roseOption.type || 'area';
var centerPosition = {
x: opts.width / 2,
y: (opts.height - config.legendHeight) / 2
};
var radius = Math.min(centerPosition.x - config.pieChartLinePadding - config.pieChartTextPadding - config._pieTextMaxLength_,
centerPosition.y - config.pieChartLinePadding - config.pieChartTextPadding);
if (opts.dataLabel) {
radius -= 10;
} else {
radius -= 2 * config.padding;
}
var minRadius = roseOption.minRadius || radius*0.5;
series = getRoseDataPoints(series, roseOption.type, minRadius, radius, process);
var activeRadius = config.pieChartLinePadding / 2;
series = series.map(function(eachSeries) {
eachSeries._start_ += (roseOption.offsetAngle || 0) * Math.PI / 180;
return eachSeries;
});
series.forEach(function(eachSeries, seriesIndex) {
if (opts.tooltip) {
if (opts.tooltip.index == seriesIndex) {
context.beginPath();
context.setFillStyle(hexToRgb(eachSeries.color, roseOption.activeOpacity || 0.5));
context.moveTo(centerPosition.x, centerPosition.y);
context.arc(centerPosition.x, centerPosition.y, activeRadius+eachSeries._radius_, eachSeries._start_, eachSeries._start_ + 2 * eachSeries._proportion_ * Math.PI);
context.closePath();
context.fill();
}
}
context.beginPath();
context.setLineWidth(2 * opts.pixelRatio);
context.lineJoin = "round";
context.setStrokeStyle('#ffffff');
context.setFillStyle(eachSeries.color);
context.moveTo(centerPosition.x, centerPosition.y);
context.arc(centerPosition.x, centerPosition.y, eachSeries._radius_ , eachSeries._start_, eachSeries._start_ + 2 * eachSeries._proportion_ *Math.PI);
context.closePath();
context.fill();
if (opts.disablePieStroke !== true) {
context.stroke();
}
});
if (opts.dataLabel !== false && process === 1) {
// fix https://github.com/xiaolin3303/wx-charts/issues/132
var valid = false;
for (var i = 0, len = series.length; i < len; i++) {
if (series[i].data > 0) {
valid = true;
break;
}
}
if (valid) {
drawPieText(series, opts, config, context, radius, centerPosition);
}
}
return {
center: centerPosition,
radius: radius,
series: series
};
}
function drawArcbarDataPoints(series, opts, config, context) {
var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
var arcbarOption = opts.extra.arcbar || {};
arcbarOption.startAngle = arcbarOption.startAngle ? arcbarOption.startAngle : 0.75;
arcbarOption.endAngle = arcbarOption.endAngle ? arcbarOption.endAngle : 0.25;
arcbarOption.type = arcbarOption.type ? arcbarOption.type : 'default';
series = getArcbarDataPoints(series, arcbarOption, process);
var centerPosition = {
x: opts.width / 2,
y: (opts.height) / 2
};
var radius = Math.min(centerPosition.x, centerPosition.y);
if (typeof arcbarOption.width === 'number' && arcbarOption.width > 0) {
arcbarOption.width = arcbarOption.width;
} else {
arcbarOption.width = 12 * opts.pixelRatio;
}
radius -= config.padding + arcbarOption.width / 2;
//背景颜色
context.setLineWidth(arcbarOption.width); // 设置圆环的宽度
context.setStrokeStyle(arcbarOption.backgroundColor || '#E9E9E9'); // 设置圆环的颜色
context.setLineCap('round'); // 设置圆环端点的形状
context.beginPath(); //开始一个新的路径
if (arcbarOption.type == 'default') {
context.arc(centerPosition.x, centerPosition.y, radius, arcbarOption.startAngle * Math.PI, arcbarOption.endAngle *
Math.PI, false);
} else {
context.arc(centerPosition.x, centerPosition.y, radius, 0, 2 * Math.PI, false);
}
context.stroke(); //对当前路径进行描边
for (let i = 0; i < series.length; i++) {
let eachSeries = series[i];
context.setLineWidth(arcbarOption.width);
context.setStrokeStyle(eachSeries.color);
context.setLineCap('round');
context.beginPath();
context.arc(centerPosition.x, centerPosition.y, radius, arcbarOption.startAngle * Math.PI, eachSeries._proportion_ *
Math.PI, false);
context.stroke();
}
drawRingTitle(opts, config, context);
return {
center: centerPosition,
radius: radius,
series: series
};
}
function drawGaugeDataPoints(categories, series, opts, config, context) {
var process = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 1;
var gaugeOption = opts.extra.gauge || {};
gaugeOption.startAngle = gaugeOption.startAngle ? gaugeOption.startAngle : 0.75;
if (gaugeOption.oldAngle == undefined) {
gaugeOption.oldAngle = gaugeOption.startAngle;
}
if (gaugeOption.oldData == undefined) {
gaugeOption.oldData = 0;
}
gaugeOption.endAngle = gaugeOption.endAngle ? gaugeOption.endAngle : 0.25;
categories = getGaugeAxisPoints(categories, gaugeOption.startAngle, gaugeOption.endAngle);
var centerPosition = {
x: opts.width / 2,
y: (opts.height) / 2
};
var radius = Math.min(centerPosition.x, centerPosition.y);
if (typeof gaugeOption.width === 'number' && gaugeOption.width > 0) {
gaugeOption.width = gaugeOption.width;
} else {
gaugeOption.width = 15 * opts.pixelRatio;
}
radius -= config.padding + gaugeOption.width / 2;
var innerRadius = radius - gaugeOption.width;
//画背景
context.setLineWidth(gaugeOption.width);
context.setLineCap('butt');
for (let i = 0; i < categories.length; i++) {
let eachCategories = categories[i];
context.beginPath();
context.setStrokeStyle(eachCategories.color);
context.arc(centerPosition.x, centerPosition.y, radius, eachCategories._startAngle_ * Math.PI, eachCategories._endAngle_ *
Math.PI, false);
context.stroke();
}
context.save();
//画刻度线
let totalAngle = gaugeOption.startAngle - gaugeOption.endAngle + 1;
gaugeOption.splitLine.fixRadius = gaugeOption.splitLine.fixRadius ? gaugeOption.splitLine.fixRadius : 0;
gaugeOption.splitLine.splitNumber = gaugeOption.splitLine.splitNumber ? gaugeOption.splitLine.splitNumber : 10;
gaugeOption.splitLine.width = gaugeOption.splitLine.width ? gaugeOption.splitLine.width : 15 * opts.pixelRatio;
gaugeOption.splitLine.color = gaugeOption.splitLine.color ? gaugeOption.splitLine.color : '#FFFFFF';
gaugeOption.splitLine.childNumber = gaugeOption.splitLine.childNumber ? gaugeOption.splitLine.childNumber : 5;
gaugeOption.splitLine.childWidth = gaugeOption.splitLine.childWidth ? gaugeOption.splitLine.childWidth : 5 * opts.pixelRatio;
let splitAngle = totalAngle / gaugeOption.splitLine.splitNumber;
let childAngle = totalAngle / gaugeOption.splitLine.splitNumber / gaugeOption.splitLine.childNumber;
let startX = -radius - gaugeOption.width * 0.5 - gaugeOption.splitLine.fixRadius;
let endX = -radius - gaugeOption.width * 0.5 - gaugeOption.splitLine.fixRadius + gaugeOption.splitLine.width;
let childendX = -radius - gaugeOption.width * 0.5 - gaugeOption.splitLine.fixRadius + gaugeOption.splitLine.childWidth;
context.translate(centerPosition.x, centerPosition.y);
context.rotate((gaugeOption.startAngle - 1) * Math.PI);
for (let i = 0; i < gaugeOption.splitLine.splitNumber + 1; i++) {
context.beginPath();
context.setStrokeStyle(gaugeOption.splitLine.color);
context.setLineWidth(2 * opts.pixelRatio);
context.moveTo(startX, 0);
context.lineTo(endX, 0);
context.stroke();
context.rotate(splitAngle * Math.PI);
}
context.restore();
context.save();
context.translate(centerPosition.x, centerPosition.y);
context.rotate((gaugeOption.startAngle - 1) * Math.PI);
for (let i = 0; i < gaugeOption.splitLine.splitNumber * gaugeOption.splitLine.childNumber + 1; i++) {
context.beginPath();
context.setStrokeStyle(gaugeOption.splitLine.color);
context.setLineWidth(1 * opts.pixelRatio);
context.moveTo(startX, 0);
context.lineTo(childendX, 0);
context.stroke();
context.rotate(childAngle * Math.PI);
}
context.restore();
//画指针
gaugeOption.pointer.width = gaugeOption.pointer.width ? gaugeOption.pointer.width : 15 * opts.pixelRatio;
if (gaugeOption.pointer.color == undefined || gaugeOption.pointer.color == 'auto') {
gaugeOption.pointer.color == 'auto';
} else {
gaugeOption.pointer.color == gaugeOption.pointer.color;
}
series = getGaugeDataPoints(series, categories, gaugeOption, process);
for (let i = 0; i < series.length; i++) {
let eachSeries = series[i];
context.save();
context.translate(centerPosition.x, centerPosition.y);
context.rotate((eachSeries._proportion_ - 1) * Math.PI);
context.beginPath();
context.setFillStyle(eachSeries.color);
context.moveTo(gaugeOption.pointer.width, 0);
context.lineTo(0, -gaugeOption.pointer.width / 2);
context.lineTo(-innerRadius, 0);
context.lineTo(0, gaugeOption.pointer.width / 2);
context.lineTo(gaugeOption.pointer.width, 0);
context.closePath();
context.fill();
context.beginPath();
context.setFillStyle('#FFFFFF');
context.arc(0, 0, gaugeOption.pointer.width / 6, 0, 2 * Math.PI, false);
context.fill();
context.restore();
}
if (opts.dataLabel !== false) {
drawGaugeLabel(gaugeOption, radius, centerPosition, opts, config, context);
}
drawRingTitle(opts, config, context);
if (process === 1 && opts.type === 'gauge') {
gaugeOption.oldAngle = series[0]._proportion_;
gaugeOption.oldData = series[0].data;
}
return {
center: centerPosition,
radius: radius,
innerRadius: innerRadius,
categories: categories,
totalAngle: totalAngle
};
}
function drawRadarDataPoints(series, opts, config, context) {
var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
var radarOption = opts.extra.radar || {};
var coordinateAngle = getRadarCoordinateSeries(opts.categories.length);
var centerPosition = {
x: opts.width / 2,
y: (opts.height - config.legendHeight) / 2
};
var radius = Math.min(centerPosition.x - (getMaxTextListLength(opts.categories) + config.radarLabelTextMargin),
centerPosition.y - config.radarLabelTextMargin);
radius -= config.padding;
// draw grid
context.beginPath();
context.setLineWidth(1 * opts.pixelRatio);
context.setStrokeStyle(radarOption.gridColor || "#cccccc");
coordinateAngle.forEach(function (angle) {
var pos = convertCoordinateOrigin(radius * Math.cos(angle), radius * Math.sin(angle), centerPosition);
context.moveTo(centerPosition.x, centerPosition.y);
context.lineTo(pos.x, pos.y);
});
context.stroke();
context.closePath();
// draw split line grid
var _loop = function _loop(i) {
var startPos = {};
context.beginPath();
context.setLineWidth(1 * opts.pixelRatio);
context.setStrokeStyle(radarOption.gridColor || "#cccccc");
coordinateAngle.forEach(function (angle, index) {
var pos = convertCoordinateOrigin(radius / config.radarGridCount * i * Math.cos(angle), radius / config.radarGridCount * i * Math.sin(angle), centerPosition);
if (index === 0) {
startPos = pos;
context.moveTo(pos.x, pos.y);
} else {
context.lineTo(pos.x, pos.y);
}
});
context.lineTo(startPos.x, startPos.y);
context.stroke();
context.closePath();
};
for (var i = 1; i <= config.radarGridCount; i++) {
_loop(i);
}
var radarDataPoints = getRadarDataPoints(coordinateAngle, centerPosition, radius, series, opts, process);
radarDataPoints.forEach(function(eachSeries, seriesIndex) {
// 绘制区域数据
context.beginPath();
context.setFillStyle(eachSeries.color);
context.setGlobalAlpha(0.3);
eachSeries.data.forEach(function(item, index) {
if (index === 0) {
context.moveTo(item.position.x, item.position.y);
} else {
context.lineTo(item.position.x, item.position.y);
}
});
context.closePath();
context.fill();
context.setGlobalAlpha(1);
if (opts.dataPointShape !== false) {
var shape = config.dataPointShape[seriesIndex % config.dataPointShape.length];
var points = eachSeries.data.map(function(item) {
return item.position;
});
drawPointShape(points, eachSeries.color, shape, context, opts);
}
});
// draw label text
drawRadarLabel(coordinateAngle, radius, centerPosition, opts, config, context);
return {
center: centerPosition,
radius: radius,
angleList: coordinateAngle
};
}
function drawCanvas(opts, context) {
context.draw();
}
var Timing = {
easeIn: function easeIn(pos) {
return Math.pow(pos, 3);
},
easeOut: function easeOut(pos) {
return Math.pow(pos - 1, 3) + 1;
},
easeInOut: function easeInOut(pos) {
if ((pos /= 0.5) < 1) {
return 0.5 * Math.pow(pos, 3);
} else {
return 0.5 * (Math.pow(pos - 2, 3) + 2);
}
},
linear: function linear(pos) {
return pos;
}
};
function Animation(opts) {
this.isStop = false;
opts.duration = typeof opts.duration === 'undefined' ? 1000 : opts.duration;
opts.timing = opts.timing || 'linear';
var delay = 17;
var createAnimationFrame = function createAnimationFrame() {
if (typeof requestAnimationFrame !== 'undefined') {
return requestAnimationFrame;
} else if (typeof setTimeout !== 'undefined') {
return function(step, delay) {
setTimeout(function() {
var timeStamp = +new Date();
step(timeStamp);
}, delay);
};
} else {
return function(step) {
step(null);
};
}
};
var animationFrame = createAnimationFrame();
var startTimeStamp = null;
var _step = function step(timestamp) {
if (timestamp === null || this.isStop === true) {
opts.onProcess && opts.onProcess(1);
opts.onAnimationFinish && opts.onAnimationFinish();
return;
}
if (startTimeStamp === null) {
startTimeStamp = timestamp;
}
if (timestamp - startTimeStamp < opts.duration) {
var process = (timestamp - startTimeStamp) / opts.duration;
var timingFunction = Timing[opts.timing];
process = timingFunction(process);
opts.onProcess && opts.onProcess(process);
animationFrame(_step, delay);
} else {
opts.onProcess && opts.onProcess(1);
opts.onAnimationFinish && opts.onAnimationFinish();
}
};
_step = _step.bind(this);
animationFrame(_step, delay);
}
// stop animation immediately
// and tigger onAnimationFinish
Animation.prototype.stop = function() {
this.isStop = true;
};
function drawCharts(type, opts, config, context) {
var _this = this;
var series = opts.series;
var categories = opts.categories;
series = fillSeriesColor(series, config);
series = fillSeriesType(series, opts);
let seriesMA = null;
if (type == 'candle') {
let average = assign({}, opts.extra.candle.average);
if (average.show) {
seriesMA = calCandleMA(average.day, average.name, average.color, series[0].data);
opts.seriesMA = seriesMA;
}
}
var _calLegendData = calLegendData(series, opts, config),
legendHeight = _calLegendData.legendHeight;
config.legendHeight = legendHeight;
var _calYAxisData = calYAxisData(series, opts, config),
yAxisWidth = _calYAxisData.yAxisWidth;
config.yAxisWidth = yAxisWidth;
if (categories && categories.length) {
var _calCategoriesData = calCategoriesData(categories, opts, config),
xAxisHeight = _calCategoriesData.xAxisHeight,
angle = _calCategoriesData.angle;
config.xAxisHeight = xAxisHeight;
config._xAxisTextAngle_ = angle;
}
if (type === 'pie' || type === 'ring' || type === 'rose') {
config._pieTextMaxLength_ = opts.dataLabel === false ? 0 : getPieTextMaxLength(series);
}
var duration = opts.animation ? opts.duration : 0;
this.animationInstance && this.animationInstance.stop();
switch (type) {
case 'line':
this.animationInstance = new Animation({
timing: 'easeIn',
duration: duration,
onProcess: function onProcess(process) {
context.clearRect(0, 0, opts.width, opts.height);
if (opts.rotate) {
contextRotate(context, opts);
}
drawYAxisGrid(categories, opts, config, context);
drawXAxis(categories, opts, config, context);
var _drawLineDataPoints = drawLineDataPoints(series, opts, config, context, process),
xAxisPoints = _drawLineDataPoints.xAxisPoints,
calPoints = _drawLineDataPoints.calPoints,
eachSpacing = _drawLineDataPoints.eachSpacing;
_this.chartData.xAxisPoints = xAxisPoints;
_this.chartData.calPoints = calPoints;
_this.chartData.eachSpacing = eachSpacing;
drawLegend(opts.series, opts, config, context);
drawYAxis(series, opts, config, context);
drawToolTipBridge(opts, config, context, process, eachSpacing, xAxisPoints);
drawCanvas(opts, context);
},
onAnimationFinish: function onAnimationFinish() {
_this.event.trigger('renderComplete');
}
});
break;
case 'mix':
this.animationInstance = new Animation({
timing: 'easeIn',
duration: duration,
onProcess: function onProcess(process) {
context.clearRect(0, 0, opts.width, opts.height);
if (opts.rotate) {
contextRotate(context, opts);
}
drawYAxisGrid(categories, opts, config, context);
drawXAxis(categories, opts, config, context);
var _drawMixDataPoints = drawMixDataPoints(series, opts, config, context, process),
xAxisPoints = _drawMixDataPoints.xAxisPoints,
calPoints = _drawMixDataPoints.calPoints,
eachSpacing = _drawMixDataPoints.eachSpacing;
_this.chartData.xAxisPoints = xAxisPoints;
_this.chartData.calPoints = calPoints;
_this.chartData.eachSpacing = eachSpacing;
drawLegend(opts.series, opts, config, context);
drawYAxis(series, opts, config, context);
drawToolTipBridge(opts, config, context, process, eachSpacing, xAxisPoints);
drawCanvas(opts, context);
},
onAnimationFinish: function onAnimationFinish() {
_this.event.trigger('renderComplete');
}
});
break;
case 'column':
this.animationInstance = new Animation({
timing: 'easeIn',
duration: duration,
onProcess: function onProcess(process) {
context.clearRect(0, 0, opts.width, opts.height);
if (opts.rotate) {
contextRotate(context, opts);
}
drawYAxisGrid(categories, opts, config, context);
drawXAxis(categories, opts, config, context);
var _drawColumnDataPoints = drawColumnDataPoints(series, opts, config, context, process),
xAxisPoints = _drawColumnDataPoints.xAxisPoints,
calPoints = _drawColumnDataPoints.calPoints,
eachSpacing = _drawColumnDataPoints.eachSpacing;
_this.chartData.xAxisPoints = xAxisPoints;
_this.chartData.calPoints = calPoints;
_this.chartData.eachSpacing = eachSpacing;
drawLegend(opts.series, opts, config, context);
drawYAxis(series, opts, config, context);
drawToolTipBridge(opts, config, context, process, eachSpacing, xAxisPoints);
drawCanvas(opts, context);
},
onAnimationFinish: function onAnimationFinish() {
_this.event.trigger('renderComplete');
}
});
break;
case 'area':
this.animationInstance = new Animation({
timing: 'easeIn',
duration: duration,
onProcess: function onProcess(process) {
context.clearRect(0, 0, opts.width, opts.height);
if (opts.rotate) {
contextRotate(context, opts);
}
drawYAxisGrid(categories, opts, config, context);
drawXAxis(categories, opts, config, context);
var _drawAreaDataPoints = drawAreaDataPoints(series, opts, config, context, process),
xAxisPoints = _drawAreaDataPoints.xAxisPoints,
calPoints = _drawAreaDataPoints.calPoints,
eachSpacing = _drawAreaDataPoints.eachSpacing;
_this.chartData.xAxisPoints = xAxisPoints;
_this.chartData.calPoints = calPoints;
_this.chartData.eachSpacing = eachSpacing;
drawLegend(opts.series, opts, config, context);
drawYAxis(series, opts, config, context);
drawToolTipBridge(opts, config, context, process, eachSpacing, xAxisPoints);
drawCanvas(opts, context);
},
onAnimationFinish: function onAnimationFinish() {
_this.event.trigger('renderComplete');
}
});
break;
case 'ring':
case 'pie':
this.animationInstance = new Animation({
timing: 'easeInOut',
duration: duration,
onProcess: function onProcess(process) {
context.clearRect(0, 0, opts.width, opts.height);
if (opts.rotate) {
contextRotate(context, opts);
}
_this.chartData.pieData = drawPieDataPoints(series, opts, config, context, process);
drawLegend(opts.series, opts, config, context);
drawToolTipBridge(opts, config, context, process);
drawCanvas(opts, context);
},
onAnimationFinish: function onAnimationFinish() {
_this.event.trigger('renderComplete');
}
});
break;
case 'rose':
this.animationInstance = new Animation({
timing: 'easeInOut',
duration: duration,
onProcess: function onProcess(process) {
context.clearRect(0, 0, opts.width, opts.height);
if (opts.rotate) {
contextRotate(context, opts);
}
_this.chartData.pieData = drawRoseDataPoints(series, opts, config, context, process);
drawLegend(opts.series, opts, config, context);
drawToolTipBridge(opts, config, context, process);
drawCanvas(opts, context);
},
onAnimationFinish: function onAnimationFinish() {
_this.event.trigger('renderComplete');
}
});
break;
case 'radar':
this.animationInstance = new Animation({
timing: 'easeInOut',
duration: duration,
onProcess: function onProcess(process) {
context.clearRect(0, 0, opts.width, opts.height);
if (opts.rotate) {
contextRotate(context, opts);
}
_this.chartData.radarData = drawRadarDataPoints(series, opts, config, context, process);
drawLegend(opts.series, opts, config, context);
drawToolTipBridge(opts, config, context, process);
drawCanvas(opts, context);
},
onAnimationFinish: function onAnimationFinish() {
_this.event.trigger('renderComplete');
}
});
break;
case 'arcbar':
this.animationInstance = new Animation({
timing: 'easeInOut',
duration: duration,
onProcess: function onProcess(process) {
context.clearRect(0, 0, opts.width, opts.height);
if (opts.rotate) {
contextRotate(context, opts);
}
_this.chartData.arcbarData = drawArcbarDataPoints(series, opts, config, context, process);
drawCanvas(opts, context);
},
onAnimationFinish: function onAnimationFinish() {
_this.event.trigger('renderComplete');
}
});
break;
case 'gauge':
this.animationInstance = new Animation({
timing: 'easeInOut',
duration: duration,
onProcess: function onProcess(process) {
context.clearRect(0, 0, opts.width, opts.height);
if (opts.rotate) {
contextRotate(context, opts);
}
_this.chartData.gaugeData = drawGaugeDataPoints(categories, series, opts, config, context, process);
drawCanvas(opts, context);
},
onAnimationFinish: function onAnimationFinish() {
_this.event.trigger('renderComplete');
}
});
break;
case 'candle':
this.animationInstance = new Animation({
timing: 'easeIn',
duration: duration,
onProcess: function onProcess(process) {
context.clearRect(0, 0, opts.width, opts.height);
if (opts.rotate) {
contextRotate(context, opts);
}
drawYAxisGrid(categories, opts, config, context);
drawXAxis(categories, opts, config, context);
var _drawCandleDataPoints = drawCandleDataPoints(series, seriesMA, opts, config, context, process),
xAxisPoints = _drawCandleDataPoints.xAxisPoints,
calPoints = _drawCandleDataPoints.calPoints,
eachSpacing = _drawCandleDataPoints.eachSpacing;
_this.chartData.xAxisPoints = xAxisPoints;
_this.chartData.calPoints = calPoints;
_this.chartData.eachSpacing = eachSpacing;
if (seriesMA) {
drawLegend(seriesMA, opts, config, context);
} else {
drawLegend(opts.series, opts, config, context);
}
drawYAxis(series, opts, config, context);
drawToolTipBridge(opts, config, context, process, eachSpacing, xAxisPoints);
drawCanvas(opts, context);
},
onAnimationFinish: function onAnimationFinish() {
_this.event.trigger('renderComplete');
}
});
break;
}
}
// simple event implement
function Event() {
this.events = {};
}
Event.prototype.addEventListener = function(type, listener) {
this.events[type] = this.events[type] || [];
this.events[type].push(listener);
};
Event.prototype.trigger = function() {
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
var type = args[0];
var params = args.slice(1);
if (!!this.events[type]) {
this.events[type].forEach(function(listener) {
try {
listener.apply(null, params);
} catch (e) {
// console.error(e);
}
});
}
};
var Charts = function Charts(opts) {
opts.pixelRatio = opts.pixelRatio ? opts.pixelRatio : 1;
opts.fontSize = opts.fontSize ? opts.fontSize * opts.pixelRatio : 13 * opts.pixelRatio;
opts.title = assign({}, opts.title);
opts.subtitle = assign({}, opts.subtitle);
opts.yAxis = assign({}, {
gridType:'solid',
dashLength:4 * opts.pixelRatio
},opts.yAxis);
opts.xAxis = assign({}, {
rotateLabel:false,
type:'calibration',
gridType:'solid',
dashLength:4 * opts.pixelRatio,
scrollAlign:'left'
},opts.xAxis);
opts.extra = assign({}, opts.extra);
opts.rotate = opts.rotate ? true : false;
opts.animation = opts.animation ? true : false;
var config$$1 = assign({}, config);
config$$1.yAxisTitleWidth = opts.yAxis.disabled !== true && opts.yAxis.title ? config$$1.yAxisTitleWidth : 0;
if (opts.type == 'pie' || opts.type == 'ring' ) {
config$$1.pieChartLinePadding = opts.dataLabel === false ? 0 : opts.extra.pie.labelWidth*opts.pixelRatio || config$$1.pieChartLinePadding *opts.pixelRatio;
}
if (opts.type == 'rose' ) {
config$$1.pieChartLinePadding = opts.dataLabel === false ? 0 : opts.extra.rose.labelWidth*opts.pixelRatio || config$$1.pieChartLinePadding *opts.pixelRatio;
}
config$$1.pieChartTextPadding = opts.dataLabel === false ? 0 : config$$1.pieChartTextPadding * opts.pixelRatio;
config$$1.yAxisSplit = opts.yAxis.splitNumber ? opts.yAxis.splitNumber : config.yAxisSplit;
//屏幕旋转
config$$1.rotate = opts.rotate;
if (opts.rotate) {
let tempWidth = opts.width;
let tempHeight = opts.height;
opts.width = tempHeight;
opts.height = tempWidth;
}
//适配高分屏
config$$1.yAxisWidth = config.yAxisWidth * opts.pixelRatio;
config$$1.xAxisHeight = config.xAxisHeight * opts.pixelRatio;
if (opts.enableScroll && opts.xAxis.scrollShow) {
config$$1.xAxisHeight += 6 * opts.pixelRatio;
}
config$$1.xAxisLineHeight = config.xAxisLineHeight * opts.pixelRatio;
config$$1.legendHeight = config.legendHeight * opts.pixelRatio;
config$$1.padding = config.padding * opts.pixelRatio;
config$$1.fontSize = opts.fontSize;
config$$1.titleFontSize = config.titleFontSize * opts.pixelRatio;
config$$1.subtitleFontSize = config.subtitleFontSize * opts.pixelRatio;
config$$1.toolTipPadding = config.toolTipPadding * opts.pixelRatio;
config$$1.toolTipLineHeight = config.toolTipLineHeight * opts.pixelRatio;
config$$1.columePadding = config.columePadding * opts.pixelRatio;
this.opts = opts;
this.config = config$$1;
opts.$this = opts.$this ? opts.$this : this;
this.context = uni.createCanvasContext(opts.canvasId, opts.$this);
/* 兼容原生H5
this.context = document.getElementById(opts.canvasId).getContext("2d");
this.context.setStrokeStyle = function(e){ return this.strokeStyle=e; }
this.context.setLineWidth = function(e){ return this.lineWidth=e; }
this.context.setLineCap = function(e){ return this.lineCap=e; }
this.context.setFontSize = function(e){ return this.font=e+"px sans-serif"; }
this.context.setFillStyle = function(e){ return this.fillStyle=e; }
this.context.draw = function(){ }
*/
this.chartData = {};
this.event = new Event();
this.scrollOption = {
currentOffset: 0,
startTouchX: 0,
distance: 0,
lastMoveTime: 0
};
//计算右对齐偏移距离
if (opts.enableScroll && opts.xAxis.scrollAlign == 'right') {
let _calYAxisData = calYAxisData(opts.series, opts, config$$1),
yAxisWidth = _calYAxisData.yAxisWidth;
config$$1.yAxisWidth = yAxisWidth;
let offsetLeft = 0;
let _getXAxisPoints0 = getXAxisPoints(opts.categories, opts, config$$1),
xAxisPoints = _getXAxisPoints0.xAxisPoints,
startX = _getXAxisPoints0.startX,
endX = _getXAxisPoints0.endX,
eachSpacing = _getXAxisPoints0.eachSpacing;
let totalWidth = eachSpacing * (xAxisPoints.length - 1);
let screenWidth = endX - startX;
offsetLeft = screenWidth - totalWidth;
this.scrollOption = {
currentOffset: offsetLeft,
startTouchX: offsetLeft,
distance: 0,
lastMoveTime: 0
};
opts._scrollDistance_ = offsetLeft;
}
drawCharts.call(this, opts.type, opts, config$$1, this.context);
};
Charts.prototype.updateData = function() {
let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
this.opts = assign({}, this.opts, data);
let scrollPosition = data.scrollPosition || 'current';
switch (scrollPosition) {
case 'current':
this.opts._scrollDistance_ = this.scrollOption.currentOffset;
break;
case 'left':
this.opts._scrollDistance_ = 0;
this.scrollOption = {
currentOffset: 0,
startTouchX: 0,
distance: 0,
lastMoveTime: 0
};
break;
case 'right':
let _calYAxisData = calYAxisData(this.opts.series, this.opts, this.config),
yAxisWidth = _calYAxisData.yAxisWidth;
this.config.yAxisWidth = yAxisWidth;
let offsetLeft = 0;
let _getXAxisPoints0 = getXAxisPoints(this.opts.categories, this.opts, this.config),
xAxisPoints = _getXAxisPoints0.xAxisPoints,
startX = _getXAxisPoints0.startX,
endX = _getXAxisPoints0.endX,
eachSpacing = _getXAxisPoints0.eachSpacing;
let totalWidth = eachSpacing * (xAxisPoints.length - 1);
let screenWidth = endX - startX;
offsetLeft = screenWidth - totalWidth;
this.scrollOption = {
currentOffset: offsetLeft,
startTouchX: offsetLeft,
distance: 0,
lastMoveTime: 0
};
this.opts._scrollDistance_ = offsetLeft;
break;
}
drawCharts.call(this, this.opts.type, this.opts, this.config, this.context);
};
Charts.prototype.zoom = function() {
var val = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.opts.xAxis.itemCount;
if (this.opts.enableScroll !== true) {
// console.log('请启用滚动条后使用!')
return;
}
//当前屏幕中间点
let centerPoint = Math.round(Math.abs(this.scrollOption.currentOffset) / this.chartData.eachSpacing) + Math.round(
this.opts.xAxis.itemCount / 2);
this.opts.animation = false;
this.opts.xAxis.itemCount = val.itemCount;
//重新计算x轴偏移距离
let _calYAxisData = calYAxisData(this.opts.series, this.opts, this.config),
yAxisWidth = _calYAxisData.yAxisWidth;
this.config.yAxisWidth = yAxisWidth;
let offsetLeft = 0;
let _getXAxisPoints0 = getXAxisPoints(this.opts.categories, this.opts, this.config),
xAxisPoints = _getXAxisPoints0.xAxisPoints,
startX = _getXAxisPoints0.startX,
endX = _getXAxisPoints0.endX,
eachSpacing = _getXAxisPoints0.eachSpacing;
let centerLeft = eachSpacing * centerPoint;
let screenWidth = endX - startX;
let MaxLeft = screenWidth - eachSpacing * (xAxisPoints.length - 1);
offsetLeft = screenWidth / 2 - centerLeft;
if (offsetLeft > 0) {
offsetLeft = 0;
}
if (offsetLeft < MaxLeft) {
offsetLeft = MaxLeft;
}
this.scrollOption = {
currentOffset: offsetLeft,
startTouchX: offsetLeft,
distance: 0,
lastMoveTime: 0
};
this.opts._scrollDistance_ = offsetLeft;
drawCharts.call(this, this.opts.type, this.opts, this.config, this.context);
};
Charts.prototype.stopAnimation = function() {
this.animationInstance && this.animationInstance.stop();
};
Charts.prototype.addEventListener = function(type, listener) {
this.event.addEventListener(type, listener);
};
Charts.prototype.getCurrentDataIndex = function(e) {
var touches = null;
if(e.changedTouches){
touches = e.changedTouches[0];
}else{
touches = e.mp.changedTouches[0];
}
if (touches) {
var _touches$ = getTouches(touches, this.opts, e);
if (this.opts.type === 'pie' || this.opts.type === 'ring' || this.opts.type === 'rose') {
return findPieChartCurrentIndex({
x: _touches$.x,
y: _touches$.y
}, this.chartData.pieData);
} else if (this.opts.type === 'radar') {
return findRadarChartCurrentIndex({
x: _touches$.x,
y: _touches$.y
}, this.chartData.radarData, this.opts.categories.length);
} else {
return findCurrentIndex({
x: _touches$.x,
y: _touches$.y
}, this.chartData.xAxisPoints, this.opts, this.config, Math.abs(this.scrollOption.currentOffset));
}
}
return -1;
};
Charts.prototype.showToolTip = function(e) {
var option = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var touches = null;
if(e.changedTouches){
touches = e.changedTouches[0];
}else{
touches = e.mp.changedTouches[0];
}
if(!touches){
// console.log("touchError");
return;
}
var _touches$ = getTouches(touches, this.opts, e);
if (this.opts.type === 'line' || this.opts.type === 'area' || this.opts.type === 'column') {
var index = this.getCurrentDataIndex(e);
var currentOffset = this.scrollOption.currentOffset;
var opts = assign({}, this.opts, {
_scrollDistance_: currentOffset,
animation: false
});
if (index > -1) {
var seriesData = getSeriesDataItem(this.opts.series, index);
if (seriesData.length !== 0) {
var _getToolTipData = getToolTipData(seriesData, this.chartData.calPoints, index, this.opts.categories, option),
textList = _getToolTipData.textList,
offset = _getToolTipData.offset;
offset.y = _touches$.y;
opts.tooltip = {
textList: textList,
offset: offset,
option: option,
index: index
};
}
}
drawCharts.call(this, opts.type, opts, this.config, this.context);
}
if (this.opts.type === 'mix') {
var index = this.getCurrentDataIndex(e);
var currentOffset = this.scrollOption.currentOffset;
var opts = assign({}, this.opts, {
_scrollDistance_: currentOffset,
animation: false
});
if (index > -1) {
var seriesData = getSeriesDataItem(this.opts.series, index);
if (seriesData.length !== 0) {
var _getMixToolTipData = getMixToolTipData(seriesData, this.chartData.calPoints, index, this.opts.categories,option),
textList = _getMixToolTipData.textList,
offset = _getMixToolTipData.offset;
offset.y = _touches$.y;
opts.tooltip = {
textList: textList,
offset: offset,
option: option,
index: index
};
}
}
drawCharts.call(this, opts.type, opts, this.config, this.context);
}
if (this.opts.type === 'candle') {
var index = this.getCurrentDataIndex(e);
var currentOffset = this.scrollOption.currentOffset;
var opts = assign({}, this.opts, {
_scrollDistance_: currentOffset,
animation: false
});
if (index > -1) {
var seriesData = getSeriesDataItem(this.opts.series, index);
if (seriesData.length !== 0) {
var _getToolTipData = getCandleToolTipData(this.opts.series[0].data, seriesData, this.chartData.calPoints, index,this.opts.categories, this.opts.extra.candle, option),
textList = _getToolTipData.textList,
offset = _getToolTipData.offset;
offset.y = _touches$.y;
opts.tooltip = {
textList: textList,
offset: offset,
option: option,
index: index
};
}
}
drawCharts.call(this, opts.type, opts, this.config, this.context);
}
if (this.opts.type === 'pie' || this.opts.type === 'ring' || this.opts.type === 'rose') {
var index = this.getCurrentDataIndex(e);
var currentOffset = this.scrollOption.currentOffset;
var opts = assign({}, this.opts, {
_scrollDistance_: currentOffset,
animation: false
});
if (index > -1) {
var seriesData = this.opts.series[index];
var textList = [{
text: option.format ? option.format(seriesData) : seriesData.name + ': ' + seriesData.data,
color: seriesData.color
}];
var offset = {
x: _touches$.x,
y: _touches$.y
};
opts.tooltip = {
textList: textList,
offset: offset,
option: option,
index: index
};
}
drawCharts.call(this, opts.type, opts, this.config, this.context);
}
if (this.opts.type === 'radar') {
var index = this.getCurrentDataIndex(e);
var currentOffset = this.scrollOption.currentOffset;
var opts = assign({}, this.opts, {
_scrollDistance_: currentOffset,
animation: false
});
if (index > -1) {
var seriesData = getSeriesDataItem(this.opts.series, index);
if (seriesData.length !== 0) {
var textList = seriesData.map(function(item) {
return {
text: option.format ? option.format(item) : item.name + ': ' + item.data,
color: item.color
};
});
var offset = {
x: _touches$.x,
y: _touches$.y
};
opts.tooltip = {
textList: textList,
offset: offset,
option: option,
index: index
};
}
}
drawCharts.call(this, opts.type, opts, this.config, this.context);
}
};
Charts.prototype.translate = function(distance) {
this.scrollOption = {
currentOffset: distance,
startTouchX: distance,
distance: 0,
lastMoveTime: 0
};
let opts = assign({}, this.opts, {
_scrollDistance_: distance,
animation: false
});
drawCharts.call(this, this.opts.type, opts, this.config, this.context);
};
Charts.prototype.scrollStart = function(e) {
var touches = null;
if(e.changedTouches){
touches = e.changedTouches[0];
}else{
touches = e.mp.changedTouches[0];
}
var _touches$ = getTouches(touches, this.opts, e);
if (touches && this.opts.enableScroll === true) {
this.scrollOption.startTouchX = _touches$.x;
}
};
Charts.prototype.scroll = function(e) {
if (this.scrollOption.lastMoveTime === 0) {
this.scrollOption.lastMoveTime = Date.now();
}
let Limit = this.opts.extra.touchMoveLimit || 20;
let currMoveTime = Date.now();
let duration = currMoveTime - this.scrollOption.lastMoveTime;
if (duration < Math.floor(1000 / Limit)) return;
this.scrollOption.lastMoveTime = currMoveTime;
var touches = null;
if(e.changedTouches){
touches = e.changedTouches[0];
}else{
touches = e.mp.changedTouches[0];
}
var _touches$ = getTouches(touches, this.opts, e);
if (touches && this.opts.enableScroll === true) {
var _distance;
_distance = _touches$.x - this.scrollOption.startTouchX;
var currentOffset = this.scrollOption.currentOffset;
var validDistance = calValidDistance(currentOffset + _distance, this.chartData, this.config, this.opts);
this.scrollOption.distance = _distance = validDistance - currentOffset;
var opts = assign({}, this.opts, {
_scrollDistance_: currentOffset + _distance,
animation: false
});
drawCharts.call(this, opts.type, opts, this.config, this.context);
return currentOffset + _distance;
}
};
Charts.prototype.scrollEnd = function(e) {
if (this.opts.enableScroll === true) {
var _scrollOption = this.scrollOption,
currentOffset = _scrollOption.currentOffset,
distance = _scrollOption.distance;
this.scrollOption.currentOffset = currentOffset + distance;
this.scrollOption.distance = 0;
}
};
if ( typeof module === "object" && typeof module.exports === "object" ) {
module.exports = Charts;
//export default Charts;//建议使用nodejs的module导出方式,如报错请使用export方式导出
}
u-charts.min.js
'use strict';var config={yAxisWidth:15,yAxisSplit:5,xAxisHeight:15,xAxisLineHeight:15,legendHeight:15,yAxisTitleWidth:15,padding:12,pixelRatio:1,rotate:!1,columePadding:3,fontSize:13,dataPointShape:["circle","circle","circle","circle"],colors:["#1890ff","#2fc25b","#facc14","#f04864","#8543e0","#90ed7d"],pieChartLinePadding:15,pieChartTextPadding:5,xAxisTextPadding:3,titleColor:"#333333",titleFontSize:20,subtitleColor:"#999999",subtitleFontSize:15,toolTipPadding:3,toolTipBackground:"#000000",toolTipOpacity:.7,toolTipLineHeight:20,radarGridCount:3,radarLabelTextMargin:15,gaugeLabelTextMargin:15};function assign(e){if(null==e)throw new TypeError("Cannot convert undefined or null to object");for(var t,i=Object(e),o=1;o<arguments.length;o++)if(t=arguments[o],null!=t)for(var a in t)Object.prototype.hasOwnProperty.call(t,a)&&(i[a]=t[a]);return i}var util={toFixed:function(e,t){return t=t||2,this.isFloat(e)&&(e=e.toFixed(t)),e},isFloat:function(e){return 0!=e%1},approximatelyEqual:function(e,t){return 1e-10>Math.abs(e-t)},isSameSign:function(e,t){var i=Math.abs;return i(e)===e&&i(t)===t||i(e)!==e&&i(t)!==t},isSameXCoordinateArea:function(e,t){return this.isSameSign(e.x,t.x)},isCollision:function(e,t){e.end={},e.end.x=e.start.x+e.width,e.end.y=e.start.y-e.height,t.end={},t.end.x=t.start.x+t.width,t.end.y=t.start.y-t.height;var i=t.start.x>e.end.x||t.end.x<e.start.x||t.end.y>e.start.y||t.start.y<e.end.y;return!i}};function getH5Offset(t){return t.mp={changedTouches:[]},t.mp.changedTouches.push({x:t.offsetX,y:t.offsetY}),t}function hexToRgb(e,t){var i=/^#?([a-f\d])([a-f\d])([a-f\d])$/i,o=e.replace(i,function(e,t,i,o){return t+t+i+i+o+o}),a=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(o),n=parseInt(a[1],16),l=parseInt(a[2],16),r=parseInt(a[3],16);return"rgba("+n+","+l+","+r+","+t+")"}function findRange(e,t,i){if(isNaN(e))throw new Error("[wxCharts] unvalid series data!");i=i||10,t=t?t:"upper";for(var o=1;1>i;)i*=10,o*=10;for(e="upper"===t?Math.ceil(e*o):Math.floor(e*o);0!=e%i;)"upper"===t?e++:e--;return e/o}function calCandleMA(e,t,i,o){let a=[];for(let n,l=0;l<e.length;l++){n={data:[],name:t[l],color:i[l]};for(let t=0,i=o.length;t<i;t++){if(t<e[l]){n.data.push(null);continue}let i=0;for(let a=0;a<e[l];a++)i+=o[t-a][1];n.data.push(+(i/e[l]).toFixed(3))}a.push(n)}return a}function calValidDistance(e,t,i,o){var a=o.width-i.padding-t.xAxisPoints[0],n=t.eachSpacing*o.categories.length,l=e;return 0<=e?l=0:Math.abs(e)>=n-a&&(l=a-n),l}function isInAngleRange(e,t,i){function o(e){for(;0>e;)e+=2*a;for(;e>2*a;)e-=2*a;return e}var a=Math.PI;return e=o(e),t=o(t),i=o(i),t>i&&(i+=2*a,e<t&&(e+=2*a)),e>=t&&e<=i}function calRotateTranslate(e,t,i){var o=e,a=i-t,n=o+(i-a-o)/1.4142135623730951;n*=-1;return{transX:n,transY:(i-a)*(1.4142135623730951-1)-(i-a-o)/1.4142135623730951}}function createCurveControlPoints(e,t){function i(e,t){return!!(e[t-1]&&e[t+1])&&(e[t].y>=Math.max(e[t-1].y,e[t+1].y)||e[t].y<=Math.min(e[t-1].y,e[t+1].y))}var o=.2,a=.2,n=null,l=null,r=null,s=null;if(1>t?(n=e[0].x+(e[1].x-e[0].x)*o,l=e[0].y+(e[1].y-e[0].y)*o):(n=e[t].x+(e[t+1].x-e[t-1].x)*o,l=e[t].y+(e[t+1].y-e[t-1].y)*o),t>e.length-3){var d=e.length-1;r=e[d].x-(e[d].x-e[d-1].x)*a,s=e[d].y-(e[d].y-e[d-1].y)*a}else r=e[t+1].x-(e[t+2].x-e[t].x)*a,s=e[t+1].y-(e[t+2].y-e[t].y)*a;return i(e,t+1)&&(s=e[t+1].y),i(e,t)&&(l=e[t].y),{ctrA:{x:n,y:l},ctrB:{x:r,y:s}}}function convertCoordinateOrigin(e,t,i){return{x:i.x+e,y:i.y-t}}function avoidCollision(e,t){if(t)for(;util.isCollision(e,t);)0<e.start.x?e.start.y--:0>e.start.x?e.start.y++:0<e.start.y?e.start.y++:e.start.y--;return e}function fillSeriesColor(e,t){var i=0;return e.map(function(e){return e.color||(e.color=t.colors[i],i=(i+1)%t.colors.length),e})}function fillSeriesType(e,t){return e.map(function(e){return e.type||(e.type=t.type),e})}function getDataRange(e,t){var i=0,o=t-e;return i=1e4<=o?1e3:1e3<=o?100:100<=o?10:10<=o?5:1<=o?1:.1<=o?.1:.01,{minRange:findRange(e,"lower",i),maxRange:findRange(t,"upper",i)}}function measureText(e){var t=1<arguments.length&&arguments[1]!==void 0?arguments[1]:config.fontSize;e=e+"";var e=e.split(""),o=0;for(let t,a=0;a<e.length;a++)t=e[a],o+=/[a-zA-Z]/.test(t)?7:/[0-9]/.test(t)?5.5:/\./.test(t)?2.7:/-/.test(t)?3.25:/[\u4e00-\u9fa5]/.test(t)?10:/\(|\)/.test(t)?3.73:/\s/.test(t)?2.5:/%/.test(t)?8:10;return o*t/10}function dataCombine(e){return e.reduce(function(e,t){return(e.data?e.data:e).concat(t.data)},[])}function dataCombineStack(e){for(var t=Array(e[0].data.length),o=0;o<t.length;o++)t[o]=0;for(var a=0;a<e.length;a++)for(var o=0;o<t.length;o++)t[o]+=e[a].data[o];return e.reduce(function(e,i){return(e.data?e.data:e).concat(i.data).concat(t)},[])}function getTouches(t,i,o){let e,a;return t.clientX?i.rotate?(a=i.height-t.clientX*i.pixelRatio,e=(t.pageY-o.currentTarget.offsetTop-i.height/i.pixelRatio/2*(i.pixelRatio-1))*i.pixelRatio):(e=t.clientX*i.pixelRatio,a=(t.pageY-o.currentTarget.offsetTop-i.height/i.pixelRatio/2*(i.pixelRatio-1))*i.pixelRatio):i.rotate?(a=i.height-t.x*i.pixelRatio,e=t.y*i.pixelRatio):(e=t.x*i.pixelRatio,a=t.y*i.pixelRatio),{x:e,y:a}}function getSeriesDataItem(e,t){var i=[];for(let o,a=0;a<e.length;a++)if(o=e[a],null!==o.data[t]&&"undefined"!=typeof o.data[t]){let e={};e.color=o.color,e.type=o.type,e.style=o.style,e.shape=o.shape,e.disableLegend=o.disableLegend,e.name=o.name,e.data=o.format?o.format(o.data[t]):o.data[t],i.push(e)}return i}function getMaxTextListLength(e){var t=e.map(function(e){return measureText(e)});return Math.max.apply(null,t)}function getRadarCoordinateSeries(e){for(var t=Math.PI,o=[],a=0;a<e;a++)o.push(2*t/e*a);return o.map(function(e){return-1*e+t/2})}function getToolTipData(e,t,o,i){var a=4<arguments.length&&void 0!==arguments[4]?arguments[4]:{},n=e.map(function(e){return{text:a.format?a.format(e,i[o]):e.name+": "+e.data,color:e.color}}),l=[],r={x:0,y:0};for(let a,n=0;n<t.length;n++)a=t[n],"undefined"!=typeof a[o]&&null!==a[o]&&l.push(a[o]);for(let a,n=0;n<l.length;n++)a=l[n],r.x=Math.round(a.x),r.y+=a.y;return r.y/=l.length,{textList:n,offset:r}}function getMixToolTipData(e,t,o,i){var a=4<arguments.length&&void 0!==arguments[4]?arguments[4]:{},n=e.map(function(e){return{text:a.format?a.format(e,i[o]):e.name+": "+e.data,color:e.color,disableLegend:!!e.disableLegend}});n=n.filter(function(e){if(!0!==e.disableLegend)return e});var l=[],r={x:0,y:0};for(let a,n=0;n<t.length;n++)a=t[n],"undefined"!=typeof a[o]&&null!==a[o]&&l.push(a[o]);for(let a,n=0;n<l.length;n++)a=l[n],r.x=Math.round(a.x),r.y+=a.y;return r.y/=l.length,{textList:n,offset:r}}function getCandleToolTipData(e,t,o,a,i,n){6<arguments.length&&void 0!==arguments[6]?arguments[6]:{};let l=n.color.upFill,r=n.color.downFill,s=[l,l,r,l];var d=[];let h={text:i[a],color:null};d.push(h),t.map(function(t){0==a&&0>t.data[1]-t.data[0]?s[1]=r:(t.data[0]<e[a-1][1]&&(s[0]=r),t.data[1]<t.data[0]&&(s[1]=r),t.data[2]>e[a-1][1]&&(s[2]=l),t.data[3]<e[a-1][1]&&(s[3]=r));let i={text:"\u5F00\u76D8\uFF1A"+t.data[0],color:s[0]},o={text:"\u6536\u76D8\uFF1A"+t.data[1],color:s[1]},n={text:"\u6700\u4F4E\uFF1A"+t.data[2],color:s[2]},h={text:"\u6700\u9AD8\uFF1A"+t.data[3],color:s[3]};d.push(i,o,n,h)});var c=[],x={x:0,y:0};for(let l,r=0;r<o.length;r++)l=o[r],"undefined"!=typeof l[a]&&null!==l[a]&&c.push(l[a]);return x.x=Math.round(c[0][0].x),{textList:d,offset:x}}function findCurrentIndex(e,t,i,o){var a=4<arguments.length&&void 0!==arguments[4]?arguments[4]:0,n=-1;return isInExactChartArea(e,i,o)&&t.forEach(function(t,i){e.x+a>t&&(n=i)}),n}function isInExactChartArea(e,t,i){return e.x<t.width-i.padding&&e.x>i.padding+i.yAxisWidth+i.yAxisTitleWidth&&e.y>i.padding&&e.y<t.height-i.legendHeight-i.xAxisHeight-i.padding}function findRadarChartCurrentIndex(e,t,i){var o=Math.PI,a=2*o/i,n=-1;if(isInExactPieChartArea(e,t.center,t.radius)){var l=function(e){return 0>e&&(e+=2*o),e>2*o&&(e-=2*o),e},r=Math.atan2(t.center.y-e.y,e.x-t.center.x);r=-1*r,0>r&&(r+=2*o);var s=t.angleList.map(function(e){return e=l(-1*e),e});s.forEach(function(e,t){var i=l(e-a/2),s=l(e+a/2);s<i&&(s+=2*o),(r>=i&&r<=s||r+2*o>=i&&r+2*o<=s)&&(n=t)})}return n}function findPieChartCurrentIndex(e,t){var o=-1;if(isInExactPieChartArea(e,t.center,t.radius)){var a=Math.atan2(t.center.y-e.y,e.x-t.center.x);a=-a;for(var n,l=0,r=t.series.length;l<r;l++)if(n=t.series[l],isInAngleRange(a,n._start_,n._start_+2*n._proportion_*Math.PI)){o=l;break}}return o}function isInExactPieChartArea(e,t,i){var o=Math.pow;return o(e.x-t.x,2)+o(e.y-t.y,2)<=o(i,2)}function splitPoints(e){var t=[],i=[];return e.forEach(function(e){null===e?(i.length&&t.push(i),i=[]):i.push(e)}),i.length&&t.push(i),t}function calLegendData(e,t,i){if(!1===t.legend)return{legendList:[],legendHeight:0};var o=5*t.pixelRatio,a=8*t.pixelRatio,n=15*t.pixelRatio,l=[],r=0,s=[];for(let a=0;a<e.length;a++){let i=e[a],d=3*o+n+measureText(i.name||"undefined");r+d>t.width?(l.push(s),r=d,s=[i]):(r+=d,s.push(i))}return s.length&&l.push(s),{legendList:l,legendHeight:l.length*(i.fontSize+a)+o}}function calCategoriesData(e,t,i){var o={angle:0,xAxisHeight:i.xAxisHeight},a=getXAxisPoints(e,t,i),n=a.eachSpacing,l=e.map(function(e){return measureText(e)}),r=Math.max.apply(this,l);return!0==t.xAxis.rotateLabel&&r+2*i.xAxisTextPadding>n&&(o.angle=45*Math.PI/180,o.xAxisHeight=2*i.xAxisTextPadding+r*Math.sin(o.angle)),o}function getRadarDataPoints(e,t,i,o,a){var n=Math.max,l=5<arguments.length&&void 0!==arguments[5]?arguments[5]:1,r=a.extra.radar||{};r.max=r.max||0;var s=n(r.max,n.apply(null,dataCombine(o))),d=[];for(let n=0;n<o.length;n++){let a=o[n],r={};r.color=a.color,r.data=[],a.data.forEach(function(o,a){let n={};n.angle=e[a],n.proportion=o/s,n.position=convertCoordinateOrigin(i*n.proportion*l*Math.cos(n.angle),i*n.proportion*l*Math.sin(n.angle),t),r.data.push(n)}),d.push(r)}return d}function getPieDataPoints(e,t){var o=2<arguments.length&&arguments[2]!==void 0?arguments[2]:1,a=0,n=0;for(let o,n=0;n<e.length;n++)o=e[n],o.data=null===o.data?0:o.data,a+=o.data;for(let n,l=0;l<e.length;l++)n=e[l],n.data=null===n.data?0:n.data,n._proportion_=0===a?1/e.length*o:n.data/a*o,n._radius_=t;for(let o,a=0;a<e.length;a++)o=e[a],o._start_=n,n+=2*o._proportion_*Math.PI;return e}function getRoseDataPoints(e,t,o,a){var n=4<arguments.length&&arguments[4]!==void 0?arguments[4]:1,l=0,r=0,s=[];for(let n,r=0;r<e.length;r++)n=e[r],n.data=null===n.data?0:n.data,l+=n.data,s.push(n.data);var d=s.pop(),h=s.shift();for(let r,s=0;s<e.length;s++)r=e[s],r.data=null===r.data?0:r.data,r._proportion_=0===l||"area"==t?1/e.length*n:r.data/l*n,r._radius_=o+(a-o)*((r.data-d)/(h-d));for(let n,l=0;l<e.length;l++)n=e[l],n._start_=r,r+=2*n._proportion_*Math.PI;return e}function getArcbarDataPoints(e,t){var o=2<arguments.length&&arguments[2]!==void 0?arguments[2]:1;1==o&&(o=.999999);for(let a,n=0;n<e.length;n++){a=e[n],a.data=null===a.data?0:a.data;let i;i="default"==t.type?t.startAngle-t.endAngle+1:2,a._proportion_=i*a.data*o+t.startAngle,2<=a._proportion_&&(a._proportion_%=2)}return e}function getGaugeAxisPoints(e,t,o){let a=t;for(let n=0;n<e.length;n++)e[n].value=null===e[n].value?0:e[n].value,e[n]._startAngle_=a,e[n]._endAngle_=(t-o+1)*e[n].value+t,2<=e[n]._endAngle_&&(e[n]._endAngle_%=2),a=e[n]._endAngle_;return e}function getGaugeDataPoints(e,t,o){let a=3<arguments.length&&arguments[3]!==void 0?arguments[3]:1;for(let n,l=0;l<e.length;l++){if(n=e[l],n.data=null===n.data?0:n.data,"auto"==o.pointer.color){for(let e=0;e<t.length;e++)if(n.data<=t[e].value){n.color=t[e].color;break}}else n.color=o.pointer.color;let i=o.startAngle-o.endAngle+1;n._endAngle_=i*n.data+o.startAngle,n._oldAngle_=o.oldAngle,o.oldAngle<o.endAngle&&(n._oldAngle_+=2),n._proportion_=n.data>=o.oldData?(n._endAngle_-n._oldAngle_)*a+o.oldAngle:n._oldAngle_-(n._oldAngle_-n._endAngle_)*a,2<=n._proportion_&&(n._proportion_%=2)}return e}function getPieTextMaxLength(e){e=getPieDataPoints(e);let t=0;for(let o=0;o<e.length;o++){let i=e[o],a=i.format?i.format(+i._proportion_.toFixed(2)):util.toFixed(100*i._proportion_)+"%";t=Math.max(t,measureText(a))}return t}function fixColumeData(e,t,i,o,a,n){return e.map(function(e){return null===e?null:(e.width=Math.ceil((t-2*a.columePadding)/i),n.extra.column&&n.extra.column.width&&0<+n.extra.column.width&&(e.width=Math.min(e.width,+n.extra.column.width)),e.x+=(o+.5-i/2)*e.width,e)})}function fixColumeMeterData(e,t,i,o,a,n,l){var r=Math.min;return e.map(function(e){return null===e?null:(e.width=t-2*a.columePadding,e.width=n.extra.column&&n.extra.column.width&&0<+n.extra.column.width?r(e.width,+n.extra.column.width):r(e.width,25),0<o&&(e.width-=2*l),e)})}function fixColumeStackData(e,t,i,o,a,n){var l=Math.min;return e.map(function(e){return null===e?null:(e.width=t-2*a.columePadding,e.width=n.extra.column&&n.extra.column.width&&0<+n.extra.column.width?l(e.width,+n.extra.column.width):l(e.width,25),e)})}function getXAxisPoints(e,t,i){var o=i.yAxisWidth+i.yAxisTitleWidth,a=t.width-2*i.padding-o,n=t.enableScroll?Math.min(t.xAxis.itemCount,e.length):e.length,l=a/n,r=[],s=i.padding+o,d=t.width-i.padding;return e.forEach(function(e,t){r.push(s+t*l)}),!0===t.enableScroll?r.push(s+e.length*l):r.push(d),{xAxisPoints:r,startX:s,endX:d,eachSpacing:l}}function getCandleDataPoints(e,t,i,o,a,n,l){var r=Math.round,s=7<arguments.length&&void 0!==arguments[7]?arguments[7]:1,d=[],h=n.height-2*l.padding-l.xAxisHeight-l.legendHeight;return e.forEach(function(e,c){if(null===e)d.push(null);else{var x=[];e.forEach(function(e){var d={x:o[c]+r(a/2)},p=e.value||e,g=h*(p-t)/(i-t);g*=s,d.y=n.height-l.xAxisHeight-l.legendHeight-r(g)-l.padding,x.push(d)}),d.push(x)}}),d}function getDataPoints(e,t,i,o,a,n,l){var r=Math.round,s=7<arguments.length&&void 0!==arguments[7]?arguments[7]:1,d=[],h=n.height-2*l.padding-l.xAxisHeight-l.legendHeight;return e.forEach(function(e,c){if(null===e)d.push(null);else{var x={color:e.color,x:o[c]+r(a/2)},p=e;"object"==typeof e&&null!=e&&(p=e.value);var g=h*(p-t)/(i-t);g*=s,x.y=n.height-l.xAxisHeight-l.legendHeight-r(g)-l.padding,d.push(x)}}),d}function getStackDataPoints(e,t,i,o,a,n,l,r,s){var d=Math.round,h=9<arguments.length&&void 0!==arguments[9]?arguments[9]:1,c=[],x=n.height-2*l.padding-l.xAxisHeight-l.legendHeight;return e.forEach(function(e,p){if(null===e)c.push(null);else{var g={color:e.color,x:o[p]+d(a/2)};if(0<r){var y=0;for(let e=0;e<=r;e++)y+=s[e].data[p];var f=y-e,u=x*(y-t)/(i-t),m=x*(f-t)/(i-t)}else var y=e,u=x*(y-t)/(i-t),m=0;var T=m;u*=h,T*=h,g.y=n.height-l.xAxisHeight-l.legendHeight-d(u)-l.padding,g.y0=n.height-l.xAxisHeight-l.legendHeight-d(T)-l.padding,c.push(g)}}),c}function getYAxisTextList(e,t,o,a){var n,l=Math.min,r=Math.max;n="stack"==a?dataCombineStack(e):dataCombine(e);var s=[];n=n.filter(function(e){return"object"==typeof e&&null!==e?e.constructor==Array?null!==e:null!==e.value:null!==e}),n.map(function(e){"object"==typeof e?e.constructor==Array?e.map(function(e){s.push(e)}):s.push(e.value):s.push(e)});var d=0,h=0;if(0<s.length&&(d=l.apply(this,s),h=r.apply(this,s)),"number"==typeof t.yAxis.min&&(d=l(t.yAxis.min,d)),"number"==typeof t.yAxis.max&&(h=r(t.yAxis.max,h)),d===h){var c=h||10;h+=c}for(var x=getDataRange(d,h),p=x.minRange,g=x.maxRange,y=[],f=(g-p)/o.yAxisSplit,u=0;u<=o.yAxisSplit;u++)y.push(p+f*u);return y.reverse()}function calYAxisData(e,t,i){var o=assign({},t.extra.column||{type:""}),a=getYAxisTextList(e,t,i,o.type),n=i.yAxisWidth,l=a.map(function(e){return e=util.toFixed(e,2),e=t.yAxis.format?t.yAxis.format(+e):e,n=Math.max(n,measureText(e)+5),e});return!0===t.yAxis.disabled&&(n=0),{rangesFormat:l,ranges:a,yAxisWidth:n}}function calTooltipYAxisData(e,t,i,o){var a=getYAxisTextList(t,i,o),n=i.height-2*o.padding-o.xAxisHeight-o.legendHeight;let l=a[0],r=a[a.length-1],s=o.padding,d=o.padding+n,h=l-(l-r)*(e-s)/(d-s);return h=i.yAxis.format?i.yAxis.format(+h):h,h}function contextRotate(e,t){var i=Math.PI;!0===t.rotateLock?!0!==t._rotate_&&(e.translate(t.height,0),e.rotate(90*i/180),t._rotate_=!0):(e.translate(t.height,0),e.rotate(90*i/180))}function drawPointShape(e,t,i,o,a){o.beginPath(),o.setStrokeStyle("#ffffff"),o.setLineWidth(1*a.pixelRatio),o.setFillStyle(t),"diamond"===i?e.forEach(function(e){null!==e&&(o.moveTo(e.x,e.y-4.5),o.lineTo(e.x-4.5,e.y),o.lineTo(e.x,e.y+4.5),o.lineTo(e.x+4.5,e.y),o.lineTo(e.x,e.y-4.5))}):"circle"===i?e.forEach(function(e){null!==e&&(o.moveTo(e.x+3.5*a.pixelRatio,e.y),o.arc(e.x,e.y,4*a.pixelRatio,0,2*Math.PI,!1))}):"rect"===i?e.forEach(function(e){null!==e&&(o.moveTo(e.x-3.5,e.y-3.5),o.rect(e.x-3.5,e.y-3.5,7,7))}):"triangle"==i&&e.forEach(function(e){null!==e&&(o.moveTo(e.x,e.y-4.5),o.lineTo(e.x-4.5,e.y+4.5),o.lineTo(e.x+4.5,e.y+4.5),o.lineTo(e.x,e.y-4.5))}),o.closePath(),o.fill(),o.stroke()}function drawRingTitle(e,t,i){var o=e.title.fontSize||t.titleFontSize,a=e.subtitle.fontSize||t.subtitleFontSize,n=e.title.name||"",l=e.subtitle.name||"",r=e.title.color||t.titleColor,s=e.subtitle.color||t.subtitleColor,d=n?o:0,h=l?a:0,c=5;if(l){var x=measureText(l,a),p=(e.width-x)/2+(e.subtitle.offsetX||0),g=(e.height-t.legendHeight+a)/2+(e.subtitle.offsetY||0);n&&(g-=(d+c)/2),i.beginPath(),i.setFontSize(a),i.setFillStyle(s),i.fillText(l,p,g),i.closePath(),i.stroke()}if(n){var y=measureText(n,o),f=(e.width-y)/2+(e.title.offsetX||0),u=(e.height-t.legendHeight+o)/2+(e.title.offsetY||0);l&&(u+=(h+c)/2),i.beginPath(),i.setFontSize(o),i.setFillStyle(r),i.fillText(n,f,u),i.closePath(),i.stroke()}}function drawPointText(e,t,i,o){var a=t.data;e.forEach(function(e,n){if(null!==e){o.beginPath(),o.setFontSize(t.textSize||i.fontSize),o.setFillStyle(t.textColor||"#666666");var l=a[n];"object"==typeof a[n]&&null!==a[n]&&(l=a[n].value);var r=t.format?t.format(l):l;o.fillText(r,e.x-measureText(r,t.textSize||i.fontSize)/2,e.y-2),o.closePath(),o.stroke()}})}function drawGaugeLabel(e,t,i,o,a,n){var l=Math.PI;t-=e.width/2+a.gaugeLabelTextMargin;let r=e.startAngle-e.endAngle+1,s=r/e.splitLine.splitNumber,d=e.endNumber-e.startNumber,h=d/e.splitLine.splitNumber,c=e.startAngle,x=e.startNumber;for(let r=0;r<e.splitLine.splitNumber+1;r++){var p={x:t*Math.cos(c*l),y:t*Math.sin(c*l)},g=e.labelFormat?e.labelFormat(x):x;p.x+=i.x-measureText(g)/2,p.y+=i.y;var y=p.x,f=p.y;n.beginPath(),n.setFontSize(a.fontSize),n.setFillStyle(e.labelColor||"#666666"),n.fillText(g,y,f+a.fontSize/2),n.closePath(),n.stroke(),c+=s,2<=c&&(c%=2),x+=h}}function drawRadarLabel(e,t,i,o,a,n){var l=o.extra.radar||{};t+=a.radarLabelTextMargin,e.forEach(function(e,r){var s={x:t*Math.cos(e),y:t*Math.sin(e)},d=convertCoordinateOrigin(s.x,s.y,i),h=d.x,c=d.y;util.approximatelyEqual(s.x,0)?h-=measureText(o.categories[r]||"")/2:0>s.x&&(h-=measureText(o.categories[r]||"")),n.beginPath(),n.setFontSize(a.fontSize),n.setFillStyle(l.labelColor||"#666666"),n.fillText(o.categories[r]||"",h,c+a.fontSize/2),n.closePath(),n.stroke()})}function drawPieText(e,t,o,a,i,n){var l=Math.cos,r=Math.sin,s=Math.min,d=Math.max,h=Math.PI,c=o.pieChartLinePadding,x=[],p=null,g=e.map(function(e){var t=2*h-(e._start_+2*h*e._proportion_/2),i=e.format?e.format(+e._proportion_.toFixed(2)):util.toFixed(100*e._proportion_)+"%",o=e.color,a=e._radius_;return{arc:t,text:i,color:o,radius:a,textColor:e.textColor,textSize:e.textSize}});for(let h=0;h<g.length;h++){let e=g[h],t=l(e.arc)*(e.radius+c),i=r(e.arc)*(e.radius+c),a=l(e.arc)*e.radius,n=r(e.arc)*e.radius,y=0<=t?t+o.pieChartTextPadding:t-o.pieChartTextPadding,f=i,u=measureText(e.text),m=f;p&&util.isSameXCoordinateArea(p.start,{x:y})&&(0<y?m=s(f,p.start.y):0>t?m=d(f,p.start.y):0<f?m=d(f,p.start.y):m=s(f,p.start.y)),0>y&&(y-=u);let T={lineStart:{x:a,y:n},lineEnd:{x:t,y:i},start:{x:y,y:m},width:u,height:o.fontSize,text:e.text,color:e.color,textColor:e.textColor,textSize:e.textSize};p=avoidCollision(T,p),x.push(p)}for(let l=0;l<x.length;l++){let e=x[l],i=convertCoordinateOrigin(e.lineStart.x,e.lineStart.y,n),r=convertCoordinateOrigin(e.lineEnd.x,e.lineEnd.y,n),s=convertCoordinateOrigin(e.start.x,e.start.y,n);a.setLineWidth(1*t.pixelRatio),a.setFontSize(o.fontSize),a.beginPath(),a.setStrokeStyle(e.color),a.setFillStyle(e.color),a.moveTo(i.x,i.y);let d=0>e.start.x?s.x+e.width:s.x,c=0>e.start.x?s.x-5:s.x+5;a.quadraticCurveTo(r.x,r.y,d,s.y),a.moveTo(i.x,i.y),a.stroke(),a.closePath(),a.beginPath(),a.moveTo(s.x+e.width,s.y),a.arc(d,s.y,2,0,2*h),a.closePath(),a.fill(),a.beginPath(),a.setFontSize(e.textSize||o.fontSize),a.setFillStyle(e.textColor||"#666666"),a.fillText(e.text,c,s.y+3),a.closePath(),a.stroke(),a.closePath()}}function drawToolTipSplitLine(e,t,i,o){var a=t.extra.tooltip||{};a.gridType=null==a.gridType?"solid":a.gridType,a.dashLength=null==a.dashLength?4:a.dashLength;var n=i.padding,l=t.height-i.padding-i.xAxisHeight-i.legendHeight;if("dash"==a.gridType&&o.setLineDash([a.dashLength,a.dashLength]),o.beginPath(),o.setStrokeStyle(a.gridColor||"#cccccc"),o.setLineWidth(1*t.pixelRatio),o.moveTo(e,n),o.lineTo(e,l),o.closePath(),o.stroke(),o.setLineDash([]),a.xAxisLabel){let n=t.categories[t.tooltip.index];o.setFontSize(i.fontSize);let r=o.measureText(n).width,s=e-i.toolTipPadding-.5*r,d=l;o.beginPath(),o.setFillStyle(hexToRgb(a.labelBgColor||i.toolTipBackground,a.labelBgOpacity||i.toolTipOpacity)),o.setStrokeStyle(a.labelBgColor||i.toolTipBackground),o.setLineWidth(1*t.pixelRatio),o.rect(s,d,r+2*i.toolTipPadding,i.fontSize+2*i.toolTipPadding),o.closePath(),o.stroke(),o.fill(),o.beginPath(),o.setFontSize(i.fontSize),o.setFillStyle(a.labelFontColor||i.fontColor),o.fillText(n,s+2*i.toolTipPadding,d+i.toolTipPadding+i.fontSize),o.closePath(),o.stroke()}}function drawToolTipHorizentalLine(e,t,i,o){var a=e.extra.tooltip||{};a.gridType=null==a.gridType?"solid":a.gridType,a.dashLength=null==a.dashLength?4:a.dashLength;var n=t.padding+t.yAxisWidth+t.yAxisTitleWidth,l=e.width-t.padding;if("dash"==a.gridType&&i.setLineDash([a.dashLength,a.dashLength]),i.beginPath(),i.setStrokeStyle(a.gridColor||"#cccccc"),i.setLineWidth(1*e.pixelRatio),i.moveTo(n,e.tooltip.offset.y),i.lineTo(l,e.tooltip.offset.y),i.closePath(),i.stroke(),i.setLineDash([]),a.yAxisLabel){let l=calTooltipYAxisData(e.tooltip.offset.y,e.series,e,t,o);i.setFontSize(t.fontSize);let r=i.measureText(l).width,s=n-2*t.toolTipPadding-r,d=e.tooltip.offset.y;i.beginPath(),i.setFillStyle(hexToRgb(a.labelBgColor||t.toolTipBackground,a.labelBgOpacity||t.toolTipOpacity)),i.setStrokeStyle(a.labelBgColor||t.toolTipBackground),i.setLineWidth(1*e.pixelRatio),i.rect(s,d-.5*t.fontSize-t.toolTipPadding,r+2*t.toolTipPadding,t.fontSize+2*t.toolTipPadding),i.closePath(),i.stroke(),i.fill(),i.beginPath(),i.setFontSize(t.fontSize),i.setFillStyle(a.labelFontColor||t.fontColor),i.fillText(l,s+t.toolTipPadding,d+.5*t.fontSize),i.closePath(),i.stroke()}}function drawToolTipSplitArea(e,t,i,o,a){var n=t.extra.tooltip||{activeBgColor:"#000000",activeBgOpacity:.08};n.activeBgColor=n.activeBgColor?n.activeBgColor:"#000000",n.activeBgOpacity=n.activeBgOpacity?n.activeBgOpacity:.08;var l=i.padding,r=t.height-i.padding-i.xAxisHeight-i.legendHeight;o.beginPath(),o.setFillStyle(hexToRgb(n.activeBgColor,n.activeBgOpacity)),o.rect(e-a/2,l,a,r-l),o.closePath(),o.fill()}function drawToolTip(e,t,i,o,a){var n=Math.round,l=i.extra.tooltip||{bgColor:"#000000",bgOpacity:.7,fontColor:"#FFFFFF"};l.bgColor=l.bgColor?l.bgColor:"#000000",l.bgOpacity=l.bgOpacity?l.bgOpacity:.7,l.fontColor=l.fontColor?l.fontColor:"#FFFFFF";var r=4*i.pixelRatio,s=5*i.pixelRatio,d=8*i.pixelRatio,h=!1;("line"==i.type||"area"==i.type||"candle"==i.type||"mix"==i.type)&&drawToolTipSplitLine(i.tooltip.offset.x,i,o,a),t=assign({x:0,y:0},t),t.y-=8*i.pixelRatio;var c=e.map(function(e){return measureText(e.text)}),x=r+s+4*o.toolTipPadding+Math.max.apply(null,c),p=2*o.toolTipPadding+e.length*o.toolTipLineHeight;t.x-Math.abs(i._scrollDistance_)+d+x>i.width&&(h=!0),a.beginPath(),a.setFillStyle(hexToRgb(l.bgColor||o.toolTipBackground,l.bgOpacity||o.toolTipOpacity)),h?(a.moveTo(t.x,t.y+10*i.pixelRatio),a.lineTo(t.x-d,t.y+10*i.pixelRatio-5*i.pixelRatio),a.lineTo(t.x-d,t.y),a.lineTo(t.x-d-n(x),t.y),a.lineTo(t.x-d-n(x),t.y+p),a.lineTo(t.x-d,t.y+p),a.lineTo(t.x-d,t.y+10*i.pixelRatio+5*i.pixelRatio),a.lineTo(t.x,t.y+10*i.pixelRatio)):(a.moveTo(t.x,t.y+10*i.pixelRatio),a.lineTo(t.x+d,t.y+10*i.pixelRatio-5*i.pixelRatio),a.lineTo(t.x+d,t.y),a.lineTo(t.x+d+n(x),t.y),a.lineTo(t.x+d+n(x),t.y+p),a.lineTo(t.x+d,t.y+p),a.lineTo(t.x+d,t.y+10*i.pixelRatio+5*i.pixelRatio),a.lineTo(t.x,t.y+10*i.pixelRatio)),a.closePath(),a.fill(),e.forEach(function(e,i){if(null!==e.color){a.beginPath(),a.setFillStyle(e.color);var n=t.x+d+2*o.toolTipPadding,l=t.y+(o.toolTipLineHeight-o.fontSize)/2+o.toolTipLineHeight*i+o.toolTipPadding+1;h&&(n=t.x-x-d+2*o.toolTipPadding),a.fillRect(n,l,r,o.fontSize),a.closePath()}}),e.forEach(function(e,i){var n=t.x+d+2*o.toolTipPadding+r+s;h&&(n=t.x-x-d+2*o.toolTipPadding+ +r+s);var c=t.y+(o.toolTipLineHeight-o.fontSize)/2+o.toolTipLineHeight*i+o.toolTipPadding;a.beginPath(),a.setFontSize(o.fontSize),a.setFillStyle(l.fontColor),a.fillText(e.text,n,c+o.fontSize),a.closePath(),a.stroke()})}function drawYAxisTitle(e,t,i,o){var a=i.xAxisHeight+(t.height-i.xAxisHeight-measureText(e))/2;o.save(),o.beginPath(),o.setFontSize(i.fontSize),o.setFillStyle(t.yAxis.titleFontColor||"#333333"),o.translate(0,t.height),o.rotate(-90*Math.PI/180),o.fillText(e,a,i.padding+.5*i.fontSize),o.closePath(),o.stroke(),o.restore()}function drawColumnDataPoints(e,t,i,o){var a=4<arguments.length&&void 0!==arguments[4]?arguments[4]:1,n=t.extra.column||{type:{},meter:{}};n.type=null==n.type?"group":n.type,n.meter=n.meter||{},n.meter.border=null==n.meter.border?4:n.meter.border,n.meter.fillColor=null==n.meter.fillColor?"#FFFFFF":n.meter.fillColor;var l=calYAxisData(e,t,i),r=l.ranges,s=getXAxisPoints(t.categories,t,i),d=s.xAxisPoints,h=s.eachSpacing,c=r.pop(),x=r.shift(),p=[];return o.save(),t._scrollDistance_&&0!==t._scrollDistance_&&!0===t.enableScroll&&o.translate(t._scrollDistance_,0),t.tooltip&&t.tooltip.textList&&t.tooltip.textList.length&&1===a&&drawToolTipSplitArea(t.tooltip.offset.x,t,i,o,h),e.forEach(function(l,r){var s=l.data;switch(n.type){case"group":var g=getDataPoints(s,c,x,d,h,t,i,a),y=getStackDataPoints(s,c,x,d,h,t,i,r,e,a);p.push(y),g=fixColumeData(g,h,e.length,r,i,t),g.forEach(function(e){if(null!==e){o.beginPath(),o.setFillStyle(e.color||l.color);var a=e.x-e.width/2+1,n=t.height-e.y-i.padding-i.xAxisHeight-i.legendHeight;o.moveTo(a,e.y),o.fillRect(a,e.y,e.width-2,n),o.closePath(),o.fill()}});break;case"stack":var g=getStackDataPoints(s,c,x,d,h,t,i,r,e,a);p.push(g),g=fixColumeStackData(g,h,e.length,r,i,t,e),g.forEach(function(e){if(null!==e){o.beginPath(),o.setFillStyle(e.color||l.color);var a=e.x-e.width/2+1,n=t.height-e.y-i.padding-i.xAxisHeight-i.legendHeight,s=t.height-e.y0-i.padding-i.xAxisHeight-i.legendHeight;0<r&&(n-=s),o.moveTo(a,e.y),o.fillRect(a,e.y,e.width-2,n),o.closePath(),o.fill()}});break;case"meter":var g=getDataPoints(s,c,x,d,h,t,i,a);p.push(g),g=fixColumeMeterData(g,h,e.length,r,i,t,n.meter.border),0==r?g.forEach(function(e){if(null!==e){o.beginPath(),o.setFillStyle(n.meter.fillColor);var a=e.x-e.width/2,r=t.height-e.y-i.padding-i.xAxisHeight-i.legendHeight;o.moveTo(a,e.y),o.fillRect(a,e.y,e.width,r),o.closePath(),o.fill(),0<n.meter.border&&(o.beginPath(),o.setStrokeStyle(l.color),o.setLineWidth(n.meter.border*t.pixelRatio),o.moveTo(a+.5*n.meter.border,e.y+r),o.lineTo(a+.5*n.meter.border,e.y+.5*n.meter.border),o.lineTo(a+e.width-.5*n.meter.border,e.y+.5*n.meter.border),o.lineTo(a+e.width-.5*n.meter.border,e.y+r),o.stroke())}}):g.forEach(function(e){if(null!==e){o.beginPath(),o.setFillStyle(e.color||l.color);var a=e.x-e.width/2,n=t.height-e.y-i.padding-i.xAxisHeight-i.legendHeight;o.moveTo(a,e.y),o.fillRect(a,e.y,e.width,n),o.closePath(),o.fill()}});}}),!1!==t.dataLabel&&1===a&&e.forEach(function(l,r){var s=l.data;switch(n.type){case"group":var p=getDataPoints(s,c,x,d,h,t,i,a);p=fixColumeData(p,h,e.length,r,i,t),drawPointText(p,l,i,o);break;case"stack":var p=getStackDataPoints(s,c,x,d,h,t,i,r,e,a);drawPointText(p,l,i,o);break;case"meter":var p=getDataPoints(s,c,x,d,h,t,i,a);drawPointText(p,l,i,o);}}),o.restore(),{xAxisPoints:d,calPoints:p,eachSpacing:h}}function drawCandleDataPoints(e,t,i,o,a){var n=5<arguments.length&&void 0!==arguments[5]?arguments[5]:1,l=i.extra.candle||{color:{},average:{}};l.color.upLine=l.color.upLine?l.color.upLine:"#f04864",l.color.upFill=l.color.upFill?l.color.upFill:"#f04864",l.color.downLine=l.color.downLine?l.color.downLine:"#2fc25b",l.color.downFill=l.color.downFill?l.color.downFill:"#2fc25b",l.average.show=!0===l.average.show,l.average.name=l.average.name?l.average.name:[],l.average.day=l.average.day?l.average.day:[],l.average.color=l.average.color?l.average.color:["#1890ff","#2fc25b","#facc14","#f04864","#8543e0","#90ed7d"],i.extra.candle=l;var r=calYAxisData(e,i,o),s=r.ranges,d=getXAxisPoints(i.categories,i,o),h=d.xAxisPoints,c=d.eachSpacing,x=s.pop(),p=s.shift(),g=[];return a.save(),i._scrollDistance_&&0!==i._scrollDistance_&&!0===i.enableScroll&&a.translate(i._scrollDistance_,0),l.average.show&&t.forEach(function(e){var t=e.data,l=getDataPoints(t,x,p,h,c,i,o,n),r=splitPoints(l);r.forEach(function(t){a.beginPath(),a.setStrokeStyle(e.color),a.setLineWidth(1),1===t.length?(a.moveTo(t[0].x,t[0].y),a.arc(t[0].x,t[0].y,1,0,2*Math.PI)):(a.moveTo(t[0].x,t[0].y),t.forEach(function(e,i){if(0<i){var o=createCurveControlPoints(t,i-1);a.bezierCurveTo(o.ctrA.x,o.ctrA.y,o.ctrB.x,o.ctrB.y,e.x,e.y)}}),a.moveTo(t[0].x,t[0].y)),a.closePath(),a.stroke()})}),e.forEach(function(e){var t=e.data,r=getCandleDataPoints(t,x,p,h,c,i,o,n);g.push(r);var s=splitPoints(r);s=s[0],s.forEach(function(e,o){a.beginPath(),0<t[o][1]-t[o][0]?(a.setStrokeStyle(l.color.upLine),a.setFillStyle(l.color.upFill),a.setLineWidth(1*i.pixelRatio),a.moveTo(e[3].x,e[3].y),a.lineTo(e[1].x,e[1].y),a.lineTo(e[1].x-c/4,e[1].y),a.lineTo(e[0].x-c/4,e[0].y),a.lineTo(e[0].x,e[0].y),a.lineTo(e[2].x,e[2].y),a.lineTo(e[0].x,e[0].y),a.lineTo(e[0].x+c/4,e[0].y),a.lineTo(e[1].x+c/4,e[1].y),a.lineTo(e[1].x,e[1].y),a.moveTo(e[3].x,e[3].y)):(a.setStrokeStyle(l.color.downLine),a.setFillStyle(l.color.downFill),a.setLineWidth(1*i.pixelRatio),a.moveTo(e[3].x,e[3].y),a.lineTo(e[0].x,e[0].y),a.lineTo(e[0].x-c/4,e[0].y),a.lineTo(e[1].x-c/4,e[1].y),a.lineTo(e[1].x,e[1].y),a.lineTo(e[2].x,e[2].y),a.lineTo(e[1].x,e[1].y),a.lineTo(e[1].x+c/4,e[1].y),a.lineTo(e[0].x+c/4,e[0].y),a.lineTo(e[0].x,e[0].y),a.moveTo(e[3].x,e[3].y)),a.closePath(),a.fill(),a.stroke()})}),a.restore(),{xAxisPoints:h,calPoints:g,eachSpacing:c}}function drawAreaDataPoints(e,t,i,o){var a=4<arguments.length&&void 0!==arguments[4]?arguments[4]:1,n=t.extra.area||{type:"straight",opacity:.5,addLine:!1,width:2};n.type=n.type?n.type:"straight",n.opacity=n.opacity?n.opacity:.2,n.addLine=!0==n.addLine,n.width=n.width?n.width:2;var l=calYAxisData(e,t,i),r=l.ranges,s=getXAxisPoints(t.categories,t,i),d=s.xAxisPoints,h=s.eachSpacing,c=r.pop(),x=r.shift(),p=t.height-i.padding-i.xAxisHeight-i.legendHeight,g=[];return o.save(),t._scrollDistance_&&0!==t._scrollDistance_&&!0===t.enableScroll&&o.translate(t._scrollDistance_,0),t.tooltip&&t.tooltip.textList&&t.tooltip.textList.length&&1===a&&drawToolTipSplitLine(t.tooltip.offset.x,t,i,o),e.forEach(function(e,l){let r=e.data,s=getDataPoints(r,c,x,d,h,t,i,a);g.push(s);let y=splitPoints(s);for(let a,r=0;r<y.length;r++){if(a=y[r],o.beginPath(),o.setStrokeStyle(hexToRgb(e.color,n.opacity)),o.setFillStyle(hexToRgb(e.color,n.opacity)),o.setLineWidth(n.width*t.pixelRatio),1<a.length){let e=a[0],t=a[a.length-1];o.moveTo(e.x,e.y),"curve"===n.type?a.forEach(function(e,t){if(0<t){let i=createCurveControlPoints(a,t-1);o.bezierCurveTo(i.ctrA.x,i.ctrA.y,i.ctrB.x,i.ctrB.y,e.x,e.y)}}):a.forEach(function(e,t){0<t&&o.lineTo(e.x,e.y)}),o.lineTo(t.x,p),o.lineTo(e.x,p),o.lineTo(e.x,e.y)}else{let e=a[0];o.moveTo(e.x-h/2,e.y),o.lineTo(e.x+h/2,e.y),o.lineTo(e.x+h/2,p),o.lineTo(e.x-h/2,p),o.moveTo(e.x-h/2,e.y)}o.closePath(),o.fill(),n.addLine&&(o.beginPath(),o.setStrokeStyle(e.color),o.setLineWidth(n.width*t.pixelRatio),1===a.length?(o.moveTo(a[0].x,a[0].y),o.arc(a[0].x,a[0].y,1,0,2*Math.PI)):(o.moveTo(a[0].x,a[0].y),"curve"===n.type?a.forEach(function(e,t){if(0<t){let i=createCurveControlPoints(a,t-1);o.bezierCurveTo(i.ctrA.x,i.ctrA.y,i.ctrB.x,i.ctrB.y,e.x,e.y)}}):a.forEach(function(e,t){0<t&&o.lineTo(e.x,e.y)}),o.moveTo(a[0].x,a[0].y)),o.closePath(),o.stroke())}if(!1!==t.dataPointShape){var f=i.dataPointShape[l%i.dataPointShape.length];drawPointShape(s,e.color,f,o,t)}}),!1!==t.dataLabel&&1===a&&e.forEach(function(e){var n=e.data,l=getDataPoints(n,c,x,d,h,t,i,a);drawPointText(l,e,i,o)}),o.restore(),{xAxisPoints:d,calPoints:g,eachSpacing:h}}function drawLineDataPoints(e,t,i,o){var a=4<arguments.length&&void 0!==arguments[4]?arguments[4]:1,n=t.extra.line||{type:"straight",width:2};n.type=n.type?n.type:"straight",n.width=n.width?n.width:2;var l=calYAxisData(e,t,i),r=l.ranges,s=getXAxisPoints(t.categories,t,i),d=s.xAxisPoints,h=s.eachSpacing,c=r.pop(),x=r.shift(),p=[];return o.save(),t._scrollDistance_&&0!==t._scrollDistance_&&!0===t.enableScroll&&o.translate(t._scrollDistance_,0),t.tooltip&&t.tooltip.textList&&t.tooltip.textList.length&&1===a&&drawToolTipSplitLine(t.tooltip.offset.x,t,i,o),e.forEach(function(e,l){var r=e.data,s=getDataPoints(r,c,x,d,h,t,i,a);p.push(s);var g=splitPoints(s);if(g.forEach(function(i){o.beginPath(),o.setStrokeStyle(e.color),o.setLineWidth(n.width*t.pixelRatio),1===i.length?(o.moveTo(i[0].x,i[0].y),o.arc(i[0].x,i[0].y,1,0,2*Math.PI)):(o.moveTo(i[0].x,i[0].y),"curve"===n.type?i.forEach(function(e,t){if(0<t){var a=createCurveControlPoints(i,t-1);o.bezierCurveTo(a.ctrA.x,a.ctrA.y,a.ctrB.x,a.ctrB.y,e.x,e.y)}}):i.forEach(function(e,t){0<t&&o.lineTo(e.x,e.y)}),o.moveTo(i[0].x,i[0].y)),o.closePath(),o.stroke()}),!1!==t.dataPointShape){var y=i.dataPointShape[l%i.dataPointShape.length];drawPointShape(s,e.color,y,o,t)}}),!1!==t.dataLabel&&1===a&&e.forEach(function(e){var n=e.data,l=getDataPoints(n,c,x,d,h,t,i,a);drawPointText(l,e,i,o)}),o.restore(),{xAxisPoints:d,calPoints:p,eachSpacing:h}}function drawMixDataPoints(e,t,i,o){var a=Math.PI,n=4<arguments.length&&void 0!==arguments[4]?arguments[4]:1,l=calYAxisData(e,t,i),r=l.ranges,s=getXAxisPoints(t.categories,t,i),d=s.xAxisPoints,h=s.eachSpacing,c=r.pop(),x=r.shift(),p=t.height-i.padding-i.xAxisHeight-i.legendHeight,g=[],y=0,f=0;if(e.forEach(function(e){"column"==e.type&&(f+=1)}),o.save(),t._scrollDistance_&&0!==t._scrollDistance_&&!0===t.enableScroll&&o.translate(t._scrollDistance_,0),t.tooltip&&t.tooltip.textList&&t.tooltip.textList.length&&1===n&&drawToolTipSplitLine(t.tooltip.offset.x,t,i,o),e.forEach(function(e,l){var r=e.data,s=getDataPoints(r,c,x,d,h,t,i,n);if(g.push(s),"column"==e.type&&(s=fixColumeData(s,h,f,y,i,t),s.forEach(function(a){if(null!==a){o.beginPath(),o.setFillStyle(a.color||e.color);var n=a.x-a.width/2+1,l=t.height-a.y-i.padding-i.xAxisHeight-i.legendHeight;o.moveTo(n,a.y),o.rect(n,a.y,a.width-2,l),o.closePath(),o.fill()}}),y+=1),"area"==e.type){let a=splitPoints(s);for(let n,l=0;l<a.length;l++){if(n=a[l],o.beginPath(),o.setStrokeStyle(e.color),o.setFillStyle(e.color),o.setGlobalAlpha(.2),o.setLineWidth(2*t.pixelRatio),1<n.length){var u=n[0];let t=n[n.length-1];o.moveTo(u.x,u.y),"curve"===e.style?n.forEach(function(e,t){if(0<t){var i=createCurveControlPoints(n,t-1);o.bezierCurveTo(i.ctrA.x,i.ctrA.y,i.ctrB.x,i.ctrB.y,e.x,e.y)}}):n.forEach(function(e,t){0<t&&o.lineTo(e.x,e.y)}),o.lineTo(t.x,p),o.lineTo(u.x,p),o.lineTo(u.x,u.y)}else{let e=n[0];o.moveTo(e.x-h/2,e.y),o.lineTo(e.x+h/2,e.y),o.lineTo(e.x+h/2,p),o.lineTo(e.x-h/2,p),o.moveTo(e.x-h/2,e.y)}o.closePath(),o.fill(),o.setGlobalAlpha(1)}}if("line"==e.type){var m=splitPoints(s);m.forEach(function(i){o.beginPath(),o.setStrokeStyle(e.color),o.setLineWidth(2*t.pixelRatio),1===i.length?(o.moveTo(i[0].x,i[0].y),o.arc(i[0].x,i[0].y,1,0,2*a)):(o.moveTo(i[0].x,i[0].y),"curve"==e.style?i.forEach(function(e,t){if(0<t){var a=createCurveControlPoints(i,t-1);o.bezierCurveTo(a.ctrA.x,a.ctrA.y,a.ctrB.x,a.ctrB.y,e.x,e.y)}}):i.forEach(function(e,t){0<t&&o.lineTo(e.x,e.y)}),o.moveTo(i[0].x,i[0].y)),o.closePath(),o.stroke()})}if("point"==e.type&&s.forEach(function(i){i&&(o.beginPath(),o.setFillStyle(e.color),o.setStrokeStyle("#FFFFFF"),o.setLineWidth(1*t.pixelRatio),o.moveTo(i.x+3.5*t.pixelRatio,i.y),o.arc(i.x,i.y,4*t.pixelRatio,0,2*a),o.closePath(),o.fill(),o.stroke())}),!0==e.addPoint&&"column"!==e.type){var T=i.dataPointShape[l%i.dataPointShape.length];drawPointShape(s,e.color,T,o,t)}}),!1!==t.dataLabel&&1===n){var y=0;e.forEach(function(e){var a=e.data,l=getDataPoints(a,c,x,d,h,t,i,n);"column"===e.type?(l=fixColumeData(l,h,f,y,i,t),drawPointText(l,e,i,o),y+=1):drawPointText(l,e,i,o)})}return o.restore(),{xAxisPoints:d,calPoints:g,eachSpacing:h}}function drawToolTipBridge(e,t,i,o,a,n){var l=e.extra.tooltip||{};l.horizentalLine&&e.tooltip&&1===o&&("line"==e.type||"area"==e.type||"column"==e.type||"candle"==e.type||"mix"==e.type)&&drawToolTipHorizentalLine(e,t,i,a,n),i.save(),e._scrollDistance_&&0!==e._scrollDistance_&&!0===e.enableScroll&&i.translate(e._scrollDistance_,0),e.tooltip&&e.tooltip.textList&&e.tooltip.textList.length&&1===o&&drawToolTip(e.tooltip.textList,e.tooltip.offset,e,t,i,a,n),i.restore()}function drawXAxis(e,t,i,o){var a=Math.ceil,n=getXAxisPoints(e,t,i),l=n.xAxisPoints,r=n.startX,s=n.endX,d=n.eachSpacing,h=t.height-i.padding-i.xAxisHeight-i.legendHeight,c=i.padding;if(t.enableScroll&&t.xAxis.scrollShow){var x=t.height-i.padding-i.legendHeight+6*t.pixelRatio,p=s-r,g=d*(l.length-1),y=0;t._scrollDistance_&&(y=-t._scrollDistance_*p/g),o.beginPath(),o.setLineCap("round"),o.setLineWidth(6*t.pixelRatio),o.setStrokeStyle(t.xAxis.scrollBackgroundColor||"#EFEBEF"),o.moveTo(r,x),o.lineTo(s,x),o.stroke(),o.closePath(),o.beginPath(),o.setLineCap("round"),o.setLineWidth(6*t.pixelRatio),o.setStrokeStyle(t.xAxis.scrollColor||"#A6A6A6"),o.moveTo(r+y,x),o.lineTo(r+y+p*p/g,x),o.stroke(),o.setLineCap("butt"),o.closePath()}if(o.save(),t._scrollDistance_&&0!==t._scrollDistance_&&o.translate(t._scrollDistance_,0),o.beginPath(),o.setStrokeStyle(t.xAxis.gridColor||"#cccccc"),o.setLineCap("butt"),o.setLineWidth(1*t.pixelRatio),"dash"==t.xAxis.gridType&&o.setLineDash([t.xAxis.dashLength,t.xAxis.dashLength]),!0!==t.xAxis.disableGrid&&("calibration"===t.xAxis.type?l.forEach(function(e,i){0<i&&(o.moveTo(e-d/2,h),o.lineTo(e-d/2,h+4*t.pixelRatio))}):(t.xAxis.gridEval=t.xAxis.gridEval||1,l.forEach(function(e,i){0==i%t.xAxis.gridEval&&(o.moveTo(e,h),o.lineTo(e,c))}))),o.closePath(),o.stroke(),o.setLineDash([]),!0!==t.xAxis.disabled){let n=t.width-2*i.padding-i.yAxisWidth-i.yAxisTitleWidth,r=e.length;t.xAxis.labelCount&&(r=t.xAxis.itemCount?a(e.length/t.xAxis.itemCount*t.xAxis.labelCount):t.xAxis.labelCount,r-=1);let s=a(e.length/r),c=[],x=e.length;for(let t=0;t<x;t++)0==t%s?c.push(e[t]):c.push("");c[x-1]=e[x-1];var f=t.xAxis.fontSize||i.fontSize;0===i._xAxisTextAngle_?c.forEach(function(e,i){var a=d/2-measureText(e,f)/2;o.beginPath(),o.setFontSize(f),o.setFillStyle(t.xAxis.fontColor||"#666666"),o.fillText(e,l[i]+a,h+f+5),o.closePath(),o.stroke()}):c.forEach(function(e,a){o.save(),o.beginPath(),o.setFontSize(f),o.setFillStyle(t.xAxis.fontColor||"#666666");var n=measureText(e),r=calRotateTranslate(l[a]+d/2,h+f/2+5,t.height),s=r.transX,c=r.transY;o.rotate(-1*i._xAxisTextAngle_),o.translate(s,c),o.fillText(e,l[a]+(d/2-n),h+f+5),o.closePath(),o.stroke(),o.restore()})}o.restore()}function drawYAxisGrid(e,t,o,a){if(!0!==t.yAxis.disableGrid){for(var n=t.height-2*o.padding-o.xAxisHeight-o.legendHeight,l=Math.floor(n/o.yAxisSplit),r=o.yAxisWidth+o.yAxisTitleWidth,s=o.padding+r,d=getXAxisPoints(e,t,o),h=d.xAxisPoints,c=d.eachSpacing,x=c*(h.length-1),p=s+x,g=[],y=0;y<o.yAxisSplit;y++)g.push(o.padding+l*y);g.push(o.padding+l*o.yAxisSplit+2),a.save(),t._scrollDistance_&&0!==t._scrollDistance_&&a.translate(t._scrollDistance_,0),"dash"==t.yAxis.gridType&&a.setLineDash([t.yAxis.dashLength,t.yAxis.dashLength]),a.beginPath(),a.setStrokeStyle(t.yAxis.gridColor||"#cccccc"),a.setLineWidth(1*t.pixelRatio),g.forEach(function(e){a.moveTo(s,e),a.lineTo(p,e)}),a.closePath(),a.stroke(),a.setLineDash([]),a.restore()}}function drawYAxis(e,t,o,a){if(!0!==t.yAxis.disabled){var n=calYAxisData(e,t,o),l=n.rangesFormat,r=o.yAxisWidth+o.yAxisTitleWidth,s=t.height-2*o.padding-o.xAxisHeight-o.legendHeight,d=Math.floor(s/o.yAxisSplit),h=o.padding+r,c=t.width-o.padding,x=t.height-o.padding-o.xAxisHeight-o.legendHeight+o.xAxisTextPadding;a.beginPath(),a.setFillStyle(t.background||"#ffffff"),0>t._scrollDistance_&&a.fillRect(0,0,h,x+o.xAxisHeight),a.fillRect(c,0,t.width,x+o.xAxisHeight),a.closePath(),a.stroke();for(var p=[],g=0;g<=o.yAxisSplit;g++)p.push(o.padding+d*g);var y=t.yAxis.fontSize||o.fontSize;l.forEach(function(e,i){var n=p[i]?p[i]:x;a.beginPath(),a.setFontSize(y),a.setFillStyle(t.yAxis.fontColor||"#666666"),a.fillText(e,o.padding+o.yAxisTitleWidth,n+y/2),a.closePath(),a.stroke()}),t.yAxis.title&&drawYAxisTitle(t.yAxis.title,t,o,a)}}function drawLegend(e,t,o,a){var n=Math.PI;if(!1!==t.legend){var i=calLegendData(e,t,o),l=i.legendList,r=5*t.pixelRatio,s=10*t.pixelRatio,d=15*t.pixelRatio;l.forEach(function(e,i){var l=0;for(let t,o=0;o<e.length;o++)t=e[o],t.name=t.name||"undefined",l+=3*r+measureText(t.name)+d;var h=(t.width-l)/2+r,c=t.height-o.padding-o.legendHeight+i*(o.fontSize+s)+r+s;a.setFontSize(o.fontSize);for(let l,s=0;s<e.length;s++){switch(l=e[s],t.type){case"line":a.beginPath(),a.setLineWidth(1*t.pixelRatio),a.setStrokeStyle(l.color),a.setFillStyle(l.color),a.moveTo(h+7.5*t.pixelRatio,c+5*t.pixelRatio),a.arc(h+7.5*t.pixelRatio,c+5*t.pixelRatio,6*t.pixelRatio,0,2*n),a.closePath(),a.fill(),a.stroke();break;case"pie":a.beginPath(),a.setLineWidth(1*t.pixelRatio),a.setStrokeStyle(l.color),a.setFillStyle(l.color),a.moveTo(h+7.5*t.pixelRatio,c+5*t.pixelRatio),a.arc(h+7.5*t.pixelRatio,c+5*t.pixelRatio,6*t.pixelRatio,0,2*n),a.closePath(),a.fill(),a.stroke();break;case"ring":case"rose":a.beginPath(),a.setLineWidth(1*t.pixelRatio),a.setStrokeStyle(l.color),a.setFillStyle(l.color),a.moveTo(h+7.5*t.pixelRatio,c+5*t.pixelRatio),a.arc(h+7.5*t.pixelRatio,c+5*t.pixelRatio,6*t.pixelRatio,0,2*n),a.closePath(),a.fill(),a.stroke();break;case"gauge":break;case"arcbar":break;default:a.beginPath(),a.setLineWidth(1*t.pixelRatio),a.setStrokeStyle(l.color),a.setFillStyle(l.color),a.moveTo(h,c),a.fillRect(h,c,15*t.pixelRatio,10*t.pixelRatio),a.closePath(),a.fill(),a.stroke();}h+=r+d,a.beginPath(),a.setFontSize(o.fontSize),a.setFillStyle(t.extra.legendTextColor||"#333333"),a.fillText(l.name,h,c+6*t.pixelRatio+3*t.pixelRatio),a.closePath(),a.stroke(),h+=measureText(l.name)+2*r}})}}function drawPieDataPoints(e,t,o,a){var n=Math.PI,l=4<arguments.length&&void 0!==arguments[4]?arguments[4]:1,r=t.extra.pie||{},s={x:t.width/2,y:(t.height-o.legendHeight)/2},d=Math.min(s.x-o.pieChartLinePadding-o.pieChartTextPadding-o._pieTextMaxLength_,s.y-o.pieChartLinePadding-o.pieChartTextPadding);d-=t.dataLabel?10:2*o.padding,e=getPieDataPoints(e,d,l);var h=o.pieChartLinePadding/2;if(e=e.map(function(e){return e._start_+=(r.offsetAngle||0)*n/180,e}),e.forEach(function(e,i){t.tooltip&&t.tooltip.index==i&&(a.beginPath(),a.setFillStyle(hexToRgb(e.color,t.extra.pie.activeOpacity||.5)),a.moveTo(s.x,s.y),a.arc(s.x,s.y,e._radius_+h,e._start_,e._start_+2*e._proportion_*n),a.closePath(),a.fill()),a.beginPath(),a.setLineWidth(2*t.pixelRatio),a.lineJoin="round",a.setStrokeStyle("#ffffff"),a.setFillStyle(e.color),a.moveTo(s.x,s.y),a.arc(s.x,s.y,e._radius_,e._start_,e._start_+2*e._proportion_*n),a.closePath(),a.fill(),!0!==t.disablePieStroke&&a.stroke()}),"ring"===t.type){var c=.6*d;"number"==typeof t.extra.pie.ringWidth&&0<t.extra.pie.ringWidth&&(c=Math.max(0,d-t.extra.pie.ringWidth)),a.beginPath(),a.setFillStyle(t.background||"#ffffff"),a.moveTo(s.x,s.y),a.arc(s.x,s.y,c,0,2*n),a.closePath(),a.fill()}if(!1!==t.dataLabel&&1===l){for(var x=!1,p=0,g=e.length;p<g;p++)if(0<e[p].data){x=!0;break}x&&drawPieText(e,t,o,a,d,s)}return 1===l&&"ring"===t.type&&drawRingTitle(t,o,a),{center:s,radius:d,series:e}}function drawRoseDataPoints(e,t,o,a){var n=Math.PI,l=4<arguments.length&&void 0!==arguments[4]?arguments[4]:1,r=t.extra.rose||{};r.type=r.type||"area";var s={x:t.width/2,y:(t.height-o.legendHeight)/2},d=Math.min(s.x-o.pieChartLinePadding-o.pieChartTextPadding-o._pieTextMaxLength_,s.y-o.pieChartLinePadding-o.pieChartTextPadding);d-=t.dataLabel?10:2*o.padding;var h=r.minRadius||.5*d;e=getRoseDataPoints(e,r.type,h,d,l);var c=o.pieChartLinePadding/2;if(e=e.map(function(e){return e._start_+=(r.offsetAngle||0)*n/180,e}),e.forEach(function(e,i){t.tooltip&&t.tooltip.index==i&&(a.beginPath(),a.setFillStyle(hexToRgb(e.color,r.activeOpacity||.5)),a.moveTo(s.x,s.y),a.arc(s.x,s.y,c+e._radius_,e._start_,e._start_+2*e._proportion_*n),a.closePath(),a.fill()),a.beginPath(),a.setLineWidth(2*t.pixelRatio),a.lineJoin="round",a.setStrokeStyle("#ffffff"),a.setFillStyle(e.color),a.moveTo(s.x,s.y),a.arc(s.x,s.y,e._radius_,e._start_,e._start_+2*e._proportion_*n),a.closePath(),a.fill(),!0!==t.disablePieStroke&&a.stroke()}),!1!==t.dataLabel&&1===l){for(var x=!1,p=0,g=e.length;p<g;p++)if(0<e[p].data){x=!0;break}x&&drawPieText(e,t,o,a,d,s)}return{center:s,radius:d,series:e}}function drawArcbarDataPoints(e,t,i,o){var a=Math.PI,n=4<arguments.length&&void 0!==arguments[4]?arguments[4]:1,l=t.extra.arcbar||{};l.startAngle=l.startAngle?l.startAngle:.75,l.endAngle=l.endAngle?l.endAngle:.25,l.type=l.type?l.type:"default",e=getArcbarDataPoints(e,l,n);var r={x:t.width/2,y:t.height/2},s=Math.min(r.x,r.y);l.width="number"==typeof l.width&&0<l.width?l.width:12*t.pixelRatio,s-=i.padding+l.width/2,o.setLineWidth(l.width),o.setStrokeStyle(l.backgroundColor||"#E9E9E9"),o.setLineCap("round"),o.beginPath(),"default"==l.type?o.arc(r.x,r.y,s,l.startAngle*a,l.endAngle*a,!1):o.arc(r.x,r.y,s,0,2*a,!1),o.stroke();for(let n,d=0;d<e.length;d++)n=e[d],o.setLineWidth(l.width),o.setStrokeStyle(n.color),o.setLineCap("round"),o.beginPath(),o.arc(r.x,r.y,s,l.startAngle*a,n._proportion_*a,!1),o.stroke();return drawRingTitle(t,i,o),{center:r,radius:s,series:e}}function drawGaugeDataPoints(e,t,o,i,a){var n=Math.PI,l=5<arguments.length&&void 0!==arguments[5]?arguments[5]:1,r=o.extra.gauge||{};r.startAngle=r.startAngle?r.startAngle:.75,null==r.oldAngle&&(r.oldAngle=r.startAngle),null==r.oldData&&(r.oldData=0),r.endAngle=r.endAngle?r.endAngle:.25,e=getGaugeAxisPoints(e,r.startAngle,r.endAngle);var s={x:o.width/2,y:o.height/2},d=Math.min(s.x,s.y);r.width="number"==typeof r.width&&0<r.width?r.width:15*o.pixelRatio,d-=i.padding+r.width/2;var h=d-r.width;a.setLineWidth(r.width),a.setLineCap("butt");for(let l,r=0;r<e.length;r++)l=e[r],a.beginPath(),a.setStrokeStyle(l.color),a.arc(s.x,s.y,d,l._startAngle_*n,l._endAngle_*n,!1),a.stroke();a.save();let c=r.startAngle-r.endAngle+1;r.splitLine.fixRadius=r.splitLine.fixRadius?r.splitLine.fixRadius:0,r.splitLine.splitNumber=r.splitLine.splitNumber?r.splitLine.splitNumber:10,r.splitLine.width=r.splitLine.width?r.splitLine.width:15*o.pixelRatio,r.splitLine.color=r.splitLine.color?r.splitLine.color:"#FFFFFF",r.splitLine.childNumber=r.splitLine.childNumber?r.splitLine.childNumber:5,r.splitLine.childWidth=r.splitLine.childWidth?r.splitLine.childWidth:5*o.pixelRatio;let x=c/r.splitLine.splitNumber,p=c/r.splitLine.splitNumber/r.splitLine.childNumber,g=-d-.5*r.width-r.splitLine.fixRadius,y=-d-.5*r.width-r.splitLine.fixRadius+r.splitLine.width,f=-d-.5*r.width-r.splitLine.fixRadius+r.splitLine.childWidth;a.translate(s.x,s.y),a.rotate((r.startAngle-1)*n);for(let l=0;l<r.splitLine.splitNumber+1;l++)a.beginPath(),a.setStrokeStyle(r.splitLine.color),a.setLineWidth(2*o.pixelRatio),a.moveTo(g,0),a.lineTo(y,0),a.stroke(),a.rotate(x*n);a.restore(),a.save(),a.translate(s.x,s.y),a.rotate((r.startAngle-1)*n);for(let l=0;l<r.splitLine.splitNumber*r.splitLine.childNumber+1;l++)a.beginPath(),a.setStrokeStyle(r.splitLine.color),a.setLineWidth(1*o.pixelRatio),a.moveTo(g,0),a.lineTo(f,0),a.stroke(),a.rotate(p*n);a.restore(),r.pointer.width=r.pointer.width?r.pointer.width:15*o.pixelRatio,null==r.pointer.color||"auto"==r.pointer.color?"auto"==r.pointer.color:r.pointer.color==r.pointer.color,t=getGaugeDataPoints(t,e,r,l);for(let l,d=0;d<t.length;d++)l=t[d],a.save(),a.translate(s.x,s.y),a.rotate((l._proportion_-1)*n),a.beginPath(),a.setFillStyle(l.color),a.moveTo(r.pointer.width,0),a.lineTo(0,-r.pointer.width/2),a.lineTo(-h,0),a.lineTo(0,r.pointer.width/2),a.lineTo(r.pointer.width,0),a.closePath(),a.fill(),a.beginPath(),a.setFillStyle("#FFFFFF"),a.arc(0,0,r.pointer.width/6,0,2*n,!1),a.fill(),a.restore();return!1!==o.dataLabel&&drawGaugeLabel(r,d,s,o,i,a),drawRingTitle(o,i,a),1===l&&"gauge"===o.type&&(r.oldAngle=t[0]._proportion_,r.oldData=t[0].data),{center:s,radius:d,innerRadius:h,categories:e,totalAngle:c}}function drawRadarDataPoints(e,t,o,a){var n=Math.cos,l=Math.sin,r=4<arguments.length&&void 0!==arguments[4]?arguments[4]:1,s=t.extra.radar||{},d=getRadarCoordinateSeries(t.categories.length),h={x:t.width/2,y:(t.height-o.legendHeight)/2},c=Math.min(h.x-(getMaxTextListLength(t.categories)+o.radarLabelTextMargin),h.y-o.radarLabelTextMargin);c-=o.padding,a.beginPath(),a.setLineWidth(1*t.pixelRatio),a.setStrokeStyle(s.gridColor||"#cccccc"),d.forEach(function(e){var t=convertCoordinateOrigin(c*n(e),c*l(e),h);a.moveTo(h.x,h.y),a.lineTo(t.x,t.y)}),a.stroke(),a.closePath();for(var x=function(e){var i={};a.beginPath(),a.setLineWidth(1*t.pixelRatio),a.setStrokeStyle(s.gridColor||"#cccccc"),d.forEach(function(t,r){var s=convertCoordinateOrigin(c/o.radarGridCount*e*n(t),c/o.radarGridCount*e*l(t),h);0===r?(i=s,a.moveTo(s.x,s.y)):a.lineTo(s.x,s.y)}),a.lineTo(i.x,i.y),a.stroke(),a.closePath()},p=1;p<=o.radarGridCount;p++)x(p);var g=getRadarDataPoints(d,h,c,e,t,r);return g.forEach(function(e,i){if(a.beginPath(),a.setFillStyle(e.color),a.setGlobalAlpha(.3),e.data.forEach(function(e,t){0===t?a.moveTo(e.position.x,e.position.y):a.lineTo(e.position.x,e.position.y)}),a.closePath(),a.fill(),a.setGlobalAlpha(1),!1!==t.dataPointShape){var n=o.dataPointShape[i%o.dataPointShape.length],l=e.data.map(function(e){return e.position});drawPointShape(l,e.color,n,a,t)}}),drawRadarLabel(d,c,h,t,o,a),{center:h,radius:c,angleList:d}}function drawCanvas(e,t){t.draw()}var Timing={easeIn:function(e){return Math.pow(e,3)},easeOut:function(e){return Math.pow(e-1,3)+1},easeInOut:function(e){var t=Math.pow;return 1>(e/=.5)?.5*t(e,3):.5*(t(e-2,3)+2)},linear:function(e){return e}};function Animation(e){this.isStop=!1,e.duration="undefined"==typeof e.duration?1e3:e.duration,e.timing=e.timing||"linear";var t=function(){return"undefined"==typeof requestAnimationFrame?"undefined"==typeof setTimeout?function(e){e(null)}:function(e,t){setTimeout(function(){var t=+new Date;e(t)},t)}:requestAnimationFrame}(),i=null,o=function(a){if(null===a||!0===this.isStop)return e.onProcess&&e.onProcess(1),void(e.onAnimationFinish&&e.onAnimationFinish());if(null===i&&(i=a),a-i<e.duration){var n=(a-i)/e.duration,l=Timing[e.timing];n=l(n),e.onProcess&&e.onProcess(n),t(o,17)}else e.onProcess&&e.onProcess(1),e.onAnimationFinish&&e.onAnimationFinish()};o=o.bind(this),t(o,17)}Animation.prototype.stop=function(){this.isStop=!0};function drawCharts(e,t,i,o){var a=this,n=t.series,l=t.categories;n=fillSeriesColor(n,i),n=fillSeriesType(n,t);let r=null;if("candle"==e){let e=assign({},t.extra.candle.average);e.show&&(r=calCandleMA(e.day,e.name,e.color,n[0].data),t.seriesMA=r)}var s=calLegendData(n,t,i),d=s.legendHeight;i.legendHeight=d;var h=calYAxisData(n,t,i),c=h.yAxisWidth;if(i.yAxisWidth=c,l&&l.length){var x=calCategoriesData(l,t,i),p=x.xAxisHeight,g=x.angle;i.xAxisHeight=p,i._xAxisTextAngle_=g}("pie"===e||"ring"===e||"rose"===e)&&(i._pieTextMaxLength_=!1===t.dataLabel?0:getPieTextMaxLength(n));var y=t.animation?t.duration:0;this.animationInstance&&this.animationInstance.stop(),"line"===e?this.animationInstance=new Animation({timing:"easeIn",duration:y,onProcess:function(e){o.clearRect(0,0,t.width,t.height),t.rotate&&contextRotate(o,t),drawYAxisGrid(l,t,i,o),drawXAxis(l,t,i,o);var r=drawLineDataPoints(n,t,i,o,e),s=r.xAxisPoints,d=r.calPoints,h=r.eachSpacing;a.chartData.xAxisPoints=s,a.chartData.calPoints=d,a.chartData.eachSpacing=h,drawLegend(t.series,t,i,o),drawYAxis(n,t,i,o),drawToolTipBridge(t,i,o,e,h,s),drawCanvas(t,o)},onAnimationFinish:function(){a.event.trigger("renderComplete")}}):"mix"===e?this.animationInstance=new Animation({timing:"easeIn",duration:y,onProcess:function(e){o.clearRect(0,0,t.width,t.height),t.rotate&&contextRotate(o,t),drawYAxisGrid(l,t,i,o),drawXAxis(l,t,i,o);var r=drawMixDataPoints(n,t,i,o,e),s=r.xAxisPoints,d=r.calPoints,h=r.eachSpacing;a.chartData.xAxisPoints=s,a.chartData.calPoints=d,a.chartData.eachSpacing=h,drawLegend(t.series,t,i,o),drawYAxis(n,t,i,o),drawToolTipBridge(t,i,o,e,h,s),drawCanvas(t,o)},onAnimationFinish:function(){a.event.trigger("renderComplete")}}):"column"===e?this.animationInstance=new Animation({timing:"easeIn",duration:y,onProcess:function(e){o.clearRect(0,0,t.width,t.height),t.rotate&&contextRotate(o,t),drawYAxisGrid(l,t,i,o),drawXAxis(l,t,i,o);var r=drawColumnDataPoints(n,t,i,o,e),s=r.xAxisPoints,d=r.calPoints,h=r.eachSpacing;a.chartData.xAxisPoints=s,a.chartData.calPoints=d,a.chartData.eachSpacing=h,drawLegend(t.series,t,i,o),drawYAxis(n,t,i,o),drawToolTipBridge(t,i,o,e,h,s),drawCanvas(t,o)},onAnimationFinish:function(){a.event.trigger("renderComplete")}}):"area"===e?this.animationInstance=new Animation({timing:"easeIn",duration:y,onProcess:function(e){o.clearRect(0,0,t.width,t.height),t.rotate&&contextRotate(o,t),drawYAxisGrid(l,t,i,o),drawXAxis(l,t,i,o);var r=drawAreaDataPoints(n,t,i,o,e),s=r.xAxisPoints,d=r.calPoints,h=r.eachSpacing;a.chartData.xAxisPoints=s,a.chartData.calPoints=d,a.chartData.eachSpacing=h,drawLegend(t.series,t,i,o),drawYAxis(n,t,i,o),drawToolTipBridge(t,i,o,e,h,s),drawCanvas(t,o)},onAnimationFinish:function(){a.event.trigger("renderComplete")}}):"ring"===e||"pie"===e?this.animationInstance=new Animation({timing:"easeInOut",duration:y,onProcess:function(e){o.clearRect(0,0,t.width,t.height),t.rotate&&contextRotate(o,t),a.chartData.pieData=drawPieDataPoints(n,t,i,o,e),drawLegend(t.series,t,i,o),drawToolTipBridge(t,i,o,e),drawCanvas(t,o)},onAnimationFinish:function(){a.event.trigger("renderComplete")}}):"rose"===e?this.animationInstance=new Animation({timing:"easeInOut",duration:y,onProcess:function(e){o.clearRect(0,0,t.width,t.height),t.rotate&&contextRotate(o,t),a.chartData.pieData=drawRoseDataPoints(n,t,i,o,e),drawLegend(t.series,t,i,o),drawToolTipBridge(t,i,o,e),drawCanvas(t,o)},onAnimationFinish:function(){a.event.trigger("renderComplete")}}):"radar"===e?this.animationInstance=new Animation({timing:"easeInOut",duration:y,onProcess:function(e){o.clearRect(0,0,t.width,t.height),t.rotate&&contextRotate(o,t),a.chartData.radarData=drawRadarDataPoints(n,t,i,o,e),drawLegend(t.series,t,i,o),drawToolTipBridge(t,i,o,e),drawCanvas(t,o)},onAnimationFinish:function(){a.event.trigger("renderComplete")}}):"arcbar"===e?this.animationInstance=new Animation({timing:"easeInOut",duration:y,onProcess:function(e){o.clearRect(0,0,t.width,t.height),t.rotate&&contextRotate(o,t),a.chartData.arcbarData=drawArcbarDataPoints(n,t,i,o,e),drawCanvas(t,o)},onAnimationFinish:function(){a.event.trigger("renderComplete")}}):"gauge"===e?this.animationInstance=new Animation({timing:"easeInOut",duration:y,onProcess:function(e){o.clearRect(0,0,t.width,t.height),t.rotate&&contextRotate(o,t),a.chartData.gaugeData=drawGaugeDataPoints(l,n,t,i,o,e),drawCanvas(t,o)},onAnimationFinish:function(){a.event.trigger("renderComplete")}}):"candle"===e?this.animationInstance=new Animation({timing:"easeIn",duration:y,onProcess:function(e){o.clearRect(0,0,t.width,t.height),t.rotate&&contextRotate(o,t),drawYAxisGrid(l,t,i,o),drawXAxis(l,t,i,o);var s=drawCandleDataPoints(n,r,t,i,o,e),d=s.xAxisPoints,h=s.calPoints,c=s.eachSpacing;a.chartData.xAxisPoints=d,a.chartData.calPoints=h,a.chartData.eachSpacing=c,r?drawLegend(r,t,i,o):drawLegend(t.series,t,i,o),drawYAxis(n,t,i,o),drawToolTipBridge(t,i,o,e,c,d),drawCanvas(t,o)},onAnimationFinish:function(){a.event.trigger("renderComplete")}}):void 0}function Event(){this.events={}}Event.prototype.addEventListener=function(e,t){this.events[e]=this.events[e]||[],this.events[e].push(t)},Event.prototype.trigger=function(){for(var e=arguments.length,t=Array(e),i=0;i<e;i++)t[i]=arguments[i];var o=t[0],a=t.slice(1);!this.events[o]||this.events[o].forEach(function(e){try{e.apply(null,a)}catch(t){console.error(t)}})};var Charts=function(e){e.pixelRatio=e.pixelRatio?e.pixelRatio:1,e.fontSize=e.fontSize?e.fontSize*e.pixelRatio:13*e.pixelRatio,e.title=assign({},e.title),e.subtitle=assign({},e.subtitle),e.yAxis=assign({},{gridType:"solid",dashLength:4*e.pixelRatio},e.yAxis),e.xAxis=assign({},{rotateLabel:!1,type:"calibration",gridType:"solid",dashLength:4*e.pixelRatio,scrollAlign:"left"},e.xAxis),e.extra=assign({},e.extra),e.rotate=!!e.rotate,e.animation=!!e.animation;var t=assign({},config);if(t.yAxisTitleWidth=!0!==e.yAxis.disabled&&e.yAxis.title?t.yAxisTitleWidth:0,("pie"==e.type||"ring"==e.type)&&(t.pieChartLinePadding=!1===e.dataLabel?0:e.extra.pie.labelWidth*e.pixelRatio||t.pieChartLinePadding*e.pixelRatio),"rose"==e.type&&(t.pieChartLinePadding=!1===e.dataLabel?0:e.extra.rose.labelWidth*e.pixelRatio||t.pieChartLinePadding*e.pixelRatio),t.pieChartTextPadding=!1===e.dataLabel?0:t.pieChartTextPadding*e.pixelRatio,t.yAxisSplit=e.yAxis.splitNumber?e.yAxis.splitNumber:config.yAxisSplit,t.rotate=e.rotate,e.rotate){let t=e.width,i=e.height;e.width=i,e.height=t}if(t.yAxisWidth=config.yAxisWidth*e.pixelRatio,t.xAxisHeight=config.xAxisHeight*e.pixelRatio,e.enableScroll&&e.xAxis.scrollShow&&(t.xAxisHeight+=6*e.pixelRatio),t.xAxisLineHeight=config.xAxisLineHeight*e.pixelRatio,t.legendHeight=config.legendHeight*e.pixelRatio,t.padding=config.padding*e.pixelRatio,t.fontSize=e.fontSize,t.titleFontSize=config.titleFontSize*e.pixelRatio,t.subtitleFontSize=config.subtitleFontSize*e.pixelRatio,t.toolTipPadding=config.toolTipPadding*e.pixelRatio,t.toolTipLineHeight=config.toolTipLineHeight*e.pixelRatio,t.columePadding=config.columePadding*e.pixelRatio,this.opts=e,this.config=t,e.$this=e.$this?e.$this:this,this.context=uni.createCanvasContext(e.canvasId,e.$this),this.chartData={},this.event=new Event,this.scrollOption={currentOffset:0,startTouchX:0,distance:0,lastMoveTime:0},e.enableScroll&&"right"==e.xAxis.scrollAlign){let i=calYAxisData(e.series,e,t),o=i.yAxisWidth;t.yAxisWidth=o;let a=0,n=getXAxisPoints(e.categories,e,t),l=n.xAxisPoints,r=n.startX,s=n.endX,d=n.eachSpacing,h=d*(l.length-1);a=s-r-h,this.scrollOption={currentOffset:a,startTouchX:a,distance:0,lastMoveTime:0},e._scrollDistance_=a}drawCharts.call(this,e.type,e,t,this.context)};Charts.prototype.updateData=function(){let e=0<arguments.length&&arguments[0]!==void 0?arguments[0]:{};this.opts=assign({},this.opts,e);let t=e.scrollPosition||"current";switch(t){case"current":this.opts._scrollDistance_=this.scrollOption.currentOffset;break;case"left":this.opts._scrollDistance_=0,this.scrollOption={currentOffset:0,startTouchX:0,distance:0,lastMoveTime:0};break;case"right":let e=calYAxisData(this.opts.series,this.opts,this.config),i=e.yAxisWidth;this.config.yAxisWidth=i;let o=0,a=getXAxisPoints(this.opts.categories,this.opts,this.config),n=a.xAxisPoints,l=a.startX,r=a.endX,s=a.eachSpacing,d=s*(n.length-1);o=r-l-d,this.scrollOption={currentOffset:o,startTouchX:o,distance:0,lastMoveTime:0},this.opts._scrollDistance_=o;}drawCharts.call(this,this.opts.type,this.opts,this.config,this.context)},Charts.prototype.zoom=function(){var e=Math.round,t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:this.opts.xAxis.itemCount;if(!0!==this.opts.enableScroll)return void console.log("\u8BF7\u542F\u7528\u6EDA\u52A8\u6761\u540E\u4F7F\u7528\uFF01");let i=e(Math.abs(this.scrollOption.currentOffset)/this.chartData.eachSpacing)+e(this.opts.xAxis.itemCount/2);this.opts.animation=!1,this.opts.xAxis.itemCount=t.itemCount;let o=calYAxisData(this.opts.series,this.opts,this.config),a=o.yAxisWidth;this.config.yAxisWidth=a;let n=0,l=getXAxisPoints(this.opts.categories,this.opts,this.config),r=l.xAxisPoints,s=l.startX,d=l.endX,h=l.eachSpacing,c=d-s,x=c-h*(r.length-1);n=c/2-h*i,0<n&&(n=0),n<x&&(n=x),this.scrollOption={currentOffset:n,startTouchX:n,distance:0,lastMoveTime:0},this.opts._scrollDistance_=n,drawCharts.call(this,this.opts.type,this.opts,this.config,this.context)},Charts.prototype.stopAnimation=function(){this.animationInstance&&this.animationInstance.stop()},Charts.prototype.addEventListener=function(e,t){this.event.addEventListener(e,t)},Charts.prototype.getCurrentDataIndex=function(t){var e=null;if(e=t.changedTouches?t.changedTouches[0]:t.mp.changedTouches[0],e){var i=getTouches(e,this.opts,t);return"pie"===this.opts.type||"ring"===this.opts.type||"rose"===this.opts.type?findPieChartCurrentIndex({x:i.x,y:i.y},this.chartData.pieData):"radar"===this.opts.type?findRadarChartCurrentIndex({x:i.x,y:i.y},this.chartData.radarData,this.opts.categories.length):findCurrentIndex({x:i.x,y:i.y},this.chartData.xAxisPoints,this.opts,this.config,Math.abs(this.scrollOption.currentOffset))}return-1},Charts.prototype.showToolTip=function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},i=null;if(i=t.changedTouches?t.changedTouches[0]:t.mp.changedTouches[0],!i)return void console.log("touchError");var o=getTouches(i,this.opts,t);if("line"===this.opts.type||"area"===this.opts.type||"column"===this.opts.type){var a=this.getCurrentDataIndex(t),n=this.scrollOption.currentOffset,l=assign({},this.opts,{_scrollDistance_:n,animation:!1});if(-1<a){var r=getSeriesDataItem(this.opts.series,a);if(0!==r.length){var s=getToolTipData(r,this.chartData.calPoints,a,this.opts.categories,e),d=s.textList,h=s.offset;h.y=o.y,l.tooltip={textList:d,offset:h,option:e,index:a}}}drawCharts.call(this,l.type,l,this.config,this.context)}if("mix"===this.opts.type){var a=this.getCurrentDataIndex(t),n=this.scrollOption.currentOffset,l=assign({},this.opts,{_scrollDistance_:n,animation:!1});if(-1<a){var r=getSeriesDataItem(this.opts.series,a);if(0!==r.length){var c=getMixToolTipData(r,this.chartData.calPoints,a,this.opts.categories,e),d=c.textList,h=c.offset;h.y=o.y,l.tooltip={textList:d,offset:h,option:e,index:a}}}drawCharts.call(this,l.type,l,this.config,this.context)}if("candle"===this.opts.type){var a=this.getCurrentDataIndex(t),n=this.scrollOption.currentOffset,l=assign({},this.opts,{_scrollDistance_:n,animation:!1});if(-1<a){var r=getSeriesDataItem(this.opts.series,a);if(0!==r.length){var s=getCandleToolTipData(this.opts.series[0].data,r,this.chartData.calPoints,a,this.opts.categories,this.opts.extra.candle,e),d=s.textList,h=s.offset;h.y=o.y,l.tooltip={textList:d,offset:h,option:e,index:a}}}drawCharts.call(this,l.type,l,this.config,this.context)}if("pie"===this.opts.type||"ring"===this.opts.type||"rose"===this.opts.type){var a=this.getCurrentDataIndex(t),n=this.scrollOption.currentOffset,l=assign({},this.opts,{_scrollDistance_:n,animation:!1});if(-1<a){var r=this.opts.series[a],d=[{text:e.format?e.format(r):r.name+": "+r.data,color:r.color}],h={x:o.x,y:o.y};l.tooltip={textList:d,offset:h,option:e,index:a}}drawCharts.call(this,l.type,l,this.config,this.context)}if("radar"===this.opts.type){var a=this.getCurrentDataIndex(t),n=this.scrollOption.currentOffset,l=assign({},this.opts,{_scrollDistance_:n,animation:!1});if(-1<a){var r=getSeriesDataItem(this.opts.series,a);if(0!==r.length){var d=r.map(function(t){return{text:e.format?e.format(t):t.name+": "+t.data,color:t.color}}),h={x:o.x,y:o.y};l.tooltip={textList:d,offset:h,option:e,index:a}}}drawCharts.call(this,l.type,l,this.config,this.context)}},Charts.prototype.translate=function(e){this.scrollOption={currentOffset:e,startTouchX:e,distance:0,lastMoveTime:0};let t=assign({},this.opts,{_scrollDistance_:e,animation:!1});drawCharts.call(this,this.opts.type,t,this.config,this.context)},Charts.prototype.scrollStart=function(t){var e=null;e=t.changedTouches?t.changedTouches[0]:t.mp.changedTouches[0];var i=getTouches(e,this.opts,t);e&&!0===this.opts.enableScroll&&(this.scrollOption.startTouchX=i.x)},Charts.prototype.scroll=function(t){0===this.scrollOption.lastMoveTime&&(this.scrollOption.lastMoveTime=Date.now());let e=this.opts.extra.touchMoveLimit||20,i=Date.now(),o=i-this.scrollOption.lastMoveTime;if(!(o<Math.floor(1e3/e))){this.scrollOption.lastMoveTime=i;var a=null;a=t.changedTouches?t.changedTouches[0]:t.mp.changedTouches[0];var n=getTouches(a,this.opts,t);if(a&&!0===this.opts.enableScroll){var l=n.x-this.scrollOption.startTouchX;var r=this.scrollOption.currentOffset,s=calValidDistance(r+l,this.chartData,this.config,this.opts);this.scrollOption.distance=l=s-r;var d=assign({},this.opts,{_scrollDistance_:r+l,animation:!1});return drawCharts.call(this,d.type,d,this.config,this.context),r+l}}},Charts.prototype.scrollEnd=function(){if(!0===this.opts.enableScroll){var e=this.scrollOption,t=e.currentOffset,i=e.distance;this.scrollOption.currentOffset=t+i,this.scrollOption.distance=0}},"object"==typeof module&&"object"==typeof module.exports&&(module.exports=Charts);
u-parse
components
wxParseAudio.vue
<template>
<!--增加audio标签支持-->
<audio
:id="node.attr.id"
:class="node.classStr"
:style="node.styleStr"
:src="node.attr.src"
:loop="node.attr.loop"
:poster="node.attr.poster"
:name="node.attr.name"
:author="node.attr.author"
controls></audio>
</template>
<script>
export default {
name: 'wxParseAudio',
props: {
node: {
type: Object,
default() {
return {};
},
},
},
};
</script>
wxParseImg.vue
<template>
<image
:mode="node.attr.mode"
:lazy-load="node.attr.lazyLoad"
:class="node.classStr"
:style="newStyleStr || node.styleStr"
:data-src="node.attr.src"
:src="node.attr.src"
@tap="wxParseImgTap"
@load="wxParseImgLoad"
/>
</template>
<script>
export default {
name: 'wxParseImg',
data() {
return {
newStyleStr: '',
preview: true,
};
},
props: {
node: {
type: Object,
default() {
return {};
},
},
},
methods: {
wxParseImgTap(e) {
if (!this.preview) return;
const { src } = e.currentTarget.dataset;
if (!src) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {// TODO 遍历获取父节点执行方法
parent = parent.$parent;
}
parent.preview(src, e);
},
// 图片视觉宽高计算函数区
wxParseImgLoad(e) {
const { src } = e.currentTarget.dataset;
if (!src) return;
const { width, height } = e.mp.detail;
const recal = this.wxAutoImageCal(width, height);
const { imageheight, imageWidth } = recal;
const { padding, mode } = this.node.attr;
const { styleStr } = this.node;
const imageHeightStyle = mode === 'widthFix' ? '' : `height: ${imageheight}px;`;
this.newStyleStr = `${styleStr}; ${imageHeightStyle}; width: ${imageWidth}px; padding: 0 ${+padding}px;`;
},
// 计算视觉优先的图片宽高
wxAutoImageCal(originalWidth, originalHeight) {
// 获取图片的原始长宽
const { padding } = this.node.attr;
const windowWidth = this.node.$screen.width - (2 * padding);
const results = {};
if (originalWidth < 60 || originalHeight < 60) {
const { src } = this.node.attr;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.removeImageUrl(src);
this.preview = false;
}
// 判断按照那种方式进行缩放
if (originalWidth > windowWidth) {
// 在图片width大于手机屏幕width时候
results.imageWidth = windowWidth;
results.imageheight = windowWidth * (originalHeight / originalWidth);
} else {
// 否则展示原来的数据
results.imageWidth = originalWidth;
results.imageheight = originalHeight;
}
return results;
},
},
};
</script>
wxParseTemplate0.vue
<template>
<view>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--audio类型-->
<block v-else-if="node.tag == 'audio'">
<wx-parse-audio :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--table类型-->
<block v-else-if="node.tag == 'table'">
<view :class="node.classStr" class="table" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他标签-->
<block v-else>
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</view>
</template>
<script>
import wxParseTemplate from './wxParseTemplate1';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
export default {
name: 'wxParseTemplate0',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;// TODO currentTarget才有dataset
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {// TODO 遍历获取父节点执行方法
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>
wxParseTemplate1.vue
<template>
<view :class="(node.tag == 'li' ? node.classStr : (node.node==='text'?'text':''))">
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<!-- <view :class="node.classStr" :style="node.styleStr"> -->
<view :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--audio类型-->
<block v-else-if="node.tag == 'audio'">
<wx-parse-audio :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他标签-->
<block v-else>
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</view>
</template>
<script>
import wxParseTemplate from './wxParseTemplate2';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
export default {
name: 'wxParseTemplate1',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>
wxParseTemplate10.vue
<template>
<view>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--audio类型-->
<block v-else-if="node.tag == 'audio'">
<wx-parse-audio :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他标签-->
<block v-else>
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</view>
</template>
<script>
import wxParseTemplate from './wxParseTemplate11';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
export default {
name: 'wxParseTemplate10',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>
wxParseTemplate11.vue
<template>
<view>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" :style="node.styleStr">
{{node.text}}
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--audio类型-->
<block v-else-if="node.tag == 'audio'">
<wx-parse-audio :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
{{node.text}}
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他标签-->
<block v-else>
<view :class="node.classStr" :style="node.styleStr">
{{node.text}}
</view>
</block>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</view>
</template>
<script>
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
export default {
name: 'wxParseTemplate11',
props: {
node: {},
},
components: {
wxParseImg,
wxParseVideo,
wxParseAudio,
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>
wxParseTemplate2.vue
<template>
<view>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--audio类型-->
<block v-else-if="node.tag == 'audio'">
<wx-parse-audio :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他标签-->
<block v-else>
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</view>
</template>
<script>
import wxParseTemplate from './wxParseTemplate3';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
export default {
name: 'wxParseTemplate2',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>
wxParseTemplate3.vue
<template>
<view>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--audio类型-->
<block v-else-if="node.tag == 'audio'">
<wx-parse-audio :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他标签-->
<block v-else>
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</view>
</template>
<script>
import wxParseTemplate from './wxParseTemplate4';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
export default {
name: 'wxParseTemplate3',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>
wxParseTemplate4.vue
<template>
<view>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--audio类型-->
<block v-else-if="node.tag == 'audio'">
<wx-parse-audio :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他标签-->
<block v-else>
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</view>
</template>
<script>
import wxParseTemplate from './wxParseTemplate5';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
export default {
name: 'wxParseTemplate4',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>
wxParseTemplate5.vue
<template>
<view>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--audio类型-->
<block v-else-if="node.tag == 'audio'">
<wx-parse-audio :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他标签-->
<block v-else>
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</view>
</template>
<script>
import wxParseTemplate from './wxParseTemplate6';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
export default {
name: 'wxParseTemplate5',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>
wxParseTemplate6.vue
<template>
<view>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--audio类型-->
<block v-else-if="node.tag == 'audio'">
<wx-parse-audio :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他标签-->
<block v-else>
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</view>
</template>
<script>
import wxParseTemplate from './wxParseTemplate7';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
export default {
name: 'wxParseTemplate6',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>
wxParseTemplate7.vue
<template>
<view>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--audio类型-->
<block v-else-if="node.tag == 'audio'">
<wx-parse-audio :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他标签-->
<block v-else>
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</view>
</template>
<script>
import wxParseTemplate from './wxParseTemplate8';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
export default {
name: 'wxParseTemplate7',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>
wxParseTemplate8.vue
<template>
<view>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--audio类型-->
<block v-else-if="node.tag == 'audio'">
<wx-parse-audio :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他标签-->
<block v-else>
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</view>
</template>
<script>
import wxParseTemplate from './wxParseTemplate9';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
export default {
name: 'wxParseTemplate8',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>
wxParseTemplate9.vue
<template>
<view>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--audio类型-->
<block v-else-if="node.tag == 'audio'">
<wx-parse-audio :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他标签-->
<block v-else>
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</view>
</template>
<script>
import wxParseTemplate from './wxParseTemplate10';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
export default {
name: 'wxParseTemplate9',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>
wxParseVideo.vue
<template>
<!--增加video标签支持,并循环添加-->
<view :class="node.classStr" :style="node.styleStr">
<video :class="node.classStr" class="video-video" :src="node.attr.src"></video>
</view>
</template>
<script>
export default {
name: 'wxParseVideo',
props: {
node: {},
},
};
</script>
libs
html2json.js
/**
* html2Json 改造来自: https://github.com/Jxck/html2json
*
*
* author: Di (微信小程序开发工程师)
* organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
* 垂直微信小程序开发交流社区
*
* github地址: https://github.com/icindy/wxParse
*
* for: 微信小程序富文本解析
* detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
*/
import wxDiscode from './wxDiscode';
import HTMLParser from './htmlparser';
function makeMap(str) {
const obj = {};
const items = str.split(',');
for (let i = 0; i < items.length; i += 1) obj[items[i]] = true;
return obj;
}
// Block Elements - HTML 5
const block = makeMap('br,code,address,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video');
// Inline Elements - HTML 5
const inline = makeMap('a,abbr,acronym,applet,b,basefont,bdo,big,button,cite,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var');
// Elements that you can, intentionally, leave open
// (and which close themselves)
const closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr');
function removeDOCTYPE(html) {
const isDocument = /<body.*>([^]*)<\/body>/.test(html);
return isDocument ? RegExp.$1 : html;
}
function trimHtml(html) {
return html
.replace(/<!--.*?-->/gi, '')
.replace(/\/\*.*?\*\//gi, '')
.replace(/[ ]+</gi, '<')
.replace(/<script[^]*<\/script>/gi, '')
.replace(/<style[^]*<\/style>/gi, '');
}
function getScreenInfo() {
const screen = {};
wx.getSystemInfo({
success: (res) => {
screen.width = res.windowWidth;
screen.height = res.windowHeight;
},
});
return screen;
}
function html2json(html, customHandler, imageProp, host) {
// 处理字符串
html = removeDOCTYPE(html);
html = trimHtml(html);
html = wxDiscode.strDiscode(html);
// 生成node节点
const bufArray = [];
const results = {
nodes: [],
imageUrls: [],
};
const screen = getScreenInfo();
function Node(tag) {
this.node = 'element';
this.tag = tag;
this.$screen = screen;
}
HTMLParser(html, {
start(tag, attrs, unary) {
// node for this element
const node = new Node(tag);
if (bufArray.length !== 0) {
const parent = bufArray[0];
if (parent.nodes === undefined) {
parent.nodes = [];
}
}
if (block[tag]) {
node.tagType = 'block';
} else if (inline[tag]) {
node.tagType = 'inline';
} else if (closeSelf[tag]) {
node.tagType = 'closeSelf';
}
node.attr = attrs.reduce((pre, attr) => {
const { name } = attr;
let { value } = attr;
if (name === 'class') {
node.classStr = value;
}
// has multi attibutes
// make it array of attribute
if (name === 'style') {
node.styleStr = value;
}
if (value.match(/ /)) {
value = value.split(' ');
}
// if attr already exists
// merge it
if (pre[name]) {
if (Array.isArray(pre[name])) {
// already array, push to last
pre[name].push(value);
} else {
// single value, make it array
pre[name] = [pre[name], value];
}
} else {
// not exist, put it
pre[name] = value;
}
return pre;
}, {});
// 优化样式相关属性
if (node.classStr) {
node.classStr += ` ${node.tag}`;
} else {
node.classStr = node.tag;
}
if (node.tagType === 'inline') {
node.classStr += ' inline';
}
// 对img添加额外数据
if (node.tag === 'img') {
let imgUrl = node.attr.src;
imgUrl = wxDiscode.urlToHttpUrl(imgUrl, imageProp.domain);
Object.assign(node.attr, imageProp, {
src: imgUrl || '',
});
if (imgUrl) {
results.imageUrls.push(imgUrl);
}
}
// 处理a标签属性
if (node.tag === 'a') {
node.attr.href = node.attr.href || '';
}
// 处理font标签样式属性
if (node.tag === 'font') {
const fontSize = [
'x-small',
'small',
'medium',
'large',
'x-large',
'xx-large',
'-webkit-xxx-large',
];
const styleAttrs = {
color: 'color',
face: 'font-family',
size: 'font-size',
};
if (!node.styleStr) node.styleStr = '';
Object.keys(styleAttrs).forEach((key) => {
if (node.attr[key]) {
const value = key === 'size' ? fontSize[node.attr[key] - 1] : node.attr[key];
node.styleStr += `${styleAttrs[key]}: ${value};`;
}
});
}
// 临时记录source资源
if (node.tag === 'source') {
results.source = node.attr.src;
}
if (customHandler.start) {
customHandler.start(node, results);
}
if (unary) {
// if this tag doesn't have end tag
// like <img src="hoge.png"/>
// add to parents
const parent = bufArray[0] || results;
if (parent.nodes === undefined) {
parent.nodes = [];
}
parent.nodes.push(node);
} else {
bufArray.unshift(node);
}
},
end(tag) {
// merge into parent tag
const node = bufArray.shift();
if (node.tag !== tag) {
// console.error('invalid state: mismatch end tag');
}
// 当有缓存source资源时于于video补上src资源
if (node.tag === 'video' && results.source) {
node.attr.src = results.source;
delete results.source;
}
if (customHandler.end) {
customHandler.end(node, results);
}
if (bufArray.length === 0) {
results.nodes.push(node);
} else {
const parent = bufArray[0];
if (!parent.nodes) {
parent.nodes = [];
}
parent.nodes.push(node);
}
},
chars(text) {
if (!text.trim()) return;
const node = {
node: 'text',
text,
};
if (customHandler.chars) {
customHandler.chars(node, results);
}
if (bufArray.length === 0) {
results.nodes.push(node);
} else {
const parent = bufArray[0];
if (parent.nodes === undefined) {
parent.nodes = [];
}
parent.nodes.push(node);
}
},
});
return results;
}
export default html2json;
htmlparser.js
/**
*
* htmlParser改造自: https://github.com/blowsie/Pure-JavaScript-HTML5-Parser
*
* author: Di (微信小程序开发工程师)
* organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
* 垂直微信小程序开发交流社区
*
* github地址: https://github.com/icindy/wxParse
*
* for: 微信小程序富文本解析
* detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
*/
// Regular Expressions for parsing tags and attributes
const startTag = /^<([-A-Za-z0-9_]+)((?:\s+[a-zA-Z0-9_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/;
const endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/;
const attr = /([a-zA-Z0-9_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g;
function makeMap(str) {
const obj = {};
const items = str.split(',');
for (let i = 0; i < items.length; i += 1) obj[items[i]] = true;
return obj;
}
// Empty Elements - HTML 5
const empty = makeMap('area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr');
// Block Elements - HTML 5
const block = makeMap('address,code,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video');
// Inline Elements - HTML 5
const inline = makeMap('a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var');
// Elements that you can, intentionally, leave open
// (and which close themselves)
const closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr');
// Attributes that have their values filled in disabled="disabled"
const fillAttrs = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected');
function HTMLParser(html, handler) {
let index;
let chars;
let match;
let last = html;
const stack = [];
stack.last = () => stack[stack.length - 1];
function parseEndTag(tag, tagName) {
// If no tag name is provided, clean shop
let pos;
if (!tagName) {
pos = 0;
} else {
// Find the closest opened tag of the same type
tagName = tagName.toLowerCase();
for (pos = stack.length - 1; pos >= 0; pos -= 1) {
if (stack[pos] === tagName) break;
}
}
if (pos >= 0) {
// Close all the open elements, up the stack
for (let i = stack.length - 1; i >= pos; i -= 1) {
if (handler.end) handler.end(stack[i]);
}
// Remove the open elements from the stack
stack.length = pos;
}
}
function parseStartTag(tag, tagName, rest, unary) {
tagName = tagName.toLowerCase();
if (block[tagName]) {
while (stack.last() && inline[stack.last()]) {
parseEndTag('', stack.last());
}
}
if (closeSelf[tagName] && stack.last() === tagName) {
parseEndTag('', tagName);
}
unary = empty[tagName] || !!unary;
if (!unary) stack.push(tagName);
if (handler.start) {
const attrs = [];
rest.replace(attr, function genAttr(matches, name) {
const value = arguments[2] || arguments[3] || arguments[4] || (fillAttrs[name] ? name : '');
attrs.push({
name,
value,
escaped: value.replace(/(^|[^\\])"/g, '$1\\"'), // "
});
});
if (handler.start) {
handler.start(tagName, attrs, unary);
}
}
}
while (html) {
chars = true;
if (html.indexOf('</') === 0) {
match = html.match(endTag);
if (match) {
html = html.substring(match[0].length);
match[0].replace(endTag, parseEndTag);
chars = false;
}
// start tag
} else if (html.indexOf('<') === 0) {
match = html.match(startTag);
if (match) {
html = html.substring(match[0].length);
match[0].replace(startTag, parseStartTag);
chars = false;
}
}
if (chars) {
index = html.indexOf('<');
let text = '';
while (index === 0) {
text += '<';
html = html.substring(1);
index = html.indexOf('<');
}
text += index < 0 ? html : html.substring(0, index);
html = index < 0 ? '' : html.substring(index);
if (handler.chars) handler.chars(text);
}
if (html === last) throw new Error(`Parse Error: ${html}`);
last = html;
}
// Clean up any remaining tags
parseEndTag();
}
export default HTMLParser;
wxDiscode.js
// HTML 支持的数学符号
function strNumDiscode(str) {
str = str.replace(/∀/g, '∀');
str = str.replace(/∂/g, '∂');
str = str.replace(/∃/g, '∃');
str = str.replace(/∅/g, '∅');
str = str.replace(/∇/g, '∇');
str = str.replace(/∈/g, '∈');
str = str.replace(/∉/g, '∉');
str = str.replace(/∋/g, '∋');
str = str.replace(/∏/g, '∏');
str = str.replace(/∑/g, '∑');
str = str.replace(/−/g, '−');
str = str.replace(/∗/g, '∗');
str = str.replace(/√/g, '√');
str = str.replace(/∝/g, '∝');
str = str.replace(/∞/g, '∞');
str = str.replace(/∠/g, '∠');
str = str.replace(/∧/g, '∧');
str = str.replace(/∨/g, '∨');
str = str.replace(/∩/g, '∩');
str = str.replace(/∪/g, '∪');
str = str.replace(/∫/g, '∫');
str = str.replace(/∴/g, '∴');
str = str.replace(/∼/g, '∼');
str = str.replace(/≅/g, '≅');
str = str.replace(/≈/g, '≈');
str = str.replace(/≠/g, '≠');
str = str.replace(/≤/g, '≤');
str = str.replace(/≥/g, '≥');
str = str.replace(/⊂/g, '⊂');
str = str.replace(/⊃/g, '⊃');
str = str.replace(/⊄/g, '⊄');
str = str.replace(/⊆/g, '⊆');
str = str.replace(/⊇/g, '⊇');
str = str.replace(/⊕/g, '⊕');
str = str.replace(/⊗/g, '⊗');
str = str.replace(/⊥/g, '⊥');
str = str.replace(/⋅/g, '⋅');
return str;
}
// HTML 支持的希腊字母
function strGreeceDiscode(str) {
str = str.replace(/Α/g, 'Α');
str = str.replace(/Β/g, 'Β');
str = str.replace(/Γ/g, 'Γ');
str = str.replace(/Δ/g, 'Δ');
str = str.replace(/Ε/g, 'Ε');
str = str.replace(/Ζ/g, 'Ζ');
str = str.replace(/Η/g, 'Η');
str = str.replace(/Θ/g, 'Θ');
str = str.replace(/Ι/g, 'Ι');
str = str.replace(/Κ/g, 'Κ');
str = str.replace(/Λ/g, 'Λ');
str = str.replace(/Μ/g, 'Μ');
str = str.replace(/Ν/g, 'Ν');
str = str.replace(/Ξ/g, 'Ν');
str = str.replace(/Ο/g, 'Ο');
str = str.replace(/Π/g, 'Π');
str = str.replace(/Ρ/g, 'Ρ');
str = str.replace(/Σ/g, 'Σ');
str = str.replace(/Τ/g, 'Τ');
str = str.replace(/Υ/g, 'Υ');
str = str.replace(/Φ/g, 'Φ');
str = str.replace(/Χ/g, 'Χ');
str = str.replace(/Ψ/g, 'Ψ');
str = str.replace(/Ω/g, 'Ω');
str = str.replace(/α/g, 'α');
str = str.replace(/β/g, 'β');
str = str.replace(/γ/g, 'γ');
str = str.replace(/δ/g, 'δ');
str = str.replace(/ε/g, 'ε');
str = str.replace(/ζ/g, 'ζ');
str = str.replace(/η/g, 'η');
str = str.replace(/θ/g, 'θ');
str = str.replace(/ι/g, 'ι');
str = str.replace(/κ/g, 'κ');
str = str.replace(/λ/g, 'λ');
str = str.replace(/μ/g, 'μ');
str = str.replace(/ν/g, 'ν');
str = str.replace(/ξ/g, 'ξ');
str = str.replace(/ο/g, 'ο');
str = str.replace(/π/g, 'π');
str = str.replace(/ρ/g, 'ρ');
str = str.replace(/ς/g, 'ς');
str = str.replace(/σ/g, 'σ');
str = str.replace(/τ/g, 'τ');
str = str.replace(/υ/g, 'υ');
str = str.replace(/φ/g, 'φ');
str = str.replace(/χ/g, 'χ');
str = str.replace(/ψ/g, 'ψ');
str = str.replace(/ω/g, 'ω');
str = str.replace(/ϑ/g, 'ϑ');
str = str.replace(/ϒ/g, 'ϒ');
str = str.replace(/ϖ/g, 'ϖ');
str = str.replace(/·/g, '·');
return str;
}
function strcharacterDiscode(str) {
// 加入常用解析
str = str.replace(/ /g, ' ');
str = str.replace(/ /g, ' ');
str = str.replace(/ /g, ' ');
str = str.replace(/"/g, "'");
str = str.replace(/&/g, '&');
str = str.replace(/</g, '<');
str = str.replace(/>/g, '>');
str = str.replace(/•/g, '•');
return str;
}
// HTML 支持的其他实体
function strOtherDiscode(str) {
str = str.replace(/Œ/g, 'Œ');
str = str.replace(/œ/g, 'œ');
str = str.replace(/Š/g, 'Š');
str = str.replace(/š/g, 'š');
str = str.replace(/Ÿ/g, 'Ÿ');
str = str.replace(/ƒ/g, 'ƒ');
str = str.replace(/ˆ/g, 'ˆ');
str = str.replace(/˜/g, '˜');
str = str.replace(/ /g, '');
str = str.replace(/ /g, '');
str = str.replace(/ /g, '');
str = str.replace(/‌/g, '');
str = str.replace(/‍/g, '');
str = str.replace(/‎/g, '');
str = str.replace(/‏/g, '');
str = str.replace(/–/g, '–');
str = str.replace(/—/g, '—');
str = str.replace(/‘/g, '‘');
str = str.replace(/’/g, '’');
str = str.replace(/‚/g, '‚');
str = str.replace(/“/g, '“');
str = str.replace(/”/g, '”');
str = str.replace(/„/g, '„');
str = str.replace(/†/g, '†');
str = str.replace(/‡/g, '‡');
str = str.replace(/•/g, '•');
str = str.replace(/…/g, '…');
str = str.replace(/‰/g, '‰');
str = str.replace(/′/g, '′');
str = str.replace(/″/g, '″');
str = str.replace(/‹/g, '‹');
str = str.replace(/›/g, '›');
str = str.replace(/‾/g, '‾');
str = str.replace(/€/g, '€');
str = str.replace(/™/g, '™');
str = str.replace(/←/g, '←');
str = str.replace(/↑/g, '↑');
str = str.replace(/→/g, '→');
str = str.replace(/↓/g, '↓');
str = str.replace(/↔/g, '↔');
str = str.replace(/↵/g, '↵');
str = str.replace(/⌈/g, '⌈');
str = str.replace(/⌉/g, '⌉');
str = str.replace(/⌊/g, '⌊');
str = str.replace(/⌋/g, '⌋');
str = str.replace(/◊/g, '◊');
str = str.replace(/♠/g, '♠');
str = str.replace(/♣/g, '♣');
str = str.replace(/♥/g, '♥');
str = str.replace(/♦/g, '♦');
str = str.replace(/'/g, "'");
return str;
}
function strDiscode(str) {
str = strNumDiscode(str);
str = strGreeceDiscode(str);
str = strcharacterDiscode(str);
str = strOtherDiscode(str);
return str;
}
function urlToHttpUrl(url, domain) {
if (/^\/\//.test(url)) {
return `https:${url}`;
} else if (/^\//.test(url)) {
return `https://${domain}${url}`;
}
return url;
}
export default {
strDiscode,
urlToHttpUrl,
};
readme.md
## uParse 适用于 uni-app/mpvue 的富文本解析组件
> 支持 Html、Markdown 解析,Fork自: [mpvue-wxParse](https://github.com/F-loat/mpvue-wxParse)
## 属性
| 名称 | 类型 | 默认值 | 描述 |
| -----------------|--------------- | ------------- | ---------------- |
| loading | Boolean | false | 数据加载状态 |
| className | String | — | 自定义 class 名称 |
| content | String | — | 渲染内容 |
| noData | String | 数据不能为空 | 空数据时的渲染展示 |
| startHandler | Function | 见源码 | 自定义 parser 函数 |
| endHandler | Function | null | 自定义 parser 函数 |
| charsHandler | Function | null | 自定义 parser 函数 |
| imageProp | Object | 见下文 | 图片相关参数 |
### 自定义 parser 函数具体介绍
* 传入的参数为当前节点 `node` 对象及解析结果 `results` 对象,例如 `startHandler(node, results)`
* 无需返回值,通过对传入的参数直接操作来完成需要的改动
* 自定义函数会在原解析函数处理之后执行
### imageProp 对象具体属性
| 名称 | 类型 | 默认值 | 描述 |
| -----------------|--------------- | ------------- | ------------------ |
| mode | String | 'aspectFit' | 图片裁剪、缩放的模式 |
| padding | Number | 0 | 图片内边距 |
| lazyLoad | Boolean | false | 图片懒加载 |
| domain | String | '' | 图片服务域名 |
## 事件
| 名称 | 参数 | 描述 |
| -----------------|----------------- | ---------------- |
| preview | 图片地址,原始事件 | 预览图片时触发 |
| navigate | 链接地址,原始事件 | 点击链接时触发 |
## 基本使用方法
<template>
<div>
<u-parse :content="article" @preview="preview" @navigate="navigate" />
</div>
</template>
<script>
import uParse from '@/components/u-parse/u-parse.vue'
export default {
components: {
uParse
},
data () {
return {
article: '<div>我是HTML代码</div>'
}
},
methods: {
preview(src, e) {
// do something
},
navigate(href, e) {
// do something
}
}
}
</script>
<style>
@import url("@/components/u-parse/u-parse.css");
</style>
## 渲染 Markdown
> 先将 markdown 转换为 html 即可
npm install marked
import marked from 'marked'
import uParse from '@/components/u-parse/u-parse.vue'
export default {
components: {
uParse
},
data () {
return {
article: marked(`#hello, markdown!`)
}
}
}
u-parse.css
/**
* author: Di (微信小程序开发工程师)
* organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
* 垂直微信小程序开发交流社区
*
* github地址: https://github.com/icindy/wxParse
*
* for: 微信小程序富文本解析
* detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
*/
.wxParse {
width: 100%;
font-family: Helvetica, sans-serif;
font-size: 30upx;
color: #666;
line-height: 1.8;
}
.wxParse view {
word-break: hyphenate;
}
.wxParse .inline {
display: inline;
margin: 0;
padding: 0;
}
.wxParse .div {
margin: 0;
padding: 0;
}
.wxParse .h1 .text {
font-size: 2em;
margin: 0.67em 0;
}
.wxParse .h2 .text {
font-size: 1.5em;
margin: 0.83em 0;
}
.wxParse .h3 .text {
font-size: 1.17em;
margin: 1em 0;
}
.wxParse .h4 .text {
margin: 1.33em 0;
}
.wxParse .h5 .text {
font-size: 0.83em;
margin: 1.67em 0;
}
.wxParse .h6 .text {
font-size: 0.67em;
margin: 2.33em 0;
}
.wxParse .h1 .text,
.wxParse .h2 .text,
.wxParse .h3 .text,
.wxParse .h4 .text,
.wxParse .h5 .text,
.wxParse .h6 .text,
.wxParse .b,
.wxParse .strong {
font-weight: bolder;
}
.wxParse .p {
margin: 1em 0;
}
.wxParse .i,
.wxParse .cite,
.wxParse .em,
.wxParse .var,
.wxParse .address {
font-style: italic;
}
.wxParse .pre,
.wxParse .tt,
.wxParse .code,
.wxParse .kbd,
.wxParse .samp {
font-family: monospace;
}
.wxParse .pre {
overflow: auto;
background: #f5f5f5;
padding: 16upx;
white-space: pre;
margin: 1em 0upx;
}
.wxParse .code {
display: inline;
background: #f5f5f5;
}
.wxParse .big {
font-size: 1.17em;
}
.wxParse .small,
.wxParse .sub,
.wxParse .sup {
font-size: 0.83em;
}
.wxParse .sub {
vertical-align: sub;
}
.wxParse .sup {
vertical-align: super;
}
.wxParse .s,
.wxParse .strike,
.wxParse .del {
text-decoration: line-through;
}
.wxParse .strong,
.wxParse .s {
display: inline;
}
.wxParse .a {
color: deepskyblue;
}
.wxParse .video {
text-align: center;
margin: 22upx 0;
}
.wxParse .video-video {
width: 100%;
}
.wxParse .img {
display: inline-block;
width: 0;
height: 0;
max-width: 100%;
overflow: hidden;
}
.wxParse .blockquote {
margin: 10upx 0;
padding: 22upx 0 22upx 22upx;
font-family: Courier, Calibri, "宋体";
background: #f5f5f5;
border-left: 6upx solid #dbdbdb;
}
.wxParse .blockquote .p {
margin: 0;
}
.wxParse .ul, .wxParse .ol {
display: block;
margin: 1em 0;
padding-left: 33upx;
}
.wxParse .ol {
list-style-type: disc;
}
.wxParse .ol {
list-style-type: decimal;
}
.wxParse .ol>weixin-parse-template,.wxParse .ul>weixin-parse-template {
display: list-item;
align-items: baseline;
text-align: match-parent;
}
.wxParse .ol>.li,.wxParse .ul>.li {
display: list-item;
align-items: baseline;
text-align: match-parent;
}
.wxParse .ul .ul, .wxParse .ol .ul {
list-style-type: circle;
}
.wxParse .ol .ol .ul, .wxParse .ol .ul .ul, .wxParse .ul .ol .ul, .wxParse .ul .ul .ul {
list-style-type: square;
}
.wxParse .u {
text-decoration: underline;
}
.wxParse .hide {
display: none;
}
.wxParse .del {
display: inline;
}
.wxParse .figure {
overflow: hidden;
}
.wxParse .table {
width: 100%;
}
.wxParse .thead, .wxParse .tfoot, .wxParse .tr {
display: flex;
flex-direction: row;
}
.wxParse .tr {
width:100%;
display: flex;
border-right: 2upx solid #e0e0e0;
border-bottom: 2upx solid #e0e0e0;
}
.wxParse .th,
.wxParse .td {
display: flex;
width: 1276upx;
overflow: auto;
flex: 1;
padding: 11upx;
border-left: 2upx solid #e0e0e0;
}
.wxParse .td:last {
border-top: 2upx solid #e0e0e0;
}
.wxParse .th {
background: #f0f0f0;
border-top: 2upx solid #e0e0e0;
}
u-parse.vue
<!--**
* forked from:https://github.com/F-loat/mpvue-wxParse
*
* github地址: https://github.com/dcloudio/uParse
*
* for: uni-app框架下 富文本解析
*/-->
<template>
<!--基础元素-->
<div class="wxParse" :class="className" v-if="!loading">
<block v-for="(node,index) of nodes" :key="index">
<wxParseTemplate :node="node" />
</block>
</div>
</template>
<script>
import HtmlToJson from './libs/html2json';
import wxParseTemplate from './components/wxParseTemplate0';
export default {
name: 'wxParse',
props: {
loading: {
type: Boolean,
default: false,
},
className: {
type: String,
default: '',
},
content: {
type: String,
default: '',
},
noData: {
type: String,
default: '<div style="color: #999;text-align: center;">加载中...</div>',
},
startHandler: {
type: Function,
default() {
return (node) => {
node.attr.class = null;
node.attr.style = null;
};
},
},
endHandler: {
type: Function,
default: null,
},
charsHandler: {
type: Function,
default: null,
},
imageProp: {
type: Object,
default() {
return {
mode: 'aspectFit',
padding: 0,
lazyLoad: false,
domain: '',
};
},
},
},
components: {
wxParseTemplate,
},
data() {
return {
imageUrls: [],
};
},
computed: {
nodes() {
const {
content,
noData,
imageProp,
startHandler,
endHandler,
charsHandler,
} = this;
const parseData = content || noData;
const customHandler = {
start: startHandler,
end: endHandler,
chars: charsHandler,
};
const results = HtmlToJson(parseData, customHandler, imageProp, this);
this.imageUrls = results.imageUrls;
return results.nodes;
},
},
methods: {
navigate(href, $event) {
this.$emit('navigate', href, $event);
},
preview(src, $event) {
if (!this.imageUrls.length) return;
uni.previewImage({
current: src,
urls: this.imageUrls,
});
this.$emit('preview', src, $event);
},
removeImageUrl(src) {
const { imageUrls } = this;
imageUrls.splice(imageUrls.indexOf(src), 1);
},
},
};
</script>
uni-countdown
readme.md
### CountDown 倒计时
倒计时组件,组件名:``uni-countdown``,代码块: uCountDown。
**使用方式:**
在 ``script`` 中引用组件
import uniCountdown from "@/components/uni-countdown/uni-countdown.vue"
export default {
components: {uniCountdown}
}
一般用法
<uni-countdown
:day="1"
:hour="1"
:minute="12"
:second="40">
</uni-countdown>
不显示天数
<uni-countdown
:show-day="false"
:hour="12"
:minute="12"
:second="12">
</uni-countdown>
修改颜色
<uni-countdown
color="#FFFFFF"
background-color="#00B26A"
border-color="#00B26A"
:day="1"
:hour="2"
:minute="30"
:second="0">
</uni-countdown>
实际效果参考:[https://github.com/dcloudio/uni-ui](https://github.com/dcloudio/uni-ui)
**uniCountDown 属性说明:**
|属性名|类型|默认值 |说明|
|---|----|---|---|
|background-color|String|#FFFFFF|背景色|
|border-color|String|#000000|边框颜色|
|color |String |#000000|文字颜色|
|splitor-color|String|#000000|割符号颜色|
|day|Number|0|天数|
|hour|Number|0|小时|
|minute|Number|0|分钟|
|second|Number|0|秒|
|show-day|Boolean|true|是否显示天数|
|show-colon|Boolean|true|是否以冒号为分隔符|
**uniCountDown 事件说明:**
|事件称名|说明|返回参数|
|---|----|---|
|timeup|倒计时时间到触发事件|-|
uni-countdown.vue
<template>
<view class="uni-countdown">
<view v-if="showDay && d!=0" class="uni-countdown__number" :style="{borderColor:borderColor, color:color, background:backgroundColor}">{{d}}</view>
<view v-if="showDay && d!=0" class="uni-countdown__splitor" :style="{color:textColor}">天</view>
<view class="uni-countdown__number" :style="{borderColor:borderColor, color:color, background:backgroundColor}">{{h}}</view>
<view class="uni-countdown__splitor" :style="{color:textColor}">{{showColon ? ':' : '时'}}</view>
<view class="uni-countdown__number" :style="{borderColor:borderColor, color:color, background:backgroundColor}">{{i}}</view>
<view class="uni-countdown__splitor" :style="{color:textColor}">{{showColon ? ':' : '分'}}</view>
<view class="uni-countdown__number" :style="{borderColor:borderColor, color:color, background:backgroundColor}">{{s}}</view>
<view v-if="!showColon" class="uni-countdown__splitor" :style="{color:textColor}">秒</view>
</view>
</template>
<script>
export default {
name: "uni-countdown",
props: {
showDay: {
type: Boolean,
default: true
},
showColon: {
type: Boolean,
default: true
},
backgroundColor: {
type: String,
default: "#FFFFFF"
},
borderColor: {
type: String,
default: "#000000"
},
color: {
type: String,
// value: "#000000"
},
textColor: {
type: String,
default: "#000000"
},
splitorColor: {
type: String,
default: "#000"
},
day: {
type: Number,
default: 0
},
hour: {
type: Number,
default: 0
},
minute: {
type: Number,
default: 0
},
second: {
type: Number,
default: 0
}
},
data() {
return {
timer: null,
d: '00',
h: '00',
i: '00',
s: '00',
leftTime: 0,
seconds: 0
}
},
created: function(e) {
this.seconds = this.toSeconds(this.day, this.hour, this.minute, this.second)
this.countDown()
this.timer = setInterval(() => {
this.seconds--
if (this.seconds < 0) {
this.timeUp()
return
}
this.countDown()
}, 1000)
},
beforeDestroy() {
clearInterval(this.timer)
},
methods: {
toSeconds(day, hours, minutes, seconds) {
return (day * 60 * 60 * 24) + (hours * 60 * 60) + (minutes * 60) + seconds
},
timeUp() {
clearInterval(this.timer)
this.$emit('timeup')
},
countDown() {
let seconds = this.seconds
let [day, hour, minute, second] = [0, 0, 0, 0]
if (seconds > 0) {
day = Math.floor(seconds / (60 * 60 * 24))
hour = Math.floor(seconds / (60 * 60)) - (day * 24)
minute = Math.floor(seconds / 60) - (day * 24 * 60) - (hour * 60)
second = Math.floor(seconds) - (day * 24 * 60 * 60) - (hour * 60 * 60) - (minute * 60)
} else {
this.timeUp()
}
if (day < 10) {
day = '0' + day
}
if (hour < 10) {
hour = '0' + hour
}
if (minute < 10) {
minute = '0' + minute
}
if (second < 10) {
second = '0' + second
}
this.d = day
this.h = hour
this.i = minute
this.s = second
}
}
}
</script>
<style lang="scss">
$countdown-height:44upx;
.uni-countdown {
padding: 2upx 0;
display: inline-flex;
flex-wrap: nowrap;
justify-content: center;
&__splitor {
justify-content: center;
line-height: $countdown-height;
padding: 0 5upx;
font-size: 24upx;
// color: #d0d0d0;
}
&__number {
line-height: $countdown-height;
justify-content: center;
height: $countdown-height;
border-radius: $uni-border-radius-base;
// margin: 0 5upx;
font-size: 24upx;
// border: 1px solid #000000;
font-size: $uni-font-size-sm;
// padding: 0 10upx;
}
}
</style>
uni-fab
uni-fab.vue
<template>
<view>
<view
class="fab-box fab"
:class="{
leftBottom: leftBottom,
rightBottom: rightBottom,
leftTop: leftTop,
rightTop: rightTop
}"
>
<view
class="fab-circle"
:class="{
left: horizontal === 'left' && direction === 'horizontal',
top: vertical === 'top' && direction === 'vertical',
bottom: vertical === 'bottom' && direction === 'vertical',
right: horizontal === 'right' && direction === 'horizontal'
}"
:style="{ 'background-color': styles.buttonColor }"
@click="open"
>
<image class="icon icon-jia" src="../../../static/image/menu.png" mode="" :class="{ active: showContent }"></image>
<!-- <text class="icon icon-jia" :class="{ active: showContent }"></text> -->
</view>
<view
class="fab-content"
:class="{
left: horizontal === 'left',
right: horizontal === 'right',
flexDirection: direction === 'vertical',
flexDirectionStart: flexDirectionStart,
flexDirectionEnd: flexDirectionEnd
}"
:style="{ width: boxWidth, height: boxHeight, background: styles.backgroundColor }"
>
<view v-if="flexDirectionStart || horizontalLeft" class="fab-item first"></view>
<view
class="fab-item"
v-for="(item, index) in content"
:key="index"
:class="{ active: showContent }"
:style="{
color: item.active ? styles.selectedColor : styles.color
}"
@click="taps(index, item)"
>
<image
class="content-image icon"
:src="item.active ? item.selectedIconPath : item.iconPath"
mode=""
></image>
<text class="text">{{ item.text }}</text>
</view>
<view v-if="flexDirectionEnd || horizontalRight" class="fab-item first"></view>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
pattern: {
type: Object,
default: () => {
return {};
}
},
horizontal: {
type: String,
default: 'left'
},
vertical: {
type: String,
default: 'bottom'
},
direction: {
type: String,
default: 'horizontal'
},
content: {
type: Array,
default: () => {
return [];
}
}
},
data() {
return {
fabShow: false,
flug: true,
showContent: false,
styles: {
color: '#3c3e49',
selectedColor: '#007AFF',
backgroundColor: '#fff',
buttonColor: '#3c3e49'
}
};
},
created() {
if (this.top === 0) {
this.fabShow = true;
}
// 初始化样式
this.styles = Object.assign({}, this.styles, this.pattern);
},
methods: {
open() {
this.showContent = !this.showContent;
},
/**
* 按钮点击事件
*/
taps(index, item) {
this.$emit('trigger', {
index,
item
});
},
/**
* 获取 位置信息
*/
getPosition(types, paramA, paramB) {
if (types === 0) {
return this.horizontal === paramA && this.vertical === paramB;
} else if (types === 1) {
return this.direction === paramA && this.vertical === paramB;
} else if (types === 2) {
return this.direction === paramA && this.horizontal === paramB;
} else {
return this.showContent && this.direction === paramA
? this.contentWidth
: this.contentWidthMin;
}
}
},
watch: {
pattern(newValue, oldValue) {
// console.log(JSON.stringify(newValue));
this.styles = Object.assign({}, this.styles, newValue);
}
},
computed: {
contentWidth(e) {
return uni.upx2px((this.content.length + 1) * 90 + 20) + 'px';
},
contentWidthMin() {
return uni.upx2px(90) + 'px';
},
// 动态计算宽度
boxWidth() {
return this.getPosition(3, 'horizontal');
},
// 动态计算高度
boxHeight() {
return this.getPosition(3, 'vertical');
},
// 计算左下位置
leftBottom() {
return this.getPosition(0, 'left', 'bottom');
},
// 计算右下位置
rightBottom() {
return this.getPosition(0, 'right', 'bottom');
},
// 计算左上位置
leftTop() {
return this.getPosition(0, 'left', 'top');
},
rightTop() {
return this.getPosition(0, 'right', 'top');
},
flexDirectionStart() {
return this.getPosition(1, 'vertical', 'top');
},
flexDirectionEnd() {
return this.getPosition(1, 'vertical', 'bottom');
},
horizontalLeft() {
return this.getPosition(2, 'horizontal', 'left');
},
horizontalRight() {
return this.getPosition(2, 'horizontal', 'right');
}
}
};
</script>
<style scoped>
.fab-box {
position: fixed;
display: flex;
justify-content: center;
align-items: center;
z-index: 2;
}
.fab-box.top {
width: 60upx;
height: 60upx;
right: 30upx;
bottom: 60upx;
border: 1px #5989b9 solid;
background: #6699cc;
border-radius: 10upx;
color: #fff;
transition: all 0.3;
opacity: 0;
}
.fab-box.active {
opacity: 1;
}
.fab-box.fab {
z-index: 10;
}
.fab-box.fab.leftBottom {
left: 30upx;
bottom: 130upx;
}
.fab-box.fab.leftTop {
left: 30upx;
top: 80upx;
/* #ifdef H5 */
top: calc(80upx + var(--window-top));
/* #endif */
}
.fab-box.fab.rightBottom {
right: 30upx;
bottom: 130upx;
}
.fab-box.fab.rightTop {
right: 30upx;
top: 80upx;
/* #ifdef H5 */
top: calc(80upx + var(--window-top));
/* #endif */
}
.fab-circle {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
width: 90upx;
height: 90upx;
background: #3c3e49;
/* background: #5989b9; */
border-radius: 50%;
box-shadow: 0 0 5px 2px rgba(0, 0, 0, 0.2);
z-index: 11;
}
.fab-circle.left {
left: 0;
}
.fab-circle.right {
right: 0;
}
.fab-circle.top {
top: 0;
}
.fab-circle.bottom {
bottom: 0;
}
.fab-circle .icon-jia {
color: #ffffff;
font-size: 50upx;
transition: all 0.3s;
}
.fab-circle .icon-jia.active {
transform: rotate(90deg);
}
.fab-content {
background: #6699cc;
box-sizing: border-box;
display: flex;
border-radius: 100upx;
overflow: hidden;
box-shadow: 0 0 5px 2px rgba(0, 0, 0, 0.1);
transition: all 0.2s;
width: 110upx;
}
.fab-content.left {
justify-content: flex-start;
}
.fab-content.right {
justify-content: flex-end;
}
.fab-content.flexDirection {
flex-direction: column;
justify-content: flex-end;
}
.fab-content.flexDirectionStart {
flex-direction: column;
justify-content: flex-start;
}
.fab-content.flexDirectionEnd {
flex-direction: column;
justify-content: flex-end;
}
.fab-content .fab-item {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 90upx;
height: 90upx;
font-size: 24upx;
color: #fff;
opacity: 0;
transition: opacity 0.2s;
}
.fab-content .fab-item.active {
opacity: 1;
}
.fab-content .fab-item .content-image {
width: 60upx;
height: 60upx;
margin-bottom: 10upx;
}
.fab-content .fab-item.first {
width: 110upx;
}
/* @font-face {
font-family: 'iconfont';
src: url('https://at.alicdn.com/t/font_1028200_xhbo4rn58rp.ttf?t=1548214263520')
format('truetype');
}
.icon {
font-family: 'iconfont' !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-jia:before {
content: '\e630';
}
.icon-arrow-up:before {
content: '\e603';
} */
</style>
uni-icon
readme.md
### Icon 图标
用于展示 icon,组件名:``uni-icon``,代码块: uIcon。
**使用方式:**
在 ``script`` 中引用组件
import uniIcon from "@/components/uni-icon/uni-icon.vue"
export default {
components: {uniIcon}
}
在 ``template`` 中使用组件
<uni-icon type="contact" size="30"></uni-icon>
实际效果参考:[https://github.com/dcloudio/uni-ui](https://github.com/dcloudio/uni-ui)
**Icon 属性说明:**
|属性名 |类型|默认值 |说明|
|---|----|---|---|
|type |String |-|图标图案,参考下表|
|color |String |-|图标颜色 |
|size |Number |24|图标大小|
|@click |EventHandle|-|点击 Icon 触发事件|
**type 类型:**
<div>
<link rel="stylesheet" type="text/css" href="https://img-cdn-qiniu.dcloud.net.cn/uniapp/doc/icon1.1.css"/>
<ul class="icon-group">
<li class="icon-item"><span class="uni-icon uni-icon-contact"></span><span>contact</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-person"></span><span>person</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-personadd"></span><span>personadd</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-contact-filled"></span><span>contact-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-person-filled"></span><span>person-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-personadd-filled"></span><span>personadd-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-phone"></span><span>phone</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-email"></span><span>email</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-chatbubble"></span><span>chatbubble</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-chatboxes"></span><span>chatboxes</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-phone-filled"></span><span>phone-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-email-filled"></span><span>email-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-chatbubble-filled"></span><span>chatbubble-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-chatboxes-filled"></span><span>chatboxes-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-weibo"></span><span>weibo</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-weixin"></span><span>weixin</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-pengyouquan"></span><span>pengyouquan</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-chat"></span><span>chat</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-qq"></span><span>qq</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-videocam"></span><span>videocam</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-camera"></span><span>camera</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-mic"></span><span>mic</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-location"></span><span>location</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-mic-filled"></span><span>mic-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-location-filled"></span><span>location-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-micoff"></span><span>micoff</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-image"></span><span>image</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-map"></span><span>map</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-compose"></span><span>compose</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-trash"></span><span>trash</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-upload"></span><span>upload</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-download"></span><span>download</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-close"></span><span>close</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-redo"></span><span>redo</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-undo"></span><span>undo</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-refresh"></span><span>refresh</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-star"></span><span>star</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-plus"></span><span>plus</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-minus"></span><span>minus</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-circle"></span><span>circle</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-clear"></span><span>clear</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-refresh-filled"></span><span>refresh-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-star-filled"></span><span>star-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-plus-filled"></span><span>plus-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-minus-filled"></span><span>minus-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-circle-filled"></span><span>circle-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-checkbox-filled"></span><span>checkbox-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-closeempty"></span><span>closeempty</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-refreshempty"></span><span>refreshempty</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-reload"></span><span>reload</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-starhalf"></span><span>starhalf</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-spinner"></span><span>spinner</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-spinner-cycle"></span><span>spinner-cycle</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-search"></span><span>search</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-plusempty"></span><span>plusempty</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-forward"></span><span>forward</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-back"></span><span>back</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-checkmarkempty"></span><span>checkmarkempty</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-home"></span><span>home</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-navigate"></span><span>navigate</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-gear"></span><span>gear</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-paperplane"></span><span>paperplane</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-info"></span><span>info</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-help"></span><span>help</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-locked"></span><span>locked</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-more"></span><span>more</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-flag"></span><span>flag</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-home-filled"></span><span>home-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-gear-filled"></span><span>gear-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-info-filled"></span><span>info-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-help-filled"></span><span>help-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-more-filled"></span><span>more-filled</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-settings"></span><span>settings</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-list"></span><span>list</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-bars"></span><span>bars</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-loop"></span><span>loop</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-paperclip"></span><span>paperclip</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-eye"></span><span>eye</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-arrowup"></span><span>arrowup</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-arrowdown"></span><span>arrowdown</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-arrowleft"></span><span>arrowleft</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-arrowright"></span><span>arrowright</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-arrowthinup"></span><span>arrowthinup</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-arrowthindown"></span><span>arrowthindown</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-arrowthinleft"></span><span>arrowthinleft</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-arrowthinright"></span><span>arrowthinright</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-pulldown"></span><span>pulldown</span></li>
<li class="icon-item"><span class="uni-icon uni-icon-scan"></span><span>scan</span></li>
</ul>
</div>
uni-icon.vue
<template>
<view class="uni-icon" :class="['uni-icon-'+type]" :style="{color:color,'font-size':fontSize}" @click="onClick()"></view>
</template>
<script>
export default {
name: 'uni-icon',
props: {
/**
* 图标类型
*/
type: String,
/**
* 图标颜色
*/
color: String,
/**
* 图标大小
*/
size: [Number, String]
},
computed: {
fontSize() {
return `${this.size}px`
}
},
methods: {
onClick() {
this.$emit('click')
}
}
}
</script>
<style>
@font-face {
font-family: uniicons;
font-weight: normal;
font-style: normal;
src: url(data:font/truetype;charset=utf-8;base64,AAEAAAAQAQAABAAARkZUTYBH1lsAAHcQAAAAHEdERUYAJwBmAAB28AAAAB5PUy8yWe1cyQAAAYgAAABgY21hcGBhbBUAAAK0AAACQmN2dCAMpf40AAAPKAAAACRmcGdtMPeelQAABPgAAAmWZ2FzcAAAABAAAHboAAAACGdseWZsfgfZAAAQEAAAYQxoZWFkDdbyjwAAAQwAAAA2aGhlYQd+AyYAAAFEAAAAJGhtdHgkeBuYAAAB6AAAAMpsb2NhPEknLgAAD0wAAADCbWF4cAIjA3IAAAFoAAAAIG5hbWVceWDDAABxHAAAAg1wb3N05pkPsQAAcywAAAO8cHJlcKW5vmYAAA6QAAAAlQABAAAAAQAA6ov1dV8PPPUAHwQAAAAAANJrTZkAAAAA2DhhuQAA/yAEAAMgAAAACAACAAAAAAAAAAEAAAMg/yAAXAQAAAAAAAQAAAEAAAAAAAAAAAAAAAAAAAAFAAEAAABgAXoADAAAAAAAAgBGAFQAbAAAAQQBogAAAAAABAP/AfQABQAAApkCzAAAAI8CmQLMAAAB6wAzAQkAAAIABgMAAAAAAAAAAAABEAAAAAAAAAAAAAAAUGZFZAGAAB3mEgMs/ywAXAMgAOAAAAABAAAAAAMYAs0AAAAgAAEBdgAiAAAAAAFVAAAD6QAsBAAAYADAAMAAYADAAMAAoACAAIAAYACgAIAAgABgALMAQABAAAUAVwBeAIABAAD0AQAA9AEAAEAAVgCgAOAAwADAAFEAfgCAAGAAQABgAGAAYAA+AFEAYABAAGAAYAA0AGAAPgFAAQAAgABAAAAAJQCBAQABQAFAASwAgABgAIAAwABgAGAAwADBAQAAgACAAGAAYADBAEAARABAABcBXwATAMAAwAFAAUABQAFAAMAAwAEeAF8AVQBAAAAAAAADAAAAAwAAABwAAQAAAAABPAADAAEAAAAcAAQBIAAAAEQAQAAFAAQAAAAdAHjhAuEy4gPiM+Jk4wPjM+Ng42TkCeQR5BPkNOQ55EPkZuRo5HLlCOUw5TLlNeU35WDlY+Vl5WjlieWQ5hL//wAAAAAAHQB44QDhMOIA4jDiYOMA4zLjYONj5ADkEOQT5DTkN+RA5GDkaORw5QDlMOUy5TTlN+Vg5WLlZeVn5YDlkOYS//8AAf/k/4sfBB7XHgod3h2yHRcc6Ry9HLscIBwaHBkb+Rv3G/Eb1RvUG80bQBsZGxgbFxsWGu4a7RrsGusa1BrOGk0AAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBgAAAQAAAAAAAAABAgAAAAIAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsAAssCBgZi2wASwgZCCwwFCwBCZasARFW1ghIyEbilggsFBQWCGwQFkbILA4UFghsDhZWSCwCkVhZLAoUFghsApFILAwUFghsDBZGyCwwFBYIGYgiophILAKUFhgGyCwIFBYIbAKYBsgsDZQWCGwNmAbYFlZWRuwACtZWSOwAFBYZVlZLbACLCBFILAEJWFkILAFQ1BYsAUjQrAGI0IbISFZsAFgLbADLCMhIyEgZLEFYkIgsAYjQrIKAAIqISCwBkMgiiCKsAArsTAFJYpRWGBQG2FSWVgjWSEgsEBTWLAAKxshsEBZI7AAUFhlWS2wBCywCCNCsAcjQrAAI0KwAEOwB0NRWLAIQyuyAAEAQ2BCsBZlHFktsAUssABDIEUgsAJFY7ABRWJgRC2wBiywAEMgRSCwACsjsQQEJWAgRYojYSBkILAgUFghsAAbsDBQWLAgG7BAWVkjsABQWGVZsAMlI2FERC2wByyxBQVFsAFhRC2wCCywAWAgILAKQ0qwAFBYILAKI0JZsAtDSrAAUlggsAsjQlktsAksILgEAGIguAQAY4ojYbAMQ2AgimAgsAwjQiMtsAosS1RYsQcBRFkksA1lI3gtsAssS1FYS1NYsQcBRFkbIVkksBNlI3gtsAwssQANQ1VYsQ0NQ7ABYUKwCStZsABDsAIlQrIAAQBDYEKxCgIlQrELAiVCsAEWIyCwAyVQWLAAQ7AEJUKKiiCKI2GwCCohI7ABYSCKI2GwCCohG7AAQ7ACJUKwAiVhsAgqIVmwCkNHsAtDR2CwgGIgsAJFY7ABRWJgsQAAEyNEsAFDsAA+sgEBAUNgQi2wDSyxAAVFVFgAsA0jQiBgsAFhtQ4OAQAMAEJCimCxDAQrsGsrGyJZLbAOLLEADSstsA8ssQENKy2wECyxAg0rLbARLLEDDSstsBIssQQNKy2wEyyxBQ0rLbAULLEGDSstsBUssQcNKy2wFiyxCA0rLbAXLLEJDSstsBgssAcrsQAFRVRYALANI0IgYLABYbUODgEADABCQopgsQwEK7BrKxsiWS2wGSyxABgrLbAaLLEBGCstsBsssQIYKy2wHCyxAxgrLbAdLLEEGCstsB4ssQUYKy2wHyyxBhgrLbAgLLEHGCstsCEssQgYKy2wIiyxCRgrLbAjLCBgsA5gIEMjsAFgQ7ACJbACJVFYIyA8sAFgI7ASZRwbISFZLbAkLLAjK7AjKi2wJSwgIEcgILACRWOwAUViYCNhOCMgilVYIEcgILACRWOwAUViYCNhOBshWS2wJiyxAAVFVFgAsAEWsCUqsAEVMBsiWS2wJyywByuxAAVFVFgAsAEWsCUqsAEVMBsiWS2wKCwgNbABYC2wKSwAsANFY7ABRWKwACuwAkVjsAFFYrAAK7AAFrQAAAAAAEQ+IzixKAEVKi2wKiwgPCBHILACRWOwAUViYLAAQ2E4LbArLC4XPC2wLCwgPCBHILACRWOwAUViYLAAQ2GwAUNjOC2wLSyxAgAWJSAuIEewACNCsAIlSYqKRyNHI2EgWGIbIVmwASNCsiwBARUUKi2wLiywABawBCWwBCVHI0cjYbAGRStlii4jICA8ijgtsC8ssAAWsAQlsAQlIC5HI0cjYSCwBCNCsAZFKyCwYFBYILBAUVizAiADIBuzAiYDGllCQiMgsAlDIIojRyNHI2EjRmCwBEOwgGJgILAAKyCKimEgsAJDYGQjsANDYWRQWLACQ2EbsANDYFmwAyWwgGJhIyAgsAQmI0ZhOBsjsAlDRrACJbAJQ0cjRyNhYCCwBEOwgGJgIyCwACsjsARDYLAAK7AFJWGwBSWwgGKwBCZhILAEJWBkI7ADJWBkUFghGyMhWSMgILAEJiNGYThZLbAwLLAAFiAgILAFJiAuRyNHI2EjPDgtsDEssAAWILAJI0IgICBGI0ewACsjYTgtsDIssAAWsAMlsAIlRyNHI2GwAFRYLiA8IyEbsAIlsAIlRyNHI2EgsAUlsAQlRyNHI2GwBiWwBSVJsAIlYbABRWMjIFhiGyFZY7ABRWJgIy4jICA8ijgjIVktsDMssAAWILAJQyAuRyNHI2EgYLAgYGawgGIjICA8ijgtsDQsIyAuRrACJUZSWCA8WS6xJAEUKy2wNSwjIC5GsAIlRlBYIDxZLrEkARQrLbA2LCMgLkawAiVGUlggPFkjIC5GsAIlRlBYIDxZLrEkARQrLbA3LLAuKyMgLkawAiVGUlggPFkusSQBFCstsDgssC8riiAgPLAEI0KKOCMgLkawAiVGUlggPFkusSQBFCuwBEMusCQrLbA5LLAAFrAEJbAEJiAuRyNHI2GwBkUrIyA8IC4jOLEkARQrLbA6LLEJBCVCsAAWsAQlsAQlIC5HI0cjYSCwBCNCsAZFKyCwYFBYILBAUVizAiADIBuzAiYDGllCQiMgR7AEQ7CAYmAgsAArIIqKYSCwAkNgZCOwA0NhZFBYsAJDYRuwA0NgWbADJbCAYmGwAiVGYTgjIDwjOBshICBGI0ewACsjYTghWbEkARQrLbA7LLAuKy6xJAEUKy2wPCywLyshIyAgPLAEI0IjOLEkARQrsARDLrAkKy2wPSywABUgR7AAI0KyAAEBFRQTLrAqKi2wPiywABUgR7AAI0KyAAEBFRQTLrAqKi2wPyyxAAEUE7ArKi2wQCywLSotsEEssAAWRSMgLiBGiiNhOLEkARQrLbBCLLAJI0KwQSstsEMssgAAOistsEQssgABOistsEUssgEAOistsEYssgEBOistsEcssgAAOystsEgssgABOystsEkssgEAOystsEossgEBOystsEsssgAANystsEwssgABNystsE0ssgEANystsE4ssgEBNystsE8ssgAAOSstsFAssgABOSstsFEssgEAOSstsFIssgEBOSstsFMssgAAPCstsFQssgABPCstsFUssgEAPCstsFYssgEBPCstsFcssgAAOCstsFgssgABOCstsFkssgEAOCstsFossgEBOCstsFsssDArLrEkARQrLbBcLLAwK7A0Ky2wXSywMCuwNSstsF4ssAAWsDArsDYrLbBfLLAxKy6xJAEUKy2wYCywMSuwNCstsGEssDErsDUrLbBiLLAxK7A2Ky2wYyywMisusSQBFCstsGQssDIrsDQrLbBlLLAyK7A1Ky2wZiywMiuwNistsGcssDMrLrEkARQrLbBoLLAzK7A0Ky2waSywMyuwNSstsGossDMrsDYrLbBrLCuwCGWwAyRQeLABFTAtAABLuADIUlixAQGOWbkIAAgAYyCwASNEILADI3CwDkUgIEu4AA5RS7AGU1pYsDQbsChZYGYgilVYsAIlYbABRWMjYrACI0SzCgkFBCuzCgsFBCuzDg8FBCtZsgQoCUVSRLMKDQYEK7EGAUSxJAGIUViwQIhYsQYDRLEmAYhRWLgEAIhYsQYBRFlZWVm4Af+FsASNsQUARAAAAAAAAAAAAAAAAAAAAAAAAAAAMgAyAxj/4QMg/yADGP/hAyD/IAAAACgAKAAoAWQCCgO0BYoGDgaiB4gIgAjICXYJ8Ap6CrQLGAtsDPgN3A50D1wRyhIyEzATnhQaFHIUvBVAFeIXHBd8GEoYkBjWGTIZjBnoGmAaohsCG1QblBvqHCgcehyiHOAdDB1qHaQd6h4IHkYenh7YHzggmiDkIQwhJCE8IVwhviIcJGYkiCT0JYYmACZ4J3YntijEKQ4peim6KsQsECw+LLwtSC3eLfYuDi4mLj4uiC7QLxYvXC94L5owBjCGAAAAAgAiAAABMgKqAAMABwApQCYAAAADAgADVwACAQECSwACAgFPBAEBAgFDAAAHBgUEAAMAAxEFDyszESERJzMRIyIBEO7MzAKq/VYiAmYAAAAFACz/4QO8AxgAFgAwADoAUgBeAXdLsBNQWEBKAgEADQ4NAA5mAAMOAQ4DXgABCAgBXBABCQgKBgleEQEMBgQGDF4ACwQLaQ8BCAAGDAgGWAAKBwUCBAsKBFkSAQ4ODVEADQ0KDkIbS7AXUFhASwIBAA0ODQAOZgADDgEOA14AAQgIAVwQAQkICggJCmYRAQwGBAYMXgALBAtpDwEIAAYMCAZYAAoHBQIECwoEWRIBDg4NUQANDQoOQhtLsBhQWEBMAgEADQ4NAA5mAAMOAQ4DXgABCAgBXBABCQgKCAkKZhEBDAYEBgwEZgALBAtpDwEIAAYMCAZYAAoHBQIECwoEWRIBDg4NUQANDQoOQhtATgIBAA0ODQAOZgADDgEOAwFmAAEIDgEIZBABCQgKCAkKZhEBDAYEBgwEZgALBAtpDwEIAAYMCAZYAAoHBQIECwoEWRIBDg4NUQANDQoOQllZWUAoU1M7OzIxFxdTXlNeW1g7UjtSS0M3NTE6MjoXMBcwURExGBEoFUATFisBBisBIg4CHQEhNTQmNTQuAisBFSEFFRQWFA4CIwYmKwEnIQcrASInIi4CPQEXIgYUFjMyNjQmFwYHDgMeATsGMjYnLgEnJicBNTQ+AjsBMhYdAQEZGxpTEiUcEgOQAQoYJx6F/koCogEVHyMODh8OIC3+SSwdIhQZGSATCHcMEhIMDRISjAgGBQsEAgQPDiVDUVBAJBcWCQUJBQUG/qQFDxoVvB8pAh8BDBknGkwpEBwEDSAbEmGINBc6OiUXCQEBgIABExsgDqc/ERoRERoRfBoWEyQOEA0IGBoNIxETFAF35AsYEwwdJuMAAAIAYP+AA6ACwAAHAFcASEBFSklDOTg2JyYcGRcWDAQDTw8CAQQCQAAEAwEDBAFmAAAFAQIDAAJZAAMEAQNNAAMDAVEAAQMBRQkITEswLQhXCVcTEAYQKwAgBhAWIDYQJTIeAhUUByYnLgE1NDc1Nj8DPgE3Njc2NzYvATUmNzYmJyYnIwYHDgEXFgcUBxUOARceARcWFxYVMBUUBhQPARQjDgEHJjU0PgQCrP6o9PQBWPT+YE2OZjxYUWkEAgEBAQICAgECAg0FEwgHCAEECgQOEyhNI0woFA4ECgQBBAEEBQ4IBA4IAQECASlwHFkbMUdTYwLA9P6o9PQBWNE8Zo5NimohHwEGDgMDBgMDBgYGAwUDHSIWLCMUAgEVORM6GjMFBTMaOhM5FQEBAQoTGhkgCSEeECAIAwUCAQEBDCgMaos0Y1NHMRsAAAAAAwDA/+ADQAJgAAAAUwDAATZLsAtQWEAck5KFAAQBC56alYR6BQABqadzQkA/EQoICgADQBtLsAxQWEAck5KFAAQBC56alYR6BQABqadzQkA/EQoIBwADQBtAHJOShQAEAQuempWEegUAAamnc0JAPxEKCAoAA0BZWUuwC1BYQDUDAQELAAsBAGYEAQAKCwAKZAAKBwsKB2QJCAIHBgsHBmQAAgALAQILWQwBBgYFUAAFBQsFQhtLsAxQWEAvAwEBCwALAQBmBAEABwsAB2QKCQgDBwYLBwZkAAIACwECC1kMAQYGBVAABQULBUIbQDUDAQELAAsBAGYEAQAKCwAKZAAKBwsKB2QJCAIHBgsHBmQAAgALAQILWQwBBgYFUAAFBQsFQllZQB5VVIuKZWRiYV9eXVxUwFXATk05OC8uJyUfHhMSDQ4rCQEuAScmJy4BPwE2Nz4DNTcyPgE3PgE1NC4DIzc+ATc2JiMiDgEVHgEfASIHFBYXHgMXMxYXFh8DBgcOAQcOBAcGFSE0LgMHITY3Njc+ATcyNjI+ATI+ATI3Njc2Jz0CNCY9AycuAScmLwEuAicmJyY+ATc1JicmNzYyFxYHDgIHMQYVHgEHBgcUDgEVBw4CBw4BDwEdAQYdARQGFRQXHgIXFhceARcWFx4CFwGVAUIQRAMeCgMBAQEMBgIEBAMBAgUJAwELAwMDAgEDAgYBAVBGL0YgAQYCAwsBCwECBQQFAQIHBwMFBwMBAQIFGAsGExETEghpAoASFyEU4v7tBQwWIAkZEQEFAwQDBAMEAwIpEAwBAQUDCgMFBwEBCAkBBAQCAgcBCQEBHSByIB0BAQUDAQEBCwMEBQkJAQIEBQEDCgMFAQEMBxwPBwgYERkJIRUEBQUCAY3+uwYLAQYMBCkSExMRBRARDwUFAQwLByYLBQcEAgEJBiwaNlEoPCMaKgkIEwskCQYKBQIBLhEHCQ8FRAsDBQoDAQMDBAQDJUMSIRUUCEQHCBALBAUCAQEBAQEBCRQOMggJBwQFAgMCCAcFEggOKgcEBQQDExIMCAkDDBswKR0hIR0pFSYNAwUGAhINEhMDBAUEBwkWFQQIEAcHCAIDBAkEDAYyDgkOBQECBAIFBAsQAwQFAwAABADA/+ADQAJgAAsADABfAMwBckuwC1BYQByfnpEMBAcEqqahkIYFBge1s39OTEsdFggQBgNAG0uwDFBYQByfnpEMBAcEqqahkIYFBge1s39OTEsdFggNBgNAG0Acn56RDAQHBKqmoZCGBQYHtbN/TkxLHRYIEAYDQFlZS7ALUFhARwkBBwQGBAcGZgoBBhAEBhBkABANBBANZA8OAg0MBA0MZAAIABEBCBFZAgEABQEDBAADVwABAAQHAQRXEgEMDAtQAAsLCwtCG0uwDFBYQEEJAQcEBgQHBmYKAQYNBAYNZBAPDgMNDAQNDGQACAARAQgRWQIBAAUBAwQAA1cAAQAEBwEEVxIBDAwLUAALCwsLQhtARwkBBwQGBAcGZgoBBhAEBhBkABANBBANZA8OAg0MBA0MZAAIABEBCBFZAgEABQEDBAADVwABAAQHAQRXEgEMDAtQAAsLCwtCWVlAJGFgl5ZxcG5ta2ppaGDMYcxaWUVEOzozMSsqHx4RERERERATFCsBIzUjFSMVMxUzNTMFAS4BJyYnLgE/ATY3PgM1NzI+ATc+ATU0LgMjNz4BNzYmIyIOARUeAR8BIgcUFhceAxczFhcWHwMGBw4BBw4EBwYVITQuAwchNjc2Nz4BNzI2Mj4BMj4BMjc2NzYnPQI0Jj0DJy4BJyYvAS4CJyYnJj4BNzUmJyY3NjIXFgcOAgcxBhUeAQcGBxQOARUHDgIHDgEPAR0BBh0BFAYVFBceAhcWFx4BFxYXHgIXA0AyHDIyHDL+VQFCEEQDHgoDAQEBDAYCBAQDAQIFCQMBCwMDAwIBAwIGAQFQRi9GIAEGAgMLAQsBAgUEBQECBwcDBQcDAQECBRgLBhMRExIIaQKAEhchFOL+7QUMFiAJGREBBQMEAwQDBAMCKRAMAQEFAwoDBQcBAQgJAQQEAgIHAQkBAR0gciAdAQEFAwEBAQsDBAUJCQECBAUBAwoDBQEBDAccDwcIGBEZCSEVBAUFAgHuMjIcMjJF/rsGCwEGDAQpEhMTEQUQEQ8FBQEMCwcmCwUHBAIBCQYsGjZRKDwjGioJCBMLJAkGCgUCAS4RBwkPBUQLAwUKAwEDAwQEAyVDEiEVFAhEBwgQCwQFAgEBAQEBAQkUDjIICQcEBQIDAggHBRIIDioHBAUEAxMSDAgJAwwbMCkdISEdKRUmDQMFBgISDRITAwQFBAcJFhUECBAHBwgCAwQJBAwGMg4JDgUBAgQCBQQLEAMEBQMAAAIAYP+AA6ACwAAHAEQAMkAvQRsaCwQCAwFAAAAAAwIAA1kEAQIBAQJNBAECAgFRAAECAUUJCCckCEQJRBMQBRArACAGEBYgNhABIiYnPgE3PgE1NCcmJyYnJj8BNTYmJyY+Ajc2NzMWFx4BBwYXMBceAQcOAQcOBRUUFhcWFw4CAqz+qPT0AVj0/mBWmTUccCgEAggOBBMJBwgBAgQEAgIGDgooTCNNKBQOBAoEAQQBBAUPBwIGBwgFBAIDaVEjWm0CwPT+qPT0AVj910hADCgMAQYOIBAeIRUtIxQBAgcxFgcZGh8OMwUFMxo6EzkVAwoTGhkgCQsYFBAOEQgOBgEfISs9IQAAAAEAwP/gA0ACYABSADdANEE/PhAJBQUAAUADAQECAAIBAGYEAQAFAgAFZAACAgVPAAUFCwVCTUw4Ny4tJiQeHRIRBg4rJS4BJyYnLgE/ATY3PgM1NzI+ATc+ATU0LgMjNz4BNzYmIyIOARUeAR8BIgcUFhceAxczFhcWHwMGBw4BBw4EBwYVITQuAwLXEEQDHgoDAQEBDAYCBAQDAQIFCQMBCwMDAwIBAwIGAQFQRi9GIAEGAgMLAQsBAgUEBQECBwcDBQcDAQECBRgLBhMRExIIaQKAEhchFEgGCwEGDAQpEhMTEQUQEQ8FBQEMCwcmCwUHBAIBCQYsGjZRKDwjGioJCBMLJAkGCgUCAS4RBwkPBUQLAwUKAwEDAwQEAyVDEiEVFAgAAAAAAgDA/+ADQAJgAAsAXgDAQApNS0ocFQULBgFAS7ALUFhALgAIAQAIXAkBBwQGAAdeCgEGCwQGC2QCAQAFAQMEAANYAAEABAcBBFcACwsLC0IbS7AMUFhALQAIAQhoCQEHBAYAB14KAQYLBAYLZAIBAAUBAwQAA1gAAQAEBwEEVwALCwsLQhtALgAIAQhoCQEHBAYEBwZmCgEGCwQGC2QCAQAFAQMEAANYAAEABAcBBFcACwsLC0JZWUAUWVhEQzo5MjAqKR4dEREREREQDBQrASM1IxUjFTMVMzUzAy4BJyYnLgE/ATY3PgM1NzI+ATc+ATU0LgMjNz4BNzYmIyIOARUeAR8BIgcUFhceAxczFhcWHwMGBw4BBw4EBwYVITQuAwNAMhwyMhwyaRBEAx4KAwEBAQwGAgQEAwECBQkDAQsDAwMCAQMCBgEBUEYvRiABBgIDCwELAQIFBAUBAgcHAwUHAwEBAgUYCwYTERMSCGkCgBIXIRQB7jIyHDIy/nYGCwEGDAQpEhMTEQUQEQ8FBQEMCwcmCwUHBAIBCQYsGjZRKDwjGioJCBMLJAkGCgUCAS4RBwkPBUQLAwUKAwEDAwQEAyVDEiEVFAgAAAIAoP/AA3cCgABJAIwAXEBZYgEGB3l3EhAEAAYCQAADAgcCAwdmAAYHAAcGAGYAAgAHBgIHWQAAAAkBAAlZAAEACAUBCFkABQQEBU0ABQUEUQAEBQRFhYOAfmVjYWBPTUJALSwqKCQiChArJS4BIyIOAQcGIyImLwEmLwEmLwEuAy8BLgI1ND4CNzYnJi8BJiMiBwYjBw4CBw4BFB4BFx4BFx4BFx4BMzI+Ajc2JyYHBgcGIyInLgEnLgY2NzY3MDcyNTYzMhYfAR4BBwYXHgIfAR4BFxYXFh8BFh8BFjMyNjc2MzIeAhcWBwYDQBtnJQYMCgQwCgQKCwIlFgQBAgQGBg0QDAEKCAgCBgkHIR4QMQIdJhwkAQEBDhcPBAQECBQQI0gzLDo2NWEkFhYjIBI2KwYdJCYKFUBoNDkrGSglISMTBAMECSECAR0TDBULAi4jFSACAQoLDAEXFQsBAgMBAxYnAhwRDR8fBgoPKykjChsGBIEbOwIEAh8HCgIfGAMCAwMGBw0TDQELCgwEAwgLDgksPyE7AyQXAQEJFhgMDRYiJDMdQGE1LjAnJioCChoWQTcGaSsEAUomLy0ZLzI1PzMmGA4cFQEBEgwNAjlKHCwYCRMODgEZFwsBAwIBBBciAhgPFAQRGBoKGxYRAAADAIAAIAOAAiAAAwAGABMAPEA5EhEODQwJCAQIAwIBQAQBAQACAwECVwUBAwAAA0sFAQMDAE8AAAMAQwcHAAAHEwcTBgUAAwADEQYPKxMRIREBJSEBERcHFzcXNxc3JzcRgAMA/oD+ugKM/VrmiASeYGCeBIjmAiD+AAIA/uj4/kABrK+bBItJSYsEm6/+VAACAID/4AOAAmAAJwBVAGpAZzQyIQMEABQBAQJKAQgBThgCDAk/AQcMBUAABAACAAQCZgUDAgIBAAIBZAsKAggBCQEICWYACQwBCQxkAAYAAAQGAFkAAQAMBwEMWQAHBwsHQlFPTUtJSEZFRUQ+PCkoERIRISYQDRQrADIeARUUBwYjIiciIycjJiciByMHDgEPAT4DNTQnJicmJyY1NDYkIg4BFRQXHgIXJjUxFhUUBwYWFzMyPwI2PwEzIzY3MhcVMzIVFjMyPgE0JgGhvqNeY2WWVDcBAgECDw4REAEEBQsCTwsLBQENAgEDATVeAWrQsWc9AQMCAQIHJAIJCAYDBANlAQoJAQELCwsKAgE9WmiwZmcCQEqAS29MTxMBBAEGAgEEASMhJBMFAhYTAwEEAUNPS39qU45UWkwBBAQBAwELDAJyBgwCAQEsAQMEAwEDAQEUTYqnjgAAAAADAGD/gAOgAsAACQARABgAnrUUAQYFAUBLsApQWEA6AAEACAABCGYABgUFBl0AAgAAAQIAVwwBCAALBAgLVwAEAAMJBANXCgEJBQUJSwoBCQkFTwcBBQkFQxtAOQABAAgAAQhmAAYFBmkAAgAAAQIAVwwBCAALBAgLVwAEAAMJBANXCgEJBQUJSwoBCQkFTwcBBQkFQ1lAFgoKGBcWFRMSChEKEREREhEREREQDRYrEyEVMzUhETM1IzcRIRczNTMRAyMVJyERIYACACD9wODA4AFFgBtgIGBu/s4CAAKgwOD+QCCg/kCAgAHA/mBtbQGAAAAAAQCg/8ADdwKAAEkANkAzEhACAAMBQAACAwJoAAMAA2gAAQAEAAEEZgAAAQQATQAAAARRAAQABEVCQC0sKigkIgUQKyUuASMiDgEHBiMiJi8BJi8BJi8BLgMvAS4CNTQ+Ajc2JyYvASYjIgcGIwcOAgcOARQeARceARceARceATMyPgI3NicmA0AbZyUGDAoEMAoECgsCJRYEAQIEBgYNEAwBCggIAgYJByEeEDECHSYcJAEBAQ4XDwQEBAgUECNIMyw6NjVhJBYWIyASNisGgRs7AgQCHwcKAh8YAwIDAwYHDRMNAQsKDAQDCAsOCSw/ITsDJBcBAQkWGAwNFiIkMx1AYTUuMCcmKgIKGhZBNwYAAAAAAgCAACADgAIgAAwADwArQCgPCwoHBgUCAQgAAQFAAAEAAAFLAAEBAE8CAQABAEMAAA4NAAwADAMOKyURBRcHJwcnByc3JREBIQEDgP76iASeYGCeBIj++gLv/SEBcCAB5MebBItJSYsEm8f+HAIA/ugAAAABAID/4AOAAmAALQBBQD4iDAoDAgAmAQYDFwEBBgNABQQCAgADAAIDZgADBgADBmQAAAAGAQAGWQABAQsBQiknJSMhIB4dHRwWFBAHDysAIg4BFRQXHgIXJjUxFhUUBwYWFzMyPwI2PwEzIzY3MhcVMzIVFjMyPgE0JgJo0LFnPQEDAgECByQCCQgGAwQDZQEKCQEBCwsLCgIBPVposGZnAmBTjlRaTAEEBAEDAQsMAnIGDAIBASwBAwQDAQMBARRNiqeOAAAAAAIAYP+AA6ACwAAFAA0AbUuwClBYQCkAAQYDBgEDZgAEAwMEXQAAAAIGAAJXBwEGAQMGSwcBBgYDTwUBAwYDQxtAKAABBgMGAQNmAAQDBGkAAAACBgACVwcBBgEDBksHAQYGA08FAQMGA0NZQA4GBgYNBg0RERIRERAIFCsBIREzNSEFESEXMzUzEQKg/cDgAWD+wAFFgBtgAsD+QOAg/kCAgAHAAAAAAAcAs//hAygCZwA3AEYAWABmAHEAjwC7AQBAIZkBCwkZFBMDAAd2AQQABQEMA0wpAgIMBUB+AQUlAQ0CP0uwC1BYQFQACQgLCAkLZgAKCwELCgFmAAAHBAEAXg8BBA0HBA1kAA0DBw0DZAAMAwIDDAJmDgECAmcACAALCggLWQABBQMBTQYBBQAHAAUHWQABAQNRAAMBA0UbQFUACQgLCAkLZgAKCwELCgFmAAAHBAcABGYPAQQNBwQNZAANAwcNA2QADAMCAwwCZg4BAgJnAAgACwoIC1kAAQUDAU0GAQUABwAFB1kAAQEDUQADAQNFWUAmc3I5OLW0srGko6CfmJeUkoSDgH99fHKPc49BPzhGOUYeHREQEA4rAS4CNj8BNicuAQ4BDwEOASImJzUmPgI3NC4CBgcOBBUOAR0BHgQXFj4CNzYnJgMGLgI1NDY3NhYVFAcGJw4DFxUUHgEXFjY3PgEuAQcGJjU0Njc2HgIVFAY3BiYnJjY3NhYXFjcyPgE3NTYuBA8BIgYVFDM2HgMOARUUFxYnLgEGIg4BByMPAQYVFB4BMzY3NjIeAxcWBw4CFRQWMjY3Mz4BLgMChQcIAQEBARgdCiAgHQkKBQgGAwEBAQECAQMMFSUZGTMnIBAXFwQiLz86ISdXT0IPJEAQ6yVFMh5tTU9sQjVYHSgQCAEBDg0vUhoMAhIzPg8UEw4IDgkGFS8FCwIDAgUGCwIG9AQHBQECBxAVFhIFBgcKERAWDgYDAQEOAgsJExEODwYFAQEBEgcLBwEVAw4VGRkZCRMLAQEDDhUMAQEJARAZISIBLgEGBgYCAjIlDAkHCgUFAgIBAwQDCAcMBA4XGg4BCwsrLywbAShPFBQsRSsfDgMEEidCKmM0Df7mAhUnOSFBXwUETEFKNyv7BSAnJg0NBQ4gCB4YKRQ8NyK0AhMPEBsCAQUJDQgQGUEFAQYFEAQFAQYNtAUIBgIeLRkRBAEBAQwJFgYHCRYPFAcCEwIB/gMDAQMCAQEBBhgJDgkBBgECCxAeEzcyAgYQBw0PChAqSjcuHxQAAAYAQP+kA8ACmwAOABkAPABHAE8AcwCJQIZSAQQLZl4CDQBfOjEDBg0DQDk0AgY9CgEHCAsIBwtmEQELBAgLBGQQAg8DAAENAQANZg4BDQYBDQZkAAYGZwAMCQEIBwwIWQUBBAEBBE0FAQQEAVEDAQEEAUVRUBAPAQBtamloVlRQc1FzTUxJSENBPj0wLiIfHh0WFQ8ZEBkGBAAOAQ4SDislIiY0NjMyHgMVFA4BIyIuATU0NjIWFAYFNC4BJyYrASIOBhUUFx4BMzI3FzAXHgE+ATUnPgEAIiY0NjMyHgEVFDYyFhQGIiY0FzIXLgEjIg4DFRQWFwcUBhQeAT8BHgEzMDsCLgE1ND4BAw4QFxcQBgwKBwQLEdMKEgsXIBcXAWpEdUcGBQkdNjIsJh4VCwgXlWFBOj4BAgUEAxIsMv1UIBcXEAsSCr0hFhYhFtoGCxG0dzVhTzshPTYYAQUJClgcOyADBAMEBFCI4RchFwQICQwHChILCxIKERcXIRc4P2tCBAEKEhohJyowGR0dT2gZKgEBAQEHBkIiXgFEFyAXChILEDcXIBcXIEEBZogcM0VVLUBvJ1kBBAoDAwQ9CgoPHQ9HeEYAAAgAQP9hA8EC4gAHABAAFAAYAB0AJgAvADcAZkBjMCATAwIENiECAQI3HQwBBAABLRwCAwAsJxoXBAUDBUAAAQIAAgEAZgAAAwIAA2QIAQQGAQIBBAJXBwEDBQUDSwcBAwMFUQAFAwVFHx4VFRERKigeJh8mFRgVGBEUERQSFQkQKyUBBhUUFyEmASEWFwE+ATU0JyYnBwEWFz8BETY3JwMiBxEBLgMDFjMyNjcRBgcBDgQHFwFd/vcUGAEPBgJI/vEFBQEJCgo1RIK//m5EgL/bf0C/00pGARMQHyEilEBDJkgiBQX+pxguKSQfDL6cAQlAREpGBgEbBQb+9x9CIkuIgEDA/lp/P77E/oNEgb8ByRj+8QETBQcFA/yTFAwMAQ4FBAIvDSAmKi8ZvgAAAAAFAAX/QgP7AwAAIQA0AEAAUABgAMFADggBAgUWAQECAkAQAQE9S7ALUFhAKQoBAAADBAADWQ0IDAYEBAkHAgUCBAVZCwECAQECTQsBAgIBUQABAgFFG0uwFlBYQCINCAwGBAQJBwIFAgQFWQsBAgABAgFVAAMDAFEKAQAACgNCG0ApCgEAAAMEAANZDQgMBgQECQcCBQIEBVkLAQIBAQJNCwECAgFRAAECAUVZWUAmUlFCQSMiAQBbWVFgUmBKSEFQQlA8OzY1LSsiNCM0GhgAIQEhDg4rASIOAhUUFhcWDgQPAT4ENx4BMzI+AjU0LgEDIi4BNTQ+AzMyHgIVFA4BAiIGFRQeATI+ATU0JSIOAhUUFjMyPgI1NCYhIgYVFB4DMzI+ATQuAQIFZ72KUmlbAQgOExIQBQUIHVBGUBgaNxxnuoZPhueKdMF0K1BogkRVm29CcL5PPSoUISciFP7ODxoTDCoeDxsUDCsBsR8pBw0SFgwUIRQUIQMARHSgWGWyPBctJCEYEQUEAQYTFiQUBQVEdKBYdchz/PRTm2E6bllDJTphhUlhmlQBpycfFSMVFSMVHycKEhsPIC0MFRwQHycnHw0XEw4IFSMqIBEAAAEAV/9uA6kC0QF5AaJBjQFiAIYAdAByAHEAbgBtAGwAawBqAGkAYAAhABQAEwASABEAEAAMAAsACgAFAAQAAwACAAEAAAAbAAsAAAFHAUYBRQADAAIACwFgAV0BXAFbAVoBWQFYAUoAqACnAJ0AkACPAI4AjQCMABAADQACAJsAmgCZAJQAkwCSAAYAAQANAS4BLQEqALUAtACzAAYACQABAScBJgElASQBIwEiASEBIAEfAR4BHQEcARsBGgEZARgBFgEVARQBEwESAREBEAEPAQ4BDQEMAO0AzADLAMkAyADHAMYAxADDAMIAwQDAAL8AvgC9ALwAKwAFAAkBCgDoAOcA0wAEAAMABQAHAEABRACHAAIACwCcAJEAAgANAQsAAQAFAAMAP0BFDAELAAIACwJmAAINAAINZAANAQANAWQAAQkAAQlkCgEJBQAJBWQEAQMFBwUDB2YIAQcHZwAACwUASwAAAAVPBgEFAAVDQR4BVwFUAUMBQgFBAT8BLAErASkBKAD9APoA+AD3AOwA6wDqAOkA2wDaANkA2ACmAKUAmACVADkANwAOAA4rEy8CNT8FNT8HNT8iOwEfMRUHFQ8DHQEfERUPDSsCLwwjDwwfDRUXBx0BBxUPDyMHIy8NIycjJw8JIw8BKwIvFDU3NTc9AT8PMz8BMzUvESsBNSMPARUPDSsCLwg1PxfRAgEBAgEDAgQFAQECAgICAgMBAgMEAgMDBAQEBQYDAwcHBwkJCQsICAkKCQsLCwsMCw0NGQ0nDQ0ODA0NDQ0MDAwLCwkFBAkIBwcGBwUFBgQHBAMDAgICBAMCAQIBAgUDAgQDAgICAQEBAQMCAgMMCQQGBQYGBwQDAwMCAwIDAQEBAgQBAgICAwIDAgQDAgMDBAICAwIEBAQDBAUFAQECAgIEBQcGBgcHAwUKAQEFFgkJCQgEAgMDAQIBAQICBAMDAwYGBwgJBAQKCgsLDAslDgwNDQ4ODQ0ODQcGBAQLDAcIBQcKCwcGEAgIDAgICAonFhYLCwoKCgkJCAgGBwIDAgICAQIBAQEBAgEDAgEEAwQCBQMFBQUGBgcHAgEBBAoGCAcICQQEBAMFAwQDAwIBAQEDAQEBBQIEAwUEBQUGBgUHBwECAQICAgIBAQIBAQECAQMDAwMEBQUFBwcHBgcIBAUGBwsIAUsFBwQOBgYHBwgHBQUHBwkDBAQCEwoLDQ4HCQcICggJCQUECgoJCgkKCgcGBwUFBQUEAwQDAgIEAQIBAwMDBAQFBgUHBwYEAwcIBwgICAkICQgRCQgJCAcJDw0MChACAwgFBgYHCAgIBAYEBAYFCgUGAgEFEQ0ICgoLDA4JCAkICQgPEA4TBwwLCgQEBAQCBAMCAQIDAQEDAgQGBgUGCgsBAgMDCw8RCQoKCgUFCgEBAwsFBQcGAwQEBAQEBAQDAwMDAgMFBQMCBQMEAwQBAQMCAgICAQECAQIEAgQFBAICAgEBAQUEBQYDAwYCAgMBAQICAgECAwIEAwQEBQIDAgMDAwYDAwMEBAMHBAUEBQIDBQICAwECAgICAQEBAQECAggFBwcKCgYGBwcHCAkJCAsBAQICAgMIBQQFBgQFBQMEAgIDAQYEBAUFCwcWEAgJCQgKCgkKCQsJCwkKCAgIBAUGBQoGAAAABABeACADogIgABMAKAAsADEAN0A0MTAvLiwrKikIAgMBQAQBAAADAgADWQACAQECTQACAgFRAAECAUUCACYjGRYLCAATAhMFDisBISIOARURFBYzITI2NRE0LgMTFAYjISIuBTURNDYzBTIWFRcVFxEHESc1NwJf/kYSIRQrHAG6HCcHDBAUFRMO/kYECAcHBQQCFg8Bug4TXsQigIACIBEeEv6IHCsqHQF4CxQQDAb+Rw8WAgQFBwcIBAF4DRIBEQ1pq2sBgDz+90OEQwAAAAYAgAAAA4ACQAAfAEkAUQBZAF0AZQDfS7AoUFhAUgAPCw4HD14AEA4SDhASZgABCQEIAwEIWQADAAcDSwQCEwMACgEHCwAHWQALAA4QCw5ZABIAEQ0SEVkADQAMBg0MWQAGBQUGTQAGBgVSAAUGBUYbQFMADwsOCw8OZgAQDhIOEBJmAAEJAQgDAQhZAAMABwNLBAITAwAKAQcLAAdZAAsADhALDlkAEgARDRIRWQANAAwGDQxZAAYFBQZNAAYGBVIABQYFRllALAEAZWRhYF1cW1pXVlNST05LSkZEOjg3Ni8tJiMaFxIQDw4NDAgFAB8BHxQOKwEjJicuASsBIgYHBgcjNSMVIyIGFREUFjMhMjY1ETQmExQOASMhIiY1ETQ+AjsBNz4BNzY/ATMwOwEeAhceAx8BMzIeARUkIgYUFjI2NAYiJjQ2MhYUNzMVIwQUFjI2NCYiA0N7AwYwJBCxECMuCAQbRBsbKCkaAoAaIyMDBw4I/YANFgYJDQeICQQPAyYNDLEBAQEDBQMFDxgSCgmKCQ0H/ueOZGSOZHF0UVF0UTUiIv8AJTYlJTYB4AMHNSEfNAgFICAkGf6gGygoGwFgGiP+YwoPChYNAWAGCwcFBgUTBCoMCAECAwMFERwUCwYHDggCZI5kZI7SUXRRUXTgImk2JSU2JQADAQD/YAMAAuAACwAXADEATUBKDAsCBQMCAwUCZgAAAAMFAANZAAIAAQQCAVkABAoBBgcEBlkJAQcICAdLCQEHBwhPAAgHCEMYGBgxGDEuLSwrERETEycVFxUQDRcrACIGFREUFjI2NRE0AxQGIiY1ETQ2MhYVFxUUDgEjIiY9ASMVFBYXFSMVITUjNT4BPQECQYJdXYJdIEpoSkpoSmA7ZjtagiaLZZIBQopjhwLgYkX+y0ViYkUBNUX+hjhPTzgBNThPTziZnzxkO4Bbn59lkwd+JCR+B5NlnwAABAD0/2ADDALgABIAJAAsADkARkBDFhQTDAoGBgMEAUAYCAIDPQAAAAECAAFZAAIABQQCBVkGAQQDAwRNBgEEBANRAAMEA0UuLTQzLTkuOSopJiUhIBAHDysAIgYVFB8CGwE3Nj8BPgI1NAcVBg8BCwEmJy4BNTQ2MhYVFCYiBhQWMjY0ByImNTQ+ATIeARQOAQJv3p0TAQP19QEBAQEGCQQyAQEC1tgBAQgKisSKt2pLS2pLgCc3GSwyLBkZLALgm24zMgMG/fcCCQIDAQMQISIRb8gBAQME/jkBywMBFi4XYYiIYS63S2pLS2qTNycZLBkZLDIsGQACAQD/YAMAAuAACwAlAEFAPgoJAgMBAAEDAGYAAQAAAgEAWQACCAEEBQIEWQcBBQYGBUsHAQUFBk8ABgUGQwwMDCUMJRERERETEykVEAsXKyQyNjURNCYiBhURFCUVFA4BIyImPQEjFRQWFxUjFSE1IzU+AT0BAb+CXV2CXQF8O2Y7WoImi2WSAUKKY4ddYkUBNUViYkX+y0XhnzxkO4Bbn59lkwd+JCR+B5NlnwAAAAIA9P9gAwwC4AASAB8AK0AoDAoIBgQBPQMBAQIBaQAAAgIATQAAAAJRAAIAAkUUExoZEx8UHxAEDysAIgYVFB8CGwE3Nj8BPgI1NAUiJjU0PgEyHgEUDgECb96dEwED9fUBAQEBBgkE/vQnNxksMiwZGSwC4JtuMzIDBv33AgkCAwEDECEiEW/DNycZLBkZLDIsGQAFAQD/YAMwAuAAAwAKABUAHQA1AF9AXAcBAgEcGxQGBAACIQEEACABAwQEQAUBAgEAAQIAZgABCgEABAEAWQAEBgEDBwQDWQkBBwgIB0sJAQcHCE8ACAcIQwUENTQzMjEwLy4rKiQiHx4YFxAOBAoFCgsOKwE3AQclMjcDFRQWNxE0JiMiDgEHATY3NSMVFAcXNgc2NycGIyIuAz0BIxUUFhcVIxUhNSMBERwCAxz+7CUg413fXEIZLyYPARIJYiIiFDDqMi0TLTMjQzYpFyaLZZIBQooC0BD8kBD9EQGB60VipwE1RWIQHRP+LRoan59ANSJDqwMXIBYWKTVDI6CfZZMHfiQkAAADAED/oAPAAqAABwAXADoAkEALMQEBBzowAgMFAkBLsBhQWEAwAAYBAAEGAGYABAAFBQReCAECAAcBAgdZAAEAAAQBAFkABQMDBU0ABQUDUgADBQNGG0AxAAYBAAEGAGYABAAFAAQFZggBAgAHAQIHWQABAAAEAQBZAAUDAwVNAAUFA1IAAwUDRllAFAoINjMuLCUjGxkSDwgXChcTEAkQKwAyNjQmIgYUASEiBhURFBYzITI2NRE0JgMmIyIGDwEOBCMiJy4CLwEmIyIHAxE+ATMhMh4BFRMCuFA4OFA4AQj88BchIRcDEBchIeULDwcLByYCBAUEBQMNCQEDAwFsDRQUDv0CDgoCzAYMBwEBYDhQODhQAQghGP1yGCEhGAKOGCH+dQwGBSACAgMBAQgBAgQBdA8P/s8CCQoNBgsH/fcAAAAIAFb/PQO3AskAKQA2AFUAYwBxAIAAkQCdALJAr3IBBwxNAQYHcAELCTg3IBMEAgVMRUQZBAACKgEBAAZAVVROAwQMPgAGBwkHBglmAAUOAg4FAmYAAgAOAgBkAAABDgABZAABAWcADAALBAwLWQAJAAoDCQpZAAQAAw0EA1kSAQ0AEAgNEFkRAQcACA8HCFkADw4OD00ADw8OUQAODw5FgoFXVpiWk5KKiIGRgpF/fnd2bWxlZF1cVmNXY1FQSUhAPjIwIyIdHBcVEw4rAScPAScmDwEOARURFB4DNj8BFxYzMj8BFhcWMjc2NxcWMjY3NjURNAEuATU0PgEzMhYVFAY3Jz4BNTQuASMiBhUUFwcnLgEjBg8BETcXFjI2PwEXBSIGFREUFjI2NRE0LgEXIg4CHQEUFjI2PQEmNxUUHgEyPgE9ATQuASMGAyIOAhUUFjMyPgI1NC4BBiImNDYzMh4CFRQDqbcL28kHB9MGBgIEBAYGA83KAwQEAx4vQwUUBWQsTgMGBQIH/vw2XCdDKD1WXakzBgUxVDJMayYWyQIDAgQDusHKAgUFAtyi/aoICwsPCwUIzAQHBQMLDwsDxAUICgkFBQkFDzAOGRILKBwOGRMLEx8GGhMTDQcLCQUCnyoBZFQDA1ICCQb9vAMGBQMCAQFQVQECDV5mCAiXbhIBAgIGCAJFDvzVVbUqJ0QnVjwqtZoMERwMMVUxbEspUgpUAQEBAUgCHExVAQEBZCU1Cwf+kAgLCwgBcAUIBUcDBQcDjQcLCweND1K6BQkEBAkFugUIBQP+nQsSGQ4cKAoTGQ4SIBJkExoTBQkMBg0AAAAAAwCg/+ADgAKgAAkAEgAjAEFAPh4SEQ0MBQIGDgkIAwQBAkAABQYFaAAGAgZoAAQBAAEEAGYAAgABBAIBVwAAAANPAAMDCwNCEicYEREREAcVKykBESE3IREhEQcFJwEnARUzASc3Jy4CIyIPATMfATc+ATU0AuD94AGgIP4gAmAg/vsTAVYW/phAAWkXRhkCBwcECwgZARYqGAQEAgAg/cABwCCYEwFXF/6YQQFoF0AZAwMCCBgXKhkECgUMAAAABgDg/6ADIAKgACAALwBCAEYASgBOALhAC0A5ODAeEAYICwFAS7AUUFhAQQAKAwwDCl4OAQwNAwwNZA8BDQsDDQtkAAsICAtcAAEABgABBlkHAgIACQUCAwoAA1cACAQECE0ACAgEUgAECARGG0BDAAoDDAMKDGYOAQwNAwwNZA8BDQsDDQtkAAsIAwsIZAABAAYAAQZZBwICAAkFAgMKAANXAAgEBAhNAAgIBFIABAgERllAGU5NTEtKSUhHRkVEQ0JBNBY1GjMRFTMQEBcrASM1NCYrASIOAh0BIxUzExQWMyEyPgc1EzMlND4COwEyHgMdASMBFRQGIyEiJi8BLgQ9AQMhBzMRIxMjAzMDIxMzAyCgIhmLCxYQCaAqLyMYARoFCwkJCAYFBAIuKf59BQgLBYsFCQcGA8YBDhEM/uYDBgMEAwQDAgEwAbPoHByOHRYezh0VHgI9KBkiCRAWDCgd/bsZIgIDBgYICAoKBgJFRQYLCAUDBgcJBSj9nwENEQECAgIEBQUGAwECRED+HgHi/h4B4v4eAAAAAAIAwP+gA0AC4AALABQAP0A8FBEQDw4NDAcDPgAGAAEABgFmBwUCAwIBAAYDAFcAAQQEAUsAAQEEUAAEAQREAAATEgALAAsREREREQgTKwEVMxEhETM1IREhESUnNxcHJxEjEQJA4P3A4P8AAoD+QheVlRduIAIAIP3gAiAg/aACYDQXlZUXbf4aAeYAAgDA/6ADQAKgAAsAFAA+QDsUERAPDg0MBwEAAUAABgMGaAcFAgMCAQABAwBXAAEEBAFLAAEBBFAABAEERAAAExIACwALEREREREIEysBFTMRIREzNSERIREFBxc3JwcRIxECQOD9wOD/AAKA/kIXlZUXbiACACD94AIgIP2gAmDZF5WVF20B5v4aAAADAFH/cQOvAsAADgAdACkAJ0AkKSgnJiUkIyIhIB8eDAE9AAABAQBNAAAAAVEAAQABRRkYEgIPKwEuASIGBw4BHgI+AiYDDgEuAjY3PgEyFhcWEAMHJwcXBxc3FzcnNwMmPJuemzxQOTmg1tagOTloScXFkjQ0STePkI83b9WoqBioqBioqBipqQJGPD4+PFDW1qA5OaDW1v4cSTQ0ksXFSTY5OTZw/sQBXqinF6ioF6eoGKioAAAAAgB+AAADgAJgABMAIgBBQD4WCgIDBBsXEhAJBQABAkAVCwICPgAAAQBpAAIFAQQDAgRZAAMBAQNNAAMDAVEAAQMBRRQUFCIUIhsUFhAGEis7ATc2Nz4CNxUJARUGBwYXMBUwATUNATUiBgcmPgWAFSZKThwrQCYBgP6At2hjAgGgASj+2IyvRQEBDBg4T4M+dyMMDwwBoAEAAQChCGhkpQYBYIHBwoJcdwcZRkBOOCcAAAAAAgCAAAADgAJgAB8AKgA6QDclDAIDBCQgDQAEAgECQCYLAgA+AAIBAmkAAAAEAwAEWQADAQEDTQADAwFRAAEDAUUUHBYUGQUTKyUwNTQuAicuASc1CQE1HgEXHgEfATMwPQcnLgEjFS0BFSAXFgOAAxAsIzWLXv6AAYA3TCorSiMmFSBFr4z+2AEoAQRZI0AGGipRUSM1NwSh/wD/AKACExMUTjg+BwcIBwcIBggTd1yCwsGBtEkAAAMAYP+AA6ACwAAVAB0ALgBdQFoNAQIICwEEAQJADAEBAT8JAQQBAAEEAGYABQAIAgUIWQACAAEEAgFZAAAAAwcAA1kKAQcGBgdNCgEHBwZRAAYHBkUfHgAAJyYeLh8uGxoXFgAVABUTFBUiCxIrARQGIyIuATQ+ATMVNycVIgYUFjI2NQIgBhAWIDYQASIuATU0PgIyHgIUDgIC2H5aO2M6OmM7wMBqlpbUllT+qPT0AVj0/mBnsGY8Zo6ajmY8PGaOASBafjpjdmM6b2+AWJbUlpVrAaD0/qj09AFY/ddmsGdNjmY8PGaOmo5mPAAAAAIAQP+AA8ACwAAJABMALkArEAICAD4TDQwLCgkIBwYFCgI9AQEAAgIASwEBAAACTwMBAgACQxIaEhAEEisBIQsBIQUDJQUDFycHNychNxchBwPA/qlpaf6pARhtARUBFW4u1dVV2AEGUlIBBtgBggE+/sLE/sLFxQE+6JiY9ZX395UAAAMAYP+AA6ACwAAHABoAJgBHQEQAAAADBAADWQkBBQgBBgcFBlcABAAHAgQHVwoBAgEBAk0KAQICAVEAAQIBRQkIJiUkIyIhIB8eHRwbEA4IGgkaExALECsAIAYQFiA2EAEiLgE0PgEzMh4EFRQOAgMjFSMVMxUzNTM1IwKs/qj09AFY9P5gZ7BmZrBnNGNTRzEbPGaOPSHv7yHw8ALA9P6o9PQBWP3XZrDOsGYbMUdTYzRNjmY8An3wIe/vIQAAAAMAYP+AA6ACwAAHABgAHAA8QDkABAMFAwQFZgAFAgMFAmQAAAADBAADWQYBAgEBAk0GAQICAVIAAQIBRgkIHBsaGREQCBgJGBMQBxArACAGEBYgNhABIi4BNTQ+AjIeAhQOAgEhFSECrP6o9PQBWPT+YGewZjxmjpqOZjw8Zo7+swIA/gACwPT+qPT0AVj912awZ02OZjw8Zo6ajmY8AY0iAAAAAgBg/4ADoALAAAcAGAApQCYAAAADAgADWQQBAgEBAk0EAQICAVEAAQIBRQkIERAIGAkYExAFECsAIAYQFiA2EAEiLgE1ND4CMh4CFA4CAqz+qPT0AVj0/mBnsGY8Zo6ajmY8PGaOAsD0/qj09AFY/ddmsGdNjmY8PGaOmo5mPAACAD7/XgPCAuIAEQArACpAJwQBAAADAgADWQACAQECTQACAgFRAAECAUUCACYjGRYMCQARAhEFDisBISIOAhURFBYzITI2NRE0JhMUDgIjISIuBTURNDYzITIeAxUDW/1KFSYcEDwrArYrPDwPCA4TCv08BgsKCQcFAx4VAsQIEAwKBQLiEBwmFf1KKzw8KwK2Kzz83AoTDggDBQcJCgsGAsQVHgUKDBAIAAAAAgBR/3EDrwLAAA4AGgAZQBYaGRgXFhUUExIREA8MAD0AAABfEgEPKwEuASIGBw4BHgI+AiYDBycHJzcnNxc3FwcDJjybnps8UDk5oNbWoDk5thioqBioqBioqBipAkY8Pj48UNbWoDk5oNbW/oIYqKcXqKgXp6gYqAAAAAIAYP+AA6ACwAAHABwAQ0BADgEDABABBgQCQA8BBAE/AAYEBQQGBWYAAAADBAADWQAEAAUCBAVZAAIBAQJNAAICAVEAAQIBRRIVFBMTExAHFSsAIAYQFiA2EAAiJjQ2MzUXBzUiDgEVFBYyNjUzFAKs/qj09AFY9P7K1JaWasDAO2M6f7N+KALA9P6o9PQBWP5UltSWWIBvbzpjO1l/flpqAAAAAQBA/4ADwALAAAkAGEAVAgEAPgkIBwYFBQA9AQEAAF8SEAIQKwEhCwEhBQMlBQMDwP6paWn+qQEYbQEVARVuAYIBPv7CxP7CxcUBPgAAAAACAGD/gAOgAsAABwATADZAMwcBBQYCBgUCZgQBAgMGAgNkAAAABgUABlcAAwEBA0sAAwMBUgABAwFGERERERETExAIFisAIAYQFiA2EAcjFSM1IzUzNTMVMwKs/qj09AFY9KDwIu7uIvACwPT+qPT0AVi+7u4i8PAAAAAAAgBg/4ADoALAAAcACwAhQB4AAAADAgADVwACAQECSwACAgFRAAECAUURExMQBBIrACAGEBYgNhAHITUhAqz+qPT0AVj0oP4AAgACwPT+qPT0AVi+IgAAAAMANP9TA80C7AAHABgAKgA5QDYAAQQABAEAZgAABQQABWQAAwYBBAEDBFkABQICBU0ABQUCUgACBQJGGhkjIRkqGioXFRMSBxIrABQWMjY0JiIFFA4CIi4CND4CMh4CASIOAhUUHgEzMj4CNTQuAQEufK57e64CI0h8qryre0lJe6u8qnxI/jRRlGtAa7htUZRrP2u4AXeve3uve9Ndq3tJSXuru6t7SUl7qwEyQGqUUmy4az9rlFFtuGsAAgBg/4ADoALAAAcAEgAnQCQSERAPDgUCAAFAAAACAGgAAgEBAk0AAgIBUgABAgFGJBMQAxErACAGEBYgNhABBiMiJi8BNxc3FwKs/qj09AFY9P4gCQkECgRwJF76IwLA9P6o9PQBWP7BCQUEcCNe+yQAAAACAD7/XgPCAuIAFAAcACpAJxwbGhkYFgYBAAFAAgEAAQEATQIBAAABUQABAAFFAgAKBwAUAhQDDisBISIGFREUFjMhMjY1ETQuBQEnByc3FwEXA1v9Sis8PCsCtis8BQsOEhQX/kQFBcogrwFjIALiPCv9Sis8PCsCtgwXFREOCwX9bwUFyiCvAWMgAAEBQABgAsAB4AALAAazCAABJisBBycHFwcXNxc3JzcCqKioGKioGKioGKmpAeCpqBeoqBenqBepqAAAAAEBAAAgAwACeAAUADlANggBBAIBQAcBAgE/BgEBPgAEAgMCBANmAAEAAgQBAlkAAwAAA00AAwMAUQAAAwBFEhUUExAFEyskIiY0NjM1Fwc1Ig4BFRQWMjY1MxQCatSWlmrAwDtjOn+zfiggltSWWIBvbzpjO1l/flpqAAABAID/oAQAAqAAJgA4QDUbGgoJCAcGBQQJAgEBQAQBAAABAgABWQACAwMCTQACAgNRAAMCA0UBAB8dFxUQDgAmASYFDisBMh4BFTcXByc3FzQuAiMiDgEUHgEzMj4BNxcOASMiLgE1ND4CAgBosWduEo2FEmY5YIRJYaVgYKVhTYtjGBknyH1osWc9Z44CoGaxaGkSiIgSaUmEYDhgpcKlYD5uRwd0kmexaE6OZz0AAAIAQP+AA8ACwAAJAA8AKkAnCgcCAD4PDg0EAwIBAAgCPQEBAAICAEsBAQAAAk8AAgACQxISFQMRKyUDJQUDJSELASElFyEHFycBWG0BFQEVbQEY/qlpaf6pAcBSAQbYVdW+/sLFxQE+xAE+/sLU9pX1lwAAAgAA/yAEAAMgABQAKwA8QDkABQECAQUCZgACBAECBGQABAcBAwQDVQABAQBRBgEAAAoBQhYVAQAmJSEfFSsWKw8OCggAFAEUCA4rASIOAgc+AjMyEhUUFjI2NTQuAQMyPgM3DgMjIgI1NCYiBhUUHgECAGe7iVIDA3C+b6z0OFA4ieyLUpt8XzYCAkRvmFOs9DhQOInsAyBPhrlmd8l0/vq6KDg4KIvsifwAMl16mVJZonRFAQa6KDg4KIvsiQAADAAl/0QD2wL6AA8AHQAuADwATgBfAHAAgACVAKcAtADDAG1AapWBcAMBAE49AgYBLh4CBQa1AQkKlgECCQVAAAoFCQUKCWYACQIFCQJkCwEAAAEGAAFZCAEGBwEFCgYFWQQBAgMDAk0EAQICA1EAAwIDRQEAuLeYlzs4NDErKCMgHRwXFhEQCgkADwEPDA4rATIeAx0BFAYiJj0BNDYTMhYdARQGIiY9ATQ2MwEUBisBIi4BNTQ2OwEyHgEVIRQGKwEiJjU0NjsBMhYlFhQGDwEGJicmNj8BPgEeARcBFgYPAQ4BLgEnJjY/ATYWFwEeAQ8BDgEnLgE/AT4CFhcBHgEPAQ4BJy4BNj8BPgEXAz4BHgEfARYGBwYmLwEuAT4DNwE2MhYfARYGBw4BLgEvASY2NwE+AR8BHgEOAS8BLgEBPgEyHwEeAQ4BLwEuATcCAAUJBwYDEhgSEgwMEhIYEhIMAdsSDH4IDggSDH4IDgj9BBIMfgwSEgx+DBICvAQIB20KGAcGBwptBgwKCgP9agYGC20FDAsJAwcHC2wLGAYB6AsGBj8GGAoLBwc/AwkLDAX+ggsGBj8GGAsHCAEDPwcYCl0GDAsJAz8GBgsKGAc/AgIBAgMGAwF/Bw8OBD8GBgsFDAsJAz8HBwv91AYYCm0LBgwYC2wLBwKcBQ4PB20LBgwYC20KBwYC+gMFCAkFfQ0REQ19DRH9BBENfgwSEgx+DREBIQwRCA0IDREIDQkMEREMDRER4QgPDgQ/BgYLCxgGPwMBAwcF/oILGAY/AwEDBwULGAY/BgcKAiwGGAttCwYGBhgLbQUHAwED/WoGGAttCwYGBA4QB20LBgYClgMBAwcFbQsYBgYGC20DCAgHBwYC/WoECAdtCxgGAwEDBwVtCxgGAegLBgY/BhgWBgY/Bhj+jQcIBD8GGBYGBj8GGAsAAgCB/6ADgQKgAA8AIAAtQCoOAQIDAgFADwACAT0AAAACAwACWQADAQEDTQADAwFRAAEDAUUoGCMmBBIrBSc2NTQuASMiBhQWMzI3FwEuATU0NjIWFRQOBCMiA4HjQ1KMUn6ysn5rVOL9niYpn+GgEyM0PUUkcTHiVGtSjVGy/LNE4wEPJmQ2caCfcSVFPTQjEwAAAAEBAAAgAwACIAALACVAIgAEAwEESwUBAwIBAAEDAFcABAQBTwABBAFDEREREREQBhQrASMVIzUjNTM1MxUzAwDwIu7uIvABDu7uIvDwAAAAAQFA/+ACwAJgAAUABrMDAQEmKwE3CQEnAQFAQQE//sFBAP8CH0H+wP7AQQD/AAAAAQFA/+ACwAJgAAUABrMDAQEmKwEnCQE3AwLAQf7BAT9B/wIfQf7A/sBBAP8AAAAAAQEsAIQCywG9AAoAEkAPCgkIBwYFAD4AAABfIQEPKyUGIyImLwE3FzcXAcAJCQQKBHAkXvojjQkFBHAjXvskAAQAgP+gA4ACoAAIABEAGwAfAExASR0cGxoYFxYTERAPCAENBAcBQAABBwE/GRICBj4ABgAHBAYHVwAEAAEDBAFXBQEDAAADSwUBAwMATwIBAAMAQxkWERESERESCBYrCQERMxEzETMRAyMRIREjESUFAQc1IxUHFQkBNSUHNTMCAP7A4MDgIKD/AKABIAEg/uDAgEABgAGA/aBAQAJA/wD+YAEA/wABoP6AAQD/AAFx5uYBb5pawDMpATP+zSmAM4YAAAADAGD/gAOgAsAAGQAhACUAPkA7IgEEACUBAQQCQAAEAAEABAFmAAIFAQAEAgBZAAEDAwFNAAEBA1EAAwEDRQEAJCMfHhsaEA4AGQEZBg4rATIeARceARQGBw4EIyIuAScuATQ+AyAGEBYgNhAnBSERAgAzYVckNjo6NhYxNTk7HzNhVyQ2Ojpti/n+qPT0AVj04P5BAP8CnxoyJDeLmos3FSQbEwkaMiQ3i5qMbDoh9P6o9PQBWBTA/wAAAAQAgP+gA4ACoAASAB4ApgE3AW5LsCZQWEBhAAcAHQUHHVkJAQUfGwIaBgUaWQgBBh4BHAAGHFkhAQAAAwQAA1kKIgIEIAEZEgQZWRgBEhEBCwISC1kAAgABFAIBWRYBFA8BDRMUDVkAFQAOFQ5VFwETEwxREAEMDAsMQhtAZwAHAB0FBx1ZCQEFHxsCGgYFGlkIAQYeARwABhxZIQEAAAMEAANZCiICBCABGRIEGVkYARIRAQsCEgtZAAIAARQCAVkWARQPAQ0TFA1ZFwETEAEMFRMMWQAVDg4VTQAVFQ5RAA4VDkVZQUwAIQAfAAEAAAE2ATMBIwEiAR4BHAEQAQ0BBgEEAP8A/QD8APsA7wDsAOcA5ADZANcA0wDRAMsAyADBAL8AvAC6AKwAqQCfAJwAkgCRAI4AjACHAIQAfwB9AHkAdwBqAGcAWgBXAEwASgBGAEQAPAA5ADQAMgAtACsAHwCmACEApgAaABkAFAATAA0ADAAAABIAAQASACMADisBIg4CBwYVFB4BFxYyNjU0JyYCIiY1ND4BMh4BFRQ3IyImNTQ/ATY0LwEmIyIPAQ4CIyImPQE0JisBIgYdARQOAyMiJi8BJiMiDwEGFB8BFhUUDgErASIOAg8BDgMdARQWOwEyHgEVFA4BDwEGFB8BFjMyPwE+ATMyFh0BFBY7ATI2PQE0NjMyHwEWMj8BNjQvASY1NDY7ATI2PQI0LgEXFRQrASIHDgIVFB4BHwEWDwEGIyIvASYjIgYdARQOAisBIiY9ATQnJiMiBg8BBiMiLwEmND8BNjU0JyYrASImPQE0NjsBMjc2NTQmLwEmND8BNjMwMzIeAR8BFjMyPgE3Nj0BNDsBMh4BHQEUHwEeBDMyPwE+ATIWHwEeARUUDwEGFRQeARcWOwEyFQICFCUiIA04DRkSOJ9xOTgNhV0qSldKK68eExsPFA4OLQ4VFQ4TBAsNBhMdHBQ8FR0FCAwOCAkRBxMOFRUOLQ4OEw8MFQwfBAkICAMGAwQDAh4UHwwVDAMHBRMODi0NFhQPEwYRChMcHRQ9FB4bExQOEw4qDi0ODhQPGxMeFBsMFgIPHiAXBwoGBgsIEw0NLAUICAQTGCEfLwMFBgQ8BwsXGB8QHgsSBQgIBC0FBRIaFxYhHwcLCwcfIBcWDQwSBQUsBQgDAgMDARMXIQsTEgcYET0ECAQYCAQJCQoKBiEYEgIHBwcCLQIDBRMZBQoIFiEeDwHgBw8VDThQGjAsEjhwUE85OP6gXkIrSisrSitCkhsTFA0TDykOLA4OEgUHBBsTHhQeHhQfBw4LCAUIBxMODiwOKQ8SDhQMFgwCAwQDBgMHCAkFPBUdDBYMBwwKBRIPKQ4sDg4TBwgbEx4VHR0VHhMbEBMODi0OKQ8TDRQTHBwUHx4OFw1QHhAYBxIUCwoVEgcTDAwtBQUSGi0hHgQHBAMKCB4gFxcNDBMFBS0FDgUSGCEgFxcLBj0HCxcXIBAeCxIFDgUtBAECARMZBQoHFyAfEgUIBR8fGAYDBQQDARkSAwICAi0CBgQHBRMXIQsTEQgXEgAAAwDA/+ADQAJgAAMABgAJAAq3CAcGBQMCAyYrEx8BCQIDEwEnwOlzAST+iAE45uL+tqYBLWfmAoD+bwFM/g8B9f7GSQAEAGD/gAOgAsAABwARABkAKgBRQE4ABwAKAQcKWQABAAACAQBZAAIAAwQCA1cLBgIEAAUJBAVXDAEJCAgJTQwBCQkIUQAICQhFGxoICCMiGiobKhcWExIIEQgREREREhMSDRQrABQWMjY0JiITESMVMxUjFTM1EiAGEBYgNhABIi4BNTQ+AjIeAhQOAgHPFyIXFyI6YCAggGz+qPT0AVj0/mBnsGY8Zo6ajmY8PGaOAdkiFxciF/6AAQAQ8BAQAlD0/qj09AFY/ddmsGdNjmY8PGaOmo5mPAAEAGD/gAOgAsAABwAYADMAQABeQFsABQYHBgUHZgAHCAYHCGQAAAADBAADWQsBBAAGBQQGWQwBCAAJAggJWQoBAgEBAk0KAQICAVEAAQIBRTU0GhkJCDk4NEA1QCsqIR8eHRkzGjMREAgYCRgTEA0QKwAgBhAWIDYQASIuATU0PgIyHgIUDgIDIg4BFTMmMzIWFRQGBw4CBzM+ATc+ATU0JgMiBhQWMjY1NC4DAqz+qPT0AVj0/mBnsGY8Zo6ajmY8PGaORis8ICYCYSQyFRIXGQsBJgENIBoaRjEPExQcFAQGCAsCwPT+qPT0AVj912awZ02OZjw8Zo6ajmY8AlkbOCldLSMWJREVJikdKiEfGC4fMjv+ixMcFBQOBQsIBgMAAAAABQDA/4ADQALAAAsAEwAXACkAMQBYQFUnIAIJCgFAAAAABAEABFkFDAMDAQAHCAEHVwAIAAsKCAtZAAoACQYKCVkABgICBksABgYCTwACBgJDAAAvLisqJCMbGhcWFRQTEg8OAAsACxETEw0RKwE1NCYiBh0BIxEhESU0NjIWHQEhASERIQc0JiIGFRQWFxUUFjI2PQE+AQYiJjQ2MhYUAtB6rHpwAoD+EGeSZ/6gAdD9wAJA4CU2JRsVCQ4JFRszGhMTGhMBYJBWenpWkP4gAeCQSWdnSZD+QAGgoBslJRsWIwVSBwkJB1IFIwoTGhMTGgAAAAYAwQDgA0ABYAAHAA8AHgAnAC8ANwBFQEIKDQYDAggMBAMAAQIAWQkFAgEDAwFNCQUCAQEDUQsHAgMBA0UgHxEQNTQxMC0sKSgkIx8nICcYFhAeER4TExMQDhIrADIWFAYiJjQ2IgYUFjI2NCUyHgEVFAYjIi4CNTQ2NyIGFBYyNjQmBDIWFAYiJjQ2IgYUFjI2NAHxHhUVHhU/NiUlNiX+wQoQChUPBw4JBhUPGyUlNSYmAdYeFRUeFT82JSU2JQFEFR4VFR4xJTYlJTYJChAKDxUGCQ4HDxUcJTYlJTYlHBUeFRUeMSU2JSU2AAAAAAIBAP/gAwACYAAwAEsBIUuwC1BYQB4vFwIJA0s+AgoBPQEFCDEBBwUtKgIGBwVAGwEHAT8bS7AMUFhAHi8XAgkDSz4CCgI9AQUIMQEHBS0qAgYHBUAbAQcBPxtAHi8XAgkDSz4CCgE9AQUIMQEHBS0qAgYHBUAbAQcBP1lZS7ALUFhALwAACQEJAAFmAAMACQADCVkCAQEACggBClkACAAFBwgFWQAHAAYEBwZZAAQECwRCG0uwDFBYQC8BAQAJAgkAAmYAAwAJAAMJWQACAAoIAgpZAAgABQcIBVkABwAGBAcGWQAEBAsEQhtALwAACQEJAAFmAAMACQADCVkCAQEACggBClkACAAFBwgFWQAHAAYEBwZZAAQECwRCWVlAD0pIQkAkLDQjFikxEhALFysBIg4EIyIuAS8BJicuAiMiDgEPARkBMxE+ATMyHgEXFjMyPgM3PgE3ETUGAwYjIicuAiMiDgEHET4BMzIXHgQzMjcC4AISCBEMDwcOGh4JGxIHHCEzFipAEgUHIA0zKBMqNQ5aMQgREgsUAwoPBwwUNxYuVw03LRUYKhsLDTMoLVMGJxIgHA4XOAJAAwEBAQECBQIGBAEGBwYLCAMF/rf+5AEfBQgIDwMTAQIBAgEBAgEBOiEC/sMHEgMPCQQFAwETBQgSAQkDBgIHAAACAID/oAOAAqAACAASADVAMhIRDw4NCggBAAkBAwFAEAkCAz4AAQMAAwEAZgADAQADSwADAwBPAgEAAwBDFBEREgQSKwkBETMRMxEzEQEHNSMVBxUJATUCAP7A4MDg/sDAgEABgAGAAkD/AP5gAQD/AAGgAWCaWsAzKQEz/s0pAAIAgP+gA4ACoACBAI4ApLaIhwIHAAFAS7AmUFhAMQADAA8AAw9ZBhACAA0BBw4AB1kEAQILAQkIAglZAA4ACg4KVQUBAQEIUQwBCAgLCEIbQDcAAwAPAAMPWQYQAgANAQcOAAdZAA4JCg5NBAECCwEJCAIJWQUBAQwBCAoBCFkADg4KUQAKDgpFWUAmAgCMi4WEe3hramdlX1xXVVFPRUI8OSwqJSMbGBMRDQwAgQKBEQ4rASMiJjU0PwE2NC8BJiIPAQ4BIyImPQE0JisBIg4BHQEUDgIjIi4BLwEmIyIPAQYUHwEeAxUUBisBIg4BHQEUFjsBMhYVFA8BBhQfARYzMj8BPgEzMhYdARQWOwEyNj0BND4BMzIfARYyPwE+ATQmLwEmNTQ+ATsBMjY9AjYmBxQGIiY1MTQ+ATIeAQNRHhMbDxQODi0OKg4TBxEKExwdFD0NFg0IDREJBwwKBRMOFRUOLQ4OEwQFBAIbEh8NFw4eFB8SGw8TDg4tDRYUDxMGEgkTHB0UPRQdDRUNEw8TDikPLAcICAcTDwwVDB8UGgEbw16FXSpKV0orAW8cExMOEw4pDywODhMHCBsSHxQeDhcNHwkQDQcDBwUTDg4sDikPEgQICAkFExwNFg48FRwcExQOEg8pDiwODhMHCBsTHhQeHRUeDBUNEBIODiwHExITBxMNFA0VDRwUHx4VHE9CXl5CK0orK0oAAAMAYP+AA6ACwAAHABEAGwA3QDQAAAACAwACWQADAAcGAwdXAAYIAQUEBgVXAAQBAQRLAAQEAVEAAQQBRREREREUFBMTEAkXKwAgBhAWIDYQJDIWFRQGIiY1NBMjNTM1IzUzETMCrP6o9PQBWPT+RiIXFyIXcYAgIGAgAsD0/qj09AFYJBcREBgYEBH+hxDwEP8AAAADAGD/gAOgAsAABwAUAC4ASEBFAAUHBgcFBmYABgQHBgRkAAAABwUAB1kABAADAgQDWggBAgEBAk0IAQICAVIAAQIBRgkIKignJiUjGRgNDAgUCRQTEAkQKwAgBhAWIDYQASImNDYyFhUUDgM3DgEHIzQ+Ajc+ATU0JiMiFyM2MzIWFRQGAqz+qPT0AVj0/mkPExMdFAQGCAs+IA0BJgcOFhESFTIkYQImAYYzRhoCwPT+qPT0AVj+eBQcExMOBgoIBwPnICEqFiEfGxARJhUjLV18OzIeLwADAMEA4ANAAWAABwAQABgAK0AoBAYCAwABAQBNBAYCAwAAAVEFAwIBAAFFCQgWFRIRDQwIEAkQExAHECsAIgYUFjI2NCUiBhQWMjY0JiAiBhQWMjY0Ahs2JSU2Jf7BGyUlNSYmAgA2JSU2JQFgJTYlJTYlJTYlJTYlJTYlJTYAAAwAQP/QA8ACcAAHAA8AFwAfACcALwA1ADsAQwBLAFMAWwEES7AhUFhAYgACAAJoAAMBCgEDCmYACggBCghkAAsJBgkLBmYABgQJBgRkAAcFB2kYFwIUFgEVARQVVwAAAAEDAAFZDwEMDgENCQwNWAAIAAkLCAlZEwEQEgERBRARWAAEBAVRAAUFCwVCG0BnAAIAAmgAAwEKAQMKZgAKCAEKCGQACwkGCQsGZgAGBAkGBGQABwUHaRgXAhQWARUBFBVXAAAAAQMAAVkPAQwOAQ0JDA1YAAgACQsICVkABBAFBE0TARASAREFEBFYAAQEBVEABQQFRVlALVRUVFtUW1pZT05NTEpJSEc/Pj08Ozo5ODMyMTAtLCkoJSQTExMTExMTExAZFysAMhYUBiImNDYiBhQWMjY0AjIWFAYiJjQ2IgYUFjI2NAAyFhQGIiY0NiIGFBYyNjQXIRUhNjQiFBcjNTMBMxUjNjU0JgcUFhUhNSEGEzMVIzY1NCYnBhUUFhUhNQKzGhMTGhM6NCYmNCZNGhMTGhM6NCYmNCb+MxoTExoTOjQmJjQmHwIh/d8BwAGhoQI+oaEBAb8B/d8CIQG/oaEBAb4BAf3fAlATGhMTGjMmNCYmNP3mExoTExozJjQmJjQBFhMaExMaMyY0JiY0CiAIEBAIIP7wIAgIBAgMBAgEIAgCKCAICAQIBAgIBAgEIAAJAEQAIAO8AssAFQAnADMARABQAF0AcQB+AIwBEkuwClBYQF4XAQwLAwoMXgANAgoLDV4ABwAIAQcIWQABEgEACQEAWQAJFQEGCwkGWQADEwECDQMCWQALFgEKDwsKWQAPGQEQBQ8QWQAFFAEEEQUEWQARDg4RTQAREQ5RGAEOEQ5FG0BgFwEMCwMLDANmAA0CCgINCmYABwAIAQcIWQABEgEACQEAWQAJFQEGCwkGWQADEwECDQMCWQALFgEKDwsKWQAPGQEQBQ8QWQAFFAEEEQUEWQARDg4RTQAREQ5RGAEOEQ5FWUBGgH9zcl9eUlE1NCooGBYCAISDf4yAjHl4cn5zfmlnXnFfcVhXUV1SXUxLRkU9OzRENUQwLSgzKjMhHhYnGCcOCwAVAhUaDisBISIuBTU0NjMhMh4DFRQGByEiLgI1NDYzITIeAhUUBgchIiY0NjMhMhYUBgEiJjU0PgIzMh4BFRQOAiYiDgEUHgEyPgE0JgMiJjU0PgEyHgEUDgEnIg4BFRQeAzMyPgE1NC4DAyImNTQ+ATIeARQOASciBhQWMjY1NC4EA5r93QQHBwYFAwIUDgIjBQsIBgQUDv3dBg0JBhQOAiMHDAkGFA793Q4UFA4CIw4UFP0DKzwRGyYVGzAbEBwmCxMPCQkPExAJCRkrPBwvNzAbGzAbCg8JAwYJCgYJEAkEBggLBSs8HC83MBsbMBsOFBQcFAMEBggJAkICAwUGBwcEDhQDBgkKBg4U7wYJDAcOFAUJDQcOFO8UHRQUHRQBmjwqFSYbERwvHBUlHBCICQ8TEAkJEBMP/pI8KhwvHBwvNzAbiAkPCgULCAYECRAJBgoJBgP+iTwqHC8cHC83MBuJFB0UFA4FCQcHBAMAAwBA/+EDvwJnAAMABwALACZAIwACAAMAAgNXAAAAAQQAAVcABAQFTwAFBQsFQhEREREREAYUKxMhFSERIRUhESEVIUADf/yBA3/8gQN//IEBPDABWzD92S8AAAAEABf/iAPpArgABQAiADkAPwA9QDo/Pj08Ozo5LSwjIiEfHhQTBgUEAwIBABcCAQFAAAAAAQIAAVkAAgMDAk0AAgIDUQADAgNFLx4XLQQSKwEHJwcXNycwPQEuAyMiDgIHFz4BMh4BFxUUBgcXNjUxBw4BIi4BNTQ2NycGHQMeAjMyNjcBBxc3FzcD01NVFWppUQFBbZdSN2lcTRscMrDMrGUBAQEgAlAysMytZQEBIAICb7ptbsA2/RxpFlNTFgEgU1MWamkYAQJTlWxAHTZNMBBZZ2SsZg4GDgcEFRa4WWdkrWYKFAoEFRYCBANsuGtwYAFIaRdTUxcAAAABAV//nwKgAqAASQBLQEg6AQAFRx8KAwIDAkAABQAFaAcBAAMAaAADAgNoAAIABAECBFkAAQYGAU0AAQEGUgAGAQZGAQBDQTc2LSslIx0bCAcASQFJCA4rASIOARURFAYiJjcwETQ2NzYXHgEVERQOAgcGIyImNTARNCYjIg4BFQMUFjMWNz4CNRM0JyYiBwYHMB0DBhYzFjc2NRE2JgKJBgsGRVtFARIQIyMQEQICBAIGCAkNDQkHCgYBKRwdFAYJBAE4Gz8aOAEBYEBDLi8BDQHqBgsG/no9QUM9AdYXIwkVFQojF/4/BgoICAMHFhMBWgoNBgsG/qcqLwEZCBQXDQHBSyIQDyFLeI19VFFeAS8wTwGFCg4AAwAT//YD7QJJABcAIwAxAJpLsA9QWEAiBwEEAgUCBF4ABQMDBVwAAQYBAgQBAlkAAwMAUgAAAAsAQhtLsBhQWEAkBwEEAgUCBAVmAAUDAgUDZAABBgECBAECWQADAwBSAAAACwBCG0ApBwEEAgUCBAVmAAUDAgUDZAABBgECBAECWQADAAADTQADAwBSAAADAEZZWUAUJSQZGCsqJDElMSAfGCMZIykmCBArARQOBCMiLgM0PgMzMhcWFxYlIg4CFRQWMjY0JgciDgEVFBYyNjU0LgID7SE8WmqGRlGddVsvL1t2nFHInWMdCP4TMFhAJYvFi4tjKUYoWH5YGCg4ASAYPkM/Mx8rRFBNPE1QRCpwR0sW4iZCWjFljo7KjlgpSCpAW1tAIDkqGAAAAQDAAGADQAHgAAUABrMCAAEmKyU3CQEXAQMZJ/7A/sAnARlgKQFX/qkpAS0AAAAAAQDAAGADQAHgAAUABrMCAAEmKwEXCQE3AQMZJ/7A/sAnARkB4Cn+qQFXKf7TAAAAAQFA/+ACwAJgAAUABrMDAQEmKwEnCQE3AQLAKf6pAVcp/tMCOSf+wP7AJwEZAAAAAQFA/+ACwAJgAAUABrMDAQEmKwE3CQEnAQFAKQFX/qkpAS0COSf+wP7AJwEZAAAAAQFA/+ACwAJgACEAJUAiGRgTCwQFAAIBQAAAAgECAAFmAAICAVEAAQELAUIsFREDESsBBiIvAREUBiImNREHBicmNDc2NzYzMhYfAR4BHwEeARUUArsEDQWVCQ4JlQwKBQWuAgYFAwUBAgFYLCsDAgGkBASF/ccHCQkHAjmECwoFDgSfAQUCAQIBUCgnAgYDBwAAAAEBQP/gAsACYAAgACRAIRgTCwQEAgABQAAAAQIBAAJmAAEBAlEAAgILAkIsFREDESslJiIPARE0JiIGFREnJgcGFBcWFxYzMjY3PgE/AT4BNTQCuwQNBZUJDgmVDAoFBa4CBgUEBgEBWCwrAwKcBASFAjkHCQkH/ceECwoFDgSfAQUDAgFQKCcCBgMHAAAAAAEAwABgA0AB4AAdACpAJxYSAgABAUAAAgECaAADAANpAAEAAAFNAAEBAFIAAAEARhwUIyMEEislNi8BITI2NCYjITc2JyYiBwYHBhUUFx4BHwEWMzYBfAoKhQI5BwkJB/3HhAsKBQ4EnwEFBQFQKCcEBwdlCgyVCQ4JlQwKBQWuAgYFBwQBWCwrBQEAAQDAAGADQAHhAB4AJUAiFxMCAAEBQAACAAJpAAEAAAFNAAEBAFEAAAEARR0cIyMDECslJj8BISImNDYzIScmNz4BFhcWFxYVFAcOAQ8BBiMmAoQKCoX9xwcJCQcCOYQLCgMJCAOfAQUFAVAoJwQHB2UKDJUJDgmVDAoDAwIErgIGBQcEAVgsKwUBAAABAR7/pwLaAn8ABgAWQBMAAQA9AAEAAWgCAQAAXxEREQMRKwUTIxEjESMB/N6Rm5BZASgBsP5QAAEAX/97A6ECvQALAAAJAgcJARcJATcJAQNt/pL+lDQBbf6TNAFsAW40/pEBbwK9/pIBbDP+lP6UMwFs/pIzAW4BbQAABABV/3EDqgLIABMAJwA+AEQAAAUGLgE0Nz4BNCYnJjQ+ARceARQGJw4BJjQ3PgE0JicmNDYWFx4BFAYDJyMiJicRPgE3Mzc+AR4BFREUDgEmJzcRByMRMwMwCBgQCTI2NTIJEBgJOj4/rAgYEQgYGRgXCBEYCB8gIuHIpxchAQEhF6fFDh8eEBAbHw4f1Lq4FAkBEhgJNIaXhTQJGBIBCTycsJxSCAESFwkZPkU+GQkXEQEIIVNcU/7ggiEYAbkXIQGTCgMPGxD9HBAaDwEIMALkn/5HAAAABQBA/3wDwAK8AAsAHwAzAEgAXQAAJSEiJjQ2MyEyFhQGAyMiJjQ2OwEyNj0BNDYyFh0BDgEFIy4BJzU0NjIWHQEUFjsBMhYUBgMiJj0BPgE3MzIWFAYrASIGHQEUBiEiJj0BNCYrASImNDY7AR4BFxUUBgOg/MAOEhIOA0AOEhJuwA4SEg7ADhISHBIBNv33oCk2ARIcEhIOoA4SEu4OEgE2KaAOEhIOoA4SEgLyDhISDsAOEhIOwCk2ARL8EhwSEhwS/oASHBISDqAOEhIOoCk2AQE2KaAOEhIOoA4SEhwSAiASDqApNgESHBISDqAOEhIOoA4SEhwSATYpoA4SAAAADACWAAEAAAAAAAEACAASAAEAAAAAAAIABgApAAEAAAAAAAMAHABqAAEAAAAAAAQADwCnAAEAAAAAAAUALwEXAAEAAAAAAAYADwFnAAMAAQQJAAEAEAAAAAMAAQQJAAIADAAbAAMAAQQJAAMAOAAwAAMAAQQJAAQAHgCHAAMAAQQJAAUAXgC3AAMAAQQJAAYAHgFHAGkAYwBvAG4AZgBvAG4AdAAAaWNvbmZvbnQAAE0AZQBkAGkAdQBtAABNZWRpdW0AAGkAYwBvAG4AZgBvAG4AdAAgAE0AZQBkAGkAdQBtADoAVgBlAHIAcwBpAG8AbgAgADEALgAwADAAAGljb25mb250IE1lZGl1bTpWZXJzaW9uIDEuMDAAAGkAYwBvAG4AZgBvAG4AdAAgAE0AZQBkAGkAdQBtAABpY29uZm9udCBNZWRpdW0AAFYAZQByAHMAaQBvAG4AIAAxAC4AMAAwACAARABlAGMAZQBtAGIAZQByACAAMQAzACwAIAAyADAAMQA4ACwAIABpAG4AaQB0AGkAYQBsACAAcgBlAGwAZQBhAHMAZQAAVmVyc2lvbiAxLjAwIERlY2VtYmVyIDEzLCAyMDE4LCBpbml0aWFsIHJlbGVhc2UAAGkAYwBvAG4AZgBvAG4AdAAtAE0AZQBkAGkAdQBtAABpY29uZm9udC1NZWRpdW0AAAAAAAIAAAAAAAD/UQAyAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAEAAgBbAQIBAwEEAQUBBgEHAQgBCQEKAQsBDAENAQ4BDwEQAREBEgETARQBFQEWARcBGAEZARoBGwEcAR0BHgEfASABIQEiASMBJAElASYBJwEoASkBKgErASwBLQEuAS8BMAExATIBMwE0ATUBNgE3ATgBOQE6ATsBPAE9AT4BPwFAAUEBQgFDAUQBRQFGAUcBSAFJAUoBSwFMAU0BTgFPAVABUQFSAVMBVAFVAVYBVwFYAVkBWgFbAVwBXQd1bmlFMTAwB3VuaUUxMDEHdW5pRTEwMgd1bmlFMTMwB3VuaUUxMzEHdW5pRTEzMgd1bmlFMjAwB3VuaUUyMDEHdW5pRTIwMgd1bmlFMjAzB3VuaUUyMzAHdW5pRTIzMQd1bmlFMjMyB3VuaUUyMzMHdW5pRTI2MAd1bmlFMjYxB3VuaUUyNjIHdW5pRTI2Mwd1bmlFMjY0B3VuaUUzMDAHdW5pRTMwMQd1bmlFMzAyB3VuaUUzMDMHdW5pRTMzMgd1bmlFMzMzB3VuaUUzNjAHdW5pRTM2Mwd1bmlFMzY0B3VuaUU0MDAHdW5pRTQwMQd1bmlFNDAyB3VuaUU0MDMHdW5pRTQwNAd1bmlFNDA1B3VuaUU0MDYHdW5pRTQwNwd1bmlFNDA4B3VuaUU0MDkHdW5pRTQxMAd1bmlFNDExB3VuaUU0MTMHdW5pRTQzNAd1bmlFNDM3B3VuaUU0MzgHdW5pRTQzOQd1bmlFNDQwB3VuaUU0NDEHdW5pRTQ0Mgd1bmlFNDQzB3VuaUU0NjAHdW5pRTQ2MQd1bmlFNDYyB3VuaUU0NjMHdW5pRTQ2NAd1bmlFNDY1B3VuaUU0NjYHdW5pRTQ2OAd1bmlFNDcwB3VuaUU0NzEHdW5pRTQ3Mgd1bmlFNTAwB3VuaUU1MDEHdW5pRTUwMgd1bmlFNTAzB3VuaUU1MDQHdW5pRTUwNQd1bmlFNTA2B3VuaUU1MDcHdW5pRTUwOAd1bmlFNTMwB3VuaUU1MzIHdW5pRTUzNAd1bmlFNTM1B3VuaUU1MzcHdW5pRTU2MAd1bmlFNTYyB3VuaUU1NjMHdW5pRTU2NQd1bmlFNTY3B3VuaUU1NjgHdW5pRTU4MAd1bmlFNTgxB3VuaUU1ODIHdW5pRTU4Mwd1bmlFNTg0B3VuaUU1ODUHdW5pRTU4Ngd1bmlFNTg3B3VuaUU1ODgHdW5pRTU4OQRFdXJvBEV1cm8AAQAB//8ADwABAAAADAAAABYAAAACAAEAAQBfAAEABAAAAAIAAAAAAAAAAQAAAADVpCcIAAAAANJrTZkAAAAA2DhhuQ==) format('truetype');
}
.uni-icon {
font-family: uniicons;
font-size: 24px;
font-weight: normal;
font-style: normal;
line-height: 1;
display: inline-block;
text-decoration: none;
-webkit-font-smoothing: antialiased;
}
.uni-icon.uni-active {
color: #007aff;
}
.uni-icon-contact:before {
content: '\e100';
}
.uni-icon-person:before {
content: '\e101';
}
.uni-icon-personadd:before {
content: '\e102';
}
.uni-icon-contact-filled:before {
content: '\e130';
}
.uni-icon-person-filled:before {
content: '\e131';
}
.uni-icon-personadd-filled:before {
content: '\e132';
}
.uni-icon-phone:before {
content: '\e200';
}
.uni-icon-email:before {
content: '\e201';
}
.uni-icon-chatbubble:before {
content: '\e202';
}
.uni-icon-chatboxes:before {
content: '\e203';
}
.uni-icon-phone-filled:before {
content: '\e230';
}
.uni-icon-email-filled:before {
content: '\e231';
}
.uni-icon-chatbubble-filled:before {
content: '\e232';
}
.uni-icon-chatboxes-filled:before {
content: '\e233';
}
.uni-icon-weibo:before {
content: '\e260';
}
.uni-icon-weixin:before {
content: '\e261';
}
.uni-icon-pengyouquan:before {
content: '\e262';
}
.uni-icon-chat:before {
content: '\e263';
}
.uni-icon-qq:before {
content: '\e264';
}
.uni-icon-videocam:before {
content: '\e300';
}
.uni-icon-camera:before {
content: '\e301';
}
.uni-icon-mic:before {
content: '\e302';
}
.uni-icon-location:before {
content: '\e303';
}
.uni-icon-mic-filled:before,
.uni-icon-speech:before {
content: '\e332';
}
.uni-icon-location-filled:before {
content: '\e333';
}
.uni-icon-micoff:before {
content: '\e360';
}
.uni-icon-image:before {
content: '\e363';
}
.uni-icon-map:before {
content: '\e364';
}
.uni-icon-compose:before {
content: '\e400';
}
.uni-icon-trash:before {
content: '\e401';
}
.uni-icon-upload:before {
content: '\e402';
}
.uni-icon-download:before {
content: '\e403';
}
.uni-icon-close:before {
content: '\e404';
}
.uni-icon-redo:before {
content: '\e405';
}
.uni-icon-undo:before {
content: '\e406';
}
.uni-icon-refresh:before {
content: '\e407';
}
.uni-icon-star:before {
content: '\e408';
}
.uni-icon-plus:before {
content: '\e409';
}
.uni-icon-minus:before {
content: '\e410';
}
.uni-icon-circle:before,
.uni-icon-checkbox:before {
content: '\e411';
}
.uni-icon-close-filled:before,
.uni-icon-clear:before {
content: '\e434';
}
.uni-icon-refresh-filled:before {
content: '\e437';
}
.uni-icon-star-filled:before {
content: '\e438';
}
.uni-icon-plus-filled:before {
content: '\e439';
}
.uni-icon-minus-filled:before {
content: '\e440';
}
.uni-icon-circle-filled:before {
content: '\e441';
}
.uni-icon-checkbox-filled:before {
content: '\e442';
}
.uni-icon-closeempty:before {
content: '\e460';
}
.uni-icon-refreshempty:before {
content: '\e461';
}
.uni-icon-reload:before {
content: '\e462';
}
.uni-icon-starhalf:before {
content: '\e463';
}
.uni-icon-spinner:before {
content: '\e464';
}
.uni-icon-spinner-cycle:before {
content: '\e465';
}
.uni-icon-search:before {
content: '\e466';
}
.uni-icon-plusempty:before {
content: '\e468';
}
.uni-icon-forward:before {
content: '\e470';
}
.uni-icon-back:before,
.uni-icon-left-nav:before {
content: '\e471';
}
.uni-icon-checkmarkempty:before {
content: '\e472';
}
.uni-icon-home:before {
content: '\e500';
}
.uni-icon-navigate:before {
content: '\e501';
}
.uni-icon-gear:before {
content: '\e502';
}
.uni-icon-paperplane:before {
content: '\e503';
}
.uni-icon-info:before {
content: '\e504';
}
.uni-icon-help:before {
content: '\e505';
}
.uni-icon-locked:before {
content: '\e506';
}
.uni-icon-more:before {
content: '\e507';
}
.uni-icon-flag:before {
content: '\e508';
}
.uni-icon-home-filled:before {
content: '\e530';
}
.uni-icon-gear-filled:before {
content: '\e532';
}
.uni-icon-info-filled:before {
content: '\e534';
}
.uni-icon-help-filled:before {
content: '\e535';
}
.uni-icon-more-filled:before {
content: '\e537';
}
.uni-icon-settings:before {
content: '\e560';
}
.uni-icon-list:before {
content: '\e562';
}
.uni-icon-bars:before {
content: '\e563';
}
.uni-icon-loop:before {
content: '\e565';
}
.uni-icon-paperclip:before {
content: '\e567';
}
.uni-icon-eye:before {
content: '\e568';
}
.uni-icon-arrowup:before {
content: '\e580';
}
.uni-icon-arrowdown:before {
content: '\e581';
}
.uni-icon-arrowleft:before {
content: '\e582';
}
.uni-icon-arrowright:before {
content: '\e583';
}
.uni-icon-arrowthinup:before {
content: '\e584';
}
.uni-icon-arrowthindown:before {
content: '\e585';
}
.uni-icon-arrowthinleft:before {
content: '\e586';
}
.uni-icon-arrowthinright:before {
content: '\e587';
}
.uni-icon-pulldown:before {
content: '\e588';
}
.uni-icon-closefill:before {
content: '\e589';
}
.uni-icon-sound:before {
content: "\e590";
}
.uni-icon-scan:before {
content: "\e612";
}
</style>
uni-load-more
readme.md
### LoadMore 加载更多
用于列表中,做滚动加载使用,展示 loading 的各种状态,组件名:``uni-load-more``,代码块: uLoadMore。
**使用方式:**
在 ``script`` 中引用组件
import uniLoadMore from "@/components/uni-load-more/uni-load-more.vue"
export default {
components: {uniLoadMore}
}
在 ``template`` 中使用组件
<uni-load-more status="loading"></uni-load-more>
实际效果参考:[https://github.com/dcloudio/uni-ui](https://github.com/dcloudio/uni-ui)
**属性说明:**
|属性名 |类型|默认值 |说明|
|---|----|---|---|
|status |String |more|loading 的状态,可选值:more(loading前)、loading(loading中)、noMore(没有更多了)|
|show-icon |Boolean |true|是否显示 loading 图标|
|color |String |#777777|图标和文字颜色 |
|content-text |Object |```{contentdown: "上拉显示更多",contentrefresh: "正在加载...",contentnomore: "没有更多数据了"}```|各状态文字说明|
uni-load-more.vue
<template>
<view class="uni-load-more">
<view class="uni-load-more__img" v-show="status === 'loading' && showIcon">
<view class="load1">
<view :style="{background:color}"></view>
<view :style="{background:color}"></view>
<view :style="{background:color}"></view>
<view :style="{background:color}"></view>
</view>
<view class="load2">
<view :style="{background:color}"></view>
<view :style="{background:color}"></view>
<view :style="{background:color}"></view>
<view :style="{background:color}"></view>
</view>
<view class="load3">
<view :style="{background:color}"></view>
<view :style="{background:color}"></view>
<view :style="{background:color}"></view>
<view :style="{background:color}"></view>
</view>
</view>
<text class="uni-load-more__text" :style="{color:color}">{{status === 'more' ? contentText.contentdown : (status === 'loading' ? contentText.contentrefresh : contentText.contentnomore)}}</text>
</view>
</template>
<script>
export default {
name: "uni-load-more",
props: {
status: {
//上拉的状态:more-loading前;loading-loading中;noMore-没有更多了
type: String,
default: 'more'
},
showIcon: {
type: Boolean,
default: true
},
color: {
type: String,
default: "#999"
},
contentText: {
type: Object,
default () {
return {
contentdown: "上拉显示更多",
contentrefresh: "正在加载...",
contentnomore: "没有更多数据了"
};
}
}
},
data() {
return {}
}
}
</script>
<style lang="scss">
.uni-load-more {
display: flex;
flex-direction: row;
height: 80upx;
align-items: center;
justify-content: center;
&__text {
font-size: 26upx;
color: $uni-text-color-grey;
}
&__img {
height: 24px;
width: 24px;
margin-right: 10px;
&>view {
position: absolute;
view {
width: 6px;
height: 2px;
border-top-left-radius: 1px;
border-bottom-left-radius: 1px;
background: $uni-text-color-grey;
position: absolute;
opacity: 0.2;
transform-origin: 50%;
animation: load 1.56s ease infinite;
&:nth-child(1) {
transform: rotate(90deg);
top: 2px;
left: 9px;
}
&:nth-child(2) {
transform: rotate(180deg);
top: 11px;
right: 0px;
}
&:nth-child(3) {
transform: rotate(270deg);
bottom: 2px;
left: 9px;
}
&:nth-child(4) {
top: 11px;
left: 0px;
}
}
}
}
}
.load1,
.load2,
.load3 {
height: 24px;
width: 24px;
}
.load2 {
transform: rotate(30deg);
}
.load3 {
transform: rotate(60deg);
}
.load1 view:nth-child(1) {
animation-delay: 0s;
}
.load2 view:nth-child(1) {
animation-delay: 0.13s;
}
.load3 view:nth-child(1) {
animation-delay: 0.26s;
}
.load1 view:nth-child(2) {
animation-delay: 0.39s;
}
.load2 view:nth-child(2) {
animation-delay: 0.52s;
}
.load3 view:nth-child(2) {
animation-delay: 0.65s;
}
.load1 view:nth-child(3) {
animation-delay: 0.78s;
}
.load2 view:nth-child(3) {
animation-delay: 0.91s;
}
.load3 view:nth-child(3) {
animation-delay: 1.04s;
}
.load1 view:nth-child(4) {
animation-delay: 1.17s;
}
.load2 view:nth-child(4) {
animation-delay: 1.30s;
}
.load3 view:nth-child(4) {
animation-delay: 1.43s;
}
@-webkit-keyframes load {
0% {
opacity: 1;
}
100% {
opacity: 0.2;
}
}
</style>
uni-number-box
readme.md
### NumberBox 数字输入框
带加减按钮的数字输入框,组件名:``uni-number-box``,代码块: uNumberBox。
**使用方式:**
在 ``script`` 中引用组件
import uniNumberBox from "@/components/uni-number-box/uni-number-box.vue"
export default {
components: {uniNumberBox}
}
在 ``template`` 中使用组件
<uni-number-box></uni-number-box>
<uni-number-box :min="0" :max="9"></uni-number-box>
<uni-number-box @change="bindChange"></uni-number-box>
实际效果参考:[https://github.com/dcloudio/uni-ui](https://github.com/dcloudio/uni-ui)
**NumberBox 属性说明:**
|属性名 |类型 |默认值 |说明 |
|--- |---- |--- |--- |
|value |Number |0 |输入框当前值 |
|min |Number |0 |最小值 |
|max |Number |100 |最大值 |
|step |Number |1 |每次点击改变的间隔大小 |
|disabled |Boolean|false |是否为禁用状态 |
**事件说明:**
|事件名称 |说明 |
|---|---|
|change |输入框值改变时触发的事件,参数为输入框当前的 value|
uni-number-box.vue
<template>
<view class="uni-numbox">
<view class="uni-numbox__minus" :class="{'uni-numbox--disabled': disableSubtract||disabled}" @click="_calcValue('subtract')">-</view>
<input class="uni-numbox__value" type="number" :disabled="disabled" :value="inputValue" @blur="_onBlur">
<view class="uni-numbox__plus" :class="{'uni-numbox--disabled': disableAdd||disabled}" @click="_calcValue('add')">+</view>
</view>
</template>
<script>
export default {
name: 'uni-number-box',
props: {
value: {
type: Number,
default: 1
},
min: {
type: Number,
default: 0
},
max: {
type: Number,
default: 9999
},
step: {
type: Number,
default: 1
},
disabled: {
type: Boolean,
default: false
}
},
data() {
return {
inputValue: this.value
}
},
computed: {
disableSubtract() {
return this.inputValue <= this.min
},
disableAdd() {
return this.inputValue >= this.max
}
},
watch: {
value(val) {
this.inputValue = val;
},
inputValue(val) {
this.$emit('change', val);
}
},
methods: {
_calcValue(type) {
if (this.disabled) {
return
}
const scale = this._getDecimalScale()
let value = this.inputValue * scale
let step = this.step * scale
if (type === 'subtract') {
value -= step
} else if (type === 'add') {
value += step
}
if (value < this.min || value > this.max) {
return
}
this.inputValue = value / scale;
},
_getDecimalScale() {
let scale = 1
// 浮点型
if (~~this.step !== this.step) {
scale = Math.pow(10, (this.step + '').split('.')[1].length)
}
return scale
},
_onBlur(event) {
let value = event.detail.value
if (!value) {
this.inputValue = 0
return
}
value = +value;
if (value > this.max) {
value = this.max
} else if (value < this.min) {
value = this.min
}
this.inputValue = value
}
}
}
</script>
<style lang="scss">
$numbox-btn-width:44upx;
$numbox-input-width:44upx;
$numbox-height:52upx;
$uni-font-size-xxl:32upx;
.uni-numbox {
display: inline-flex;
flex-direction: row;
justify-content: flex-start;
height: $numbox-height;
position: relative;
&:after {
content: '';
position: absolute;
transform-origin: center;
box-sizing: border-box;
pointer-events: none;
top: -50%;
left: -50%;
right: -50%;
bottom: -50%;
// border: 1px solid $uni-border-color;
border-radius: $uni-border-radius-lg;
transform: scale(.5);
}
&__minus,
&__plus {
margin: 0;
// background-color: $uni-bg-color-grey;
width: $numbox-btn-width;
font-size: $uni-font-size-xxl;
height: 100%;
line-height: $numbox-height;
text-align: center;
color: $uni-text-color;
position: relative;
}
&__value {
position: relative;
background-color: $uni-bg-color;
width: $numbox-input-width;
height: 100%;
text-align: center;
min-height: 40upx;
font-size: 26upx;
&:after {
content: '';
position: absolute;
transform-origin: center;
box-sizing: border-box;
pointer-events: none;
top: -50%;
left: -50%;
right: -50%;
bottom: -50%;
border-style: solid;
border-color: $uni-border-color;
border-left-width: 0px;
border-right-width: 0px;
border-top-width: 0;
border-bottom-width: 0;
transform: scale(.5);
}
}
&--disabled {
color: $uni-text-color-disable;
}
}
</style>
uni-rate
readme.md
### Rate 评分
评分组件,组件名:``uni-rate``,代码块: uRate。
**使用方式:**
在 ``script`` 中引用组件
import uniRate from "@/components/uni-rate/uni-rate.vue"
export default {
components: {uniRate}
}
基本用法
<uni-rate value="2"></uni-rate>
自定义星星大小
<uni-rate size="18" value="5"></uni-rate>
设置评分数
<uni-rate max="10" value="5"></uni-rate>
不可点击状态
<uni-rate disabled="true" value="3.5"></uni-rate>
实际效果参考:[https://github.com/dcloudio/uni-ui](https://github.com/dcloudio/uni-ui)
**属性说明:**
|属性名|类型|默认值 |说明|
|---|----|---|---|
|value|Number|0|当前评分|
|max|Number|5|最大的评分|
|size|Number|24|星星的大小|
|margin|Number|0|星星的间距|
|color|String|#ececec|星星的颜色|
|active-color|String|#ffca3e|选中状态的星星的颜色|
|is-fill|Boolean|true|星星的类型,是否为实心类型|
|disabled|Boolean|false|是否为不可点击状态|
**事件说明:**
|事件称名|说明|返回参数|
|---|----|---|
|change|Rate 的 value 改变时触发事件,返回参数为Rate的value|{value:Number}|
uni-rate.vue
<template>
<view class="uni-rate">
<view class="uni-rate-icon" v-for="(star,index) in stars" :key="index" :style="{marginLeft:margin+'px'}" @click="onClick(index)">
<uni-icon :size="size" :color="color" :type="isFill === false || isFill === 'false' ? 'star' : 'star-filled'"></uni-icon>
<view class="uni-rate-icon-on" :style="{width:star.activeWitch}">
<uni-icon :size="size" :color="activeColor" type="star-filled"></uni-icon>
</view>
</view>
</view>
</template>
<script>
import uniIcon from '../uni-icon/uni-icon.vue'
export default {
name: "uni-rate",
components: {
uniIcon
},
props: {
isFill: { //星星的类型,是否镂空
type: [Boolean, String],
default: true
},
color: { //星星的颜色
type: String,
default: '#ececec'
},
activeColor: { //星星选中状态颜色
type: String,
default: '#ffca3e'
},
size: { //星星的大小
type: [Number, String],
default: 24
},
value: { //当前评分
type: [Number, String],
default: 0
},
max: { //最大评分
type: [Number, String],
default: 5
},
margin: { //星星的间距
type: [Number, String],
default: 0
},
disabled: { //是否可点击
type: [Boolean, String],
default: false
},
id: {
type: [Number, String],
default: 1
}
},
data() {
// console.log('data')
return {
maxSync: this.max,
valueSync: this.value
}
},
computed: {
stars() {
const max = Number(this.maxSync) ? Number(this.maxSync) : 5
const value = Number(this.valueSync) ? Number(this.valueSync) : 0
const starList = []
const floorValue = Math.floor(value)
const ceilValue = Math.ceil(value)
for (let i = 0; i < max; i++) {
if (floorValue > i) {
starList.push({
activeWitch: '100%'
})
} else if (ceilValue - 1 === i) {
starList.push({
activeWitch: (value - floorValue) * 100 + '%'
})
} else {
starList.push({
activeWitch: '0'
})
}
}
return starList
}
},
methods: {
onClick(index) {
if (this.disabled === true || this.disabled === 'true') {
return
}
this.valueSync = index + 1
this.$emit('change', {
id: this.id,
value: this.valueSync
})
}
}
}
</script>
<style lang="scss">
.uni-rate {
line-height: 0;
font-size: 0;
display: flex;
flex-direction: row;
&-icon {
position: relative;
line-height: 0;
font-size: 0;
display: inline-block;
&-on {
position: absolute;
top: 0;
left: 0;
overflow: hidden;
}
}
}
</style>
uni-segmented-control
uni-segmented-control.vue
<template>
<view class="segmented-control" :class="styleType" :style="wrapStyle">
<view v-for="(item, index) in values" class="segmented-control-item" :class="styleType" :key="index" :style="index === currentIndex ? activeStyle : itemStyle" @click="onClick(index)">
{{item}}
</view>
</view>
</template>
<script>
export default {
name: 'uni-segmented-control',
props: {
current: {
type: Number,
default: 0
},
values: {
type: Array,
default () {
return [];
}
},
activeColor: {
type: String,
default: '#007aff'
},
styleType: {
type: String,
default: 'button'
}
},
data() {
return {
currentIndex: this.current
}
},
watch: {
current(val) {
if (val !== this.currentIndex) {
this.currentIndex = val;
}
}
},
computed: {
wrapStyle() {
let styleString = '';
switch (this.styleType) {
case 'text':
styleString = `border:0;`;
break;
default:
styleString = `border-color: ${this.activeColor}`;
break;
}
return styleString;
},
itemStyle() {
let styleString = '';
switch (this.styleType) {
case 'text':
styleString = `color:#999;border-left:0;`;
break;
default:
styleString = `color:${this.activeColor};border-color:${this.activeColor};`;
break;
}
return styleString;
},
activeStyle() {
let styleString = '';
switch (this.styleType) {
case 'text':
styleString = `color:${this.activeColor};border-left:0;border-bottom-style:solid;border-bottom-width:4upx`;
break;
default:
styleString = `color:#fff;border-color:${this.activeColor};background-color:${this.activeColor}`;
break;
}
return styleString;
}
},
methods: {
onClick(index) {
if (this.currentIndex !== index) {
this.currentIndex = index;
this.$emit('clickItem', index);
}
}
},
}
</script>
<style>
.segmented-control {
display: flex;
flex-direction: row;
justify-content: center;
width: 75%;
font-size: 28upx;
border-radius: 10upx;
box-sizing: border-box;
margin: 0 auto;
overflow: hidden;
}
.segmented-control.button {
border: 2upx solid;
}
.segmented-control.text {
border: 0;
border-radius: 0upx;
}
.segmented-control-item {
flex: 1;
text-align: center;
line-height: 60upx;
box-sizing: border-box;
}
.segmented-control-item.button {
border-left: 1upx solid;
}
.segmented-control-item.text {
border-left: 0;
}
.segmented-control-item:first-child {
border-left-width: 0;
}
</style>
uni-swipe-action
readme.md
### SwipeAction 滑动操作
通过滑动触发选项的容器,组件名:``uni-swipe-action``
**使用方式:**
在 ``script`` 中引用组件
import uniSwipeAction from "@/components/uni-swipe-action"
export default {
components: {uniSwipeAction}
}
一般用法
<uni-swipe-action :options="[
{
text: '取消',
style: {
backgroundColor: '#007aff'
}
}, {
text: '确认',
style: {
backgroundColor: '#dd524d'
}
}
]">
<view class='cont'>SwipeAction 基础使用场景</view>
</uni-swipe-action>
禁止滑动
<uni-swipe-action :disabled="true" :options="[
{
text: '取消',
style: {
backgroundColor: '#007aff'
}
}, {
text: '确认',
style: {
backgroundColor: '#dd524d'
}
}
]">
<view class='cont'>点击按钮自动关闭</view>
</uni-swipe-action>
传递点击事件
<uni-swipe-action @click="bindClick" :options="[
{
text: '取消',
style: {
backgroundColor: '#007aff'
}
}, {
text: '确认',
style: {
backgroundColor: '#dd524d'
}
}
]">
<view class='cont'>点击选项时触发事件</view>
</uni-swipe-action>
与 List 组件使用
<uni-list>
<uni-swipe-action :options="options1">
<uni-list-item title="item1" show-arrow="false"></uni-list-item>
</uni-swipe-action>
<uni-swipe-action :options="options2">
<uni-list-item title="item2" show-arrow="false"></uni-list-item>
</uni-swipe-action>
<uni-swipe-action :options="options3">
<uni-list-item title="item3" show-arrow="false"></uni-list-item>
</uni-swipe-action>
</uni-list>
**SwipeAction 属性说明:**
|属性名|类型|默认值|是否必填 |说明|
|:--|:--|:--|:--|:--|
|is-opened|Boolean|false|否|是否为开启状态|
|disabled|Boolean|false|否|是否禁止滑动|
|auto-close|Boolean|true|否|在组件开启状态时点击组件,是否自动关闭|
|options|Array<Object>|-|是|组件选项内容及样式|
options 参数说明
|参数|类型|是否必填|说明|
|:--|:--|:--|:--|
|text|String|是|按钮的文字|
|style|Object|否|按钮样式{backgroundColor,color,fontSize},backgroundColor默认为:#C7C6CD,color默认为:#FFFFFF,fontSize默认为:28upx|
**SwipeAction 事件说明:**
|事件称名|说明|返回参数|
|:--|:---|:--|
|click|点击选项按钮时触发事件|{text,style,index} ,text(按钮文字)、style(按钮的样式)、index(下标)|
|opened|完全打开时触发|-|
|closed|完全关闭时触发|-|
uni-swipe-action.vue
<template>
<view class="uni-swipe-action">
<view class="uni-swipe-action__container" :class="!isMoving ? 'animtion' : ''" @touchstart="touchStart" @touchmove="touchMove" @touchend="touchEnd" @touchcancel="touchEnd" @click="bindClickCont" :style="{'transform':transformX,'-webkit-transform':transformX}">
<view class="uni-swipe-action__content">
<slot></slot>
</view>
<view class="uni-swipe-action__btn-group" :id="elId">
<div v-for="(item,index) in options" :key="index" class="uni-swipe-action--btn" :style="{backgroundColor: item.style && item.style.backgroundColor ? item.style.backgroundColor : '#C7C6CD',color: item.style && item.style.color ? item.style.color : '#FFFFFF',fontSize: item.style && item.style.fontSize ? item.style.fontSize : '28upx'}" @click="bindClickBtn(item,index)">
{{item.text}}
</div>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'uni-swipe-action',
props: {
isOpened: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
autoClose: {
type: Boolean,
default: true
},
options: Array
},
watch: {
isOpened(newValue, oldValue) {
this.isShowBtn = newValue ? true : false;
this.endMove();
}
},
data() {
const elId = `Uni_${Math.ceil(Math.random() * 10e5).toString(36)}`
return {
elId: elId,
moveLength: 0,
isMoving: false,
direction: '',
startX: 0,
startY: 0,
isShowBtn: false,
btnGroupWidth: 0
}
},
// #ifdef H5
mounted() {
let view = uni.createSelectorQuery().select(`#${this.elId}`);
view.fields({
size: true
}, data => {
this.btnGroupWidth = data.width;
}).exec();
if (this.isOpened === true) {
this.isShowBtn = true;
this.endMove();
}
},
// #endif
// #ifndef H5
onReady() {
let view = uni.createSelectorQuery().select(`#${this.elId}`);
view.fields({
size: true
}, data => {
this.btnGroupWidth = data.width;
}).exec();
if (this.isOpened === true) {
this.isShowBtn = true;
this.endMove();
}
},
// #endif
computed: {
transformX() {
return `translateX(${this.moveLength}px)`
}
},
methods: {
bindClickBtn(item, index) {
this.$emit('click', {
text: item.text,
style: item.style,
index: index,
key: item.key
})
},
bindClickCont(e) {
if (this.isShowBtn && this.autoClose === true) {
this.isShowBtn = false;
this.endMove();
}
},
touchStart(event) {
this.startX = event.touches[0].pageX;
this.startY = event.touches[0].pageY;
},
touchMove(event) {
if (this.direction === 'Y' || this.disabled === true) {
return;
}
var moveY = event.touches[0].pageY - this.startY,
moveX = event.touches[0].pageX - this.startX;
if (!this.isMoving && Math.abs(moveY) > Math.abs(moveX)) { //纵向滑动
this.direction = 'Y';
return;
}
this.direction = moveX > 0 ? 'right' : 'left';
this.isMoving = true;
},
touchEnd(event) {
this.isMoving = false;
if (this.direction !== 'right' && this.direction !== 'left') {
this.direction = '';
return;
}
if (this.direction == 'right') {
this.isShowBtn = false
} else {
this.isShowBtn = true
}
this.endMove()
},
endMove() {
if (this.direction === 'Y' || this.disabled === true) {
this.direction = '';
return;
}
if (this.isShowBtn) {
this.moveLength = -this.btnGroupWidth;
this.$emit('opened');
} else {
this.moveLength = 0;
this.$emit('closed');
}
this.direction = '';
}
}
}
</script>
<style>
@charset "UTF-8";
.uni-swipe-action {
width: 100%;
overflow: hidden
}
.uni-swipe-action__container {
background-color: #fff;
width: 200%;
display: flex;
flex-direction: row;
flex-wrap: wrap
}
.uni-swipe-action__container.animtion {
transition: transform 350ms cubic-bezier(.165, .84, .44, 1)
}
.uni-swipe-action__content {
width: 50%
}
.uni-swipe-action__btn-group {
display: flex;
flex-direction: row
}
.uni-swipe-action--btn {
padding: 0 32upx;
color: #fff;
background-color: #c7c6cd;
font-size: 28upx;
display: inline-flex;
text-align: center;
flex-direction: row;
align-items: center
}
</style>
config
api.js
import {
apiBaseUrl
} from './config.js';
import * as common from './common.js' //引入common
import * as db from './db.js' //引入common
// 需要登陆的,都写到这里,否则就是不需要登陆的接口
const methodsToken = [
'user.info',
'user.editinfo',
'user.changeavatar',
'user.logout',
'user.addgoodsbrowsing',
'user.delgoodsbrowsing',
'user.goodsbrowsing',
'user.goodscollection',
'user.goodscollectionlist',
'user.vuesaveusership',
'user.saveusership',
'user.getshipdetail',
'user.setdefship',
'user.editship',
'user.removeship',
'user.getusership',
'user.pay',
'user.orderevaluate',
'user.getuserdefaultship',
'user.issign',
'user.sign',
'user.mypoint',
'user.userpointlog',
'user.getbankcardlist',
'user.getdefaultbankcard',
'user.addbankcard',
'user.removebankcard',
'user.setdefaultbankcard',
'user.getbankcardinfo',
'user.editpwd',
'user.forgotpwd',
'user.recommend',
'user.balancelist',
'user.sharecode',
'user.cash',
'user.cashlist',
'user.myinvite',
'user.activationinvite',
'coupon.getcoupon',
'coupon.usercoupon',
'cart.add',
'cart.del',
'cart.getlist',
'cart.setnums',
'cart.getnumber',
'order.cancel',
'order.del',
'order.details',
'order.confirm',
'order.getlist',
'order.create',
'order.getship',
'order.getorderlist',
'order.getorderstatusnum',
'order.aftersaleslist',
'order.aftersalesinfo',
'order.aftersalesstatus',
'order.addaftersales',
'order.sendreship',
'order.iscomment',
'payments.getinfo',
'user.getuserpoint',
'coupon.getcouponkey',
'store.isclerk',
'store.storeladinglist',
'store.ladinginfo',
'store.lading',
'store.ladingdel',
'distribution_center-api-info',
'distribution_center-api-applydistribution',
'distribution_center-api-setstore',
'distribution_center-api-myorder',
'pintuan.pintuanteam',
'lottery-api-getLotteryConfig',
'lottery-api-lottery',
'lottery-api-lotteryLog'
];
const post = (method, data, callback) => {
uni.showLoading({
title: '加载中'
});
// 判断token是否存在
if (methodsToken.indexOf(method) >= 0) {
// 获取用户token
let userToken = db.get("userToken");
if (!userToken) {
common.jumpToLogin();
return false;
} else {
data.token = userToken;
}
}
data.method = method;
uni.request({
url: apiBaseUrl + 'api.html',
data: data,
header: {
'Accept': 'application/json',
'Content-Type': 'application/json',
// 'Content-Type': 'application/x-www-form-urlencoded', //自定义请求头信息
},
method: 'POST',
success: (response) => {
uni.hideLoading();
const result = response.data
if (!result.status) {
// 登录信息过期或者未登录
if (result.data === 14007 || result.data === 14006) {
db.del("userToken");
uni.showToast({
title: result.msg,
icon: 'none',
duration: 1000,
complete: function() {
setTimeout(function() {
uni.hideToast();
// #ifdef H5 || APP-PLUS
uni.navigateTo({
url: '/pages/login/login/index1'
})
// #endif
// #ifdef MP-WEIXIN || MP-ALIPAY
uni.navigateTo({
url: '/pages/login/choose/index',
animationType: 'pop-in',
animationDuration: 200
});
// #endif
}, 1000)
}
});
}
}
callback(result);
},
complete: () => {
uni.hideLoading();
},
fail: (error) => {
uni.hideLoading();
if (error && error.response) {
showError(error.response);
}
},
});
}
//插件post
const pluginsPost = (method, data, callback) => {
uni.showLoading({
title: '加载中'
});
// 判断token是否存在
if (methodsToken.indexOf(method) >= 0) {
// 获取用户token
let userToken = db.get("userToken");
if (!userToken) {
common.jumpToLogin();
return false;
} else {
data.token = userToken;
}
}
uni.request({
url: apiBaseUrl + 'plugins/' + method + '.html',
data: data,
header: {
'Accept': 'application/json',
'Content-Type': 'application/json',
// 'Content-Type': 'application/x-www-form-urlencoded', //自定义请求头信息
},
method: 'POST',
success: (response) => {
uni.hideLoading();
const result = response.data
if (!result.status) {
// 登录信息过期或者未登录
if (result.data === 14007 || result.data === 14006) {
db.del("userToken");
uni.showToast({
title: result.msg,
icon: 'none',
duration: 1000,
complete: function() {
setTimeout(function() {
uni.hideToast();
// #ifdef H5 || APP-PLUS
uni.navigateTo({
url: '/pages/login/login/index1'
})
// #endif
// #ifdef MP-WEIXIN || MP-ALIPAY
uni.navigateTo({
url: '/pages/login/choose/index',
animationType: 'pop-in',
animationDuration: 200
});
// #endif
}, 1000);
}
});
}
}
callback(result);
},
fail: (error) => {
uni.hideLoading();
if (error && error.response) {
showError(error.response);
}
},
complete: () => {
setTimeout(function() {
uni.hideLoading();
}, 250);
}
});
}
const get = (url, callback) => {
uni.showLoading({
title: '加载中'
});
uni.request({
url: url,
header: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded', //自定义请求头信息
},
method: 'GET',
success: (response) => {
uni.hideLoading();
callback(response.data);
},
fail: (error) => {
uni.hideLoading();
if (error && error.response) {
showError(error.response);
}
},
complete: () => {
setTimeout(function() {
uni.hideLoading();
}, 250);
}
});
}
const showError = error => {
let errorMsg = ''
switch (error.status) {
case 400:
errorMsg = '请求参数错误'
break
case 401:
errorMsg = '未授权,请登录'
break
case 403:
errorMsg = '跨域拒绝访问'
break
case 404:
errorMsg = `请求地址出错: ${error.config.url}`
break
case 408:
errorMsg = '请求超时'
break
case 500:
errorMsg = '服务器内部错误'
break
case 501:
errorMsg = '服务未实现'
break
case 502:
errorMsg = '网关错误'
break
case 503:
errorMsg = '服务不可用'
break
case 504:
errorMsg = '网关超时'
break
case 505:
errorMsg = 'HTTP版本不受支持'
break
default:
errorMsg = error.msg
break
}
uni.showToast({
title: errorMsg,
icon: 'none',
duration: 1000,
complete: function() {
setTimeout(function() {
uni.hideToast();
}, 1000);
}
});
}
// 文件上传
export const uploadFiles = (callback) => {
uni.chooseImage({
success: (chooseImageRes) => {
uni.showLoading({
title: '上传中...'
});
const tempFilePaths = chooseImageRes.tempFilePaths;
const uploadTask = uni.uploadFile({
url: apiBaseUrl + 'api.html', //仅为示例,非真实的接口地址
filePath: tempFilePaths[0],
fileType: 'image',
name: 'file',
headers: {
'Accept': 'application/json',
'Content-Type': 'multipart/form-data',
},
formData: {
'method': 'images.upload',
'upfile': tempFilePaths[0]
},
success: (uploadFileRes) => {
callback(JSON.parse(uploadFileRes.data));
},
fail: (error) => {
if (error && error.response) {
showError(error.response);
}
},
complete: () => {
setTimeout(function() {
uni.hideLoading();
}, 250);
}
});
// uploadTask.onProgressUpdate((res) => {
// console.log('上传进度' + res.progress);
// console.log('已经上传的数据长度' + res.totalBytesSent);
// console.log('预期需要上传的数据总长度' + res.totalBytesExpectedToSend);
//
// // 测试条件,取消上传任务。
// if (res.progress > 50) {
// uploadTask.abort();
// }
// });
}
});
}
// 上传图片
export const uploadImage = (num, callback) => {
uni.chooseImage({
count: num,
success: (res) => {
uni.showLoading({
title: '上传中...'
});
let tempFilePaths = res.tempFilePaths
for (var i = 0; i < tempFilePaths.length; i++) {
uni.uploadFile({
url: apiBaseUrl + 'api.html',
filePath: tempFilePaths[i],
fileType: 'image',
name: 'file',
headers: {
'Accept': 'application/json',
'Content-Type': 'multipart/form-data',
},
formData: {
'method': 'images.upload',
'upfile': tempFilePaths[i]
},
success: (uploadFileRes) => {
callback(JSON.parse(uploadFileRes.data));
},
fail: (error) => {
if (error && error.response) {
showError(error.response);
}
},
complete: () => {
setTimeout(function() {
uni.hideLoading();
}, 250);
},
});
}
}
});
}
// 获取店铺配置
export const shopConfig = (callback) => get(apiBaseUrl + 'api/common/jshopconf', callback);
// 用户注册
export const reg = (data, callback) => post('user.reg', data, callback);
// 用户登录
export const login = (data, callback) => post('user.login', data, callback);
// 用户信息
export const userInfo = (data, callback) => post('user.info', data, callback);
// 上传头像
export const changeAvatar = (data, callback) => post('user.changeavatar', data, callback);
// 编辑用户信息
export const editInfo = (data, callback) => post('user.editinfo', data, callback);
// 发送短信验证码
export const sms = (data, callback) => post('user.sms', data, callback);
// 短信验证码登录
export const smsLogin = (data, callback) => post('user.smslogin', data, callback);
// 退出登录
export const logout = (data, callback) => post('user.logout', data, callback);
// 获取首页幻灯片
export const slider = (data, callback) => post('advert.getAdvertList', data, callback);
// 获取广告
export const advert = (data, callback) => post('advert.getcarousellists', data, callback);
// 获取公告列表
export const notice = (data, callback) => post('notice.noticeList', data, callback);
// 获取公告详情
export const noticeInfo = (data, callback) => post('notice.noticeInfo', data, callback);
// 获取文章详情
export const articleInfo = (data, callback) => post('articles.getArticleDetail', data, callback);
// 获取文章列表
export const articleList = (data, callback) => post('articles.getArticleList', data, callback);
// 获取商品分类
export const categories = (data, callback) => post('categories.getallcat', data, callback);
// 获取商品列表
export const goodsList = (data, callback) => post('goods.getlist', data, callback);
// 获取商品详情
export const goodsDetail = (data, callback) => post('goods.getdetial', data, callback);
// 获取商品参数信息
export const goodsParams = (data, callback) => post('goods.getgoodsparams', data, callback);
// 获取设置默认货品
export const getProductInfo = (data, callback) => post('goods.getproductinfo', data, callback);
// 获取商品评论信息
export const goodsComment = (data, callback) => post('goods.getgoodscomment', data, callback);
// 添加购物车
export const addCart = (data, callback) => post('cart.add', data, callback);
// 移除购物车
export const removeCart = (data, callback) => post('cart.del', data, callback);
// 获取购物车列表
export const cartList = (data, callback) => post('cart.getlist', data, callback);
// 设置购物车商品数量
export const setCartNum = (data, callback) => post('cart.setnums', data, callback);
// 获取购物车数量
export const getCartNum = (data, callback) => post('cart.getnumber', data, callback);
// 获取用户的收货地址列表
export const userShip = (data, callback) => post('user.getusership', data, callback);
// 获取用户默认收货地址
export const userDefaultShip = (data, callback) => post('user.getuserdefaultship', data, callback);
// 存储用户收货地址
export const saveUserShip = (data, callback) => post('user.vuesaveusership', data, callback);
// 微信存储收货地址
export const saveUserShipWx = (data, callback) => post('user.saveusership', data, callback);
//获取区域ID
export const getAreaId = (data, callback) => post('user.getareaid', data, callback);
// 获取收货地址详情
export const shipDetail = (data, callback) => post('user.getshipdetail', data, callback);
// 收货地址编辑
export const editShip = (data, callback) => post('user.editship', data, callback);
// 收货地址删除
export const removeShip = (data, callback) => post('user.removeship', data, callback);
// 设置默认收货地址
export const setDefShip = (data, callback) => post('user.setdefship', data, callback);
// 生成订单
export const createOrder = (data, callback) => post('order.create', data, callback);
// 获取状态订单列表
export const getOrderList = (data, callback) => post('order.getlist', data, callback);
// 取消订单
export const cancelOrder = (data, callback) => post('order.cancel', data, callback);
// 删除订单
export const delOrder = (data, callback) => post('order.del', data, callback);
// 获取订单详情
export const orderDetail = (data, callback) => post('order.details', data, callback);
// 确认收货
export const confirmOrder = (data, callback) => post('order.confirm', data, callback);
// 获取配送方式
export const orderShip = (data, callback) => post('order.getship', data, callback);
// 获取全部订单列表
export const orderList = (data, callback) => post('order.getorderlist', data, callback);
// 获取订单不同状态的数量
export const getOrderStatusSum = (data, callback) => post('order.getorderstatusnum', data, callback);
// 售后单列表
export const afterSalesList = (data, callback) => post('order.aftersaleslist', data, callback);
// 售后单详情
export const afterSalesInfo = (data, callback) => post('order.aftersalesinfo', data, callback);
// 订单售后状态
export const afterSalesStatus = (data, callback) => post('order.aftersalesstatus', data, callback);
// 添加售后单
export const addAfterSales = (data, callback) => post('order.addaftersales', data, callback);
// 用户发送退货包裹
export const sendShip = (data, callback) => post('order.sendreship', data, callback);
// 添加商品浏览足迹
export const addGoodsBrowsing = (data, callback) => post('user.addgoodsbrowsing', data, callback);
// 删除商品浏览足迹
export const delGoodsBrowsing = (data, callback) => post('user.delgoodsbrowsing', data, callback);
// 获取商品浏览足迹
export const goodsBrowsing = (data, callback) => post('user.goodsbrowsing', data, callback);
// 商品收藏 关注/取消
export const goodsCollection = (data, callback) => post('user.goodscollection', data, callback);
// 获取商品收藏关注列表
export const goodsCollectionList = (data, callback) => post('user.goodscollectionlist', data, callback);
// 获取店铺支付方式列表
export const paymentList = (data, callback) => post('payments.getlist', data, callback);
// 获取支付单详情
export const paymentInfo = (data, callback) => post('payments.getinfo', data, callback);
// 支付接口
export const pay = (data, callback) => post('user.pay', data, callback);
// 订单评价接口
export const orderEvaluate = (data, callback) => post('user.orderevaluate', data, callback);
// 判断是否签到
export const isSign = (data, callback) => post('user.issign', data, callback);
// 签到接口
export const sign = (data, callback) => post('user.sign', data, callback);
// 我的积分
export const myPoint = (data, callback) => post('user.mypoint', data, callback);
// 积分记录
export const pointLog = (data, callback) => post('user.userpointlog', data, callback);
// 物流信息接口
export const logistics = (data, callback) => post('order.logisticbyapi', data, callback);
// 优惠券列表
export const couponList = (data, callback) => post('coupon.couponlist', data, callback);
// 优惠券详情
export const couponDetail = (data, callback) => post('coupon.coupondetail', data, callback);
// 用户领取优惠券
export const getCoupon = (data, callback) => post('coupon.getcoupon', data, callback);
// 用户已领取的优惠券列表
export const userCoupon = (data, callback) => post('coupon.usercoupon', data, callback);
// 获取店铺设置
export const getSetting = (data, callback) => post('user.getsetting', data, callback);
// 获取商户配置信息
export const getSellerSetting = (data, callback) => post('user.getsellersetting', data, callback);
// 获取我的银行卡列表
export const getBankCardList = (data, callback) => post('user.getbankcardlist', data, callback);
// 获取默认的银行卡
export const getDefaultBankCard = (data, callback) => post('user.getdefaultbankcard', data, callback);
// 添加银行卡
export const addBankCard = (data, callback) => post('user.addbankcard', data, callback);
// 删除银行卡
export const removeBankCard = (data, callback) => post('user.removebankcard', data, callback);
// 设置默认银行卡
export const setDefaultBankCard = (data, callback) => post('user.setdefaultbankcard', data, callback);
// 获取银行卡信息
export const getBankCardInfo = (data, callback) => post('user.getbankcardinfo', data, callback);
// 获取银行卡组织信息
export const getBankCardOrganization = (data, callback) => post('user.getbankcardorganization', data, callback);
// 用户修改密码
export const editPwd = (data, callback) => post('user.editpwd', data, callback);
// 用户找回密码
export const forgotPwd = (data, callback) => post('user.forgotpwd', data, callback);
// 获取用户余额明细
export const getBalanceList = (data, callback) => post('user.balancelist', data, callback);
// 用户推荐列表
export const recommendList = (data, callback) => post('user.recommend', data, callback);
// 邀请码
export const shareCode = (data, callback) => post('user.sharecode', data, callback);
// 用户提现
export const userToCash = (data, callback) => post('user.cash', data, callback);
// 用户提现列表
export const cashList = (data, callback) => post('user.cashlist', data, callback);
// 绑定授权登录
export const trustBind = (data, callback) => post('user.trustbind', data, callback);
// 获取用户信息
// export const trustLogin = (data, callback) => post('user.trustcallback', data, callback);
// 判断用户下单可以使用多少积分
export const usablePoint = (data, callback) => post('user.getuserpoint', data, callback);
// 门店列表
export const storeList = (data, callback) => post('store.getstorelist', data, callback);
// 判断是否开启门店自提
export const switchStore = (data, callback) => post('store.getstoreswitch', data, callback);
// 获取默认的门店
export const defaultStore = (data, callback) => post('store.getdefaultstore', data, callback);
// 判断是否开启积分
export const isPoint = (data, callback) => post('user.ispoint', data, callback);
// 用户输入code领取优惠券
export const couponKey = (data, callback) => post('coupon.getcouponkey', data, callback);
// 判断是否是店员
export const isStoreUser = (data, callback) => post('store.isclerk', data, callback);
// 获取店铺提货单列表
export const storeLadingList = (data, callback) => post('store.storeladinglist', data, callback);
// 获取提货单详情
export const ladingInfo = (data, callback) => post('store.ladinginfo', data, callback);
// 店铺提单操作
export const ladingExec = (data, callback) => post('store.lading', data, callback);
// 提货单删除
export const ladingDel = (data, callback) => post('store.ladingdel', data, callback);
// 获取活动列表
export const activityList = (data, callback) => post('group.getlist', data, callback);
// 获取活动详情
export const activityDetail = (data, callback) => post('group.getgoodsdetial', data, callback);
//小程序解析code
export const login1 = (data, callback) => post('user.wxapplogin1', data, callback);
//小程序登录第二步
export const login2 = (data, callback) => post('user.wxapplogin2', data, callback);
//支付宝小程序解析code
export const alilogin1 = (data, callback) => post('user.alipayapplogin1', data, callback);
//取下级地址列表
export const getAreaList = (data, callback) => post('user.getarealist', data, callback);
//取搜索页推荐关键字
export const getRecommendKeys = (callback) => post('store.getrecommendkeys', {}, callback);
// 获取我的邀请信息
export const myInvite = (callback) => post('user.myinvite', {}, callback);
// 设置我的上级邀请人
export const setMyInvite = (data, callback) => post('user.activationinvite', data, callback);
// 获取小程序二维码
export const getInviteQRCode = (data, callback) => post('store.getinviteqrcode', data, callback);
// 生成海报
export const createPoster = (data, callback) => post('user.getposter', data, callback);
// 获取秒杀团购
export const getGroup = (data, callback) => post('group.getlist', data, callback);
// 获取秒杀团购详情
export const groupInfo = (data, callback) => post('group.getgoodsdetial', data, callback);
// 自定义页面
export const getPageConfig = (data, callback) => post('pages.getpageconfig', data, callback);
//万能表单
export const getFormDetial = (data, callback) => post('form.getformdetial', data, callback);
//提交表单
export const addSubmitForm = (data, callback) => post('form.addsubmit', data, callback);
//公众号授权获取openid
export const getOpenId = (data, callback) => post('user.officiallogin', data, callback);
// 获取授权登录方式
export const getTrustLogin = (data, callback) => post('user.gettrustlogin', data, callback);
// APP信任登录
export const appTrustLogin = (data, callback) => post('user.uniapplogin', data, callback);
// 获取分销商进度状态
export const getDistributioninfo = (data, callback) => pluginsPost('distribution_center-api-info', data, callback);
// 申请分销商
export const applyDistribution = (data, callback) => pluginsPost('distribution_center-api-applydistribution', data,
callback);
// 店铺设置
export const setStore = (data, callback) => pluginsPost('distribution_center-api-setstore', data, callback);
//我的分销订单
export const getStoreInfo = (data, callback) => pluginsPost('distribution_center-api-getstoreinfo', data, callback);
//我的分销订单
export const getDistributionOrder = (data, callback) => pluginsPost('distribution_center-api-myorder', data, callback);
// 拼团列表
export const pintuanList = (data, callback) => post('pintuan.list', data, callback);
// 拼团商品详情
export const pintuanGoodsInfo = (data, callback) => post('pintuan.goodsinfo', data, callback);
// 拼团货品详情
export const pintuanProductInfo = (data, callback) => post('pintuan.productinfo', data, callback);
//微信图文消息
export const messageDetail = (data, callback) => post('articles.getweixinmessage', data, callback);
//获取APP版本
export const getAppVersion = (data, callback) => pluginsPost('app-api-checkVersion', data, callback);
//获取APP版本
export const getOrderPintuanTeamInfo = (data, callback) => post('pintuan.pintuanteam', data, callback);
//抽奖规则
export const lotteryConfig = (callback) => pluginsPost('lottery-api-getLotteryConfig', {}, callback);
//抽奖操作
export const lottery = (callback) => pluginsPost('lottery-api-lottery', {}, callback);
//获取我的抽奖记录
export const myLottery = (data, callback) => pluginsPost('lottery-api-lotteryLog', data, callback);
//生成分享URL
export const createShareUrl = (data, callback) => post('user.shareurl', data, callback);
common.js
import * as db from './db.js' //引入common
import store from './../store'
//把obj对象里的值覆盖到newobj里面
function deepCopy(newobj, obj) {
if (typeof obj != 'object') {
return obj
}
for (var attr in obj) {
var a = {}
if (newobj[attr]) {
a = newobj[attr]
}
newobj[attr] = deepCopy(a, obj[attr])
}
return newobj
}
//跳转到登陆页面
function jumpToLogin(method) {
var now_time = Date.parse(new Date())
var value = db.get('jump_to_login')
if (!value) {
value = 0
}
if (now_time - value > 3000) {
//db.set('jump_to_login',now_time); //暂时屏蔽登录时间查询
// 将当前页面route存vuex中 登录注册后跳转
let pages = getCurrentPages()
let page = pages[pages.length - 1]
// 获取页面参数信息
let pagePath = ''
// #ifdef H5 || MP-WEIXIN || APP-PLUS || APP-PLUS-NVUE
if (page.route.indexOf('pages/goods/index/index') !== -1) {
//商品详情页
if (page.goodsId) {
pagePath = '/' + page.route + '?id=' + page.goodsId;
} else {
pagePath = '/pages/index/index';
}
}
if (page.route.indexOf('pages/goods/index/group') !== -1) {
//团购秒杀详情页
if (page.goodsId && page.groupId) {
pagePath = '/' + page.route + '?id=' + page.goodsId + '&group_id' + page.groupId;
} else {
pagePath = '/pages/index/index';
}
}
// #endif
// #ifdef MP-ALIPAY
if (page.__proto__.route.indexOf('pages/goods/index/index') !== -1) {
//商品详情页
if (page.rootVM.goodsId) {
pagePath = '/' + page.__proto__.route + '?id=' + page.rootVM.goodsId;
} else {
pagePath = '/pages/index/index';
}
}
if (page.__proto__.route.indexOf('pages/goods/index/group') !== -1) {
//团购秒杀详情页
if (page.rootVM.goodsId && page.rootVM.groupId) {
pagePath = '/' + page.__proto__.route + '?id=' + page.rootVM.goodsId + '&group_id' + page.rootVM.groupId;
} else {
pagePath = '/pages/index/index';
}
}
// #endif
if (pagePath) {
store.commit({
type: 'redirect',
page: pagePath
})
}
uni.showToast({
title: '请先登录!',
icon: 'none',
duration: 1000,
success: function(res) {
// #ifdef H5 || APP-PLUS
setTimeout(() => {
uni.hideToast();
uni.navigateTo({
url: '/pages/login/login/index1'
})
}, 1000)
// #endif
// #ifdef MP-WEIXIN || MP-ALIPAY
setTimeout(() => {
uni.hideToast();
uni.navigateTo({
url: '/pages/login/choose/index',
animationType: 'pop-in',
animationDuration: 200
})
}, 500)
// #endif
}
})
}
}
//当出错的时候,显示错误信息,并且跳转 弃用
/* function errorToBack(msg = '出错了,请重试',delta=1){
uni.showToast({
title: msg,
icon: 'none',
duration: 2000,
});
if(delta > 0){
setTimeout(function () {
uni.navigateBack({
delta: delta
})
}, 1000);
}
} */
//操作成功后,的提示信息
function successToShow(msg = '保存成功', callback = function() {}) {
setTimeout(function() {
uni.showToast({
title: msg,
icon: 'success',
duration: 1000,
success() {
setTimeout(function() {
callback()
}, 500)
}
})
}, 100)
/* uni.showToast({
title: msg,
icon: 'success',
duration: 1000
}) */
}
//操作失败的提示信息
function errorToShow(msg = '操作失败', callback = function() {}) {
setTimeout(function() {
uni.showToast({
title: msg,
icon: 'none',
duration: 1500,
success() {
setTimeout(function() {
callback()
}, 1500)
}
})
},100)
}
//加载显示
function loadToShow(msg = '加载中') {
uni.showToast({
title: msg,
icon: 'loading'
})
}
//加载隐藏
function loadToHide() {
uni.hideToast()
}
// 提示框
function modelShow(
title = '提示',
content = '确认执行此操作吗?',
callback = () => {},
showCancel = true,
cancelText = '取消',
confirmText = '确定'
) {
uni.showModal({
title: title,
content: content,
showCancel: showCancel,
cancelText: cancelText,
confirmText: confirmText,
cancelText: cancelText,
success: function(res) {
if (res.confirm) {
// 用户点击确定操作
setTimeout(() => {
callback()
}, 500)
} else if (res.cancel) {
// 用户取消操作
}
}
})
}
//时间戳转时间格式
function timeToDate(date, flag = false) {
var date = new Date(date * 1000) //如果date为13位不需要乘1000
var Y = date.getFullYear() + '-'
var M =
(date.getMonth() + 1 < 10 ?
'0' + (date.getMonth() + 1) :
date.getMonth() + 1) + '-'
var D = (date.getDate() < 10 ? '0' + date.getDate() : date.getDate()) + ' '
var h = (date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + ':'
var m =
(date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()) + ':'
var s = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
if (flag) {
return Y + M + D
} else {
return Y + M + D + h + m + s
}
}
function time2date(micro_second) {
var time = {}
// 总秒数
var second = Math.floor(micro_second)
// 天数
time.day = PrefixInteger(Math.floor(second / 3600 / 24), 2)
// 小时
time.hour = PrefixInteger(Math.floor((second / 3600) % 24), 2)
// 分钟
time.minute = PrefixInteger(Math.floor((second / 60) % 60), 2)
// 秒
time.second = PrefixInteger(Math.floor(second % 60), 2)
var newtime = ''
if (time.day > 0) {
newtime =
time.day +
'天' +
time.hour +
'小时' +
time.minute +
'分' +
time.second +
'秒'
} else {
if (time.hour != 0) {
newtime = time.hour + '小时' + time.minute + '分' + time.second + '秒'
} else {
newtime = time.minute + '分' + time.second + '秒'
}
}
return newtime
}
function timeToDateObj(micro_second) {
var time = {}
// 总秒数
var second = Math.floor(micro_second)
// 天数
time.day = Math.floor(second / 3600 / 24)
// 小时
time.hour = Math.floor((second / 3600) % 24)
// 分钟
time.minute = Math.floor((second / 60) % 60)
// 秒
time.second = Math.floor(second % 60)
return time
}
//货币格式化
function formatMoney(number, places, symbol, thousand, decimal) {
number = number || 0
places = !isNaN((places = Math.abs(places))) ? places : 2
symbol = symbol !== undefined ? symbol : '¥'
thousand = thousand || ','
decimal = decimal || '.'
var negative = number < 0 ? '-' : '',
i = parseInt((number = Math.abs(+number || 0).toFixed(places)), 10) + '',
j = (j = i.length) > 3 ? j % 3 : 0
return (
symbol +
negative +
(j ? i.substr(0, j) + thousand : '') +
i.substr(j).replace(/(\d{3})(?=\d)/g, '$1' + thousand) +
(places ?
decimal +
Math.abs(number - i)
.toFixed(places)
.slice(2) :
'')
)
}
function throttle(fn, context, delay) {
clearTimeout(fn.timeoutId)
fn.timeoutId = setTimeout(function() {
fn.call(context)
}, delay)
}
// 时间格式化输出,如11:03 25:19 每1s都会调用一次
function dateformat(micro_second) {
var time = {}
// 总秒数
var second = Math.floor(micro_second / 1000) // 天数
time.day = PrefixInteger(Math.floor(second / 3600 / 24), 2) // 小时
time.hour = PrefixInteger(Math.floor((second / 3600) % 24), 2) // 分钟
time.minute = PrefixInteger(Math.floor((second / 60) % 60), 2) // 秒
time.second = PrefixInteger(Math.floor(second % 60), 2)
return time
}
//不足位数前面补0
function PrefixInteger(num, length) {
return (Array(length).join('0') + num).slice(-length)
}
//验证是否是手机号
function isPhoneNumber(str) {
var myreg = /^[1][3,4,5,6,7,8,9][0-9]{9}$/
if (!myreg.test(str)) {
return false
} else {
return true
}
}
/**
*
* 对象参数转为url参数
*
*/
function builderUrlParams(url, data) {
if (typeof url == 'undefined' || url == null || url == '') {
return ''
}
if (typeof data == 'undefined' || data == null || typeof data != 'object') {
return ''
}
url += url.indexOf('?') != -1 ? '' : '?'
for (var k in data) {
url += (url.indexOf('=') != -1 ? '&' : '') + k + '=' + encodeURI(data[k])
}
return url
}
/**
* 使用循环的方式判断一个元素是否存在于一个数组中
* @param {Object} arr 数组
* @param {Object} value 元素值
*/
function isInArray(arr, value) {
for (var i = 0; i < arr.length; i++) {
if (value === arr[i]) {
return true
}
}
return false
}
/**
* 统一跳转
*/
function navigateTo(url) {
uni.navigateTo({
url: url,
animationType: 'pop-in',
animationDuration: 300
})
}
/**
* 关闭当前页面并跳转
*/
function redirectTo(url) {
uni.redirectTo({
url: url,
animationType: 'pop-in',
animationDuration: 300
})
}
/**
* 获取url参数
*
* @param {*} name
* @param {*} [url=window.location.serach]
* @returns
*/
function getQueryString(name, url) {
var url = url || window.location.href
var reg = new RegExp('(^|&|/?)' + name + '=([^&|/?]*)(&|/?|$)', 'i')
var r = url.substr(1).match(reg)
if (r != null) {
return r[2]
}
return null
}
/**
*
* 判断是否在微信浏览器 true是
*/
function isWeiXinBrowser() {
// #ifdef H5
// window.navigator.userAgent属性包含了浏览器类型、版本、操作系统类型、浏览器引擎类型等信息,这个属性可以用来判断浏览器类型
let ua = window.navigator.userAgent.toLowerCase()
// 通过正则表达式匹配ua中是否含有MicroMessenger字符串
if (ua.match(/MicroMessenger/i) == 'micromessenger') {
return true
} else {
return false
}
// #endif
return false
}
/**
* 金额相加
* @param {Object} value1
* @param {Object} value2
*/
function moneySum(value1, value2) {
return (parseFloat(value1) + parseFloat(value2)).toFixed(2);
}
/**
* 金额相减
* @param {Object} value1
* @param {Object} value2
*/
function moneySub(value1, value2) {
let res = (parseFloat(value1) - parseFloat(value2)).toFixed(2);
return res > 0 ? res : 0;
}
/**
* 分享URL解压缩
* @param {Object} url
*/
function shareParameterEncode(url) {
let urlArray = url.split('-');
let newUrl = 'type=' + urlArray[0] + '&invite=' + urlArray[1] + '&id=' + urlArray[2] + '&team_id=' + urlArray[3] +
'&id_type=' + urlArray[4] + '&page_code=' + urlArray[5] + '&group_id=' + urlArray[6];
return newUrl;
}
/**
* 分享URL压缩
* @param {Object} url
*/
function shareParameterDecode(url) {
var urlArray = url.split('&');
var allParameter = {
'type': '',
'invite': '',
'id': '',
'team_id': '',
'id_type': '',
'page_code': '',
'group_id': '',
};
for (var i = 0; i < urlArray.length; i++) {
var parameter = urlArray[i].split('=');
allParameter[parameter[0]] = parameter[1];
}
var newUrl = allParameter.type + '-' + allParameter.invite + '-' + allParameter.id + '-' + allParameter.team_id + '-' +
allParameter.id_type + '-' + allParameter.page_code + '-' + allParameter.group_id;
return newUrl;
}
export {
deepCopy,
jumpToLogin,
timeToDate,
formatMoney,
/* errorToBack, */
successToShow,
throttle,
errorToShow,
time2date,
isPhoneNumber,
isInArray,
loadToShow,
loadToHide,
navigateTo,
redirectTo,
modelShow,
builderUrlParams,
isWeiXinBrowser,
dateformat,
getQueryString,
timeToDateObj,
moneySum,
moneySub,
shareParameterEncode,
shareParameterDecode
}
config.js
export const apiBaseUrl = 'http://www.b2c.com/'
// #ifdef H5
export const baseUrl=process.env.NODE_ENV === 'development'?window.location.origin+'/':apiBaseUrl
// #endif
export const paymentType = {
//支付单类型
order: 1, //订单
recharge: 2, //充值
form_order: 5, //表单付款码
form_pay: 6 //表单订单
}
db.js
import * as common from './common.js' //引入common
//取值
function get(key,sync = true) {
try {
if(sync){
return uni.getStorageSync(key);
}else{
let data = '';
uni.getStorage({
key:key,
success: function (res) {
data = res.data;
}
});
return data;
}
} catch (e) {
return false;
}
}
//赋值
function set(key, value, sync = true) {
try {
if (sync) {
return uni.setStorageSync(key, value);
} else {
uni.setStorage({
key: key,
data: value
});
}
} catch (e) {
}
}
//移除
function del(key, sync = true){
try {
if (sync) {
return uni.removeStorageSync(key);
} else {
uni.removeStorage({
key: key
});
}
} catch (e) {
return false;
}
}
//清空
function clear(sync = true){
try {
if (sync) {
return uni.clearStorageSync();
} else {
uni.clearStorage();
}
} catch (e) {
return false;
}
}
//获取用户token,如果缓存有,直接返回,如果没有,就先微信登陆,然后服务器登陆,最后返回token
function userToken(callback) {
var token = get('userToken');
if (token){
callback(token);
}else{
//如果没有登陆,就去登陆
common.jumpToLogin();
}
}
export {
get,
set,
del,
clear,
userToken
}
mixins.js
export const orders = {
mounted() {},
methods: {
// 查看订单详情
orderDetail(orderId) {
this.$common.navigateTo(
'/pages/member/order/orderdetail?order_id=' + orderId
)
},
// 取消订单
// 去支付
toPay(orderId) {
this.$common.navigateTo(
'/pages/goods/payment/index?order_id=' + orderId + '&type=1'
)
},
// 确认收货
// 去评价
toEvaluate(orderId) {
this.$common.navigateTo(
'/pages/member/order/evaluate?order_id=' + orderId
)
},
// 申请售后
// 查看物流信息
showExpress(code, no, address = '') {
let params = encodeURIComponent(
'code=' + code + '&no=' + no + '&add=' + address
)
this.$common.navigateTo(
'/pages/member/order/express_delivery?params=' + params
)
}
}
}
/**
* 商品接口信息
*
*/
export const goods = {
mounted() {},
methods: {
// 查看商品详情
goodsDetail(goodsId) {
this.$common.navigateTo('/pages/goods/index/index?id=' + goodsId)
},
// 跳转商品列表页
goodsList(obj = {}) {
let url = '/pages/classify/index'
if (Object.keys(obj).length) {
url = this.$common.builderUrlParams(url, obj)
}
this.$common.navigateTo(url)
},
// 团购秒杀详情
groupDetail(id, group_id) {
this.$common.navigateTo(
'/pages/goods/index/group?id=' + id + '&group_id=' + group_id
)
},
//拼团详情页
pintuanDetail(id, team_id) {
if (team_id) {
this.$common.navigateTo(
'/pages/goods/index/pintuan?id=' + id + '&team_id=' + team_id
)
} else {
this.$common.navigateTo('/pages/goods/index/pintuan?id=' + id)
}
}
}
}
/**
*
* 返回操作处理
*
*/
export const goBack = {
onBackPress(options) {
if (options.from === 'navigateBack') {
return false
}
let loginPages = ['/pages/cart/index/index', '/pages/member/index/index']
let backPage = this.$store.state.redirectPage
if (loginPages.indexOf(backPage) > -1) {
this.$store.commit({
type: 'redirect',
page: ''
})
uni.switchTab({
url: '/pages/index/index'
})
return true
}
}
}
/* Function Info
* Author: zhf
* CreateTime: 2019/7/12 下午12:10:00
* LastEditor: zhf
* ModifyTime: 2019/7/12 下午12:10:00
* Description: 登录成功统一跳转处理
*/
export const jumpBackPage = {
methods: {
handleBack() {
let redirect = this.$store.state.redirectPage
this.$store.commit({
type: 'redirect',
page: ''
})
let switchTabs = ['/pages/index/index', '/pages/member/index/index']
if (switchTabs.indexOf(redirect) > -1) {
uni.switchTab({
url: redirect
})
} else if (redirect) {
uni.redirectTo({
url: redirect
})
} else {
uni.switchTab({
url: '/pages/index/index'
})
}
}
}
}
/* Function Info
* Author: zhf
* CreateTime: 2019/7/12 下午12:10:28
* LastEditor: zhf
* ModifyTime: 2019/7/12 下午12:10:28
* Description: 操作判断登录处理
*/
export const checkLogin = {
methods: {
checkIsLogin() {
uni.showToast({
title: '请先登录!',
icon: 'none',
duration: 800,
success: function(res) {
// #ifdef H5 || APP-PLUS
setTimeout(() => {
uni.hideToast()
uni.navigateTo({
url: '/pages/login/login/index1'
})
}, 800)
// #endif
// #ifdef MP-WEIXIN || MP-ALIPAY
setTimeout(() => {
uni.hideToast()
uni.navigateTo({
url: '/pages/login/choose/index',
animationType: 'pop-in',
animationDuration: 200
})
}, 500)
// #endif
}
})
}
}
}
/**
* 工具函数
*/
export const tools = {
methods: {
copyData(data) {
var _this = this;
uni.setClipboardData({
data: data,
success: function() {
_this.$common.errorToShow('复制成功')
}
});
}
}
}
index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="author" content="novice@jihainet.com" />
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<title>
<%= htmlWebpackPlugin.options.title %>
</title>
<!-- <script type="text/javascript">
let url = window.location.origin;
if(!/Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent)) {
window.location.href= url + '/web/';
}
</script> -->
<script>
document.addEventListener('DOMContentLoaded', function () {
document.documentElement.style.fontSize = document.documentElement.clientWidth / 20 + 'px'
})
</script>
<!-- <script src="https://cdn.bootcss.com/vConsole/3.3.2/vconsole.min.js"></script>
<script>
var vConsole = new VConsole();
</script> -->
<link rel="stylesheet" href="<%= BASE_URL %>static/index.css" />
</head>
<body>
<div id="app"></div>
</body>
<script>
(function (w, d, s, n, a, e) {
w[n] = w[n] || function () {
(w[n].z = w[n].z || []).push(arguments)
};
a = d.createElement(s), e = d.getElementsByTagName(s)[0];
a.async = 1;
a.charset = "UTF-8";
a.src = "https://pubres.aihecong.com/hecong.js";
e.parentNode.insertBefore(a, e)
})(window, document, "script", "_AIHECONG");
</script>
</html>
main.js
import Vue from 'vue'
import App from './App'
import * as Api from './config/api.js'
import * as Common from './config/common.js'
import * as Db from './config/db.js'
import * as Config from './config/config.js'
import store from './store'
import './common/uni-H5Api'
Vue.config.productionTip = false
Vue.prototype.$api = Api;
Vue.prototype.$common = Common;
Vue.prototype.$db = Db;
Vue.prototype.$config = Config;
Vue.prototype.$store = store;
App.mpType = 'app'
const app = new Vue({
...App
})
app.$mount()
manifest.json
{
"name" : "Jshop云商",
"appid" : "__UNI__60F611E",
"description" : "Jshop云商",
"versionName" : "2.0",
"versionCode" : 15,
"transformPx" : false,
"app-plus" : {
/* 5+App特有相关 */
"modules" : {
"Payment" : {}
},
/* 模块配置 */
"distribute" : {
/* 应用发布信息 */
"android" : {
/* android打包配置 */
"permissions" : [
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.INTERNET\"/>",
"<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.READ_CONTACTS\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>",
"<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
]
},
"ios" : {},
/* ios打包配置 */
"sdkConfigs" : {
"payment" : {
"weixin" : {
"appid" : "wxf62e2f29f15741af"
},
"alipay" : {
"scheme" : ""
}
}
}
},
"splashscreen" : {
"waiting" : true
}
},
/* SDK配置 */
"quickapp" : {},
/* 快应用特有相关 */
"mp-weixin" : {
"appid" : "wxaec38ca2e5cdc46a",
"setting" : {
"urlCheck" : true,
"postcss" : true,
"minified" : true,
"es6" : true
},
"permission" : {
"scope.userLocation" : {
"desc" : "用于获取您附近的门店列表"
}
},
"usingComponents" : false
},
"h5" : {
"title" : "Jshop云商",
"domain" : "https://wmp.uneedabox.com",
"router" : {
"base" : "/wap/",
"mode" : "history"
},
"template" : "index.html",
"devServer" : {
"port" : 8080,
"disableHostCheck" : true,
"https" : false
},
"sdkConfigs" : {
"maps" : {
"qqmap" : {
"key" : "AEIBZ-H5TRI-A6VGA-5KRNA-QKKK6-JGB33"
}
}
}
}
}
pages
activity
index.vue
<template>
<view class="conbox">
<view class="container">
<image src="../../static/img/bg.png" class="cont" mode=""></image>
<image src="../../static/img/caidai.png" class="caidai" mode=""></image>
<view class="header">
<view class="header-title">
<view class="left">
免费次数:<text style="color: #E4431A;">{{chishu}}</text>
</view>
<view class="left">
账户积分:<text style="color: #E4431A;">{{jifen}}</text>
</view>
<view class="right" @click="getmyPrize">
抽奖记录 >
</view>
</view>
</view>
<view class="main">
<view class="canvas-container">
<view :animation="animationData" class="canvas-content" id="zhuanpano" style="">
<!-- <view :animation="animationData" class="canvas-content" id="zhuanpano" :style="[{transform:'rotate('+runDeg+')'}]"> -->
<!-- <canvas class="canvas" canvas-id="canvas"></canvas> -->
<view class="canvas-line">
<view class="canvas-litem" v-for="(item,index1) in awardsList" :key="index1" :style="[{transform:'rotate('+item.lineTurn+')'}]"></view>
</view>
<view class="canvas-list">
<view class="canvas-item" :style="[{zIndex:index2}]" v-for="(iteml,index2) in awardsList" :key="index2">
<view class="canvas-item-text" :style="[{transform:'rotate('+iteml.turn+')'}]">
<text>{{iteml.award}}</text>
<image class="canvas-item-text-img" src="../../static/img/kongjiang.png" v-if="iteml.type == 0"></image>
<image class="canvas-item-text-img" src="../../static/img/jifen.png" v-if="iteml.type == 1"></image>
<image class="canvas-item-text-img" src="../../static/img/youhuiquan.png" v-if="iteml.type == 2"></image>
<image class="canvas-item-text-img" src="../../static/img/yue.png" v-if="iteml.type == 3"></image>
<image class="canvas-item-text-img" src="../../static/img/shangpin.png" v-if="iteml.type == 4"></image>
</view>
</view>
</view>
</view>
<view @tap="playReward" class="canvas-btn" v-bind:class="btnDisabled">开始 </view>
</view>
</view>
<view class="typecheckbox"></view>
<!-- 规则 -->
<view class="guize">
<view class="title">
规则说明
</view>
<view class="g_item" v-for="(v, k) in awardsConfig.rule" :key="k">
{{v}}
</view>
</view>
<view class="typecheckbox2"></view>
<!-- 抽奖记录 -->
<view class="shadowbox" v-if="r_flg" @click="closeshadow">
<view class="myrewards" @click.stop="openshadow">
<view class="title">
抽奖记录
</view>
<view class="itembox">
<view class="item" v-for="(items,i) in myPrizelist" :key="i">
<div class="t">
<text class="left">{{items.name}}</text>
<text class="right">{{items.ctime_name}}</text>
</div>
<div class="b">
{{items.prize_content}}
</div>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
awardsConfig: {
chance: true, //是否有抽奖机会
prize: [], //奖品列表
},
awardsList: {},
animationData: {},
btnDisabled: '',
thanksarr: [], //存储谢谢参与的索引
chishu: 0,
mold: 1,
r_flg: 0,
myPrizelist:[],
jifen: 0
}
},
onLoad: function() {
// 获取奖品列表
this.initdata(this)
},
onReady: function(e) {
},
methods: {
// 查看奖品
getmyPrize(){
this.$api.myLottery({page: 1, limit: 1000}, res => {
this.myPrizelist = res.data
this.r_flg=1
})
},
openshadow(){
this.r_flg=1
},
closeshadow(){
this.r_flg=0
},
// 初始化抽奖数据
initdata:function(that){
this.$api.lotteryConfig(res => {
if(res.status){
this.awardsConfig = res.data
this.chishu = res.data.user.day_remaining;
this.jifen = res.data.user.jifen;
// 获取奖品的个数
let awarrlength = this.awardsConfig.prize.length
// 为每一项追加index属性
this.awardsConfig.prize.forEach(function(element, index) {
element.index = index
});
// 画转盘
this.drawAwardRoundel();
}else{
this.$common.errorToShow(res.msg, () => {
uni.navigateBack({
delta: 1
});
});
}
});
},
//画抽奖圆盘
drawAwardRoundel: function() {
// 拿到奖品列表
var awards = this.awardsConfig.prize;
var awardsList = [];
// 每份奖品所占角度
var turnNum = 1 / awards.length * 360; // 文字旋转 turn 值
// 奖项列表
for (var i = 0; i < awards.length; i++) {
awardsList.push({
turn: i * turnNum + 'deg', //每个奖品块旋转的角度
lineTurn: i * turnNum + turnNum / 2 + 'deg', //奖品分割线的旋转角度
award: awards[i].title, //奖品的名字,
type: awards[i].type,
id: awards[i].id,
});
}
if(this.chishu < 1 && this.jifen < this.awardsConfig.integral_exchange) {
this.btnDisabled = 'disabled';
}else{
if(!this.awardsConfig.user.lottery){
this.btnDisabled = 'disabled';
}else{
this.btnDisabled = '';
}
}
this.awardsList = awardsList;
},
//发起抽奖
playReward: function() {
if(this.chishu < 1) {
if(this.jifen < this.awardsConfig.integral_exchange) {
this.$common.errorToShow('抽奖次数已经用完');
return false;
} else if (this.jifen >= this.awardsConfig.integral_exchange) {
this.$common.modelShow('提示', '本次抽奖将消耗'+this.awardsConfig.integral_exchange+'积分,确认吗?', res => {
this.lottery();
});
}
}else{
this.lottery();
}
},
lottery: function () {
// 抽奖
this.$api.lottery(res => {
if(res.status) {
let awardIndex = 0;
let awardInfo = res.data.result;
//获取抽奖结果
this.awardsList.forEach(function(element, index) {
if (element.id == awardInfo.id) {
awardIndex = index;
}
})
//中奖index
let awardsNum = this.awardsConfig.prize;
let runNum = 4; //旋转8周
let duration = 3686; //时长
// 旋转角度
this.runDeg = this.runDeg || 0;
let preDeg = this.runDeg;
this.runDeg = this.runDeg + (360 - this.runDeg % 360) + (360 * runNum - awardIndex * (360 / awardsNum.length)) + 1;
//创建动画
if(process.env.VUE_APP_PLATFORM == 'h5'){
// document.styleSheets[0]
document.getElementById('zhuanpano').style='animation:rotate_before 4s 0ms ease forwards;'
if(document.styleSheets[0].cssRules.length>0){
Array.from(document.styleSheets[0].cssRules).forEach(function(element,index){
if(element.name == 'rotate_before'){
// 删除上次插入的动画
document.styleSheets[0].deleteRule(index)
}
})
}
// console.log(document.styleSheets[0].cssRules)
// console.log("@keyframes rotate_before{from{ transform: rotate("+preDeg+"deg); }to{ transform: rotate("+this.runDeg+"deg);}}")
// 插入定义的动画
document.styleSheets[0].insertRule("@keyframes rotate_before{from{ transform: rotate("+preDeg+"deg); }to{ transform: rotate("+this.runDeg+"deg);}}",8);
}else{
var animationRun = uni.createAnimation({
duration: duration,
timingFunction: 'ease'
})
animationRun.rotate(this.runDeg).step();
this.animationData = animationRun.export();
}
// // #ifndef H5
// console.log(document.styleSheets)
// document.getElementById('zhuanpano')
// // #endif
this.btnDisabled = 'disabled';
// 中奖提示
var awardsConfig = this.awardsConfig;
var awardType = awardsConfig.prize[awardIndex].type;
this.jifen = this.chishu <= 0 ? (this.jifen - awardsConfig.integral_exchange >= 0 ? this.jifen - awardsConfig.integral_exchange : 0) : this.jifen;
this.chishu = this.chishu > 1 ? this.chishu - 1 : 0;
if (awardType != 0) {
let msg = this.getPrizeMsg(awardsConfig.prize[awardIndex].type, awardsConfig.prize[awardIndex].val);
setTimeout(function() {
this.$common.modelShow('恭喜', '获得' + (awardsConfig.prize[awardIndex].title) + ',' + msg, res => {
setTimeout(function(){
document.getElementById('zhuanpano').style=''
},1000)
}, false);
if(!res.data.is_lottery.lottery){
this.btnDisabled = 'disabled';
}else{
this.btnDisabled = '';
}
}.bind(this), duration);
} else {
setTimeout(function() {
this.$common.modelShow('很遗憾', '没中奖,再接再厉!', res => {
setTimeout(function(){
document.getElementById('zhuanpano').style=''
},1000)
}, false);
if(!res.data.is_lottery.lottery){
this.btnDisabled = 'disabled';
}else{
this.btnDisabled = '';
}
}.bind(this), duration);
}
} else {
this.$common.modelShow('提示', res.msg);
}
});
},
//获取显示的奖品信息
getPrizeMsg: function(type, val){
let msg = '';
switch(type){
case 1: //积分
msg = '积分:' + val + '个';
break;
case 2: //优惠券
msg = '优惠券:“' + val + '” 一张';
break;
case 3: //余额
msg = '余额:' + val + '元';
break;
case 4: //商品
msg = '商品:“' + val + '”';
break;
default: //默认
break;
}
return msg;
}
}
}
</script>
<style scoped>
.conbox {
width: 750upx;
height: 100vh;
overflow-x: hidden;
overflow-y: scroll;
}
.container,
image.cont {
width: 750upx;
min-height: 100vh;
height: auto;
position: relative;
}
image.cont {
height: 100%;
position: absolute;
z-index: 0;
}
image.caidai {
position: absolute;
top: 0;
left: 0;
width: 750upx;
height: 1024upx;
}
.header {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
/* height: 246upx; */
padding-top: 48upx;
padding-bottom: 40upx;
box-sizing: border-box;
position: relative;
z-index: 3;
}
.header-title {
width: 100%;
height: 60upx;
display: flex;
align-items: center;
padding: 0 48upx;
box-sizing: border-box;
justify-content: space-between;
}
.header-title>view {
padding: 8upx 16upx;
border: 1px solid #d89720;
color: #d89720;
font-size: 28upx;
border-radius: 26upx;
}
/* 转盘 */
.canvas-container {
margin: 0 auto;
position: relative;
width: 600upx;
height: 600upx;
background: url(../../static/img/circle.png) no-repeat;
background-size: cover;
border-radius: 50%;
}
.canvas {
width: 100%;
height: 100%;
display: block !important;
border-radius: 50%;
}
.canvas-content {
position: absolute;
left: 0;
top: 0;
z-index: 1;
display: block;
width: 600upx;
height: 600upx;
border-radius: inherit;
/* background-clip: padding-box; */
/* background-color: #ffcb3f; */
}
.canvas-element {
position: relative;
z-index: 1;
width: inherit;
height: inherit;
border-radius: 50%;
}
.canvas-list {
position: absolute;
left: 0;
top: 0;
width: inherit;
height: inherit;
z-index: 9999;
}
.canvas-item {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
color: #e4370e;
/* text-shadow: 0 1upx 1upx rgba(255, 255, 255, 0.6); */
}
.canvas-item-text {
position: relative;
display: block;
padding-top: 46upx;
margin: 0 auto;
text-align: center;
-webkit-transform-origin: 50% 300upx;
transform-origin: 50% 300upx;
display: flex;
flex-direction: column;
align-items: center;
color: #FB778B;
}
.canvas-item-text text {
font-size: 30upx;
}
.canvas-item-text-img {
width: 50upx;
height: 50upx;
padding-top: 30upx;
}
/* 分隔线 */
.canvas-line {
position: absolute;
left: 0;
top: 0;
width: inherit;
height: inherit;
z-index: 99;
}
.canvas-litem {
position: absolute;
left: 300upx;
top: 0;
width: 3upx;
height: 300upx;
background-color: rgba(228, 55, 14, 0.4);
overflow: hidden;
-webkit-transform-origin: 50% 300upx;
transform-origin: 50% 300upx;
}
/**
* 抽奖按钮
*/
.canvas-btn {
position: absolute;
left: 260upx;
top: 260upx;
z-index: 400;
width: 80upx;
height: 80upx;
border-radius: 50%;
color: #f4e9cc;
background-color: #e44025;
line-height: 80upx;
text-align: center;
font-size: 26upx;
text-shadow: 0 -1px 1px rgba(0, 0, 0, 0.6);
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.6);
text-decoration: none;
}
.canvas-btn::after {
position: absolute;
display: block;
content: ' ';
left: 12upx;
top: -44upx;
width: 0;
height: 0;
overflow: hidden;
border-width: 30upx;
border-style: solid;
border-color: transparent;
border-bottom-color: #e44025;
}
.canvas-btn.disabled {
pointer-events: none;
background: #b07a7b;
color: #ccc;
}
.canvas-btn.disabled::after {
border-bottom-color: #b07a7b;
}
.canvas-btn-table {
color: #A83FDB;
width: 120upx;
text-align: center;
position: absolute;
left: 240upx;
top: 360upx;
font-size: 26upx;
background-color: #FFFFFF;
opacity: 0.9;
}
.typecheckbox {
width: 100%;
position: relative;
z-index: 3;
display: flex;
justify-content: space-between;
padding: 20upx;
box-sizing: border-box;
color: #fff;
font-size: 28upx;
top: -120upx;
flex-direction: column;
height: 180upx;
align-items: flex-end;
/* padding-top: 46upx; */
}
.typecheckbox2{
width: 100%;
position: relative;
z-index: 3;
display: flex;
justify-content: space-between;
padding: 20upx;
box-sizing: border-box;
color: #fff;
font-size: 28upx;
top: -120upx;
flex-direction: column;
height: 120upx;
align-items: flex-end;
/* padding-top: 46upx; */
}
.typecheckbox view {
border: 1px solid #FF3637;
background: transparent;
color: #FF3637;
display: flex;
height: 60upx;
width: 140upx;
border-radius: 50upx;
align-items: center;
justify-content: center;
display: flex;
margin-left: 20upx;
}
.typecheckbox view.active {
background: #FF3637;
color: #fff;
}
.guize {
width: 502upx;
min-height: 300upx;
display: flex;
flex-direction: column;
position: relative;
z-index: 3;
background-image: linear-gradient(-180deg, #F48549 0%, #F2642E 100%);
border: 18upx solid #E4431A;
border-radius: 16px;
margin: 0 auto;
margin-top: -104upx;
padding: 48upx;
/* box-sizing: border-box; */
color: #fff;
}
.guize .title {
text-align: center;
margin-bottom: 28upx;
}
.guize .g_item {
font-family: PingFang-SC-Medium;
font-size: 24upx;
color: #FFFFFF;
letter-spacing: 0.5px;
text-align: justify;
line-height: 20px;
}
.shadowbox {
width: 750upx;
height: 100vh;
position: fixed;
top: 0;
left: 0;
z-index: 999;
background: rgba(0, 0, 0, .6);
display: flex;
justify-content: center;
align-items: center;
}
.myrewards {
width: 600upx;
min-height: 80upx;
background: #FFEEDF;
border: 10upx solid #F2692F;
color: #333;
font-size: 24upx;
font-family: PingFang-SC-Medium;
border-radius: 40upx;
padding:0 24upx 20upx;
}
.myrewards .title {
font-family: PingFang-SC-Bold;
font-size: 16px;
color: #E4431A;
letter-spacing: 0.57px;
display: flex;
padding-top: 36upx;
justify-content: center;
}
.myrewards .itembox {
max-height: 320upx;
overflow-y: auto;
}
.myrewards .item {
width: 100%;
padding: 12upx 0;
box-sizing: border-box;
border-bottom: 1upx dashed #CCCCCC;
}
.myrewards .item .t{
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom:10upx;
}
.myrewards .item .b{
font-size: 12px;
color:#999999;
text-align: left;
}
</style>
article
index.vue
<template>
<view class="content">
<view class="article">
<view class="article-title" v-if="shopLogo && shopName">
<img :src="shopLogo" alt="" class='shop-logo'>
<text class='shop-name'>{{ shopName }}</text>
<text class="fsz24 color-9 article-time">{{ info.ctime }}</text>
</view>
<!-- <view class="article-time">
</view> -->
<view class="article-content">
<jshopContent :content="info.content" v-if="info.content"></jshopContent>
</view>
</view>
</view>
</template>
<script>
import jshopContent from '@/components/jshop/jshop-content.vue'
export default {
components: {
jshopContent
},
data() {
return {
myShareCode: '', //分享Code
idType: 1, //1文章 2公告 3微信图文消息
id: 0,
info: {}
}
},
onLoad(e) {
this.idType = e.id_type;
this.id = e.id;
if (!this.idType && !this.id) {
this.$common.errorToShow('请求出错', res => {
uni.switchTab({
url: '/pages/index/index'
});
});
} else if (this.idType == 1) {
this.articleDetail();
} else if (this.idType == 2) {
uni.setNavigationBarTitle({
title: '公告详情'
});
this.noticeDetail();
} else if (this.idType == 3) {
uni.setNavigationBarTitle({
title: '图文消息'
});
this.messageDetail();
}
this.getMyShareCode();
},
computed: {
shopName() {
return this.$store.state.config.shop_name
},
shopLogo() {
return this.$store.state.config.shop_logo
}
},
methods: {
articleDetail() {
let data = {
article_id: this.id
}
this.$api.articleInfo(data, res => {
if (res.status) {
this.info = res.data
uni.setNavigationBarTitle({
title: this.info.title
});
} else {
this.$common.errorToShow(res.msg, res => {
uni.navigateBack({
delta: 1
});
});
}
})
},
noticeDetail() {
let data = {
id: this.id
}
this.$api.noticeInfo(data, res => {
if (res.status) {
this.info = res.data
uni.setNavigationBarTitle({
title: this.info.title
});
} else {
this.$common.errorToShow(res.msg)
}
})
},
//微信图文消息
messageDetail() {
let data = {
id: this.id
}
this.$api.messageDetail(data, res => {
if (res.status) {
this.info = res.data
uni.setNavigationBarTitle({
title: this.info.title
});
} else {
this.$common.errorToShow(res.msg)
}
})
},
getMyShareCode() {
let userToken = this.$db.get("userToken");
if (userToken && userToken != '') {
// 获取我的分享码
this.$api.shareCode({}, res => {
if (res.status) {
this.myShareCode = res.data ? res.data : '';
}
});
}
}
},
//分享
onShareAppMessage() {
let myInviteCode = this.myShareCode ? this.myShareCode : '';
let ins = this.$common.shareParameterDecode('type=4&id=' + this.id + '&id_type=' + this.idType + '&invite=' +
myInviteCode);
let path = '/pages/share/jump?scene=' + ins;
return {
title: this.info.title,
// #ifdef MP-ALIPAY
//desc: this.goodsInfo.brief,
// #endif
//imageUrl: this.goodsInfo.album[0],
path: path
}
}
}
</script>
<style>
.content {
/* #ifdef H5 */
height: calc(100vh - 90upx);
/* #endif */
/* #ifndef H5 */
height: 100vh;
/* #endif */
background-color: #fff;
}
.article {
padding: 20upx;
}
.article-title {
font-size: 32upx;
color: #333;
margin-bottom: 20upx;
/* text-align: center; */
position: relative;
height: 100upx;
}
.article-time {
/* text-align: right; */
margin-left: 20upx;
}
.article-content {
font-size: 28upx !important;
color: #666;
line-height: 1.6;
margin-top: 20upx;
}
.article-content p img {
width: 100% !important;
}
.shop-logo {
width: 60upx;
height: 60upx;
border-radius: 50%;
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.shop-name {
line-height: 100upx;
margin-left: 80upx;
}
</style>
list.vue
<template>
<view class="content">
<view class='cell-group margin-cell-group'>
<view class='cell-item'
v-for="item in list"
:key="item.id"
@click="articleDetail(item.id)"
>
<view class="cell-title-img">
<image :src="item.cover" mode="aspectFill"></image>
</view>
<view class="cell-item-bd">
<view class="article-title ">
{{ item.title }}
</view>
<view class="article-time">
{{ item.ctime }}
</view>
</view>
</view>
</view>
<uni-load-more
:status="loadStatus"
></uni-load-more>
</view>
</template>
<script>
import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue'
export default {
components: { uniLoadMore },
data () {
return {
cid: 0, // 文章分类id
page: 1,
limit: 10,
list: [],
loadStatus: 'more'
}
},
onLoad (options) {
this.cid = options.cid
if (!this.cid) {
this.$common.errorToShow('未指定文章分类', () => {
uni.navigateBack({
delta: 1
})
})
} else {
this.articleList()
}
},
onReachBottom () {
if (this.loadStatus === 'more') {
this.articleList()
}
},
methods: {
articleList () {
let data = {
page: this.page,
limit: this.limit,
type_id:this.cid
}
this.loadStatus = 'loading'
this.$api.articleList(data, res => {
if (res.status) {
const _list = res.data.list
this.list = [...this.list, ..._list]
if (res.data.count > this.list.length) {
this.loadStatus = 'more'
this.page ++
} else {
// 数据已加载完毕
this.loadStatus = 'noMore'
}
} else {
// 接口请求出错了
this.$common.errorToShow(res.msg)
}
})
},
// 查看文章详情
articleDetail (articleId) {
this.$common.navigateTo('/pages/article/index?id=' + articleId +'&id_type=1')
}
}
}
</script>
<style>
.cell-title-img{
width: 160upx;
height: 160upx;
}
.cell-title-img image{
width: 100%;
height: 100%;
}
.cell-item-bd{
padding-right: 0;
vertical-align: top;
position: relative;
}
.article-title{
font-size: 28upx;
color: #333;
width: 100%;
min-height: 80upx;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
.article-time{
font-size: 24upx;
color: #999;
display: inline-block;
min-width: 220upx;
min-height: 32upx;
position: absolute;
bottom: 0;
}
</style>
author.vue
<template>
<view class="content">
<view class="content-c">
<image class="load-img" src="/static/image/loading.gif" mode=""></image>
<view class="load-text color-9">信息加载中.....</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
code: '',
type: '',
state: ''
}
},
onLoad(options) {
// 获取url上的参数
this.code = this.getUrlParam('code')
this.state = this.getUrlParam('state')
this.type = options.type
var _this = this
setTimeout(function() {
_this.userTrustLogin()
}, 100)
},
methods: {
// 获取url地址参数
getUrlParam(paraName) {
let url = window.location.toString()
let arrObj = url.split('?')
if (arrObj.length > 1) {
let arrPara = arrObj[1].split('&')
let arr
for (let i = 0; i < arrPara.length; i++) {
arr = arrPara[i].split('=')
if (arr != null && arr[0] == paraName) {
if (arr[1].indexOf('#')) {
let str
str = arr[1].split('#')
return str[0]
}
return arr[1]
}
}
return ''
} else {
return ''
}
},
// 第三方登录
userTrustLogin() {
let data = {
scope: 1,
code: this.code,
state: this.state,
invitecode: this.$db.get('invitecode') || ''
}
this.$api.getOpenId(data, res => {
if (res.status) {
if (res.data.token) {
this.$db.set('userToken', res.data.token)
this.redirectHandler()
} else if (res.data.user_wx_id) {
uni.redirectTo({
url: '/pages/login/login/index?user_wx_id=' + res.data.user_wx_id
})
}
} else {
this.$common.errorToShow(res.msg)
}
})
},
redirectHandler() {
this.$db.del('invitecode')
let redirectPage = this.$db.get('redirectPage')
if (redirectPage) {
this.$db.del('redirectPage')
this.$common.redirectTo(redirectPage)
} else {
uni.reLaunch({
url: '/pages/index/index'
})
}
}
}
}
</script>
<style>
.content {
position: relative;
height: 80vh;
}
.content-c {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
}
.load-img {
width: 100upx;
height: 100upx;
}
.load-text {
font-size: 26upx;
}
</style>
cart
index
index.vue
<template>
<view class="content" v-if="cartData.list && cartData.list.length > 0">
<view class="content-top">
<view class="cell-group margin-cell-group">
<view class="cell-item">
<view class="cell-item-hd">
<image class="cell-hd-icon" src="/static/image/homepage.png" style="width: 32upx;height: 32upx;"></image>
</view>
<view class="cell-item-bd">
<text class="cell-bd-text">{{ shopName }}</text>
</view>
<view class="cell-item-ft">
<text class="cell-bd-text" @click="editBtn" v-if="!editStatus">编辑</text>
<text class="cell-bd-text" @click="editNoBtn" v-else>完成</text>
<!-- <image class='cell-ft-next icon' src='/static/image/right.png'></image> -->
</view>
</view>
</view>
<view class="img-list cart-list">
<checkbox-group class="cart-checkbox" v-for="(item, index) in cartData.list" :key="index" :val="item.id" @change="checkboxChange(item.id)">
<view class="">
<label class="uni-list-cell uni-list-cell-pd">
<view class="cart-checkbox-c">
<checkbox color="#FF7159" :checked="item.is_select" :value="item.id" :disabled="item.stockNo" v-if="item.stockNo" class="checkboxNo" />
<checkbox color="#FF7159" :checked="item.is_select" :value="item.id" v-else/>
</view>
</label>
<view class="img-list-item">
<image class="img-list-item-l little-img have-none" :src="item.products.image_path" mode="aspectFill"></image>
<view class="img-list-item-r little-right">
<view class="little-right-t">
<view class="goods-name list-goods-name" @click="goodsDetail(item.products.goods_id)">
{{ item.products.name }}
</view>
<view class="goods-price red-price">
¥{{ item.products.price }}
</view>
</view>
<view class="romotion-tip" v-if="item.products.promotion_list">
<view class="romotion-tip-item" v-for="(v, k) in item.products.promotion_list" :key="k" :class="v.type !== 2 ? 'bg-gray' : ''">
{{v.name}}
</view>
</view>
<view class="goods-item-c">
<view class="goods-buy">
<!-- 商品规格 -->
<view class="goods-salesvolume" v-if="item.products.spes_desc">
{{ item.products.spes_desc }}
</view>
<view class="goods-salesvolume" v-else></view>
<view class="goods-numbox">
<text v-if="item.stockNo && !editStatus" class="stockError">库存不足</text>
<text v-else-if="item.stockTension && !editStatus" class="stockError stockTension">库存紧张</text>
<uni-number-box v-on:change="bindChange($event, item)" :min="1" :max="item.maxStock" :value="item.nums" v-if="!editStatus"></uni-number-box>
<view v-else="" @click="del(index,item.id)" class='click-del'>
<image class="icon" src="/static/image/delete.png" mode=""></image>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</checkbox-group>
</view>
</view>
<view class="cart-bottom">
<checkbox-group class="cart-checkbox" @change="checkboxAllButton">
<label class="uni-list-cell uni-list-cell-pd">
<view class="cart-checkbox-c">
<checkbox :checked="checkboxAll" color="#FF7159" /> 全选
</view>
</label>
<view class="cart-bottom-right">
<view class="cart-bottom-right-t" v-if="!editStatus">
合计:
<view class="goods-price red-price">¥{{ cartData.amount }}</view>
</view>
<button class="btn btn-square btn-b" v-if="!editStatus" @click="settlement" hover-class="btn-hover2">去结算</button>
<view v-else>
<button class="btn btn-square btn-b" @click="delList">删除</button>
<!-- <button class="btn btn-square" @click="collection">收藏</button> -->
</view>
</view>
</checkbox-group>
</view>
</view>
<!-- 购物车为空 -->
<!-- <view class='cart-none' v-else-if="cartData.list && cartData.list.length < 1 && isLoad == true">
<image class="cart-none-img" src="/static/image/car.png" mode=""></image>
<view class='cart-none-t'>购物车快饿瘪了 T.T</view>
<view class='cart-none-m'>快给我挑点宝贝吧</view>
<navigator class="cart-none-b" url='../../index/index' hover-class="btn-hover" open-type="switchTab">去逛逛</navigator>
</view> -->
<view class='cart-none' v-else>
<image class="cart-none-img" src="/static/image/car.png" mode=""></image>
<view class='cart-none-t'>购物车快饿瘪了 T.T</view>
<view class='cart-none-m'>快给我挑点宝贝吧</view>
<navigator class="cart-none-b" url='../../index/index' hover-class="btn-hover" open-type="switchTab">去逛逛</navigator>
</view>
</template>
<script>
import uniNumberBox from '@/components/uni-number-box/uni-number-box.vue'
import { goods } from '@/config/mixins.js'
export default {
mixins: [goods],
data() {
return {
startX: 0, //开始坐标
startY: 0,
cartData: {}, //购物车数据
cartIds: [], //选中ids
checkboxAll: false, //全选按钮
total: 0.0, //总价
goSettlement: false, //去结算按钮
cartId: '',
cartNum: '',
isLoad: false,
cartNums: 0,
editStatus: false
}
},
components: { uniNumberBox },
//页面加载
onShow: function() {
let userToken = this.$db.get('userToken')
if (userToken) {
this.getCartData(); //获取购物车数据
}
},
computed: {
// 从vuex中获取店铺名称
shopName() {
return this.$store.state.config.shop_name
},
goods_stocks_warn() {
return this.$store.state.config.goods_stocks_warn
}
},
methods: {
checkboxChange: function(e) {
let _this = this
let id = e
let cartData = _this.cartData
for (let key in cartData.list) {
if (cartData.list[key].id == id) {
if (cartData.list[key].is_select == true) {
cartData.list[key].is_select = false
} else {
cartData.list[key].is_select = true
}
}
}
_this.cartData = cartData
_this.setNumsData()
_this.isAllCheckbox()
},
//数组转字符串
arrayToStr: function(array) {
return array.toString()
},
//获取购物车数据
getCartData: function() {
let _this = this
let cartIds = _this.arrayToStr(_this.cartIds)
let data = {
ids: cartIds,
display: 'all'
}
this.$api.cartList(data, function(res) {
if (res.status) {
let data = res.data
_this.showHandle(data) //数量设置
}
})
},
//渲染前配置数据
showHandle: function(data, flag = true) {
let _this = this
let goSettlement = false
for (let i in data.list) {
//不可能购买0件
if (data.list[i].nums < 1) {
data.list[i].nums = 1
}
//不能买大于库存的数量(库存不足)
let stockNo = false
let maxStock = data.list[i].products.stock
if (data.list[i].nums > data.list[i].products.stock) {
//data.list[i].nums = data.list[i].products.stock;
stockNo = true
maxStock = data.list[i].nums
}
data.list[i].maxStock = maxStock
data.list[i].stockNo = stockNo
//库存紧张
let stockTension = false
if (_this.goods_stocks_warn >= data.list[i].products.stock) {
stockTension = true
}
data.list[i].stockTension = stockTension
//设置样式
data.list[i].minStatus = 'normal'
data.list[i].maxStatus = 'normal'
if (data.list[i].nums == 1) {
data.list[i].minStatus = 'disabled'
}
if (data.list[i].nums == data.list[i].products.stock) {
data.list[i].maxStatus = 'disabled'
}
//设置规格参数
data.list[i].spes = []
if (data.list[i].products.spes_desc != null) {
let spesArray = data.list[i].products.spes_desc.split(',')
for (let key in spesArray) {
let spesOne = spesArray[key].split(':')
data.list[i].spes.push(spesOne[1])
}
}
//添加左滑效果
data.list[i].isTouchMove = false
//是否可以去支付
if (data.list[i].is_select) {
goSettlement = true
}
//id转换为字符串
data.list[i].id = _this.arrayToStr(data.list[i].id)
//选中状态
if (flag) {
if (data.list[i].is_select) {
if (_this.cartIds.indexOf(data.list[i].id) < 0) {
_this.cartIds.push(data.list[i].id)
}
}
}
}
data.goods_pmt = _this.$common.formatMoney(data.goods_pmt, 2, '')
data.order_pmt = _this.$common.formatMoney(data.order_pmt, 2, '')
data.amount = _this.$common.formatMoney(data.amount, 2, '')
let isLoad = false
if (data.list.length < 1) {
isLoad = true
}
let n = 0
for (let i in data.promotion_list) {
n++
}
_this.goSettlement = goSettlement
_this.isLoad = isLoad
_this.cartNums = n
if (flag) {
_this.cartData = data
} else {
_this.getCartData()
}
_this.isAllCheckbox()
},
//是否全选
isAllCheckbox: function() {
let _this = this
let cartData = _this.cartData.list
let goSettlement = false
let flag = true
for (let key in cartData) {
if (
cartData[key].is_select == false &&
cartData[key].stockNo == false
) {
flag = false
}
if (cartData[key].is_select == true) {
goSettlement = true
}
}
if (cartData.length <= 0) {
flag = false
}
_this.checkboxAll = flag
_this.goSettlement = goSettlement
},
//全选操作
checkboxAllButton: function(e) {
if (this.checkboxAll == true) {
this.checkboxAll = false
this.setAllCheckbox(false)
} else {
this.checkboxAll = true
this.setAllCheckbox(true)
}
},
//全选设置
setAllCheckbox: function(e) {
let _this = this
let cartData = _this.cartData
if (e) {
//全选
for (let key in cartData.list) {
if (cartData.list[key].stockNo == false) {
cartData.list[key].is_select = true
}
}
} else {
//全不选
for (let key in cartData.list) {
cartData.list[key].is_select = false
}
}
_this.cartData = cartData
_this.setNumsData()
_this.isAllCheckbox()
},
//设置刷新数据
setNumsData: function() {
let _this = this
let cartData = _this.cartData
let cartIds = []
for (let key in cartData.list) {
if (cartData.list[key].is_select) {
cartIds.push(cartData.list[key].id)
} else {
// if (cartData.list[key].products.promotion_list) {
// for (let k in cartData.list[key].products.promotion_list) {
// cartData.list[key].products.promotion_list[k].type = 1;
// }
// }
}
}
_this.cartIds = cartIds
_this.cartData = cartData
if (cartIds.length == 0) {
let cartData = _this.cartData
for (let k in cartData.promotion_list) {
cartData.promotion_list[k].type = 1
}
cartData.goods_pmt = '0.00'
cartData.order_pmt = '0.00'
cartData.amount = '0.00'
_this.cartData = cartData
} else {
_this.getCartData()
}
},
//购物车数量调整
bindChange(value, e) {
let _this = this
let id = e.id
let num = value
let cartData = _this.cartData
let changeSelected = false
for (let key in cartData.list) {
if (cartData.list[key].id == id) {
if (num <= cartData.list[key].products.stock) {
cartData.list[key].nums = num
changeSelected = true
}
}
}
if (changeSelected) {
_this.cartData = cartData
_this.cartId = id
_this.cartNum = num
_this.$common.throttle(_this.bindCartNumberOperation, _this, 350)
} else {
//_this.$common.errorToShow('数量错误1');
}
return false
},
//数量减一操作
bindCartNumberOperation: function() {
let _this = this
_this.setCartNum(_this.cartId, _this.cartNum)
},
//设置购物车数量
setCartNum: function(id, nums) {
let _this = this
let data = {
id: id,
nums: nums
}
_this.$api.setCartNum(data, function(res) {
if (_this.cartIds.indexOf(id) > -1) {
//_this.getCartData();
if (res.status) {
_this.$nextTick(function() {
_this.showHandle(res.data, false)
})
} else {
_this.$common.errorToShow(res.msg)
}
} else {
_this.$nextTick(function() {
_this.showHandle(res.data, false)
})
}
})
},
//删除事件
del: function(index, id) {
let _this = this
let cartid = id //cart_id
//移除渲染
_this.cartData.list.splice(index, 1)
_this.cartData = _this.cartData
_this.isLoad = true
//移除数据库
let data = {
ids: cartid
}
_this.$api.removeCart(data, function(res) {
if (res.status) {
_this.$common.successToShow(res.msg)
}
_this.setNumsData()
_this.isAllCheckbox()
})
},
//收藏
collection: function(e) {
let _this = this
app.db.userToken(function(token) {
let data = {
goods_id: e.currentTarget.dataset.goodsid
}
app.api.goodsCollection(data, function(res) {
for (let k in _this.cartData.list) {
if (
_this.cartData.list[k].products.goods_id ==
e.currentTarget.dataset.goodsid
) {
if (res.msg == '收藏成功') {
_this.cartData.list[k].isCollection = true
} else {
_this.cartData.list[k].isCollection = false
}
}
}
wx.showToast({
title: res.msg,
complete: function () {
setTimeout(function() {
uni.hideToast();
},1000);
}
})
})
})
},
//去结算
settlement: function(e) {
let _this = this
if (_this.goSettlement) {
let cartData = _this.cartData.list
let newData = ''
for (let key in cartData) {
if (cartData[key].is_select == true) {
newData += ',' + cartData[key].id
}
}
if (newData.substr(0, 1) == ',') {
newData = newData.substr(1)
}
if (newData.length > 0) {
_this.$common.navigateTo(
'/pages/goods/place-order/index?cart_ids=' + JSON.stringify(newData)
)
return true
} else {
//没有选择不跳转
}
}
},
//手指触摸动作开始 记录起点X坐标
touchstart: function(e) {
//开始触摸时 重置所有删除
let _this = this
_this.cartData.list.forEach(function(v, i) {
if (v.isTouchMove)
//只操作为true的
v.isTouchMove = false
})
_this.setData({
startX: e.changedTouches[0].clientX,
startY: e.changedTouches[0].clientY,
cartData: _this.cartData
})
},
//滑动事件处理
touchmove: function(e) {
let _this = this
let index = e.currentTarget.dataset.index //当前索引
let startX = _this.startX //开始X坐标
let startY = _this.startY //开始Y坐标
let touchMoveX = e.changedTouches[0].clientX //滑动变化坐标
let touchMoveY = e.changedTouches[0].clientY //滑动变化坐标
let angle = _this.angle(
{ X: startX, Y: startY },
{ X: touchMoveX, Y: touchMoveY }
) //获取滑动角度
_this.cartData.list.forEach(function(v, i) {
v.isTouchMove = false
//滑动超过30度角 return
if (Math.abs(angle) > 30) return
if (i == index) {
if (touchMoveX > startX)
//右滑
v.isTouchMove = false
else
//左滑
v.isTouchMove = true
}
})
//更新数据
_this.setData({
cartData: _this.cartData
})
},
//计算滑动角度
angle: function(start, end) {
let _X = end.X - start.X,
_Y = end.Y - start.Y
//返回角度 /Math.atan()返回数字的反正切值
return 360 * Math.atan(_Y / _X) / (2 * Math.PI)
},
//点击编辑
editBtn: function() {
this.editStatus = true
},
//点击完成
editNoBtn: function() {
let _this = this
this.editStatus = false
let is_select = false
for (let i in _this.cartData.list) {
if (_this.cartData.list[i].is_select) {
is_select = true
break
}
}
if (is_select) {
_this.getCartData()
}
},
delList: function() {
let _this = this
let ids = []
for (let k in _this.cartData.list) {
if (_this.cartData.list[k].is_select) {
ids += _this.cartData.list[k].id + ','
}
}
let data = {
ids: ids
}
_this.$api.removeCart(data, function(res) {
if (res.status) {
_this.$common.successToShow(res.msg)
}
_this.setNumsData()
_this.isAllCheckbox()
})
}
}
}
</script>
<style>
.cell-item-hd {
max-width: 40upx;
min-width: 40upx;
}
.margin-cell-group {
margin: 0 0 2upx 0;
}
.little-right .goods-salesvolume {
float: none;
}
.cart-bottom {
/* #ifdef H5 */
bottom: 50px;
/* #endif */
/* #ifndef H5 */
bottom: 0;
/* #endif */
z-index: 99;
height: 90upx;
width: 100%;
background-color: #fff;
position: fixed;
overflow: hidden;
box-shadow: 0 0 20upx #ccc;
}
.cart-bottom-right {
height: 90upx;
float: right;
overflow: hidden;
}
.cart-bottom-right-t {
display: inline-block;
height: 100%;
line-height: 90upx;
margin-right: 20upx;
font-size: 28upx;
color: #666;
}
.cart-bottom-right-t .red-price {
float: none;
}
.btn-square {
float: right;
}
.cart-bottom .cart-checkbox-c {
color: #333;
font-size: 30upx;
}
.cart-none {
text-align: center;
padding: 200upx 0;
}
.cart-none-img {
width: 252upx;
height: 228upx;
margin-bottom: 40upx;
}
.cart-none-t {
color: #666;
font-size: 28upx;
}
.cart-none-m {
color: #666;
font-size: 28upx;
margin-bottom: 40upx;
}
.cart-none-b {
/* border: 2upx solid #ccc; */
display: inline-block;
padding: 16upx 40upx;
font-size: 30upx;
color: #666;
background-color: #e3e3e3;
}
.stockError {
font-size: 12px;
color: #ffffff;
background-color: #ff7159;
padding: 1px 3px;
border-radius: 3px;
}
.stockTension {
background-color: #ffc107;
}
/* #ifdef MP-ALIPAY */
label {
display: block;
}
/* #endif */
.click-del{
overflow: hidden;
height: 52upx;
}
.click-del .icon{
float: right;
}
</style>
classify
classify.vue
<template>
<view class="classify">
<!-- 二级小图 -->
<view class="goods-box" v-if="cate_style == 3">
<view class="goods-list">
<scroll-view scroll-y="true">
<view class="goods-li" :class="{active:index==ins}" @click="active(index)" v-for="(tab,index) in beans" :key="index">
<view class="shelectedZhu"></view>
{{tab.name}}
</view>
</scroll-view>
</view>
<view class="goods-grid">
<scroll-view class="goods-content" scroll-y="true">
<view class="goods-banner" v-if="advert.tpl1_class_banner1">
<image mode="widthFix" v-for="item in advert.tpl1_class_banner1" :key="item.id" :src="item.img" @click="showSliderInfo(item.type, item.val)"/>
</view>
<view class="goods-item">
<view class="goods-item-box" v-if="isChild">
<view class="goods-items" v-for="(item, index) in beans[ins].child" :key="index" @click="goClass(item.id)">
<image class="goods-item-img" :src="item.image_url" alt="" mode="aspectFill"/>
<view class="goods-item-name">{{item.name}}</view>
</view>
</view>
</view>
</scroll-view>
</view>
</view>
<!-- 一级小图 -->
<view class="goods-box level1-s" v-if="cate_style == 2">
<view class="goods-grid">
<scroll-view class="goods-content" scroll-y="true">
<view class="goods-item">
<view class="goods-item-box">
<view class="goods-items" v-for="(item, index) in beans" :key="index" @click="goClass(item.id)">
<image class="goods-item-img" :src="item.image_url" alt="" mode="aspectFill"/>
<view class="goods-item-name">{{item.name}}</view>
</view>
</view>
</view>
</scroll-view>
</view>
</view>
<!-- 一级大图 -->
<view class="goods-box level1-b" v-if="cate_style == 1">
<view class="goods-grid">
<scroll-view class="goods-content" scroll-y="true">
<view class="goods-item">
<view class="goods-item-box">
<view class="goods-items" v-for="(item, index) in beans" :key="index" @click="goClass(item.id)">
<image class="goods-item-img" :src="item.image_url" alt="" mode="aspectFill"/>
<view class="goods-item-name">{{item.name}}</view>
</view>
</view>
</view>
</scroll-view>
</view>
</view>
</view>
</template>
<script>
var _this;
import { mapGetters } from 'vuex'
import { goods } from '@/config/mixins.js'
export default {
mixins: [goods],
data() {
return {
dataList: null,
ins: 0,
beans:[],
advert: {},
isChild: false
};
},
computed: {
cate_style () {
return this.$store.state.config.cate_style ? this.$store.state.config.cate_style : 3;
}
},
methods: {
//切换样式 请求分类数据
active (index) {
this.ins = index;
this.isChild = this.beans[index].hasOwnProperty('child');
},
categories () {
this.$api.categories({}, res => {
if(res.status){
for(var i = 0; i < res.data.length; i++){
if (i == 0) {
res.data[i].active = true;
}
}
this.beans = res.data;
this.isChild = this.beans[0].hasOwnProperty('child');
}
});
},
goClass (cat_id) {
uni.navigateTo({
url: '/pages/classify/index?id=' + cat_id
});
},
getBanner() {
this.$api.advert({
codes: 'tpl1_class_banner1'
}, res => {
this.advert = res.data.list;
});
},
// 广告点击查看详情
showSliderInfo(type, val) {
if (type == 1) {
// URL
// #ifdef H5
window.location.href = val
// #endif
} else if (type == 2) {
// 商品详情
this.goodsDetail(val)
} else if (type == 3) {
// 文章详情
this.$common.navigateTo('/pages/article/index?id=' + val +'&id_type=1')
} else if (type == 4) {
// 文章列表
this.$common.navigateTo('/pages/article/list?cid=' + val)
}
},
},
onLoad () {
this.categories();
this.getBanner();
},
};
</script>
<style>
.classify {
/* #ifdef H5 */
height: calc(100vh - 188upx);
/* #endif */
/* #ifndef H5 */
height: 100vh;
/* #endif */
}
.goods-box {
height: 100%;
overflow: hidden;
}
.goods-list {
overflow: auto;
height: 100%;
width: 160upx;
float: left;
display: inline-block;
background-color: #f8f8f8;
}
.goods-li{
font-size: 24upx;
color: #666;
height: 100upx;
line-height: 100upx;
text-align: center;
position: relative;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.goods-li.active{
background-color: #fff;
}
.shelectedZhu {
height: 56upx;
width: 8upx;
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.goods-li.active .shelectedZhu{
background-color: #333;
}
.goods-content{
width: 590upx;
display: inline-block;
float: left;
padding: 20upx;
box-sizing: border-box;
}
.goods-grid{
height: 100%;
overflow: auto;
background-color: #fff;
}
.goods-banner{
width: 100%;
/* height: 200upx; */
margin-bottom: 20upx;
}
.goods-banner image{
width: 100%;
height: 100%;
}
.goods-item{
}
.goods-item-box{
overflow: hidden;
}
.goods-items{
width: 170upx;
margin-right: 20upx;
margin-bottom: 20upx;
display: inline-block;
}
.goods-items:nth-child(3n){
margin-right: 0;
}
.goods-item-img{
width: 170upx;
height: 170upx;
}
.goods-item-name{
text-align: center;
color: #666;
font-size: 26upx;
}
.level1-s .goods-content,.level1-b .goods-content{
width: 100%;
}
.level1-s .goods-items{
width: 222upx;
}
.level1-s .goods-item-img{
width: 222upx;
height: 222upx;
}
.level1-b .goods-items{
width: 100%;
}
.level1-b .goods-item-img{
width: 100%;
height: 222upx;
}
</style>
index.vue
<template>
<view class="content">
<!-- 搜索框 -->
<view class="search">
<view class="search-c" @click="goSearch">
<view class="search-input search-input-p" v-bind:class="$store.state.searchStyle">
<view class="search-input-p-c">
{{ searchKey }}
</view>
</view>
<image class="icon search-icon" src="/static/image/zoom.png"></image>
</view>
</view>
<!-- 条件筛选 -->
<view class="screen">
<view class="screen-item" @click="comprehensive">
<text class="screen-item-text">综合</text>
<view class='screen-item-icon'>
<image v-if="searchData.order.key == 'sort' && searchData.order.sort == 'asc'" class="screen-item-icon-img" src="/static/image/bottom-black.png"></image>
<image v-else class="screen-item-icon-img" src="/static/image/bottom-gray.png" ></image>
</view>
</view>
<view class="screen-item" @click="priceSort">
<text class="screen-item-text">价格</text>
<view class="screen-item-icon">
<image v-if="searchData.order.key == 'price' && searchData.order.sort == 'asc'" class="screen-item-icon-img" src="/static/image/top-black.png"></image>
<image v-else-if="!(searchData.order.key == 'price' && searchData.order.sort == 'asc')" class="screen-item-icon-img" src="/static/image/top-gray.png"></image>
<image v-if="searchData.order.key == 'price' && searchData.order.sort == 'desc'" class="screen-item-icon-img" src="/static/image/bottom-black.png"></image>
<image v-if="!(searchData.order.key == 'price' && searchData.order.sort == 'desc')" class="screen-item-icon-img" src="/static/image/bottom-gray.png" ></image>
</view>
</view>
<view class="screen-item" @click="salesVolume">
<text class="screen-item-text">销量</text>
<view class="screen-item-icon">
<image v-if="searchData.order.key == 'buy_count' && searchData.order.sort == 'asc'" class="screen-item-icon-img" src="/static/image/top-black.png"></image>
<image v-else-if="!(searchData.order.key == 'buy_count' && searchData.order.sort == 'asc')" class="screen-item-icon-img" src="/static/image/top-gray.png"></image>
<image v-if="searchData.order.key == 'buy_count' && searchData.order.sort == 'desc'" class="screen-item-icon-img" src="/static/image/bottom-black.png"></image>
<image v-if="!(searchData.order.key == 'buy_count' && searchData.order.sort == 'desc')" class="screen-item-icon-img" src="/static/image/bottom-gray.png"></image>
</view>
</view>
<view class="screen-item">
<view class="screen-item-icon" style-type="button" :current="current" @click="listGrid">
<image class="list-grid" src="/static/image/switch-ic-side-2.png" v-if="current == 0"></image>
<image class="list-grid" src="/static/image/switch-ic-list.png" v-else-if="current == 1"></image>
</view>
</view>
<view class="screen-item screents" v-if="screents" @click="toshow()">
<text class="screen-item-text">筛选</text>
<image class="filter-img" src="/static/image/top.png"></image>
</view>
<view class="screen-item screents" v-else-if="screentc" @click="toclose()">
<text class="screen-item-text">筛选</text>
<image class="filter-img" src="/static/image/bottom.png"></image>
</view>
</view>
<!-- 高级赛选 -->
<lvv-popup position="top" ref="lvvpopref" style="background: none;">
<view class="fliter-c">
<scroll-view scroll-y="true" style="height: 100%;">
<view class="fliter-item">
<view class='cell-item right-img'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>价格区间</view>
</view>
</view>
<view class="fliter-i-c">
<view class="fic-item">
<input class="fic-item-input" type="number" v-model="sPrice" />
</view>
<view class="fic-item-line"></view>
<view class="fic-item">
<input class="fic-item-input" type="number" v-model="ePrice" />
</view>
</view>
</view>
<view class="fliter-item" v-if="cat_list.length > 0">
<view class='cell-item right-img'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>分类</view>
</view>
</view>
<view class="fliter-i-c">
<view v-for="item in cat_list" :key="item.goods_cat_id" v-if="item.goods_cat_id && item.name" @click="selectKey('cat_list', item.goods_cat_id)">
<view class="fic-item" v-if="!item.isSelect">
<view class="fic-item-text two-line" >
{{item.name}}
</view>
</view>
<view class="fic-item fic-item-active" v-else-if="item.isSelect">
<view class="fic-item-text two-line">
{{item.name}}
</view>
</view>
</view>
</view>
</view>
<view class="fliter-item" v-if="brand_list.length > 0">
<view class='cell-item right-img'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>品牌</view>
</view>
</view>
<view class="fliter-i-c">
<view v-for="item in brand_list" :key="item.brand_id" v-if="item.brand_id && item.name" @click="selectKey('brand_list', item.brand_id)">
<view class="fic-item" v-if="!item.isSelect">
<view class="fic-item-text two-line">
{{item.name}}
</view>
</view>
<view class="fic-item fic-item-active" v-else-if="item.isSelect">
<view class="fic-item-text two-line">
{{item.name}}
</view>
</view>
</view>
</view>
</view>
<view class="fliter-item" v-if="label_list.length > 0">
<view class='cell-item right-img'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>标签</view>
</view>
</view>
<view class="fliter-i-c">
<view v-for="item in label_list" :key="item.id" v-if="item.id && item.name" @click="selectKey('label_list', item.id)">
<view class="fic-item" v-if="!item.isSelect">
<view class="fic-item-text two-line">
{{item.name}}
</view>
</view>
<view class="fic-item fic-item-active" v-else-if="item.isSelect">
<view class="fic-item-text two-line">
{{item.name}}
</view>
</view>
</view>
</view>
</view>
</scroll-view>
<view class="button-bottom">
<!-- <button class="btn btn-square" @click="filterNo()">重置</button> -->
<button class="btn btn-square" @click="toclose()">关闭</button>
<button class="btn btn-b btn-square" @click="filterOk()">确定</button>
</view>
</view>
</lvv-popup>
<!-- 商品列表 -->
<scroll-view scroll-y="true" :scroll-into-view="toView" class="scroll-Y" @scrolltolower="lower" enable-back-to-top="true" lower-threshold="45">
<!-- 表格图片 -->
<view class="img-grids" v-show="current === 0">
<view v-if="goodsList.length>0">
<view class="img-grids-item" v-for="(item, index) in goodsList" :key="index" @click="goodsDetail(item.id)">
<image class="img-grids-item-t have-none" :src="item.image_url" mode='aspectFill'></image>
<view class="img-grids-item-b">
<view class="goods-name grids-goods-name">
{{item.name}}
</view>
<view class="goods-item-c">
<view class="goods-price red-price">¥{{item.price}}</view>
<image class="goods-cart" src="/static/image/ic-car.png"></image>
</view>
</view>
</view>
</view>
<!-- 无数据时默认显示 -->
<view class="order-none" v-else>
<image class="order-none-img" src="/static/image/order.png" mode=""></image>
</view>
</view>
<!-- 列表图片 -->
<view class="img-list" v-show="current === 1">
<view v-if="goodsList.length>0">
<view class="img-list-item" v-for="(item, index) in goodsList" :key="index" @click="goodsDetail(item.id)">
<image class="img-list-item-l" :src="item.image_url" mode='aspectFill'></image>
<view class="img-list-item-r">
<view class="goods-name list-goods-name">
{{item.name}}
</view>
<view class="goods-item-c">
<view class="goods-price red-price">¥{{item.price}}</view>
<view class="goods-buy">
<view class="goods-salesvolume" v-if="item.comments_count > 0">{{item.comments_count}}条评论</view>
<view class="goods-salesvolume" v-else-if="item.comments_count <= 0">暂无评论</view>
<image class="goods-cart" src="/static/image/ic-car.png"></image>
</view>
</view>
</view>
</view>
</view>
<view class="order-none" v-else>
<image class="order-none-img" src="/static/image/order.png" mode=""></image>
</view>
</view>
</scroll-view>
</view>
</template>
<script>
import lvvPopup from '@/components/lvv-popup/lvv-popup.vue'
export default {
data() {
return {
current: 0,
id: '',
showView: false,
goodsList: [],
minPrice: '',
maxPrice: '',
ajaxStatus: false,
loading: true,
loadingComplete: false,
nodata: false,
toView: '',
searchData: {
where: {},
limit: 10,
page: 1,
order: {
key: 'sort',
sort: 'asc'
}
},
searchKey: '请输入关键字搜索', //关键词
alllist: true,
allgrid: false,
screents: true,
screentc: false,
sPrice: '',
ePrice: '',
brand_list: [],
cat_list: [],
label_list: []
};
},
//加载执行
onLoad: function(options) {
var where = {};
if (options.id) {
where = {
cat_id: options.id
};
//this.getGoodsClass(options.id);
}
if (options.key) {
where = {
search_name: options.key
};
this.searchKey = options.key;
}
if (options.type) {
if (options.type == 'hot') {
where = {
hot: true
};
}
if (options.type == 'recommend') {
where = {
recommend: true
}
}
}
if(options.cat_id){
where.cat_id = options.cat_id
}
if(options.brand_id){
where.brand_id =options.brand_id
}
if(options.hot){
where.hot =options.hot
}
if(options.recommend){
where.recommend =options.recommend
}
if(options.label_id){
where.label_id =options.label_id
}
this.setSearchData({
where: where
});
this.getGoods();
},
components: {lvvPopup},
methods: {
listGrid() {
if (this.current == 0) {
this.current = 1;
} else {
this.current = 0;
}
},
//设置查询条件
setSearchData: function(searchData, clear = false) {
var sd = this.searchData;
this.searchData = this.$common.deepCopy(sd, searchData)
if (clear) {
this.goodsList = [];
}
},
//获取分类名称
// getGoodsClass: function(id) {
// let data = {
// id: id
// };
// this.$api.getGoodsClass(data, function(res) {
// wx.setNavigationBarTitle({
// title: res.data
// });
// });
// },
onChangeShowState: function() {
var _this = this;
_this.showView = !_this.showView;
},
//点击综合排序
comprehensive: function() {
this.setSearchData(
{
order: {
key: 'sort',
sort: 'asc'
},
page: 1
},
true
);
this.getGoods();
},
//销量
salesVolume: function() {
if (this.searchData.order.key == 'buy_count') {
if (this.searchData.order.sort == 'desc') {
this.searchData.order.sort = 'asc';
} else {
this.searchData.order.sort = 'desc';
}
} else {
this.searchData.order = {
key: 'buy_count',
sort: 'desc'
};
}
this.searchData.page = 1; //从第一页重新显示
this.setSearchData(this.searchData, true);
this.getGoods();
},
//价格排序
priceSort: function() {
if (this.searchData.order.key == 'price') {
if (this.searchData.order.sort == 'desc') {
this.searchData.order.sort = 'asc';
} else {
this.searchData.order.sort = 'desc';
}
} else {
this.searchData.order = {
key: 'price',
sort: 'asc'
};
}
this.searchData.page = 1; //从第一页重新显示
this.setSearchData(this.searchData, true);
this.getGoods();
},
//设置查询价格区间
// orderPrice: function(e) {
// var reg = /^[0-9]+(.[0-9]{2})?$/;
// if (!reg.test(e.detail.value)) {
// this.$common.errorToShow('请输入正确金额');
// this.maxPrice = '';
// } else {
// this.maxPrice = e.detail.value;
// }
// },
//查询价格区间
// searchPrice: function(event) {
// if (
// this.minPrice > 0 &&
// this.maxPrice > 0 &&
// this.minPrice > this.maxPrice
// ) {
// app.common.errorToShow('价格区间有误');
// return false;
// }
//
// this.setSearchData(
// {
// page: 1,
// where: {
// price_f: this.minPrice,
// price_t: this.maxPrice
// }
// },
// true
// );
// this.getGoods();
// },
//页面相关事件处理函数--监听用户下拉动作
onPullDownRefresh: function() {},
//跳转到商品详情页面
goodsDetail: function(id) {
let url = '/pages/goods/index/index?id=' + id;
this.$common.navigateTo(url);
},
//取得商品数据
getGoods: function() {
var _this = this;
if (_this.ajaxStatus) {
return false;
}
_this.ajaxStatus = true;
_this.loading = true;
_this.loadingComplete = false;
_this.nodata = true;
//如果已经没有数据了,就不取数据了,直接提示已经没有数据
if (_this.loadingComplete) {
_this.$common.errorToShow("暂时没有数据了")
return false;
}
_this.$api.goodsList(_this.conditions(), function(res) {
if (res.status) {
//判是否没有数据了,只要返回的记录条数小于总记录条数,那就说明到底了,因为后面没有数据了
var isEnd = false;
if (res.data.list.length < _this.searchData.limit) {
isEnd = true;
}
//判断是否为空
var isEmpty = false;
if (_this.searchData.page == 1 && res.data.list.length == 0) {
isEmpty = true;
}
if(res.data.class_name != ''){
uni.setNavigationBarTitle({
title: res.data.class_name
});
}else{
if(res.data.where && res.data.where.search_name && res.data.where.search_name != ''){
uni.setNavigationBarTitle({
title: '商品搜索'
});
}
}
_this.goodsList = _this.goodsList.concat(res.data.list);
_this.ajaxStatus = false;
_this.loading = !isEnd && !isEmpty;
_this.toView = '';
_this.loadingComplete = isEnd && !isEmpty;
_this.nodata = isEmpty;
if(res.data.filter){
let filter = res.data.filter;
if(filter.brand_ids){
for(let i = 0; i < filter.brand_ids.length; i++){
filter.brand_ids[i].isSelect = false;
}
_this.brand_list = filter.brand_ids;
}
if(filter.goods_cat){
for(let i = 0; i < filter.goods_cat.length; i++){
filter.goods_cat[i].isSelect = false;
}
_this.cat_list = filter.goods_cat;
}
if(filter.label_ids){
for(let i = 0; i < filter.label_ids.length; i++){
filter.label_ids[i].isSelect = false;
}
_this.label_list = filter.label_ids;
}
}
}
});
},
//上拉加载
lower: function() {
var _this = this;
_this.toView = 'loading';
if (!_this.loadingComplete) {
_this.setSearchData({
page: _this.searchData.page + 1
});
_this.getGoods();
}
},
listgrid: function() {
let _this = this;
if (_this.alllist) {
_this.allgrid = true;
_this.listgrid = true;
_this.alllist = false;
} else {
_this.allgrid = false;
_this.listgrid = false;
_this.alllist = true;
}
},
// 统一返回筛选条件 查询条件 分页
conditions () {
let data = this.searchData;
var newData = {};
newData = this.$common.deepCopy(newData,data);
//把data里的where换成json
if(data.where){
newData.where = JSON.stringify(data.where);
}
//把排序换成字符串
if(data.order){
var sort = data.order.key + ' ' + data.order.sort;
if(data.order.key != 'sort'){
sort = sort + ',sort asc' //如果不是综合排序,增加上第二个排序优先级排序
}
newData.order = sort;
}else{
newData.order = 'sort asc';
}
return newData;
},
//老搜索
search(){
this.setSearchData(
{
page: 1,
where: {
search_name: this.keyword
}
},
true
);
this.getGoods();
},
//去搜索
goSearch() {
let pages = getCurrentPages();
let prevPage = pages[pages.length - 2];
// #ifdef H5 || MP-WEIXIN
if(prevPage && prevPage.route){
let search_flag = prevPage.route;
if (search_flag == 'pages/index/search') {
uni.navigateBack({
delta: 1
});
}else{
this.$common.navigateTo('/pages/index/search');
}
}else{
this.$common.navigateTo('/pages/index/search');
}
// #endif
// #ifdef MP-ALIPAY
if(prevPage && prevPage.__proto__.route){
let search_flag = prevPage.__proto__.route;
if (search_flag == 'pages/index/search') {
uni.navigateBack({
delta: 1
});
}else{
this.$common.navigateTo('/pages/index/search');
}
}else{
this.$common.navigateTo('/pages/index/search');
}
// #endif
},
//筛选条件弹出窗口
toshow(){
this.$refs.lvvpopref.show();
this.screents = false;
this.screentc = true;
},
//关闭筛选
toclose(){
this.$refs.lvvpopref.close();
this.screentc = false;
this.screents = true;
},
//取消筛选
filterNo(){
this.ePrice = '';
this.sPrice = '';
for(let i = 0; i < this.cat_list.length; i++){
this.cat_list[i].isSelect = false;
}
for(let i = 0; i < this.brand_list.length; i++){
this.brand_list[i].isSelect = false;
}
for(let i = 0; i < this.label_list.length; i++){
this.label_list[i].isSelect = false;
}
this.filterOk();
this.toclose();
},
//确认筛选
filterOk(){
let data = this.searchData;
//获取分类
// data.where.cat_id = '';
for(let i = 0; i < this.cat_list.length; i++){
if(this.cat_list[i].isSelect){
data.where.cat_id = this.cat_list[i].goods_cat_id;
}
}
//获取多个品牌
let brand_ids = '';
for(let i = 0; i < this.brand_list.length; i++){
if(this.brand_list[i].isSelect){
brand_ids += this.brand_list[i].brand_id+',';
}
}
if(brand_ids){
brand_ids = brand_ids.substr(0, brand_ids.length-1);
}
data.where.brand_id = brand_ids;
//获取标签
data.where.label_id = '';
for(let i = 0; i < this.label_list.length; i++){
if(this.label_list[i].isSelect){
data.where.label_id = this.label_list[i].id;
}
}
//价格区间
data.where.price_f = '';
data.where.price_t = '';
if(this.sPrice*1 < 0 || (this.ePrice != '' && this.ePrice <= 0) || this.ePrice*1 < 0 || (this.sPrice*1 > this.ePrice*1 && this.sPrice != '' && this.ePrice != '')){
this.$common.errorToShow('价格区间有误');
return false;
}else{
data.where.price_f = this.sPrice;
data.where.price_t = this.ePrice;
}
this.setSearchData(data, true);
this.getGoods();
this.toclose();
},
//选择
selectKey(type, id){
//分类一次只能选择一个
if(type == 'cat_list'){
for(let i = 0; i < this.cat_list.length; i++){
if(this.cat_list[i].goods_cat_id == id){
this.cat_list[i].isSelect = this.cat_list[i].isSelect?false:true;
}else{
this.cat_list[i].isSelect = false;
}
}
}
if(type == 'brand_list'){
for(let i = 0; i < this.brand_list.length; i++){
if(this.brand_list[i].brand_id == id){
this.brand_list[i].isSelect = this.brand_list[i].isSelect?false:true;
}
}
}
if(type == 'label_list'){
for(let i = 0; i < this.label_list.length; i++){
if(this.label_list[i].id == id){
this.label_list[i].isSelect = this.label_list[i].isSelect?false:true;
}else{
this.label_list[i].isSelect = false;
}
}
}
}
},
// #ifdef MP-ALIPAY
onChangeShowState_show: function () {
var that = this;
that.setData({
showView: that.showView =true
})
},
onChangeShowState_hid: function () {
var that = this;
that.setData({
showView: that.showView =false
})
},
// #endif
};
</script>
<style>
page{
background-color: #fff;
}
.search{
position: fixed;
z-index: 997;
/* #ifdef H5 */
top: 44px;
/* #endif */
}
.screen {
width: 100%;
padding: 10upx 26upx 20upx;
overflow: hidden;
margin-bottom: 2upx;
background-color: #fff;
position: fixed;
/* #ifdef H5 */
top: calc(44px + 104upx);
/* #endif */
/* #ifndef H5 */
top: 104upx;
/* #endif */
z-index: 997;
}
.screen-item {
width: 20%;
height: 50upx;
line-height: 42upx;
float: left;
text-align: center;
position: relative;
}
.screents {
border-left: 2upx solid #eee;
}
.screen-item-text {
font-size: 24upx;
color: #333;
margin-right: 8upx;
}
.screen-item-icon {
display: inline-block;
position: absolute;
top: 50%;
transform: translateY(-50%);
overflow: hidden;
}
.screen-item-icon-img {
width: 16upx;
height: 8upx;
display: block;
}
.screen-item-icon .screen-item-icon-img:first-child {
margin-bottom: 4upx;
}
.list-grid {
width: 44upx;
height: 44upx;
float: left;
}
.filter-img {
width: 18upx;
height: 8upx;
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.img-grids{
padding-bottom: 26upx;
}
.img-grids-item {
margin-bottom: 0;
}
.img-grids>view,.img-list>view{
overflow: hidden;
}
.scroll-Y{
/* #ifdef H5 */
height:calc(100vh - 44px - 186upx);
/* #endif */
/* #ifndef H5 */
height:calc(100vh - 186upx);
/* #endif */
position: fixed;
bottom: 0;
}
.search-input-p{
color: #888;
}
.order-none{
text-align: center;
padding: 200upx 0;
}
.order-none-img{
width: 274upx;
height: 274upx;
}
.fliter-c{
width: 100%;
/* #ifdef H5 */
height: calc(100% - 44px - 184upx);
top: calc(44px + 182upx);
/* #endif */
/* #ifndef H5 */
height: calc(100% - 184upx);
top: 182upx;
/* #endif */
background: #FFFFFF;
position: absolute;
left:0;
padding-bottom: 90upx;
}
.fliter-item{}
.fliter-item .cell-item{
border-bottom: none;
}
.fliter-i-c{
padding: 0 26upx;
overflow: hidden;
}
.fic-item{
display: inline-block;
float: left;
width: 160upx;
margin-right: 14upx;
height: 70upx;
background-color: #f1f1f1;
text-align: center;
font-size: 24upx;
margin-bottom: 14upx;
color: #333;
padding: 0 10upx;
}
.fic-item-active{
background-color: #FF7159;
color: #fff;
}
.fic-item-text{
position: relative;
top:50%;
transform: translateY(-50%);
}
.fic-item:nth-child(4n){
margin-right: 0;
}
.fic-item-line{
float: left;
margin: 34upx 18upx 0 0;
width: 50upx;
height: 2upx;
border-bottom: 2upx solid #ccc;
}
.fic-item-input{
position: relative;
top: 50%;
transform: translateY(-50%);
}
/* #ifdef MP-ALIPAY */
.hide{
display: none;
}
.show{
display: block;
}
/* #endif */
.square{
border-radius: 0;
}
.radius{
border-radius: 12upx;
}
</style>
pintuan_list.vue
<template>
<view class="content">
<!-- 列表图片 -->
<view class="img-list" >
<view v-if="goodsList.length>0">
<view class="img-list-item" v-for="(item, index) in goodsList" :key="index" @click="goodsDetail(item.id)">
<image class="img-list-item-l" :src="item.image_url" mode='aspectFill'></image>
<view class="img-list-item-r">
<view class="goods-name list-goods-name">
{{item.name}}
</view>
<view class="goods-item-c">
<view class="pintuan_time">
<text class="fsz24 color-9">剩余:</text><uni-countdown textColor="#999" color="#999" :day="item.lasttime.day" :hour="item.lasttime.hour" :minute="item.lasttime.minute" :second="item.lasttime.second"></uni-countdown>
</view>
<view class="goods-price red-price">
¥{{item.pintuanPrice}} <text class="people-num color-9 fsz24">{{item.pintuan_rule.people_number}}人成团</text>
<!-- <image class="goods-cart" src="/static/image/more.png"></image> -->
</view>
<view class="goods-buy">
<view class="goods-salesvolume" v-if="item.comments_count > 0">{{item.comments_count}}条评论</view>
<view class="goods-salesvolume" v-else-if="item.comments_count <= 0">暂无评论</view>
<image class="goods-cart" src="/static/image/more.png"></image>
</view>
</view>
</view>
</view>
</view>
<view class="order-none" v-else>
<image class="order-none-img" src="/static/image/order.png" mode=""></image>
</view>
</view>
</view>
</template>
<script>
import uniCountdown from "@/components/uni-countdown/uni-countdown.vue"
export default {
components:{uniCountdown},
data() {
return {
goodsList: {},
pintuanPrice: 0,
lasttime: {
day: 0,
hour: false,
minute: 0,
second: 0
}, //购买倒计时
};
},
//加载执行
onLoad: function() {
this.getGoods();
},
methods: {
//跳转到商品详情页面
goodsDetail: function(id) {
let url = '/pages/goods/index/pintuan?id=' + id;
this.$common.navigateTo(url);
},
//取得商品数据
getGoods: function() {
var _this = this;
let data = {}
_this.$api.pintuanList(data, res => {
if (res.status) {
_this.goodsList = res.data;
_this.goodsList.forEach(item=>{
if (item.pintuan_price<=0) {
item.pintuan_price = '0.00'
} else {
item.pintuanPrice = this.$common.moneySub(item.price,item.pintuan_rule.discount_amount);
}
let timestamp = Date.parse(new Date())/1000;
let lasttime = item.pintuan_rule.etime - timestamp;
item.lasttime = _this.$common.timeToDateObj(lasttime);
})
}
});
},
},
};
</script>
<style>
.list-grid {
width: 44upx;
height: 44upx;
float: left;
}
.img-grids{
padding-bottom: 26upx;
}
.img-grids-item {
margin-bottom: 0;
}
.img-grids>view,.img-list>view{
overflow: hidden;
}
.order-none{
text-align: center;
padding: 200upx 0;
}
.order-none-img{
width: 274upx;
height: 274upx;
}
.goods-price{
margin-bottom: 10upx;
width: 100%;
overflow: hidden;
}
.people-num{
margin-left: 16upx;
}
.img-list-item .goods-item-c{
bottom: 0;
}
</style>
form
detail
form.vue
<template>
<view v-show="showPage">
<form @submit="formSubmit" bindreset="formReset">
<view class="content">
<view v-if="form.head_type==1">
<view class="banner">
<image :src='form.head_type_value_url[0]' mode='widthFix'></image>
</view>
</view>
<!-- 轮播图 -->
<view v-else-if="form.head_type == 2">
<view>
<view class='sw'>
<swiper>
<swiper-item v-for="(item,item_index) in form.head_type_value_url" :key="item_index">
<image :src="item" class="slide-image" mode='widthFix' />
</swiper-item>
</swiper>
</view>
</view>
</view>
<view v-else-if="form.head_type==3">
<view class='video'>
<video :src='form.head_type_video_url[0]' :poster="form.head_type_value_url[0]"></video>
</view>
</view>
<!-- 纯文字 -->
<view v-if="form.desc !=''">
<view class='plaintext'>
<text>{{form.desc}}</text>
</view>
</view>
<view class="input-box">
<view v-for="(item,index) in form.items" :key="index">
<view class='goods-box-item' v-if="item.type=='goods'">
<image class='goods-img' :src='item.goods.image_url' mode='aspectFit'></image>
<view class='goods-right'>
<view class='goods-name'>{{item.name}}</view>
<view class='goods-mid'>
<text>已售{{item.goods.buy_count}}</text>
</view>
<view class='goods-buttom'>
<view class="goods-price">¥{{item.goods.price}}</view>
<view class='choose-specs' @click="specifications($event,item)" data-type='1' :data-goods="item.goods.id"
:data-id="item.id" data-statu="openspecs">
选规格
</view>
<text class='order-num' v-if="item.cart_count> 0">{{item.cart_count}}</text>
</view>
</view>
</view>
<view class='form-input-box-item' v-if="item.type=='text'">
<view class='ib-item-left'>
<text>{{item.name}}:</text>
</view>
<view class='ib-item-right'>
<input class='ib-item-input' type="text" :name="''+item.id" :data-id="item.id" v-model="item.default_value"
placeholder-class='ib-item-input-c' :placeholder="'请输入'+item.name"></input>
</view>
</view>
<!-- 日期 -->
<view class='form-input-box-item' v-if="item.type=='date'">
<view class='ib-item-left'>
<text>{{item.name}}:</text>
</view>
<view class='ib-item-right'>
<view class="ib-item-mid">
<picker mode="date" :name="''+item.id" :value="item.default_value" start="1949-10-01" end="2019-10-01" @change="bindDateChange($event,item)"
:data-id='item.id'>
<view>{{item.default_value}}</view>
</picker>
<image class='icon-img-right' src='/static/image/ic-unfold.png'></image>
</view>
</view>
</view>
<!-- 时间 -->
<view class='form-input-box-item' v-if="item.type=='time'">
<view class='ib-item-left'>
<text>{{item.name}}:</text>
</view>
<view class='ib-item-right'>
<view class="ib-item-mid">
<picker class="weui-btn" :name="''+item.id" mode="time" :value="item.default_value" start="09:01" end="21:01"
@change="bindTimeChange($event,item)" :data-id='item.id'>
<view>{{item.default_value}}</view>
</picker>
<image class='icon-img-right' src='/static/image/ic-unfold.png'></image>
</view>
</view>
</view>
<!-- 范围选择 -->
<!-- 多选 -->
<view class='form-input-box-item' v-if="item.type=='checbox'">
<view class='ib-item-left'>
<text>{{item.name}}:</text>
</view>
<view class='ib-item-right'>
<view class='checkout-list'>
<checkbox-group @change="checkboxChange($event,item)" :data-value="item.id" :name="''+item.id">
<label class="checkout-item" v-for="(checkbox_item,item_index) in item.checbox_value" :key="item_index">
<view class="checkout-item-c" :class="checkbox_item.checked?'black':''">
<checkbox class="" :value="checkbox_item.value" :checked="checkbox_item.checked" /> {{checkbox_item.value}}
</view>
</label>
</checkbox-group>
</view>
</view>
</view>
<!-- radio时处理 -->
<view class='form-input-box-item' v-if="item.type=='radio'">
<view class='ib-item-left'>
<text>{{item.name}}:</text>
</view>
<view class='ib-item-right'>
<radio-group class="uni-list" @change="radioChange($event,item)" :data-value="item.id" :name="''+item.id">
<label class=" uni-list-cell uni-list-cell-pd " v-for="(radio_item, item_index) in item.radio_value" :key="item_index">
<view class="invoice-type-icon">
<radio class="a-radio" :id="radio_item" :value="radio_item" checked=true v-if="radio_item==item.default_value"></radio>
<radio class="a-radio" :id="radio_item" :value="radio_item" v-if="radio_item!=item.default_value"></radio>
</view>
<view class="invoice-type-c">
<label class="label-2-text" :for="radio_item">
<text>{{radio_item}}</text>
</label>
</view>
</label>
</radio-group>
</view>
</view>
<!-- 省市区选择 -->
<view class='form-input-box-item' v-if="item.type=='area'">
<view class='ib-item-left'>
<text>{{item.name}}:</text>
</view>
<view class='ib-item-right'>
<view class="ib-item-mid">
<input class="fsz26" :value="pickerValue" @focus="showThreePicker" :name="''+item.id" />
<area-picker class="fsz26" ref="areaPicker" :areaId="areaId" :defaultIndex="defaultIndex" @onConfirm="onConfirm"></area-picker>
</view>
</view>
</view>
<!-- 金额 -->
<view class='form-input-box-item' v-if="item.type=='money'">
<view class='ib-item-left'>
<text>{{item.name}}:</text>
</view>
<view class='ib-item-right'>
<view class="ib-item-mid">
<input class='ib-item-input' type="digit" :name="''+item.id" v-model="item.default_value" placeholder-class='ib-item-input-c'
:placeholder="'请输入'+item.name"></input>
</view>
</view>
</view>
<!-- 密码 -->
<view class='form-input-box-item' v-if="item.type=='password'">
<view class='ib-item-left'>
<text>{{item.name}}:</text>
</view>
<view class='ib-item-right'>
<view class="ib-item-mid">
<input class='ib-item-input' type='password' :name="''+item.id" v-model="item.default_value" placeholder-class='ib-item-input-c'
:placeholder="'请输入'+item.name"></input>
</view>
</view>
</view>
<!-- 图片 -->
<view class='form-input-box-item' v-if="item.type=='image'">
<view class='form-input-box-title'>上传{{item.name}}</view>
<view class='form-multiple-rows'>
<view class='f-m-r-item'>
<view class='upload-img-list'>
<view class='upload-img-bd'>
<view class='upload-img' v-for="(pic_item, i) in item.pics" :key="i">
<image @click='pic_del(item,index,i)' :data-index="i" class='del-img' src='/static/image/del.png'></image>
<image class='upload-camera' :src="pic_item.src" mode='aspectFit'></image>
<input type='text' hidden='hidden' :name="item.id+'_'+i" v-model="pic_item.image_id"></input>
</view>
</view>
<view class='upload-img-hd'>
<image class='upload-camera' src="/static/image/camera.png" @click="pic_choose($event,item,index)"
:data-id="item.id"></image>
</view>
</view>
</view>
</view>
</view>
<!-- 文本域 -->
<view class='form-input-box-item' v-if="item.type=='textarea'">
<view class='form-input-box-title'>{{item.name}}</view>
<view class='form-multiple-rows'>
<view class='f-m-r-item form-input-box-item'>
<textarea :name="''+item.id" class='ib-item-textarea' :placeholder="'请输入'+item.name" placeholder-class="ib-item-input-c"></textarea>
</view>
</view>
</view>
<!-- 定位 -->
<view class='form-input-box-item' v-if="item.type=='coordinate'">
<view class='ib-item-left'>
<text>{{item.name}}:</text>
</view>
<view class='ib-item-right'>
<view class="ib-item-mid">
<image class='icon-img' src='/static/image/ic-location.png'></image>
<input class='ib-item-input margin-r' placeholder-class='ib-item-input-c' :name="''+item.id" :value="item.default_value"
disabled='disabled' placeholder="点击获取位置信息" @click="chooseLocation($event,item)" :data-id='item.id' />
</view>
</view>
</view>
</view>
</view>
<view class='goods-bottom' v-if="form.type==1">
<text class='goods-total'>合计
<text class='goods-total-r'>¥{{goodsTotalMoney}}</text>
</text>
</view>
</view>
<!-- 底部按钮 -->
<view class='bottom-btn'>
<button :style='{backgroundColor:form.button_color}' data-statu="open" form-type="submit" :disabled='submitStatus'
:loading='submitStatus'>{{form.button_name}}</button>
</view>
</form>
<lvv-popup position="bottom" ref="lvvpopref" class="lvvpopref">
<!-- 多规格商品弹出 -->
<block v-if="showSpecs">
<view class="modal-body" data-statu="closespecs" catchtouchmove="move">
<view class='specs-goods-t'>
<view class='specs-goods-information'>
<text class='specs-goods-name'>{{goodsInfoName}}</text>
<text class='specs-goods-price'>¥{{goodsInfoPrint}}</text>
</view>
<view class='close-btn' @click="closeModal" :data-goods="select_goods_id" :data-id="select_id" data-type="100"
data-statu="closespecs">
<image src='/static/image/close.png'></image>
</view>
</view>
<scroll-view class='specs-goods-c' scroll-y="true">
<view class="color" v-for="(value,key) in goodsSpesDesc" :key="key">
<text class='salespromotion-service-name'>{{key}}</text>
<view class='salespromotion-service-b'>
<block v-for="(i,item_index) in value" :key="item_index">
<view v-if="i.is_default" class='pitch-on'>{{i.name}}</view>
<view v-else-if="i.product_id != 0" :class='i.is_default ? "pitch-on" : ""' :data-key="i.product_id" :data-id="i.name"
@click="selectSku">{{i.name}}</view>
<view v-else class='nothing'>{{i.name}}</view>
</block>
</view>
</view>
<!-- 库存 -->
<view class='number'>
<text class='salespromotion-service-name'>数量</text>
<view class="stepper">
<text :class="goodsNums==0?'disabled':'normal'" @click="bindMinus">-</text>
<input type="number" @change="bindManual" v-model="goodsNums" />
<text :class="goodsNums==goodsInfoNumber?'disabled':'normal'" @click="bindPlus">+</text>
</view>
</view>
</scroll-view>
<view class='detail-footer'>
<!-- 点击加购物车/购买 -->
<view class='detail-footer-right determine-next' v-if="status">
<!-- <view @click='goodsAddCart' class='determine'>确定</view> -->
<view @click='goodsAddCart' class='next'>下一步</view>
</view>
<view class='detail-footer-right' v-else>
<view class='stockno'>该商品已售罄</view>
</view>
</view>
</view>
</block>
</lvv-popup>
</view>
</template>
<script>
import areaPicker from '@/components/area-picker/areaPicker.vue'
import lvvPopup from '@/components/lvv-popup/lvv-popup.vue'
export default {
name: '',
components: {
areaPicker,
lvvPopup
},
props: {},
data() {
return {
formId: '',
form: {
head_type: 1,
head_type_value_url: '',
},
showPage: true,
hiddenForm: true,
indicatorDots: true, //商品轮播图底部圆点
autoplay: true, //商品轮播图自动播放
interval: 3000, //商品轮播图切换间隔
duration: 500, //商品轮播图切换动画时间
slideImg: [], //幻灯片广告数据
minusStatus: 'disabled', // 使用data数据对象设置样式名
animationData: {},
opacityData: {},
hide: 'animathide',
formMoney: 0.0, //表单金额
region: ['河南省', '郑州市', '中原区'],
areaId: 410102,
pickerValue: '',
defaultIndex: [0, 0, 0],
pics: [], //图片
goodsNums: 0,
cart: [],
currentKey: 0, //当前下单的商品的Key
currentGoodsId: 0, //当前选中的商品ID
goodsTotalMoney: '0.00', //商品总额
originForm: [], //原始表单
paymentType: '', //支付类型
payment_type: '', //表单付款码||表单订单
/** 商品信息*/
goodsSpesDesc: '',
productId: '',
status: '',
goodsInfoName: '',
goodsInfoPrint: '',
goodsInfoNumber: '',
select_goods_id: '',
select_id: '',
showSpecs: false,
submitStatus: false, //按钮状态
}
},
onLoad(options) {
var id = options.id
if (!id) {
this.$common.errorToShow('路径错误')
return false
}
this.formId = id
this.$db.set('formId', id)
},
onShow() {
this.getFormDetail()
},
methods: {
// 省市区联动初始化
showThreePicker() {
this.pickerValue =
this.region[0] + ' ' + this.region[1] + ' ' + this.region[2]
this.$refs.areaPicker[0].showPicker()
},
onConfirm(e) {
let province_name = e[0].name
let city_name = e[1].name
let county_name = e[2].name
this.pickerValue = e[0].name + ' ' + e[1].name + ' ' + e[2].name
let data = {
province_name: province_name,
city_name: city_name,
county_name: county_name
}
let regionName = [province_name, city_name, county_name]
this.$api.getAreaId(data, res => {
if (res.status) {
this.areaId = res.data
} else {
uni.showModal({
title: '提示',
content: '地区选择出现问题,请重新选择地区',
showCancel: false
})
}
})
},
getFormDetail() {
var data = {
id: this.formId,
token: this.$db.get('userToken')
}
var that = this
this.$api.getFormDetial(data, res => {
if (res.status) {
this.form = res.data
this.originForm = res.data
if (res.data.type == '1' || res.data.type == '2') {
if (res.data.type == '1') {
//订单
that.payment_type = this.$config.paymentType.form_order
} else if (res.data.type == '2') {
//付款码
that.payment_type = this.$config.paymentType.form_pay
}
}
//设置title名称
uni.setNavigationBarTitle({
title: res.data.name
})
} else {
this.showPage = false;
if (typeof res.data.need_login == 'undefined') {
uni.showModal({
title: '提示',
content: '表单已过期,请扫描新的二维码',
showCancel: false,
success: function(res) {
if (res.confirm) {
uni.switchTab({
url: '../../index/index'
})
}
}
})
} else {
//去登录
this.$store.commit({
type: 'redirect',
page: '/pages/form/detail/form?id=' + this.formId
})
this.$common.jumpToLogin();
}
}
})
},
// 选择日期
bindDateChange(e, item) {
item.default_value = e.target.value
},
// 选择时间
bindTimeChange(e, item) {
item.default_value = e.target.value
},
// 单选
radioChange(e, item) {
item.default_value = e.detail.value
},
// 多选
checkboxChange(e, item) {
var values = e.detail.value
for (var i = 0; i < item.checbox_value.length; ++i) {
const checkbox_item = item.checbox_value[i]
if (values.includes(checkbox_item.value)) {
this.$set(checkbox_item, 'checked', true)
} else {
this.$set(checkbox_item, 'checked', false)
}
}
},
//商品减一
bindMinus() {
if (this.goodsNums > 1) {
this.goodsNums--
} else {
this.goodsNums = 0
}
},
//商品加一
bindPlus() {
if (this.goodsNums >= this.goodsInfoNumber) {
this.goodsNums = this.goodsInfoNumber
} else {
this.goodsNums++
}
},
/* 输入框事件 */
bindManual(e) {
this.num = e.detail.value
},
//选择位置
chooseLocation(e, item) {
wx.chooseLocation({
success(e) {
item.default_value = e.latitude + ',' + e.longitude
},
fail(e) {
wx.getSetting({
success(res) {
if (!res.authSetting['scope.userLocation']) {
wx.openSetting()
}
}
})
}
})
},
pic_choose(e, item, index) {
var that = this
this.$api.uploadImage(5, res => {
if (res.status) {
if (!item.pics) {
item.pics = []
}
item.pics.push({
src: res.data.url.replace(/\\/g, '/'),
image_id: res.data.image_id
})
this.$set(this.form.items, index, item)
that.$common.successToShow(res.msg)
} else {
that.$common.errorToShow(res.msg)
}
})
},
//删除图片
pic_del(item, index, i) {
item.pics.splice(i, 1)
this.$set(this.form.items, index, item)
},
//表单提交
formSubmit(e) {
var that = this
var data = e.detail.value
//订单时需要合并购物车信息
if (this.form.type == 1) {
if (this.cart.length < 1) {
this.$common.errorToShow('请先选择商品')
return true
}
var tempArray = []
this.cart.forEach(function(item, index, input) {
tempArray[item.key + '_' + index] = item
})
data = Object.assign(data, tempArray)
}
let userToken = this.$db.get('userToken')
let obj = {
data,
id: this.form.id,
token: userToken
}
this.submitStatus = true;
this.$api.addSubmitForm(obj, res => {
this.submitStatus = false;
if (res.status) {
//表单类型判断是否需要支付,支付金额多少
if (that.form.type == '1' || that.form.type == '2') {
that.$common.successToShow(res.msg);
//跳转首页
setTimeout(function() {
//出来支付按钮
that.$common.redirectTo('/pages/goods/payment/index?form_id=' + res.data.id + '&type=' + that.payment_type +
'&recharge=' + res.data.money)
}, 1000)
} else {
that.formReset()
that.$common.successToShow(res.msg)
//跳转首页
setTimeout(function() {
wx.switchTab({
url: '../../index/index'
})
}, 1500)
}
} else {
this.$common.errorToShow(res.msg);
}
})
},
//表单清空
formReset(e) {
this.$db.set('formId', '')
this.cart = [] //初始化,刷新当前页面
this.form = this.originForm
},
closeModal() {
this.$refs.lvvpopref.close()
},
//选择规格弹出
specifications(e, item) {
this.$refs.lvvpopref.show()
this.showSpecs = true
this.select_id = e.target.dataset.id
this.select_goods_id = e.target.dataset.goods
this.currentKey = e.target.dataset.id //当前选中的key
this.currentGoodsId = e.target.dataset.goods //当前选中的商品ID
this.getGoodsInfo(item)
},
//获取商品详情
getGoodsInfo(item) {
let goods = item.goods
this.goodsSpesDesc = this.getSpes(goods.product)
this.productId = goods.product.id
this.goodsInfoName = goods.product.name
this.goodsInfoPrint = goods.product.price
this.goodsInfoNumber = goods.product.stock
this.goodsNums = this.getNumsByKey(this.currentKey, goods.product.id)
this.status = goods.product.stock < 1 ? false : true
},
/*获取key的数量 */
getNumsByKey(key, productId) {
var that = this
if (that.cart.length < 1) {
return 0
} else {
for (var i = 0; i < that.cart.length; i++) {
if (that.cart[i].key == key && that.cart[i].productId == productId) {
return that.cart[i].nums
}
}
return 0
}
},
//加入购物车
goodsAddCart: function() {
var productId = this.productId
var currentKey = this.currentKey
if (this.cart.length < 1) {
this.cart.push({
key: currentKey,
productId: productId,
goodsId: this.select_goods_id,
nums: this.goodsNums,
price: this.goodsInfoPrint
})
} else {
var isIn = false
for (var i = 0; i < this.cart.length; i++) {
if (
this.cart[i].key == currentKey &&
this.cart[i].productId == productId
) {
this.cart[i] = {
key: currentKey,
productId: productId,
goodsId: this.select_goods_id,
nums: this.goodsNums,
price: this.goodsInfoPrint
}
isIn = true
}
}
if (!isIn) {
this.cart.push({
key: currentKey,
productId: productId,
goodsId: this.select_goods_id,
nums: this.goodsNums,
price: this.goodsInfoPrint
})
}
}
this.showSpecs = false
this.$refs.lvvpopref.close()
this.getCartNums()
},
getCartNums() {
var items = this.form.items
var itemKey = ''
for (var i = 0, len = items.length; i < len; ++i) {
if (items[i].id == this.currentKey) {
itemKey = i
}
}
var that = this
if (this.form.items[itemKey].goods.id == this.currentGoodsId) {
if (this.form.items[itemKey].cart_count > 0) {
var cart_count = 0
var currentKey = this.currentKey
this.cart.forEach(function(item, index, input) {
if (item.key == currentKey) {
cart_count += item.nums
}
that.form.items[itemKey].cart_count = cart_count
})
} else {
this.form.items[itemKey].cart_count = this.goodsNums
}
} else {
this.form.items[itemKey].cart_count = this.goodsNums
}
this.getGoodsTotalMoney()
},
//获取商品总额
getGoodsTotalMoney() {
var that = this
var goodsTotalMoney = 0
this.cart.forEach(function(item, index, input) {
goodsTotalMoney += item.price * item.nums
})
this.goodsTotalMoney = this.$common.formatMoney(goodsTotalMoney, 2, '')
},
getSpes: function(product) {
if (!product.default_spes_desc) {
return []
}
return product.default_spes_desc
},
//获取规格信息
selectSku(e) {
var id = e.target.dataset.key
this.$api.getProductInfo({
id
}, res => {
if (res.status) {
this.goodsSpesDesc = this.getSpes(res.data)
this.productId = res.data.id
this.goodsInfoName = res.data.name
this.goodsInfoPrint = res.data.price
this.goodsInfoNumber = res.data.stock
this.goodsNums = this.getNumsByKey(this.currentKey, res.data.id)
this.status = res.data.stock < 1 ? false : true
}
})
}
},
//分享
onShareAppMessage() {
let myInviteCode = this.$db.get("userToken");
let ins = this.$common.shareParameterDecode('type=10&id=' + this.formId + '&invite=' + myInviteCode);
let path = '/pages/share/jump?scene=' + ins;
return {
title: this.form.name,
path: path
}
}
}
</script>
<style>
.content {
margin-bottom: 200rpx;
background-color: #eeeeee;
}
.sw,
.video {
height: 350rpx;
}
.banner,
.sw,
.video {
width: 100%;
/* height: 350rpx; */
background-color: #fff;
}
.banner image,
.sw swiper,
.sw swiper image,
.video video {
width: 100%;
height: 100%;
}
.plaintext {
padding: 20rpx 30rpx;
font-size: 30rpx;
color: #333;
background-color: #fff;
}
.goods {
/* margin: 20rpx 0; */
background-color: #fff;
}
.form-input-box-title {
/* padding: 20rpx 30rpx 0; */
font-size: 28rpx;
}
.goods-box-item {
overflow: hidden;
padding: 20rpx 30rpx 20rpx 0;
margin-left: 30rpx;
border-bottom: 2rpx solid #eeeeee;
}
.goods-box-item:nth-last-child(2) {
border: none;
}
.goods-img {
width: 150rpx;
height: 150rpx;
display: inline-block;
float: left;
}
.goods-right {
width: 520rpx;
display: inline-block;
float: left;
margin-left: 20rpx;
}
.goods-name {
font-size: 30rpx;
color: #333;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.goods-mid {
font-size: 24rpx;
color: #999;
}
.goods-buttom {
overflow: hidden;
position: relative;
height: 60rpx;
}
.goods-price {
font-size: 28rpx;
color: #eb0000;
display: inline-block;
}
.stepper {
width: 156rpx;
height: 48rpx;
border-radius: 6rpx;
margin: 0 auto;
display: inline-block;
overflow: hidden;
box-sizing: border-box;
float: right;
}
.stepper text {
width: 44rpx;
line-height: 42rpx;
text-align: center;
float: left;
box-sizing: border-box;
border: 2rpx solid #ccc;
}
.stepper input {
width: 64rpx;
height: 38rpx;
float: left;
text-align: center;
font-size: 28rpx;
display: inline-block;
box-sizing: border-box;
}
.stepper .normal {
color: black;
}
.stepper .disabled {
color: #ccc;
}
.choose-specs {
width: 136rpx;
height: 48rpx;
line-height: 46rpx;
border-radius: 50rpx;
margin: 0 auto;
text-align: center;
display: inline-block;
overflow: hidden;
box-sizing: border-box;
float: right;
font-size: 24rpx;
border: 2rpx solid #ccc;
position: relative;
top: 12rpx;
}
.goods-bottom {
border-top: 2rpx solid #eeeeee;
overflow: hidden;
padding: 20rpx 30rpx;
background-color: #fff;
}
.goods-total {
float: right;
color: #999;
font-size: 28rpx;
}
.goods-total-r {
color: #eb0000;
font-size: 30rpx;
}
.input-box {
margin: 20rpx 0;
background-color: #fff;
}
.form-input-box-item {
overflow: hidden;
padding: 20rpx 30rpx 20rpx 0;
margin-left: 30rpx;
border-bottom: 2rpx solid #eeeeee;
}
.ib-item-left {
display: inline-block;
min-width: 150rpx;
max-width: 600rpx;
font-size: 28rpx;
color: #333;
float: left;
padding: 10rpx 0;
}
.ib-item-right {
min-width: 600rpx;
max-width: 690rpx;
display: inline-block;
color: #666;
font-size: 28rpx;
float: left;
padding: 6rpx 0;
}
.ib-item-input {
color: #666;
font-size: 28rpx;
}
.margin-r {
margin-left: 40rpx;
}
.ib-item-input-c {
color: #999;
font-size: 28rpx;
}
.ib-item-label {
display: inline-block;
position: relative;
min-width: 150rpx;
margin-right: 20rpx;
}
.ib-item-label radio {
position: absolute;
opacity: 0;
width: 40rpx;
height: 40rpx;
}
.ib-item-label-text {
display: inline-block;
margin-left: 60rpx;
position: relative;
top: 2rpx;
}
.label-icon {
position: absolute;
top: 0;
}
.label-icon icon {
margin: 0;
}
.ib-item-mid {
padding-top: 4rpx;
margin: 0;
position: relative;
}
.ib-item-mid picker {
height: 40rpx;
}
.ib-item-mid .weui-select {
border: none;
height: 100%;
line-height: 48rpx;
min-height: 40rpx;
}
.ib-item-mid-text {
margin-left: 40rpx;
color: #999;
}
.icon-img {
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 32rpx;
height: 32rpx;
}
.icon-img-right {
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 32rpx;
height: 32rpx;
right: 0;
}
.form-multiple-rows .form-input-box-item {
border: none;
}
.f-m-r-item {
color: #666;
font-size: 28rpx;
margin-top: 16upx;
}
.f-m-r-item .ib-item-label {
display: block;
margin-bottom: 20rpx;
}
.f-m-r-item .ib-item-label:last-child {
margin-bottom: 0;
}
.various-spec-list {
overflow: hidden;
}
.various-spec-item {
padding: 10rpx 20rpx;
display: inline-block;
border: 2rpx solid #e2e2e2;
margin-right: 20rpx;
margin-bottom: 20rpx;
border-radius: 6rpx;
color: #666;
background-color: #f7f7f7;
min-width: 130rpx;
text-align: center;
}
.vAactive {
border: 2rpx solid #333;
color: #333;
}
.various-spec-list:last-child .various-spec-item {
margin-bottom: 0rpx;
}
.upload-img-list {
overflow: hidden;
}
.upload-img-hd {
position: relative;
width: 150rpx;
height: 150rpx;
border: 2rpx solid #e2e2e2;
background-color: #f7f7f7;
border-radius: 6rpx;
box-sizing: border-box;
float: left;
margin-left: 30rpx;
}
.upload-img-hd input {
position: absolute;
width: 100%;
height: 100%;
opacity: 0;
}
.upload-img-hd image {
width: 48rpx;
height: 48rpx;
position: relative;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.upload-img-bd {
/* width: 150rpx; */
/* height: 150rpx; */
float: left;
overflow: hidden;
}
.upload-img .upload-camera {
width: 100%;
height: 100%;
}
.upload-img {
width: 150rpx;
height: 150rpx;
position: relative;
float: left;
margin-right: 30rpx;
}
.upload-img:last-child {
margin-right: 0;
}
.del-img {
width: 36rpx !important;
height: 36rpx !important;
position: absolute;
right: 0;
top: 0;
z-index: 99;
}
.ib-item-textarea {
width: 100%;
height: 200rpx;
box-sizing: border-box;
border: 2rpx solid #e2e2e2;
background-color: #f7f7f7;
border-radius: 6rpx;
padding: 20rpx 30rpx;
}
.bottom-btn {
position: fixed;
bottom: 0;
width: 100%;
z-index: 95;
}
.bottom-btn button {
width: 100%;
height: 90rpx;
line-height: 90rpx;
margin: 0 auto;
background-color: #333;
color: #fff;
font-size: 32rpx;
border-radius: 0;
}
.bottom-btn button::after {
border-radius: 0;
}
.hidden {
display: none;
}
.checkout-list {
overflow: hidden;
}
.checkout-item {
display: inline-block;
float: left;
}
.checkout-item-c {
padding: 4rpx 14rpx;
border: 2rpx solid #ccc;
margin-right: 10rpx;
border-radius: 6rpx;
color: #888;
}
.checkout-item-c checkbox {
display: none;
}
.black {
background-color: rgb(55, 55, 55);
color: #fff;
border: 2rpx solid rgb(55, 55, 55);
}
/*支付按钮样式*/
.content-bot {
margin-top: 18rpx;
}
.content-bot>view {
padding: 16rpx 0;
margin-bottom: 2rpx;
position: relative;
background-color: #fff;
height: 75rpx;
}
.content-bot>view button {
background-color: #fff;
width: 100%;
height: 100%;
padding: 0;
position: static;
text-align: left;
}
.content-bot>view button::after {
border: none;
}
.content-bot .left-img {
display: inline-block;
height: 82rpx;
width: 94rpx;
border-right: 2rpx solid #f4f4f4;
position: absolute;
left: 30rpx;
top: 50%;
transform: translateY(-50%);
}
.content-bot .left-img image {
width: 64rpx;
height: 64rpx;
position: relative;
top: 8rpx;
}
.content-bot-right {
display: inline-block;
margin-left: 150rpx;
position: relative;
top: 16rpx;
}
.modal-box {
position: fixed;
width: 100%;
height: 100%;
top: 0px;
background: rgba(0, 0, 0, 0.4);
overflow: hidden;
z-index: 1000;
}
.modal-body {
position: fixed;
bottom: 0;
background-color: #fff;
width: 100%;
z-index: 1001;
font-size: 28rpx;
}
.modal-payment .item {
height: 80rpx;
width: 100%;
line-height: 80rpx;
text-align: center;
}
.modal-payment .immediate-pay {
height: 80rpx;
line-height: 80rpx;
width: 100%;
text-align: center;
border: none;
border-radius: 0;
border-bottom: 2rpx solid #eee;
box-sizing: border-box;
background-color: #fff;
}
.modal-payment .immediate-pay::after {
border: none;
}
.specs-goods-t {
position: relative;
padding: 30rpx;
border-bottom: 2rpx solid #f3f3f3;
}
.specs-goods-information {
width: 520rpx;
display: inline-block;
}
.specs-goods-information .specs-goods-name {
width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
display: block;
font-size: 24rpx;
margin-bottom: 20rpx;
}
.specs-goods-information .specs-goods-price {
display: block;
color: #ff3b44;
font-size: 30rpx;
}
.close-btn {
width: 40rpx;
height: 40rpx;
border-radius: 50%;
display: inline-block;
position: absolute;
right: 30rpx;
}
.close-btn image {
width: 100%;
height: 100%;
}
.modal-body .detail-footer-right {
width: 100%;
}
.gray-text {
color: #a5a5a5;
font-size: 28rpx;
}
.salespromotion-service-name {
color: #a5a5a5;
margin-right: 26rpx;
}
.color .salespromotion-service-name {
float: left;
}
.salespromotion-service-body,
.salespromotion-service-body view {
display: inline-block;
}
.sales-promotion .salespromotion-service-body {
margin: auto;
}
.sales-promotion text.salespromotion-service-body {
background-color: #ff3b44;
color: #fff;
font-size: 18rpx;
margin-left: 0rpx;
border-radius: 10rpx;
height: 28rpx;
line-height: 28rpx;
padding: 0 10rpx;
}
.salespromotion-service-body view {
width: 170rpx;
height: 40rpx;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
position: relative;
left: -6rpx;
}
.salespromotion-service-body view:first-child {
margin-right: 8rpx;
}
.color-number {
font-size: 28rpx;
border-bottom: 14rpx solid #f3f3f3;
}
.color,
.specifications,
.number {
padding: 22rpx 25rpx;
border-bottom: 2rpx solid #f3f3f3;
overflow: hidden;
}
.color {
padding-bottom: 8rpx;
}
.color .salespromotion-service-b,
.specifications .salespromotion-service-b {
width: 600rpx;
display: inline-block;
float: left;
}
.color .salespromotion-service-b>view,
.specifications .salespromotion-service-b>view {
padding: 2rpx 20rpx;
display: inline-block;
text-align: center;
border: 2rpx solid #e0e0e0;
border-radius: 8rpx;
color: #666;
margin-right: 22rpx;
margin-bottom: 12rpx;
}
.pitch-on {
border: 2rpx solid #ff3b44;
background-color: #ff3b44;
color: #fff !important;
}
.nothing {
border: 2rpx dashed #e0e0e0 !important;
color: #c9c9c9 !important;
}
.specs-goods-c {
margin-bottom: 100rpx;
max-height: 432rpx;
}
.number {
padding: 22rpx 25rpx;
}
.number>text {
color: #999;
position: relative;
font-size: 28rpx;
}
.detail-footer {
overflow: hidden;
height: 100rpx;
position: fixed;
bottom: 0;
width: 750rpx;
text-align: center;
z-index: 1000;
}
.detail-footer-left {
width: 30%;
height: 100rpx;
font-size: 24rpx;
color: #666;
background-color: #f7f7f7;
padding-top: 10rpx;
box-sizing: border-box;
display: inline-block;
}
.detail-footer-left>view {
width: 50%;
box-sizing: border-box;
float: left;
display: inline-block;
}
.detail-footer-left>view image {
height: 36rpx;
width: 36rpx;
}
.detail-footer-left>view text {
display: block;
}
.detail-footer-right {
width: 70%;
display: inline-block;
height: 100rpx;
line-height: 100rpx;
float: right;
font-size: 28rpx;
color: #fff;
box-sizing: border-box;
}
.detail-footer-right>view {
width: 100%;
display: inline-block;
}
.modal-body .detail-footer-right {
width: 100%;
}
.detail-footer-right>view {
background-color: #333;
}
.order-num {
display: block;
min-width: 16rpx;
height: 28rpx;
line-height: 28rpx;
background-color: #ff3b44;
color: #fff;
font-size: 16rpx;
border-radius: 50rpx;
position: absolute;
right: 0rpx;
top: 0rpx;
padding: 0 6rpx;
text-align: center;
}
.uni-list-cell-pd {
/* width: 200upx; */
margin-right: 40upx;
}
.invoice-type-icon,
.invoice-type-c {
display: inline-block;
}
.lvvpopref {
z-index: 100;
}
</style>
goods
index
group.vue
<template>
<view class="content">
<view class="nav-back">
<view class="back-btn" @click="backBtn()">
<image class="icon" src="/static/image/back-black.png" mode=""></image>
</view>
</view>
<view class="content-top">
<!-- 轮播图 -->
<view class='swiper'>
<swiper class="swiper-c" :indicator-dots="swiper.indicatorDots" :autoplay="swiper.autoplay" :interval="swiper.interval"
:duration="swiper.duration">
<swiper-item class="have-none" v-for="(item, index) in goodsInfo.album" :key="index" @click="clickImg(item)">
<image class='' :src='item' mode="aspectFill"></image>
</swiper-item>
</swiper>
</view>
<!-- 轮播图end -->
<view class='cell-group'>
<!-- 倒计时 -->
<view class='price-salesvolume' v-if="lasttime.hour!==false">
<view class='commodity-price'>
<text class='current-price'>¥{{product.price}}</text>
<text class='cost-price' v-if="parseFloat(product.mktprice)>0">¥{{product.mktprice}}</text>
</view>
<view class='commodity-salesvolume'>
<text>已售{{goodsInfo.buy_count}}件/剩余{{product.stock}}件</text>
<text>累计销售{{goodsInfo.buy_count}}件</text>
</view>
<view class='commodity-time-img'></view>
<view class='commodity-time'>
<text>距结束仅剩</text>
<view class='commodity-day'>
<uni-countdown :show-day="false" :hour="lasttime.hour" :minute="lasttime.minute" :second="lasttime.second"></uni-countdown>
</view>
</view>
<!-- <view class='commodity-time'>
已结束
</view> -->
</view>
<!-- 倒计时end -->
<!-- 分享 -->
<view class='cell-item goods-details'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>
<view class="color-3 fsz28 cell-hd-title-view">
{{ product.name }}
</view>
<view v-if="goodsInfo.brief" class="color-9 fsz24 cell-hd-title-view">
{{ goodsInfo.brief }}
</view>
</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' @click="goShare()" src='/static/image/share.png'></image>
</view>
</view>
<!-- 分享end -->
<!-- 促销 -->
<view class='cell-item goods-title-item' v-if="promotion.length">
<view class='cell-item-hd'>
<view class='cell-hd-title'>促销</view>
</view>
<view class='cell-item-bd'>
<view class="romotion-tip">
<view class="romotion-tip-item" :class="item.type !== 2 ? 'bg-gray' : ''" v-for="(item, index) in promotion"
:key="index">
{{ item.name }}
</view>
</view>
</view>
</view>
<!-- 促销end -->
<!-- 规格 -->
<view class='cell-item goods-title-item' v-if="isSpes">
<view class='cell-item-hd'>
<view class='cell-hd-title'>规格</view>
</view>
<view class='cell-item-bd' @click="toshow()">
<text class='cell-bd-text'>{{ product.spes_desc }}</text>
</view>
</view>
<!-- 规格end -->
<!-- 说明 -->
<view class='cell-item goods-title-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>说明</view>
</view>
<view class='cell-item-bd'>
<view class="cell-bd-view">
<image class="goods-title-item-ic" src="/static/image/ic-dui.png" mode=""></image>
<text class="cell-bd-text">24小时内发货</text>
</view>
<view class="cell-bd-view">
<image class="goods-title-item-ic" src="/static/image/ic-dui.png" mode=""></image>
<text class="cell-bd-text">7天拆封无条件退货</text>
</view>
</view>
</view>
<!-- 说明end -->
</view>
<view class="goods-content">
<uni-segmented-control :current="current" :values="items" @clickItem="onClickItem" style-type="text" active-color="#333"></uni-segmented-control>
<view class="goods-content-c">
<view class="goods-detail" v-if="current === 0">
<jshopContent :content="goodsInfo.intro" v-if="goodsInfo.intro"></jshopContent>
</view>
<view class="goods-parameter" v-else-if="current === 1">
<view class='cell-group' v-if="goodsParams.length">
<view class='cell-item' v-for="(item, index) in goodsParams" :key="index">
<view class='cell-item-hd'>
<view class='cell-hd-title'>{{ item.name }}</view>
</view>
<view class='cell-item-bd'>
<text class='cell-bd-text'>{{ item.value }}</text>
</view>
</view>
<!-- <view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>保修政策</view>
</view>
<view class='cell-item-bd'>
<view class="cell-bd-view">
<text class="cell-bd-text">二十日内包修理或换货</text>
</view>
<view class="cell-bd-view">
<text class="cell-bd-text">一年内包修理</text>
</view>
</view>
</view> -->
</view>
</view>
<view class="goods-assess" v-else-if="current === 2">
<view v-if="goodsComments.list.length">
<view class="goods-assess-item" v-for="(item, index) in goodsComments.list" :key="index">
<view class='cell-group'>
<view class='cell-item goods-title-item'>
<view class='cell-item-hd'>
<image class='user-head-img' :src='item.user.avatar' mode="aspectFill"></image>
</view>
<view class='cell-item-bd'>
<view class="cell-bd-view">
<text class="cell-bd-text">{{ item.user.nickname }}</text>
<view class="cell-bd-text-right">
<uni-rate size="16" disabled="true" :value="item.score"></uni-rate>
</view>
</view>
<view class="cell-bd-view">
<text class="cell-bd-text color-9" style="margin-right: 16upx;">{{ item.ctime }}</text>
<text class="cell-bd-text color-9">{{ item.addon }}</text>
</view>
</view>
</view>
</view>
<view class="gai-body">
<view class="gai-body-text">
{{ item.content }}
</view>
<view class="gai-body-img" v-if="item.images_url.length">
<image :src="img" mode="aspectFill" v-for="(img, key) in item.images_url" :key="key" @click="clickImg(img)"></image>
</view>
</view>
</view>
<uni-load-more :status="goodsComments.loadStatus"></uni-load-more>
</view>
<view class="comment-none" v-else>
<image class="comment-none-img" src="/static/image/order.png" mode=""></image>
</view>
</view>
</view>
</view>
</view>
<lvv-popup position="bottom" ref="share">
<!-- #ifdef H5 -->
<shareByH5 :goodsId="goodsInfo.id" :shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief"
:shareHref="shareHref" @close="closeShare()"></shareByH5>
<!-- #endif -->
<!-- #ifdef MP-WEIXIN -->
<shareByWx :goodsId="goodsInfo.id" :shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief"
:shareHref="shareHref" @close="closeShare()"></shareByWx>
<!-- #endif -->
<!-- #ifdef MP-ALIPAY -->
<shareByAli :goodsId="goodsInfo.id" :shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief"
:shareHref="shareHref" @close="closeShare()"></shareByAli>
<!-- #endif -->
<!-- #ifdef APP-PLUS -->
<shareByApp :goodsId="goodsInfo.id" :shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief"
:shareHref="shareHref" @close="closeShare()"></shareByApp>
<!-- #endif -->
</lvv-popup>
<!-- 弹出层 -->
<lvv-popup position="bottom" ref="lvvpopref">
<view style="width: 100%;max-height: 804upx;background: #FFFFFF;position: absolute;left:0;bottom: 0;">
<view class="pop-c">
<view class="pop-t">
<view class='goods-img'>
<image :src='product.image_path' mode='aspectFill'></image>
</view>
<view class='goods-information'>
<view class='pop-goods-name'>{{ product.name }}</view>
<view class='pop-goods-price red-price'>¥ {{ product.price }}</view>
</view>
<view class='close-btn' @click="toclose()">
<image src='/static/image/close.png'></image>
</view>
</view>
<scroll-view class="pop-m" scroll-y="true" style="max-height: 560upx;">
<spec :spesData="product.default_spes_desc" ref="spec" @changeSpes="changeSpes"></spec>
<view class="goods-number">
<text class="pop-m-title">数量</text>
<view class="pop-m-bd-in">
<uni-number-box :min="minNums" :max="product.stock" :value="buyNum" @change="bindChange"></uni-number-box>
</view>
</view>
</scroll-view>
<view class="pop-b">
<!-- <button class='btn btn-square btn-g btn-half' @click="addToCart">加入购物车</button>
<button class='btn btn-square btn-b btn-half' @click="buyNow">立即购买</button> -->
<button class='btn btn-square btn-b btn-all' hover-class="btn-hover2" @click="buyNow()" v-if="product.stock">确定</button>
<button class='btn btn-square btn-g btn-all' v-else>已售罄</button>
</view>
</view>
</view>
</lvv-popup>
<!-- 弹出层end -->
<div id="qrCode" ref="qrCodeDiv"></div>
<!-- 底部按钮 -->
<view class="goods-bottom">
<view class="goods-bottom-ic" @click="collection">
<image class="icon" :src="isfav ? favLogo[1] : favLogo[0]" mode=""></image>
<view v-if="!isfav">收藏</view>
<view v-if="isfav">已收藏</view>
</view>
<view class="goods-bottom-ic" @click="redirectCart">
<view class="badge color-f" v-if="cartNums">{{ cartNums }}</view>
<image class="icon" src="/static/image/ic-me-car.png" mode=""></image>
<view>购物车</view>
</view>
<button class='btn btn-square btn-b tl' @click="toshow(2)" hover-class="btn-hover2">立即{{typeName}}</button>
</view>
<!-- 底部按钮end -->
<!-- 右边浮动球 -->
<!-- <view class="right-ball">
<view class="" @click="goIndex()">
<image class="icon" src="/static/image/tab-ic-hom-selected.png" mode=""></image>
</view>
</view> -->
<uni-fab :pattern="pattern" :content="content" :horizontal="horizontal" :vertical="vertical" :direction="direction"
@trigger="trigger"></uni-fab>
</view>
</template>
<script>
import uniSegmentedControl from "@/components/uni-segmented-control/uni-segmented-control.vue";
import lvvPopup from '@/components/lvv-popup/lvv-popup.vue';
import uniNumberBox from "@/components/uni-number-box/uni-number-box.vue";
import uniRate from "@/components/uni-rate/uni-rate.vue";
import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue';
import uniFab from '@/components/uni-fab/uni-fab.vue';
import {
get
} from '@/config/db.js';
import {
apiBaseUrl
} from '@/config/config.js'
import uniCountdown from "@/components/uni-countdown/uni-countdown.vue"
import spec from '@/components/spec/spec.vue'
// #ifdef H5
import shareByH5 from '@/components/share/shareByh5.vue'
// #endif
// #ifdef MP-WEIXIN
import shareByWx from '@/components/share/shareByWx.vue'
// #endif
// #ifdef MP-ALIPAY
import shareByAli from '@/components/share/shareByAli.vue'
// #endif
// #ifdef APP-PLUS
import shareByApp from '@/components/share/shareByApp.vue'
// #endif
import jshopContent from '@/components/jshop/jshop-content.vue'//视频和文本解析组件
export default {
components: {
uniSegmentedControl,
lvvPopup,
uniNumberBox,
uniRate,
uniLoadMore,
uniFab,
uniCountdown,
spec,
jshopContent,
// #ifdef H5
shareByH5,
// #endif
// #ifdef MP-WEIXIN
shareByWx,
// #endif
// #ifdef MP-ALIPAY
shareByAli,
// #endif
// #ifdef APP-PLUS
shareByApp,
// #endif
},
data() {
return {
myShareCode: '', //分享Code
swiper: {
indicatorDots: true,
autoplay: true,
interval: 3000,
duration: 800,
}, // 轮播图属性设置
items: ['图文详情', '商品参数', '买家评论'],
current: 0, // init tab位
goodsId: 0, // 商品id
groupId: 0, // 团购ID
goodsInfo: {}, // 商品详情
cartNums: 0, // 购物车数量
product: {}, // 规格详情
goodsParams: [], // 商品参数信息
goodsComments: {
loadStatus: 'more',
page: 1,
limit: 5,
list: []
}, // 商品评论信息
buyNum: 1, // 选定的购买数量
minBuyNum: 1, // 最小可购买数量
type: 1,
isfav: false, // 商品是否收藏
favLogo: [
'/static/image/ic-me-collect.png',
'/static/image/ic-me-collect2.png'
],
horizontal: 'right', //右下角弹出按钮
vertical: 'bottom',
direction: 'vertical',
pattern: {
color: '#7A7E83',
backgroundColor: '#fff',
selectedColor: '#007AFF',
buttonColor: "#FF7159"
},
content: [{
iconPath: '/static/image/tab-ic-hom-selected.png',
selectedIconPath: '/static/image/tab-ic-hom-unselected.png',
// text: '首页',
active: false,
url: '/pages/index/index'
},
{
iconPath: '/static/image/tab-ic-me-selected.png',
selectedIconPath: '/static/image/tab-ic-me-unselected.png',
// text: '个人中心',
active: false,
url: '/pages/member/index/index'
},
],
indicatorDots: false,
autoplay: false,
interval: 2000,
duration: 500,
lasttime: {
hour: false,
minute: 0,
second: 0
},
}
},
onLoad(e) {
this.goodsId = e.id;
this.groupId = e.group_id;
if (this.goodsId && this.groupId) {
this.getGoodsInfo();
this.getGoodsParams();
this.getGoodsComments();
} else {
this.$common.errorToShow('获取失败', () => {
uni.navigateBack({
delta: 1
});
});
}
// 获取购物车数量
this.getCartNums();
this.getMyShareCode();
},
computed: {
// 规格切换计算规格商品的 可购买数量
minNums() {
return this.product.stock > this.minBuyNum ? this.minBuyNum : this.product.stock;
},
// 判断商品是否是多规格商品 (为了兼容小程序 只能写在计算属性里面了)
isSpes() {
if (this.product.hasOwnProperty('default_spes_desc') && Object.keys(this.product.default_spes_desc).length) {
return true;
} else {
return false;
}
},
// 优惠信息重新组装
promotion() {
let arr = [];
if (this.product.promotion_list) {
for (let k in this.product.promotion_list) {
arr.push(this.product.promotion_list[k]);
}
}
return arr;
},
typeName() {
return this.goodsInfo.group_type == 3 ? '团购' : '秒杀';
},
shareHref() {
let pages = getCurrentPages()
let page = pages[pages.length - 1]
// #ifdef H5 || MP-WEIXIN || APP-PLUS || APP-PLUS-NVUE
return apiBaseUrl + 'wap/' + page.route + '?id=' + this.goodsId + '&group_id=' + this.groupId;
// #endif
// #ifdef MP-ALIPAY
return apiBaseUrl + 'wap/' + page.__proto__.route + '?id=' + this.goodsId + '&group_id=' + this.groupId;
// #endif
}
},
onReachBottom() {
if (this.current === 2 && this.goodsComments.loadStatus === 'more') {
this.getGoodsComments();
}
},
methods: {
// 返回上一页
backBtn() {
uni.navigateBack({
delta: 1
});
},
getGoodsInfo() {
let data = {
id: this.goodsId,
group_id: this.groupId,
}
// 如果用户已经登录 要传用户token
let userToken = get('userToken');
if (userToken) {
data['token'] = userToken;
}
let _this = this;
this.$api.groupInfo(data, res => {
if (res.status) {
if (res.data.length < 1) {
this.$common.errorToShow('该商品不存在,请返回重新选择商品。', () => {
uni.navigateBack({
delta: 1
});
});
} else if (res.data.marketable != 1) {
this.$common.errorToShow('该商品已下架,请返回重新选择商品。', () => {
uni.navigateBack({
delta: 1
});
});
} else {
let info = res.data;
let products = res.data.product;
this.goodsInfo = info;
this.isfav = this.goodsInfo.isfav === 'true' ? true : false;
this.product = this.spesClassHandle(products);
let lasttime = res.data.lasttime;
_this.lasttime = lasttime;
// 判断如果登录用户添加商品浏览足迹
if (userToken) {
this.goodsBrowsing();
}
}
}
});
},
// 获取购物车数量
getCartNums() {
let userToken = this.$db.get("userToken");
if (userToken && userToken != '') {
// 获取购物车数量
this.$api.getCartNum({}, res => {
if (res.status) {
this.cartNums = res.data;
}
});
}
},
// 显示modal弹出框
toshow(type) {
this.type = type;
this.$refs.lvvpopref.show();
},
// 关闭modal弹出框
toclose() {
this.$refs.lvvpopref.close();
},
// 切换商品规格
changeSpes(obj) {
let index = obj.v;
let key = obj.k;
if (this.product.default_spes_desc[index][key].hasOwnProperty('product_id') && this.product.default_spes_desc[index]
[key].product_id) {
let data = {
'id': this.product.default_spes_desc[index][key].product_id
};
let userToken = this.$db.get("userToken");
if (userToken) {
data['token'] = userToken;
}
this.$api.getProductInfo(data, res => {
if (res.status == true) {
// 切换规格判断可购买数量
this.buyNum = res.data.stock > this.minBuyNum ? this.minBuyNum : res.data.stock;
this.product = this.spesClassHandle(res.data);
}
});
uni.showLoading({
title: '加载中'
});
setTimeout(function() {
uni.hideLoading();
}, 1000);
}
},
// 多规格样式统一处理
spesClassHandle(products) {
// 判断是否是多规格 (是否有默认规格)
if (products.hasOwnProperty('default_spes_desc')) {
let spes = products.default_spes_desc;
for (let key in spes) {
for (let i in spes[key]) {
if (spes[key][i].hasOwnProperty('is_default') && spes[key][i].is_default === true) {
this.$set(spes[key][i], 'cla', 'pop-m-item selected');
} else if (spes[key][i].hasOwnProperty('product_id') && spes[key][i].product_id) {
this.$set(spes[key][i], 'cla', 'pop-m-item not-selected');
} else {
this.$set(spes[key][i], 'cla', 'pop-m-item none');
}
}
}
products.default_spes_desc = spes;
}
return products;
},
// 购买数量加减操作
bindChange(val) {
this.buyNum = val;
},
// 商品收藏/取消
collection() {
let data = {
goods_id: this.goodsInfo.id
}
this.$api.goodsCollection(data, res => {
if (res.status) {
this.isfav = !this.isfav;
this.$common.successToShow(res.msg);
} else {
this.$common.errorToShow(res.msg);
}
})
},
// tab点击切换
onClickItem(index) {
if (this.current !== index) {
this.current = index;
}
},
// 获取商品参数信息
getGoodsParams() {
this.$api.goodsParams({
id: this.goodsId
}, res => {
if (res.status == true) {
this.goodsParams = res.data;
}
})
},
// 获取商品评论信息
getGoodsComments() {
let data = {
page: this.goodsComments.page,
limit: this.goodsComments.limit,
goods_id: this.goodsId
}
this.goodsComments.loadStatus = 'loading';
this.$api.goodsComment(data, res => {
if (res.status == true) {
let _list = res.data.list;
// 如果评论没有图片 在这块作处理否则控制台报错
_list.forEach(item => {
item.ctime = this.$common.timeToDate(item.ctime)
if (!item.hasOwnProperty('images_url')) {
this.$set(item, 'images_url', [])
}
});
this.goodsComments.list = [...this.goodsComments.list, ..._list];
// 根据count数量判断是否还有数据
if (res.data.count > this.goodsComments.list.length) {
this.goodsComments.loadStatus = 'more';
this.goodsComments.page++;
} else {
this.goodsComments.loadStatus = 'noMore';
}
} else {
this.$common.errorToShow(res.msg);
}
})
},
// 添加商品浏览足迹
goodsBrowsing() {
let data = {
goods_id: this.goodsInfo.id
}
this.$api.addGoodsBrowsing(data, res => {});
},
// 立即购买
buyNow() {
if (this.buyNum > 0) {
let data = {
product_id: this.product.id,
nums: this.buyNum,
order_type: 1,
}
this.$api.addCart(data, res => {
if (res.status) {
this.toclose();
let cartIds = res.data;
this.$common.navigateTo('/pages/goods/place-order/index?cart_ids=' + JSON.stringify(cartIds));
} else {
this.$common.errorToShow(res.msg);
}
})
}
},
// 拼团
Group() {
if (this.buyNum > 0) {
let data = {
product_id: this.product.id,
nums: this.buyNum,
order_type: this.type, // 区分购买和拼团
}
this.$api.addCart(data, res => {
if (res.status) {
this.toclose();
let cartIds = res.data;
this.$common.navigateTo('/pages/goods/place-order/index?cart_ids=' + JSON.stringify(cartIds));
}
})
}
},
// 购物车页面跳转
redirectCart() {
uni.switchTab({
url: '/pages/cart/index/index'
});
},
trigger(e) {
this.content[e.index].active = !e.item.active;
uni.switchTab({
url: e.item.url
})
},
// 跳转到h5分享页面
goShare() {
this.$refs.share.show();
},
closeShare() {
this.$refs.share.close();
},
// 图片点击放大
clickImg(imgs) {
// 预览图片
uni.previewImage({
urls: imgs.split()
});
},
getMyShareCode() {
let userToken = this.$db.get("userToken");
if (userToken && userToken != '') {
// 获取我的分享码
this.$api.shareCode({}, res => {
if (res.status) {
this.myShareCode = res.data ? res.data : '';
}
});
}
}
},
//分享
onShareAppMessage() {
let myInviteCode = this.myShareCode ? this.myShareCode : '';
let ins = this.$common.shareParameterDecode('type=6&id=' + this.goodsId + '&group_id=' + this.groupId + '&invite=' +
myInviteCode);
let path = '/pages/share/jump?scene=' + ins;
return {
title: this.goodsInfo.name,
// #ifdef MP-ALIPAY
desc: this.goodsInfo.brief,
// #endif
imageUrl: this.goodsInfo.album[0],
path: path
}
}
}
</script>
<style>
.swiper {
height: 750upx;
}
.goods-top {
border-bottom: 0;
}
.goods-top .goods-price {
font-size: 38upx;
}
.cost-price {
font-size: 28upx !important;
bottom: -10upx;
color: #999;
text-decoration: line-through;
}
.goods-top .cell-item-ft {
font-size: 20upx;
color: #666;
}
.goods-details {
padding-top: 16upx;
}
.goods-details .cell-hd-title {
width: 620upx;
}
.goods-details .cell-hd-title .cell-hd-title-view {
width: 100%;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
.goods-details .cell-hd-title .cell-hd-title-view:last-child {
margin-top: 10upx;
}
.goods-details .cell-item-ft {
top: 24upx;
}
.goods-title-item .cell-item-hd {
min-width: 60upx;
color: #666;
font-size: 24upx;
}
.goods-title-item .cell-item-bd {
color: #333;
font-size: 24upx;
}
.goods-title-item .cell-bd-text {
bottom: 0;
}
.cell-bd-view {
position: relative;
overflow: hidden;
}
.cell-bd-view:first-child {
margin-bottom: 8upx;
}
.goods-title-item-ic {
width: 22upx;
height: 22upx;
position: absolute;
top: 50%;
transform: translateY(-50%);
/* #ifdef MP-ALIPAY */
background-size: 100% 100%;
/* #endif */
}
.cell-bd-view .cell-bd-text {
margin-left: 30upx;
}
.goods-content {
margin-top: 26upx;
background-color: #fff;
padding: 26upx 0;
}
.goods-content-c {}
.goods-parameter {
padding: 10upx 26upx;
}
.goods-bottom,
.pop-b {
background-color: #fff;
position: fixed;
bottom: 0;
height: 90upx;
width: 100%;
overflow: hidden;
box-shadow: 0 0 20upx #ccc;
}
.goods-bottom button {
height: 100%;
width: 35%;
}
.goods-bottom-ic {
display: inline-block;
position: relative;
text-align: center;
height: 100%;
width: 15%;
float: left;
font-size: 22upx;
color: #666;
}
.goods-bottom-ic .icon {
position: relative;
top: 6upx;
/* left: -6upx; */
/* #ifdef MP-ALIPAY */
background-size: 100% 100%;
/* #endif */
}
.goods-bottom .btn-g {
color: #333;
background-color: #D9D9D9;
}
.goods-parameter .cell-item {
border-bottom: none;
margin-left: 0;
}
.goods-parameter .cell-item-hd {
color: #333;
font-size: 24upx;
}
.goods-parameter .cell-item-bd {
color: #999;
}
.goods-parameter .cell-item-bd .cell-bd-text {
bottom: 0;
}
.goods-parameter .cell-bd-text {
margin-left: 0;
}
.pop-t {
position: relative;
padding: 30upx 26upx;
border-bottom: 2upx solid #f3f3f3;
/* box-shadow: 0 0 20upx #ccc; */
}
.goods-img {
width: 160upx;
height: 160upx;
position: absolute;
top: -20upx;
background-color: #fff;
border-radius: 6upx;
border: 2upx solid #fff;
}
.goods-img image {
height: 100%;
width: 100%;
}
.goods-information {
width: 420upx;
display: inline-block;
margin-left: 180upx;
}
.pop-goods-name {
width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
display: block;
font-size: 24upx;
margin-bottom: 20upx;
}
.pop-goods-price {
font-size: 30upx;
}
.close-btn {
width: 40upx;
height: 40upx;
border-radius: 50%;
display: inline-block;
position: absolute;
right: 30upx;
}
.close-btn image {
width: 100%;
height: 100%;
}
.pop-m {
font-size: 28upx;
margin-bottom: 90upx;
}
.goods-specs,
.goods-number {
padding: 26upx;
border-top: 1px solid #f3f3f3;
}
.goods-specs:first-child {
border: none;
}
.pop-m-title {
margin-right: 10upx;
color: #666;
}
.pop-m-bd {
overflow: hidden;
margin-top: 10upx;
}
.pop-m-item {
display: inline-block;
float: left;
padding: 6upx 16upx;
background-color: #fff;
color: #333;
margin-right: 16upx;
margin-bottom: 10upx;
}
.selected {
border: 2upx solid #333;
background-color: #333;
color: #fff;
}
.not-selected {
border: 2upx solid #ccc;
}
.none {
border: 2upx dashed #ccc;
color: #888;
}
.pop-m-bd-in {
display: inline-block;
}
.badge {
top: 2upx;
left: 62upx;
}
.goods-assess .user-head-img {
width: 80upx;
height: 80upx;
border-radius: 50%;
}
.goods-assess .cell-item-bd {
padding-right: 0;
}
.goods-assess .cell-bd-text {
margin: 0;
}
.goods-assess .cell-bd-text.color-9 {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 440upx;
}
.gai-body {}
.gai-body-text {
font-size: 26upx;
color: #333;
padding: 0 26upx;
word-wrap: break-word;
}
.gai-body-img {
overflow: hidden;
padding: 20upx 26upx;
}
.gai-body-img image {
width: 220upx;
height: 220upx;
float: left;
margin-right: 19upx;
margin-bottom: 18upx;
}
.gai-body-img image:nth-child(3n) {
margin-right: 0;
}
.redstar {
width: 24rpx;
height: 24rpx;
padding: 2rpx;
}
.mask-share-wechat {
display: inline-block;
background-color: #fff;
padding: 0;
}
.mask-share-wechat:after {
border: none;
}
.right-ball {
position: fixed;
right: 30upx;
bottom: 300upx;
z-index: 999;
text-align: center;
padding: 14upx 0;
/* line-height: 80upx; */
width: 80upx;
height: 80upx;
font-size: 24upx;
color: #fff;
background-color: rgba(0, 0, 0, .5);
border-radius: 50%;
}
.share-pop {
height: 300upx;
width: 100%;
display: flex;
}
.share-item {
flex: 1;
text-align: center;
font-size: 26upx;
color: #333;
padding: 20upx 0;
}
/* .share-item image{
width: 120upx;
height: 120upx;
} */
.comment-none {
text-align: center;
padding: 200upx 0;
}
.comment-none-img {
width: 274upx;
height: 274upx;
}
.price-salesvolume {
width: 100%;
padding: 0 0 0 26upx;
overflow: hidden;
color: #A5A5A5;
background-color: rgb(252, 226, 80);
position: relative;
}
.commodity-price {
width: 224upx;
display: inline-block;
float: left;
}
.current-price {
font-size: 40upx;
color: #FF7159;
display: block;
line-height: 1.5;
}
.cost-price {
font-size: 26upx;
text-decoration: line-through;
/* margin-left: 8rpx; */
display: block;
}
.commodity-salesvolume {
width: 240upx;
display: inline-block;
font-size: 22upx;
float: left;
padding: 16upx 0;
}
.commodity-salesvolume>text {
display: block;
}
.commodity-time-img {
display: block;
width: 0;
height: 0;
border-width: 56upx 28upx 56upx 0;
border-style: solid;
border-color: transparent #FF7159 transparent transparent;
/*透明 黄 透明 透明 */
position: absolute;
top: 0px;
left: 462upx;
}
.commodity-time {
display: inline-block;
width: 260upx;
text-align: center;
font-size: 24upx;
background-color: #FF7159;
padding: 16upx 0 18upx;
color: #FF7159;
}
.commodity-time>text {
color: rgb(252, 226, 80);
}
.nav-back {
width: 100%;
height: 44px;
/* #ifndef MP-WEIXIN */
padding: 12px 12px 0;
/* #endif */
/* #ifdef MP-WEIXIN */
padding: 26px 12px 0;
/* #endif */
position: fixed;
top: 0;
background-color: rgba(255, 255, 255, 0);
z-index: 98;
}
.back-btn {
height: 32px;
width: 32px;
border-radius: 50%;
background-color: rgba(255, 255, 255, 0.8);
}
.back-btn .icon {
height: 20px;
width: 20px;
position: relative;
top: 50%;
left: 46%;
transform: translate(-50%, -50%);
}
.commodity-day>text {
display: inline-block;
background-color: rgb(255, 212, 176);
color: rgb(255, 115, 0);
padding: 0 6upx;
border-radius: 6upx;
}
.tl {
width: 70% !important;
}
.group-swiper {
/* padding: 20upx 26upx; */
}
.group-swiper-c {
height: 242upx;
}
.group-swiper-c .swiper-item .cell-item {
height: 50%;
}
.group-swiper-c .swiper-item .cell-item .user-head-img {
width: 80upx;
height: 80upx;
border-radius: 50%;
}
.group-swiper-c .swiper-item .cell-item .cell-hd-title {
position: absolute;
top: 50%;
left: 100upx;
transform: translateY(-50%);
max-width: 260upx;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.group-swiper-c .swiper-item .cell-item .cell-item-bd {
min-width: 150upx;
max-width: 150upx
}
.group-swiper-c .swiper-item .cell-item .cell-item-ft .btn {
font-size: 26upx;
color: #fff;
background-color: #FF7159;
/* padding: 0; */
text-align: center;
}
</style>
index.vue
<template>
<view class="content">
<view class="nav-back">
<view class="back-btn" @click="backBtn()">
<image class="icon" src="/static/image/back-black.png" mode=""></image>
</view>
</view>
<view class="content-top">
<!-- 轮播图 -->
<view class='swiper'>
<swiper class="swiper-c" :indicator-dots="swiper.indicatorDots" :autoplay="swiper.autoplay" :interval="swiper.interval"
:duration="swiper.duration">
<swiper-item class="have-none" v-for="(item, index) in goodsInfo.album" :key="index" @click="clickImg(item)">
<image class='' :src='item' mode="aspectFill"></image>
</swiper-item>
</swiper>
</view>
<!-- 轮播图end -->
<view class='cell-group'>
<view class='cell-item goods-top'>
<view class='cell-item-hd'>
<view class='cell-hd-title goods-price red-price'>¥{{ product.price }}</view>
<view class='cell-hd-title goods-price cost-price' v-if="parseFloat(product.mktprice)>0">¥{{ product.mktprice }}</view>
</view>
<view class='cell-item-ft'>
<text>{{ goodsInfo.buy_count }} 人已购买</text>
</view>
</view>
<view class='cell-item goods-details'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>
<view class="color-3 fsz28 cell-hd-title-view">
{{ product.name }}
</view>
<text v-if="goodsInfo.brief" class="color-9 fsz24 ">
{{ goodsInfo.brief }}
</text>
</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' @click="goShare()" src='/static/image/share.png'></image>
</view>
</view>
<!-- 促销 -->
<view class='cell-item goods-title-item' v-if="promotion.length">
<view class='cell-item-hd'>
<view class='cell-hd-title'>促销</view>
</view>
<view class='cell-item-bd'>
<view class="romotion-tip">
<view class="romotion-tip-item" :class="item.type !== 2 ? 'bg-gray' : ''" v-for="(item, index) in promotion"
:key="index">
{{ item.name }}
</view>
</view>
</view>
</view>
<!-- 促销end -->
<!-- 规格 -->
<view class='cell-item goods-title-item' v-if="isSpes">
<view class='cell-item-hd'>
<view class='cell-hd-title'>规格</view>
</view>
<view class='cell-item-bd' @click="toshow()">
<text class='cell-bd-text'>{{ product.spes_desc }}</text>
</view>
</view>
<!-- 规格end -->
<view class='cell-item goods-title-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>说明</view>
</view>
<view class='cell-item-bd'>
<view class="cell-bd-view">
<image class="goods-title-item-ic" src="/static/image/ic-dui.png" mode=""></image>
<text class="cell-bd-text">24小时内发货</text>
</view>
<view class="cell-bd-view">
<image class="goods-title-item-ic" src="/static/image/ic-dui.png" mode=""></image>
<text class="cell-bd-text">7天拆封无条件退货</text>
</view>
</view>
</view>
</view>
<view class="goods-content">
<uni-segmented-control :current="current" :values="items" @clickItem="onClickItem" style-type="text" active-color="#333"></uni-segmented-control>
<view class="goods-content-c">
<view class="goods-detail" v-show="current === 0">
<jshopContent :content="goodsInfo.intro" v-if="goodsInfo.intro"></jshopContent>
</view>
<view class="goods-parameter" v-show="current === 1">
<view class='cell-group' v-if="goodsParams.length">
<view class='cell-item' v-for="(item, index) in goodsParams" :key="index">
<view class='cell-item-hd'>
<view class='cell-hd-title'>{{ item.name }}</view>
</view>
<view class='cell-item-bd'>
<text class='cell-bd-text'>{{ item.value }}</text>
</view>
</view>
<!-- <view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>保修政策</view>
</view>
<view class='cell-item-bd'>
<view class="cell-bd-view">
<text class="cell-bd-text">二十日内包修理或换货</text>
</view>
<view class="cell-bd-view">
<text class="cell-bd-text">一年内包修理</text>
</view>
</view>
</view> -->
</view>
</view>
<view class="goods-assess" v-show="current === 2">
<view v-if="goodsComments.list.length">
<view class="goods-assess-item" v-for="(item, index) in goodsComments.list" :key="index">
<view class='cell-group'>
<view class='cell-item goods-title-item'>
<view class='cell-item-hd'>
<image class='user-head-img' :src='item.user.avatar' mode="aspectFill"></image>
</view>
<view class='cell-item-bd'>
<view class="cell-bd-view">
<text class="cell-bd-text">{{ (item.user.nickname && item.user.nickname != '')?item.user.nickname:item.user.mobile }}</text>
<view class="cell-bd-text-right">
<uni-rate size="16" disabled="true" :value="item.score"></uni-rate>
</view>
</view>
<view class="cell-bd-view">
<text class="cell-bd-text color-9" style="margin-right: 16upx;">{{ item.ctime }}</text>
<text class="cell-bd-text color-9">{{ item.addon }}</text>
</view>
</view>
</view>
</view>
<view class="gai-body">
<view class="gai-body-text">
{{ item.content }}
</view>
<view class="gai-body-img" v-if="item.images_url.length">
<image :src="img" mode="aspectFill" v-for="(img, key) in item.images_url" :key="key" @click="clickImg(img)"></image>
</view>
<view class="seller-content" v-if="item.seller_content">
<view class="seller-content-top">
<image class="seller-content-img" src="/static/image/seller-content.png"></image>掌柜回复
</view>
{{item.seller_content}}
</view>
</view>
</view>
<uni-load-more :status="goodsComments.loadStatus"></uni-load-more>
</view>
<view class="comment-none" v-else>
<image class="comment-none-img" src="/static/image/order.png" mode=""></image>
</view>
</view>
</view>
</view>
</view>
<lvv-popup position="bottom" ref="share">
<!-- #ifdef H5 -->
<shareByH5 :goodsId="goodsInfo.id" :shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief"
:shareHref="shareHref" @close="closeShare()"></shareByH5>
<!-- #endif -->
<!-- #ifdef MP-WEIXIN -->
<shareByWx :goodsId="goodsInfo.id" :shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief"
:shareHref="shareHref" @close="closeShare()"></shareByWx>
<!-- #endif -->
<!-- #ifdef MP-ALIPAY -->
<shareByAli :goodsId="goodsInfo.id" :shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief"
:shareHref="shareHref" @close="closeShare()"></shareByAli>
<!-- #endif -->
<!-- #ifdef APP-PLUS -->
<shareByApp :goodsId="goodsInfo.id" :shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief"
:shareHref="shareHref" @close="closeShare()"></shareByApp>
<!-- #endif -->
</lvv-popup>
<!-- 弹出层 -->
<lvv-popup position="bottom" ref="lvvpopref">
<view style="width: 100%;max-height: 804upx;background: #FFFFFF;position: absolute;left:0;bottom: 0;">
<view class="pop-c">
<view class="pop-t">
<view class='goods-img'>
<image :src='product.image_path' mode='aspectFill'></image>
</view>
<view class='goods-information'>
<view class='pop-goods-name'>{{ product.name }}</view>
<view class='pop-goods-price red-price'>¥ {{ product.price }}</view>
</view>
<view class='close-btn' @click="toclose()">
<image src='/static/image/close.png'></image>
</view>
</view>
<scroll-view class="pop-m" scroll-y="true" style="max-height: 560upx;">
<spec :spesData="product.default_spes_desc" ref="spec" @changeSpes="changeSpes"></spec>
<view class="goods-number">
<text class="pop-m-title">数量</text>
<view class="pop-m-bd-in">
<uni-number-box :min="minNums" :max="product.stock" :value="buyNum" @change="bindChange"></uni-number-box>
</view>
</view>
</scroll-view>
<view class="pop-b">
<!-- <button class='btn btn-square btn-g btn-half' @click="addToCart">加入购物车</button>
<button class='btn btn-square btn-b btn-half' @click="buyNow">立即购买</button> -->
<button class='btn btn-square btn-b btn-all' hover-class="btn-hover2" @click="clickHandle()" :disabled='submitStatus'
:loading='submitStatus' v-if="product.stock">确定</button>
<button class='btn btn-square btn-g btn-all' v-else>已售罄</button>
</view>
</view>
</view>
</lvv-popup>
<!-- 弹出层end -->
<div id="qrCode" ref="qrCodeDiv"></div>
<!-- 底部按钮 -->
<view class="goods-bottom">
<view class="goods-bottom-ic" @click="collection">
<image class="icon" :src="isfav ? favLogo[1] : favLogo[0]" mode=""></image>
<view v-if="!isfav">收藏</view>
<view v-if="isfav">已收藏</view>
</view>
<view class="goods-bottom-ic" @click="redirectCart">
<view class="badge color-f" v-if="cartNums">{{ cartNums }}</view>
<image class="icon" src="/static/image/ic-me-car.png" mode=""></image>
<view>购物车</view>
</view>
<button class='btn btn-square btn-g' @click="toshow(1)" hover-class="btn-hover2">加入购物车</button>
<button class='btn btn-square btn-b' @click="toshow(2)" hover-class="btn-hover2">立即购买</button>
</view>
<!-- 底部按钮end -->
<!-- 右边浮动球 -->
<!-- <view class="right-ball">
<view class="" @click="goIndex()">
<image class="icon" src="/static/image/tab-ic-hom-selected.png" mode=""></image>
</view>
</view> -->
<uni-fab :pattern="pattern" :content="content" :horizontal="horizontal" :vertical="vertical" :direction="direction"
@trigger="trigger"></uni-fab>
</view>
</template>
<script>
import uniSegmentedControl from "@/components/uni-segmented-control/uni-segmented-control.vue";
import lvvPopup from '@/components/lvv-popup/lvv-popup.vue';
import uniNumberBox from "@/components/uni-number-box/uni-number-box.vue";
import uniRate from "@/components/uni-rate/uni-rate.vue";
import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue';
import uniFab from '@/components/uni-fab/uni-fab.vue';
import {
get
} from '@/config/db.js';
import {
apiBaseUrl
} from '@/config/config.js'
import spec from '@/components/spec/spec.vue'
// #ifdef H5
import shareByH5 from '@/components/share/shareByh5.vue'
// #endif
// #ifdef MP-WEIXIN
import shareByWx from '@/components/share/shareByWx.vue'
// #endif
// #ifdef MP-ALIPAY
import shareByAli from '@/components/share/shareByAli.vue'
// #endif
// #ifdef APP-PLUS
import shareByApp from '@/components/share/shareByApp.vue'
// #endif
import jshopContent from '@/components/jshop/jshop-content.vue'//视频和文本解析组件
export default {
components: {
uniSegmentedControl,
lvvPopup,
uniNumberBox,
uniRate,
uniLoadMore,
uniFab,
spec,
jshopContent,
// #ifdef H5
shareByH5,
// #endif
// #ifdef MP-WEIXIN
shareByWx,
// #endif
// #ifdef MP-ALIPAY
shareByAli,
// #endif
// #ifdef APP-PLUS
shareByApp,
// #endif
},
data() {
return {
myShareCode: '', //分享Code
swiper: {
indicatorDots: true,
autoplay: true,
interval: 3000,
duration: 800,
}, // 轮播图属性设置
items: ['图文详情', '商品参数', '买家评论'],
current: 0, // init tab位
goodsId: 0, // 商品id
goodsInfo: {}, // 商品详情
cartNums: 0, // 购物车数量
product: {}, // 规格详情
goodsParams: [], // 商品参数信息
goodsComments: {
loadStatus: 'more',
page: 1,
limit: 5,
list: []
}, // 商品评论信息
buyNum: 1, // 选定的购买数量
minBuyNum: 1, // 最小可购买数量
type: 2, // 1加入购物车 2购买
isfav: false, // 商品是否收藏
favLogo: [
'/static/image/ic-me-collect.png',
'/static/image/ic-me-collect2.png'
],
horizontal: 'right', //右下角弹出按钮
vertical: 'bottom',
direction: 'vertical',
pattern: {
color: '#7A7E83',
backgroundColor: '#fff',
selectedColor: '#007AFF',
buttonColor: "#FF7159"
},
content: [{
iconPath: '/static/image/tab-ic-hom-selected.png',
selectedIconPath: '/static/image/tab-ic-hom-unselected.png',
// text: '首页',
active: false,
url: '/pages/index/index'
},
{
iconPath: '/static/image/tab-ic-me-selected.png',
selectedIconPath: '/static/image/tab-ic-me-unselected.png',
// text: '个人中心',
active: false,
url: '/pages/member/index/index'
}
],
submitStatus: false
}
},
onLoad(options) {
//获取商品ID
if (options.id != '') {
this.goodsId = options.id;
}
if (this.goodsId) {
this.getGoodsDetail();
this.getGoodsParams();
this.getGoodsComments();
} else {
this.$common.errorToShow('获取失败', () => {
uni.navigateBack({
delta: 1
});
});
}
// 获取购物车数量
this.getCartNums();
this.getMyShareCode();
},
onShow(){
this.submitStatus = false;
},
computed: {
// 规格切换计算规格商品的 可购买数量
minNums() {
return this.product.stock > this.minBuyNum ? this.minBuyNum : this.product.stock;
},
// 判断商品是否是多规格商品 (为了兼容小程序 只能写在计算属性里面了)
isSpes() {
if (this.product.hasOwnProperty('default_spes_desc') && Object.keys(this.product.default_spes_desc).length) {
return true;
} else {
return false;
}
},
// 优惠信息重新组装
promotion() {
let arr = [];
if (this.product.promotion_list) {
for (let k in this.product.promotion_list) {
arr.push(this.product.promotion_list[k]);
}
}
return arr;
},
shareHref() {
let pages = getCurrentPages()
let page = pages[pages.length - 1]
// #ifdef H5 || MP-WEIXIN || APP-PLUS || APP-PLUS-NVUE
return apiBaseUrl + 'wap/' + page.route + '?id=' + this.goodsId;
// #endif
// #ifdef MP-ALIPAY
return apiBaseUrl + 'wap/' + page.__proto__.route + '?id=' + this.goodsId;
// #endif
}
},
onReachBottom() {
if (this.current === 2 && this.goodsComments.loadStatus === 'more') {
this.getGoodsComments();
}
},
methods: {
// 返回上一页
backBtn() {
uni.navigateBack({
delta: 1
});
},
// 获取商品详情
getGoodsDetail() {
let data = {
id: this.goodsId
}
// 如果用户已经登录 要传用户token
let userToken = this.$db.get("userToken");
if (userToken) {
data['token'] = userToken;
}
this.$api.goodsDetail(data, res => {
if (res.status == true) {
let info = res.data;
let products = res.data.product;
//var htmlString = info.intro; //replace(/\\/g, "").replace(/<img/g, "<img style=\"display:none;\"")
//info.intro = htmlParser(htmlString);
this.goodsInfo = info;
this.isfav = this.goodsInfo.isfav === 'true' ? true : false;
this.product = this.spesClassHandle(products);
// 判断如果登录用户添加商品浏览足迹
if (userToken) {
this.goodsBrowsing();
}
} else {
this.$common.errorToShow(res.msg, () => {
uni.navigateBack({
delta: 1
});
})
}
})
},
// 获取购物车数量
getCartNums() {
let userToken = this.$db.get("userToken");
if (userToken && userToken != '') {
// 获取购物车数量
this.$api.getCartNum({}, res => {
if (res.status) {
this.cartNums = res.data;
}
})
}
},
// 显示modal弹出框
toshow(type) {
this.type = type;
this.$refs.lvvpopref.show();
},
// 关闭modal弹出框
toclose() {
this.$refs.lvvpopref.close();
},
// 切换商品规格
changeSpes(obj) {
let index = obj.v;
let key = obj.k;
if (this.product.default_spes_desc[index][key].hasOwnProperty('product_id') && this.product.default_spes_desc[index]
[key].product_id) {
let data = {
'id': this.product.default_spes_desc[index][key].product_id
};
let userToken = this.$db.get("userToken");
if (userToken) {
data['token'] = userToken;
}
this.$api.getProductInfo(data, res => {
if (res.status == true) {
// 切换规格判断可购买数量
this.buyNum = res.data.stock > this.minBuyNum ? this.minBuyNum : res.data.stock;
this.product = this.spesClassHandle(res.data);
}
});
uni.showLoading({
title: '加载中'
});
setTimeout(function() {
uni.hideLoading();
}, 1000);
}
},
// 多规格样式统一处理
spesClassHandle(products) {
// 判断是否是多规格 (是否有默认规格)
if (products.hasOwnProperty('default_spes_desc')) {
let spes = products.default_spes_desc;
for (let key in spes) {
for (let i in spes[key]) {
if (spes[key][i].hasOwnProperty('is_default') && spes[key][i].is_default === true) {
this.$set(spes[key][i], 'cla', 'pop-m-item selected');
} else if (spes[key][i].hasOwnProperty('product_id') && spes[key][i].product_id) {
this.$set(spes[key][i], 'cla', 'pop-m-item not-selected');
} else {
this.$set(spes[key][i], 'cla', 'pop-m-item none');
}
}
}
products.default_spes_desc = spes;
}
return products;
},
// 购买数量加减操作
bindChange(val) {
this.buyNum = val;
},
// 商品收藏/取消
collection() {
let data = {
goods_id: this.goodsInfo.id
}
this.$api.goodsCollection(data, res => {
if (res.status) {
this.isfav = !this.isfav;
this.$common.successToShow(res.msg);
} else {
this.$common.errorToShow(res.msg);
}
})
},
// tab点击切换
onClickItem(index) {
if (this.current !== index) {
this.current = index;
}
},
// 获取商品参数信息
getGoodsParams() {
this.$api.goodsParams({
id: this.goodsId
}, res => {
if (res.status == true) {
this.goodsParams = res.data;
}
})
},
// 获取商品评论信息
getGoodsComments() {
let data = {
page: this.goodsComments.page,
limit: this.goodsComments.limit,
goods_id: this.goodsId
}
this.goodsComments.loadStatus = 'loading';
this.$api.goodsComment(data, res => {
if (res.status == true) {
let _list = res.data.list;
let count = res.data.count;
this.items = ['图文详情', '商品参数', '买家评论(' + count + ')']
// 如果评论没有图片 在这块作处理否则控制台报错
_list.forEach(item => {
item.ctime = this.$common.timeToDate(item.ctime, true);
if (!item.hasOwnProperty('images_url')) {
this.$set(item, 'images_url', [])
}
});
this.goodsComments.list = [...this.goodsComments.list, ..._list];
// 根据count数量判断是否还有数据
if (res.data.count > this.goodsComments.list.length) {
this.goodsComments.loadStatus = 'more';
this.goodsComments.page++;
} else {
this.goodsComments.loadStatus = 'noMore';
}
} else {
this.$common.errorToShow(res.msg);
}
})
},
// 添加商品浏览足迹
goodsBrowsing() {
let data = {
goods_id: this.goodsInfo.id
}
this.$api.addGoodsBrowsing(data, res => {});
},
// 加入购物车
addToCart() {
if (this.buyNum > 0) {
let data = {
product_id: this.product.id,
nums: this.buyNum
}
this.$api.addCart(data, res => {
if (res.status) {
this.toclose(); // 关闭弹出层
this.getCartNums(); // 获取购物车数量
this.$common.successToShow(res.msg);
} else {
this.$common.errorToShow(res.msg);
}
this.submitStatus = false;
})
} else {
this.submitStatus = false;
}
},
// 立即购买
buyNow() {
if (this.buyNum > 0) {
let data = {
product_id: this.product.id,
nums: this.buyNum,
type: 2 // 区分加入购物车和购买
}
this.$api.addCart(data, res => {
if (res.status) {
this.toclose();
let cartIds = res.data;
this.$common.navigateTo('/pages/goods/place-order/index?cart_ids=' + JSON.stringify(cartIds));
}
this.submitStatus = false;
})
} else {
this.submitStatus = false;
}
},
// 购物车页面跳转
redirectCart() {
uni.switchTab({
url: '/pages/cart/index/index'
});
},
// 点击弹出框确定按钮事件处理
clickHandle() {
this.submitStatus = true;
this.type === 1 ? this.addToCart() : this.buyNow();
},
// 右下角按钮
// goIndex(){
// uni.switchTab({
// url:'../../index/index'
// });
// },
trigger(e) {
// console.log(e);
this.content[e.index].active = !e.item.active;
// uni.showModal({
// title: '提示',
// content: `您${this.content[e.index].active?'选中了':'取消了'}${e.item.text}`,
// success: function(res) {
// if (res.confirm) {
// console.log('用户点击确定');
// } else if (res.cancel) {
// console.log('用户点击取消');
// }
// }
// });
uni.switchTab({
url: e.item.url
})
},
// 跳转到h5分享页面
goShare() {
this.$refs.share.show();
},
closeShare() {
this.$refs.share.close();
},
// 图片点击放大
clickImg(imgs) {
// 预览图片
uni.previewImage({
urls: imgs.split()
});
},
getMyShareCode() {
let userToken = this.$db.get("userToken");
if (userToken && userToken != '') {
// 获取我的分享码
this.$api.shareCode({}, res => {
if (res.status) {
this.myShareCode = res.data ? res.data : '';
}
});
}
}
},
//分享
onShareAppMessage() {
let myInviteCode = this.myShareCode ? this.myShareCode : '';
let ins = this.$common.shareParameterDecode('type=2&id=' + this.goodsInfo.id + '&invite=' + myInviteCode);
let path = '/pages/share/jump?scene=' + ins;
return {
title: this.goodsInfo.name,
// #ifdef MP-ALIPAY
desc: this.goodsInfo.brief,
// #endif
imageUrl: this.goodsInfo.album[0],
path: path
}
}
}
</script>
<style>
.swiper {
height: 750upx;
}
.goods-top {
border-bottom: 0;
}
.goods-top .goods-price {
font-size: 38upx;
}
.cost-price {
font-size: 28upx !important;
bottom: -10upx;
color: #999;
text-decoration: line-through;
}
.goods-top .cell-item-ft {
font-size: 20upx;
color: #666;
}
.goods-details {
padding-top: 0;
}
.goods-details .cell-hd-title {
width: 620upx;
}
.goods-details .cell-hd-title .cell-hd-title-view {
width: 100%;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
.goods-details .cell-hd-title .cell-hd-title-view:last-child {
margin-top: 10upx;
}
.goods-details .cell-item-ft {
top: 24upx;
}
.goods-title-item .cell-item-hd {
min-width: 60upx;
color: #666;
font-size: 24upx;
}
.goods-title-item .cell-item-bd {
color: #333;
font-size: 24upx;
}
.goods-title-item .cell-bd-text {
bottom: 0;
}
.cell-bd-view {
position: relative;
overflow: hidden;
}
.cell-bd-view:first-child {
margin-bottom: 8upx;
}
.goods-title-item-ic {
width: 22upx;
height: 22upx;
position: absolute;
top: 50%;
transform: translateY(-50%);
/* #ifdef MP-ALIPAY */
background-size: 100% 100%;
/* #endif */
}
.cell-bd-view .cell-bd-text {
margin-left: 30upx;
}
.goods-content {
margin-top: 26upx;
background-color: #fff;
padding: 26upx 0;
}
.goods-content-c {
margin-top: 20upx;
}
.goods-parameter {
padding: 10upx 26upx;
}
.goods-bottom,
.pop-b {
background-color: #fff;
position: fixed;
bottom: 0;
height: 90upx;
width: 100%;
overflow: hidden;
box-shadow: 0 0 20upx #ccc;
}
.goods-bottom button {
height: 100%;
width: 35%;
}
.goods-bottom-ic {
display: inline-block;
position: relative;
text-align: center;
height: 100%;
width: 15%;
float: left;
font-size: 22upx;
color: #666;
}
.goods-bottom-ic .icon {
position: relative;
top: 6upx;
/* left: -6upx; */
/* #ifdef MP-ALIPAY */
background-size: 100% 100%;
/* #endif */
}
.goods-bottom .btn-g {
color: #333;
background-color: #D9D9D9;
}
.goods-parameter .cell-item {
border-bottom: none;
margin-left: 0;
}
.goods-parameter .cell-item-hd {
color: #333;
font-size: 24upx;
}
.goods-parameter .cell-item-bd {
color: #999;
}
.goods-parameter .cell-item-bd .cell-bd-text {
bottom: 0;
}
.goods-parameter .cell-bd-text {
margin-left: 0;
}
.pop-t {
position: relative;
padding: 30upx 26upx;
border-bottom: 2upx solid #f3f3f3;
/* box-shadow: 0 0 20upx #ccc; */
}
.goods-img {
width: 160upx;
height: 160upx;
position: absolute;
top: -20upx;
background-color: #fff;
border-radius: 6upx;
border: 2upx solid #fff;
}
.goods-img image {
height: 100%;
width: 100%;
}
.goods-information {
width: 420upx;
display: inline-block;
margin-left: 180upx;
}
.pop-goods-name {
width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
display: block;
font-size: 24upx;
margin-bottom: 20upx;
}
.pop-goods-price {
font-size: 30upx;
}
.close-btn {
width: 40upx;
height: 40upx;
border-radius: 50%;
display: inline-block;
position: absolute;
right: 30upx;
}
.close-btn image {
width: 100%;
height: 100%;
}
.pop-m {
font-size: 28upx;
margin-bottom: 90upx;
}
.goods-specs,
.goods-number {
padding: 26upx;
border-top: 1px solid #f3f3f3;
}
.goods-specs:first-child {
border: none;
}
.pop-m-title {
margin-right: 10upx;
color: #666;
}
.pop-m-bd {
overflow: hidden;
margin-top: 10upx;
}
.pop-m-item {
display: inline-block;
float: left;
padding: 6upx 16upx;
background-color: #fff;
color: #333;
margin-right: 16upx;
margin-bottom: 10upx;
}
.selected {
border: 2upx solid #333;
background-color: #333;
color: #fff;
}
.not-selected {
border: 2upx solid #ccc;
}
.none {
border: 2upx dashed #ccc;
color: #888;
}
.pop-m-bd-in {
display: inline-block;
}
.badge {
top: 2upx;
left: 62upx;
}
.goods-assess .user-head-img {
width: 80upx;
height: 80upx;
border-radius: 50%;
}
.goods-assess .cell-item-bd {
padding-right: 0;
}
.goods-assess .cell-bd-text {
margin: 0;
}
.goods-assess .cell-bd-text.color-9 {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 440upx;
}
.gai-body {}
.gai-body-text {
font-size: 26upx;
color: #333;
padding: 0 26upx;
word-wrap: break-word;
}
.gai-body-img {
overflow: hidden;
padding: 20upx 26upx;
}
.gai-body-img image {
width: 220upx;
height: 220upx;
float: left;
margin-right: 19upx;
margin-bottom: 18upx;
}
.gai-body-img image:nth-child(3n) {
margin-right: 0;
}
.redstar {
width: 24rpx;
height: 24rpx;
padding: 2rpx;
}
.mask-share-wechat {
display: inline-block;
background-color: #fff;
padding: 0;
}
.mask-share-wechat:after {
border: none;
}
.right-ball {
position: fixed;
right: 30upx;
bottom: 300upx;
z-index: 999;
text-align: center;
padding: 14upx 0;
/* line-height: 80upx; */
width: 80upx;
height: 80upx;
font-size: 24upx;
color: #fff;
background-color: rgba(0, 0, 0, .5);
border-radius: 50%;
}
.comment-none {
text-align: center;
padding: 200upx 0;
}
.comment-none-img {
width: 274upx;
height: 274upx;
}
.price-salesvolume {
width: 100%;
padding: 0 0 0 26upx;
overflow: hidden;
color: #A5A5A5;
background-color: rgb(252, 226, 80);
position: relative;
}
.commodity-price {
width: 224upx;
display: inline-block;
float: left;
}
.current-price {
font-size: 40upx;
color: #FF7159;
display: block;
line-height: 1.5;
}
.cost-price {
font-size: 26upx;
text-decoration: line-through;
/* margin-left: 8rpx; */
display: block;
}
.commodity-salesvolume {
width: 240upx;
display: inline-block;
font-size: 22upx;
float: left;
padding: 16upx 0;
}
.commodity-salesvolume>text {
display: block;
}
.commodity-time-img {
display: block;
width: 0;
height: 0;
border-width: 48upx 28upx 50upx 0;
border-style: solid;
border-color: transparent #FF7159 transparent transparent;
/*透明 黄 透明 透明 */
position: absolute;
top: 0px;
left: 462upx;
}
.commodity-time {
display: inline-block;
width: 260upx;
text-align: center;
font-size: 24upx;
background-color: #FF7159;
padding: 16upx 0 18upx;
color: rgb(250, 233, 0);
}
.commodity-time>text {
display: block;
}
.commodity-day {
font-size: 22upx;
}
.commodity-day>text {
display: inline-block;
background-color: rgb(255, 212, 176);
color: rgb(255, 115, 0);
padding: 0 6upx;
border-radius: 6upx;
}
.nav-back {
width: 100%;
height: 44px;
/* #ifndef MP-WEIXIN */
padding: 12px 12px 0;
/* #endif */
/* #ifdef MP-WEIXIN */
padding: 26px 12px 0;
/* #endif */
position: fixed;
top: 0;
background-color: rgba(255, 255, 255, 0);
z-index: 98;
}
.back-btn {
height: 32px;
width: 32px;
border-radius: 50%;
background-color: rgba(255, 255, 255, 0.8);
}
.back-btn .icon {
height: 20px;
width: 20px;
position: relative;
top: 50%;
left: 46%;
transform: translate(-50%, -50%);
}
.seller-content {
background-color: #f8f8f8;
margin: 0 13px 15px;
padding: 10px;
color: #6e6e6e;
border-radius: 4px;
}
.seller-content-top {
font-weight: bold;
margin-bottom: 6px;
}
.seller-content-img {
width: 20px;
height: 20px;
vertical-align: middle;
margin-right: 4px;
}
</style>
pintuan.vue
<template>
<view class="content">
<view class="nav-back">
<view class="back-btn" @click="backBtn()">
<image class="icon" src="/static/image/back-black.png" mode=""></image>
</view>
</view>
<view class="content-top">
<!-- 轮播图 -->
<view class='swiper'>
<swiper class="swiper-c" :indicator-dots="swiper.indicatorDots" :autoplay="swiper.autoplay" :interval="swiper.interval"
:duration="swiper.duration">
<swiper-item class="have-none" v-for="(item, index) in goodsInfo.album" :key="index" @click="clickImg(item)">
<!-- {{goodsInfo.album}} -->
<image class='' :src='item' mode="aspectFill"></image>
</swiper-item>
</swiper>
</view>
<!-- 轮播图end -->
<view class='cell-group'>
<!-- 倒计时 -->
<view class='price-salesvolume' v-if="lasttime.hour!==false">
<view class='commodity-price'>
<text class='current-price'>¥{{pintuanPrice}}</text>
<text class='cost-price' v-if="parseFloat(product.mktprice)>0">¥{{product.mktprice}}</text>
</view>
<view class='commodity-salesvolume'>
<text>已售{{goodsInfo.buy_count}}件/剩余{{product.stock}}件</text>
<text>累计销售{{goodsInfo.buy_count}}件</text>
</view>
<view class='commodity-time' v-if="goodsInfo.pintuan_rule.pintuan_start_status == 1">
<text>距结束仅剩</text>
<view class='commodity-day'>
<uni-countdown textColor="#fce250" :day="lasttime.day" :hour="lasttime.hour" :minute="lasttime.minute" :second="lasttime.second"></uni-countdown>
</view>
</view>
<view class='commodity-time' v-if="goodsInfo.pintuan_rule.pintuan_start_status == 2">
<text>即将开团</text>
<view class='commodity-day'>
<uni-countdown textColor="#fce250" :day="goodsInfo.pintuan_rule.lasttime.day" :hour="goodsInfo.pintuan_rule.lasttime.hour"
:minute="goodsInfo.pintuan_rule.lasttime.minute" :second="goodsInfo.pintuan_rule.lasttime.second"></uni-countdown>
</view>
</view>
<view class='commodity-time-img'></view>
<!-- <view class='commodity-time'>
已结束
</view> -->
</view>
<!-- 倒计时end -->
<!-- 分享 -->
<view class='cell-item goods-details'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>
<view class="color-3 fsz28 cell-hd-title-view">
{{ product.name }}
</view>
<view v-if="goodsInfo.brief" class="color-9 fsz24 cell-hd-title-view">
{{ goodsInfo.brief }}
</view>
</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' @click="goShare()" src='/static/image/share.png'></image>
</view>
</view>
<!-- 分享end -->
<!-- 促销 -->
<view class='cell-item goods-title-item' v-if="promotion.length">
<view class='cell-item-hd'>
<view class='cell-hd-title'>促销</view>
</view>
<view class='cell-item-bd'>
<view class="romotion-tip">
<view class="romotion-tip-item" :class="item.type !== 2 ? 'bg-gray' : ''" v-for="(item, index) in promotion"
:key="index">
{{ item.name }}
</view>
</view>
</view>
</view>
<!-- 促销end -->
<!-- 规格 -->
<view class='cell-item goods-title-item' v-if="isSpes">
<view class='cell-item-hd'>
<view class='cell-hd-title'>规格</view>
</view>
<view class='cell-item-bd' @click="toshow()">
<text class='cell-bd-text'>{{ product.spes_desc }}</text>
</view>
</view>
<!-- 规格end -->
<!-- 说明 -->
<view class='cell-item goods-title-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>说明</view>
</view>
<view class='cell-item-bd'>
<view class="cell-bd-view">
<image class="goods-title-item-ic" src="/static/image/ic-dui.png" mode=""></image>
<text class="cell-bd-text">24小时内发货</text>
</view>
<view class="cell-bd-view">
<image class="goods-title-item-ic" src="/static/image/ic-dui.png" mode=""></image>
<text class="cell-bd-text">7天拆封无条件退货</text>
</view>
</view>
</view>
<!-- 说明end -->
</view>
<!-- 团购拼单 -->
<view class="cell-group margin-cell-group" v-if="pintuanRecord.length>0">
<view class='cell-item right-img'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>{{teamCount}}人在拼单,可直接参与</view>
</view>
<!-- <view class='cell-item-ft' >
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
<text class='cell-ft-text'>查看更多</text>
</view> -->
</view>
<view class="group-swiper">
<swiper class="group-swiper-c" :class="groupHeight" :indicator-dots="indicatorDots" :autoplay="autoplay" vertical="true"
circular="true" :interval="interval" :duration="duration">
<swiper-item v-for="(item, index) in pintuanRecord" :key="index">
<view class="swiper-item">
<view class='cell-item'>
<view class='cell-item-hd'>
<image class="user-head-img cell-hd-icon have-none" :src='item[0].user_avatar' mode=""></image>
<view class="cell-hd-title">
{{item[0].nickname}}
</view>
</view>
<view class='cell-item-bd'>
<view class="cell-bd-view">
<text class="cell-bd-text">还差<text class="red-price">{{item[0].team_nums}}人</text>拼成</text>
</view>
<view class="cell-bd-view">
<view class='commodity-day'>
<text class="fsz24 color-6">剩余:</text>
<uni-countdown color="#666" :day="item[0].remainder_time.day" :hour="item[0].remainder_time.hour" :minute="item[0].remainder_time.minute"
:second="item[0].remainder_time.second"></uni-countdown>
</view>
</view>
</view>
<view class="cell-item-ft">
<button class="btn" @click="toshow(2,item[0].team_id)">去拼单</button>
</view>
<!-- <view class="cell-item-ft" v-else>
<button class="btn btn-b">拼团中</button>
</view> -->
</view>
<view class='cell-item' v-if="item[1]">
<view class='cell-item-hd'>
<image class="user-head-img cell-hd-icon have-none" :src='item[1].user_avatar' mode=""></image>
<view class="cell-hd-title">
{{item[1].nickname}}
</view>
</view>
<view class='cell-item-bd'>
<view class="cell-bd-view">
<text class="cell-bd-text">还差<text class="red-price">{{item[1].team_nums}}人</text>拼成</text>
</view>
<view class="cell-bd-view">
<view class='commodity-day'>
<text class="fsz24 color-6">剩余:</text>
<uni-countdown color="#666" :day="item[1].remainder_time.day" :hour="item[1].remainder_time.hour" :minute="item[1].remainder_time.minute"
:second="item[1].remainder_time.second"></uni-countdown>
</view>
</view>
</view>
<view class="cell-item-ft">
<button class="btn" @click="toshow(2,item[1].id)">去拼单</button>
</view>
</view>
</view>
</swiper-item>
</swiper>
</view>
</view>
<view class="cell-group margin-cell-group" v-else="">
<view class='cell-item right-img'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>暂无开团信息</view>
</view>
</view>
</view>
<view class="goods-content">
<uni-segmented-control :current="current" :values="items" @clickItem="onClickItem" style-type="text" active-color="#333"></uni-segmented-control>
<view class="goods-content-c">
<view class="goods-detail" v-if="current === 0">
<jshopContent :content="goodsInfo.intro" v-if="goodsInfo.intro"></jshopContent>
</view>
<view class="goods-parameter" v-else-if="current === 1">
<view class='cell-group' v-if="goodsParams.length">
<view class='cell-item' v-for="(item, index) in goodsParams" :key="index">
<view class='cell-item-hd'>
<view class='cell-hd-title'>{{ item.name }}</view>
</view>
<view class='cell-item-bd'>
<text class='cell-bd-text'>{{ item.value }}</text>
</view>
</view>
</view>
</view>
<view class="goods-assess" v-else-if="current === 2">
<view v-if="goodsComments.list.length">
<view class="goods-assess-item" v-for="(item, index) in goodsComments.list" :key="index">
<view class='cell-group'>
<view class='cell-item goods-title-item'>
<view class='cell-item-hd'>
<image class='user-head-img' :src='item.user.avatar' mode="aspectFill"></image>
</view>
<view class='cell-item-bd'>
<view class="cell-bd-view">
<text class="cell-bd-text">{{ item.user.nickname }}</text>
<view class="cell-bd-text-right">
<uni-rate size="16" disabled="true" :value="item.score"></uni-rate>
</view>
</view>
<view class="cell-bd-view">
<text class="cell-bd-text color-9" style="margin-right: 16upx;">{{ item.ctime }}</text>
<text class="cell-bd-text color-9">{{ item.addon }}</text>
</view>
</view>
</view>
</view>
<view class="gai-body">
<view class="gai-body-text">
{{ item.content }}
</view>
<view class="gai-body-img" v-if="item.images_url.length">
<image :src="img" mode="aspectFill" v-for="(img, key) in item.images_url" :key="key" @click="clickImg(img)"></image>
</view>
</view>
</view>
<uni-load-more :status="goodsComments.loadStatus"></uni-load-more>
</view>
<view class="comment-none" v-else>
<image class="comment-none-img" src="/static/image/order.png" mode=""></image>
</view>
</view>
</view>
</view>
</view>
<lvv-popup position="bottom" ref="pintuanpop">
<view class="ig-top" v-if="teamInfo.list.length>0">
<view class="ig-top-t">
<view class="">
剩余时间:<uni-countdown :day="teamInfo.team_time.day" :hour="teamInfo.team_time.hour" :minute="teamInfo.team_time.minute"
:second="teamInfo.team_time.second"></uni-countdown>
</view>
</view>
<view class="ig-top-m">
<view class="user-head-img-c" v-for="(item, index) in teamInfo.list" :key="index">
<view class="user-head-img-tip" v-if="item.id == item.team_id">拼主</view>
<image class="user-head-img cell-hd-icon have-none" :src='item.user_avatar' mode=""></image>
</view>
<view class="user-head-img-c uhihn" v-if="teamInfo.team_nums" v-for="n in teamInfo.team_nums" :key="n"><text>?</text></view>
</view>
<view class="ig-top-b">
<view class="igtb-top">
还差<text class="red-price">{{ teamInfo.team_nums }}</text>人,赶快拼单吧
</view>
<view class="igtb-mid">
<button class="btn" @click="toshow(2,teamInfo.id)">参与拼团</button>
</view>
</view>
</view>
</lvv-popup>
<lvv-popup position="bottom" ref="share">
<!-- #ifdef H5 -->
<shareByH5 :shareType='3' :goodsId="goodsInfo.id" :shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name"
:shareContent="goodsInfo.brief" :shareHref="shareHref" @close="closeShare()"></shareByH5>
<!-- #endif -->
<!-- #ifdef MP-WEIXIN -->
<shareByWx :shareType='3' :goodsId="goodsInfo.id" :shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name"
:shareContent="goodsInfo.brief" :shareHref="shareHref" @close="closeShare()"></shareByWx>
<!-- #endif -->
<!-- #ifdef MP-ALIPAY -->
<shareByAli :shareType='3' :goodsId="goodsInfo.id" :shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name"
:shareContent="goodsInfo.brief" :shareHref="shareHref" @close="closeShare()"></shareByAli>
<!-- #endif -->
<!-- #ifdef APP-PLUS -->
<shareByApp :shareType='3' :goodsId="goodsInfo.id" :shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name"
:shareContent="goodsInfo.brief" :shareHref="shareHref" @close="closeShare()"></shareByApp>
<!-- #endif -->
</lvv-popup>
<!-- 弹出层 -->
<lvv-popup position="bottom" ref="lvvpopref">
<view style="width: 100%;max-height: 804upx;background: #FFFFFF;position: absolute;left:0;bottom: 0;">
<view class="pop-c">
<view class="pop-t">
<view class='goods-img'>
<image :src='product.image_path' mode='aspectFill'></image>
</view>
<view class='goods-information'>
<view class='pop-goods-name'>{{ product.name }}</view>
<view class='pop-goods-price red-price'>¥ {{ price }}</view>
</view>
<view class='close-btn' @click="toclose()">
<image src='/static/image/close.png'></image>
</view>
</view>
<scroll-view class="pop-m" scroll-y="true" style="max-height: 560upx;">
<spec :spesData="product.default_spes_desc" ref="spec" @changeSpes="changeSpes"></spec>
<view class="goods-number">
<text class="pop-m-title">数量</text>
<view class="pop-m-bd-in">
<uni-number-box :min="minNums" :max="product.stock" :value="buyNum" @change="bindChange"></uni-number-box>
</view>
</view>
</scroll-view>
<view class="pop-b">
<!-- <button class='btn btn-square btn-g btn-half' @click="addToCart">加入购物车</button>
<button class='btn btn-square btn-b btn-half' @click="buyNow">立即购买</button> -->
<button class='btn btn-square btn-b btn-all' hover-class="btn-hover2" @click="buyNow()" v-if="product.stock">确定</button>
<button class='btn btn-square btn-g btn-all' v-else>已售罄</button>
</view>
</view>
</view>
</lvv-popup>
<!-- 弹出层end -->
<div id="qrCode" ref="qrCodeDiv"></div>
<!-- 底部按钮 -->
<view class="goods-bottom">
<view class="goods-bottom-ic" @click="collection">
<image class="icon" :src="isfav ? favLogo[1] : favLogo[0]" mode=""></image>
<view v-if="!isfav">收藏</view>
<view v-if="isfav">已收藏</view>
</view>
<view class="goods-bottom-ic" @click="redirectCart">
<view class="badge color-f" v-if="cartNums">{{ cartNums }}</view>
<image class="icon" src="/static/image/ic-me-car.png" mode=""></image>
<view>购物车</view>
</view>
<button class='btn btn-square btn-g' @click="toshow(1)" hover-class="btn-hover2">
<view class="btn-content">
<view class="color-6">¥{{product.price}}</view>
<view class="color-6 fsz24">单独购买</view>
</view>
</button>
<button class='btn btn-square btn-b' @click="toshow(2)" hover-class="btn-hover2" v-if="goodsInfo.pintuan_rule.pintuan_start_status == 1 ">
<view class="btn-content">
<view class="">¥{{pintuanPrice}}</view>
<view class="fsz24">发起拼团</view>
</view>
</button>
<button class='btn btn-square btn-b' hover-class="btn-hover2" v-if="goodsInfo.pintuan_rule.pintuan_start_status == 2 ">
<view class="btn-content">
<view class="">¥{{pintuanPrice}}</view>
<view class="fsz24">即将开团</view>
</view>
</button>
<button class='btn btn-square btn-b' hover-class="btn-hover2" v-if="goodsInfo.pintuan_rule.pintuan_start_status == 3 ">
<view class="btn-content">
<view class="">¥{{pintuanPrice}}</view>
<view class="fsz24">拼团已结束</view>
</view>
</button>
</view>
<!-- 底部按钮end -->
<!-- 右边浮动球 -->
<!-- <view class="right-ball">
<view class="" @click="goIndex()">
<image class="icon" src="/static/image/tab-ic-hom-selected.png" mode=""></image>
</view>
</view> -->
<uni-fab :pattern="pattern" :content="content" :horizontal="horizontal" :vertical="vertical" :direction="direction"
@trigger="trigger"></uni-fab>
</view>
</template>
<script>
import uniSegmentedControl from "@/components/uni-segmented-control/uni-segmented-control.vue";
import lvvPopup from '@/components/lvv-popup/lvv-popup.vue';
import uniNumberBox from "@/components/uni-number-box/uni-number-box.vue";
import uniRate from "@/components/uni-rate/uni-rate.vue";
import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue';
import uniFab from '@/components/uni-fab/uni-fab.vue';
import {
get
} from '@/config/db.js';
import {
apiBaseUrl
} from '@/config/config.js'
import uniCountdown from "@/components/uni-countdown/uni-countdown.vue"
import spec from '@/components/spec/spec.vue'
// #ifdef H5
import shareByH5 from '@/components/share/shareByh5.vue'
// #endif
// #ifdef MP-WEIXIN
import shareByWx from '@/components/share/shareByWx.vue'
// #endif
// #ifdef MP-ALIPAY
import shareByAli from '@/components/share/shareByAli.vue'
// #endif
// #ifdef APP-PLUS
import shareByApp from '@/components/share/shareByApp.vue'
// #endif
import jshopContent from '@/components/jshop/jshop-content.vue'//视频和文本解析组件
export default {
components: {
uniSegmentedControl,
lvvPopup,
uniNumberBox,
uniRate,
uniLoadMore,
uniFab,
uniCountdown,
spec,
jshopContent,
// #ifdef H5
shareByH5,
// #endif
// #ifdef MP-WEIXIN
shareByWx,
// #endif
// #ifdef MP-ALIPAY
shareByAli,
// #endif
// #ifdef APP-PLUS
shareByApp,
// #endif
},
data() {
return {
myShareCode: '', //分享Code
swiper: {
indicatorDots: true,
autoplay: true,
interval: 3000,
duration: 800,
}, // 轮播图属性设置
items: ['图文详情', '商品参数', '买家评论'],
current: 0, // init tab位
goodsId: 0, // 商品id
groupId: 0, // 团购ID
goodsInfo: {
pintuan_rule: {
pintuan_start_status: 1
}
}, // 商品详情
cartNums: 0, // 购物车数量
product: {}, // 规格详情
goodsParams: [], // 商品参数信息
goodsComments: {
loadStatus: 'more',
page: 1,
limit: 5,
list: []
}, // 商品评论信息
buyNum: 1, // 选定的购买数量
minBuyNum: 1, // 最小可购买数量
type: 2, // 1单独购买 2拼团
isfav: false, // 商品是否收藏
favLogo: [
'/static/image/ic-me-collect.png',
'/static/image/ic-me-collect2.png'
],
horizontal: 'right', //右下角弹出按钮
vertical: 'bottom',
direction: 'vertical',
pattern: {
color: '#7A7E83',
backgroundColor: '#fff',
selectedColor: '#007AFF',
buttonColor: "#FF7159"
},
content: [{
iconPath: '/static/image/tab-ic-hom-selected.png',
selectedIconPath: '/static/image/tab-ic-hom-unselected.png',
// text: '首页',
active: false,
url: '/pages/index/index'
},
{
iconPath: '/static/image/tab-ic-me-selected.png',
selectedIconPath: '/static/image/tab-ic-me-unselected.png',
// text: '个人中心',
active: false,
url: '/pages/member/index/index'
},
],
indicatorDots: false,
autoplay: false,
interval: 2000,
duration: 500,
lasttime: {
day: 0,
hour: false,
minute: 0,
second: 0
}, //购买倒计时
pintuanPrice: 0,
discount_amount: 0, //拼团优惠金额
price: 0,
teamCount: 0, //已经有多少人拼团
pintuanRecord: [], //拼团列表
remainder_time: {
day: 0,
hour: false,
minute: 0,
second: 0
}, //拼团倒计时
groupHeight: 'groupHeight',
teamId: 0, //去参团的teamid
teamInfo: {
list: [],
team_time: {
day: 0,
hour: 0,
minute: 0,
second: 0
}, //被邀请拼团倒计时
},
}
},
onLoad(e) {
this.goodsId = e.id;
if (e.team_id) {
this.teamId = e.team_id;
this.getTeam(this.teamId)
}
if (this.goodsId) {
this.getGoodsInfo();
this.getGoodsParams();
this.getGoodsComments();
} else {
this.$common.errorToShow('获取失败', () => {
uni.navigateBack({
delta: 1
});
});
}
// 获取购物车数量
this.getCartNums();
this.getMyShareCode();
},
onReady() {
},
computed: {
// 规格切换计算规格商品的 可购买数量
minNums() {
return this.product.stock > this.minBuyNum ? this.minBuyNum : this.product.stock;
},
// 判断商品是否是多规格商品 (为了兼容小程序 只能写在计算属性里面了)
isSpes() {
if (this.product.hasOwnProperty('default_spes_desc') && Object.keys(this.product.default_spes_desc).length) {
return true;
} else {
return false;
}
},
// 优惠信息重新组装
promotion() {
let arr = [];
if (this.product.promotion_list) {
for (let k in this.product.promotion_list) {
arr.push(this.product.promotion_list[k]);
}
}
return arr;
},
typeName() {
return this.goodsInfo.group_type == 3 ? '团购' : '秒杀';
},
shareHref() {
let pages = getCurrentPages()
let page = pages[pages.length - 1]
// #ifdef H5 || MP-WEIXIN || APP-PLUS || APP-PLUS-NVUE
return apiBaseUrl + 'wap/' + page.route + '?id=' + this.goodsId + '&group_id=' + this.groupId;
// #endif
// #ifdef MP-ALIPAY
return apiBaseUrl + 'wap/' + page.__proto__.route + '?id=' + this.goodsId + '&group_id=' + this.groupId;
// #endif
}
},
onReachBottom() {
if (this.current === 2 && this.goodsComments.loadStatus === 'more') {
this.getGoodsComments();
}
},
methods: {
// 返回上一页
backBtn() {
uni.navigateBack({
delta: 1
});
},
// 获取商品详情
getGoodsInfo() {
let data = {
id: this.goodsId
}
// 如果用户已经登录 要传用户token
let userToken = get('userToken');
if (userToken) {
data['token'] = userToken;
}
let _this = this;
_this.$api.pintuanGoodsInfo(data, res => {
console.log(res);
if (res.status) {
if (res.data.length < 1) {
_this.$common.errorToShow('该商品不存在,请返回重新选择商品。', () => {
uni.navigateBack({
delta: 1
});
});
} else if (res.data.marketable != 1) {
_this.$common.errorToShow('该商品已下架,请返回重新选择商品。', () => {
uni.navigateBack({
delta: 1
});
});
} else {
let info = res.data;
_this.goodsInfo = info;
let products = res.data.product;
_this.discount_amount = parseFloat(info.pintuan_rule.discount_amount).toFixed(2);
//products.price = _this.$common.moneySub(products.price,_this.discount_amount);
_this.product = _this.spesClassHandle(products);
_this.isfav = _this.goodsInfo.isfav === 'true' ? true : false;
// _this.pintuanPrice = info.pintuan_price.toFixed(2)
_this.pintuanPrice = this.$common.moneySub(this.product.price, this.discount_amount);
let timestamp = Date.parse(new Date()) / 1000;
let lasttime = res.data.pintuan_rule.etime - timestamp;
_this.lasttime = _this.$common.timeToDateObj(lasttime);
// 获取拼团记录
let pintuan_data = info.pintuan_record;
let new_data = new Array();
for (var k = 0; k < pintuan_data.length; k++) {
pintuan_data[k].remainder_time = _this.$common.timeToDateObj(pintuan_data[k].close_time - timestamp)
if (k == 0 || k % 2 == 0) {
if (k + 1 < pintuan_data.length) {
var a = [
pintuan_data[k],
pintuan_data[k + 1]
];
} else {
var a = [pintuan_data[k]];
}
new_data.push(a);
}
}
pintuan_data.length < 2 ? _this.groupHeight = 'groupHeight' : _this.groupHeight = '';
_this.pintuanRecord = new_data;
// console.log(new_data);
_this.teamCount = info.pintuan_record_nums;
// 判断如果登录用户添加商品浏览足迹
if (userToken) {
_this.goodsBrowsing();
}
}
}
});
},
// 获取通过分享进来的拼团数据
getTeam(id) {
this.$api.getOrderPintuanTeamInfo({
team_id: id
}, res => {
if (res.status) {
this.teamInfo = {
list: res.data.teams,
current_count: res.data.teams.length,
people_number: res.data.people_number,
team_nums: res.data.team_nums, //剩余
close_time: res.data.close_time, //关闭时间
id: res.data.id, //拼团id
team_id: res.data.team_id, //拼团团队id
rule_id: res.data.rule_id,
status: res.data.status
};
let timestamp = Date.parse(new Date()) / 1000;
this.teamInfo.team_time = this.$common.timeToDateObj(res.data.close_time - timestamp);
if (res.data.status == 1) {
this.pintuanShow();
} else {
this.teamId = 0;
}
} else {
this.$common.errorToShow(res.msg)
}
});
},
// 获取购物车数量
getCartNums() {
let userToken = this.$db.get("userToken");
if (userToken && userToken != '') {
// 获取购物车数量
this.$api.getCartNum({}, res => {
if (res.status) {
this.cartNums = res.data;
}
});
}
},
// 显示modal弹出框
toshow(type, team_id) {
this.type = type;
if (team_id) {
this.teamId = team_id
}
if (this.type == 2) {
this.price = this.pintuanPrice;
} else {
this.price = this.product.price;
}
this.$refs.lvvpopref.show();
},
// 关闭modal弹出框
toclose() {
this.$refs.lvvpopref.close();
},
// 切换商品规格
changeSpes(obj) {
let index = obj.v;
let key = obj.k;
//type = 1是立即购买,2是拼团购买
if (this.product.default_spes_desc[index][key].hasOwnProperty('product_id') && this.product.default_spes_desc[index]
[key].product_id) {
let data = {
'id': this.product.default_spes_desc[index][key].product_id
};
let userToken = this.$db.get("userToken");
if (userToken) {
data['token'] = userToken;
}
this.$api.getProductInfo(data, res => {
if (res.status == true) {
// 切换规格判断可购买数量
this.buyNum = res.data.stock > this.minBuyNum ? this.minBuyNum : res.data.stock;
this.product = this.spesClassHandle(res.data);
//products.price = _this.$common.moneySub(products.price,_this.discount_amount);
if (this.type == 2) { //拼团
this.price = this.$common.moneySub(this.product.price, this.discount_amount);
} else {
this.price = this.product.price;
}
}
});
uni.showLoading({
title: '加载中'
});
setTimeout(function() {
uni.hideLoading();
}, 1000);
}
},
// 多规格样式统一处理
spesClassHandle(products) {
// 判断是否是多规格 (是否有默认规格)
if (products.hasOwnProperty('default_spes_desc')) {
let spes = products.default_spes_desc;
for (let key in spes) {
for (let i in spes[key]) {
if (spes[key][i].hasOwnProperty('is_default') && spes[key][i].is_default === true) {
this.$set(spes[key][i], 'cla', 'pop-m-item selected');
} else if (spes[key][i].hasOwnProperty('product_id') && spes[key][i].product_id) {
this.$set(spes[key][i], 'cla', 'pop-m-item not-selected');
} else {
this.$set(spes[key][i], 'cla', 'pop-m-item none');
}
}
}
products.default_spes_desc = spes;
}
return products;
},
// 购买数量加减操作
bindChange(val) {
this.buyNum = val;
},
// 商品收藏/取消
collection() {
let data = {
goods_id: this.goodsInfo.id
}
this.$api.goodsCollection(data, res => {
if (res.status) {
this.isfav = !this.isfav;
this.$common.successToShow(res.msg);
} else {
this.$common.errorToShow(res.msg);
}
})
},
// tab点击切换
onClickItem(index) {
if (this.current !== index) {
this.current = index;
}
},
// 获取商品参数信息
getGoodsParams() {
this.$api.goodsParams({
id: this.goodsId
}, res => {
if (res.status == true) {
this.goodsParams = res.data;
}
})
},
// 获取商品评论信息
getGoodsComments() {
let data = {
page: this.goodsComments.page,
limit: this.goodsComments.limit,
goods_id: this.goodsId
}
this.goodsComments.loadStatus = 'loading';
this.$api.goodsComment(data, res => {
if (res.status == true) {
let _list = res.data.list;
// 如果评论没有图片 在这块作处理否则控制台报错
_list.forEach(item => {
item.ctime = this.$common.timeToDate(item.ctime)
if (!item.hasOwnProperty('images_url')) {
this.$set(item, 'images_url', [])
}
});
this.goodsComments.list = [...this.goodsComments.list, ..._list];
// 根据count数量判断是否还有数据
if (res.data.count > this.goodsComments.list.length) {
this.goodsComments.loadStatus = 'more';
this.goodsComments.page++;
} else {
this.goodsComments.loadStatus = 'noMore';
}
} else {
this.$common.errorToShow(res.msg);
}
})
},
// 添加商品浏览足迹
goodsBrowsing() {
let data = {
goods_id: this.goodsInfo.id
}
this.$api.addGoodsBrowsing(data, res => {});
},
// 立即购买
buyNow() {
if (this.buyNum > 0) {
let data = {
product_id: this.product.id,
nums: this.buyNum,
order_type: this.type
}
this.$api.addCart(data, res => {
if (res.status) {
this.toclose();
let cartIds = res.data;
if (this.teamId == 0) {
this.$common.navigateTo('/pages/goods/place-order/index?cart_ids=' + JSON.stringify(cartIds) + '&order_type=' +
this.type);
} else {
this.$common.navigateTo('/pages/goods/place-order/index?cart_ids=' + JSON.stringify(cartIds) + '&order_type=' +
this.type + '&team_id=' + this.teamId);
}
} else {
this.toclose();
this.$common.errorToShow(res.msg);
}
})
}
},
// 购物车页面跳转
redirectCart() {
uni.switchTab({
url: '/pages/cart/index/index'
});
},
trigger(e) {
this.content[e.index].active = !e.item.active;
uni.switchTab({
url: e.item.url
})
},
// 跳转到h5分享页面
goShare() {
this.$refs.share.show();
},
closeShare() {
this.$refs.share.close();
},
// 拼团弹出层
pintuanShow() {
this.$refs.pintuanpop.show();
// this.$refs.lvvpopref.close();
},
pintuanClose() {
//this.$refs.pintuanpop.close();
// this.$refs.pintuanpop.close();
// this.$refs.share.close();
//this.$refs.lvvpopref.close();
},
// 图片点击放大
clickImg(imgs) {
// 预览图片
uni.previewImage({
urls: imgs.split()
});
},
getMyShareCode() {
let userToken = this.$db.get("userToken");
if (userToken && userToken != '') {
// 获取我的分享码
this.$api.shareCode({}, res => {
if (res.status) {
this.myShareCode = res.data ? res.data : '';
}
});
}
}
},
//分享
onShareAppMessage() {
let myInviteCode = this.myShareCode ? this.myShareCode : '';
let ins = this.$common.shareParameterDecode('type=5&id=' + this.goodsId + '&invite=' + myInviteCode);
let path = '/pages/share/jump?scene=' + ins;
console.log(path);
return {
title: this.goodsInfo.name,
// #ifdef MP-ALIPAY
desc: this.goodsInfo.brief,
// #endif
imageUrl: this.goodsInfo.album[0],
path: path
}
}
}
</script>
<style>
.swiper {
height: 750upx;
}
.goods-top {
border-bottom: 0;
}
.goods-top .goods-price {
font-size: 38upx;
}
.cost-price {
font-size: 28upx !important;
bottom: -10upx;
color: #999;
text-decoration: line-through;
}
.goods-top .cell-item-ft {
font-size: 20upx;
color: #666;
}
.goods-details {
padding-top: 16upx;
}
.goods-details .cell-hd-title {
width: 620upx;
}
.goods-details .cell-hd-title .cell-hd-title-view {
width: 100%;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
.goods-details .cell-hd-title .cell-hd-title-view:last-child {
margin-top: 10upx;
}
.goods-details .cell-item-ft {
top: 42upx;
}
.goods-title-item .cell-item-hd {
min-width: 60upx;
color: #666;
font-size: 24upx;
}
.goods-title-item .cell-item-bd {
color: #333;
font-size: 24upx;
}
.goods-title-item .cell-bd-text {
bottom: 0;
}
.cell-bd-view {
position: relative;
overflow: hidden;
}
.cell-bd-view:first-child {
margin-bottom: 8upx;
}
.goods-title-item-ic {
width: 22upx;
height: 22upx;
position: absolute;
top: 50%;
transform: translateY(-50%);
/* #ifdef MP-ALIPAY */
background-size: 100% 100%;
/* #endif */
}
.cell-bd-view .cell-bd-text {
margin-left: 30upx;
}
.goods-content {
margin-top: 26upx;
background-color: #fff;
padding: 26upx 0;
}
.goods-content-c {}
.goods-parameter {
padding: 10upx 26upx;
}
.goods-bottom,
.pop-b {
background-color: #fff;
position: fixed;
bottom: 0;
height: 90upx;
width: 100%;
overflow: hidden;
box-shadow: 0 0 20upx #ccc;
}
.goods-bottom button {
height: 100%;
width: 35%;
}
.goods-bottom-ic {
display: inline-block;
position: relative;
text-align: center;
height: 100%;
width: 15%;
float: left;
font-size: 22upx;
color: #666;
}
.goods-bottom-ic .icon {
position: relative;
top: 6upx;
/* left: -6upx; */
/* #ifdef MP-ALIPAY */
background-size: 100% 100%;
/* #endif */
}
.goods-bottom .btn-g {
color: #333;
background-color: #D9D9D9;
}
.goods-parameter .cell-item {
border-bottom: none;
margin-left: 0;
}
.goods-parameter .cell-item-hd {
color: #333;
font-size: 24upx;
}
.goods-parameter .cell-item-bd {
color: #999;
}
.goods-parameter .cell-item-bd .cell-bd-text {
bottom: 0;
}
.goods-parameter .cell-bd-text {
margin-left: 0;
}
.pop-t {
position: relative;
padding: 30upx 26upx;
border-bottom: 2upx solid #f3f3f3;
/* box-shadow: 0 0 20upx #ccc; */
}
.goods-img {
width: 160upx;
height: 160upx;
position: absolute;
top: -20upx;
background-color: #fff;
border-radius: 6upx;
border: 2upx solid #fff;
}
.goods-img image {
height: 100%;
width: 100%;
}
.goods-information {
width: 420upx;
display: inline-block;
margin-left: 180upx;
}
.pop-goods-name {
width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
display: block;
font-size: 24upx;
margin-bottom: 20upx;
}
.pop-goods-price {
font-size: 30upx;
}
.close-btn {
width: 40upx;
height: 40upx;
border-radius: 50%;
display: inline-block;
position: absolute;
right: 30upx;
}
.close-btn image {
width: 100%;
height: 100%;
}
.pop-m {
font-size: 28upx;
margin-bottom: 90upx;
}
.goods-specs,
.goods-number {
padding: 26upx;
border-top: 1px solid #f3f3f3;
}
.goods-specs:first-child {
border: none;
}
.pop-m-title {
margin-right: 10upx;
color: #666;
}
.pop-m-bd {
overflow: hidden;
margin-top: 10upx;
}
.pop-m-item {
display: inline-block;
float: left;
padding: 6upx 16upx;
background-color: #fff;
color: #333;
margin-right: 16upx;
margin-bottom: 10upx;
}
.selected {
border: 2upx solid #333;
background-color: #333;
color: #fff;
}
.not-selected {
border: 2upx solid #ccc;
}
.none {
border: 2upx dashed #ccc;
color: #888;
}
.pop-m-bd-in {
display: inline-block;
}
.badge {
top: 2upx;
left: 62upx;
}
.goods-assess .user-head-img {
width: 80upx;
height: 80upx;
border-radius: 50%;
}
.goods-assess .cell-item-bd {
padding-right: 0;
}
.goods-assess .cell-bd-text {
margin: 0;
}
.goods-assess .cell-bd-text.color-9 {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 440upx;
}
.gai-body {}
.gai-body-text {
font-size: 26upx;
color: #333;
padding: 0 26upx;
word-wrap: break-word;
}
.gai-body-img {
overflow: hidden;
padding: 20upx 26upx;
}
.gai-body-img image {
width: 220upx;
height: 220upx;
float: left;
margin-right: 19upx;
margin-bottom: 18upx;
}
.gai-body-img image:nth-child(3n) {
margin-right: 0;
}
.redstar {
width: 24rpx;
height: 24rpx;
padding: 2rpx;
}
.mask-share-wechat {
display: inline-block;
background-color: #fff;
padding: 0;
}
.mask-share-wechat:after {
border: none;
}
.right-ball {
position: fixed;
right: 30upx;
bottom: 300upx;
z-index: 999;
text-align: center;
padding: 14upx 0;
/* line-height: 80upx; */
width: 80upx;
height: 80upx;
font-size: 24upx;
color: #fff;
background-color: rgba(0, 0, 0, .5);
border-radius: 50%;
}
.share-pop {
height: 300upx;
width: 100%;
display: flex;
}
.share-item {
flex: 1;
text-align: center;
font-size: 26upx;
color: #333;
padding: 20upx 0;
}
/* .share-item image{
width: 120upx;
height: 120upx;
} */
.comment-none {
text-align: center;
padding: 200upx 0;
}
.comment-none-img {
width: 274upx;
height: 274upx;
}
.price-salesvolume {
width: 100%;
height: 112upx;
padding: 0 0 0 26upx;
overflow: hidden;
color: #A5A5A5;
background-color: rgb(252, 226, 80);
position: relative;
}
.commodity-price {
width: 224upx;
display: inline-block;
float: left;
}
.current-price {
font-size: 40upx;
color: #FF7159;
display: block;
line-height: 1.5;
}
.cost-price {
font-size: 26upx;
text-decoration: line-through;
/* margin-left: 8rpx; */
display: block;
}
.commodity-salesvolume {
width: 240upx;
display: inline-block;
font-size: 22upx;
float: left;
padding: 16upx 0;
}
.commodity-salesvolume>text {
display: block;
}
.commodity-time-img {
display: block;
width: 0;
height: 0;
border-width: 56upx 28upx 56upx 0;
border-style: solid;
border-color: transparent #FF7159 transparent transparent;
/*透明 黄 透明 透明 */
/* position: absolute; */
/* top: 0px; */
/* right: 260upx; */
float: right;
}
.commodity-time {
display: inline-block;
width: 220upx;
height: 100%;
text-align: center;
font-size: 24upx;
background-color: #FF7159;
padding: 16upx 0 18upx;
color: #FF7159;
float: right;
}
.commodity-time>text {
color: rgb(252, 226, 80);
}
.commodity-day>text {
display: inline-block;
background-color: rgb(255, 212, 176);
color: rgb(255, 115, 0);
padding: 0 6upx;
border-radius: 6upx;
}
.nav-back {
width: 100%;
height: 44px;
/* #ifndef MP-WEIXIN */
padding: 12px 12px 0;
/* #endif */
/* #ifdef MP-WEIXIN */
padding: 26px 12px 0;
/* #endif */
position: fixed;
top: 0;
background-color: rgba(255, 255, 255, 0);
z-index: 98;
}
.back-btn {
height: 32px;
width: 32px;
border-radius: 50%;
background-color: rgba(255, 255, 255, 0.8);
}
.back-btn .icon {
height: 20px;
width: 20px;
position: relative;
top: 50%;
left: 46%;
transform: translate(-50%, -50%);
}
.tl {
width: 70% !important;
}
.group-swiper {
/* padding: 20upx 26upx; */
}
.groupHeight {
height: 122upx !important;
}
.group-swiper-c {
height: 242upx;
}
.group-swiper-c .swiper-item .cell-item {
height: 50%;
}
.group-swiper-c .swiper-item .cell-item .user-head-img {
width: 80upx;
height: 80upx;
border-radius: 50%;
}
.group-swiper-c .swiper-item .cell-item .cell-hd-title {
position: absolute;
top: 50%;
left: 100upx;
transform: translateY(-50%);
max-width: 220upx;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.group-swiper-c .swiper-item .cell-item .cell-item-bd {
min-width: 150upx;
max-width: 200upx;
padding-right: 134upx;
text-align: center;
}
.group-swiper-c .swiper-item .cell-item .cell-item-bd .cell-bd-view {
margin-bottom: 0;
}
.group-swiper-c .swiper-item .cell-item .cell-item-bd .cell-bd-text {
float: none;
}
.group-swiper-c .commodity-day>text {
background: none !important;
padding: 0;
}
.group-swiper-c .swiper-item .cell-item .cell-item-ft .btn {
font-size: 26upx;
color: #fff;
background-color: #FF7159;
/* padding: 0; */
text-align: center;
}
.btn-content {
line-height: 1.2;
position: relative;
top: 49%;
transform: translateY(-50%);
}
.ig-top {
text-align: center;
background-color: #fff;
padding: 20upx 26upx;
width: 690upx;
min-height: 90upx;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.ig-top-t,
.ig-top-m {
margin-bottom: 20upx;
}
.ig-top-t>view {
display: inline-block;
padding: 0 10upx;
color: #999;
}
.user-head-img-c {
position: relative;
width: 80upx;
height: 80upx;
border-radius: 50%;
margin-right: 20upx;
box-sizing: border-box;
display: inline-block;
/* float: left; */
border: 1px solid #f3f3f3;
}
.user-head-img-tip {
position: absolute;
top: -6upx;
left: -10upx;
display: inline-block;
background-color: #FF7159;
color: #fff;
font-size: 22upx;
z-index: 98;
padding: 0 10upx;
border-radius: 10upx;
transform: scale(.8);
}
.user-head-img-c .user-head-img {
width: 100%;
height: 100%;
border-radius: 50%;
}
.user-head-img-c:first-child {
border: 1px solid #FF7159;
}
.uhihn {
width: 80upx;
height: 80upx;
border-radius: 50%;
display: inline-block;
border: 2upx dashed #e1e1e1;
text-align: center;
color: #d1d1d1;
font-size: 40upx;
box-sizing: border-box;
position: relative;
}
.uhihn>text {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.igtb-top {
font-size: 32upx;
color: #333;
margin-bottom: 16upx;
}
.igtb-mid {
margin-bottom: 16upx;
}
.igtb-mid .btn {
width: 100%;
background-color: #FF7159;
color: #fff;
}
.igtb-bot {
font-size: 24upx;
color: #666;
}
</style>
pintuan2.vue
<template>
<view class="content">
<view class="content-top">
<!-- 轮播图 -->
<view class='swiper'>
<swiper class="swiper-c" :indicator-dots="swiper.indicatorDots" :autoplay="swiper.autoplay" :interval="swiper.interval"
:duration="swiper.duration">
<swiper-item class="have-none" v-for="(item, index) in goodsInfo.album" :key="index" @click="clickImg(item)">
<image class='' :src='item' mode="aspectFill"></image>
</swiper-item>
</swiper>
</view>
<!-- 轮播图end -->
<view class='cell-group'>
<!-- 倒计时 -->
<view class='price-salesvolume' v-if="lasttime.hour!==false">
<view class='commodity-price'>
<text class='current-price'>¥{{ product.pintuan_price }}</text>
<text class='cost-price'>¥{{product.mktprice}}</text>
</view>
<view class='commodity-salesvolume'>
<text>已售{{goodsInfo.buy_count}}件/剩余{{product.stock}}件</text>
<text>累计销售{{goodsInfo.buy_count}}件</text>
</view>
<view class='commodity-time-img'></view>
<view class='commodity-time'>
<text>距结束仅剩</text>
<view class='commodity-day'>
<uni-countdown :day="lasttime.day" :hour="lasttime.hour" :minute="lasttime.minute" :second="lasttime.second"></uni-countdown>
</view>
</view>
<!-- <view class='commodity-time'>
已结束
</view> -->
</view>
<!-- 倒计时end -->
<!-- 分享 -->
<view class='cell-item goods-details'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>{{ product.name }}</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' @click="goShare()" src='../../../static/image/share.png'></image>
</view>
</view>
<!-- 分享end -->
<!-- 规格 -->
<view class='cell-item goods-title-item' v-if="isSpes">
<view class='cell-item-hd'>
<view class='cell-hd-title'>规格</view>
</view>
<view class='cell-item-bd' @click="toshow(2)">
<text class='cell-bd-text'>{{ product.spes_desc }}</text>
</view>
</view>
<!-- 规格end -->
<!-- 说明 -->
<view class='cell-item goods-title-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>说明</view>
</view>
<view class='cell-item-bd'>
<view class="cell-bd-view">
<image class="goods-title-item-ic" src="../../../static/image/ic-dui.png" mode=""></image>
<text class="cell-bd-text">24小时内发货</text>
</view>
<view class="cell-bd-view">
<image class="goods-title-item-ic" src="../../../static/image/ic-dui.png" mode=""></image>
<text class="cell-bd-text">7天拆封无条件退货</text>
</view>
</view>
</view>
<!-- 说明end -->
</view>
<!-- 团购拼单 -->
<view class="cell-group margin-cell-group" v-if="teamCount">
<view class='cell-item right-img'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>{{teamCount}}人在拼单,可直接参与</view>
</view>
<!-- <view class='cell-item-ft' >
<image class='cell-ft-next icon' src='../../../static/image/right.png'></image>
<text class='cell-ft-text'>查看更多</text>
</view> -->
</view>
<view class="group-swiper">
<swiper class="group-swiper-c" :indicator-dots="indicatorDots" :autoplay="autoplay" vertical="true" circular="true"
:interval="interval" :duration="duration">
<swiper-item v-for="(item, index) in teamList" :key="index">
<view class="swiper-item">
<view class='cell-item'>
<view class='cell-item-hd'>
<image class="user-head-img cell-hd-icon have-none" :src='item[0].avatar' mode=""></image>
<view class="cell-hd-title">
{{item[0].user_name}}
</view>
</view>
<view class='cell-item-bd'>
<view class="cell-bd-view">
<text class="cell-bd-text">还差<text class="red-price">{{item[0].peopleNums}}人</text>拼成</text>
</view>
<view class="cell-bd-view">
<view class='commodity-day'>
<uni-countdown :day="item[0].remainder_time.day" :hour="item[0].remainder_time.hour" :minute="item[0].remainder_time.minute"
:second="item[0].remainder_time.second"></uni-countdown>
</view>
</view>
</view>
<view class="cell-item-ft" v-if="!item[0].is_own">
<button class="btn" @click="toshow(1,item[0].id)">去拼单</button>
</view>
<view class="cell-item-ft" v-else>
<button class="btn btn-b">拼团中</button>
</view>
</view>
<view class='cell-item' v-if="item[1]">
<view class='cell-item-hd'>
<image class="user-head-img cell-hd-icon have-none" :src='item[1].avatar' mode=""></image>
<view class="cell-hd-title">
{{item[1].user_name}}
</view>
</view>
<view class='cell-item-bd'>
<view class="cell-bd-view">
<text class="cell-bd-text">还差<text class="red-price">{{item[1].peopleNums}}人</text>拼成</text>
</view>
<view class="cell-bd-view">
<view class='commodity-day'>
<uni-countdown :day="item[1].remainder_time.day" :hour="item[1].remainder_time.hour" :minute="item[1].remainder_time.minute"
:second="item[1].remainder_time.second"></uni-countdown>
</view>
</view>
</view>
<view class="cell-item-ft" v-if="!item[1].is_own">
<button class="btn" @click="toshow(1,item[1].id)">去拼单</button>
</view>
<view class="cell-item-ft" v-else>
<button class="btn btn-b">拼团中</button>
</view>
</view>
</view>
</swiper-item>
</swiper>
</view>
</view>
<view class="cell-group margin-cell-group" v-else>
<view class='cell-item right-img'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>暂无开团信息</view>
</view>
</view>
</view>
<view class="goods-content">
<uni-segmented-control :current="current" :values="items" @clickItem="onClickItem" style-type="text" active-color="#333"></uni-segmented-control>
<view class="goods-content-c">
<view class="goods-detail" v-if="current === 0">
<u-parse :content="goodsInfo.intro" />
</view>
<view class="goods-parameter" v-else-if="current === 1">
<view class='cell-group' v-if="goodsParams.length">
<view class='cell-item' v-for="(item, index) in goodsParams" :key="index">
<view class='cell-item-hd'>
<view class='cell-hd-title'>{{ item.name }}</view>
</view>
<view class='cell-item-bd'>
<text class='cell-bd-text'>{{ item.value }}</text>
</view>
</view>
</view>
</view>
<view class="goods-assess" v-else-if="current === 2">
<view v-if="goodsComments.list.length">
<view class="goods-assess-item" v-for="(item, index) in goodsComments.list" :key="index">
<view class='cell-group'>
<view class='cell-item goods-title-item'>
<view class='cell-item-hd'>
<image class='user-head-img' :src='item.user.avatar' mode="aspectFill"></image>
</view>
<view class='cell-item-bd'>
<view class="cell-bd-view">
<text class="cell-bd-text">{{ item.user.nickname }}</text>
<view class="cell-bd-text-right">
<uni-rate size="16" disabled="true" :value="item.score"></uni-rate>
</view>
</view>
<view class="cell-bd-view">
<text class="cell-bd-text color-9" style="margin-right: 16upx;">{{ item.ctime }}</text>
<text class="cell-bd-text color-9">{{ item.addon }}</text>
</view>
</view>
</view>
</view>
<view class="gai-body">
<view class="gai-body-text">
{{ item.content }}
</view>
<view class="gai-body-img" v-if="item.images_url.length">
<image :src="img" mode="aspectFill" v-for="(img, key) in item.images_url" :key="key" @click="clickImg(img)"></image>
</view>
</view>
</view>
<uni-load-more :status="goodsComments.loadStatus"></uni-load-more>
</view>
<view class="comment-none" v-else>
<image class="comment-none-img" src="../../../static/image/order.png" mode=""></image>
</view>
</view>
</view>
</view>
</view>
<!-- 弹出层 -->
<lvv-popup position="bottom" ref="share">
<!-- #ifdef H5 -->
<shareByH5 :shareType='3' :goodsId="goodsInfo.id" :groupId="groupInfo.id" :shareImg="goodsInfo.image_url"
:shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief" :shareHref="shareHref" @close="closeShare()"></shareByH5>
<!-- #endif -->
<!-- #ifdef MP-WEIXIN -->
<shareByWx :shareType='3' :goodsId="goodsInfo.id" :groupId="groupInfo.id" :shareImg="goodsInfo.image_url"
:shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief" :shareHref="shareHref" @close="closeShare()"></shareByWx>
<!-- #endif -->
<!-- #ifdef MP-ALIPAY -->
<shareByAli :shareType='3' :goodsId="goodsInfo.id" :groupId="groupInfo.id" :shareImg="goodsInfo.image_url"
:shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief" :shareHref="shareHref" @close="closeShare()"></shareByAli>
<!-- #endif -->
<!-- #ifdef APP-PLUS -->
<shareByApp :shareType='3' :goodsId="goodsInfo.id" :groupId="groupInfo.id" :shareImg="goodsInfo.image_url"
:shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief" :shareHref="shareHref" @close="closeShare()"></shareByApp>
<!-- #endif -->
</lvv-popup>
<!-- 弹出层 -->
<lvv-popup position="bottom" ref="lvvpopref">
<view style="width: 100%;max-height: 804upx;background: #FFFFFF;position: absolute;left:0;bottom: 0;">
<view class="pop-c">
<view class="pop-t">
<view class='goods-img'>
<image :src='product.image_path' mode='aspectFill'></image>
</view>
<view class='goods-information'>
<view class='pop-goods-name'>{{ product.name }}</view>
<view class='pop-goods-price red-price'>¥ {{ product.price }}</view>
</view>
<view class='close-btn' @click="toclose()">
<image src='../../../static/image/close.png'></image>
</view>
</view>
<scroll-view class="pop-m" scroll-y="true" style="max-height: 560upx;">
<spec :spesData="product.default_spes_desc" ref="spec" @changeSpes="changeSpes"></spec>
<view class="goods-number">
<text class="pop-m-title">数量</text>
<view class="pop-m-bd-in">
<uni-number-box :min="minNums" :max="product.stock" :value="buyNum" @change="bindChange"></uni-number-box>
</view>
</view>
</scroll-view>
<view class="pop-b" v-if="lvvpopref_type == 2">
<button class='btn btn-square btn-g btn-half' @click="buyNow(1)">单独购买¥ {{ product.price }}</button>
<button class='btn btn-square btn-b btn-half' @click="buyNow(2)">立即拼单¥ {{ product.pintuan_price }}</button>
</view>
<view class="pop-b" v-else>
<button class='btn btn-square btn-b' @click="buyNow1(2)">确定¥ {{ product.pintuan_price }}</button>
</view>
</view>
</view>
</lvv-popup>
<!-- 弹出层end -->
<!-- 底部按钮 -->
<view class="goods-bottom">
<view class="goods-bottom-ic" @click="collection">
<image class="icon" :src="isfav ? favLogo[1] : favLogo[0]" mode=""></image>
<view v-if="!isfav">收藏</view>
<view v-if="isfav">已收藏</view>
</view>
<view class="goods-bottom-ic" @click="redirectCart">
<view class="badge color-f" v-if="cartNums">{{ cartNums }}</view>
<image class="icon" src="../../../static/image/ic-me-car.png" mode=""></image>
<view>购物车</view>
</view>
<button class='btn btn-square btn-b tl' @click="toshow(2)" hover-class="btn-hover2">立即拼单</button>
</view>
<!-- 底部按钮end -->
<!-- 右边浮动球 -->
<uni-fab :pattern="pattern" :content="content" :horizontal="horizontal" :vertical="vertical" :direction="direction"
@trigger="trigger"></uni-fab>
</view>
</template>
<script>
import uniSegmentedControl from "@/components/uni-segmented-control/uni-segmented-control.vue";
import lvvPopup from '@/components/lvv-popup/lvv-popup.vue';
import uniNumberBox from "@/components/uni-number-box/uni-number-box.vue";
import uniRate from "@/components/uni-rate/uni-rate.vue";
import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue';
import uniFab from '@/components/uni-fab/uni-fab.vue';
import {
get
} from '@/config/db.js';
import {
apiBaseUrl
} from '@/config/config.js';
import {
pintuanUrl
} from '@/config/config.js';
import uniCountdown from "@/components/uni-countdown/uni-countdown.vue";
import uParse from '@/components/u-parse/u-parse.vue';
import spec from '@/components/spec/spec.vue';
import share from '@/components/share/share.vue';
// #ifdef H5
import shareByH5 from '@/components/share/shareByh5.vue'
// #endif
// #ifdef MP-WEIXIN
import shareByWx from '@/components/share/shareByWx.vue'
// #endif
// #ifdef MP-ALIPAY
import shareByAli from '@/components/share/shareByAli.vue'
// #endif
// #ifdef APP-PLUS
import shareByApp from '@/components/share/shareByApp.vue'
// #endif
import htmlParser from '@/common/html-parser'
export default {
components: {
uniSegmentedControl,
lvvPopup,
uniNumberBox,
uniRate,
uniLoadMore,
uniFab,
uniCountdown,
uParse,
share,
spec,
// #ifdef H5
shareByH5,
// #endif
// #ifdef MP-WEIXIN
shareByWx,
// #endif
// #ifdef MP-ALIPAY
shareByAli,
// #endif
// #ifdef APP-PLUS
shareByApp,
// #endif
},
data() {
return {
myShareCode: '', //分享Code
shareType: 0,
providerList: [], // 分享通道 包含生成海报
swiper: {
indicatorDots: true,
autoplay: true,
interval: 3000,
duration: 800,
}, // 轮播图属性设置
items: ['图文详情', '商品参数', '买家评论'],
current: 0, // init tab位
goodsId: 0, // 商品id
groupId: 0, // 拼团ID
cartNums: 0, // 购物车数量
groupInfo: {}, // 拼团详情
goodsInfo: {}, //商品详情
teamList: [], //团队列表
teamCount: 0, //开团团数
product: {}, // 规格详情
goodsParams: [], // 商品参数信息
goodsComments: {
loadStatus: 'more',
page: 1,
limit: 5,
list: []
}, // 商品评论信息
buyNum: 1, // 选定的购买数量
minBuyNum: 1, // 最小可购买数量
type: 2, // 1加入购物车 2购买
isfav: false, // 商品是否收藏
favLogo: [
'../../../static/image/ic-me-collect.png',
'../../../static/image/ic-me-collect2.png'
],
horizontal: 'right', //右下角弹出按钮
vertical: 'bottom',
direction: 'vertical',
pattern: {
color: '#7A7E83',
backgroundColor: '#fff',
selectedColor: '#007AFF',
buttonColor: "#FF7159"
},
content: [{
iconPath: '../../../static/image/tab-ic-hom-selected.png',
selectedIconPath: '../../../static/image/tab-ic-hom-unselected.png',
// text: '首页',
active: false,
url: '/pages/index/index'
},
{
iconPath: '../../../static/image/tab-ic-me-selected.png',
selectedIconPath: '../../../static/image/tab-ic-me-unselected.png',
// text: '个人中心',
active: false,
url: '/pages/member/index/index'
},
],
indicatorDots: false,
autoplay: false,
interval: 2000,
duration: 500,
lasttime: {
hour: false,
minute: 0,
second: 0
},
lvvpopref_type: 2,
team_id: 0, //团id
userToken: 0,
invite: 0 //邀请人的团Id
}
},
onLoad(e) {
this.goodsId = e.id;
this.groupId = e.group_id;
//获取拼团id,商品ID
if (this.goodsId && this.groupId) {
this.getPintuanInfo(groupId);
this.getTeam(groupId);
this.getGoodsParams();
this.getGoodsComments();
} else {
this.$common.errorToShow('获取失败', () => {
uni.navigateBack({
delta: 1
});
});
}
// 获取购物车数量
this.getCartNums();
this.getMyShareCode();
},
computed: {
// 规格切换计算规格商品的 可购买数量
minNums() {
return this.product.stock > this.minBuyNum ? this.minBuyNum : this.product.stock;
},
// 判断商品是否是多规格商品 (为了兼容小程序 只能写在计算属性里面了)
isSpes() {
if (this.product.hasOwnProperty('default_spes_desc') && Object.keys(this.product.default_spes_desc).length) {
return true;
} else {
return false;
}
},
// 优惠信息重新组装
promotion() {
let arr = [];
if (this.product.promotion_list) {
for (let k in this.product.promotion_list) {
arr.push(this.product.promotion_list[k]);
}
}
return arr;
},
shareHref() {
let pages = getCurrentPages()
let page = pages[pages.length - 1]
// #ifdef H5 || MP-WEIXIN || APP-PLUS || APP-PLUS-NVUE
return apiBaseUrl + 'wap/#/' + page.route + '?id=' + this.goodsId + '&group_id=' + this.groupId;
// #endif
// #ifdef MP-ALIPAY
return apiBaseUrl + 'wap/#/' + page.__proto__.route + '?id=' + this.goodsId + '&group_id=' + this.groupId;
// #endif
}
},
onReachBottom() {
if (this.current === 2 && this.goodsComments.loadStatus === 'more') {
this.getGoodsComments();
}
},
methods: {
// 关闭弹出层
close() {
this.$emit('close')
},
// 点击操作
clickHandler(e) {
if (e.cate === 'poster') {
this.createPoster()
} else {
// 去分享
this.share(e)
}
},
// 购物车页面跳转
redirectCart() {
uni.switchTab({
url: '/pages/cart/index/index'
});
},
//开团列表
getTeam(id) {
uni.showLoading({
title: '加载中'
});
let userToken = this.$db.get("userToken");
if (userToken && userToken != '') {
this.userToken = userToken;
}
uni.request({
url: this.$config.pintuanUrl + 'getTeam',
header: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
method: 'POST',
data: {
rule_id: id,
token: this.userToken
},
success: (res) => {
uni.hideLoading();
if (res.data.status) {
let data = res.data.data;
let new_data = new Array();
for (var k = 0; k < data.length; k++) {
if (k == 0 || k % 2 == 0) {
if (k + 1 < data.length) {
var a = [
data[k],
data[k + 1]
];
} else {
var a = [data[k]];
}
new_data.push(a);
}
}
//console.log(new_data);
this.teamList = new_data;
this.teamCount = res.data.count;
}
},
fail: (error) => {
uni.hideLoading();
if (error && error.response) {
this.$common.showError(error.response);
}
},
});
},
//拼团信息
getPintuanInfo(id) {
uni.showLoading({
title: '加载中'
});
uni.request({
url: this.$config.pintuanUrl + 'getPintuanInfo',
header: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
method: 'POST',
data: {
id: id
},
success: (res) => {
uni.hideLoading();
if (res.data.status) {
if (res.data.data.length < 1) {
this.$common.errorToShow('该拼团活动不存在,请返回重新选择。', () => {
uni.navigateBack({
delta: 1
});
});
}
// else if (res.data.data.goods_info.goodmarketable != 1){
// this.$common.errorToShow('该商品已下架,请返回重新选择商品。', () => {
// uni.navigateBack({
// delta: 1
// });
// });
// }
else {
this.groupInfo = res.data.data;
this.product = res.data.data.goods_info.product;
this.goodsInfo = this.groupInfo.goods_info;
let price = this.product.price;
if (price > 0) {
this.product.price = price;
} else {
this.product.price = 0.00;
}
this.product = this.spesClassHandle(this.product);
this.lasttime = res.data.data.lasttime;
}
}
},
fail: (error) => {
uni.hideLoading();
if (error && error.response) {
this.$common.showError(error.response);
}
},
});
},
// 获取购物车数量
getCartNums() {
let userToken = this.$db.get("userToken");
if (userToken && userToken != '') {
// 获取购物车数量
this.$api.getCartNum({}, res => {
if (res.status) {
this.cartNums = res.data;
}
});
}
},
// 显示modal弹出框
toshow(type, team_id = 0) {
if (type == 1) {
this.lvvpopref_type = 1;
}
if (type == 2) {
this.lvvpopref_type = 2;
}
if (team_id !== 0) {
this.team_id = team_id;
}
this.$refs.lvvpopref.show();
},
// 关闭modal弹出框
toclose() {
this.$refs.lvvpopref.close();
},
// 切换商品规格
changeSpes(obj) {
//console.log(obj);
let index = obj.v;
let key = obj.k;
if (this.product.default_spes_desc[index][key].hasOwnProperty('product_id') && this.product.default_spes_desc[index]
[key].product_id) {
uni.showLoading({
title: '加载中'
});
uni.request({
url: this.$config.pintuanUrl + 'getProductInfo',
header: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
method: 'POST',
data: {
id: this.product.default_spes_desc[index][key].product_id,
discount_amount: this.groupInfo.discount_amount
},
success: (res) => {
uni.hideLoading();
if (res.data.status) {
// 切换规格判断可购买数量
this.buyNum = res.data.data.stock > this.minBuyNum ? this.minBuyNum : res.data.data.stock;
this.product = this.spesClassHandle(res.data.data);
}
},
fail: (error) => {
uni.hideLoading();
if (error && error.response) {
this.$common.showError(error.response);
}
},
});
setTimeout(function() {
uni.hideLoading();
}, 1000);
}
},
// 多规格样式统一处理
spesClassHandle(products) {
// 判断是否是多规格 (是否有默认规格)
if (products.hasOwnProperty('default_spes_desc')) {
let spes = products.default_spes_desc;
for (let key in spes) {
for (let i in spes[key]) {
if (spes[key][i].hasOwnProperty('is_default') && spes[key][i].is_default === true) {
this.$set(spes[key][i], 'cla', 'pop-m-item selected');
} else if (spes[key][i].hasOwnProperty('product_id') && spes[key][i].product_id) {
this.$set(spes[key][i], 'cla', 'pop-m-item not-selected');
} else {
this.$set(spes[key][i], 'cla', 'pop-m-item none');
}
}
}
products.default_spes_desc = spes;
}
return products;
},
// 购买数量加减操作
bindChange(val) {
this.buyNum = val;
},
// 商品收藏/取消
collection() {
let data = {
goods_id: this.goodsId
}
this.$api.goodsCollection(data, res => {
if (res.status) {
this.isfav = !this.isfav;
this.$common.successToShow(res.msg);
} else {
this.$common.errorToShow(res.msg);
}
})
},
// tab点击切换
onClickItem(index) {
if (this.current !== index) {
this.current = index;
}
},
// 获取商品参数信息
getGoodsParams() {
this.$api.goodsParams({
id: this.goodsId
}, res => {
if (res.status == true) {
this.goodsParams = res.data;
}
})
},
// 获取商品评论信息
getGoodsComments() {
let data = {
page: this.goodsComments.page,
limit: this.goodsComments.limit,
goods_id: this.goodsId
}
this.goodsComments.loadStatus = 'loading';
this.$api.goodsComment(data, res => {
if (res.status == true) {
let _list = res.data.list;
// 如果评论没有图片 在这块作处理否则控制台报错
_list.forEach(item => {
item.ctime = this.$common.timeToDate(item.ctime)
if (!item.hasOwnProperty('images_url')) {
this.$set(item, 'images_url', [])
}
});
this.goodsComments.list = [...this.goodsComments.list, ..._list];
// 根据count数量判断是否还有数据
if (res.data.count > this.goodsComments.list.length) {
this.goodsComments.loadStatus = 'more';
this.goodsComments.page++;
} else {
this.goodsComments.loadStatus = 'noMore';
}
} else {
this.$common.errorToShow(res.msg);
}
})
},
// 添加商品浏览足迹
goodsBrowsing() {
let data = {
goods_id: this.goodsInfo.id
}
this.$api.addGoodsBrowsing(data, res => {});
},
// 立即购买
buyNow(card_type) {
if (this.buyNum > 0) {
let data = {
product_id: this.product.id,
nums: this.buyNum,
type: 2, // 区分加入购物车和购买,
}
if (card_type == 2) {
data['cart_type'] = 2;
}
this.$api.addCart(data, res => {
if (res.status) {
this.toclose();
let cartIds = res.data;
if (card_type == 1) {
this.$common.navigateTo('/pages/goods/place-order/index?cart_ids=' + JSON.stringify(cartIds));
} else {
if (this.invite != 0) {
this.$common.navigateTo('/pages/goods/place-order/index?cart_ids=' + JSON.stringify(cartIds) +
'&cart_type=2&team_id=' + this.invite);
} else {
this.$common.navigateTo('/pages/goods/place-order/index?cart_ids=' + JSON.stringify(cartIds) +
'&cart_type=2');
}
}
}
})
}
},
// 立即购买
buyNow1(card_type) {
if (this.buyNum > 0) {
let data = {
product_id: this.product.id,
nums: this.buyNum,
type: 2, // 区分加入购物车和购买,
}
if (card_type == 2) {
data['cart_type'] = 2;
}
this.$api.addCart(data, res => {
if (res.status) {
this.toclose();
let cartIds = res.data;
if (this.team_id != 0) {
this.$common.navigateTo('/pages/goods/place-order/index?cart_ids=' + JSON.stringify(cartIds) +
'&cart_type=2&team_id=' + this.team_id);
} else {
this.$common.navigateTo('/pages/goods/place-order/index?cart_ids=' + JSON.stringify(cartIds) + '&cart_type=2');
}
}
})
}
},
trigger(e) {
this.content[e.index].active = !e.item.active;
uni.switchTab({
url: e.item.url
})
},
// 跳转到h5分享页面
goShare() {
this.$refs.share.show();
},
closeShare() {
this.$refs.share.close();
},
// 图片点击放大
clickImg(imgs) {
// 预览图片
uni.previewImage({
urls: imgs.split()
});
},
getMyShareCode() {
let userToken = this.$db.get("userToken");
if (userToken && userToken != '') {
// 获取我的分享码
this.$api.shareCode({}, res => {
if (res.status) {
this.myShareCode = res.data ? res.data : '';
}
});
}
}
},
//分享
onShareAppMessage() {
let myInviteCode = this.myShareCode ? this.myShareCode : '';
let ins = encodeURIComponent('type=5&id=' + this.goodsId + '&group_id=' + this.groupId + '&invite=' + myInviteCode);
let path = '/pages/share/jump?scene=' + ins;
return {
title: this.goodsInfo.name,
// #ifdef MP-ALIPAY
desc: this.goodsInfo.brief,
// #endif
imageUrl: this.goodsInfo.album[0],
path: path
}
}
}
</script>
<style>
.swiper {
height: 750upx;
}
.goods-top {
border-bottom: 0;
}
.goods-top .goods-price {
font-size: 38upx;
}
.cost-price {
font-size: 28upx !important;
bottom: -10upx;
color: #999;
text-decoration: line-through;
}
.goods-top .cell-item-ft {
font-size: 20upx;
color: #666;
}
.goods-details {
padding-top: 16upx;
}
.goods-details .cell-hd-title {
width: 620upx;
color: #333;
font-size: 26upx;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
.goods-details .cell-item-ft {
top: 40%;
}
.goods-title-item .cell-item-hd {
min-width: 60upx;
color: #666;
font-size: 24upx;
}
.goods-title-item .cell-item-bd {
color: #333;
font-size: 24upx;
}
.goods-title-item .cell-bd-text {
bottom: 0;
}
.cell-bd-view {
position: relative;
overflow: hidden;
}
.cell-bd-view:first-child {
margin-bottom: 8upx;
}
.goods-title-item-ic {
width: 22upx;
height: 22upx;
position: absolute;
top: 50%;
transform: translateY(-50%);
/* #ifdef MP-ALIPAY */
background-size: 100% 100%;
/* #endif */
}
.cell-bd-view .cell-bd-text {
margin-left: 30upx;
}
.goods-content {
margin-top: 26upx;
background-color: #fff;
padding: 26upx 0;
}
.goods-content-c {}
.goods-parameter {
padding: 10upx 26upx;
}
.goods-bottom,
.pop-b {
background-color: #fff;
position: fixed;
bottom: 0;
height: 90upx;
width: 100%;
overflow: hidden;
display: flex;
box-shadow: 0 0 20upx #ccc;
}
.pop-b button {
flex: 1;
}
.goods-bottom button {
height: 100%;
width: 35%;
}
.goods-bottom-ic {
display: inline-block;
position: relative;
text-align: center;
height: 100%;
width: 15%;
float: left;
font-size: 22upx;
color: #666;
}
.goods-bottom-ic .icon {
position: relative;
top: 6upx;
/* left: -6upx; */
/* #ifdef MP-ALIPAY */
background-size: 100% 100%;
/* #endif */
}
.goods-bottom .btn-g {
color: #333;
background-color: #D9D9D9;
}
.goods-parameter .cell-item {
border-bottom: none;
margin-left: 0;
}
.goods-parameter .cell-item-hd {
color: #333;
font-size: 24upx;
}
.goods-parameter .cell-item-bd {
color: #999;
}
.goods-parameter .cell-item-bd .cell-bd-text {
bottom: 0;
}
.goods-parameter .cell-bd-text {
margin-left: 0;
}
.pop-t {
position: relative;
padding: 30upx 26upx;
border-bottom: 2upx solid #f3f3f3;
/* box-shadow: 0 0 20upx #ccc; */
}
.goods-img {
width: 160upx;
height: 160upx;
position: absolute;
top: -20upx;
background-color: #fff;
border-radius: 6upx;
border: 2upx solid #fff;
}
.goods-img image {
height: 100%;
width: 100%;
}
.goods-information {
width: 420upx;
display: inline-block;
margin-left: 180upx;
}
.pop-goods-name {
width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
display: block;
font-size: 24upx;
margin-bottom: 20upx;
}
.pop-goods-price {
font-size: 30upx;
}
.close-btn {
width: 40upx;
height: 40upx;
border-radius: 50%;
display: inline-block;
position: absolute;
right: 30upx;
}
.close-btn image {
width: 100%;
height: 100%;
}
.pop-m {
font-size: 28upx;
margin-bottom: 90upx;
}
.goods-specs,
.goods-number {
padding: 26upx;
border-top: 1px solid #f3f3f3;
}
.goods-specs:first-child {
border: none;
}
.pop-m-title {
margin-right: 10upx;
color: #666;
}
.pop-m-bd {
overflow: hidden;
margin-top: 10upx;
}
.pop-m-item {
display: inline-block;
float: left;
padding: 6upx 16upx;
background-color: #fff;
color: #333;
margin-right: 16upx;
margin-bottom: 10upx;
}
.selected {
border: 2upx solid #333;
background-color: #333;
color: #fff;
}
.not-selected {
border: 2upx solid #ccc;
}
.none {
border: 2upx dashed #ccc;
color: #888;
}
.pop-m-bd-in {
display: inline-block;
}
.badge {
top: 2upx;
left: 62upx;
}
.goods-assess .user-head-img {
width: 80upx;
height: 80upx;
border-radius: 50%;
}
.goods-assess .cell-item-bd {
padding-right: 0;
}
.goods-assess .cell-bd-text {
margin: 0;
}
.goods-assess .cell-bd-text.color-9 {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 440upx;
}
.gai-body {}
.gai-body-text {
font-size: 26upx;
color: #333;
padding: 0 26upx;
}
.gai-body-img {
overflow: hidden;
padding: 20upx 26upx;
}
.gai-body-img image {
width: 220upx;
height: 220upx;
float: left;
margin-right: 19upx;
margin-bottom: 18upx;
}
.gai-body-img image:nth-child(3n) {
margin-right: 0;
}
.redstar {
width: 24rpx;
height: 24rpx;
padding: 2rpx;
}
.mask-share-wechat {
display: inline-block;
background-color: #fff;
padding: 0;
}
.mask-share-wechat:after {
border: none;
}
.right-ball {
position: fixed;
right: 30upx;
bottom: 300upx;
z-index: 999;
text-align: center;
padding: 14upx 0;
/* line-height: 80upx; */
width: 80upx;
height: 80upx;
font-size: 24upx;
color: #fff;
background-color: rgba(0, 0, 0, .5);
border-radius: 50%;
}
.share-pop {
height: 300upx;
width: 100%;
display: flex;
}
.share-item {
flex: 1;
text-align: center;
font-size: 26upx;
color: #333;
padding: 20upx 0;
}
.share-item image {
width: 120upx;
height: 120upx;
}
.share-item .btn {
line-height: 1;
display: block;
font-size: 26upx;
background-color: #fff;
}
.comment-none {
text-align: center;
padding: 200upx 0;
}
.comment-none-img {
width: 274upx;
height: 274upx;
}
.price-salesvolume {
width: 100%;
padding: 0 0 0 26upx;
overflow: hidden;
color: #A5A5A5;
background-color: rgb(252, 226, 80);
position: relative;
}
.commodity-price {
width: 224upx;
display: inline-block;
float: left;
}
.current-price {
font-size: 40upx;
color: #FF7159;
display: block;
line-height: 1.5;
}
.cost-price {
font-size: 26upx;
text-decoration: line-through;
/* margin-left: 8rpx; */
display: block;
}
.commodity-salesvolume {
width: 240upx;
display: inline-block;
font-size: 22upx;
float: left;
padding: 16upx 0;
}
.commodity-salesvolume>text {
display: block;
}
.commodity-time-img {
display: block;
width: 0;
height: 0;
border-width: 56upx 28upx 56upx 0;
border-style: solid;
border-color: transparent #FF7159 transparent transparent;
/*透明 黄 透明 透明 */
position: absolute;
top: 0px;
left: 462upx;
}
.commodity-time {
display: inline-block;
width: 260upx;
text-align: center;
font-size: 24upx;
background-color: #FF7159;
padding: 16upx 0 18upx;
color: #FF7159;
}
.commodity-time>text {
color: rgb(252, 226, 80);
}
.commodity-day>text {
display: inline-block;
background-color: rgb(255, 212, 176);
color: rgb(255, 115, 0);
padding: 0 6upx;
border-radius: 6upx;
}
.tl {
width: 70% !important;
}
.group-swiper {
/* padding: 20upx 26upx; */
}
.group-swiper-c {
height: 242upx;
}
.group-swiper-c .swiper-item .cell-item {
height: 50%;
}
.group-swiper-c .swiper-item .cell-item .user-head-img {
width: 80upx;
height: 80upx;
border-radius: 50%;
}
.group-swiper-c .swiper-item .cell-item .cell-hd-title {
position: absolute;
top: 50%;
left: 100upx;
transform: translateY(-50%);
max-width: 260upx;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.group-swiper-c .swiper-item .cell-item .cell-item-bd {
min-width: 150upx;
max-width: 150upx
}
.group-swiper-c .swiper-item .cell-item .cell-item-ft .btn {
font-size: 26upx;
color: #fff;
background-color: #FF7159;
/* padding: 0; */
text-align: center;
}
.price-salesvolume .commodity-day .uni-countdown__splitor {
color: rgb(252, 226, 80);
}
.group-swiper .commodity-day .uni-countdown__splitor {
color: #666;
}
@import url('@/components/u-parse/u-parse.css')
</style>
payment
auth.vue
<template>
<view class="content">
<view class="content-c">
<image class="load-img" src="/static/image/loading.gif" mode=""></image>
<view class="load-text color-9">信息加载中.....</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
type: '',
openid: '',
orderId: '',
state: ''
}
},
onLoad(options) {
this.orderId = options.order_id
this.money = Number(options.money)
this.type = Number(options.type)
this.uid = Number(options.uid)
this.state = this.$common.getQueryString('state')
this.getCode()
},
methods: {
getCode() {
var code = this.$common.getQueryString('code')
code && this.getOpenId(code)
},
getOpenId(code) {
let data = {
code: code,
scope: 2,
state: this.state
}
//模拟接口
this.$api.getOpenId(data, res => {
if (res.status) {
this.openid = res.data.openid
this.toPayHandler('wechatpay')
} else {
this.$common.errorToShow(res.msg)
}
})
},
checkWXJSBridge(data) {
let that = this
let interval = setInterval(() => {
if (typeof window.WeixinJSBridge != 'undefined') {
clearTimeout(interval)
that.onBridgeReady(data)
}
}, 200)
},
onBridgeReady(data) {
var _this = this
window.WeixinJSBridge.invoke(
'getBrandWCPayRequest',
{
appId: data.appid, // 公众号名称,由商户传入
timeStamp: data.timeStamp, // 时间戳,自1970年以来的秒数
nonceStr: data.nonceStr, // 随机串
package: data.package,
signType: data.signType, // 微信签名方式:
paySign: data.paySign // 微信签名
},
function(res) {
if (res.err_msg === 'get_brand_wcpay_request:ok') {
_this.$common.successToShow('支付成功')
} else if (res.err_msg === 'get_brand_wcpay_request:cancel') {
_this.$common.errorToShow('取消支付')
} else {
_this.$common.errorToShow('支付失败')
}
setTimeout(() => {
_this.$common.redirectTo(
'/pages/goods/payment/result?id=' + data.payment_id
)
},1000)
}
)
},
toPayHandler(code) {
let data = {
payment_code: code,
payment_type: this.type
}
data['ids'] = (this.type == 1 || this.type == 5 || this.type == 6) ? this.orderId : this.uid
//data['ids'] = this.type == 1 ? this.orderId : this.uid
if (this.type == 1 && this.orderId) {
// 微信jsapi支付
if (this.openid) {
data['params'] = {
trade_type: 'JSAPI_OFFICIAL',
openid: this.openid
}
}
} else if (this.type == 2 && this.money) {
if (this.openid) {
data['params'] = {
trade_type: 'JSAPI_OFFICIAL',
money: this.money,
openid: this.openid
}
}
}else if ((this.type == 5 || this.type == 6) && this.recharge) {
data['params'] = {
trade_type: 'JSAPI_OFFICIAL',
openid: this.openid,
formid: this.orderId
}
}
this.$api.pay(data, res => {
if (res.status) {
const data = res.data
this.checkWXJSBridge(data)
} else {
this.$common.errorToShow(res.msg)
}
})
}
}
}
</script>
<style>
.content {
position: relative;
height: 80vh;
}
.content-c {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
}
.load-img {
width: 100upx;
height: 100upx;
}
.load-text {
font-size: 26upx;
}
</style>
index.vue
<template>
<view class="content">
<view class='cell-group margin-cell-group'>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>订单类型</view>
</view>
<view class='cell-item-ft'>
<text class="cell-ft-p" v-if="type == 1" @click="orderDetail(orderId)">商品订单</text>
<text class="cell-ft-p" v-if="type == 2" @click="toRecharge()">充值订单</text>
<text class="cell-ft-p" v-if="type == 5" >快捷下单</text>
<text class="cell-ft-p" v-if="type == 6" >付款码</text>
</view>
</view>
<view v-if="type == 1">
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>订单编号</view>
</view>
<view class='cell-item-ft'>
<text class="cell-ft-p" @click="orderDetail(orderId)">{{ orderId }}</text>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>订单金额</view>
</view>
<view class='cell-item-ft'>
<text class="cell-ft-p red-price">¥{{ orderInfo.order_amount }}</text>
</view>
</view>
</view>
<view v-else-if="type == 2">
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>充值金额</view>
</view>
<view class='cell-item-ft'>
<text class="cell-ft-p red-price">¥ {{ recharge }}</text>
</view>
</view>
</view>
</view>
<!-- #ifdef H5 -->
<payments-by-h5
:orderId="orderId"
:recharge="recharge"
:type="type"
:uid="userInfo.id"
></payments-by-h5>
<!-- #endif -->
<!-- #ifdef MP-WEIXIN -->
<payments-by-wx
:orderId="orderId"
:recharge="recharge"
:type="type"
:uid="userInfo.id"
></payments-by-wx>
<!-- #endif -->
<!-- #ifdef MP-ALIPAY -->
<payments-by-ali
:orderId="orderId"
:recharge="recharge"
:type="type"
:uid="userInfo.id"
></payments-by-ali>
<!-- #endif -->
<!-- #ifdef APP-PLUS||APP-PLUS-NVUE -->
<payments-by-app
:orderId="orderId"
:recharge="recharge"
:type="type"
:uid="userInfo.id"
></payments-by-app>
<!-- #endif -->
</view>
</template>
<script>
// #ifdef H5
import paymentsByH5 from '@/components/payments/paymentsByH5.vue'
// #endif
// #ifdef MP-WEIXIN
import paymentsByWx from '@/components/payments/paymentsByWx.vue'
// #endif
// #ifdef MP-ALIPAY
import paymentsByAli from '@/components/payments/paymentsByAli.vue'
// #endif
// #ifdef APP-PLUS||APP-PLUS-NVUE
import paymentsByApp from '@/components/payments/paymentsByApp.vue'
// #endif
import { orders } from '@/config/mixins.js'
export default {
mixins: [orders],
data () {
return {
orderId: 0,
recharge: 0,
type: 1, // 订单类型 1商品订单 2充值订单
orderInfo: {}, // 订单详情
userInfo: {}, // 用户信息
form_id:0
}
},
components: {
// #ifdef H5
paymentsByH5,
// #endif
// #ifdef MP-WEIXIN
paymentsByWx,
// #endif
// #ifdef MP-ALIPAY
paymentsByAli,
// #endif
// #ifdef APP-PLUS||APP-PLUS-NVUE
paymentsByApp,
// #endif
},
onLoad (options) {
this.orderId = options.order_id
this.recharge = Number(options.recharge)
this.type = Number(options.type)
this.form_id = Number(options.form_id)
if (this.orderId && this.type == 1) {
// 商品订单
this.getOrderInfo()
} else if (this.recharge && this.type == 2) {
// 充值订单 获取用户id
this.getUserInfo()
} else if (this.form_id && (this.type == 5 || this.type == 6)) {
// 表单订单 id传到订单上
this.orderId = ''+this.form_id;
} else {
this.$common.errorToShow('订单支付参数错误', () => {
uni.navigateBack({
delta: 1
})
})
}
},
methods: {
// 获取订单详情
getOrderInfo () {
let data = {
order_id: this.orderId
}
this.$api.orderDetail(data, res => {
if (res.status) {
this.orderInfo = res.data
if(this.orderInfo.pay_status == 2){
this.$common.redirectTo(
'/pages/goods/payment/result?order_id=' + this.orderInfo.order_id
)
}
}
})
},
// 获取用户信息
getUserInfo () {
this.$api.userInfo({}, res => {
if (res.status) {
this.userInfo = res.data
} else {
this.$common.errorToShow(res.msg)
}
})
},
// 跳转我的余额页面
toRecharge () {
this.$common.navigateTo('/pages/member/balance/index')
}
}
}
</script>
<style>
.margin-cell-group{
margin-bottom: 20upx;
}
.cell-hd-title{
color: #999;
}
.payment-method .cell-item-hd{
min-width: 70upx;
}
.payment-method .cell-hd-icon{
width: 70upx;
height: 70upx;
}
.payment-method .cell-item-bd{
border-left: 2upx solid #F0F0F0;
padding-left: 30upx;
}
.payment-method .cell-bd-text{
font-size: 28upx;
color: #666;
}
.payment-method .address{
font-size: 24upx;
color: #999;
}
</style>
result.vue
<template>
<view class="content">
<view class="result succsee" v-if="status && paymentInfo.status === 2">
<image class="result-img" src="/static/image/win.png" mode=""></image>
<view class="result-top">
支付成功
</view>
<view class="result-mid red-price">
{{ paymentInfo.money }}
</view>
<view class="result-bot">
<button class="btn btn-g" @click="orderDetail()">查看详情</button>
</view>
</view>
<view class="result fail" v-else-if="status && paymentInfo.status === 1">
<image class="result-img" src="/static/image/pastdue.png" mode=""></image>
<view class="result-top">
支付失败
</view>
<view class="result-mid red-price">
{{ paymentInfo.money }}
</view>
<view class="result-bot">
<button class="btn btn-g" @click="orderDetail()">查看详情</button>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
paymentId: 0,
paymentInfo: {}, // 支付单详情
orderId: 0,
status: false
}
},
onLoad(options) {
if (options.id) {
this.paymentId = options.id
}
if (options.order_id) {
this.orderId = options.order_id
}
},
mounted() {
this.getPaymentInfo()
},
methods: {
getPaymentInfo() {
if (!this.paymentId) {
this.status = true;
this.paymentInfo.money = '0.00'
this.paymentInfo.status = 2;
this.paymentInfo.type = 1;
return
}
let data = {
payment_id: this.paymentId
}
this.$api.paymentInfo(data, res => {
if (res.status) {
let info = res.data
if (info.payment_code === 'alipay') {
info.payment_name = '支付宝支付'
} else if (info.payment_code === 'wechatpay') {
info.payment_name = '微信支付'
} else if (info.payment_code === 'balancepay') {
info.payment_name = '余额支付'
}
// 获取订单号
if (info.rel.length) {
for (let i = 0; i < info.rel.length; i++) {
if (info.rel[i].source_id) {
this.orderId = info.rel[i].source_id
break;
}
}
}
this.status = true;
this.paymentInfo = info
} else {
this.$common.errorToShow(res.msg)
}
})
},
orderDetail() {
if (this.orderId && this.paymentInfo.type === 1) {
this.$common.redirectTo('/pages/member/order/orderdetail?order_id=' + this.orderId)
} else if (this.paymentInfo.type === 2) {
this.$common.redirectTo('/pages/member/balance/details')
} else if (this.paymentInfo.type === 5 || this.paymentInfo.type === 6) {
uni.switchTab({
url: '/pages/index/index'
});
}
}
}
}
</script>
<style>
.result {
text-align: center;
padding-top: 200upx;
}
.result-img {
width: 140upx;
height: 140upx;
margin-bottom: 20upx;
}
.result-num {
color: #666;
font-size: 30upx;
margin-bottom: 20upx;
}
.result-top {
color: #666;
font-size: 30upx;
margin-bottom: 20upx;
}
.result-mid {
margin-bottom: 60upx;
}
.result-bot .btn {
margin-top: 40upx;
font-size: 26upx;
padding: 0 50upx;
}
</style>
place-order
index.vue
<template>
<form class="content" @submit="toPay" report-submit="true">
<view class="content-top">
<uni-segmented-control :current="type_current" :values="type_items" @clickItem="onTypeItem" style-type="text" active-color="#333" v-if="storeSwitch == 1"></uni-segmented-control>
<view class="content">
<view v-show="type_current === 0">
<!-- 收货地址信息 -->
<view class='cell-group margin-cell-group' v-if="userShip.id" @click="showAddressList">
<view class='cell-item add-title-item right-img'>
<view class='cell-item-hd'>
<image class='cell-hd-icon' src='/static/image/location.png'></image>
</view>
<view class='cell-item-bd'>
<view class="cell-bd-view">
<text class="cell-bd-text">收货人:{{ userShip.name }}</text>
<text class="cell-bd-text-right">{{ userShip.mobile }}</text>
</view>
<view class="cell-bd-view">
<text class="cell-bd-text address">{{ userShip.area_name }}</text>
</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
</view>
<view class="cell-group margin-cell-group" v-else>
<view class='cell-item add-title-items'>
<button class="btn btn-b" @click="goAddress()" hover-class="btn-hover2">添加收货地址</button>
</view>
</view>
</view>
<view v-show="type_current === 1">
<!-- 门店信息 -->
<view v-if="store.id != 0" class='cell-group margin-cell-group' @click="goStorelist()">
<view class='cell-item add-title-item right-img'>
<view class='cell-item-hd'>
<image class='cell-hd-icon' src='/static/image/homepage.png'></image>
</view>
<view class='cell-item-bd'>
<view class="cell-bd-view">
<text class="cell-bd-text">{{store.name}}</text>
<text class="cell-bd-text-right">{{store.mobile}}</text>
</view>
<view class="cell-bd-view">
<text class="cell-bd-text address">{{store.address}}</text>
</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
</view>
<view v-else class='cell-group margin-cell-group'>
<view class='cell-item add-title-item right-img no-store'>暂无门店</view>
</view>
</view>
</view>
<view class='cell-group margin-cell-group' v-if="storeSwitch == 1 && type_current === 1">
<view class='cell-item user-head'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>姓名</view>
</view>
<view class='cell-item-bd'>
<input class='cell-bd-input' placeholder='请输入提货人姓名' v-model="store_pick.name"></input>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>电话</view>
</view>
<view class='cell-item-bd'>
<input class='cell-bd-input' placeholder='请输入提货人电话' v-model="store_pick.mobile"></input>
</view>
</view>
</view>
<!-- 商品列表信息 -->
<view class='img-list'>
<view class='img-list-item' v-if="item.is_select == true" v-for="(item, index) in products" :key="index">
<image class='img-list-item-l little-img have-none' :src='item.products.image_path' mode='aspectFill'></image>
<view class='img-list-item-r little-right'>
<view class='little-right-t'>
<view class='goods-name list-goods-name' @click="goodsDetail(item.products.goods_id)">{{ item.products.name }}</view>
<view class='goods-price'>¥{{ item.products.price }}</view>
</view>
<view class="romotion-tip" v-if="item.products.promotion_list">
<view class="romotion-tip-item" :class="v.type !== 2 ? 'bg-gray' : ''" v-for="(v, k) in item.products.promotion_list" :key="k">
{{ v.name }}
</view>
</view>
<view class='goods-item-c'>
<view class='goods-buy'>
<view class='goods-salesvolume' v-if="item.products.spes_desc !== null">{{ item.products.spes_desc }}</view>
<view class='goods-num'>× {{ item.nums }}</view>
</view>
</view>
</view>
</view>
</view>
<view class='cell-group'>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>优惠券</view>
</view>
<view class='cell-item-ft'>
<text class="cell-ft-p" @click="toshow()">{{ usedCouponsCompute }}</text>
</view>
</view>
<!-- 商户开启积分 并且用户有积分情况下 -->
<view class='cell-item add-title-item right-img' v-if="isOpenPoint === 1 && userPointNums > 0">
<view class='cell-item-bd'>
<view class="cell-bd-view">
积分抵扣
</view>
<view class="cell-bd-view">
<text class="cell-bd-text address color-9">可用 {{ canUsePoint }} 积分,可抵扣 {{ pointMoney }} 元,共有 {{ userPointNums }} 积分。</text>
</view>
</view>
<view class='cell-item-ft' @click="changePointHandle">
<label class="radio">
<radio value="1" :checked="isUsePoint" color="#FF7159"/>
<!-- <radio class="radioNo" disabled="true"/> -->
</label>
</view>
</view>
<view class='cell-item invoice right-img' v-if="invoiceSwitch == 1">
<view class='cell-item-hd'>
<view class='cell-hd-title'>发票</view>
</view>
<view class='cell-item-ft' @click="goInvoice()">
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
<text class='cell-ft-text'>{{invoice.name}}</text>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-bd-view'>商品价格</view>
<view class='cell-bd-view' v-if="cartData.goods_pmt_old > 0">商品优惠</view>
<view class='cell-hd-view' v-if="cartData.order_pmt_old > 0">订单优惠</view>
<view class='cell-hd-view' v-if="!couponIsUsed">优惠券抵扣</view>
<view class='cell-hd-view' v-if="cartData.point > 0">积分抵扣</view>
<view class='cell-hd-view'>运费</view>
</view>
<view class='cell-item-ft'>
<view class="cell-ft-view red-price">{{ cartData.goods_amount }}</view>
<view class="cell-ft-view" v-if="cartData.goods_pmt_old > 0">-{{ cartData.goods_pmt }}</view>
<view class="cell-ft-view" v-if="cartData.order_pmt_old > 0">-{{ cartData.order_pmt }}</view>
<view class="cell-ft-view" v-if="!couponIsUsed">-{{ cartData.coupon_pmt }}</view>
<view class="cell-ft-view" v-if="cartData.point > 0">-{{ cartData.point_money }}</view>
<view class="cell-ft-view">{{ cartData.cost_freight }}</view>
</view>
</view>
</view>
<view class='cell-group leave-message'>
<view class='cell-item right-img'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>买家留言</view>
</view>
</view>
<view class="cell-textarea ">
<!-- #ifndef MP-WEIXIN -->
<textarea v-model="memo" placeholder="50字以内(选填)" maxlength="50"/>
<!-- #endif -->
<!-- #ifdef MP-WEIXIN -->
<input v-model="memo" placeholder="50字以内(选填)"/>
<!-- #endif -->
</view>
</view>
</view>
<!-- 优惠券信息 -->
<lvv-popup position="bottom" ref="lvvpopref">
<view style="width: 100%;height: 700upx;background: #F8F8F8;;position: absolute;left:0;bottom: 0;">
<view class="pop-c">
<!-- <view class="pop-t">
<view class='cell-item invoice'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>优惠券</view>
</view>
<view class='cell-item-ft'
@click="toclose()">
<image class='cell-ft-next icon' src='/static/image/close.png'></image>
</view>
</view>
</view> -->
<view class="pop-b">
<view class="pop-b-t">
<uni-segmented-control
:current="current"
:values="items"
@clickItem="onClickItem"
style-type="text"
active-color="#333"
></uni-segmented-control>
</view>
<view class="" v-show="current === 0">
<scroll-view class="coupon-c" scroll-y="true" style="" v-if="userCoupons.length">
<view class="coupon-c-item" v-for="(item, index) in userCoupons" :key="index">
<view :class="item.cla">
<view class="cci-l-c color-f">
coupon
</view>
</view>
<view class="cci-r">
<!-- <image class="cci-r-img" src="" mode=""></image> -->
<view class="cci-r-c">
<view class="ccirc-t color-9">
{{ item.name }}
</view>
<view class="ccirc-b">
<view class="ccirc-b-l">
<view class="ccirc-b-tip">
{{ item.expression1 + item.expression2 }}
</view>
<view class="ccirc-b-time color-9">
有效期:{{ item.stime + ' - ' + item.etime }}
</view>
</view>
<view class="ccirc-b-r color-f"
@click="couponHandle(index)"
v-if="!item.checked && !item.disabled"
>
立即使用
</view>
<view class="ccirc-b-r color-f"
@click="couponHandle(index)"
v-else-if="item.checked && !item.disabled"
>
取消使用
</view>
<!-- <view class="ccirc-b-r color-f bg-c">
不可用
</view> -->
</view>
</view>
</view>
</view>
</scroll-view>
<view class="coupon-none" v-else>
<image class="coupon-none-img" src="/static/image/order.png" mode=""></image>
</view>
</view>
<view class="coupon-c" v-show="current === 1">
<view class="coupon-enter">
<view class="coupon-input">
<input type="text" v-model="inputCouponCode" placeholder="请输入优惠券码"/>
</view>
<!-- #ifdef MP-WEIXIN -->
<!-- <view class="coupon-code">
<image src="/static/image/ewm.png" class="icon" mode="" @click="scanCode"></image>
</view> -->
<!-- #endif -->
<view class="coupon-enter-btn"
@click="useInputCouponCode"
>
<button class="btn btn-b">确认</button>
</view>
</view>
</view>
</view>
<view class="button-bottom">
<button class="btn btn-square"
@click="notUseCoupon()"
>不使用优惠卷</button>
<button class="btn btn-square btn-b"
@click="toclose()"
>确定</button>
</view>
</view>
</view>
</lvv-popup>
<view class="button-bottom">
<view class="button-bottom-c">
<view class="button-bottom-c-t">共 {{ productNums }} 件商品</view>
<view class="button-bottom-c-b">合计<text class="red-price"> {{ cartData.amount }}</text></view>
</view>
<button class='btn btn-square btn-b' hover-class="btn-hover2" form-type="submit" :disabled='submitStatus' :loading='submitStatus'>立即支付</button>
</view>
</form>
</template>
<script>
import lvvPopup from '@/components/lvv-popup/lvv-popup.vue'
import uniSegmentedControl from "@/components/uni-segmented-control/uni-segmented-control.vue"
import { goods } from '@/config/mixins.js'
export default {
mixins: [ goods ],
data () {
return {
type_items: ['快递配送','门店自提'],//门店自提切换
type_current: 0,
cartData: {}, // 购物车商品详情
products: [], // 货品信息
promotions: [], // 促销信息
userShip: {}, // 用户收货地址
receiptType: 1, // 订单类型 1是发货订单 2是门店自提订单
params: {
ids: 0, // 传递过来的购物车id
area_id: 0, // 收货地址id
coupon_code: '', // 优惠券码列表(string)多张逗号分隔
point: 0 ,// 抵扣积分额
type :1 ,//购物车类型
}, // 监听params参数信息 以重新请求接口
// 发票信息
invoice: {
type: '1', // 类型 1不开发票 2个人发票 3公司发票
name: '不开发票', // 发票抬头
code: '' // 发票税号
},
memo: '', // 买家留言
items: [
'选择优惠券',
'输入券码',
],
orderType: 1, // 商品订单类型 1
current: 0,
isUsePoint: false, // 是否勾选使用积分
userPointNums: 0, // 用户的总积分
canUsePoint: 0, // 可以使用的积分
pointMoney: '', // 积分抵扣的金额
userCoupons: [], // 用户的可用优惠券列表
usedCoupons: {}, // 已经选择使用的优惠券
inputCouponCode: '', // 输入的优惠券码
optCoupon: '' ,// 当前选择使用的优惠券(暂存使用 如果接口返回不可用则剔除优惠券状态)
store : {
id: 0,
name: '',
mobile: '',
address: ''
},
store_pick: {
name: '',
mobile: ''
},
team_id: 0, //拼团id
submitStatus: false
}
},
components: {lvvPopup,uniSegmentedControl},
onLoad (options) {
let cartIds = options.cart_ids;
if(options.order_type){
this.params.order_type = options.order_type;
}
if(options.team_id){
this.team_id = options.team_id;
}
this.params.ids = JSON.parse(cartIds)
if (!this.params.ids) {
this.$common.successToShow('获取失败', function(){
uni.navigateBack({
delta: 1
})
})
}
// 获取用户的默认收货地址信息
this.userDefaultShip()
// 获取用户的可用优惠券信息
this.getUserCounpons()
//获取默认门店信息
this.getDefaultStore();
},
methods: {
// 切换门店
onTypeItem(index) {
if (this.type_current !== index) {
this.type_current = index;
}
let receiptType = 1;
if(this.type_current != 0){
receiptType = 2;
}
this.receiptType = receiptType;
this.getCartList();
},
// 跳转到门店列表
goStorelist(){
uni.navigateTo({
url: './storelist'
})
},
// 没有收货地址时跳转
goAddress(){
uni.navigateTo({
url: '/pages/member/address/list?type=order'
})
},
// 获取用户的默认收货地址
userDefaultShip () {
this.$api.userDefaultShip({}, res => {
if (res.status && Object.keys(res.data).length) {
this.userShip = res.data
this.params.area_id = this.userShip.area_id
}
})
},
// 获取购物车商品详情
getCartList () {
let data = this.params
data['receipt_type'] = this.receiptType // 区分订单类型 1快递订单 2门店自提订单
this.$api.cartList(data, res => {
if (res.status) {
let data = res.data
// 判断是否开启积分抵扣 并且 没有勾选积分使用
if (this.isOpenPoint === 1 && !this.isUsePoint) {
let money = {
order_money: data.amount
}
this.$api.usablePoint(money, res => {
if (res.status) {
this.userPointNums = res.data // 用户总积分
this.canUsePoint = res.available_point // 可以使用的积分
this.pointMoney = res.point_rmb // 积分抵扣的总金额
}
})
}
// 所有价格转换
data.amount = this.$common.formatMoney(data.amount);
data.goods_amount = this.$common.formatMoney(data.goods_amount);
data.goods_pmt_old = data.goods_pmt;
data.goods_pmt = this.$common.formatMoney(data.goods_pmt);
data.coupon_pmt = this.$common.formatMoney(data.coupon_pmt);
data.order_pmt_old = data.order_pmt;
data.order_pmt = this.$common.formatMoney(data.order_pmt);
data.point_money = this.$common.formatMoney(data.point_money);
data.cost_freight = this.$common.formatMoney(data.cost_freight);
// 购物车详情
this.cartData = data
// 商品详情
this.products = data.list
// 优惠信息
this.promotions = data.promotion_list
// 使用的优惠券信息
this.usedCoupons = data.coupon
// 手动输入的优惠券使用成功后关闭弹窗并清除输入的优惠券码
this.current === 1 && this.$refs.lvvpopref.popshow && this.inputCouponCode ? this.toclose() : ''
this.inputCouponCode = ''
this.optCoupon = ''
} else {
this.$common.errorToShow(res.msg, () => {
// 优惠券不可用状态判断
// 优惠券号码不存在 15009
// 优惠券未开始 15010
// 优惠券已使用 15013
// 优惠券不符合使用规则 15014
// 优惠券不可使用多张 15015
let errStatus = [15009, 15010, 15013, 15014, 15015]
if (errStatus.indexOf(res.data) !== -1) {
// 删除使用的优惠券号码
if (this.current === 1) {
this.removeCouponCode(this.inputCouponCode, this.current)
} else {
// 取消选择使用的状态
if (this.optCoupon) {
this.userCoupons.forEach(item => {
if (item.coupon_code === this.optCoupon) {
item.checked = false
}
})
}
this.removeCouponCode(this.optCoupon, this.current)
}
}
})
}
})
},
// 获取用户可用的优惠券信息
getUserCounpons () {
let data = {
display: 'no_used'
}
this.$api.userCoupon(data, res => {
if (res.status) {
let _list = res.data.list
let nowTime = Math.round(new Date().getTime() / 1000).toString()
_list.forEach(item => {
this.$set(item, 'checked', false)
// 判断优惠券是否有效(开始时间)
this.$set(item, 'disabled', item.start_time > nowTime ? true : false)
this.$set(item, 'cla', item.disabled ? 'cci-l bg-c' : 'cci-l') // 绑定相应的class样式
})
this.userCoupons = _list
}
})
},
// 点击使用/取消优惠券操作
couponHandle (index) {
// 更改使用/取消状态
this.userCoupons[index].checked = !this.userCoupons[index].checked
// 暂存当次选中使用的优惠券key
this.optCoupon = this.userCoupons[index].coupon_code
let arr = []
this.userCoupons.forEach(item => {
if (item.checked) {
arr.push(item.coupon_code)
}
})
if (this.userCoupons[index].checked) {
// 使用
this.params.coupon_code = arr.join()
} else {
// 取消使用
let paramsCodes = this.params.coupon_code.split(',')
let usedIndex = paramsCodes.indexOf(this.userCoupons[index].coupon_code)
if (usedIndex !== -1) {
paramsCodes.splice(usedIndex, 1)
this.params.coupon_code = paramsCodes.join()
}
}
},
// 手输的优惠券码使用
useInputCouponCode () {
if (!this.inputCouponCode) {
this.$common.errorToShow('请输入优惠券码')
} else {
// 判断是否有使用的优惠券
if (this.params.coupon_code.length > 0) {
this.params.coupon_code += ',' + this.inputCouponCode
} else {
this.params.coupon_code = this.inputCouponCode
}
}
},
// 不使用优惠券
notUseCoupon () {
this.toclose()
this.inputCouponCode = '' // 清空手输的优惠券码
this.userCoupons.forEach(item => {
item.checked = false
}) // 取消所有选中的使用状态
this.params.coupon_code = '' // 清空params优惠券码
},
// 移除/取消使用中的指定优惠券
removeCouponCode (code, current) {
let arr = this.params.coupon_code.split(',')
arr.splice(arr.indexOf(code), 1)
current === 0 ? this.optCoupon = '' : this.inputCouponCode = ''
this.params.coupon_code = arr.join()
},
// 是否使用积分
changePointHandle(){
if(this.userPointNums > 0){
this.isUsePoint = !this.isUsePoint;
this.params.point = this.isUsePoint ? this.canUsePoint : 0;
}
},
// 显示modal弹出框
toshow(){
this.$refs.lvvpopref.show();
},
// 关闭modal弹出框
toclose(){
this.$refs.lvvpopref.close();
},
// 去支付
toPay (e) {
this.submitStatus = true;
let receiptType = 1;
if(this.type_current != 0){
receiptType = 2;
}
this.receiptType = receiptType;
let data = {
cart_ids: this.params.ids,
memo: this.memo,
coupon_code: this.params.coupon_code,
point: this.params.point,
receipt_type: this.receiptType
}
data['order_type'] = this.params.order_type; //订单类型
if(this.team_id != 0){
data['params'] = JSON.stringify({team_id:this.team_id}) //团id
}
let delivery = {}
// 判断是快递配送还是门店自提
if(this.receiptType == 1){
if(!this.userShip.id || !this.params.area_id){
this.$common.errorToShow('请选择收货地址');
this.submitStatus = false;
return false;
}
// 快递配送
delivery = {
uship_id: this.userShip.id,
area_id: this.params.area_id
}
}
if(this.receiptType == 2){
if(!this.store.id){
this.$common.errorToShow('请选择自提门店');
this.submitStatus = false;
return false;
}
if(!this.store_pick.name){
this.$common.errorToShow('请输入提货人姓名');
this.submitStatus = false;
return false;
}
if(!this.store_pick.mobile){
this.$common.errorToShow('请输入提货人电话');
this.submitStatus = false;
return false;
}
// 门店自提
delivery = {
store_id: this.store.id,
lading_name: this.store_pick.name,
lading_mobile: this.store_pick.mobile
}
}
// 发票信息
data['tax_type'] = this.invoice.type
data['tax_name'] = this.invoice.name
data['tax_code'] = this.invoice.code
// #ifdef H5
data['source'] = 2;
// #endif
// #ifdef MP-WEIXIN
data['source'] = 3;
data['formId'] = e.detail.formId;
// #endif
// #ifdef MP-ALIPAY
data['source'] = 4;
// #endif
// #ifdef APP-PLUS|| APP-PLUS-NVUE
data['source'] = 5;
// #endif
data = Object.assign(data, delivery)
this.$api.createOrder(data, res => {
if (res.status) {
// 创建订单成功 去支付
this.submitStatus = false;
this.$common.redirectTo('/pages/goods/payment/index?order_id=' + res.data.order_id + '&type=' + this.orderType)
}else{
this.$common.errorToShow(res.msg);
this.submitStatus = false;
}
})
},
// 跳转发票页面
goInvoice () {
this.$common.navigateTo('./invoice')
},
// 跳转我的收货地址列表
showAddressList () {
this.$common.navigateTo('/pages/member/address/list?type=order')
},
// tab点击切换
onClickItem(index) {
if (this.current !== index) {
this.current = index;
}
},
// 获取默认店铺
getDefaultStore(){
this.$api.defaultStore({}, res => {
if(res.status){
let store = {
id: res.data.id,
name: res.data.store_name,
mobile: res.data.store_mobile,
address: res.data.all_address
}
this.store = store;
}
});
}
//扫码
// scanCode() {
// console.log(1);
// uni.scanCode({
// success(res) {
// console.log(2);
// console.log(res)
// },
// complete(res){
// console.log(3);
// console.log(res)
// },
// fail(res) {
// console.log(4);
// console.log(res)
// }
// })
// }
},
computed: {
// 计算购物车商品数量
productNums () {
let nums = 0
for (let i in this.cartData.list) {
if(this.cartData.list[i].is_select){
nums += this.cartData.list[i].nums;
}
}
return nums
},
// 判断商户是否开启积分抵扣 1开启 2未开启
isOpenPoint () {
return this.$store.state.config.point_switch
},
// 获取使用的优惠券名称
usedCouponsCompute () {
let name = '未使用'
if (Object.keys(this.usedCoupons).length) {
let coupons = []
for (let i in this.usedCoupons) {
coupons.push(this.usedCoupons[i])
}
name = coupons.join()
}
return name
},
// 判断是否开启发票功能
invoiceSwitch () {
return this.$store.state.config.invoice_switch || 2;
},
// 判断店铺开关
storeSwitch() {
return this.$store.state.config.store_switch || 2;
},
// 根据接口返回数据判断是否使用优惠券
couponIsUsed () {
return this.cartData.coupon instanceof Array
}
},
watch: {
// 监听数据状态(切换收货地址, 是否使用优惠券, 是否使用积分) 重新请求订单数据
params: {
handler () {
this.getCartList()
},
deep: true
}
}
}
</script>
<style>
.margin-cell-group {
margin: 0 0 2upx 0;
}
.add-title-items{
text-align: center;
}
.add-title-items .btn{
height: ;
font-size: 24upx;
/* margin: 0 auto; */
}
.add-title-item .cell-item-hd {
min-width: 40upx;
color: #666;
font-size: 28upx;
}
.add-title-item .cell-item-bd {
color: #333;
font-size: 28upx;
}
.add-title-item .cell-bd-text {
bottom: 0;
}
.cell-bd-view:first-child {
margin-bottom: 8upx;
}
.cell-ft-view:first-child {
margin-bottom: 8upx;
}
.address {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
width: 100%;
}
.img-list {
margin-bottom: 20upx;
}
.button-bottom button{
height: 100%;
width: 280upx;
}
.button-bottom-c{
display: inline-block;
position: relative;
padding: 10upx 26upx;
height: 100%;
width: 470upx;
float: left;
font-size: 22upx;
color: #666;
overflow: hidden;
}
.button-bottom-c-t{
font-size: 22upx;
color: #999;
display: inline-block;
float: left;
height: 100%;
line-height: 70upx;
}
.button-bottom-c-b{
font-size: 26upx;
color: #333;
display: inline-block;
float: right;
height: 100%;
line-height: 70upx;
}
.invoice .cell-ft-text{
/* top: 4upx; */
color: #666;
font-size: 24upx;
}
.pop-t{
border-bottom: 2upx solid #f4f4f4;
background-color: #fff;
}
.pop-b{
margin-bottom: 90upx;
}
.pop-b-t{
background-color: #fff;
width: 100%;
padding-top: 10upx;
}
.coupon-c{
/* padding: 50upx; */
height: 546upx;
box-sizing: border-box;
}
.coupon-c-item{
margin: 30upx 50upx;
/* width: 100%; */
height: 150upx;
margin-bottom: 20upx;
}
.cci-l{
width: 60upx;
height: 100%;
background-color: #FF7159;
font-size: 32upx;
display: inline-block;
box-sizing: border-box;
float: left;
border-top-left-radius: 16upx;
border-bottom-left-radius: 16upx;
}
.cci-l-c{
height: 60upx;
line-height: 44upx;
width: 150upx;
text-align: center;
transform-origin: 30upx 30upx;
transform: rotate(90deg);
}
.cci-r{
position: relative;
height: 150upx;
width: calc(100% - 70upx);
margin-left: 10upx;
display: inline-block;
background-color: #fff;
}
.cci-r-img{
position: absolute;
width: 100%;
height: 100%;
background-color: #fff;
}
.cci-r-c{
position: relative;
z-index: 99;
}
.ccirc-t{
font-size: 24upx;
padding: 10upx 20upx;
min-height: 56upx;
}
.ccirc-b{
padding: 10upx;
position: relative;
}
.ccirc-b-l{
display: inline-block;
max-width: 400upx;
}
.ccirc-b-tip{
font-size: 28upx;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
min-height: 38upx;
}
.ccirc-b-tip text{
font-size: 34upx;
}
.ccirc-b-time{
font-size: 24upx;
}
.ccirc-b-r{
display: inline-block;
background-color: #FF7159;
font-size: 26upx;
padding: 4upx 10upx;
border-radius: 4upx;
position: absolute;
right: 20upx;
bottom: 12upx;
}
.pop-c .btn{
width: 100%;
}
.leave-message{
margin: 20upx 0;
}
.leave-message .cell-item{
border-bottom: 0;
}
.cell-textarea{
padding: 0 26upx 20upx;
}
/* #ifndef MP-WEIXIN */
.cell-textarea textarea{
width: 100%;
height: 100upx;
font-size: 26upx;
color: #333;
}
/* #endif */
/* #ifdef MP-WEIXIN */
.cell-textarea input{
width: 100%;
font-size: 26upx;
color: #333;
}
/* #endif */
.coupon-enter{
display: flex;
height: 60upx;
margin: 40upx;
}
.coupon-enter>view{
display: inline-block;
}
.coupon-input{
/* width: 450upx; */
flex: 1;
border: 2upx solid #e8e8e8;
background-color: #fff;
height: 100%;
}
.coupon-input input{
height: 100%;
font-size: 26upx;
padding: 2upx 10upx;
}
.coupon-code{
margin: 4upx 30upx;
}
.coupon-enter-btn{
height: 100%;
margin-left: 20upx;
}
.coupon-enter-btn .btn{
font-size: 24upx;
height: 100%;
width: 108upx;
line-height: 58upx;
}
.bg-c{
background-color: #ccc;
}
.no-store{
text-align: center;
padding: 30upx 0;
font-size: 26upx;
color: #666;
/* min-height: 60upx; */
}
.coupon-none{
text-align: center;
padding: 120upx 0;
}
.coupon-none-img{
width: 274upx;
height: 274upx;
}
</style>
invoice.vue
<template>
<view class="content">
<view class="content-top">
<view class='cell-group margin-cell-group'>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>发票类型</view>
</view>
<view class='cell-item-ft'>
<view class="uni-form-item uni-column invoice-type">
<radio-group class="uni-list" @change="radioChange">
<label class="uni-list-cell uni-list-cell-pd" v-for="(item,index) in radioItems" :key="index">
<view class="invoice-type-icon">
<radio :id="item.name" :value="item.value" :checked="item.value == type"></radio>
</view>
<view class="invoice-type-c">
<label class="label-2-text" :for="item.name">
<text>{{item.name}}</text>
</label>
</view>
</label>
</radio-group>
</view>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>发票抬头</view>
</view>
<view class='cell-item-ft'>
<input class='cell-bd-input' v-model="name" placeholder='抬头名称'></input>
</view>
</view>
<view class='cell-item' v-show="type === '3'">
<view class='cell-item-hd'>
<view class='cell-hd-title'>税号</view>
</view>
<view class='cell-item-ft'>
<input class='cell-bd-input' v-model="code" placeholder='纳税人识别号'></input>
</view>
</view>
</view>
<view class='cell-group margin-cell-group'>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>发票内容</view>
</view>
<view class='cell-item-ft'>
<view class="cell-ft-view">明细</view>
</view>
</view>
</view>
<view class='cell-group margin-cell-group'>
<view class='cell-item right-img' @click="notNeedInvoice">
<view class='cell-item-hd'>
<view class='cell-hd-title'>本次不开具发票</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
</view>
</view>
<view class="button-bottom">
<button class="btn btn-square btn-b" @click="saveInvoice" hover-class="btn-hover2">保存</button>
</view>
</view>
</template>
<script>
export default {
data() {
return {
radioItems: [
{
name: '个人或事业单位',
value: '2'
},
{
name: '企业',
value: '3'
}
],
type: '3', // 发票类型 2个人 3企业
name: '', // 抬头名称
code: '' // 税号
}
},
onLoad () {
let invoice
let pages = getCurrentPages()
let pre = pages[pages.length - 2]
// #ifdef H5
invoice = pre.invoice
// #endif
// #ifdef MP-WEIXIN || APP-PLUS || APP-PLUS-NVUE
invoice = pre.$vm.invoice
// #endif
// #ifdef MP-ALIPAY
invoice = pre.rootVM.invoice;
// #endif
if (invoice && invoice.hasOwnProperty('type') && invoice.type !== '1') {
// 发票不是未使用, 展示发票信息
this.name = invoice.name
this.code = invoice.code
this.type = invoice.type
}
},
methods: {
// 单选框点击切换
radioChange (evt) {
this.radioItems.forEach(item => {
if (item.value === evt.target.value) {
this.type = item.value
}
})
},
// 不需要发票信息
notNeedInvoice () {
let data = {
type: '1',
name: '不开发票',
code: ''
}
this.setPageData(data)
},
// 保存发票信息
saveInvoice () {
if (!this.name) {
this.$common.errorToShow('请输入发票抬头')
return false
}
// 企业类型需要输入税号
if (this.type === '3' && !this.code) {
this.$common.errorToShow('请输入发票税号信息')
return false
}
let data = {
type: this.type,
name: this.name
}
// 不是企业类型不需要税号
data['code'] = this.type === '3' ? this.code : ''
this.setPageData(data)
},
// 向上个页面赋值并返回
setPageData (data) {
let pages = getCurrentPages();//当前页
let beforePage = pages[pages.length - 2];//上个页面
// #ifdef MP-ALIPAY
beforePage.rootVM.invoice = data;
// #endif
// #ifdef MP-WEIXIN || APP-PLUS || APP-PLUS-NVUE
beforePage.$vm.invoice = data;
// #endif
// #ifdef H5
beforePage.invoice = data;
// #endif
uni.navigateBack({
delta: 1
})
}
}
}
</script>
<style>
/* .margin-cell-group{
margin-bottom: 20upx;
} */
.invoice-type .uni-list-cell{
display: inline-block;
font-size: 26upx;
color: #333;
position: relative;
margin-left: 50upx;
}
.invoice-type .uni-list-cell>view{
display: inline-block;
}
.invoice-type-icon{
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.invoice-type-c{
margin-left: 50upx;
line-height: 2;
}
.cell-item-ft .cell-bd-input{
text-align: right;
width: 500upx;
}
.button-bottom .btn {
width: 100%;
}
</style>
storelist.vue
<template>
<view class="content">
<view class='search'>
<view class='search-c'>
<image class='icon search-icon' src='/static/image/zoom.png'></image>
<input class='search-input' placeholder-class='search-input-p' placeholder='请输入门店名' v-model="key"></input>
</view>
<button class="btn btn-g" hover-class="btn-hover2" @click="storeSearch">搜索</button>
</view>
<view class='cell-group margin-cell-group'>
<view class='cell-item add-title-item right-img' v-for="(item, key) in storeList" :key="key" @click="selectStore(item.id, item.store_name, item.mobile, item.all_address)">
<view class="cell-item-hd">
<image class='cell-hd-icon' src='/static/image/homepage.png'></image>
</view>
<view class='cell-item-bd'>
<view class="cell-bd-view black-text">
<text class="cell-bd-text">{{item.store_name}}</text>
</view>
<view class="cell-bd-view">
<text class="cell-bd-text">电话:{{item.mobile}}</text>
</view>
<view class="cell-bd-view">
<text class="cell-bd-text">地址:{{item.all_address}}</text>
</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' src='/static/image/location.png'></image>
<text class="cell-ft-text color-9">{{item.distance}}</text>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data () {
return {
storeList: [],
key: '',
longitude: '',
latitude: '',
}
},
onShow () {
this.getStoreList();
},
methods: {
//门店搜索
storeSearch(){
this.getStoreList();
},
//获取门店列表
getStoreList(){
let _this = this;
uni.getLocation({
type: 'gcj02',
success: function (res) {
_this.longitude = res.longitude;
_this.latitude = res.latitude;
},
complete: function (res) {
let data = {
'key': _this.key,
'longitude': _this.longitude,
'latitude': _this.latitude
}
_this.$api.storeList(data, e => {
_this.storeList = e.data;
});
}
});
},
//门店选择
selectStore(id, name, mobile, address){
let pages = getCurrentPages()
let pre = pages[pages.length - 2]
let store = {};
store['id'] = id;
store['name'] = name;
store['mobile'] = mobile;
store['address'] = address;
// #ifdef MP-ALIPAY
pre.rootVM.store = store;
// #endif
// #ifdef MP-WEIXIN || APP-PLUS || APP-PLUS-NVUE
pre.$vm.store = store
// #endif
// #ifdef H5
pre.store = store
// #endif
uni.navigateBack({
delta: 1
});
}
}
}
</script>
<style>
.search{
display: flex;
}
.search-c{
width: 80%;
margin-right: 2%;
}
.search-icon{
left: 30upx;
}
.search-input {
padding: 10upx 30upx 10upx 90upx;
}
.search-input-p{
padding: 0 !important;
}
.search .btn{
width: 18%;
border: none;
background-color: #f1f1f1;
font-size: 28upx;
color: #333;
border-radius: 6upx;
line-height: 72upx;
}
.add-title-item .cell-item-hd {
min-width: 50upx;
color: #666;
font-size: 28upx;
}
.cell-bd-view {
margin-bottom: 6upx;
}
.cell-bd-view .cell-bd-text{
font-size: 22upx;
color: #999;
}
.black-text .cell-bd-text{
font-size: 28upx;
color: #333;
}
</style>
index
custom.vue
<template>
<view class="content" style="padding-top: 0upx;">
<jshop :data="pageData"></jshop>
<jihaiCopyright></jihaiCopyright>
</view>
</template>
<script>
import jshop from "@/components/jshop/jshop.vue"
import jihaiCopyright from "@/components/jihai-copyright/jihaiCopyright.vue"
import {
goods
} from '@/config/mixins.js'
export default {
mixins: [goods],
components: {
jihaiCopyright,
jshop
},
data() {
return {
myShareCode: '', //分享Code
imageUrl: '/static/image/share_image.png', //店铺分享图片
pageData: [],
pageCode: 'mobile_home', //页面布局编码
statusBarHeight: '0',
customBarOpacity: false,
scrollTop: 0,
showLoad: false, //是否显示loading
share_name: ''
}
},
computed: {
appTitle() {
return this.$store.state.config.shop_name;
}
},
onLoad(e) {
//增加页面编码,可自定义编码
if (e.page_code) {
this.pageCode = e.page_code
}
this.initData()
},
// 小程序沉浸式状态栏变色
onPageScroll(e) {
// console.log(e);
e.scrollTop > 50 ? this.customBarOpacity = true : this.customBarOpacity = false
},
mounted() {
// #ifdef H5
window.addEventListener('scroll', this.handleScroll)
// #endif
},
methods: {
// 搜索框滑动变色
handleScroll() {
var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
scrollTop > 50 ? this.searchBarOpacity = true : this.searchBarOpacity = false
},
destroyed() {
window.removeEventListener('scroll', this.handleScroll)
},
goSearch() {
uni.navigateTo({
url: './search'
});
},
// 首页初始化获取数据
initData() {
this.showLoad = true;
//获取首页配置
this.$api.getPageConfig({
code: this.pageCode,
}, res => {
if (res.status == true) {
this.pageData = res.data.items;
this.share_name = res.data.name;
uni.setNavigationBarTitle({
title: res.data.name
});
//隐藏loading
setTimeout(() => {
this.showLoad = false;
}, 600);
}
});
this.getMyShareCode();
},
getMyShareCode() {
let userToken = this.$db.get("userToken");
if (userToken && userToken != '') {
// 获取我的分享码
this.$api.shareCode({}, res => {
if (res.status) {
this.myShareCode = res.data ? res.data : '';
}
});
}
}
},
onPullDownRefresh() {
this.initData();
uni.stopPullDownRefresh();
},
//分享
onShareAppMessage() {
let myInviteCode = this.myShareCode ? this.myShareCode : '';
let ins = this.$common.shareParameterDecode('type=8&page_code=' + this.pageCode + '&invite=' + myInviteCode);
let path = '/pages/share/jump?scene=' + ins;
return {
title: this.share_name,
// #ifdef MP-ALIPAY
//desc: this.$store.state.config.share_desc,
// #endif
//imageUrl: this.$store.state.config.share_image,
path: path
}
}
}
</script>
<style>
.search {
/* position: fixed; */
/* #ifdef H5 */
/* top: 44px; */
/* #endif */
/* #ifndef H5 */
/* top: 0; */
/* #endif */
}
.cell-item {
border: none;
}
.cell-ft-text {
font-size: 22upx;
color: #999;
}
.status_bar {
height: var(--status-bar-height);
width: 100%;
position: fixed;
top: 0;
z-index: 999;
background: rgba(0, 0, 0, 0);
transition: all .5s;
}
.custom-navbar {
height: 40px;
line-height: 34px;
position: fixed;
width: 100%;
padding-left: 26upx;
top: var(--status-bar-height);
z-index: 999;
background: rgba(0, 0, 0, 0);
transition: all .5s;
}
.index-logo {
width: 140upx;
height: 70upx;
/* margin: 0 auto; */
}
.index-logo-img {
width: 100%;
height: 100%;
}
.isOpacity {
background: rgba(255, 255, 255, 1);
transition: all .5s;
}
/* iPhone X in portrait & landscape */
@media only screen and (min-device-width : 375px) and (max-device-width : 812px) and (-webkit-device-pixel-ratio : 3) {
.status_bar {
height: 50px;
}
.custom-navbar {
top: 50px;
}
}
/* iPhone X in landscape */
@media only screen and (min-device-width : 375px) and (max-device-width : 812px) and (-webkit-device-pixel-ratio : 3) and (orientation : landscape) {
.status_bar {
height: 50px;
}
.custom-navbar {
top: 50px;
}
}
/* iPhone X in portrait */
@media only screen and (min-device-width : 375px) and (max-device-width : 812px) and (-webkit-device-pixel-ratio : 3) and (orientation : portrait) {
.status_bar {
height: 50px;
}
.custom-navbar {
top: 50px;
}
}
</style>
index.vue
<template>
<view class="content" style="padding-top: 0upx;">
<jshop :data="pageData"></jshop>
<jihaiCopyright></jihaiCopyright>
<red-bag v-if="redBagShow" @click="handleGet"></red-bag>
</view>
</template>
<script>
import jshop from '@/components/jshop/jshop.vue'
import jihaiCopyright from '@/components/jihai-copyright/jihaiCopyright.vue'
import uniCountdown from '@/components/uni-countdown/uni-countdown.vue'
import redBag from '@/components/red-bag/index'
import {
goods
} from '@/config/mixins.js'
import {
goBack
} from '@/config/mixins.js'
export default {
mixins: [goods],
components: {
jihaiCopyright,
jshop,
uniCountdown,
redBag
},
data() {
return {
myShareCode: '', //分享Code
imageUrl: '/static/image/share_image.png', //店铺分享图片
pageData: [],
pageCode: 'mobile_home', //页面布局编码
pintuan: [], //拼团列表,
redBagShow: false, //红包
}
},
computed: {
appTitle() {
return this.$store.state.config.shop_name
}
},
onLoad(e) {
this.initData()
if(this.$store.state.config.shop_name){
uni.setNavigationBarTitle({
title: this.$store.state.config.shop_name||''
});
}
},
methods: {
//领取红包
handleGet() {},
destroyed() {
window.removeEventListener('scroll', this.handleScroll)
},
goSearch() {
uni.navigateTo({
url: './search'
})
},
// 首页初始化获取数据
initData() {
//获取首页配置
this.$api.getPageConfig({
code: this.pageCode
},
res => {
if (res.status == true) {
this.pageData = res.data.items;
//隐藏loading
setTimeout(() => {
this.showLoad = false;
}, 600);
}
}
);
this.getMyShareCode();
},
getMyShareCode() {
let userToken = this.$db.get("userToken");
if (userToken && userToken != '') {
// 获取我的分享码
this.$api.shareCode({}, res => {
if (res.status) {
this.myShareCode = res.data ? res.data : '';
}
});
}
}
},
onPullDownRefresh() {
this.initData()
//this.$db.del('all_cat');
uni.stopPullDownRefresh()
},
//分享
onShareAppMessage() {
let myInviteCode = this.myShareCode ? this.myShareCode : '';
let ins = this.$common.shareParameterDecode('type=1&invite=' + myInviteCode);
let path = '/pages/share/jump?scene=' + ins;
return {
title: this.$store.state.config.share_title,
// #ifdef MP-ALIPAY
desc: this.$store.state.config.share_desc,
// #endif
imageUrl: this.$store.state.config.share_image,
path: path
}
}
}
</script>
<style>
.search {
/* position: fixed; */
/* #ifdef H5 */
/* top: 44px; */
/* #endif */
/* #ifndef H5 */
/* top: 0; */
/* #endif */
}
.cell-item {
border: none;
}
.cell-ft-text {
font-size: 22upx;
color: #999;
}
/* .new-goods {
min-height: 300upx;
white-space: nowrap;
width: 100%;
}
.new-goods-item {
width: 200upx;
display: inline-block;
margin-right: 20upx;
}
.new-goods-item:last-child {
margin-right: 0;
}
.news-goods-img {
width: 200upx;
height: 200upx;
}
.news-goods-img image {
width: 100%;
height: 100%;
}
.news-goods-bot {
margin-top: 6upx;
}
.new-goods-name {
display: block;
font-size: 26upx;
}
.new-goods-price {
display: block;
font-size: 26upx;
color: #e14d4d;
} */
</style>
search.vue
<template>
<view class="content">
<view class='search'>
<view class='search-c'>
<image class='icon search-icon' src='/static/image/zoom.png'></image>
<input v-bind:class="$store.state.searchStyle" class='search-input' placeholder-class='search-input-p' placeholder='请输入关键字搜索' v-model="key" focus :auto-focus="focus" :fixed="focus"></input>
</view>
<button class="btn btn-g" @click="search" hover-class="btn-hover2">搜索</button>
</view>
<view class="history-c" v-show="keys.length > 0">
<view class="history-title">
<view class='ht-left'>历史记录</view>
<view class='ht-right' @click="deleteKey">清除</view>
</view>
<view class="history-body">
<view class="hb-item" v-for="(item, key) in keys" :key="key" @click="toNav(item)">
{{item}}
</view>
</view>
</view>
<view class="history-c" v-show="recommend && recommend.length > 0">
<view class="history-title">
<view class='ht-left'>搜索发现</view>
</view>
<view class="history-body">
<view class="hb-item" v-for="(item, key) in recommend" :key="key" @click="toNav(item)">
{{item}}
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
keys: [],
key: '',
navType: 'toNav',
focus: true,
}
},
computed: {
recommend() {
return this.$store.state.config.recommend_keys
}
},
methods: {
//搜索
search: function () {
let keys = this.key;
if(keys != '') {
let search_key = this.$db.get('search_key');
if (!search_key) {
search_key = [];
}
let flag = true;
for (var key in search_key) {
if (search_key[key] == keys) {
flag = false;
}
}
if (flag) {
search_key.unshift(keys);
}
this.$db.set('search_key', search_key);
this.$db.set('search_term', keys);
this.$common.navigateTo('/pages/classify/index?key=' + keys);
}
},
//清除
deleteKey: function () {
//删除显示
this.keys = [];
//删除存储
this.$db.del('search_key');
},
//跳转操作
toNav: function (keys) {
this.$db.set('search_term', keys);
let search_key = this.$db.get('search_key');
if (!search_key) {
search_key = [];
}
var flag = true;
for (var key in search_key) {
if (search_key[key] == keys) {
flag = false;
}
}
if (flag) {
search_key.unshift(keys);
}
this.$db.set('search_key', search_key);
this.$common.navigateTo('/pages/classify/index?key=' + keys);
},
},
//加载触发
onShow(e) {
this.keys = this.$db.get('search_key');
this.key = this.$db.get('search_term');
this.focus = true;
},
//页面卸载触发
onUnload() {
this.$db.set('search_term', '');
}
}
</script>
<style>
.search{
display: flex;
}
.search-c{
width: 80%;
margin-right: 2%;
}
.search-icon{
left: 30upx;
}
.search-input {
padding: 10upx 30upx 10upx 90upx;
}
.search-input-p{
padding: 0 !important;
}
.search .btn{
width: 18%;
border: none;
background-color: #f1f1f1;
font-size: 28upx;
color: #333;
border-radius: 6upx;
line-height: 72upx;
}
.history-c{
/* background-color: #fff; */
padding: 20upx 26upx;
}
.history-title{
overflow: hidden;
}
.ht-left{
float: left;
font-size: 28upx;
color: #333;
}
.ht-right{
float: right;
color: #999;
font-size: 26upx;
}
.history-body{
overflow: hidden;
margin-top: 20upx;
min-height: 200upx;
}
.hb-item{
display: inline-block;
float: left;
background-color: #fff;
color: #888;
margin-right: 20upx;
margin-bottom: 14upx;
font-size: 26upx;
padding: 10upx 20upx;
}
.square{
border-radius: 0;
}
.radius{
border-radius: 12upx;
}
</style>
login
choose
index.vue
<template>
<view class="content">
<view class="login-m">
<view class="login-item">
<view class="logo">
<open-data type="userAvatarUrl"></open-data>
</view>
</view>
<view class="login-tip">
<view class="login-tip-big">
申请获取以下权限
</view>
<view class="login-tip-small">
获得你的公开信息 (昵称、头像等)
</view>
</view>
</view>
<view class="login-b flc">
<!-- #ifdef MP-WEIXIN -->
<button class="auth-btn refuse" @click="handleRefuse">拒绝</button>
<button class="auth-btn " open-type="getUserInfo" @getuserinfo="getUserInfo" hover-class="btn-hover">允许</button>
<!-- #endif -->
<!-- #ifdef MP-ALIPAY -->
<button class="auth-btn " @click="getALICode" hover-class="btn-hover">授权登录</button>
<!-- #endif -->
</view>
</view>
</template>
<script>
export default {
data() {
return {
open_id: ''
}
},
computed: {
logoImage() {
return this.$store.state.config.shop_logo
}
},
onLoad() {
const _this = this
// #ifdef MP-WEIXIN
this.getCode(function(code) {
var data = {
code: code
}
_this.$api.login1(data, (res)=>{
if (!res.status) {
_this.$common.successToShow(res.msg, function() {
uni.navigateBack({
delta: 1
})
})
} else {
_this.open_id = res.data
}
})
})
// #endif
},
// #ifdef MP-WEIXIN
// onUnload: function() {
// wx.reLaunch({
// url: '/pages/index/index'
// })
// },
// #endif
methods: {
getCode: function(callback) {
uni.login({
// #ifdef MP-ALIPAY
scopes: 'auth_user',
// #endif
success: function(res) {
if (res.code) {
return callback(res.code)
} else {
//login成功,但是没有取到code
this.$common.errorToShow('未取得code')
}
},
fail: function(res) {
this.$common.errorToShow('用户授权失败wx.login')
}
})
},
handleRefuse(){
uni.showToast({
title: '未授权',
icon: 'none',
duration: 1000,
})
setTimeout(() => {
uni.hideToast();
uni.navigateBack(-1);
}, 1000);
},
getUserInfo: function(e) {
//console.log(e);
let _this = this
//return false;
if (e.detail.errMsg == 'getUserInfo:fail auth deny') {
_this.$common.errorToShow('未授权')
} else {
var data = {
open_id: _this.open_id,
iv: e.detail.iv,
edata: e.detail.encryptedData,
signature: e.detail.signature
}
//有推荐码的话,带上
var invitecode = _this.$db.get('invitecode')
if (invitecode) {
data.invitecode = invitecode
}
_this.toLogin(data)
}
},
//实际的去登陆
toLogin: function(data) {
let _this = this
_this.$api.login2(data, function(res) {
if (res.status) {
//判断是否返回了token,如果没有,就说明没有绑定账号,跳转到绑定页面
if (typeof res.data.token == 'undefined') {
uni.redirectTo({
url: '/pages/login/login/index?user_wx_id=' + res.data.user_wx_id
})
} else {
//登陆成功,设置token,并返回上一页
_this.$db.set('userToken', res.data.token)
uni.navigateBack({
delta: 1
})
return false
}
} else {
_this.$common.errorToShow('登录失败,请重试')
}
})
},
getALICode() {
let that = this
uni.login({
scopes: 'auth_user',
success: (res) => {
if(res.authCode){
uni.getUserInfo({
provider: 'alipay',
success: function (infoRes) {
if(infoRes.errMsg == "getUserInfo:ok"){
let user_info = {
'nickname': infoRes.nickName,
'avatar': infoRes.avatar
}
that.aLiLoginStep1(res.authCode, user_info);
}
},
fail: function (errorRes) {
this.$common.errorToShow('未取得用户昵称头像信息');
}
});
}else{
this.$common.errorToShow('未取得code');
}
},
fail: function(res) {
this.$common.errorToShow('用户授权失败my.login');
}
});
},
aLiLoginStep1(code, user_info) {
let data = {
'code': code,
'user_info': user_info
}
this.$api.alilogin1(data, res => {
this.alipayNoLogin = false;
if (res.status) {
this.open_id = res.data.user_wx_id
//判断是否返回了token,如果没有,就说明没有绑定账号,跳转到绑定页面
if (!res.data.hasOwnProperty('token')) {
this.$common.redirectTo('/pages/login/login/index?user_wx_id=' + res.data.user_wx_id);
} else {
this.$db.set('userToken', res.data.token)
uni.navigateBack({
delta: 1
});
}
} else {
this.$common.errorToShow(res.msg)
}
})
},
}
}
</script>
<style lang="scss">
.content {
background-color: #fff;
height: 100vh;
padding: 100upx 60upx 0;
}
.login-item {
display: flex;
justify-content: center;
padding-bottom: 40upx;
border-bottom: 1upx solid #dddddd;
}
.logo {
display: block;
width: 180upx;
height: 180upx;
border-radius: 50%;
overflow: hidden;
border: 2px solid #fff;
box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.2);
}
.login-tip{
padding:60upx 0;
&-big{
font-size: 28upx;
line-height: 80upx;
}
&-small{
font-size: 12px;
color:#9e9e9e;
}
}
.app-name {
font-size: 28upx;
color: #999;
}
.login-b .btn-g {
margin-top: 40upx;
}
.auth-btn{
flex:1;
display: block;
height: 80upx;
line-height: 80upx;
text-align: center;
font-size: 12px;
color:#FFF;
background:#1aad19;
border-radius: 40upx;
&.refuse{
background:#999;
margin-right:40upx;
}
}
</style>
login
index.vue
<template>
<view class="content">
<view class="login-t">
<image class="login-logo" :src="logoImage" mode="aspectFill"></image>
</view>
<view class="login-m">
<view class="login-item">
<input type="number" v-model="mobile" :maxlength="maxMobile" placeholder="请输入手机号码" focus placeholder-class="login-item-i-p" />
</view>
<view class="login-item flc">
<input class="login-item-input" placeholder-class="login-item-i-p" type="text" v-model="code" placeholder="请输入验证码" />
<view :class="sendCodeBtn" @click="sendCode" v-if="verification">发送验证码</view>
<view class="btn btn-g" v-if="!verification">{{ timer }} 秒后重新获取</view>
</view>
</view>
<view class="login-b">
<!-- #ifdef H5|APP-PLUS|APP-PLUS-NVUE -->
<view v-if="user_wx_id">
<button :class="regButtonClass" @click="toBind()" hover-class="btn-hover">登录</button>
</view>
<view v-else>
<button :class="regButtonClass" @click="login()" hover-class="btn-hover">登录</button>
<view class="login-other flc">
<view class="fz12 item" @click="selectLoginType">
密码登录
</view>
<view class="fz12 item" @click="toReg">
注册
</view>
</view>
</view>
<!-- #endif -->
<!-- #ifdef MP -->
<button :class="regButtonClass" @click="showTopTips()" hover-class="btn-hover">登录</button>
<!-- #endif -->
</view>
</view>
</template>
<script>
import { goBack, jumpBackPage } from '@/config/mixins.js'
export default {
mixins: [goBack,jumpBackPage],
data() {
return {
maxMobile: 11,
mobile: '', // 用户手机号
code: '', // 短信验证码
user_wx_id: '', //授权id
verification: true, // 通过v-show控制显示获取还是倒计时
timer: 60, // 定义初始时间为60s
btnb: 'btn btn-square btn-c btn-all', //按钮背景
type: '', // 有值是第三方登录账号绑定
isWeixinBrowser: this.$common.isWeiXinBrowser()
}
},
onLoad(option) {
if (option.user_wx_id) {
this.user_wx_id = option.user_wx_id
uni.setNavigationBarTitle({
title: '绑定手机号'
})
}
// H5第三方授权登录绑定
// if (option.type && option.type === 'bind') {
// this.type = option.type
// uni.setNavigationBarTitle({
// title: '绑定手机号'
// })
// }
},
computed: {
// 验证手机号
rightMobile() {
let res = {}
if (!this.mobile) {
res.status = false
res.msg = '请输入手机号'
} else if (!/^1[3456789]{1}\d{9}$/gi.test(this.mobile)) {
res.status = false
res.msg = '手机号格式不正确'
} else {
res.status = true
}
return res
},
// 动态计算发送验证码按钮样式
sendCodeBtn() {
let btn = 'btn btn-g'
if (this.mobile.length === this.maxMobile && this.rightMobile.status) {
return btn + ' btn-b'
} else {
return btn
}
},
// 动态更改登录按钮bg
regButtonClass() {
return this.mobile && this.mobile.length === this.maxMobile && this.code
? this.btnb + ' btn-b'
: this.btnb
},
logoImage() {
return this.$store.state.config.shop_logo
}
},
onShow() {
let _this = this
let userToken = _this.$db.get('userToken')
if (userToken) {
uni.switchTab({
url: '/pages/member/index/index'
})
return true
}
_this.timer = parseInt(_this.$db.get('timer'))
if (_this.timer != null && _this.timer > 0) {
_this.countDown()
_this.verification = false
}
},
methods: {
// 发送短信验证码
sendCode() {
if (!this.rightMobile.status) {
this.$common.errorToShow(this.rightMobile.msg)
} else {
this.$common.loadToShow('发送中...')
setTimeout(() => {
this.$common.loadToHide()
this.$api.sms({ mobile: this.mobile, code: 'login' }, res => {
if (res.status) {
this.timer = 60
this.verification = false
this.$common.successToShow(res.msg)
this.countDown() // 执行验证码计时
// this.btnb = 'btn btn-square btn-all btn-b';
} else {
this.$common.errorToShow(res.msg)
}
})
}, 1000)
}
},
// 去注册
toReg() {
this.$common.navigateTo('/pages/login/register/index')
},
// 验证码倒计时
countDown() {
let auth_timer = setInterval(() => {
// 定时器设置每秒递减
this.timer-- // 递减时间
uni.setStorage({
key: 'timer',
data: this.timer,
success: function() {}
})
if (this.timer <= 0) {
this.verification = true // 60s时间结束还原v-show状态并清除定时器
clearInterval(auth_timer)
}
}, 1000)
},
// 登录
login() {
var _this = this
if (!_this.rightMobile.status) {
_this.$common.errorToShow(_this.rightMobile.msg)
} else {
// 短信验证码登录
if (!_this.code) {
_this.$common.errorToShow('请输入短信验证码!')
} else {
let data = {
mobile: _this.mobile,
code: _this.code
}
let invicode = _this.$db.get('invitecode')
if (invicode) {
data.invitecode = invicode
}
_this.$api.smsLogin(data, res => {
if (res.status) {
this.$db.set('userToken', res.data)
_this.redirectHandler()
} else {
_this.$common.errorToShow(res.msg)
}
})
}
}
},
// 重定向跳转 或者返回上一个页面
redirectHandler() {
this.$common.successToShow('登录成功!', () => {
this.$db.set('timer', 0)
this.$db.del('invitecode')
this.handleBack()
})
},
// 跳转到普通登录
toLogin() {
uni.navigateTo({
url: '../../login/login/index'
})
},
//提交按钮
showTopTips: function() {
let _this = this
if (_this.mobile == '') {
_this.$common.errorToShow('请输入手机号码')
return false
}
if (this.code == '') {
_this.$common.errorToShow('请输入验证码')
return false
}
if (_this.user_wx_id == 0) {
_this.$common.errorToShow('登录失败,请稍后再试', function() {
uni.navigateBack({
delta: 1
})
})
return false
}
var platform = 2
//1就是h5登陆(h5端和微信公众号端),2就是微信小程序登陆,3是支付宝小程序,4是app,5是pc
// #ifdef MP-ALIPAY
platform = 3
// #endif
// #ifdef APP-PLUS||APP-PLUS-NVUE
platform = 4
// #endif
var data = {
mobile: _this.mobile,
code: _this.code,
platform: platform, //平台id,标识是小程序登陆的
user_wx_id: _this.user_wx_id //微信小程序接口存不了session,所以要绑定的id只能传到前台
}
//有推荐码的话,带上
var invitecode = _this.$db.get('invitecode')
if (invitecode) {
data.invitecode = invitecode
}
_this.$api.smsLogin(data, function(res) {
if (res.status) {
_this.$db.set('userToken', res.data)
_this.redirectHandler()
} else {
//报错了
_this.$common.errorToShow(res.msg)
}
})
},
// 公众号第三方登录账号绑定
toBind() {
if (this.mobile == '') {
this.$common.errorToShow('请输入手机号码')
return false
}
if (this.code == '') {
this.$common.errorToShow('请输入验证码')
return false
}
let data = {
mobile: this.mobile,
code: this.code,
user_wx_id:this.user_wx_id
}
// 获取邀请码
let invicode = this.$db.get('invitecode')
if (invicode) {
data.invitecode = invicode
}
this.$api.smsLogin(data, res => {
if (res.status) {
this.$db.set('userToken', res.data)
this.redirectHandler()
} else {
this.$common.errorToShow(res.msg)
}
})
},
// 切换登录方式
selectLoginType() {
this.$common.redirectTo('./index1')
}
}
}
</script>
<style lang="scss">
.content {
/* #ifdef H5 */
height: calc(100vh - 90upx);
/* #endif */
/* #ifndef H5 */
height: 100vh;
/* #endif */
background-color: #fff;
padding: 0upx 100upx;
}
.login-t {
text-align: center;
padding: 50upx 0;
}
.login-logo {
width: 180upx;
height: 180upx;
border-radius: 20upx;
background-color: #f8f8f8;
/* margin: 0 auto; */
}
.login-m {
margin-bottom: 100upx;
}
.login-item {
border-bottom: 2upx solid #d0d0d0;
overflow: hidden;
padding: 10upx;
color: #333;
margin-bottom: 30upx;
}
.login-item-input {
display: inline-block;
flex: 1;
box-sizing: border-box;
}
.login-item .btn {
border: none;
width: 40%;
text-align: right;
padding: 0;
&.btn-b {
background: none;
color: #333 !important;
}
}
.login-b .btn {
color: #999;
}
.btn-b {
color: #fff !important;
}
.login-other {
margin-bottom: 40upx;
.item {
padding: 20upx 0;
}
}
.btn-square {
color: #333;
}
</style>
index1.vue
<template>
<view class="content">
<view class="login-t">
<image class="login-logo" :src="logoImage" mode="aspectFill"></image>
</view>
<view>
<view class="login-m">
<view class="login-item">
<input type="number" v-model="mobile" :maxlength="maxMobile" placeholder="请输入手机号码" placeholder-class="login-item-i-p" />
</view>
<view class="login-item flc">
<input class="login-item-input" :password="true" placeholder-class="login-item-i-p" type="text" v-model="pwd" placeholder="请输入密码" />
</view>
<view class="login-item" v-if="isCaptcha">
<input class="login-item-input" placeholder-class="login-item-i-p" type="text" v-model="captcha" placeholder="输入验证码" />
<img class='codeimg' :src="captchaUrl" alt="">
</view>
</view>
<view class="login-b">
<button :class="loginButtonClass" @click="loginHandler" hover-class="btn-hover">登录</button>
<view class="login-other flc">
<view class="fz12 item" @click="selectLoginType">
验证码登录
</view>
<view class="fz12 item" @click="toReg">
注册
</view>
</view>
</view>
</view>
<!-- 微信浏览器里 -->
<!-- #ifdef H5 -->
<template v-if="weixinBrowser">
<view class="fz12 g5">
第三方账号登录:
</view>
<view class="flc third-block">
<view class="third-item" v-for="(item, key,index) in thirdPartyLogins" :key="index" @click="handleThirdLogin(item)">
<image class="third-item-img" :src="getThirdLoginImg(key)" mode="aspectFill"></image>
</view>
</view>
</template>
<!-- #endif -->
<!-- #ifdef APP-PLUS||APP-PLUS-NVUE -->
<view class="fz12 g5">
第三方账号登录:
</view>
<view class="flc third-block" v-if="thirdPartyLogins.length>0">
<view class="third-item" v-for="(item, key,index) in thirdPartyLogins" :key="key" @click="handleThirdLoginApp(item)">
<image class="third-item-img" src="/static/image/ic-wechat.png" mode="aspectFill" v-if="item=='weixin'"></image>
</view>
</view>
<!-- #endif -->
</view>
</template>
<script>
import { baseUrl } from '@/config/config.js'
import { goBack,jumpBackPage} from '@/config/mixins.js'
export default {
mixins: [goBack,jumpBackPage],
data() {
return {
maxMobile: 11,
mobile: '', // 手机号
pwd: '', // 密码
isCaptcha: false, // 是否需要验证码
captcha: '', // 输入的验证码
captchaUrl: '', // 验证码图片地址
btnb: 'btn btn-square btn-c btn-all', // 按钮bg
weixinBrowser: false, // 是否是微信浏览器
thirdPartyLogins: [], // 第三方登录列表
}
},
onLoad(options) {
if (options.invitecode) {
this.$db.set('invitecode', options.invitecode)
}
// 判断浏览器环境
this.weixinBrowser = this.$common.isWeiXinBrowser()
if (this.weixinBrowser) {
this.getAuths()
}
// #ifdef APP-PLUS||APP-PLUS-NVUE
this.getAppAuths();
// #endif
},
onShow() {
if (this.$db.get('userToken')) {
uni.switchTab({
url:'/pages/index/index'
})
}
},
computed: {
// 动态更改登录按钮bg
loginButtonClass() {
return this.mobile && this.mobile.length === 11 && this.pwd
? this.btnb + ' btn-b'
: this.btnb
},
logoImage() {
return this.$store.state.config.shop_logo
},
getThirdLoginImg(key) {
return key => {
if (key == 'Wxofficial') {
return '/static/image/ic-wechat.png'
}else if(key == 'weixin'){
return '/static/image/ic-wechat.png'
}
}
}
},
methods: {
// 验证手机号
rightMobile() {
let res = {}
if (!this.mobile) {
res.status = false
res.msg = '请输入手机号'
} else if (!/^1[3456789]{1}\d{9}$/gi.test(this.mobile)) {
res.status = false
res.msg = '手机号格式不正确'
} else if (!this.pwd) {
res.status = false
res.msg = '请输入密码'
} else {
res.status = true
}
return res
},
// 登录处理
loginHandler() {
if (this.mobile && this.mobile.length === 11 && this.pwd) {
if (!this.rightMobile().status) {
this.$common.errorToShow(this.rightMobile().msg)
} else {
this.toLogin()
}
}
},
// 获取验证码图片地址
getCaptchaUrl() {
this.captchaUrl = this.$config.apiBaseUrl + 'captcha.html'
},
// 去注册
toReg() {
this.$common.navigateTo('/pages/login/register/index')
},
// 去登录
toLogin() {
let data = {
mobile: this.mobile,
password: this.pwd
}
if (this.isCaptcha) {
data.captcha = this.captcha
}
// 获取邀请码
let invicode = this.$db.get('invitecode')
if (invicode) {
data.invitecode = invicode
}
this.$api.login(data, res => {
if (res.status) {
this.$db.set('userToken', res.data)
this.redirectHandler()
} else {
this.$common.errorToShow(res.msg, () => {
// 需要输入验证码 或者 验证码错误刷新
if (res.data === 10013 || res.data === 10012) {
this.isCaptcha = true
}
// 登录需要验证码
if (this.isCaptcha) {
this.getCaptchaUrl()
}
})
}
})
},
// 重定向跳转 或者返回上一个页面
redirectHandler() {
this.$db.del('invitecode')
this.handleBack()
},
// 登录方式切换
selectLoginType() {
this.$common.redirectTo('/pages/login/login/index')
},
// 获取第三方登录列表
getAuths() {
let data = {
url: baseUrl + 'wap/pages/author'
}
this.$api.getTrustLogin(data, res => {
if (res.status) {
this.thirdPartyLogins = res.data
}
})
},
// 第三方登录授权
handleThirdLogin(url) {
this.$common.redirectTo('')
let redirect = this.$store.state.redirectPage
this.$db.set('redirectPage', redirect)
window.location.href = url
},
//获取APP信任登录
getAppAuths(){
let _this = this;
_this.thirdPartyLogins = [];
uni.getProvider({
service: 'oauth',
success: function (res) {
if(res.errMsg == 'getProvider:ok'){
_this.thirdPartyLogins = res.provider;
}
}
});
},
//app第三方登录
handleThirdLoginApp(type){
uni.showLoading({
title: '加载中'
});
let _this = this;
uni.login({
provider: type,
success: function (loginRes) {
// 获取用户信息
uni.getUserInfo({
provider: type,
success: function (infoRes) {
if(infoRes.errMsg == 'getUserInfo:ok'){
var data = {
user:infoRes.userInfo,
type:type
};
var invitecode = _this.$db.get('invitecode')
if (invitecode) {
data.invitecode = invitecode
}
_this.$api.appTrustLogin(data,res=>{
uni.hideLoading();
if (res.status) {
//判断是否返回了token,如果没有,就说明没有绑定账号,跳转到绑定页面
if (typeof res.data.token == 'undefined') {
uni.redirectTo({
url: '/pages/login/login/index?user_wx_id=' + res.data.user_wx_id
})
} else {
//登陆成功,设置token,并返回上一页
_this.$db.set('userToken', res.data.token)
uni.navigateBack({
delta: 1
})
return false
}
} else {
_this.$common.errorToShow('登录失败,请重试')
}
});
}else{
uni.hideLoading();
_this.$common.errorToShow('登录失败,请重试')
}
}
});
}
});
}
}
}
</script>
<style lang="scss">
.content {
/* #ifdef H5 */
height: calc(100vh - 90upx);
/* #endif */
/* #ifndef H5 */
height: 100vh;
/* #endif */
background-color: #fff;
padding: 0upx 100upx;
}
.login-t {
text-align: center;
padding: 50upx 0;
}
.login-logo {
width: 180upx;
height: 180upx;
border-radius: 20upx;
background-color: #f8f8f8;
/* margin: 0 auto; */
}
.login-m {
margin-bottom: 100upx;
}
.login-item {
border-bottom: 2upx solid #d0d0d0;
overflow: hidden;
padding: 10upx;
font-size: 28upx;
color: #333;
margin-bottom: 30upx;
display: flex;
align-items: center;
}
.login-item-input {
display: inline-block;
// width: 60%;
flex: 1;
box-sizing: border-box;
}
.codeimg{
width: 210rpx;
}
.login-item .btn {
display: inline-block;
font-size: 28upx;
border: none;
width: 40%;
padding: 0;
line-height: 1.7;
float: right;
}
.login-b .btn {
color: #999;
}
.btn-b {
color: #fff !important;
}
.registered-item {
overflow: hidden;
width: 100%;
}
.registered {
float: right;
}
.registered-item .btn-square {
color: #333;
}
.third-block {
justify-content: center;
padding-top: 40upx;
.third-item {
width: 80upx;
height: 80upx;
background: $g2;
border-radius: 50%;
padding: 16upx;
&-img {
display: block;
width: 100%;
height: 100%;
}
}
}
.login-other {
margin-bottom: 40upx;
.item {
padding: 20upx 0;
}
}
</style>
register
index.vue
<template>
<view class="content">
<view class="reg-t">
<image class="reg-logo" :src="logoImage" mode="aspectFill"></image>
</view>
<view class="reg-m">
<view class="reg-item">
<input type="number" v-model="mobile" :maxlength="maxMobile" placeholder="请输入手机号码" focus placeholder-class="reg-item-i-p" />
</view>
<view class="reg-item flc">
<input class="reg-item-input" placeholder-class="reg-item-i-p" type="text" v-model="code" placeholder="请输入验证码" />
<view :class="sendCodeBtn" @click="sendCode" v-if="verification">发送验证码</view>
<view class="btn btn-g" v-if="!verification">{{ timer }} 秒后重新获取</view>
</view>
<view class="reg-item">
<input class="login-item-input" :password="true" placeholder-class="login-item-i-p" type="text" v-model="pwd" placeholder="请输入密码" />
</view>
</view>
<view class="reg-b">
<button :class="regButtonClass" @click="toReg()" hover-class="btn-hover">注册</button>
</view>
<view class="registered-item">
<view class="btn btn-g btn-square registered" @click="toLogin">已有账号,立即登录</view>
</view>
</view>
</template>
<script>
import { goBack } from '@/config/mixins.js'
export default {
mixins: [goBack],
data() {
return {
maxMobile: 11,
mobile: '', // 用户手机号
code: '', // 短信验证码
pwd: '', // 用户密码
verification: true, // 通过v-show控制显示获取还是倒计时
timer: 60, // 定义初始时间为60s
btnb: 'btn btn-c btn-square btn-all' //按钮背景
}
},
onLoad(options) {
let _this = this
_this.timer = parseInt(_this.$db.get('timer'))
if (_this.timer != null && _this.timer > 0) {
_this.countDown()
_this.verification = false
}
if (options.invitecode) {
this.$db.set('invitecode', options.invitecode)
}
},
computed: {
// 验证手机号
rightMobile() {
let res = {}
if (!this.mobile) {
res.status = false
res.msg = '请输入手机号'
} else if (!/^1[3456789]{1}\d{9}$/gi.test(this.mobile)) {
res.status = false
res.msg = '手机号格式不正确'
} else {
res.status = true
}
return res
},
// 动态更改登录按钮bg
regButtonClass() {
return this.mobile && this.mobile.length === 11 && this.pwd && this.code
? this.btnb + ' btn-b'
: this.btnb
},
// 动态修改发送验证码按钮
sendCodeBtn() {
let btn = 'btn btn-g'
if (this.mobile.length === this.maxMobile && this.rightMobile.status) {
return btn + ' btn-b'
} else {
return btn
}
},
logoImage() {
return this.$store.state.config.shop_logo
}
},
onShow() {
let _this = this
let userToken = _this.$db.get('userToken')
if (userToken && userToken != '') {
uni.switchTab({
url: '/pages/member/index/index'
})
return true
}
_this.timer = parseInt(_this.$db.get('timer'))
if (_this.timer != null && _this.timer > 0) {
_this.countDown()
_this.verification = false
}
},
methods: {
// 发送短信验证码
sendCode() {
if (!this.rightMobile.status) {
this.$common.errorToShow(this.rightMobile.msg)
} else {
this.$common.loadToShow('发送中...')
setTimeout(() => {
this.$common.loadToHide()
this.$api.sms({ mobile: this.mobile, code: 'reg' }, res => {
if (res.status) {
this.timer = 60
this.verification = false
this.$common.successToShow(res.msg)
this.countDown() // 执行验证码计时
this.btnb = 'btn btn-square btn-all btn-b'
} else {
this.$common.errorToShow(res.msg)
}
})
}, 1000)
}
},
// 验证码倒计时
countDown() {
let auth_timer = setInterval(() => {
// 定时器设置每秒递减
this.timer-- // 递减时间
uni.setStorage({
key: 'timer',
data: this.timer,
success: function() {}
})
if (this.timer <= 0) {
this.verification = true // 60s时间结束还原v-show状态并清除定时器
clearInterval(auth_timer)
}
}, 1000)
},
toReg() {
if (!this.rightMobile.status) {
this.$common.errorToShow(this.rightMobile.msg)
} else if (!this.code) {
this.$common.errorToShow('请输入短信验证码')
} else if (!this.pwd) {
this.$common.errorToShow('请输入登录密码')
} else {
let data = {
mobile: this.mobile,
code: this.code,
password: this.pwd
}
// 获取邀请码
let invicode = this.$db.get('invitecode')
if (invicode) {
data.invitecode = invicode
}
this.$api.smsLogin(data, res => {
if (res.status) {
this.$db.set('userToken', res.data)
this.$common.successToShow('注册成功', () => {
// 清除随机uid 和 邀请码
this.$db.del('uuid')
this.$db.del('invitecode')
let redirect = this.$store.state.redirectPage
? this.$store.state.redirectPage
: '/pages/member/index/index'
this.$store.commit({
type: 'redirect',
page: ''
})
uni.reLaunch({
url: redirect
})
})
} else {
this.$common.errorToShow(res.msg)
}
})
}
},
toLogin() {
this.$common.navigateTo('/pages/login/login/index1')
}
}
}
</script>
<style lang="scss">
.content {
/* #ifdef H5 */
height: calc(100vh - 90upx);
/* #endif */
/* #ifndef H5 */
height: 100vh;
/* #endif */
background-color: #fff;
padding: 0upx 100upx;
}
.reg-t {
text-align: center;
padding: 50upx 0;
}
.reg-logo {
width: 180upx;
height: 180upx;
border-radius: 20upx;
background-color: #f8f8f8;
/* margin: 0 auto; */
}
.reg-m {
margin-bottom: 100upx;
}
.reg-item {
border-bottom: 2upx solid #d0d0d0;
overflow: hidden;
padding: 10upx;
color: #333;
margin-bottom: 30upx;
.btn{
border: none;
width: 40%;
text-align:right;
&.btn-b {
background: none;
color: #333 !important;
}
}
}
.reg-item-input {
flex:1;
}
.reg-b .btn {
color: #999;
}
.registered-item {
overflow: hidden;
width: 100%;
}
.registered {
float: right;
}
.btn-square {
color: #333;
height: 80upx;
line-height: 80upx;
padding:0;
font-size:$fz12;
}
</style>
member
address
index.vue
<template>
<view class="content">
<view class="content-top">
<view class='cell-group'>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>收货人</view>
</view>
<view class='cell-item-bd'>
<input type="text" class='cell-bd-input' placeholder='请填写收货人姓名' v-model="name"></input>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>手机号</view>
</view>
<view class='cell-item-bd'>
<input type="text" class='cell-bd-input' placeholder='请填写收货人手机号' v-model="mobile"></input>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>省市区</view>
</view>
<view class='cell-item-bd'>
<input :value="pickerValue" @focus="showThreePicker"></input>
<area-picker ref="areaPicker" :areaId="areaId" :defaultIndex="defaultIndex" @onConfirm="onConfirm"></area-picker>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' src='/static/image/ic-pull-down.png' @click="showThreePicker"></image>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>详细地址</view>
</view>
<view class='cell-item-bd'>
<input type="text" class='cell-bd-input' placeholder='请填写收货详细地址' v-model="address"></input>
</view>
</view>
<view class='cell-item' @click="defaultChange">
<view class='cell-item-hd'>
<view class='cell-hd-title'>设为默认</view>
</view>
<view class='cell-item-ft' >
<label class="radio" ><radio value="1" :checked="checked" color="#FF7159"/></label>
</view>
</view>
</view>
</view>
<view class="button-bottom">
<button class="btn btn-square btn-w" @click="delShip" v-if="id && id != 0" hover-class="btn-hover2" :disabled='submitStatus' :loading='submitStatus'>删除</button>
<button class="btn btn-square btn-b" @click="saveShip" hover-class="btn-hover2" :disabled='submitStatus' :loading='submitStatus'>保存</button>
</view>
</view>
</template>
<script>
import areaPicker from "@/components/area-picker/areaPicker.vue";
export default {
components: {
areaPicker
},
data() {
return {
id: 0,
name: '',
mobile: '',
region: ['北京市', '北京市', '东城区'],
areaId: 110101,
address: '',
is_def: 2,
multiArray: [
[],
[],
[]
],
multiIndex: [110000, 110100, 110101],
checked: false,
pickerValue: '',
defaultIndex: [0, 0, 0],
submitStatus: false
}
},
computed: {},
methods: {
// 省市区联动初始化
showThreePicker() {
this.$refs.areaPicker.showPicker();
},
onConfirm(e) {
let province_name = e[0].name;
let city_name = e[1].name;
let county_name = e[2].name;
this.pickerValue = e[0].name+ " "+ e[1].name+" "+e[2].name
let data = {
province_name: province_name,
city_name: city_name,
county_name: county_name
}
let regionName = [province_name, city_name, county_name];
this.$api.getAreaId(data, res => {
if (res.status) {
this.areaId = res.data
} else {
uni.showModal({
title: '提示',
content: '地区选择出现问题,请重新选择地区',
showCancel: false
});
}
});
},
// 信息验证
checkData (data) {
this.submitStatus = false;
if (!data.name) {
this.$common.errorToShow('请输入收货人姓名')
return false
} else if (!data.mobile) {
this.$common.errorToShow('请输入收货人手机号')
return false
} else if (data.mobile.length !== 11) {
this.$common.errorToShow('收货人手机号格式不正确')
return false
} else if (!data.area_id) {
this.$common.errorToShow('请选择地区信息')
return false
} else if (!data.address) {
this.$common.errorToShow('请输入收货地址详细信息')
return false
} else {
return true
}
},
//默认
defaultChange(){
if(this.checked){
this.checked = false;
this.is_def = 2;
}else{
this.checked = true;
this.is_def = 1;
}
},
//编辑获取收货地址信息
getShipInfo() {
let data = {
'id': this.id
}
this.$api.shipDetail(data, res => {
if(res.status){
let region = res.data.area_name.split(" ");
this.name = res.data.name;
this.mobile = res.data.mobile;
this.region = region;
this.areaId = res.data.area_id;
this.pickerValue = this.region[0]+ " "+ this.region[1]+" "+this.region[2]
this.$refs.areaPicker.init();//初始化插件
this.address = res.data.address;
this.is_def = res.data.is_def;
if(res.data.is_def == 1){
this.checked = true;
}else{
this.checked = false;
}
}else{
this.$common.errorToShow('获取收货地址信息出现问题');
this.submitStatus = false;
}
});
},
//删除地址
delShip() {
this.submitStatus = true;
this.$api.removeShip({'id': this.id}, res => {
if(res.status){
this.$common.successToShow(res.msg, ress => {
this.submitStatus = false;
uni.navigateBack({
delta: 1
});
});
}else{
this.$common.errorToShow(res.msg);
this.submitStatus = false;
}
});
},
//存储收货地址
saveShip() {
this.submitStatus = true;
let data = {
name: this.name,
address: this.address,
mobile: this.mobile,
is_def: this.is_def,
area_id: this.areaId
}
if(this.id && this.id != 0){
//编辑存储
data.id = this.id
if (this.checkData(data)) {
this.$api.editShip(data, res => {
if(res.status){
this.$common.successToShow(res.msg, ress => {
this.submitStatus = false;
uni.navigateBack({
delta: 1
});
});
}else{
this.$common.errorToShow(res.msg);
this.submitStatus = false;
}
});
}
}else{
//添加
if (this.checkData(data)) {
this.$api.saveUserShip(data, res => {
if(res.status){
this.$common.successToShow(res.msg, ress => {
this.submitStatus = false;
uni.navigateBack({
delta: 1
});
});
}else{
this.$common.errorToShow(res.msg);
this.submitStatus = false;
}
});
}
}
}
},
onLoad(e) {
if(e.ship_id){
//编辑
this.id = e.ship_id;
this.getShipInfo();
}else{
//添加
this.pickerValue = this.region[0]+ " "+ this.region[1]+" "+this.region[2];
uni.setNavigationBarTitle({
title: '添加地址'
});
}
},
onBackPress() {
if (this.$refs.areaPicker.pickerShow) {
this.$refs.areaPicker.closePicker();
return true;
}
},
}
</script>
<style>
.user-head{
height: 100upx;
}
.user-head-img{
height: 90upx;
width: 90upx;
border-radius: 50%;
}
.cell-hd-title{
color: #333;
}
.cell-item-bd{
color: #666;
font-size: 26upx;
}
.button-bottom .btn {
width: 50%;
}
.cell-bd-input{
width: 100%;
}
/* #ifdef MP-ALIPAY */
input{
font-size: 24upx;
}
/* #endif */
</style>
list.vue
<template>
<view class="content">
<view class="content-top" v-if="list.length">
<view class="uni-list-cell uni-list-cell-pd" v-for="(item, key) in list" :key="key">
<view class='cell-group min-cell-group'>
<view class='cell-item'>
<view class='cell-item-hd' @click="isSelect(item)">
<view class='cell-hd-title'>{{item.name}} <text class="phone-num">{{item.mobile}}</text></view>
</view>
<view class='cell-item-ft' v-show="type != 'order'">
<image class='cell-ft-next icon' src='/static/image/compile.png' @click="toEdit(item.id)"></image>
<text class="cell-ft-text"></text>
</view>
</view>
<view class='cell-item' @click="isSelect(item)">
<view class='cell-item-bd'>
<view class="cell-bd-view">
<view class="cell-tip" v-show="item.is_def === 1">默认</view>
<text class="cell-bd-text">{{item.area_name + item.address}}</text>
</view>
</view>
</view>
</view>
</view>
</view>
<view class="address-none" v-else>
<image class="address-none-img" src="/static/image/order.png" mode=""></image>
</view>
<view class="button-bottom">
<!-- #ifdef MP-WEIXIN -->
<button class="btn btn-square btn-b" @click="wechatAddress" hover-class="btn-hover2">从微信获取</button>
<!-- #endif -->
<button class="btn btn-square btn-w" @click="toAdd()" hover-class="btn-hover2">新增收货地址</button>
</view>
</view>
</template>
<script>
export default {
data() {
return {
list: [] ,// 用户收货地址列表
type: ''
}
},
onLoad (e) {
if(e.type){
this.type = e.type;
}
},
onShow () {
this.userShipList();
},
methods: {
// 获取收货地址列表
userShipList () {
this.$api.userShip({}, res => {
if (res.status) {
this.list = res.data
}
})
},
// 收货地址删除
delShip (id) {
this.$common.modelShow('提示', '确认删除此收货地址?', () => {
let data = {
id: id
}
this.$api.removeShip(data, res => {
if (res.status) {
this.$common.successToShow(res.msg, () => {
this.userShipList();
});
} else {
this.$common.errorToShow(res.msg);
}
})
})
},
//编辑
toEdit (id) {
this.$common.navigateTo('./index?ship_id=' + id);
},
//添加
toAdd() {
this.$common.navigateTo('./index');
},
//选择
isSelect(data) {
if(this.type == 'order'){
let pages = getCurrentPages();//当前页
let beforePage = pages[pages.length - 2];//上个页面
// #ifdef MP-ALIPAY
beforePage.rootVM.userShip = data;
beforePage.rootVM.params.area_id = data.area_id;
// #endif
// #ifdef H5
beforePage.userShip = data;
beforePage.params.area_id = data.area_id;
// #endif
// #ifdef MP-WEIXIN || APP-PLUS || APP-PLUS-NVUE
beforePage.$vm.userShip = data;
beforePage.$vm.params.area_id = data.area_id;
// #endif
uni.navigateBack({
delta: 1
});
}
},
// #ifdef MP-WEIXIN
wechatAddress: function () {
wx.chooseAddress({
success: res => {
if (res.errMsg == "chooseAddress:ok") {
//获取成功
//存储这个收获地区信息到数据库
let data = {
province_name: res.provinceName,
city_name: res.cityName,
county_name: res.countyName,
postal_code: res.postalCode
};
let areaId = 0;
this.$api.getAreaId(data, res1 => {
if (res1.status) {
//存储用户收货信息
let userShipId = 0;
let userShipData = {
area_id: res1.data,
user_name: res.userName,
detail_info: res.detailInfo,
tel_number: res.telNumber,
is_def: 2
}
this.$api.saveUserShipWx(userShipData, res2 => {
if (res2.status) {
this.$common.errorToShow('存储微信地址成功', r => {
setTimeout(rp => {
this.userShipList();
}, 1000);
});
}else{
uni.showModal({
title: '提示',
content: '存储微信地址失败',
showCancel: false
});
}
});
}else{
uni.showModal({
title: '提示',
content: '获取微信地址失败',
showCancel: false
});
}
});
} else {
uni.showModal({
title: '提示',
content: '获取微信地址失败',
showCancel: false
});
}
}
});
},
// #endif
}
}
</script>
<style>
.cell-tip{
background-color: #FF7159;
color: #fff;
font-size: 24upx;
display: inline-block;
float: left;
/* border-radius: 10upx; */
padding: 4upx 10upx;
margin-right: 10upx;
transform: scale(.9);
}
.min-cell-group .cell-ft-text{
font-size: 24upx;
margin-right: 10upx;
}
.min-cell-group .cell-item-bd{
color: #666;
padding-right: 0;
}
.min-cell-group .default{
color: #666;
}
.min-cell-group uni-radio .uni-radio-input{
width: 36upx;
height: 36upx;
}
.min-cell-group .default .checked-radio{
display: inline-block;
float: left;
position: relative;
bottom: 2upx;
}
.green{
background-color: #999;
}
.cell-hd-title{
font-size: 28upx;
}
.phone-num{
margin-left: 20upx;
color: #999;
font-size: 24upx;
}
.address-none{
text-align: center;
padding: 200upx 0;
}
.address-none-img{
width: 274upx;
height: 274upx;
}
</style>
after_sale
detail.vue
<template>
<view class="content">
<view class="content-top">
<!-- <view class="back-img">
<view class="back-img-c">
<view class="back-img-t">退款单状态</view>
<view class="back-img-b">{{status_name}} {{refund_name}} {{reship_name}}...</view>
</view>
</view> -->
<view class='cell-group margin-cell-group'>
<view class='cell-item add-title-item'>
<view class='cell-item-bd'>
<view class="cell-bd-view black-text">
<text class="cell-bd-text color-3">退款单状态</text>
</view>
<view class="cell-bd-view">
<text class="cell-bd-text color-9">{{status_name}} {{refund_name}} {{reship_name}}...</text>
</view>
<view class="cell-bd-view">
<!-- <text class="cell-bd-text">下单时间:{{ orderInfo.ctime }}</text> -->
</view>
</view>
</view>
</view>
<view class='cell-group margin-cell-group'>
<view class='cell-item'>
<view class='cell-item-hd'><view class='cell-hd-title'>售后类型</view></view>
<view class='cell-item-ft'><view class="cell-ft-p">{{type_name}}</view></view>
</view>
<view class='cell-item'>
<view class='cell-item-hd'><view class='cell-hd-title'>退款金额</view></view>
<view class='cell-item-ft'><view class="cell-ft-p red-price">{{refund}}元</view></view>
</view>
</view>
<view class='cell-group margin-cell-group' v-if="images.length > 0">
<view class='cell-item right-img'><view class='cell-item-hd'><view class='cell-hd-title'>图片凭证</view></view></view>
<view class="">
<view class="evaluate-c-b">
<view class="goods-img-item" v-for="(item, key) in images" :key="key">
<image :src="item.url" mode="aspectFit" @click="clickImg(item.url)"></image>
</view>
</view>
</view>
</view>
<view class='cell-group margin-cell-group'>
<view class='cell-item right-img'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>问题描述</view>
</view>
</view>
<view class="cell-textarea">
<text v-if="reason">{{reason}}</text>
<text v-else>暂无描述</text>
</view>
</view>
<view class='cell-group margin-cell-group' v-show="status == 2 && reship_status == 1">
<view class='cell-item right-img'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>退货邮寄信息</view>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>收件人</view>
</view>
<view class='cell-item-bd'>
<input class='cell-bd-input' type="text" disabled="false" :value="reship_info.reship_name" />
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>联系方式</view>
</view>
<view class='cell-item-bd'>
<input class='cell-bd-input' type="text" disabled="false" :value="reship_info.reship_mobile" />
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>邮寄地址</view>
</view>
<view class='cell-item-bd'>
<input class='cell-bd-input' type="text" disabled="false" :value="reship_info.reship_area + reship_info.reship_address" />
</view>
</view>
</view>
<view class='cell-group margin-cell-group' v-show="status == 2 && reship_status == 1">
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>快递公司</view>
</view>
<view class='cell-item-bd'>
<input class='cell-bd-input' type="text" v-model="logi_code" placeholder="请填写快递公司名称"/>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>物流单号</view>
</view>
<view class='cell-item-bd'>
<input class='cell-bd-input' type="text" v-model="logi_no" placeholder="请填写物流单号" />
</view>
</view>
</view>
<view class='cell-group margin-cell-group' v-show="status == 2 && reship_status > 1">
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>快递公司</view>
</view>
<view class='cell-item-bd'>
<input class='cell-bd-input' type="text" disabled="false" :value="logi_code"/>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>物流单号</view>
</view>
<view class='cell-item-bd'>
<input class='cell-bd-input' type="text" disabled="false" :value="logi_no"/>
</view>
</view>
</view>
</view>
<view class="button-bottom" v-show="status == 2 && reship_status == 1">
<button class="btn btn-b" @click="submitBtn" :disabled='submitStatus' :loading='submitStatus'>提交</button>
</view>
<view class="button-bottom" v-show="(order_status == 1 && status == 3) || (order_status == 1 && status == 2 && refund_status != 1 && refund_status != 0) || (order_status == 1 && status == 2 && reship_status == 3)">
<button class="btn btn-b" @click="repeat">再次申请售后</button>
</view>
</view>
</template>
<script>
export default {
data() {
return {
delivers: ["请选择物流公司","顺丰", "中通", "圆通","韵达"],
deliverIndex: 0,
type_name:'', //售后类型显示
refund:0, //退款金额
images:[], //图片
reason: '暂无', //问题描述
ttype:1, //售后类型
status:1, //售后单状态
status_name: '审核中', //售后单状态文字描述
reship_status:0, //退货单状态
reship_name:'',
refund_status:0, //退款单状态
refund_name:'',
reship_info:[], //退货单明细,如果售后单未审核呢,那么显示的是售后单明细,如果售后单审核通过了,显示退款单明细
items:[], //退货明细
mark:"暂无", //拒绝原因
logi_no:'', //回填物流信息
logi_code:'', //物流公司
reship_id:'',
mode: 'aspectFill',
order_id: '', //订单号
order_status: '', //订单状态
submitStatus: false
}
},
methods: {
//提交按钮
submitBtn() {
this.submitStatus = true;
if (this.logino == '') {
this.$common.errorToShow('请输入退货快递信息');
this.submitStatus = false;
return false;
}
let data = {
logi_no: this.logi_no,
logi_code:this.logi_code,
reship_id: this.reship_id,
};
this.$api.sendShip(data, res => {
if (res.status) {
this.$common.successToShow('提交成功', ress => {
this.submitStatus = false;
uni.navigateBack({
delta: 1
});
});
} else {
this.$common.errorToShow(res.msg);
this.submitStatus = false;
}
});
},
repeat() {
this.$common.navigateTo('../after_sale/index?order_id='+this.order_id);
},
// 图片点击放大
clickImg (img) {
// 预览图片
uni.previewImage({
urls: img.split()
});
}
},
//页面加载
onLoad(options) {
let data = {
aftersales_id: options.aftersales_id
}
this.$api.afterSalesInfo(data, res => {
if(res.status){
let info = res.data.info;
if (info.type == 1){
this.ttype = 1;
this.type_name = '仅退款';
}else{
this.ttype = 2;
this.type_name = '退款退货';
}
this.refund = info.refund;
this.images = info.images;
this.reason = info.reason;
this.reship_info = res.data.reship;
this.order_id = info.order_id;
this.order_status = info.order_status;
if(info.mark){
this.mark = info.mark;
}
if(info.status == 1){
this.status = 1;
this.status_name = '审核中';
}else if(info.status == 2){
this.status = 2;
this.status_name = '申请通过';
//退款单状态
if (info.bill_refund) {
if (info.bill_refund.status == 1) {
this.refund_status = 1;
this.refund_name = '退款中';
} else if (info.bill_refund.status == 2) {
this.refund_status = 2;
this.refund_name = '退款成功';
}
}
//退货单状态
if(info.bill_reship){
this.reship_id = info.bill_reship.reship_id
if(info.bill_reship.status == 1) {
this.reship_status = 1;
this.reship_name = '待发退货';
} else if (info.bill_reship.status == 2) {
this.reship_status = 2;
this.reship_name = '待收退货';
this.logi_no = info.bill_reship.logi_no;
this.logi_code = info.bill_reship.logi_code;
} else {
this.reship_status = 3;
this.reship_name = '已收退货';
this.logi_no = info.bill_reship.logi_no;
this.logi_code = info.bill_reship.logi_code;
}
}
}else{
this.status = 3;
this.status_name = '申请驳回';
}
//售后单明细,如果有退货单明细,就用退货单明细,否则就用售后单明细
// if(info.bill_reship.items){
// page.data.items = info.bill_reship.items;
// }else{
// page.data.items = info.items;
// }
} else {
this.$common.errorToShow(res.msg);
}
});
}
}
</script>
<style>
.back-img{
width: 100%;
height: 200upx;
position: relative;
background-color: #FF7159;
}
.back-img image{
width: 100%;
height: 100%;
position: absolute;
}
.back-img-c{
width: 100%;
height: 100%;
color: #fff;
position: relative;
z-index: 99;
padding: 50upx;
}
.back-img-t{
font-size: 32upx;
}
.back-img-b{
font-size: 24upx;
}
.list-goods-name{
width: 100% !important;
}
.invoice-type .uni-list-cell{
display: inline-block;
font-size: 26upx;
color: #333;
position: relative;
margin-left: 50upx;
}
.invoice-type .uni-list-cell>view{
display: inline-block;
}
.invoice-type-icon{
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.invoice-type-c{
margin-left: 50upx;
line-height: 2;
}
.cell-item-ft .cell-bd-input{
text-align: right;
width: 500upx;
font-size: 28upx;
}
.cell-item-bd .cell-bd-input{
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.right-img{
border-bottom: 0;
}
.cell-textarea{
padding: 0 26upx 20upx;
font-size: 26upx;
color: #333;
word-wrap: break-word;
}
.evaluate-c-b{
overflow: hidden;
padding: 0 20upx;
}
.upload-img{
width: 146upx;
height: 146upx;
margin: 14upx;
text-align: center;
color: #999999;
font-size: 22upx;
border: 2upx solid #E1E1E1;
border-radius: 4upx;
display: inline-block;
float: left;
padding: 24upx 0;
}
.goods-img-item{
width: 174upx;
height: 174upx;
padding: 14upx;
float: left;
position: relative;
}
.goods-img-item:nth-child(4n){
margin-right: 0;
}
.goods-img-item image{
width: 100%;
height: 100%;
}
.del{
width: 30upx !important;
height: 30upx !important;
position: absolute;
right: 0;
top: 0;
z-index: 999;
}
.black-text .cell-bd-text{
font-size: 28upx;
}
</style>
index.vue
<template>
<view class="content">
<form @submit="submit" report-submit='true'>
<view class="content-top">
<view class="img-list cart-list">
<checkbox-group class="cart-checkbox" @change="checkboxChange">
<view class="cart-checkbox-item" v-for="(item, key) in items" :key="key">
<label class="uni-list-cell uni-list-cell-pd">
<view class="cart-checkbox-c"><checkbox :value='item.id' :checked="item.checked" color="#FF7159"/></view>
<view class="img-list-item">
<image class="img-list-item-l little-img have-none" :src="item.image_url" mode="aspectFill"></image>
<view class="img-list-item-r little-right">
<view class="little-right-t">
<view class="goods-name list-goods-name">{{item.name}}</view>
</view>
<view class="goods-item-c">
<view class="goods-buy">
<!-- 商品规格 -->
<view class="goods-salesvolume">
{{item.addon}} x{{item.nums}}
</view>
</view>
</view>
</view>
</view>
</label>
</view>
</checkbox-group>
</view>
<view class='cell-group margin-cell-group'>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>服务类型</view>
</view>
<view class='cell-item-ft'>
<view class="uni-form-item uni-column invoice-type">
<!-- <radio-group class="uni-list" @change="radioChange">
<label class="uni-list-cell uni-list-cell-pd" v-for="(item,index) in type_list" :key="index">
<view>
<radio :id="item.name" :value="item.name" :checked="item.checked"></radio>
</view>
<view>
<label class="label-2-text" :for="item.name">
<text>{{item.value}}</text>
</label>
</view>
</label>
</radio-group> -->
<!-- #ifndef MP-ALIPAY -->
<radio-group class="uni-list" @change="radioChange">
<label class="uni-list-cell uni-list-cell-pd" v-for="(item, index) in type_list" :key="index">
<view class="invoice-type-icon">
<radio class="a-radio" :id="item.name" :value="item.value" :checked="item.checked" :disabled="item.disabled"></radio>
</view>
<view class="invoice-type-c">
<label class="label-2-text" :for="item.name">
<text>{{item.name}}</text>
</label>
</view>
</label>
</radio-group>
<!-- #endif -->
<!-- #ifdef MP-ALIPAY -->
<jhlable></jhlable>
<!-- #endif -->
</view>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>退款金额</view>
</view>
<view class='cell-item-ft'>
<input class='cell-bd-input red-price' v-model="refund" :disabled="refund_input_noedit"></input>
</view>
</view>
</view>
<view class='cell-group margin-cell-group'>
<view class='cell-item right-img'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>上传凭证</view>
</view>
</view>
<view class="">
<view class="evaluate-c-b">
<view class="goods-img-item" v-for="(item, key) in images" :key="key">
<image class="del" src="/static/image/del.png" mode="" @click="delImage(item)"></image>
<image class="" :src="item.url" mode="" @click="clickImg(item.url)"></image>
</view>
<view class="upload-img" v-show="isImage" @click="upImage">
<image class="icon" src="/static/image/camera.png" mode=""></image>
<view class="">上传照片</view>
</view>
</view>
</view>
</view>
<view class='cell-group margin-cell-group'>
<view class='cell-item right-img'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>问题描述</view>
</view>
</view>
<view class="cell-textarea ">
<textarea v-model="reason" placeholder="请您在此描述问题(最多200字)" maxlength="200"/>
</view>
</view>
</view>
<view class="button-bottom">
<button class="btn btn-b btn-square" formType="submit" :disabled='submitStatus' :loading='submitStatus'>提交</button>
</view>
</form>
</view>
</template>
<script>
import jhlable from '@/components/jihai-lable.vue'
export default {
data() {
return {
type_list: [
{ value: '1', name: '仅退款', checked: true, disabled: false },
{ value: '2', name: '退货退款', checked: false, disabled:false },
],
order_id:'',
items:[], //退货明细
item_ids:[], //选择的退货
aftersale_type:1, //售后类型1退款,2退款退货
refund:0, //退款金额,等于已支付的金额减去已退款的金额
refund_show:0,
images:[], //图片
reason:'', //原因
image_max: 5, //用于前台判断上传图片按钮是否显示
refund_input_noedit: true,
mode: 'aspectFill',
submitStatus: false
}
},
components: { jhlable },
computed: {
isImage() {
let num = this.image_max - this.images.length;
if(num > 0) {
return true;
}else{
return false;
}
}
},
methods: {
// 单选框点击切换
radioChange: function(evt) {
this.type_list.forEach(item => {
if (item.value === evt.target.value) {
item.checked = true;
this.aftersale_type = evt.target.value;
}else{
item.checked = false;
}
});
if(this.type_list[0].checked){
this.refund_input_noedit = true;
}else{
this.refund_input_noedit = false;
}
},
//订单商品信息
getOrderInfo() {
let data = {
order_id: this.order_id
}
this.$api.afterSalesStatus(data, res => {
if (res.status) {
//如果不是未支付的,已取消的,已完成的状态,就都可以售后
if (res.data.text_status != 1 && res.data.text_status != 6 && res.data.text_status != 7){
//判断是已付款未发货,如果是,就禁用退货
let type_list = this.type_list;
if (res.data.text_status == 2){
type_list[1].disabled = true;
}
//设置已选中的商品
let nums = 0;
for(var i=0;i<res.data.items.length;i++){
// if(res.data.items[i].sendnums > res.data.items[i].reship_nums){
// nums = res.data.items[i].sendnums - res.data.items[i].reship_nums;
// }
res.data.items[i].id = res.data.items[i].id.toString();
nums = res.data.items[i].nums;
res.data.items[i].checked = true;
this.item_ids = this.item_ids.concat({ id: res.data.items[i].id, nums: nums });
}
this.items = res.data.items;
this.refund = res.data.payed - res.data.refunded;
this.refund_show = res.data.payed - res.data.refunded;
this.type_list = type_list;
}else{
this.$common.errorToBack('订单不可以进行售后');
}
} else {
this.$common.errorToBack('没有找到此订单');
}
});
},
//退货商品选择
checkboxChange (e) {
let nums = 0;
this.item_ids = [];
for (var i = 0; i < e.detail.value.length; i++) {
let k = e.detail.value[i];
for(var j = 0; j < this.items.length; j++){
if(this.items[j].id == k) {
if(this.items[j].sendnums > this.items[j].reship_nums) {
nums = this.items[j].sendnums - this.items[j].reship_nums;
this.item_ids = this.item_ids.concat({ id: k, nums: nums });
}
}
}
}
},
//提交
submit(e) {
this.submitStatus = true;
let images = [];
for(var i = 0; i<this.images.length; i++) {
images = images.concat(this.images[i].image_id);
}
//判断退款金额
let reg = /^[0-9]+(.[0-9]{1,2})?$/;
if (!reg.test(this.refund)) {
this.$common.errorToShow('请输入正确金额');
this.submitStatus = false;
return false;
} else {
if (this.refund > this.refund_show) {
this.$common.errorToShow('退款金额过大');
this.submitStatus = false;
return false;
}
}
//组装数据,提交数据
let data = {
order_id:this.order_id,
type: this.aftersale_type,
items:this.item_ids,
images:images,
refund: this.refund,
reason:this.reason
};
// #ifdef MP-WEIXIN
data['formId'] = e.detail.formId;
// #endif
this.$api.addAfterSales(data, res => {
if(res.status){
this.$common.successToShow('提交成功', ress => {
this.submitStatus = false;
uni.navigateBack({
delta: 1
});
});
}else{
this.$common.errorToShow(res.msg);
this.submitStatus = false;
}
});
},
//上传图片
upImage() {
let num = this.image_max - this.images.length;
if(num > 0){
this.$api.uploadImage(num, res => {
if(res.status){
this.images.push(res.data);
this.$common.successToShow(res.msg);
}else{
this.$common.errorToShow(res.msg);
}
});
}
},
//删除图片
delImage(e) {
let newImages = [];
for(var i = 0; i < this.images.length; i++) {
if(this.images[i].image_id != e.image_id){
newImages.push(this.images[i]);
}
}
this.images = newImages;
},
// 图片点击放大
clickImg (img) {
// 预览图片
uni.previewImage({
urls: img.split()
});
}
},
onLoad(e) {
this.order_id = e.order_id;
this.getOrderInfo();
}
}
</script>
<style>
.list-goods-name{
width: 100% !important;
}
.cart-checkbox-item{
position: relative;
}
.invoice-type .uni-list-cell{
display: inline-block;
font-size: 26upx;
color: #333;
position: relative;
margin-left: 50upx;
}
.invoice-type .uni-list-cell>view{
display: inline-block;
}
.invoice-type-icon{
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.invoice-type-c{
margin-left: 50upx;
line-height: 2;
}
.cell-item-ft .cell-bd-input{
text-align: right;
width: 500upx;
font-size: 28upx;
}
.right-img{
border-bottom: 0;
}
.cell-textarea{
padding: 0 26upx 20upx;
}
.cell-textarea textarea{
width: 100%;
height: 200upx;
font-size: 26upx;
color: #333;
}
.evaluate-c-b{
overflow: hidden;
padding: 0 20upx;
}
.upload-img{
width: 146upx;
height: 146upx;
margin: 14upx;
text-align: center;
color: #999999;
font-size: 22upx;
border: 2upx solid #E1E1E1;
border-radius: 4upx;
display: inline-block;
float: left;
padding: 24upx 0;
}
.goods-img-item{
width: 174upx;
height: 174upx;
padding: 14upx;
float: left;
position: relative;
}
.goods-img-item:nth-child(4n){
margin-right: 0;
}
.goods-img-item image{
width: 100%;
height: 100%;
}
.del{
width: 30upx !important;
height: 30upx !important;
position: absolute;
right: 0;
top: 0;
z-index: 999;
}
/* #ifdef MP-ALIPAY */
/* #endif */
</style>
list.vue
<template>
<view class="content">
<view class="order-list">
<view class="goods-detail" v-for="(item, key) in order" :key="key" v-if="item.order && item.order.items">
<view class="order-item">
<view class='cell-group'>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>售后单号:{{item.aftersales_id}}</view>
<button class='btn btn-g btn-small' hover-class="btn-hover" @click="copyData(item.aftersales_id)">复制</button>
</view>
<view class='cell-item-ft'>
<text class='cell-ft-text' v-if="item.status == 1">待审核</text>
<text class='cell-ft-text' v-else-if="item.status == 2">审核通过</text>
<text class='cell-ft-text' v-else-if="item.status == 3">审核拒绝</text>
</view>
</view>
</view>
<view class='img-list' v-if="item.order && item.order.items">
<view class='img-list-item' v-for="(v, k) in item.order.items" :key="k" @click="showOrder(item.aftersales_id)">
<image class='img-list-item-l little-img' :src='v.image_url' mode='aspectFill'></image>
<view class='img-list-item-r little-right'>
<view class='little-right-t'>
<view class='goods-name list-goods-name'>{{v.name}}</view>
<view class='goods-price'>¥{{v.price}}</view>
</view>
<view class='goods-item-c'>
<view class='goods-buy'>
<view class='goods-salesvolume' v-if="v.addon">{{v.addon}}</view>
<view class='goods-num'>× {{v.nums}}</view>
</view>
</view>
</view>
</view>
</view>
<!-- <view class='cell-group'>
<view class='cell-item'>
<view class='cell-item-ft goods-num'>
<text class='cell-ft-text'>合计<text class="red-price">¥{{item.order.order_amount}}(含运费¥{{item.order.cost_freight}})</text></text>
<text class='cell-ft-text'>共计{{item.countnum}}件商品</text>
</view>
</view>
</view> -->
<view class='order-list-button'>
<button class='btn btn-circle btn-b' @click="showOrder(item.aftersales_id)">查看详情</button>
</view>
</view>
</view>
<uni-load-more :status="loadStatus"></uni-load-more>
</view>
</view>
</template>
<script>
import {
tools
} from '@/config/mixins.js'
import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue'
export default {
mixins: [tools],
components: {
uniLoadMore
},
data() {
return {
order: [], //订单列表
page: 1, //当前页
limit: 5, //每页显示几条
loadStatus: 'more'
}
},
onShow() {
this.getOrderList();
},
onReachBottom () {
if (this.loadStatus === 'more') {
this.getOrderList()
}
},
methods: {
//获取订单数据
getOrderList() {
let data = {};
this.loadStatus = 'loading'
data['page'] = this.page;
data['limit'] = this.limit;
this.$api.afterSalesList(data, res => {
let orderList = this.dataFormat(res.data.list);
this.order = this.order.concat(orderList);
this.page = res.data.page*1+1;
let allpage = res.data.total_page;
if(allpage < this.page){
this.loadStatus = 'noMore'
}else{
this.loadStatus = 'more'
}
});
},
//数据格式处理
dataFormat(data) {
for (var i = 0; i < data.length; i++) {
let countnum = 0
if(data[i].order && data[i].order.items){
for (var j = 0; j < data[i].order.items.length; j++) {
countnum += data[i].order.items[j].nums;
}
data[i].countnum = countnum;
}
}
return data;
},
//查看详情
showOrder(aftersales_id) {
this.$common.navigateTo('detail?aftersales_id=' + aftersales_id);
}
},
}
</script>
<style>
.segmented-control {
width: 100%;
background-color: #fff;
position: fixed;
top: 88upx;
z-index: 999;
}
.segmented-control-item{
line-height: 70upx;
}
.order-list{
/* margin-top: 64upx; */
}
.order-item{
margin-bottom: 20upx;
}
.img-list{
margin-top: 2upx;
}
.cell-group,.img-list-item {
background-color: #fff;
}
.cell-hd-title{
font-size: 22upx;
color: #666;
}
.cell-ft-text{
top: 0;
font-size: 22upx;
color: #333;
}
.order-list-button{
width: 100%;
background-color: #fff;
text-align: right;
padding: 10upx 26upx;
}
.order-list-button .btn{
height: 50upx;
line-height: 50upx;
}
.order-list-button .btn-w{
margin-left: 20upx;
}
.goods-num .cell-ft-text{
color: #999;
}
.goods-num .cell-ft-text:first-child{
margin-left: 10upx;
}
.order-none{
text-align: center;
padding: 200upx 0;
}
.order-none-img{
width: 274upx;
height: 274upx;
}
</style>
balance
add_bankcard.vue
<template>
<view class="content">
<view class="content-top">
<view class='cell-group'>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>银行卡号</view>
</view>
<view class='cell-item-bd'>
<input type="number" class='cell-bd-input' v-model="cardNumber" focus @blur="checkCard()" placeholder='请输入银行卡号'></input>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>持卡人</view>
</view>
<view class='cell-item-bd'>
<input type="text" class='cell-bd-input' v-model="name" placeholder='请输入持卡人姓名'></input>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>银行名称</view>
</view>
<view class='cell-item-bd'>
<input type="text" class='cell-bd-input' :disabled="true" v-model="bankName"></input>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>银行卡类型</view>
</view>
<view class='cell-item-bd'>
<input type="text" class='cell-bd-input' :disabled="true" v-model='cardTypeName'></input>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>开户行名</view>
</view>
<view class='cell-item-bd'>
<input type="text" class='cell-bd-input' v-model="accountBank" placeholder='请输入开户银行名'></input>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>开户行地址</view>
</view>
<view class='cell-item-bd'>
<input :value="pickerValue" @focus="showThreePicker"></input>
<area-picker ref="areaPicker" :areaId="areaId" :defaultIndex="defaultIndex" @onConfirm="onConfirm"></area-picker>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' src='/static/image/ic-pull-down.png' @click="showThreePicker"></image>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>设为默认</view>
</view>
<view @click="defaultChange">
<view class='cell-item-ft'>
<label class="radio"><radio value="1" :checked="checked" color="#333"/></label>
</view>
</view>
</view>
</view>
</view>
<view class="button-bottom">
<!-- <button class="btn btn-square btn-w" @click="delShip" v-show="id && id != 0" hover-class="btn-hover2">删除</button> -->
<button class="btn btn-square btn-b" @click="addCard" hover-class="btn-hover2" :disabled='submitStatus' :loading='submitStatus'>保存</button>
</view>
</view>
</template>
<script>
import areaPicker from "@/components/area-picker/areaPicker.vue";
export default {
components: {
areaPicker
},
data() {
return {
bankName: '', // 银行名称
cardType: 1, // 卡类型
cardTypeName: '', // 卡片类型
bankCode: '', // 银行缩写码
accountBank: '', // 开户行
cardNumber: '', // 银行卡号
name: '', // 开户人姓名
mobile: '', //
region: ['北京市', '北京市', '东城区'],
areaId: 110101,
address: '',
is_def: 2,
checked: false,
pickerValue: '',
defaultIndex: [0, 0, 0],
submitStatus: false
}
},
computed: {},
methods: {
// 省市区联动初始化
showThreePicker() {
this.$refs.areaPicker.showPicker();
},
// 选择收货地址
onConfirm(e) {
let province_name = e[0].name;
let city_name = e[1].name;
let county_name = e[2].name;
this.pickerValue = e[0].name+ " "+ e[1].name+" "+e[2].name
let data = {
province_name: province_name,
city_name: city_name,
county_name: county_name
}
let regionName = [province_name, city_name, county_name];
this.$api.getAreaId(data, res => {
if (res.status) {
this.areaId = res.data
} else {
uni.showModal({
title: '提示',
content: '地区选择出现问题,请重新选择地区',
showCancel: false
});
}
});
},
// 选择/取消默认
defaultChange () {
this.checked = !this.checked
this.is_def = this.is_def === 1 ? 2 : 1
},
//存储收货地址
saveShip() {
if(this.id && this.id != 0){
//编辑存储
let data = {
'id': this.id,
'name': this.name,
'address': this.address,
'mobile': this.mobile,
'is_def': this.is_def
}
data['area_id'] = this.areaId,
this.$api.editShip(data, res => {
if(res.status){
this.$common.successToShow('编辑成功', function(){
uni.navigateBack({
delta: 1
});
});
}else{
this.$common.errorToShow(res.msg);
}
});
}else{
//添加
let data = {
'area_id': this.areaId,
'name': this.name,
'address': this.address,
'mobile': this.mobile,
'is_def': this.is_def
}
this.$api.saveUserShip(data, res => {
if(res.status){
this.$common.successToShow('添加成功', function(){
uni.navigateBack({
delta: 1
});
});
}else{
this.$common.errorToShow(res.msg);
}
});
}
},
// 判断获取银行卡类型
checkCard () {
if (this.cardNumber) {
let data = {
card_code: this.cardNumber
}
this.$api.getBankCardOrganization(data, res => {
if (res.status) {
let data = res.data
this.bankName = data.name
this.cardType = data.type
this.bankCode = data.bank_code
this.cardTypeName = data.type_name
} else {
this.$common.errorToShow(res.msg, () => {
this.bankCode = this.bankName = this.cardType = this.cardTypeName = ''
})
}
})
} else {
this.bankCode = this.bankName = this.cardType = this.cardTypeName = ''
}
},
// 添加银行卡
addCard () {
if (!this.cardNumber) {
this.$common.errorToShow('请输入银行卡号')
} else if (!this.bankName || !this.cardType || !this.bankCode) {
this.$common.errorToShow('请输入正确的银行卡号')
} else if (!/^[\u4E00-\u9FA5]{2,4}$/.test(this.name)) {
this.$common.errorToShow('请输入正确的持卡人名称')
} else if (!this.areaId) {
this.$common.errorToShow('请选择开户行所在地区')
} else if (!this.accountBank) {
this.$common.errorToShow('请输入开户银行信息')
} else {
this.submitStatus = true;
let data = {
bankName: this.bankName,
areaId: this.areaId,
accountBank: this.accountBank,
accountName: this.name,
bankCode: this.bankCode,
cardNumber: this.cardNumber,
cardType: this.cardType,
isDefault: this.is_def
}
this.$api.addBankCard(data, res => {
if (res.status) {
this.$common.successToShow(res.msg, ress => {
this.submitStatus = false;
uni.navigateBack({
delta: 1
});
})
} else {
this.$common.errorToShow(res.msg);
this.submitStatus = false;
}
})
}
},
// #ifdef MP-ALIPAY
// alipay bank
aliPayBank() {
if(this.cardNumber.length >= 16 && this.cardNumber.length <= 19){
let data = {
card_code: this.cardNumber
}
this.$api.getBankCardOrganization(data, res => {
if (res.status) {
let data = res.data
this.bankName = data.name
this.cardType = data.type
this.bankCode = data.bank_code
this.cardTypeName = data.type_name
} else {
this.$common.errorToShow(res.msg, () => {
this.bankCode = this.bankName = this.cardType = this.cardTypeName = ''
});
}
})
} else {
this.bankCode = this.bankName = this.cardType = this.cardTypeName = ''
}
}
// #endif
},
onLoad(e) {
if(e.ship_id){
//编辑
this.id = e.ship_id;
this.getShipInfo();
}else{
//添加
this.pickerValue = this.region[0]+ " "+ this.region[1]+" "+this.region[2];
}
},
onBackPress() {
if (this.$refs.areaPicker.pickerShow) {
this.$refs.areaPicker.closePicker();
return true;
}
},
// #ifdef MP-ALIPAY
watch: {
cardNumber () {
this.$common.throttle(this.aliPayBank, this, 450);
}
},
// #endif
}
</script>
<style>
.user-head{
height: 100upx;
}
.user-head-img{
height: 90upx;
width: 90upx;
border-radius: 50%;
}
.cell-hd-title{
color: #333;
}
.cell-item-bd{
color: #666;
font-size: 26upx;
}
.button-bottom .btn {
width: 50%;
}
/* #ifdef MP-ALIPAY */
input{
font-size: 24upx;
}
/* #endif */
</style>
bankcard.vue
<template>
<view class="content">
<view class="content-top" v-if="cards.length">
<view class="card-item"
v-for="(item, index) in cards"
:key="index"
>
<view class="card-item-tip" v-if="item.is_default === 1">
<view class="cit-bg"></view>
<view class="cit-text">默</view>
</view>
<view class="card-item-body">
<view class="cib-left">
<image class="bank-logo" :src="item.bank_logo" mode=""></image>
</view>
<view class="cib-right">
<view class="cibr-t color-3">
{{ item.bank_name }} - {{ item.card_type }}
</view>
<view class="cibr-b color-9">
{{ item.card_number }}
</view>
</view>
</view>
<view class="mr-card"
v-if="item.is_default === 2"
@click="setDefault(item.id)"
>
<button class="btn btn-w" :disabled='submitStatus' :loading='submitStatus'>设为默认</button>
</view>
<view class="del-card"
v-if="mold"
@click="selected(index)"
>
<button class="btn btn-b">选择</button>
</view>
<view class="del-card"
v-else
@click="removeCard(item.id)"
>
<button class="btn btn-b" :disabled='delSubmitStatus' :loading='delSubmitStatus'>删除</button>
</view>
</view>
</view>
<view class="cards-none" v-else>
<image class="cards-none-img" src="/static/image/order.png" mode=""></image>
</view>
<view class="button-bottom">
<button class="btn btn-b" @click="goAddcard()">添加银行卡</button>
</view>
</view>
</template>
<script>
export default {
data () {
return {
mold: '',
cards: [] ,// 我的银行卡列表
submitStatus: false,
delSubmitStatus: false
}
},
onLoad (options) {
if (options.mold && options.mold == 'select') {
this.mold = options.mold
}
},
onShow () {
this.getBankCards()
},
methods:{
// 获取我的银行卡列表
getBankCards() {
this.$api.getBankCardList({}, res => {
if (res.status) {
this.cards = res.data
}
})
},
// 删除银行卡
removeCard (cardId) {
this.$common.modelShow('提示', '确定删除该银行卡?', res => {
this.delSubmitStatus = true;
let data = {
id: cardId
}
this.$api.removeBankCard(data, res => {
if (res.status) {
this.$common.successToShow(res.msg, ress => {
this.delSubmitStatus = false;
this.getBankCards();
})
} else {
this.$common.errorToShow(res.msg);
this.delSubmitStatus = false;
}
})
})
},
// 设置默认卡
setDefault (id) {
this.submitStatus = true;
let data = {
id: id
}
this.$api.setDefaultBankCard(data, res => {
if (res.status) {
this.$common.successToShow(res.msg, ress => {
this.submitStatus = false;
this.getBankCards();
})
} else {
this.$common.errorToShow(res.msg);
this.submitStatus = false;
}
})
},
// 添加新的银行卡
goAddcard(){
this.$common.navigateTo('./add_bankcard')
},
selected (index) {
let pages = getCurrentPages();//当前页
let beforePage = pages[pages.length - 2];//上个页面
// #ifdef H5
beforePage.cardInfo = this.cards[index]
// #endif
// #ifdef MP-WEIXIN
beforePage.$vm.cardInfo = this.cards[index]
// #endif
// #ifdef MP-ALIPAY
beforePage.rootVM.cardInfo = this.cards[index]
// #endif
uni.navigateBack({
delta: 1
})
}
}
}
</script>
<style>
.card-item{
position: relative;
background-color: #fff;
margin: 26upx;
border-radius: 10upx;
box-shadow: 0 0 20upx #ccc;
padding: 60upx 30upx 80upx;
}
.card-item-tip{
position:absolute;
top:0upx;
left:0upx;
z-index:10;
border-top-left-radius:10upx;
overflow:hidden;
width:100upx;
height:100upx;
}
.cit-bg{
position:absolute;
top:0;
left:0;
z-index:11;
color:#ffffff;
width:0upx;
height:0upx;
border-bottom:solid 100upx transparent;
border-right:solid 100upx transparent;
border-top:solid 100upx #FF7159;
}
.cit-text{
position:absolute;
top:0;
left:0;
z-index:12;
color:#ffffff;
margin-top:4upx;
margin-left:14upx;
font-size:30upx;
}
.card-item-body{
position: relative;
}
.cib-left{
position: absolute;
top: 60%;
transform: translateY(-50%);
width: 250upx;
}
.bank-logo{
width: 240upx;
height: 70upx;
}
.cib-right{
margin-left: 250upx;
}
.cibr-t{
font-size: 30upx;
margin-bottom: 10upx;
text-align: center;
}
.cibr-b{
font-size: 26upx;
text-align: center;
}
.mr-card{
position: absolute;
right: 140upx;
bottom: 0upx;
}
.del-card{
position: absolute;
right: 30upx;
bottom: 0upx;
}
.del-card .btn,.mr-card .btn{
font-size: 24upx;
height: 48upx;
line-height: 46upx;
padding: 0 16upx;
}
.cards-none{
text-align: center;
padding: 200upx 0;
}
.cards-none-img{
width: 274upx;
height: 274upx;
}
</style>
cashlist.vue
<template>
<view class="content">
<view class='cell-group'>
<view class='cell-item right-img'>
<view class='cell-item-hd'>
<view class='cell-hd-title color-6'>类型筛选</view>
</view>
<view class='cell-item-bd'>
<view class="uni-list">
<view class="uni-list-cell-db color-6">
<picker @change="changeState" :value="index" :range="objectType">
<view class="uni-input">{{objectType[index]}}</view>
</picker>
</view>
<image class='right-img icon' src='/static/image/ic-pull-down.png'></image>
</view>
</view>
</view>
</view>
<view class="type-c"
v-if="list.length"
>
<view class="cell-group margin-cell-group"
v-for="(item, index) in list"
:key="index"
>
<view class="cell-item">
<view class="cell-item-hd">
<view class='cell-hd-title'>{{ item.type }}</view>
</view>
<view class="cell-item-ft">
<view class="cell-ft-p color-9">
{{ item.ctime }}
</view>
</view>
</view>
<view class="cell-item">
<view class="cell-item-hd">
<view class='cell-hd-title color-9'>提现卡号:{{ item.card_number }}</view>
</view>
<view class="cell-item-ft red-price">
{{ item.money }}
</view>
</view>
</view>
<uni-load-more
:status="loadStatus"
></uni-load-more>
</view>
<view class="order-none" v-else>
<image class="cash-none-img" src="/static/image/order.png" mode=""></image>
</view>
</view>
</template>
<script>
import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue'
export default {
components: {
uniLoadMore
},
data() {
return {
objectType: ['全部', '待审核', '提现成功', '提现失败'],
index: 0, // 默认选中的类型 索引
page: 1,
limit: 10,
list: [],
states: [0, 1, 2, 3], // 不同类型的状态
loadStatus: 'more'
}
},
onLoad () {
this.getCash()
},
onReachBottom () {
if (this.loadStatus === 'more') {
this.getCash()
}
},
methods: {
// 切换类型
changeState (e) {
if (this.index !== e.target.value) {
this.index = e.target.value;
this.page = 1
this.list = []
}
},
// 获取余额明细
getCash () {
let data = {
page: this.page,
limit: this.limit
}
if (this.states[this.index]) {
data.type = this.states[this.index]
}
this.loadStatus = 'loading'
this.$api.cashList(data, res => {
if (res.status) {
if (this.page >= res.total) {
// 没有数据了
this.loadStatus = 'noMore'
} else {
// 未加载完毕
this.loadStatus = 'more'
this.page ++
}
this.list = [...this.list, ...res.data]
} else {
this.$common.errorToShow(res.msg)
}
})
}
},
watch: {
index () {
this.getCash()
}
}
}
</script>
<style>
.uni-list{
overflow: hidden;
}
.uni-list-cell-db{
float: left;
padding-top: 8upx;
margin-right: 6upx;
display: inline-block;
}
.uni-list .right-img{
float: left;
}
.cell-item-bd{
font-size: 26upx;
}
.type-c .cell-group{
padding: 10upx 0;
}
.type-c .cell-item{
border: none;
min-height: 70upx;
padding: 0 26upx 0 0;
}
.type-c .cell-item .red-price{
font-size: 50upx;
}
.type-c .cell-item .color-9{
font-size: 24upx;
}
.order-none{
text-align: center;
padding: 200upx 0;
}
.cash-none-img{
width: 274upx;
height: 274upx;
}
</style>
details.vue
<template>
<view class="content">
<view class='cell-group'>
<view class='cell-item right-img'>
<view class='cell-item-hd'>
<view class='cell-hd-title color-6' style="top: 0;">类型筛选</view>
</view>
<view class='cell-item-bd down-pull'>
<view class="uni-list">
<view class="uni-list-cell-db color-6">
<picker @change="changeState" :value="index" :range="objectType">
<view class="uni-input">{{objectType[index]}}</view>
</picker>
</view>
<image class='right-img icon' src='/static/image/ic-pull-down.png'></image>
</view>
</view>
</view>
</view>
<view class="type-c"
v-if="list.length"
>
<view class="cell-group margin-cell-group"
v-for="(item, index) in list"
:key="index"
>
<view class="cell-item">
<view class="cell-item-hd">
<view class='cell-hd-title'>{{ item.type }}</view>
</view>
<view class="cell-item-ft">
<view class="cell-ft-p color-9">
{{ item.ctime }}
</view>
</view>
</view>
<view class="cell-item">
<view class="cell-item-hd">
<view class='cell-hd-title color-9'>余额:{{ item.balance }}</view>
</view>
<view class="cell-item-ft red-price">
{{ item.money }}
</view>
</view>
</view>
<uni-load-more
:status="loadStatus"
></uni-load-more>
</view>
<view class="order-none" v-else>
<image class="balance-none-img" src="/static/image/order.png" mode=""></image>
</view>
</view>
</template>
<script>
import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue'
export default {
components: {
uniLoadMore
},
data() {
return {
objectType: ['全部', '消费', '退款', '充值', '提现', '佣金', '平台调整'],
index: 0, // 默认选中的类型 索引
page: 1,
limit: 10,
list: [],
states: [0, 1, 2, 3, 4, 5, 7], // 不同类型的状态
loadStatus: 'more'
}
},
onLoad (e) {
if(e.status){
this.index = this.states.indexOf(parseInt(e.status));
}else{
this.balances()//修复多次加载问题
}
},
onReachBottom () {
if (this.loadStatus === 'more') {
this.balances()
}
},
methods: {
// 切换类型
changeState (e) {
if (this.index !== e.target.value) {
this.index = e.target.value;
this.page = 1
this.list = []
}
},
// 获取余额明细
balances () {
let data = {
type: this.states[this.index],
page: this.page,
limit: this.limit
}
this.loadStatus = 'loading'
this.$api.getBalanceList(data, res => {
if (res.status) {
if (this.page >= res.total) {
// 没有数据了
this.loadStatus = 'noMore'
} else {
// 未加载完毕
this.loadStatus = 'more'
this.page ++
}
this.list = [...this.list, ...res.data]
} else {
this.$common.errorToShow(res.msg)
}
})
}
},
watch: {
index () {
this.balances();
}
}
}
</script>
<style>
.uni-list{
overflow: hidden;
}
.uni-list-cell-db{
float: left;
/* padding-top: 8upx; */
margin-right: 6upx;
display: inline-block;
height: 50upx;
line-height: 50upx;
}
.uni-list .right-img{
float: left;
}
.cell-item-bd{
font-size: 26upx;
}
.type-c .cell-group{
padding: 10upx 0;
}
.type-c .cell-item{
border: none;
min-height: 70upx;
padding: 0 26upx 0 0;
}
.type-c .cell-item .red-price{
font-size: 50upx;
}
.type-c .cell-item .color-9{
font-size: 24upx;
}
.order-none{
text-align: center;
padding: 200upx 0;
}
.balance-none-img{
width: 274upx;
height: 274upx;
}
.down-pull{
position: absolute;
top: 50%;
transform: translateY(-50%);
left: 120upx;
}
</style>
index.vue
<template>
<view class="content">
<view class='withdrawcash-top'>
<text class='withdrawcash-title'>账户余额(元)</text>
<text class='withdrawcash-num'>{{ userInfo.balance }}</text>
</view>
<view class='cell-group margin-cell-group right-img'>
<view class='cell-item'>
<view class='cell-item-hd' @click="navigateToHandle('./recharge')">
<image class='cell-hd-icon' src='/static/image/topup.png'></image>
<view class='cell-hd-title'>账户充值</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd' @click="navigateToHandle('./withdraw_cash')">
<image class='cell-hd-icon' src='/static/image/withdraw.png'></image>
<view class='cell-hd-title'>余额提现</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd' @click="navigateToHandle('./details')">
<image class='cell-hd-icon' src='/static/image/detail.png'></image>
<view class='cell-hd-title'>余额明细</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd' @click="navigateToHandle('./cashlist')">
<image class='cell-hd-icon' src='/static/image/record.png'></image>
<view class='cell-hd-title'>提现记录</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd' @click="navigateToHandle('./bankcard')">
<image class='cell-hd-icon' src='/static/image/card.png'></image>
<view class='cell-hd-title'>我的银行卡</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data () {
return {
userInfo: {}
}
},
onShow () {
this.getUserInfo()
},
methods: {
// 获取用户信息
getUserInfo () {
this.$api.userInfo({}, res => {
if (res.status) {
this.userInfo = res.data
} else {
this.$common.errorToShow(res.msg)
}
})
},
// 页面跳转
navigateToHandle (pageUrl) {
this.$common.navigateTo(pageUrl)
}
}
}
</script>
<style>
.withdrawcash-top{
padding: 40upx 26upx;
background-color: #FF7159;
color: #fff;
}
.withdrawcash-title{
font-size: 28upx;
display: block
}
.withdrawcash-num{
font-size: 70upx;
display: block;
margin-top: 20upx;
margin-left: 50upx;
}
.margin-cell-group {
margin: 20upx 0;
color: #666666;
}
</style>
recharge.vue
<template>
<view class="content">
<view class="content-top">
<view class='cell-group margin-cell-group'>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>当前金额</view>
</view>
<view class='cell-item-bd'>
<text class="cell-bd-view">¥{{ user.balance }}</text>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>充值金额</view>
</view>
<view class='cell-item-bd'>
<input class='cell-bd-input' placeholder='请输入要充值的金额' v-model="money" focus type="digit"></input>
</view>
</view>
</view>
</view>
<view class="button-bottom">
<button class="btn btn-square btn-b" hover-class="btn-hover2" @click="navigateToHandle">去支付</button>
</view>
</view>
</template>
<script>
export default {
data () {
return {
user: {}, // 用户信息
payments: [], // 可用充值方式列表
money: '', // 充值的金额
orderType: 2 // 充值类型
}
},
onLoad () {
this.userInfo()
},
methods: {
// 获取用户信息
userInfo () {
this.$api.userInfo({}, res => {
if (res.status) {
this.user = res.data
}
})
},
// 去充值
navigateToHandle () {
if (!Number(this.money)) {
this.$common.errorToShow('请输入要充值的金额')
} else {
this.$common.navigateTo('/pages/goods/payment/index?recharge=' + Number(this.money) + '&type=' + this.orderType)
}
}
}
}
</script>
<style>
.user-head{
height: 100upx;
}
.user-head-img{
height: 90upx;
width: 90upx;
border-radius: 50%;
}
.cell-hd-title{
color: #333;
}
.cell-item-bd{
color: #666;
font-size: 26upx;
}
.button-bottom .btn {
width: 100%;
}
</style>
withdraw_cash.vue
<template>
<view class="content">
<view class="content-top">
<!-- 我的银行卡信息 -->
<view class='cell-group margin-cell-group'
v-if="userbankCard"
@click="toBankCardList"
>
<view class='cell-item right-img'>
<view class='cell-item-hd'>
<image class="yl-logo" :src="cardInfo.bank_logo" mode=""></image>
</view>
<view class='cell-item-bd'>
<text class="cell-bd-view">{{ cardInfo.card_number }}</text>
</view>
<view class="cell-item-ft">
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
</view>
<view class='cell-group margin-cell-group'
v-else
@click="toBankCardList"
>
<view class='cell-item right-img'>
<view class='cell-item-hd'>
<image class="yl-logo" src="/static/image/yl.png" mode=""></image>
</view>
<view class='cell-item-bd'>
<text class="cell-bd-view">请添加银行卡</text>
</view>
<view class="cell-item-ft">
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
</view>
<!-- 提现金额手续费 提现金额input -->
<view class='cell-group margin-cell-group'>
<view class='cell-item'>
<view class='cell-item-bd' v-if="tocashExplain">
<view class='cell-hd-title' style="color: #666;">{{ tocashExplain }}</view>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-bd withdrawcash-input'>
<view class='cell-hd-title'><text>¥</text><input type="number" focus v-model="money"/></view>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-bd'>
<view class='cell-hd-title' style="color: #666;" v-show="!isError">可用余额 {{ user.balance }} 元</view>
<view class='cell-hd-title' style="color: #f00;" v-show="isError">提现金额超过可用余额</view>
</view>
</view>
</view>
</view>
<view class="button-bottom">
<button class="btn btn-square btn-b" hover-class="btn-hover2" v-if="isSubmit" @click="toCash" :disabled='submitStatus' :loading='submitStatus'>确认提现</button>
<button class="btn btn-square btn-b" hover-class="btn-hover2" v-else-if="!isSubmit" disabled>确认提现</button>
</view>
</view>
</template>
<script>
export default {
data () {
return {
cardInfo: {}, // 我的银行卡信息
user: {}, // 用户信息
isError: false, // 当提现金额大于可用余额 显示错误提示
isSubmit: false, // 提现点击
money: '', // 用户输入的提现金额
submitStatus: false
}
},
onLoad () {
this.userBankCard()
this.userInfo()
},
computed: {
userbankCard () {
if (Object.keys(this.cardInfo).length) {
return true
} else {
return false
}
},
// 店铺提现手续费
tocashMoneyRate () {
return this.$store.state.config.tocash_money_rate
},
// 店铺提现最低金额
tocashMoneyLow () {
return this.$store.state.config.tocash_money_low
},
// 提现文字说明
tocashExplain () {
if (this.tocashMoneyRate && this.tocashMoneyLow) {
return '最低提现金额 ' + this.tocashMoneyLow + ' 元(收取 ' + this.tocashMoneyRate + ' %服务费)'
} else if (this.tocashMoneyLow) {
return '最低提现金额 ' + this.tocashMoneyLow + ' 元'
} else if (this.tocashMoneyRate) {
return '收取 ' + this.tocashMoneyRate + ' %服务费'
} else {
return ''
}
}
},
methods: {
// 获取我的默认银行卡信息
userBankCard () {
this.$api.getDefaultBankCard({}, res => {
if (res.status) {
this.cardInfo = res.data
}
})
},
// 获取用户信息
userInfo () {
// 获取我的余额信息
// 获取用户的可用余额
this.$api.userInfo({}, res => {
this.user = res.data
})
},
// 去提现
toCash () {
if (!Object.keys(this.cardInfo).length) {
this.$common.errorToShow('请选择要提现的银行卡')
return false
} else if (!this.money) {
this.$common.errorToShow('请输入要提现的金额')
return false
} else if (Number(this.money) === 0) {
this.$common.errorToShow('提现金额不能为0')
} else {
this.submitStatus = true;
this.$api.userToCash({
money: this.money,
cardId: this.cardInfo.id
}, res => {
if (res.status) {
this.$common.successToShow(res.msg, () => {
this.submitStatus = false;
uni.navigateBack({
delta: 1
});
})
} else {
this.$common.errorToShow(res.msg);
this.submitStatus = false;
}
})
}
},
// 跳转我的银行卡列表
toBankCardList () {
this.$common.navigateTo('./bankcard?mold=select')
}
},
watch: {
money () {
// 比较用户的输入金额 如果大于可用金额
if (this.money === '' || Number(this.money) <= 0) {
this.isSubmit = false
} else if (Number(this.money) > Number(this.user.balance)) {
this.isError = true
this.isSubmit = false
} else if (Number(this.money) < Number(this.tocashMoneyLow)) {
this.isError = false
this.isSubmit = false
} else {
this.isError = false
this.isSubmit = true
}
}
}
}
</script>
<style>
.user-head{
height: 100upx;
}
.user-head-img{
height: 90upx;
width: 90upx;
border-radius: 50%;
}
.cell-hd-title{
color: #333;
}
.cell-item{
border: none;
}
.cell-item-bd{
color: #666;
font-size: 26upx;
}
.button-bottom .btn {
width: 100%;
}
.yl-logo{
width: 188upx;
height: 54upx;
float: left;
}
.withdrawcash-input{
font-size: 50upx;
border-bottom: 2upx solid #e8e8e8;
padding-bottom: 20upx;
}
.withdrawcash-input text{
font-size: 40upx;
}
.withdrawcash-input input{
display: inline-block;
min-width: 500upx;
padding-left: 20upx;
}
/* #ifdef MP-ALIPAY */
.cell-hd-title input {
font-size: 24px;
height: 18px;
}
/* #endif */
</style>
collection
index.vue
<template>
<view class="content">
<view class="collection" v-if="list.length">
<view class="container_of_slide"
v-for="(item, index) in list"
:key="index"
>
<view class="slide_list"
@touchstart="touchStart($event,index)"
@touchend="touchEnd($event,index)"
@touchmove="touchMove($event,index)"
@tap="recover(index)"
:style="{transform:'translate3d('+item.slide_x+'px, 0, 0)'}"
v-if="item.goods"
>
<view class="now-message-info" hover-class="uni-list-cell-hover" :style="{width:Screen_width+'px'}"
@click="goodsDetail(item.goods_id)">
<view class="icon-circle">
<image class='goods-img' :src="item.goods.image_url" mode="aspectFill"></image>
</view>
<view class="list-right">
<view class="list-title">{{ item.goods.name }}</view>
<view class="red-price">¥{{ item.goods.price }}</view>
<view class="list-detail">{{ item.ctime }}</view>
</view>
<view class="list-right-1">
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
<view class="group-btn">
<view class="removeM btn-div" @tap="collect(index)">
取消
</view>
</view>
<view style="clear:both"></view>
</view>
</view>
<uni-load-more
:status="loadStatus"
></uni-load-more>
</view>
<view class="collection-none" v-else>
<image class="collection-none-img" src="/static/image/order.png" mode=""></image>
</view>
</view>
</template>
<script>
import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue'
import { goods } from '@/config/mixins.js'
export default {
mixins: [ goods ],
components: {
uniLoadMore
},
computed: {
Screen_width() {
return uni.getSystemInfoSync().windowWidth;
}
},
data() {
return {
visible: false,
start_slide_x: 0,
btnWidth: 0,
startX: 0,
LastX: 0,
startTime: 0,
screenName: '',
page: 1,
limit: 10,
list: [], // 商品浏览足迹
loadStatus: 'more'
};
},
onLoad () {
this.goodsCollectionList()
},
onShow() {
const res = uni.getSystemInfoSync();
},
onReachBottom () {
if (this.loadStatus === 'more') {
this.goodsCollectionList()
}
},
methods: {
goodsCollectionList () {
let data = {
page: this.page,
limit: this.limit
}
this.loadStatus = 'loading'
this.$api.goodsCollectionList(data, res => {
if (res.status) {
let _list = res.data.list
_list.forEach (item => {
this.$set(item, 'slide_x', 0)
item.ctime = this.$common.timeToDate(item.ctime)
})
this.list = [...this.list, ..._list]
if (res.data.count > this.list.length) {
this.page ++
this.loadStatus = 'more'
} else {
this.loadStatus = 'noMore'
}
} else {
this.$common.errorToShow(res.msg)
}
})
},
cancelEvent(){
this.visible = false
},
// 滑动开始
touchStart(e, index) {
this.startCilentY = e.touches[0].clientY;
//记录手指放上去的时间
this.startTime = e.timeStamp;
//记录滑块的初始位置
this.start_slide_x = this.list[index].slide_x;
// 按钮宽度
uni.createSelectorQuery()
.selectAll('.group-btn')
.boundingClientRect()
.exec(res => {
if (res[0] != null) {
this.btnWidth = res[0][index].width * -1;
}
});
// 记录上一次开始时手指所处位置
this.startX = e.touches[0].pageX;
// 记录上一次手指位置
this.lastX = this.startX;
//初始化非当前滑动消息列的位置
this.list.forEach((item, eq) => {
if (eq !== index) {
item.slide_x = 0;
}
});
},
// 滑动中
touchMove(e, index) {
var endCilentY = e.touches[0].clientY;
var moveClientY = endCilentY - this.startCilentY;
if (this.direction === 'Y' || Math.abs(moveClientY ) > 20 || e.currentTarget.dataset.disabled === true) { this.direction = ''; return; }
const endX = e.touches[0].pageX;
const distance = endX - this.lastX;
// 预测滑块所处位置
const duang = this.list[index].slide_x + distance;
// 如果在可行区域内
if (duang <= 0 && duang >= this.btnWidth) {
this.list[index].slide_x = duang;
}
// 此处手指所处位置将成为下次手指移动时的上一次位置
this.lastX = endX;
},
// 滑动结束
touchEnd(e, index) {
let distance = 10;
const endTime = e.timeStamp;
const x_end_distance = this.startX - this.lastX;
if (Math.abs(endTime - this.startTime) > 200) {
distance = this.btnWidth / -2;
}
// 判断手指最终位置与手指开始位置的位置差距
if (x_end_distance > distance) {
this.list[index].slide_x = this.btnWidth;
} else if (x_end_distance < distance * -1) {
this.list[index].slide_x = 0;
} else {
this.list[index].slide_x = this.start_slide_x;
}
},
// 点击回复原状
recover(index) {
this.list[index].slide_x = 0;
},
// 取消收藏
collect (index) {
let data = {
goods_id: this.list[index].goods_id
}
this.$api.goodsCollection(data, res => {
if (res.status) {
this.$common.successToShow(res.msg, () => {
this.$nextTick(() => {
this.list.splice(index, 1)
})
})
} else {
this.$common.errorToShow(res.msg)
}
})
}
}
};
</script>
<style scoped>
.collection .goods-img{
width: 150upx;
height: 150upx;
}
.container_of_slide {
width: 100%;
overflow: hidden;
}
.slide_list {
transition: all 100ms;
transition-timing-function: ease-out;
min-width: 200%;
}
.now-message-info {
box-sizing:border-box;
display: flex;
align-items: center;
font-size: 16px;
clear:both;
padding: 20upx 26upx;
margin-bottom: 2upx;
background: #FFFFFF;
}
.now-message-info,
.group-btn {
float: left;
}
.group-btn {
display: flex;
flex-direction: row;
height: 190upx;
min-width: 100upx;
align-items: center;
}
.group-btn .btn-div {
height: 190upx;
color: #fff;
text-align: center;
padding: 0 50upx;
font-size: 34upx;
line-height: 190upx;
}
.group-btn .top {
background-color: #FFAA33;
}
.group-btn .removeM {
background-color: #ff3b44;
}
.icon-circle{
width:150upx;
height: 150upx;
float: left;
}
.list-right{
float: left;
margin-left: 25upx;
height: 150upx;
}
.list-right-1{
float: right;
color: #A9A9A9;
}
.list-title{
width: 490upx;
line-height:1.5;
overflow:hidden;
color:#333;
display:-webkit-box;
-webkit-box-orient:vertical;
-webkit-line-clamp:2;
overflow:hidden;
font-size: 26upx;
color: #333;
min-height: 80upx;
}
.list-detail{
width: 460upx;
font-size: 24upx;
color: #a9a9a9;
display:-webkit-box;
-webkit-box-orient:vertical;
-webkit-line-clamp:1;
overflow:hidden;
}
.collection-none{
text-align: center;
padding: 200upx 0;
}
.collection-none-img{
width: 274upx;
height: 274upx;
}
</style>
coupon
index.vue
<template>
<view class="content">
<uni-segmented-control :current="current" :values="items" @clickItem="onClickItem" style-type="text" active-color="#333"></uni-segmented-control>
<view class="">
<view class="coupon-c-item" v-for="(item, key) in listData" :key="key">
<view class="cci-l">
<view class="cci-l-c color-f" v-if="current == 0">
coupon
</view>
<view class="cci-l-c color-f color-b" v-if="current != 0">
coupon
</view>
</view>
<view class="cci-r">
<view class="cci-r-c">
<view class="ccirc-t color-9">
{{item.name}}
</view>
<view class="ccirc-b">
<view class="ccirc-b-l">
<view class="ccirc-b-tip">
{{ item.expression1 + item.expression2 }}
</view>
<view class="ccirc-b-time color-9">
有效期:{{item.stime}} - {{item.etime}}
</view>
</view>
<view class="ccirc-b-r color-f" @click="goIndex" v-if="current == 0">
立即使用
</view>
</view>
</view>
</view>
</view>
<uni-load-more :status="loadStatus"></uni-load-more>
</view>
</view>
</template>
<script>
import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue'
import uniSegmentedControl from "@/components/uni-segmented-control/uni-segmented-control.vue";
export default {
components: {
uniSegmentedControl,uniLoadMore
},
data() {
return {
items: ['未使用','已使用','已失效'],
current: 0,
page: 1,
limit: 10,
listData: [],
loadStatus: 'more'
}
},
onLoad() {
this.getData();
},
onReachBottom () {
if (this.loadStatus === 'more') {
this.getData();
}
},
methods: {
// tab点击切换
onClickItem(index) {
if (this.current !== index) {
this.current = index;
this.page = 1;
this.listData = [];
this.getData();
}
},
//获取优惠券列表
getData() {
this.loadStatus = 'loading'
let data = {
page: this.page,
limit: this.limit
}
if (this.current == 0) {
data['display'] = 'no_used';
}
if (this.current == 1) {
data['display'] = 'yes_used';
}
if (this.current == 2) {
data['display'] = 'invalid';
}
this.$api.userCoupon(data, res => {
if (res.status) {
let now_type = 'no_used';
if (this.current == 1) {
now_type = 'yes_used';
}
if (this.current == 2) {
now_type = 'invalid';
}
if (now_type == res.data.q_type) {
if (res.data.page >= this.page) {
let newList = this.listData.concat(res.data.list);
this.listData = newList;
if (res.data.count > this.listData.length) {
this.page ++
this.loadStatus = 'more'
} else {
this.loadStatus = 'noMore'
}
}
}
}else{
this.$common.errorToShow(res.msg);
}
});
},
//跳转首页
goIndex() {
uni.switchTab({
url: '/pages/index/index'
});
}
}
}
</script>
<style>
.coupon-c-item{
margin: 30upx 50upx;
/* width: 100%; */
height: 150upx;
margin-bottom: 20upx;
}
.cci-l{
width: 60upx;
height: 100%;
background-color: #FF7159;
font-size: 32upx;
display: inline-block;
box-sizing: border-box;
float: left;
border-top-left-radius: 16upx;
border-bottom-left-radius: 16upx;
}
.cci-l-c{
height: 60upx;
line-height: 44upx;
width: 150upx;
text-align: center;
transform-origin: 30upx 30upx;
transform: rotate(90deg);
}
.cci-r{
position: relative;
height: 150upx;
width: calc(100% - 70upx);
margin-left: 10upx;
display: inline-block;
background-color: #fff;
}
.cci-r-img{
position: absolute;
width: 100%;
height: 100%;
background-color: #fff;
}
.cci-r-c{
position: relative;
z-index: 99;
}
.ccirc-t{
font-size: 24upx;
padding: 10upx 20upx;
}
.ccirc-b{
padding: 10upx;
position: relative;
}
.ccirc-b-l{
display: inline-block;
max-width: 400upx;
}
.ccirc-b-tip{
font-size: 28upx;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.ccirc-b-tip text{
font-size: 34upx;
}
.ccirc-b-time{
font-size: 24upx;
}
.ccirc-b-r{
display: inline-block;
background-color: #FF7159;
font-size: 26upx;
padding: 4upx 10upx;
border-radius: 4upx;
position: absolute;
right: 20upx;
bottom: 16upx;
}
.color-b{
background-color: #e5e5e5;
border-bottom-right-radius: 12upx;
border-bottom-left-radius: 12upx;
color: #fff;
}
</style>
distribution
agreement.vue
<template>
<view class="content">
<view class="article">
<view class="article-content">
<rich-text :nodes="content"></rich-text>
</view>
</view>
</view>
</template>
<script>
import htmlParser from '@/common/html-parser'
export default {
data() {
return {
content:this.$store.state.config.distribution_agreement,
}
},
onLoad(e) {
},
computed: {
},
methods: {
}
}
</script>
<style>
.content {
/* #ifdef H5 */
height: calc(100vh - 90upx);
/* #endif */
/* #ifndef H5 */
height: 100vh;
/* #endif */
background-color: #fff;
}
.article {
padding: 20upx;
}
.article-title {
font-size: 32upx;
color: #333;
margin-bottom: 20upx;
/* text-align: center; */
position: relative;
height: 100upx;
}
.article-time {
/* text-align: right; */
margin-left: 20upx;
}
.article-content {
font-size: 28upx !important;
color: #666;
line-height: 1.6;
margin-top: 20upx;
}
.article-content p img {
width: 100% !important;
}
.shop-logo {
width: 60upx;
height: 60upx;
border-radius: 50%;
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.shop-name {
line-height: 100upx;
margin-left: 80upx;
}
</style>
apply.vue
<template>
<view class="content">
<view class="apply-c">
<view class="apply-top">
<view class='cell-group'>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>姓名</view>
</view>
<view class='cell-item-bd'>
<input type="text" class='cell-bd-input' placeholder='请填您的姓名' v-model="name"></input>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>微信</view>
</view>
<view class='cell-item-bd'>
<input type="text" class='cell-bd-input' placeholder='请填您的微信' v-model="weixin"></input>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>QQ</view>
</view>
<view class='cell-item-bd'>
<input type="number" class='cell-bd-input' placeholder='请填您的QQ' v-model="qq"></input>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>手机</view>
</view>
<view class='cell-item-bd'>
<input type="number" class='cell-bd-input' placeholder='请填写您的手机号码' v-model="mobile"></input>
</view>
</view>
</view>
<view class="apply-tip color-6 fsz26">
<label class="radio" @click="agreeAgreement"><radio value="1" :checked="checked" color="#FF7159"/>我已经阅读并接受</label><text class="" @click="goAgreement()">"分销协议"</text>
</view>
</view>
<view class="apply-bot">
<button class="btn btn-square btn-o btn-all" hover-class="btn-hover" @click="goApplyState()">申请成为分销</button>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
name: '',
weixin: '',
qq: '',
mobile: '',
checked: false,
is_agree: 'off'
}
},
methods: {
// 是否同意协议
agreeAgreement(){
if(this.checked){
this.checked = false;
this.is_agree = 'off';
}else{
this.checked = true;
this.is_agree = 'on';
}
// console.log(this.checked)
},
// 信息验证
checkData (data) {
if (!data.name) {
this.$common.errorToShow('请输入您的姓名')
return false
} else if (!data.weixin) {
this.$common.errorToShow('请输入您的微信')
return false
} else if (!data.qq) {
// console.log(this.is_agree)
this.$common.errorToShow('请输入您的QQ')
return false
} else if (!data.mobile) {
this.$common.errorToShow('请输入您的手机号')
return false
} else if (data.mobile.length !== 11) {
this.$common.errorToShow('手机号格式不正确')
return false
} else if (data.agreement != 'on') {
//console.log(data)
this.$common.errorToShow('请钩选分销协议')
return false
} else {
return true
}
},
// 提交审核
goApplyState() {
let data = {
name: this.name,
weixin: this.weixin,
qq: this.qq,
mobile: this.mobile,
agreement: this.is_agree,
}
if (this.checkData(data)) {
this.$api.applyDistribution(data, res => {
if(res.status){
this.$common.successToShow(res.msg, function(){
uni.navigateTo({
url:'./apply_state'
});
});
}else{
this.$common.errorToShow(res.msg);
}
});
}
},
goAgreement(){
uni.navigateTo({
url: './agreement'
})
}
}
}
</script>
<style>
.content{
background-color: #FF7159;
height: calc(100vh - 44px);
padding-top: 50upx;
}
.apply-c{
margin: 40upx auto;
padding: 26upx 0;
border-radius: 30upx;
box-shadow: 0 0 10px #aaa;
width: 670upx;
min-height: 400upx;
background-color: #fff;
}
.apply-top .cell-item{
width: 610upx;
}
.apply-top .cell-item:last-child{
border-bottom: 1px solid #f3f3f3;
}
.apply-top .cell-item .cell-item-hd{
min-width: 120upx;
}
.apply-top .cell-item .cell-bd-input{
width: 100%;
}
.apply-tip{
padding: 26upx;
}
.apply-bot{
width: 100%;
text-align: center;
}
.apply-bot .btn{
border-radius: 50upx;
width: 90%;
margin: 40upx auto 0;
}
</style>
apply_state.vue
<template>
<view class="content">
<view class="apply-c">
<view class="apply-top fsz36 color-o" v-if="info.verify==2">
恭喜,您的申请已提交!
</view>
<view class="apply-top-refuse fsz36 color-o" v-if="info.verify==3">
抱歉,您的申请被驳回!
</view>
<view class="apply-top fsz36 color-o" v-if="info.verify==1">
恭喜,您的申请已通过!
</view>
<view class="apply-bot" v-if="info.verify==2">
<view class="apply-bot-sop">
<view class="abs-img">
<image class="icon" src="/static/image/del.png" mode=""></image>
</view>
<view class="color-9 abs-mid" >
<image class="dot" src="/static/image/dot-o.png" mode=""></image>
<image class="dot" src="/static/image/dot-o.png" mode=""></image>
<image class="dot" src="/static/image/dot-o.png" mode=""></image>
<image class="dot" src="/static/image/dot-o.png" mode=""></image>
<image class="dot" src="/static/image/dot-o.png" mode=""></image>
<image class="dot" src="/static/image/dot-o.png" mode=""></image>
<image class="dot" src="/static/image/dot-g.png" mode=""></image>
<image class="dot" src="/static/image/dot-g.png" mode="" ></image>
<image class="dot" src="/static/image/dot-g.png" mode="" ></image>
<image class="dot" src="/static/image/dot-g.png" mode="" ></image>
<image class="dot" src="/static/image/dot-g.png" mode="" ></image>
<image class="dot" src="/static/image/dot-g.png" mode="" ></image>
</view>
<view class="abs-img">
<image class="icon" src="/static/image/close.png" mode=""></image>
</view>
</view>
<view class="apply-bot-text">
<view class="abt-c">
<view class="color-6 fsz30">
申请提交成功
</view>
<view class="color-9 fsz24">
{{info.ctime}}
</view>
</view>
<view class="abt-c">
<view class="color-6 fsz30" v-if="info.verify==2">
等待审核
</view>
<view class="color-6 fsz30" v-if="info.verify==3">
审核驳回
</view>
<view class="color-6 fsz30" v-if="info.verify==1">
审核通过
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
info: {}
}
},
onLoad:function() {
var _this = this;
_this.$api.getDistributioninfo({check_condition:true}, function(res) {
if (res.status) {
if(res.data.need_apply && res.data.condition_status ==false){
_this.$common.redirectTo('/pages/member/distribution/index');
}
if(res.data.verify == 1){//审核通过
_this.$common.redirectTo('/pages/member/distribution/user');
}
_this.info = res.data;
} else {
//报错了
_this.$common.errorToShow(res.msg);
}
});
},
methods: {
}
}
</script>
<style>
.content{
height: calc(100vh - 44px);
padding-top: 50upx;
}
.apply-c{
margin: 40upx auto;
text-align: center;
padding: 26upx;
border-radius: 30upx;
box-shadow: 0 0 10px #aaa;
width: 670upx;
min-height: 400upx;
background-color: #fff;
}
.apply-top{
margin-top: 40upx;
}
.apply-top-refuse{
margin-top: 140upx;
}
.apply-bot{
width: 100%;
text-align: center;
}
.apply-bot-sop{
position: relative;
height: 60upx;
width: 65%;
margin: 40upx auto 20upx;
display: flex;
line-height: 1.7555;
/* vertical-align: middle; */
}
.apply-bot-sop>view{
display: inline-block;
}
.abs-img{
flex: 1;
}
.abs-img image{
position: relative;
top: 50%;
transform: translateY(-50%);
}
.abs-mid{
/* font-size: 70upx; */
flex: 2;
display: flex;
}
.apply-bot-text{
display: flex;
}
.abt-c{
flex: 1;
}
.dot{
width: 8upx;
height: 8upx;
margin: 0 4upx;
}
</style>
index.vue
<template>
<view class="content">
<view class="content-top">
<view class="dist-head">
<view class="dist-head-top">
<view class="dht-margin color-f fsz34" v-if="condition.condition_status">已达标</view>
<view class="dht-margin color-f fsz34" v-if="!condition.condition_status">未达标</view>
<cmd-progress class="dht-margin" :percent="condition.condition_progress" :stroke-width="23" stroke-color="linear-gradient(to right, #ef32d9, #89fffd)"></cmd-progress>
<view class="dht-margin color-d fsz28">{{condition.condition_msg}}</view>
</view>
<view class="dist-head-tip color-f fsz24">
注:消费金额只算实付金额部分,储值抵扣/退款退货金额不算在内。
</view>
</view>
<view class="dist-body">
<view class="db-title color-3 fsz34">
分销商须知
</view>
<view class="db-body color-6 fsz30">
<text class="db-item">{{distributionNotes}}</text>
</view>
</view>
</view>
<view class="button-bottom">
<button class="btn btn-square btn-o" hover-class="btn-hover" v-if="condition.condition_status" @click="goApply()">申请</button>
<button class="btn btn-square btn-g" v-else >您的条件暂不满足</button>
</view>
</view>
</template>
<script>
import cmdProgress from '@/components/cmd-progress/cmd-progress.vue'
export default {
components: { cmdProgress },
data() {
return {
condition: {}
}
},
methods: {
goApply() {
this.$common.navigateTo('./apply');
}
},
computed: {
distributionNotes () {
return this.$store.state.config.distribution_notes
}
},
onLoad: function() {
var _this = this;
_this.$api.getDistributioninfo({}, function(res) {
if (res.status) {
_this.condition = res.data;
if(_this.condition.hasOwnProperty('verify')){
if(_this.condition.verify == 1 || (!_this.condition.need_apply && _this.condition_status)){
_this.$common.redirectTo('/pages/member/distribution/user');
}else if(_this.condition.condition_status){
_this.$common.redirectTo('/pages/member/distribution/apply_state');//待审核
}
}
} else {
//报错了
_this.$common.errorToShow(res.msg);
}
});
}
}
</script>
<style>
.content{
background-color: #fff;
height: calc(100vh - 44px);
}
.dist-head{
padding: 50upx 26upx 20upx;
text-align: center;
background: linear-gradient( #FF7159, #ff9785);
}
.dist-head-top{
padding: 0upx 50upx 30upx;
}
.dht-margin{
margin-bottom: 26upx;
}
.dht-margin.color-d{
padding: 0 40upx;
}
.dht-mid{
margin-bottom: 12upx;
}
.dist-head-tip{
text-align: left;
}
.dist-body{
padding: 26upx;
}
.db-title{
border-bottom: 2upx solid #ccc;
padding-bottom: 26upx;
}
.db-body{
padding: 26upx 10upx;
}
.db-item{
/* padding: ; */
margin-bottom: 14upx;
}
pre {
white-space: pre-wrap; /* css-3 */
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
word-wrap: break-word; /* Internet Explorer 5.5+ */
}
</style>
my_store.vue
<template>
<view class="content my-store">
<view class="" ref="myStore">
<view class="my-store-t">
<view class="mst-top">
<image :src="store_banner_src" mode="widthFix"></image>
</view>
<view class="mst-bot">
<view class='member-grid'>
<view class='member-item'>
<image class='member-item-img' :src='store_logo_src'></image>
</view>
<view class='member-item'>
<view class="color-o fsz36">{{total_goods}}</view>
<text class='member-item-text'>全部宝贝</text>
</view>
<view class='member-item' @click="openPopup()">
<image class='member-item-icon' src='/static/image/ic-me-collect.png'></image>
<text class='member-item-text'>收藏本店</text>
</view>
<view class='member-item'>
<!-- #ifdef MP-WEIXIN -->
<button class='share btn' open-type="share">
<image class='member-item-icon' src='/static/image/qr_code.png'></image>
<text class='member-item-text'>二维码</text>
</button>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<button class='share btn' @click="createPoster()">
<image class='member-item-icon' src='/static/image/qr_code.png'></image>
<text class='member-item-text'>二维码</text>
</button>
<!-- #endif -->
</view>
</view>
</view>
</view>
<view class="my-store-m">
<view class="search">
<view class="search-c" @click="goSearch">
<view class="search-input search-input-p">
<view class="search-input-p-c">
{{ searchKey }}
</view>
</view>
<image class="icon search-icon" src="/static/image/zoom.png"></image>
</view>
</view>
</view>
<!-- 收藏弹出窗 -->
<lvv-popup position="bottom" ref="lvvpopref" @click="closePopup()">
<view class="collect-pop" @click="closePopup()">
<image v-if="isWeixinBrowser" src="/static/image/wxh5.png" mode="widthFix"></image>
<!-- #ifdef MP-WEIXIN -->
<image src="/static/image/wxxcx.png" mode="widthFix"></image>
<!-- #endif -->
<!-- #ifdef H5 -->
<view class="h5-tip color-f fsz38">
<view>请将此页面添加浏览器书签</view>
<view>方便下次浏览</view>
</view>
<!-- #endif -->
</view>
</lvv-popup>
</view>
<!-- 商品列表 -->
<view class="img-grids">
<view v-if="goodsList.length>0">
<view class="img-grids-item" v-for="(item, index) in goodsList" :key="index" @click="goodsDetail(item.id)">
<image class="img-grids-item-t have-none" :src="item.image_url" mode='aspectFill'></image>
<view class="img-grids-item-b">
<view class="goods-name grids-goods-name">
{{item.name}}
</view>
<view class="goods-item-c">
<view class="goods-price red-price">¥{{item.price}}</view>
<image class="goods-cart" src="../../static/image/ic-car.png"></image>
</view>
</view>
</view>
</view>
<!-- 无数据时默认显示 -->
<view class="order-none" v-else>
<image class="order-none-img" src="../../static/image/order.png" mode=""></image>
</view>
</view>
<uni-load-more :status="loadStatus"></uni-load-more>
</view>
</template>
<script>
import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue'
import lvvPopup from '@/components/lvv-popup/lvv-popup.vue';
import {
apiBaseUrl
} from '@/config/config.js'
export default {
components: {
lvvPopup,
uniLoadMore
},
data() {
return {
goodsList: [],
loadStatus: 'more',
orderItems: [{
name: '全部宝贝',
nums: '115'
},
{
name: '收藏本店',
icon: '/static/image/ic-me-collect.png',
},
{
name: '二维码',
icon: '/static/image/qr_code.png',
}
],
storeCode: '',
store_name: '', //店铺名称
store_logo: '',
store_logo_src: '',
store_banner: '',
store_desc: '', //店铺介绍
store_banner_src: '',
isWeixinBrowser: this.$common.isWeiXinBrowser(), //判断是否是微信浏览器
total_goods: 0,
myShareCode: '', //邀请码
page: 1, //默认页码
searchKey: '请输入关键字搜索'
}
},
onShow: function() {
if (this.$store.state.config.distribution_store == '2') {
//跳转到首页
uni.switchTab({
url: '/pages/index/index'
});
}
},
//加载执行
onLoad: function(options) {
let store = options.store;
this.storeCode = store;
this.getDistribution(store);
this.getGoods();
this.getMyShareCode()
},
mounted() {
// #ifdef H5 || APP-PLUS
window.addEventListener('scroll', this.handleScroll)
// #endif
},
updated() {
// #ifndef MP-WEIXIN
// 获取上半部分的整体高度
this.$nextTick(() => {
let h = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; //浏览器高度
this.top_height = this.$refs.myStore.$el.clientHeight;
})
// #endif
},
methods: {
// 显示modal弹出框
openPopup() {
this.$refs.lvvpopref.show();
},
// 关闭modal弹出框
closePopup() {
this.$refs.lvvpopref.close();
},
//去搜索
goSearch() {
let pages = getCurrentPages();
let prevPage = pages[pages.length - 2];
// #ifdef H5 || MP-WEIXIN
if (prevPage && prevPage.route) {
let search_flag = prevPage.route;
if (search_flag == 'pages/index/search') {
uni.navigateBack({
delta: 1
});
} else {
this.$common.navigateTo('/pages/index/search');
}
} else {
this.$common.navigateTo('/pages/index/search');
}
// #endif
// #ifdef MP-ALIPAY
if (prevPage && prevPage.__proto__.route) {
let search_flag = prevPage.__proto__.route;
if (search_flag == 'pages/index/search') {
uni.navigateBack({
delta: 1
});
} else {
this.$common.navigateTo('/pages/index/search');
}
} else {
this.$common.navigateTo('/pages/index/search');
}
// #endif
},
//跳转到商品详情页面
goodsDetail: function(id) {
let url = '/pages/goods/index/index?id=' + id;
this.$common.navigateTo(url);
},
//取得商品数据
getGoods: function() {
let data = {
page: this.page,
limit: 10
}
this.loadStatus = 'loading'
this.$api.goodsList(data, res => {
if (res.status) {
if (this.page >= res.data.total_page) {
// 没有数据了
this.loadStatus = 'noMore'
} else {
// 未加载完毕
this.loadStatus = 'more'
this.page++
}
this.goodsList = [...this.goodsList, ...res.data.list]
} else {
this.$common.errorToShow(res.msg)
}
});
},
//获取分销商信息
getDistribution: function(store) {
let _this = this;
_this.$api.getStoreInfo({
store: store
}, function(res) {
if (res.status) {
_this.store_name = res.data.store_name;
_this.store_desc = res.data.store_desc;
_this.store_logo_src = res.data.store_logo_src;
_this.store_logo = res.data.store_logo;
_this.store_banner_src = res.data.store_banner_src;
_this.total_goods = res.data.total_goods;
uni.setNavigationBarTitle({
title: _this.store_name
});
} else {
//报错了
_this.$common.errorToShow(res.msg);
}
});
},
// 生成邀请海报
createPoster() {
let data = {
type: 4,
id: this.storeCode
}
let pages = getCurrentPages()
let page = pages[pages.length - 1]
let page_path = '/pages/share/jump';
// #ifdef H5
data.source = 1;
data.return_url = apiBaseUrl + 'wap/' + page_path;
// #endif
// #ifdef MP-WEIXIN
data.source = 2;
data.return_url = page_path;
// #endif
// #ifdef MP-ALIPAY
data.source = 3;
data.return_url = page_path;
// #endif
let userToken = this.$db.get('userToken')
if (userToken) {
data.token = userToken
}
this.$api.createPoster(data, res => {
if (res.status) {
this.$common.navigateTo('/pages/share?poster=' + res.data)
} else {
this.$common.errorToShow(res.msg)
}
})
},
getMyShareCode() {
let userToken = this.$db.get("userToken");
if (userToken && userToken != '') {
// 获取我的分享码
this.$api.shareCode({}, res => {
if (res.status) {
this.myShareCode = res.data ? res.data : '';
}
});
}
}
},
//上拉加载
onReachBottom() {
if (this.loadStatus === 'more') {
this.getGoods();
}
},
//分享
onShareAppMessage() {
let myInviteCode = this.myShareCode ? this.myShareCode : '';
let ins = this.$common.shareParameterDecode('type=9&invite=' + myInviteCode + "&id=" + this.storeCode);
let path = '/pages/share/jump?scene=' + ins;
return {
title: this.$store.state.config.share_title,
// #ifdef MP-ALIPAY
desc: this.$store.state.config.share_desc,
// #endif
imageUrl: this.$store.state.config.share_image,
path: path
}
}
}
</script>
<style>
.mst-top {
width: 100%;
}
.mst-top image {
width: 100%;
}
.member-grid {
border-top: 2upx solid #ddd;
background-color: #fff;
margin-bottom: 20upx;
}
.member-item {
border-right: 2upx solid #eee;
height: 90upx;
}
.member-item:last-child {
border-right: none;
}
.member-item-img {
width: 150upx;
height: 150upx;
top: -70upx;
position: absolute;
left: 42%;
transform: translateX(-50%);
border-radius: 10upx;
background-color: #fff;
border-radius: 6upx;
box-shadow: 0 0 10upx #ccc;
}
.img-grids {
padding-bottom: 26upx;
}
.img-grids-item {
margin-bottom: 0;
}
.scroll-Y {
/* #ifdef H5 */
height: calc(100vh - 44px - 0upx);
/* #endif */
/* #ifndef H5 */
height: calc(100vh - 0upx);
/* #endif */
position: position;
/* bottom: 0; */
/* padding-bottom:200upx */
}
.collect-pop {
width: 100%;
height: 100%;
/* background: #FFFFFF; */
position: absolute;
left: 0;
bottom: 0;
/* transform: ; */
}
.collect-pop image {
width: 100%;
}
.h5-tip {
text-align: center;
margin-top: 300upx;
}
.member-item .share {
background: none !important;
line-height: normal;
}
</style>
order.vue
<template>
<view class="content">
<view class="type-c" v-if="list.length">
<view class="cell-group margin-cell-group" v-for="(item, index) in list" :key="index">
<view class="cell-item">
<view class="cell-item-hd">
<view class='cell-hd-title'>下单人:{{ item.buy_user }}</view>
</view>
<view class="cell-item-ft">
<view class="cell-ft-p color-9">
{{ item.ctime }}
</view>
</view>
</view>
<view class="cell-item">
<view class="cell-item-hd">
<view class='cell-hd-title color-9'>订单号:{{ item.order_id }}</view>
</view>
<view class="cell-item-ft red-price">
{{ item.amount }}
</view>
</view>
</view>
<uni-load-more
:status="loadStatus"
></uni-load-more>
</view>
<view class="order-none" v-else>
<image class="balance-none-img" src="/static/image/order.png" mode=""></image>
</view>
</view>
</template>
<script>
import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue'
import { goods } from '@/config/mixins.js'
export default {
mixins: [ goods ],
components: {
uniLoadMore
},
data() {
return {
startTime: 0,
screenName: '',
page: 1,
limit: 10,
list: [], // 商品浏览足迹
loadStatus: 'more'
};
},
onLoad () {
this.getDistributionOrder()
},
onShow() {
const res = uni.getSystemInfoSync();
},
onReachBottom () {
if (this.loadStatus === 'more') {
this.getDistributionOrder()
}
},
methods: {
getDistributionOrder () {
let data = {
page: this.page,
limit: this.limit
}
this.loadStatus = 'loading'
this.$api.getDistributionOrder(data, res => {
//console.log(res);
if (res.status) {
let _list = res.data.list
_list.forEach (item => {
this.$set(item, 'slide_x', 0)
})
this.list = [...this.list, ..._list]
if (res.data.count > this.list.length) {
this.page ++
this.loadStatus = 'more'
} else {
this.loadStatus = 'noMore'
}
} else {
this.$common.errorToShow(res.msg)
}
})
},
}
};
</script>
<style scoped>
.type-c .cell-group{
padding: 10upx 0;
margin-top: 0;
}
.type-c .cell-item{
border: none;
min-height: 70upx;
padding: 0 26upx 0 0;
}
.type-c .cell-item .red-price{
font-size: 50upx;
}
.type-c .cell-item .color-9{
font-size: 24upx;
}
.order-none{
text-align: center;
padding: 200upx 0;
}
.balance-none-img{
width: 274upx;
height: 274upx;
}
</style>
popularize.vue
<template>
<view class="content">
<view class="content-c">
<view class="content-c-top color-6 fsz28">
将网站分享给您的好友,您的好友通过您的分享购买网站商品,你将会获得佣金。
</view>
<image class="qrcode-img" src="/static/demo-img/qcode.png" mode="widthFix"></image>
<view class="color-3 fsz26">
长按保存二维码图片
</view>
</view>
</view>
</template>
<script>
</script>
<style>
.content-c{
text-align: center;
padding: 50upx 0;
width: 80%;
margin: 0 auto;
}
.content-c-top{
text-align: left;
}
.qrcode-img{
width: 400upx;
height: 400upx;
/* margin-top: 50upx; */
margin: 50upx auto;
}
</style>
store_setting.vue
<template>
<view class="content">
<view class="content-top">
<view class='cell-group'>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>名称</view>
</view>
<view class='cell-item-bd'>
<input class='cell-bd-input' placeholder='请输入店铺名称' v-model="store_name"></input>
</view>
</view>
<view class='cell-item user-head'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>图标</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next user-head-img have-none' mode="aspectFill" :src="logo" @click="uploadLogo"></image>
</view>
</view>
</view>
<view class='cell-group'>
<view class='cell-item right-img'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>店招</view>
</view>
</view>
<view class="">
<view class="evaluate-c-b">
<view class="goods-img-item" v-for="(item, key) in images" :key="key">
<image class="del" src="/static/image/del.png" mode="" @click="delImage(item)"></image>
<image class="" :src="item.url" mode="" @click="clickImg(item.url)"></image>
</view>
<view class="upload-img" v-show="isImage" @click="upImage">
<image class="icon" src="/static/image/camera.png" mode=""></image>
<view class="">上传照片</view>
</view>
</view>
</view>
</view>
<view class='cell-group'>
<view class='cell-item right-img'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>简介</view>
</view>
</view>
<view class="cell-textarea ">
<textarea v-model="store_desc" placeholder="请您在此描述问题(最多200字)" maxlength="200" />
</view>
</view>
</view>
<view class="button-bottom">
<button class="btn btn-square btn-b" hover-class="btn-hover2" @click="submitHandler()">保存</button>
</view>
</view>
</template>
<script>
export default {
data() {
return {
title: 'picker',
logo: '',
index: 2,
images:[],
image_max: 1,
store_name:'',//店铺名称
store_logo:'',
store_banner:'',
store_desc:'',//店铺介绍
store_logo_src:'',
store_banner_src:'',
}
},
computed: {
isImage() {
let num = this.image_max - this.images.length;
if(num > 0) {
return true;
}else{
return false;
}
}
},
methods: {
// 用户上传头像
uploadLogo () {
this.$api.uploadFiles(res => {
if (res.status) {
this.store_logo = res.data.image_id;
this.logo = res.data.url;
} else {
this.$common.errorToShow(res.msg)
}
})
},
// 保存资料
submitHandler() {
if(!this.store_name||this.store_name==''){
this.$common.errorToShow('请填写店铺名称');
return;
}
if(this.images.length <= 0){
this.$common.errorToShow('请上传店招');
return;
}
if(!this.store_logo){
this.$common.errorToShow('请上传图标');
return;
}
this.store_banner = this.images[0].image_id;
this.$api.setStore({
store_name: this.store_name,
store_logo: this.store_logo,
store_banner: this.store_banner,
store_desc: this.store_desc
}, res => {
if(res.status){
this.$common.successToShow(res.msg, result => {
uni.navigateBack({
delta: 1
});
});
}else{
this.$common.errorToShow(res.msg);
}
}
);
},
//上传图片
upImage() {
let num = this.image_max - this.images.length;
if(num > 0){
this.$api.uploadImage(num, res => {
if(res.status){
this.images.push(res.data);
this.$common.successToShow(res.msg);
}else{
this.$common.errorToShow(res.msg);
}
});
}
},
//删除图片
delImage(e) {
let newImages = [];
for(var i = 0; i < this.images.length; i++) {
if(this.images[i].image_id != e.image_id){
newImages.push(this.images[i]);
}
}
this.images = newImages;
},
// 图片点击放大
clickImg (img) {
// 预览图片
uni.previewImage({
urls: img.split()
});
}
},
onLoad: function() {
var _this = this;
_this.$api.getDistributioninfo({check_condition:false}, function(res) {
if (res.status) {
_this.store_name = res.data.store_name;
_this.store_desc = res.data.store_desc;
_this.store_logo = res.data.store_logo;
if( res.data.store_logo){
_this.logo = res.data.store_logo_src;
}
_this.store_banner = res.data.store_banner;
if(_this.store_banner){
_this.images.push({
image_id:res.data.store_banner,
url:res.data.store_banner_src
});
}
} else {
//报错了
_this.$common.errorToShow(res.msg);
}
});
}
}
</script>
<style>
.user-head{
height: 100upx;
}
.user-head-img{
height: 90upx;
width: 90upx;
border-radius: 50%;
}
.cell-hd-title{
color: #333;
}
.cell-item-bd{
color: #666;
font-size: 26upx;
}
.list-goods-name{
width: 100% !important;
}
.cart-checkbox-item{
position: relative;
}
.invoice-type .uni-list-cell{
display: inline-block;
font-size: 26upx;
color: #333;
position: relative;
margin-left: 50upx;
}
.invoice-type .uni-list-cell>view{
display: inline-block;
}
.invoice-type-icon{
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.invoice-type-c{
margin-left: 50upx;
line-height: 2;
}
.cell-item-ft .cell-bd-input{
text-align: right;
width: 500upx;
font-size: 28upx;
}
.right-img{
border-bottom: 0;
}
.cell-textarea{
padding: 0 26upx 20upx;
}
.cell-textarea textarea{
width: 100%;
height: 200upx;
font-size: 26upx;
color: #333;
}
.evaluate-c-b{
overflow: hidden;
padding: 0 20upx;
}
.upload-img{
width: 146upx;
height: 146upx;
margin: 14upx;
text-align: center;
color: #999999;
font-size: 22upx;
border: 2upx solid #E1E1E1;
border-radius: 4upx;
display: inline-block;
float: left;
padding: 24upx 0;
}
.goods-img-item{
width: 174upx;
height: 174upx;
padding: 14upx;
float: left;
position: relative;
}
.goods-img-item:nth-child(4n){
margin-right: 0;
}
.goods-img-item image{
width: 100%;
height: 100%;
}
.del{
width: 30upx !important;
height: 30upx !important;
position: absolute;
right: 0;
top: 0;
z-index: 999;
}
.cell-textarea textarea{
background-color: #f8f8f8;
padding: 12upx 20upx;
box-sizing: border-box;
}
</style>
user.vue
<template>
<view class="content">
<!-- 用户头像header -->
<view class='member-top'>
<!-- <image class='bg-img' src='/static/image/member-bg.png'></image> -->
<view class='member-top-c'>
<view class="fsz50 color-f">{{info.total_settlement_amount}}</view>
<view class='fsz26 color-d'>累计收入</view>
</view>
</view>
<!-- 用户头像header end -->
<!-- 其他功能菜单 -->
<view class='member-grid'>
<view class='member-item' v-for="(item, index) in orderItems" :key="index">
<text class='member-item-text'>{{ item.name }}</text>
<view class="color-o fsz38">{{ item.nums }}</view>
</view>
</view>
<view class='cell-group margin-cell-group right-img'>
<view class='cell-item' v-for="(item, index) in utilityMenus" :key="index">
<view class='cell-item-hd' @click="navigateToHandle(item.router)">
<image class='cell-hd-icon' :src='item.icon'></image>
<view class='cell-hd-title'>{{ item.name }}</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd' @click="createPoster()">
<image class='cell-hd-icon' src='/static/image/extension.png'></image>
<view class='cell-hd-title'>我要推广</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
</view>
<!-- 其他功能菜单end -->
<jihaiCopyright></jihaiCopyright>
</view>
</template>
<script>
import jihaiCopyright from '@/components/jihai-copyright/jihaiCopyright.vue'
import {
checkLogin
} from '@/config/mixins.js'
import {
apiBaseUrl
} from '@/config/config.js'
export default {
components: {
jihaiCopyright
},
mixins: [checkLogin],
data() {
return {
// isClerk: false,
orderItems: {
freeze: {
name: '冻结金额',
nums: "0"
},
settlement: {
name: '已结算金额',
nums: '0'
},
current_month_order: {
name: '本月订单数',
nums: '0'
}
},
utilityMenus: {
invite: {
name: '我的邀请',
icon: '/static/image/ic-me-invite.png',
router: '../invite/list'
},
order: {
name: '推广订单',
icon: '/static/image/extension_order.png',
router: './order'
},
balance: {
name: '我的佣金',
icon: '/static/image/ic-me-balance.png',
router: '../balance/details?status=5'
},
my_store: {
name: '我的店铺',
icon: '/static/image/my_store.png',
router: './my_store'
},
store_setting: {
name: '店铺设置',
icon: '/static/image/me-ic-set.png',
router: './store_setting'
}
},
info: {}, //分销商信息
}
},
onShow() {
var _this = this;
if (_this.$store.state.config.distribution_store != '1') {
delete this.utilityMenus.my_store;
delete this.utilityMenus.store_setting;
}
_this.$api.getDistributioninfo({}, function(res) {
if (res.status) {
_this.info = res.data;
if (res.data.verify != 1) { //审核通过
_this.$common.redirectTo('/pages/member/distribution/index');
}
_this.orderItems.freeze.nums = _this.info.freeze_amount;
_this.orderItems.settlement.nums = _this.info.settlement_amount;
_this.orderItems.current_month_order.nums = _this.info.current_month_order;
if (_this.$store.state.config.distribution_store == '1') {
_this.utilityMenus.my_store.router = './my_store?store=' + _this.info.store;
}
} else {
//报错了
_this.$common.errorToShow(res.msg);
}
});
},
methods: {
navigateToHandle(pageUrl) {
this.$common.navigateTo(pageUrl)
},
orderNavigateHandle(url, tab = 0) {
if (!this.hasLogin) {
return this.checkIsLogin()
}
this.$store.commit('orderTab', tab)
this.$common.navigateTo(url)
},
goAfterSaleList() {
if (!this.hasLogin) {
return this.checkIsLogin()
}
this.$common.navigateTo('../after_sale/list')
},
// 生成邀请海报
createPoster() {
let data = {
type: 4,
id: this.info.store,
}
//console.log(this.info.store)
let pages = getCurrentPages()
let page = pages[pages.length - 1]
let page_path = '/pages/share/jump';
// #ifdef H5
data.source = 1;
data.return_url = apiBaseUrl + 'wap/' + page_path;
// #endif
// #ifdef MP-WEIXIN
data.source = 2;
data.return_url = page_path;
// #endif
// #ifdef MP-ALIPAY
data.source = 3;
data.return_url = page_path;
// #endif
let userToken = this.$db.get('userToken')
if (userToken) {
data.token = userToken
}
this.$api.createPoster(data, res => {
if (res.status) {
this.$common.navigateTo('/pages/share?poster=' + res.data)
} else {
this.$common.errorToShow(res.msg)
}
})
},
},
//分享
onShareAppMessage() {
let myInviteCode = this.myShareCode ? this.myShareCode : '';
let ins = this.$common.shareParameterDecode('type=3&invite=' + myInviteCode);
let path = '/pages/share/jump?scene=' + ins;
return {
title: this.$store.state.config.share_title,
// #ifdef MP-ALIPAY
desc: this.$store.state.config.share_desc,
// #endif
imageUrl: this.$store.state.config.share_image,
path: path
}
}
}
</script>
<style>
.member-top {
position: relative;
width: 100%;
height: 340upx;
background-color: #FF7159;
}
.bg-img {
position: absolute;
width: 100%;
height: 100%;
}
.member-top-c {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
}
.user-head-img {
display: block;
width: 160upx;
height: 160upx;
border-radius: 50%;
overflow: hidden;
background-color: rgba(255, 255, 255, 0.7);
}
.user-name {
font-size: 30upx;
color: #fff;
}
.member-grid {
background-color: #fff;
border-top: 2upx solid #eee;
padding: 20upx 0;
}
.margin-cell-group {
margin: 20upx 0;
color: #666666;
}
.badge {
left: 80upx;
top: -6upx;
}
button.cell-item-hd {
background-color: #fff;
padding: 0;
line-height: 1.4;
color: #333;
}
button.cell-item-hd:after {
border: none;
}
.login-btn {
color: #fff;
width: 160upx;
height: 50upx;
line-height: 50upx;
border-radius: 25upx;
background: #ff7159;
font-size: 12px;
margin-top: 16upx;
}
</style>
history
index.vue
<template>
<view class="content">
<view class="collection" v-if="list.length">
<view class="container_of_slide"
v-for="(item, index) in list"
:key="index"
>
<view class="slide_list"
@touchstart="touchStart($event,index)"
@touchend="touchEnd($event,index)"
@touchmove="touchMove($event,index)"
@tap="recover(index)"
:style="{transform:'translate3d('+item.slide_x+'px, 0, 0)'}"
v-if="item.goods"
>
<view class="now-message-info" hover-class="uni-list-cell-hover" :style="{width:Screen_width+'px'}"
@click="goodsDetail(item.goods_id)">
<view class="icon-circle">
<image class='goods-img' :src="item.goods.image_url" mode="aspectFill"></image>
</view>
<view class="list-right">
<view class="list-title">{{ item.goods.name }}</view>
<view class="red-price">¥{{ item.goods.price }}</view>
<view class="list-detail">{{ item.ctime }}</view>
</view>
<view class="list-right-1">
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
<view class="group-btn">
<view class="top btn-div" @tap="collect(index)" v-if="item.isCollection">
取消
</view>
<view class="top btn-div" @tap="collect(index)" v-if="!item.isCollection">
收藏
</view>
<view class="removeM btn-div" @tap="remove(index)">
删除
</view>
</view>
<view style="clear:both"></view>
</view>
</view>
<uni-load-more
:status="loadStatus"
></uni-load-more>
</view>
<view class="history-none" v-else>
<image class="history-none-img" src="/static/image/order.png" mode=""></image>
</view>
</view>
</template>
<script>
import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue'
import { goods } from '@/config/mixins.js'
export default {
mixins: [ goods ],
components: {
uniLoadMore
},
computed: {
Screen_width() {
return uni.getSystemInfoSync().windowWidth;
}
},
data() {
return {
visible: false,
start_slide_x: 0,
btnWidth: 0,
startX: 0,
LastX: 0,
startTime: 0,
screenName: '',
page: 1,
limit: 10,
list: [], // 商品浏览足迹
loadStatus: 'more'
};
},
onLoad () {
this.goodsBrowsing()
},
onShow() {
const res = uni.getSystemInfoSync();
},
onReachBottom () {
if (this.loadStatus === 'more') {
this.goodsBrowsing()
}
},
methods: {
goodsBrowsing () {
let data = {
page: this.page,
limit: this.limit
}
this.loadStatus = 'loading'
this.$api.goodsBrowsing(data, res => {
if (res.status) {
let _list = res.data.list
_list.forEach (item => {
this.$set(item, 'slide_x', 0)
item.ctime = this.$common.timeToDate(item.ctime)
})
this.list = [...this.list, ..._list]
if (res.data.count > this.list.length) {
this.page ++
this.loadStatus = 'more'
} else {
this.loadStatus = 'noMore'
}
} else {
this.$common.errorToShow(res.msg)
}
})
},
cancelEvent(){
this.visible = false
},
// 滑动开始
touchStart(e, index) {
this.startCilentY = e.touches[0].clientY;
//记录手指放上去的时间
this.startTime = e.timeStamp;
//记录滑块的初始位置
this.start_slide_x = this.list[index].slide_x;
// 按钮宽度
uni.createSelectorQuery()
.selectAll('.group-btn')
.boundingClientRect()
.exec(res => {
if (res[0] != null) {
this.btnWidth = res[0][index].width * -1;
}
});
// 记录上一次开始时手指所处位置
this.startX = e.touches[0].pageX;
// 记录上一次手指位置
this.lastX = this.startX;
//初始化非当前滑动消息列的位置
this.list.forEach((item, eq) => {
if (eq !== index) {
item.slide_x = 0;
}
});
},
// 滑动中
touchMove(e, index) {
var endCilentY = e.touches[0].clientY;
var moveClientY = endCilentY - this.startCilentY;
if (this.direction === 'Y' || Math.abs(moveClientY ) > 20 || e.currentTarget.dataset.disabled === true) { this.direction = ''; return; }
const endX = e.touches[0].pageX;
const distance = endX - this.lastX;
// 预测滑块所处位置
const duang = this.list[index].slide_x + distance;
// 如果在可行区域内
if (duang <= 0 && duang >= this.btnWidth) {
this.list[index].slide_x = duang;
}
// 此处手指所处位置将成为下次手指移动时的上一次位置
this.lastX = endX;
},
// 滑动结束
touchEnd(e, index) {
let distance = 10;
const endTime = e.timeStamp;
const x_end_distance = this.startX - this.lastX;
if (Math.abs(endTime - this.startTime) > 200) {
distance = this.btnWidth / -2;
}
// 判断手指最终位置与手指开始位置的位置差距
if (x_end_distance > distance) {
this.list[index].slide_x = this.btnWidth;
} else if (x_end_distance < distance * -1) {
this.list[index].slide_x = 0;
} else {
this.list[index].slide_x = this.start_slide_x;
}
},
// 点击回复原状
recover(index) {
this.list[index].slide_x = 0;
},
// 收藏/取消
collect (index) {
let data = {
goods_id: this.list[index].goods_id
}
this.$api.goodsCollection(data, res => {
if (res.status) {
this.$common.successToShow(res.msg, () => {
this.$nextTick(() => {
this.list[index].isCollection = !this.list[index].isCollection
})
})
} else {
this.$common.errorToShow(res.msg)
}
})
},
// 删除
remove(index) {
let data = {
goods_ids: this.list[index].goods_id
}
this.$api.delGoodsBrowsing(data, res => {
if (res.status) {
this.$common.successToShow(res.msg, () => {
this.list.splice(index, 1)
})
} else {
this.$common.errorToShow(res.msg)
}
})
}
}
};
</script>
<style scoped>
.collection .goods-img{
width: 150upx;
height: 150upx;
}
.container_of_slide {
width: 100%;
overflow: hidden;
}
.slide_list {
transition: all 100ms;
transition-timing-function: ease-out;
min-width: 200%;
}
.now-message-info {
box-sizing:border-box;
display: flex;
align-items: center;
font-size: 16px;
clear:both;
padding: 20upx 26upx;
margin-bottom: 2upx;
background: #FFFFFF;
}
.now-message-info,
.group-btn {
float: left;
}
.group-btn {
display: flex;
flex-direction: row;
height: 190upx;
min-width: 100upx;
align-items: center;
}
.group-btn .btn-div {
height: 190upx;
color: #fff;
text-align: center;
padding: 0 50upx;
font-size: 34upx;
line-height: 190upx;
}
.group-btn .top {
background-color: #FF7159;
}
.group-btn .removeM {
background-color: #999;
}
.icon-circle{
width:150upx;
height: 150upx;
float: left;
}
.list-right{
float: left;
margin-left: 25upx;
height: 150upx;
}
.list-right-1{
float: right;
color: #A9A9A9;
}
.list-title{
width: 490upx;
line-height:1.5;
overflow:hidden;
color:#333;
display:-webkit-box;
-webkit-box-orient:vertical;
-webkit-line-clamp:2;
overflow:hidden;
font-size: 26upx;
color: #333;
min-height: 80upx;
}
.list-detail{
width: 460upx;
font-size: 24upx;
color: #a9a9a9;
display:-webkit-box;
-webkit-box-orient:vertical;
-webkit-line-clamp:1;
overflow:hidden;
}
.history-none{
text-align: center;
padding: 200upx 0;
}
.history-none-img{
width: 274upx;
height: 274upx;
}
</style>
index
index.vue
<template>
<view class="content">
<!-- 用户头像header -->
<view class='member-top'>
<image class='bg-img' src='/static/image/member-bg.png'></image>
<view class='member-top-c'>
<template v-if="hasLogin">
<image class='user-head-img' mode="aspectFill" :src='userInfo.avatar'></image>
<view class='user-name'>{{ userInfo.nickname }}</view>
<view class="fz12 grade" v-if="userInfo.grade_name">
{{userInfo.grade_name}}
</view>
</template>
<template v-else>
<!-- #ifdef H5 || APP-PLUS -->
<image class='user-head-img' mode="aspectFill" :src='$store.state.config.shop_logo'></image>
<view class="login-btn" @click="toLogin">
登录/注册
</view>
<!-- #endif -->
<!-- #ifdef MP-WEIXIN -->
<view class="user-head-img">
<open-data type="userAvatarUrl"></open-data>
</view>
<view>
<!-- open-type="getUserInfo" @getuserinfo="getUserInfo" -->
<button class="login-btn" hover-class="btn-hover" @click="goLogin()">授权登录</button>
</view>
<!-- #endif -->
<!-- #ifdef MP-ALIPAY -->
<view class="user-head-img"></view>
<view>
<button class="login-btn" open-type="getAuthorize" @click="getALICode" hover-class="btn-hover">授权登录</button>
</view>
<!-- #endif -->
</template>
</view>
</view>
<!-- 用户头像header end -->
<!-- 订单列表信息 -->
<view class='cell-group'>
<view class='cell-item right-img' @click="orderNavigateHandle('../order/orderlist')">
<view class='cell-item-hd'>
<view class='cell-hd-title'>我的订单</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
</view>
<view class='member-grid'>
<view class='member-item' v-for="(item, index) in orderItems" :key="index" @click="orderNavigateHandle('../order/orderlist', index + 1)">
<view class="badge color-f" v-if="item.nums">{{ item.nums }}</view>
<image class='member-item-icon' :src='item.icon'></image>
<text class='member-item-text'>{{ item.name }}</text>
</view>
<view class='member-item' @click="goAfterSaleList">
<view class="badge color-f" v-if="afterSaleNums != 0">{{afterSaleNums}}</view>
<image class='member-item-icon' src='/static/image/me-ic-evaluate.png'></image>
<text class='member-item-text'>退换货</text>
</view>
</view>
<!-- 订单列表end -->
<!-- 其他功能菜单 -->
<view class='cell-group margin-cell-group right-img'>
<view class='cell-item' v-for="(item, index) in utilityMenus" :key="index" v-if="!item.unshowItem">
<view class='cell-item-hd' @click="navigateToHandle(item.router)">
<image class='cell-hd-icon' :src='item.icon'></image>
<view class='cell-hd-title'>{{ item.name }}</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
<!-- #ifdef H5 || APP-PLUS -->
<view class='cell-item'>
<view class='cell-item-hd' @click="showChat()">
<image class='cell-hd-icon' src='/static/image/me-ic-phone.png'></image>
<view class='cell-hd-title'>联系客服</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
<!-- #endif -->
<!-- #ifdef MP-WEIXIN -->
<view class='cell-item'>
<button class="cell-item-hd " hover-class="none" open-type="contact" bindcontact="showChat" :session-from="kefupara">
<image src='/static/image/me-ic-phone.png' class='cell-hd-icon'></image>
<view class='cell-hd-title'>联系客服</view>
</button>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
<!-- #endif -->
<!-- #ifdef MP-ALIPAY -->
<view class='cell-item'>
<contact-button icon="/static/image/kefu2.png" size="170rpx*76rpx" tnt-inst-id="WKPKUZXG" scene="SCE00040186"
class="cell-item-hd " hover-class="none" />
<view class='cell-item-ft'>
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
<!-- #endif -->
</view>
<view class='cell-group margin-cell-group right-img' v-if="isClerk">
<view class='cell-item' v-for="(item, index) in clerk" :key="index">
<view class='cell-item-hd' @click="navigateToHandle(item.router)">
<image class='cell-hd-icon' :src='item.icon'></image>
<view class='cell-hd-title'>{{ item.name }}</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
</view>
<!-- 其他功能菜单end -->
<jihaiCopyright></jihaiCopyright>
</view>
</template>
<script>
import jihaiCopyright from '@/components/jihai-copyright/jihaiCopyright.vue'
import {
checkLogin
} from '@/config/mixins.js'
export default {
components: {
jihaiCopyright
},
mixins: [checkLogin],
data() {
return {
open_id: '',
hasLogin: false,
userInfo: {}, // 用户信息
kefupara: '', //客服传递资料
afterSaleNums: 0,
isClerk: false,
alipayNoLogin: true,
alipayName: '',
alipayAvatar: '',
config:'',//配置信息
orderItems: [{
name: '待付款',
icon: '/static/image/me-ic-obligation.png',
nums: 0
},
{
name: '待发货',
icon: '/static/image/me-ic-sendout.png',
nums: 0
},
{
name: '待收货',
icon: '/static/image/me-ic-receiving.png',
nums: 0
},
{
name: '待评价',
icon: '/static/image/me-ic-evaluate.png',
nums: 0
}
],
utilityMenus: {
distribution: {
name: '分销中心',
icon: '/static/image/distribution.png',
router: '../distribution/user',
unshowItem: false
},
coupon: {
name: '我的优惠券',
icon: '/static/image/ic-me-coupon.png',
router: '../coupon/index',
unshowItem: false
},
balance: {
name: '我的余额',
icon: '/static/image/ic-me-balance.png',
router: '../balance/index',
unshowItem: false
},
integral: {
name: '我的积分',
icon: '/static/image/integral.png',
router: '../integral/index',
unshowItem: false
},
address: {
name: '地址管理',
icon: '/static/image/me-ic-site.png',
router: '../address/list',
unshowItem: false
},
collection: {
name: '我的收藏',
icon: '/static/image/ic-me-collect.png',
router: '../collection/index',
unshowItem: false
},
history: {
name: '我的足迹',
icon: '/static/image/ic-me-track.png',
router: '../history/index',
unshowItem: false
},
invite: {
name: '邀请好友',
icon: '/static/image/ic-me-invite.png',
router: '../invite/index',
unshowItem: true
},
setting: {
name: '系统设置',
icon: '/static/image/me-ic-set.png',
router: '../setting/index',
unshowItem: false
}
},
clerk: [{
name: '提货单列表',
icon: '/static/image/me-ic-phone.png',
router: '../take_delivery/list'
},
{
name: '提货单核销',
icon: '/static/image/me-ic-about.png',
router: '../take_delivery/index'
}
]
}
},
onShow() {
this.initData()
},
methods: {
goLogin(){
uni.navigateTo({
url:'/pages/login/choose/index'
})
},
getUserInfo(e) {
let _this = this
//return false;
if (e.detail.errMsg == 'getUserInfo:fail auth deny') {
_this.$common.errorToShow('未授权')
} else {
var data = {
open_id: _this.open_id,
iv: e.detail.iv,
edata: e.detail.encryptedData,
signature: e.detail.signature
}
//有推荐码的话,带上
var invitecode = _this.$db.get('invitecode')
if (invitecode) {
data.invitecode = invitecode
}
_this.toWxLogin(data)
}
},
getALICode() {
let that = this
uni.login({
scopes: 'auth_user',
success: (res) => {
if (res.authCode) {
uni.getUserInfo({
provider: 'alipay',
success: function(infoRes) {
if (infoRes.errMsg == "getUserInfo:ok") {
let user_info = {
'nickname': infoRes.nickName,
'avatar': infoRes.avatar
}
that.aLiLoginStep1(res.authCode, user_info);
}
},
fail: function(errorRes) {
this.$common.errorToShow('未取得用户昵称头像信息');
}
});
} else {
this.$common.errorToShow('未取得code');
}
},
fail: function(res) {
this.$common.errorToShow('用户授权失败my.login');
}
});
},
getWxCode() {
let that = this
uni.login({
scopes: 'auth_user',
success: function(res) {
if (res.code) {
that.wxLoginStep1(res.code)
} else {
this.$common.errorToShow('未取得code')
}
},
fail: function(res) {
this.$common.errorToShow('用户授权失败wx.login')
}
})
},
wxLoginStep1(code) {
this.$api.login1({
code
}, res => {
if (res.status) {
this.open_id = res.data
} else {
this.$common.errorToShow(res.msg, function() {
uni.navigateBack({
delta: 1
})
})
}
})
},
aLiLoginStep1(code, user_info) {
let data = {
'code': code,
'user_info': user_info
}
this.$api.alilogin1(data, res => {
this.alipayNoLogin = false;
if (res.status) {
this.open_id = res.data.user_wx_id
//判断是否返回了token,如果没有,就说明没有绑定账号,跳转到绑定页面
if (!res.data.hasOwnProperty('token')) {
this.$common.redirectTo('/pages/login/login/index?user_wx_id=' + res.data.user_wx_id);
} else {
this.$db.set('userToken', res.data.token)
this.initData()
}
} else {
this.$common.errorToShow(res.msg)
}
})
},
toWxLogin(data) {
let _this = this
_this.$api.login2(data, function(res) {
if (res.status) {
//判断是否返回了token,如果没有,就说明没有绑定账号,跳转到绑定页面
if (typeof res.data.token == 'undefined') {
uni.redirectTo({
url: '/pages/login/login/index?user_wx_id=' + res.data.user_wx_id
})
} else {
_this.$db.set('userToken', res.data.token)
_this.initData()
}
} else {
_this.$common.errorToShow('登录失败,请重试')
}
})
},
toLogin() {
this.$common.navigateTo('../../login/login/index1')
},
initData() {
// 获取用户信息
var _this = this
//判断是开启分销还是原始推广
this.$api.shopConfig(res => {
this.config = res;
if (res.open_distribution) {
this.utilityMenus.invite.unshowItem = true
} else {
this.utilityMenus.distribution.unshowItem = true
this.utilityMenus.invite.unshowItem = false
}
})
if (this.$db.get('userToken')) {
this.hasLogin = true
this.$api.userInfo({}, res => {
if (res.status) {
_this.userInfo = res.data
// #ifdef MP-WEIXIN
//微信小程序打开客服时,传递用户信息
var kefupara = {}
kefupara.nickName = res.data.nickname
kefupara.tel = res.data.mobile
_this.kefupara = JSON.stringify(kefupara)
// #endif
// 获取订单不同状态的数量
let data = {
ids: '1,2,3,4',
isAfterSale: true
}
_this.$api.getOrderStatusSum(data, res => {
if (res.status) {
_this.orderItems.forEach((item, key) => {
item.nums = res.data[key + 1]
})
_this.afterSaleNums = res.data.isAfterSale ?
res.data.isAfterSale :
0
}
})
//判断是否是店员
this.$api.isStoreUser({}, res => {
this.isClerk = res.flag
})
}
})
} else {
this.hasLogin = false
// #ifdef MP-WEIXIN
this.getWxCode()
// #endif
}
},
navigateToHandle(pageUrl) {
if (!this.hasLogin) {
return this.checkIsLogin()
}
this.$common.navigateTo(pageUrl)
},
orderNavigateHandle(url, tab = 0) {
if (!this.hasLogin) {
return this.checkIsLogin()
}
this.$store.commit('orderTab', tab)
this.$common.navigateTo(url)
},
goAfterSaleList() {
if (!this.hasLogin) {
return this.checkIsLogin()
}
this.$common.navigateTo('../after_sale/list')
},
//在线客服,只有手机号的,请自己替换为手机号
showChat() {
// #ifdef H5
let _this = this
window._AIHECONG('ini', {
entId: this.config.ent_id,
button: false,
appearance: {
panelMobile: {
tone: '#FF7159',
sideMargin: 30,
ratio: 'part',
headHeight: 50
}
}
})
//传递客户信息
window._AIHECONG('customer', {
head: _this.userInfo.avatar,
'名称': _this.userInfo.nickname,
'手机': _this.userInfo.mobile
})
window._AIHECONG('showChat')
// #endif
// 拨打电话
// #ifdef APP-PLUS
if (this.kfmobile) {
uni.makePhoneCall({
phoneNumber: '' + this.kfmobile,
success: () => {
// console.log("成功拨打电话")
}
})
} else {
this.$common.errorToShow('商户未设置客服手机号')
}
// #endif
}
},
computed: {
// 获取店铺联系人手机号
kfmobile() {
return this.$store.state.config.shop_mobile || 0
}
},
watch: {}
}
</script>
<style>
.member-top {
position: relative;
width: 100%;
height: 340upx;
}
.bg-img {
position: absolute;
width: 100%;
height: 100%;
}
.member-top-c {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
}
.user-head-img {
display: block;
width: 160upx;
height: 160upx;
border-radius: 50%;
overflow: hidden;
background-color: rgba(255, 255, 255, 0.7);
margin: 0 auto 16upx;
}
.user-name {
font-size: 30upx;
color: #fff;
margin-bottom: 16upx;
}
.grade {
color: #FFF;
}
.member-grid {
background-color: #fff;
border-top: 2upx solid #eee;
padding: 20upx 0;
}
.margin-cell-group {
margin: 20upx 0;
color: #666666;
}
.badge {
left: 80upx;
top: -6upx;
}
button.cell-item-hd {
background-color: #fff;
padding: 0;
line-height: 1.4;
color: #333;
}
button.cell-item-hd:after {
border: none;
}
.login-btn {
color: #fff;
width: 180upx;
height: 50upx;
line-height: 50upx;
border-radius: 25upx;
background: #ff7159;
font-size: 12px;
}
</style>
integral
index.vue
<template>
<view class="content">
<view class="integral-top">
<view class="integral-top-t">
可用积分
</view>
<view class="integral-top-n">
{{ pointList.length ? pointList[0].balance : 0}}
</view>
<view class="integral-top-d">
{{ nowDate }}
</view>
</view>
<view class="integral-bottom">
<view class='cell-group margin-cell-group'>
<view class='cell-item add-title-item cell-title'>
<view class='cell-item-bd'>
<view class="cell-bd-view black-text">
<text class="cell-bd-text">积分记录</text>
</view>
</view>
</view>
<view
class='cell-item add-title-item'
v-for="item in pointList"
:key="item.id"
>
<view class='cell-item-bd'>
<view class="cell-bd-view black-text">
<text class="cell-bd-text">{{ item.remarks }}</text>
</view>
<view class="cell-bd-view">
<text class="cell-bd-text">{{ item.ctime }}</text>
</view>
</view>
<view class="cell-item-ft">
<text class="cell-ft-p">{{ item.num > 0 ? '+' + item.num : item.num }}</text>
</view>
</view>
<uni-load-more
:status="loadStatus"
:show-icon="true"
></uni-load-more>
</view>
</view>
</view>
</template>
<script>
import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue'
export default {
data () {
return {
page: 1,
limit: 10,
pointList: [], // 积分记录
loadStatus: 'more'
}
},
components: { uniLoadMore },
onLoad () {
this.userPointLog()
},
computed: {
nowDate () {
return this.$common.timeToDate(Math.round(new Date().getTime()/1000))
}
},
methods: {
userPointLog () {
let _this = this
let data = {
page: _this.page,
limit: _this.limit
}
_this.loadStatus = 'loading'
_this.$api.pointLog(data, function (res) {
if (res.status) {
_this.pointList = [..._this.pointList, ...res.data]
// 判断数据是否加载完毕
if (res.count > _this.pointList.length) {
_this.page ++
_this.loadStatus = 'more'
} else {
_this.loadStatus = 'noMore'
}
} else {
// 接口請求出錯
_this.$common.errorToShow(res.msg)
_this.loadStatus = 'more'
}
})
}
},
// 页面滚动到底部触发事件
onReachBottom () {
let _this = this
if (_this.loadStatus === 'more') {
_this.userPointLog()
}
}
}
</script>
<style>
.content{
background-color: #fff;
padding-top: 20upx;
}
.integral-top{
background-color: #F7F7F7;
text-align: center;
width: 698upx;
margin: 0 auto 10upx;
border-radius: 12upx;
padding: 40upx 0;
border: 2upx solid #E9E9E9;
box-shadow: 0 0 10upx #ddd;
}
.integral-top-t{
font-size: 28upx;
color: #666;
margin-bottom: 16upx;
}
.integral-top-n{
font-size: 58upx;
color: #333;
margin-bottom: 16upx;
}
.integral-top-d{
font-size: 22upx;
color: #999;
}
.cell-title .cell-bd-text{
font-size: 34upx !important;
}
.cell-bd-view{
font-size: 22upx;
color: #999;
}
.cell-item .black-text .cell-bd-text{
font-size: 28upx;
color: #333;
}
</style>
invite
index.vue
<template>
<view class="content">
<image class="invite-bg" src="/static/image/invite-bg.png" mode=""></image>
<view class="invite-c">
<view class="invite-w">
<view class='invite-w-t'>我的专属邀请码</view>
<text class='invite-w-num'>{{code}}</text>
<view class='invite-w-detail'>快去分享您的邀请码吧,让更多的好友加入到【{{appTitle}}】,您也可以获得丰厚的奖励!</view>
<view class='invite-w-bot'>
<view bindtap='commission' @click="toMoney">
<image class='invite-w-bot-ic' src='/static/image/ic-earnings.png'></image>
<text class='invite-w-bot-red'>¥{{money}}元</text>
<text class='invite-w-bot-gray'>邀请收益</text>
</view>
<view bindtap='recommendlist' @click="toList">
<image class='invite-w-bot-ic' src='/static/image/ic-number.png'></image>
<text class='invite-w-bot-red'>{{number}}人</text>
<text class='invite-w-bot-gray'>邀请人数</text>
</view>
</view>
</view>
<view class="invite-w" v-if="!is_superior">
<text class='invite-w-t-blue'>谁推荐你的?</text>
<input class='invite-w-input' placeholder='请输入推荐人邀请码' v-model="inviteKey"></input>
<view class='invite-w-btn' @click="setMyInvite">提交</view>
</view>
<view class='invite-btn'>
<!-- #ifdef MP-WEIXIN -->
<button class='share btn' open-type="share">
<image src='/static/image/ic-wechat.png'></image>
</button>
<!-- #endif -->
<!-- #ifdef H5 -->
<button class='share btn' @click="copyUrl()">
<image src='/static/image/ic-link.png'></image>
</button>
<!-- #endif -->
<button class='share btn' @click="createPoster()">
<image src='/static/image/ic-img.png'></image>
</button>
</view>
</view>
</view>
</template>
<script>
import {
apiBaseUrl
} from '@/config/config.js'
export default {
data() {
return {
myShareCode: '', //分享Code
code: '',
money: 0,
number: 0,
is_superior: false,
inviteKey: '',
imageUrl: '/static/image/share_image.png'
}
},
computed: {
appTitle() {
return this.$store.state.config.shop_name;
}
},
onShow() {
this.getInviteData();
this.getMyShareCode();
},
methods: {
//获取数据
getInviteData() {
this.$api.myInvite(res => {
this.code = res.data.code;
this.money = res.data.money;
this.number = res.data.number;
this.is_superior = res.data.is_superior;
});
},
//去佣金明细
toMoney() {
this.$common.navigateTo('../balance/details?status=5');
},
//去邀请列表
toList() {
this.$common.navigateTo('./list');
},
//填写设置要求
setMyInvite() {
let data = {
code: this.inviteKey
}
this.$api.setMyInvite(data, res => {
if (res.status) {
this.$common.successToShow('邀请码填写成功');
this.is_superior = true;
} else {
this.$common.errorToShow(res.msg);
}
});
},
// 生成邀请海报
createPoster() {
let data = {
type: 2
}
let page_path = '/pages/share/jump';
// #ifdef H5
data.source = 1;
data.return_url = apiBaseUrl + 'wap/' + page_path;
// #endif
// #ifdef MP-WEIXIN
data.source = 2;
data.return_url = page_path;
// #endif
// #ifdef MP-ALIPAY
data.source = 3;
data.return_url = page_path;
// #endif
let userToken = this.$db.get('userToken')
if (userToken) {
data.token = userToken
}
this.$api.createPoster(data, res => {
if (res.status) {
this.$common.navigateTo('/pages/share?poster=' + res.data)
} else {
this.$common.errorToShow(res.msg)
}
})
},
//复制URL链接
copyUrl() {
let data = {
type: 2
}
let page_path = '/pages/share/jump';
data.return_url = apiBaseUrl + 'wap' + page_path;
let userToken = this.$db.get('userToken')
if (userToken) {
data.token = userToken
}
let _this = this;
_this.$api.createShareUrl(data, res => {
if(res.status) {
//todo::要复制的内容是 res.data
uni.setClipboardData({
data:res.data,
success:function(data){
_this.$common.successToShow('复制成功');
},
fail:function(err){
_this.$common.errorToShow('复制分享URL失败');
}
})
} else {
_this.$common.errorToShow('复制分享URL失败');
}
});
},
getMyShareCode() {
let userToken = this.$db.get("userToken");
if (userToken && userToken != '') {
// 获取我的分享码
this.$api.shareCode({}, res => {
if (res.status) {
this.myShareCode = res.data ? res.data : '';
}
});
}
}
},
//分享
onShareAppMessage() {
let myInviteCode = this.myShareCode ? this.myShareCode : '';
let ins = this.$common.shareParameterDecode('type=3&invite=' + myInviteCode);
let path = '/pages/share/jump?scene=' + ins;
return {
title: this.$store.state.config.share_title,
// #ifdef MP-ALIPAY
desc: this.$store.state.config.share_desc,
// #endif
imageUrl: this.$store.state.config.share_image,
path: path
}
}
}
</script>
<style>
.invite {
width: 100%;
height: 100%;
background: linear-gradient(to right, #4c21d2, #4864f8);
}
.invite-bg {
position: absolute;
width: 750upx;
height: 683upx;
z-index: 66;
}
.invite-c {
position: relative;
z-index: 67;
width: 750upx;
padding: 0 30upx;
top: 488upx;
background: linear-gradient(to right, #4c21d2, #4864f8);
}
.invite-w {
background-color: #fff;
width: 690upx;
text-align: center;
padding: 40upx 100upx;
box-sizing: border-box;
border-radius: 30upx;
margin-bottom: 70upx;
position: relative;
top: -148upx;
}
.invite-w-t {
width: 70%;
margin: 0 auto;
color: #fff;
border-radius: 50upx;
font-size: 30upx;
box-sizing: border-box;
padding: 10upx;
display: block;
background: linear-gradient(to right, #5f2ef6, #b945dd);
}
.invite-w-num {
color: #5f2ef6;
display: block;
font-size: 36upx;
margin-top: 20upx;
}
.invite-w-detail {
color: #666;
font-size: 24upx;
line-height: 1.5;
margin-top: 20upx;
}
.invite-w-bot {
margin: 20upx 0 50upx;
}
.invite-w-bot>view {
width: 49%;
display: inline-block;
}
.invite-w-bot-ic {
width: 48upx;
height: 48upx;
}
.invite-w-bot-red {
font-size: 24upx;
color: #ca0400;
display: block;
}
.invite-w-bot-gray {
font-size: 24upx;
color: #acacac;
display: block;
}
.invite-w-t-blue {
color: #348dfc;
font-size: 30upx;
margin-bottom: 50upx;
display: block;
}
.invite-w-input {
font-size: 30upx;
border-bottom: 1px solid #dadada;
margin-bottom: 50upx;
color: #999;
}
.invite-w-btn {
background: linear-gradient(to right, #4a6af9, #28c4ff);
color: #fff;
width: 50%;
margin: 0 auto;
border-radius: 50upx;
font-size: 30upx;
padding: 10upx 0;
}
.invite-btn {
position: relative;
top: -150upx;
text-align: center;
width: 690upx;
}
.share {
background-color: none;
position: relative;
width: 98upx;
height: 98upx;
display: inline-block;
border-radius: 50%;
padding: 0;
margin: 0 40rpx 40rpx;
}
.invite-btn image {
width: 98upx;
height: 98upx;
}
</style>
list.vue
<template>
<view class="content">
<view class="collection">
<view class="container_of_slide" v-for="(item, index) in lists" :key="index">
<view class="slide_list">
<view class="now-message-info" hover-class="uni-list-cell-hover">
<view class="icon-circle">
<image class='goods-img' :src="item.avatar" mode="aspectFill"></image>
</view>
<view class="list-right">
<view class="list-title">昵称: {{ item.nickname }}</view>
<view class="list-detail color-6">手机号: {{ item.mobile }}</view>
<view class="list-detail">推荐时间: {{ item.ctime }}</view>
</view>
</view>
<view style="clear:both"></view>
</view>
</view>
<uni-load-more :status="loadStatus"></uni-load-more>
</view>
</view>
</template>
<script>
import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue'
export default {
components: {
uniLoadMore
},
data() {
return {
lists: [],
page: 1, //当前页
limit: 10, //每页显示几条
loadStatus: 'more'
};
},
onLoad () {
this.getShareCode();
this.getDataList();
},
onReachBottom () {
if (this.loadStatus === 'more') {
this.getDataList()
}
},
methods: {
getDataList() {
this.loadStatus = 'loading'
let data = {
page: this.page,
limit: this.limit
}
this.$api.recommendList(data, res => {
if (res.status) {
for (let i = 0; i < res.data.length; i++) {
if (res.data[i].avatar == null) {
res.data[i].avatar = this.$store.state.config.shop_default_image;
}
if (res.data[i].nickname == null) {
res.data[i].nickname = '暂无昵称'
}
}
let lists = this.lists.concat(res.data);
this.lists = lists;
if (res.total > this.page) {
this.page++
this.loadStatus = 'more'
} else {
this.loadStatus = 'noMore'
}
}else{
this.$common.errorToShow(res.msg)
}
});
},
//获取邀请码
getShareCode(){
let userToken = this.$db.get("userToken");
if (userToken && userToken != '') {
// 获取我的分享码
this.$api.shareCode({}, res => {
if (res.status) {
this.myShareCode = res.data;
}
});
}
}
},
};
</script>
<style scoped>
.collection .goods-img{
width: 150upx;
height: 150upx;
}
.container_of_slide {
width: 100%;
overflow: hidden;
}
.slide_list {
transition: all 100ms;
transition-timing-function: ease-out;
min-width: 100%;
}
.now-message-info {
box-sizing:border-box;
display: flex;
align-items: center;
font-size: 16px;
clear:both;
padding: 20upx 26upx;
margin-bottom: 2upx;
background: #FFFFFF;
width: 100%;
}
.now-message-info,
.group-btn {
float: left;
}
.group-btn {
display: flex;
flex-direction: row;
height: 190upx;
min-width: 100upx;
align-items: center;
}
.group-btn .btn-div {
height: 190upx;
color: #fff;
text-align: center;
padding: 0 50upx;
font-size: 34upx;
line-height: 190upx;
}
.group-btn .top {
background-color: #FF7159;
}
.group-btn .removeM {
background-color: #999;
}
.icon-circle{
width:150upx;
height: 150upx;
float: left;
}
.list-right{
float: left;
margin-left: 25upx;
height: 150upx;
}
.list-right-1{
float: right;
color: #A9A9A9;
}
.list-title{
width: 490upx;
line-height:1.5;
overflow:hidden;
color:#333;
font-size: 26upx;
min-height: 60upx;
}
.list-detail{
width: 460upx;
font-size: 24upx;
color: #a9a9a9;
display:-webkit-box;
-webkit-box-orient:vertical;
-webkit-line-clamp:1;
overflow:hidden;
height: 50upx;
}
</style>
order
evaluate.vue
<template>
<view class="content">
<view class="content-top">
<view class='img-list'>
<view class='img-list-item'
v-for="item in info.items"
:key="item.id"
>
<view class="img-list-item-gray">
<image class='img-list-item-l small-img' :src='item.image_url' mode='aspectFill'></image>
<view class='img-list-item-r small-right'
@click="goodsDetail(item.goods_id)"
>
<view class='little-right-t'>
<view class='goods-name list-goods-name'>{{ item.name }}</view>
</view>
</view>
</view>
<view class="evaluate-num">
<view class="evaluate-num-t">商品评分</view>
<view class="evaluate-num-b">
<uni-rate
size="18"
:id="item.id"
:value="score[item.id]"
@change="changeScore"
></uni-rate>
</view>
</view>
<view class="evaluate-content">
<view class="evaluate-c-t">
<textarea v-model="textarea[item.id]" placeholder="宝贝满足你的期待吗? 说说你的使用心得" />
</view>
<view class="evaluate-c-b">
<view class="goods-img-item"
v-if="images[item.id].length"
v-for="(img, key) in images[item.id]"
:key="key"
>
<image class="del" src="/static/image/del.png" mode="" @click="removeImg(item.id, key)"></image>
<image class="" :src="img.url" mode="" @click="clickImg(img.url)"></image>
</view>
<view class="upload-img" v-show="isupload[item.id]">
<image class="icon" src="/static/image/camera.png" mode="" @click="uploadImg(item.id)"></image>
<view class="">上传照片</view>
</view>
</view>
</view>
</view>
</view>
</view>
<view class="button-bottom">
<button class="btn btn-square btn-b" hover-class="btn-hover" @click="toEvaluate" :disabled='submitStatus' :loading='submitStatus'>提交评论</button>
</view>
</view>
</template>
<script>
import uniRate from "@/components/uni-rate/uni-rate.vue"
import { goods } from '@/config/mixins.js'
export default {
mixins: [goods],
components: {uniRate},
data () {
return {
orderId: 0,
info: {}, // 订单详情
images: [],
score: [], // 商品评价
textarea: [], // 商品评价信息
isupload: [], // 启/禁用 图片上传按钮
rate: 5,
submitStatus: false
}
},
onLoad (options) {
this.orderId = options.order_id
this.orderId
? this.orderInfo()
: this.$common.errorToShow('获取失败', () => {
uni.navigateBack({
delta: 1
})
})
},
computed: {
// 获取vuex中状态
maxUploadImg () {
return this.$store.state.config.image_max
}
},
methods: {
// 获取订单详情
orderInfo () {
let data = {
order_id: this.orderId
}
this.$api.orderDetail(data, res => {
if (res.status && res.data.text_status === 4) {
const _info = res.data
let images = []
let textarea = []
let upload = []
let score = []
_info.items.forEach (item => {
images[item.id] = []
textarea[item.id] = ''
upload[item.id] = true
score[item.id] = 5
})
this.info = _info
this.images = images
this.textarea = textarea
this.score = score
this.isupload = upload
} else {
this.$common.errorToShow('订单不存在或状态不可评价!')
}
})
},
// 上传图片
uploadImg (key) {
this.$api.uploadFiles(res => {
if (res.status) {
let img = {
url: res.data.url,
id: res.data.image_id
}
this.images[key].push(img)
this.$common.successToShow(res.msg)
} else {
this.$common.errorToShow(res.msg)
}
})
},
// 删除图片
removeImg (id, key) {
this.images[id].splice(key, 1)
},
// 图片点击放大
clickImg (img) {
// 预览图片
uni.previewImage({
urls: img.split()
});
},
// 改变评分
changeScore (e) {
this.score[e.id] = e.value
},
// 提交评价
toEvaluate () {
this.submitStatus = true;
let items = {}
this.images.forEach((item, key) => {
items[key] = {
images: item,
score: this.score[key],
textarea: this.textarea[key]
}
})
let data = {
order_id: this.orderId,
items: items
}
this.$api.orderEvaluate(data, res => {
if (res.status) {
this.$common.successToShow(res.msg, ress => {
// 更改订单列表页的订单状态
let pages = getCurrentPages(); // 当前页
let beforePage = pages[pages.length - 2]; // 上个页面
if (beforePage !== undefined && beforePage.route === 'pages/member/order/orderlist') {
// #ifdef MP-WEIXIN
beforePage.$vm.isReload = true
// #endif
// #ifdef H5
beforePage.isReload = true
// #endif
// #ifdef MP-ALIPAY
beforePage.rootVM.isReload = true
// #endif
}
this.submitStatus = false;
uni.navigateBack({
delta: 1
})
})
} else {
this.$common.errorToShow(res.msg)
this.submitStatus = false;
}
})
}
},
watch: {
images: {
handler () {
this.images.forEach((item, key) => {
this.isupload[key] = item.length > this.maxUploadImg ? false : true
})
},
deep: true
}
}
}
</script>
<style>
.img-list-item{
padding: 30upx 20upx;
}
.img-list-item-gray{
background-color: #F7F7F7;
overflow: hidden;
padding: 18upx 20upx;
}
.small-right{
width: 520upx;
}
.evaluate-content{
background-color: #fff;
padding: 20upx 0upx;
}
.evaluate-c-t{
width: 100%;
height: 240upx;
}
.evaluate-c-t textarea{
width: 100%;
height: 100%;
font-size: 26upx;
padding: 10upx;
}
.evaluate-c-b{
overflow: hidden;
}
.upload-img{
width: 146upx;
height: 146upx;
margin: 14upx;
text-align: center;
color: #999999;
font-size: 22upx;
border: 2upx solid #E1E1E1;
/* #ifdef MP-ALIPAY */
border-top: 8upx solid #E1E1E1;
/* #endif */
border-radius: 4upx;
display: inline-block;
float: left;
padding: 24upx 0;
}
.goods-img-item{
width: 174upx;
height: 174upx;
padding: 14upx;
float: left;
position: relative;
}
.goods-img-item:nth-child(4n){
margin-right: 0;
}
.goods-img-item image{
width: 100%;
height: 100%;
}
.del{
width: 30upx !important;
height: 30upx !important;
position: absolute;
right: 0;
top: 0;
z-index: 999;
}
.evaluate-num{
padding: 20upx 26upx;
background-color: #fff;
margin-top: 20upx;
}
.evaluate-num-t{
color: #333;
font-size: 28upx;
margin-bottom: 20upx;
}
.button-bottom .btn{
width: 100%;
}
</style>
express_delivery.vue
<template>
<view class="content">
<view class="ed-head color-6"
v-if="add.length"
>
收货地址:{{ add }}
</view>
<view class="ed-body">
<view v-if="isExpress">
<view class="ed-body-item"
v-for="(item, index) in express.data"
:key="index"
>
<view class="edbi-left">
<view class="edbi-date color-6">
{{ item.date }}
</view>
<view class="edbi-time color-9">
{{ item.utime }}
</view>
</view>
<view class="edbi-circle last-circle" v-if="item.end">
<view>收</view>
</view>
<view class="edbi-circle"v-else>
<view></view>
</view>
<view class="edbi-right">
<view class="edbi-title color-3">
{{ item.title }}
</view>
<view class="edbi-content color-9">
{{ item.content }}
</view>
</view>
</view>
</view>
<view class="ed-none" v-else>
暂无物流信息
</view>
</view>
</view>
</template>
<script>
export default {
data () {
return {
add: '', // 收货地址
express: {}, // 快递物流信息
// no:"70433978952894",
// data:[
// {"time":"2019-03-25 11:19:15","context":"郑州市【郑州二七区七部】,已送达 已签收"},
// {"time":"2019-03-25 08:42:02","context":"郑州市【郑州二七区七部】,【左颜璞\/15837175131】正在派件"},
// {"time":"2019-03-25 07:43:35","context":"到郑州市【郑州二七区七部】"},
// {"time":"2019-03-24 16:59:41","context":"郑州市【郑州转运中心】,正发往【郑州二七区七部】"},
// {"time":"2019-03-24 16:25:55","context":"到郑州市【郑州转运中心】"},
// {"time":"2019-03-23 22:43:27","context":"漯河市【漯河转运中心】,正发往【郑州转运中心】"},
// {"time":"2019-03-23 22:41:13","context":"到漯河市【漯河转运中心】"},
// {"time":"2019-03-23 01:35:51","context":"杭州市【杭州转运中心】,正发往【漯河转运中心】"},
// {"time":"2019-03-23 01:34:46","context":"到杭州市【杭州转运中心】"},
// {"time":"2019-03-22 22:27:29","context":"杭州市【杭州萧山区十部】,正发往【杭州转运中心】"},
// {"time":"2019-03-22 20:10:58","context":"到杭州市【杭州萧山区十部集货点】"},
// {"time":"2019-03-22 18:49:57","context":"杭州市【杭州萧山区十部】,【吴永海\/15885770819】已揽收"},
// ],
// state:"3",
// state_name:"已签收"
}
},
onLoad (options) {
let params = options.params
let arr = decodeURIComponent(params).split('&')
let code, no
for (var i = 0; i < arr.length; i++) {
let key = arr[i].split("=")[0]
if (key == 'code') {
code = arr[i].split("=")[1]
}
if (key == 'no') {
no = arr[i].split("=")[1]
}
if (key == 'add') {
this.add = arr[i].split('=')[1]
}
}
if (!code || !no) {
this.$common.errorToShow('缺少物流查询参数', () => {
uni.navigateBack({
delta: 1
})
})
}
this.expressInfo(code, no)
},
computed: {
isExpress () {
return Object.keys(this.express).length ? true : false
}
},
methods: {
expressInfo (code, no) {
let data = {
code: code,
no: no
}
this.$api.logistics(data, res => {
if (res.status) {
let _info = res.data.info
_info.data.forEach((item, key) => {
// 日期时间重新格式化处理
let times = item.time.split(' ')
this.$set(item, 'date', times[0].substring(5, times[0].length))
this.$set(item, 'utime', times[1].substring(0, 5))
// 快递信息格式化处理
let contents = item.context.split(',')
this.$set(item, 'title', contents[0])
this.$set(item, 'content', contents[1] ? contents[1] : '')
// 签收状态logo处理
this.$set(item, 'end', _info.state === 3 && key === 0 ? true : false)
})
this.express = _info
} else {
this.$common.errorToShow(res.msg)
}
})
}
}
}
</script>
<style>
.ed-head{
font-size: 30upx;
padding: 20upx 26upx;
}
.ed-body{
margin: 0 26upx;
background-color: #fff;
box-shadow: 0 0 20upx #ccc;
padding: 26upx;
}
.ed-body-item{
/* display: flex; */
overflow: hidden;
position: relative;
}
.edbi-left{
display: inline-block;
width: 96upx;
float: left;
padding: 4upx 0;
}
.edbi-date{
font-size: 26upx;
}
.edbi-time{
font-size: 24upx;
}
.edbi-circle{
display: inline-block;
width: 18upx;
height: 18upx;
border: 2upx solid #ccc;
border-radius: 50%;
position: absolute;
left: 88upx;
top: 12upx;
background-color: #fff;
z-index: 99;
}
.last-circle{
width: 40upx;
height: 40upx;
font-size: 24upx;
left: 78upx;
text-align: center;
line-height: 40upx;
color: #fff;
background-color: #FF7159;
border: none;
top: 0;
}
.edbi-right{
display: inline-block;
width: 550upx;
float: right;
border-left: 2upx solid #e8e8e8;
padding-left: 30upx;
position: relative;
padding-bottom: 30upx;
}
.edbi-title{
font-size: 30upx;
}
.edbi-content{
font-size: 26upx;
margin-top: 4upx;
}
.ed-none{
text-align: center;
font-size: 26upx;
color: #666;
padding: 100upx;
}
</style>
invitation_group.vue
<template>
<view class="content">
<view class="ig-top">
<view class="ig-top-t">
<view class="">
剩余时间:<uni-countdown :day="lasttime.day" :hour="lasttime.hour" :minute="lasttime.minute" :second="lasttime.second"></uni-countdown>
</view>
</view>
<view class="ig-top-m">
<view class="user-head-img-c" v-for="(item, index) in teamInfo.list" :key="index">
<view class="user-head-img-tip" v-if="item.id == item.team_id">拼主</view>
<image class="user-head-img cell-hd-icon have-none" :src='item.user_avatar' mode=""></image>
</view>
<view class="user-head-img-c uhihn" v-if="teamInfo.team_nums" v-for="n in teamInfo.team_nums" :key="n"><text>?</text></view>
</view>
<view class="ig-top-b">
<view class="igtb-top">
还差<text class="red-price">{{ teamInfo.team_nums }}</text>人,赶快邀请好友来拼单吧
</view>
<view class="igtb-mid">
<button class="btn" @click="goShare()">邀请好友拼单</button>
</view>
<view class="igtb-bot">
分享好友越多,成团越快
</view>
</view>
</view>
<!-- 弹出层 -->
<lvv-popup position="bottom" ref="share">
<!-- #ifdef H5 -->
<shareByH5 :shareType='3' :goodsId="goodsInfo.goods_id" :teamId="teamInfo.team_id" :groupId="teamInfo.rule_id"
:shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief" :shareHref="shareHref"
@close="closeShare()"></shareByH5>
<!-- #endif -->
<!-- #ifdef MP-WEIXIN -->
<shareByWx :shareType='3' :goodsId="goodsInfo.goods_id" :teamId="teamInfo.team_id" :groupId="teamInfo.rule_id"
:shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief" :shareHref="shareHref"
@close="closeShare()"></shareByWx>
<!-- #endif -->
<!-- #ifdef MP-ALIPAY -->
<shareByAli :shareType='3' :goodsId="goodsInfo.goods_id" :teamId="teamInfo.team_id" :groupId="teamInfo.rule_id"
:shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief" :shareHref="shareHref"
@close="closeShare()"></shareByAli>
<!-- #endif -->
<!-- #ifdef APP-PLUS -->
<shareByApp :shareType='3' :goodsId="goodsInfo.goods_id" :teamId="teamInfo.team_id" :groupId="teamInfo.rule_id"
:shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief" :shareHref="shareHref"
@close="closeShare()"></shareByApp>
<!-- #endif -->
</lvv-popup>
<view class="cell-group margin-cell-group">
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>商品名称</view>
</view>
<view class='cell-item-ft'>
<text class="cell-ft-text">{{ goodsInfo.name }}</text>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>拼单时间</view>
</view>
<view class='cell-item-ft'>
<text class="cell-ft-text">{{ orderInfo.ctime }}</text>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>拼单须知</view>
</view>
<view class='cell-item-ft group-notice'>
<text class="cell-ft-text">* 好友拼单 </text>
<text class="cell-ft-text">* 人满发货 </text>
<text class="cell-ft-text">* 人不满退款 </text>
</view>
</view>
</view>
</view>
</template>
<script>
import lvvPopup from '@/components/lvv-popup/lvv-popup.vue';
import uniCountdown from "@/components/uni-countdown/uni-countdown.vue"
import {
get
} from '@/config/db.js';
import {
apiBaseUrl
} from '@/config/config.js';
import share from '@/components/share/share.vue';
// #ifdef H5
import shareByH5 from '@/components/share/shareByh5.vue'
// #endif
// #ifdef MP-WEIXIN
import shareByWx from '@/components/share/shareByWx.vue'
// #endif
// #ifdef MP-ALIPAY
import shareByAli from '@/components/share/shareByAli.vue'
// #endif
// #ifdef APP-PLUS
import shareByApp from '@/components/share/shareByApp.vue'
// #endif
import htmlParser from '@/common/html-parser'
export default {
components: {
lvvPopup,
uniCountdown,
share,
// #ifdef H5
shareByH5,
// #endif
// #ifdef MP-WEIXIN
shareByWx,
// #endif
// #ifdef MP-ALIPAY
shareByAli,
// #endif
// #ifdef APP-PLUS
shareByApp,
// #endif
// spec
},
data() {
return {
myShareCode: '', //分享Code
shareType: 3,
providerList: [], // 分享通道 包含生成海报
swiper: {
indicatorDots: true,
autoplay: true,
interval: 3000,
duration: 800,
}, // 轮播图属性设置
goodsInfo: [],
teamInfo: [],
favLogo: [
'/static/image/ic-me-collect.png',
'/static/image/ic-me-collect2.png'
],
horizontal: 'right', //右下角弹出按钮
vertical: 'bottom',
direction: 'vertical',
pattern: {
color: '#7A7E83',
backgroundColor: '#fff',
selectedColor: '#007AFF',
buttonColor: "#FF7159"
},
query: '', // query参数登录跳转回来使用
indicatorDots: false,
autoplay: false,
interval: 2000,
duration: 500,
lasttime: {
day: 0,
hour: 0,
minute: 0,
second: 0
}, //购买倒计时
userToken: 0,
time: 0,
order_id:'',//订单号
orderInfo:{}
}
},
onLoad(options) {
if(options.order_id){
this.order_id = options.order_id;
}else{
this.$common.errorToShow('参数错误');
}
let teamInfo,orderInfo,goodsInfo
let pages = getCurrentPages()
let pre = pages[pages.length - 2]
if(typeof pre!='undefined'){
// #ifdef H5
teamInfo = pre.teamInfo
orderInfo = pre.orderInfo
// #endif
// #ifdef MP-WEIXIN || APP-PLUS || APP-PLUS-NVUE
teamInfo = pre.$vm.teamInfo
orderInfo = pre.$vm.orderInfo
// #endif
// #ifdef MP-ALIPAY
teamInfo = pre.rootVM.teamInfo;
orderInfo = pre.rootVM.orderInfo
// #endif
}
if(teamInfo && orderInfo){
this.teamInfo = teamInfo;
this.orderInfo = orderInfo;
this.goodsInfo = orderInfo.items[0];
}else{
this.orderDetail();
this.getTeam();
}
let timestamp = Date.parse(new Date())/1000;
this.lasttime = this.$common.timeToDateObj(options.close_time-timestamp);
this.getMyShareCode();
},
computed: {
shareHref() {
let pages = getCurrentPages()
let page = pages[pages.length - 1]
// #ifdef H5 || MP-WEIXIN || APP-PLUS || APP-PLUS-NVUE
return apiBaseUrl + 'wap/' + page.route + '?scene=' + this.query;
// #endif
// #ifdef MP-ALIPAY
return apiBaseUrl + 'wap/' + page.__proto__.route + '?scene=' + this.query;
// #endif
}
},
onReachBottom() {
if (this.current === 2 && this.goodsComments.loadStatus === 'more') {
this.getGoodsComments();
}
},
methods: {
//拼团信息
getTeam(){
this.$api.getOrderPintuanTeamInfo({order_id:this.order_id},res=>{
if (res.status) {
this.teamInfo = {
list:res.data.teams,
current_count:res.data.teams.length,
people_number:res.data.people_number,
team_nums:res.data.team_nums,//剩余
close_time:res.data.close_time,//关闭时间
id:res.data.id,//拼团id
team_id:res.data.team_id,//拼团团队id
rule_id:res.data.rule_id,
};
console.log(this.lasttime);
}else{
this.$common.errorToShow(res.msg)
}
});
},
//获取订单详情
orderDetail () {
let _this = this
let data = {
order_id: _this.order_id
}
_this.$api.orderDetail(data, function(res) {
if (res.status) {
let data = res.data
// 支付时间转换
if (data.ctime !== null) {
data.ctime = _this.$common.timeToDate(data.ctime)
}
_this.orderInfo = data
_this.goodsInfo = data.items[0];
} else {
_this.$common.errorToShow(res.msg)
}
})
},
// 关闭弹出层
close() {
this.$emit('close')
},
// 点击操作
clickHandler(e) {
if (e.cate === 'poster') {
this.createPoster()
} else {
// 去分享
this.share(e)
}
},
// 显示modal弹出框
toshow(type, team_id = 0) {
if (type == 1) {
this.lvvpopref_type = 1;
}
if (team_id !== 0) {
this.team_id = team_id;
}
this.$refs.lvvpopref.show();
},
// 关闭modal弹出框
toclose() {
this.$refs.lvvpopref.close();
},
// 跳转到h5分享页面
goShare() {
this.$refs.share.show();
},
closeShare() {
this.$refs.share.close();
},
getMyShareCode() {
let userToken = this.$db.get("userToken");
if (userToken && userToken != '') {
// 获取我的分享码
this.$api.shareCode({}, res => {
if (res.status) {
this.myShareCode = res.data ? res.data : '';
}
});
}
}
},
//分享
onShareAppMessage() {
let myInviteCode = this.myShareCode ? this.myShareCode : '';
let teamId = this.teamInfo.list[0].team_id;
let ins = this.$common.shareParameterDecode('type=5&invite=' + myInviteCode+'&id='+ this.goodsInfo.goods_id +'&team_id=' + teamId );
let path = '/pages/share/jump?scene=' + ins;
console.log(path);
return {
title: this.goodsInfo.name,
// #ifdef MP-ALIPAY
desc: this.goodsInfo.brief,
// #endif
imageUrl: this.goodsInfo.image_url,
path: path
}
}
}
</script>
<style>
.ig-top {
text-align: center;
background-color: #fff;
padding: 20upx 26upx;
}
.ig-top-t,
.ig-top-m {
margin-bottom: 20upx;
}
.ig-top-t>view {
display: inline-block;
padding: 0 10upx;
color: #999;
}
.user-head-img-c {
position: relative;
width: 80upx;
height: 80upx;
border-radius: 50%;
margin-right: 20upx;
box-sizing: border-box;
display: inline-block;
/* float: left; */
border: 1px solid #f3f3f3;
}
.user-head-img-tip {
position: absolute;
top: -6upx;
left: -10upx;
display: inline-block;
background-color: #FF7159;
color: #fff;
font-size: 22upx;
z-index: 98;
padding: 0 10upx;
border-radius: 10upx;
transform: scale(.8);
}
.user-head-img-c .user-head-img {
width: 100%;
height: 100%;
border-radius: 50%;
}
.user-head-img-c:first-child {
border: 1px solid #FF7159;
}
.uhihn {
width: 80upx;
height: 80upx;
border-radius: 50%;
display: inline-block;
border: 2upx dashed #e1e1e1;
text-align: center;
color: #d1d1d1;
font-size: 40upx;
box-sizing: border-box;
position: relative;
}
.uhihn>text {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.igtb-top {
font-size: 32upx;
color: #333;
margin-bottom: 16upx;
}
.igtb-mid {
margin-bottom: 16upx;
}
.igtb-mid .btn {
width: 100%;
background-color: #FF7159;
color: #fff;
}
.igtb-bot {
font-size: 24upx;
color: #666;
}
.cell-ft-text {
max-width: 520upx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.group-notice .cell-ft-text {
color: #999;
margin-left: 20upx;
font-size: 26upx;
}
</style>
orderdetail.vue
<template>
<view class="content">
<view class="content-top">
<view class='cell-group margin-cell-group'>
<view class='cell-item add-title-item'>
<view class='cell-item-bd'>
<view class="cell-bd-view black-text" v-if="orderInfo.order_type != 2">
<text class="cell-bd-text">{{ orderInfo.status_name }}</text>
</view>
<view class="cell-bd-view">
<text class="cell-bd-text">订单号:{{ orderInfo.order_id }}</text>
<button class='btn btn-g btn-small' hover-class="btn-hover" @click="copyData(orderInfo.order_id)">复制</button>
</view>
<view class="cell-bd-view">
<text class="cell-bd-text">下单时间:{{ orderInfo.ctime }}</text>
</view>
</view>
</view>
</view>
<view class='cell-group margin-cell-group'>
<view class='cell-item add-title-item' v-if="isDelivery" @click="logistics">
<view class='cell-item-bd'>
<view class="cell-bd-view black-text">
<text class="cell-bd-text">{{ orderInfo.express_delivery.context }}</text>
</view>
<view class="cell-bd-view">
<text class="cell-bd-text">{{ orderInfo.express_delivery.time }}</text>
</view>
</view>
<view class="cell-item-ft">
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
<view class='cell-item add-title-item' v-if="!orderInfo.store">
<view class='cell-item-bd'>
<view class="cell-bd-view black-text">
<text class="cell-bd-text">收件人:{{ orderInfo.ship_name }}</text>
</view>
<view class="cell-bd-view">
<text class="cell-bd-text">{{ orderInfo.ship_area_name + orderInfo.ship_address }}</text>
</view>
</view>
</view>
</view>
<view class='cell-group margin-cell-group' v-if="orderInfo.store">
<view class='cell-item add-title-item'>
<view class="cell-item-hd">
<image class='cell-hd-icon' src='/static/image/homepage.png'></image>
</view>
<view class='cell-item-bd'>
<view class="cell-bd-view black-text">
<text class="cell-bd-text">{{orderInfo.store.store_name}}</text>
</view>
<view class="cell-bd-view">
<text class="cell-bd-text">门店电话:{{orderInfo.store.mobile}}</text>
</view>
<view class="cell-bd-view">
<text class="cell-bd-text">门店地址:{{orderInfo.store.all_address}}</text>
</view>
<view class="cell-bd-view">
<text class="cell-bd-text">提货人信息:{{orderInfo.ship_name}}</text><text class="cell-bd-text" style="margin-left: 10rpx;">{{orderInfo.ship_mobile}}</text>
</view>
<view class="cell-bd-view" v-if="lading.status">
<text class="cell-bd-text">提货码:<text class="red-price">{{lading.code}}</text></text>
</view>
</view>
</view>
</view>
<!-- 团购分享拼单 -->
<view class="cell-group margin-cell-group" v-if="(orderInfo.text_status == 1 || orderInfo.text_status == 2 ) && orderInfo.order_type==2">
<view class='cell-item right-img'>
<view class='cell-item-hd'>
<view v-if="teamInfo.status==1" class='cell-hd-title'>待拼团,还差{{ teamInfo.team_nums }}人</view>
<view v-else-if="teamInfo.status==2" class='cell-hd-title'>拼团成功,待发货</view>
<view v-else-if="teamInfo.status==3" class='cell-hd-title'>拼团失败</view>
</view>
</view>
<view class="group-swiper">
<view class='cell-item' v-if="teamInfo.current_count">
<view class='cell-item-hd'>
<view class="user-head-img-c" v-for="(item, index) in teamInfo.list" :key="index">
<view class="user-head-img-tip" v-if="item.id == item.team_id">拼主</view>
<image class="user-head-img cell-hd-icon have-none" :src='item.user_avatar' mode=""></image>
</view>
<view v-if="teamInfo.team_nums > 3">
<view class="uhihn" v-for="n in 3" :key="n">?</view>
<view class="uhihn">···</view>
</view>
<view v-else>
<view class="uhihn" v-for="n in teamInfo.team_nums" :key="n">?</view>
</view>
</view>
<view class="cell-item-ft" v-if="teamInfo.status==1">
<button class="btn" @click="goInvition()">邀请拼单</button>
</view>
</view>
</view>
</view>
<view class='img-list'>
<view class='img-list-item' v-for="item in orderInfo.items" :key="item.id">
<image class='img-list-item-l little-img have-none' :src='item.image_url' mode='aspectFill'></image>
<view class='img-list-item-r little-right'>
<view class='little-right-t'>
<view class='goods-name list-goods-name' @click="goodsDetail(item.goods_id)" v-if="orderInfo.order_type == 1">{{ item.name }}</view>
<view class='goods-name list-goods-name' @click="pintuanDetail(item.goods_id)" v-else-if="orderInfo.order_type == 2">{{ item.name }}</view>
<view class='goods-price'>¥{{ item.price }}</view>
</view>
<view class="romotion-tip">
<view class="romotion-tip-item" v-for="(promotion, key) in formatPormotions(item.promotion_list)" :key="key">
{{ promotion }}
</view>
</view>
<view class='goods-item-c'>
<view class='goods-buy'>
<view class='goods-salesvolume' v-if="item.addon !== null">{{ item.addon }}</view>
<view class='goods-num'>× {{ item.nums }}</view>
</view>
</view>
</view>
</view>
</view>
<view class='cell-group margin-cell-group' v-if="orderInfo.tax_type != 1">
<view class='cell-item add-title-item'>
<view class='cell-item-bd'>
<view class="cell-bd-view black-text">
<text class="cell-bd-text">发票信息</text>
</view>
<view class="cell-bd-view" v-if="orderInfo.tax_type != 1">
<text class="cell-bd-text">发票抬头:{{orderInfo.tax_title}}</text>
</view>
<view class="cell-bd-view" v-if="orderInfo.tax_type == 3">
<text class="cell-bd-text">发票税号:{{orderInfo.tax_code}}</text>
</view>
</view>
</view>
</view>
<view class='cell-group margin-cell-group order-offer' v-if="orderInfo.promotion_list && orderInfo.promotion_list.length > 0">
<view class='cell-item add-title-item'>
<view class='cell-item-hd'>
<view class="cell-bd-view promotion-title">
<text class="cell-bd-text promotion-title-text">订单优惠</text>
</view>
</view>
<view class='cell-item-bd'>
<view v-for="(item, key) in orderInfo.promotion_list" :key="key" v-show="item.type == 2" class="order-promotion">{{item.name}}</view>
</view>
</view>
</view>
<view class='cell-group margin-cell-group order-price'>
<view class='cell-item add-title-item'>
<view class='cell-item-bd'>
<view class="cell-bd-view">
<text class="cell-bd-text">商品总价</text>
</view>
</view>
<view class='cell-item-ft'>
<text class="cell-ft-p">¥{{ orderInfo.goods_amount }}</text>
</view>
</view>
<view class='cell-item add-title-item'>
<view class='cell-item-bd'>
<view class="cell-bd-view">
<text class="cell-bd-text">运费</text>
</view>
</view>
<view class='cell-item-ft'>
<text class="cell-ft-p">¥{{ orderInfo.cost_freight }}</text>
</view>
</view>
<view class='cell-item add-title-item' v-if="orderInfo.goods_pmt > 0">
<view class='cell-item-bd'>
<view class="cell-bd-view">
<text class="cell-bd-text">商品优惠</text>
</view>
</view>
<view class='cell-item-ft'>
<text class="cell-ft-p">-¥{{ orderInfo.goods_pmt }}</text>
</view>
</view>
<view class='cell-item add-title-item' v-if="orderInfo.point_money > 0">
<view class='cell-item-bd'>
<view class="cell-bd-view">
<text class="cell-bd-text">积分优惠</text>
</view>
</view>
<view class='cell-item-ft'>
<text class="cell-ft-p">-¥{{ orderInfo.point_money }}</text>
</view>
</view>
<view class='cell-item add-title-item' v-if="orderInfo.order_pmt > 0">
<view class='cell-item-bd'>
<view class="cell-bd-view">
<text class="cell-bd-text">订单优惠</text>
</view>
</view>
<view class='cell-item-ft'>
<text class="cell-ft-p">-¥{{ orderInfo.order_pmt }}</text>
</view>
</view>
<view class='cell-item add-title-item' v-if="orderInfo.coupon_pmt > 0">
<view class='cell-item-bd'>
<view class="cell-bd-view">
<text class="cell-bd-text">其他优惠</text>
</view>
</view>
<view class='cell-item-ft'>
<text class="cell-ft-p">-¥{{ orderInfo.coupon_pmt }}</text>
</view>
</view>
<view class='cell-item add-title-item'>
<view class='cell-item-bd'>
<view class="cell-bd-view">
<text class="cell-bd-text">订单总价</text>
</view>
</view>
<view class='cell-item-ft'>
<text class="cell-ft-p red-price">¥{{ orderInfo.order_amount }}</text>
</view>
</view>
<view class='cell-item add-title-item' v-if="orderInfo.pay_status > 1">
<view class='cell-item-bd'>
<view class="cell-bd-view">
<text class="cell-bd-text">支付方式</text>
</view>
</view>
<view class='cell-item-ft'>
<text class="cell-ft-p">{{ orderInfo.payment_name }}</text>
</view>
</view>
<view class='cell-item add-title-item' v-if="orderInfo.pay_status > 1">
<view class='cell-item-bd'>
<view class="cell-bd-view">
<text class="cell-bd-text">支付时间</text>
</view>
</view>
<view class='cell-item-ft'>
<text class="cell-ft-p">{{ orderInfo.payment_time }}</text>
</view>
</view>
</view>
</view>
<view class="button-bottom" v-if="orderInfo.text_status === 1">
<button class='btn btn-circle btn-g' hover-class="btn-hover" @click="cancelOrder(orderInfo.order_id)">取消订单</button>
<button class='btn btn-circle btn-w' hover-class="btn-hover" @click="toPay(orderInfo.order_id)">立即支付</button>
</view>
<view class="button-bottom" v-if="orderInfo.text_status === 2">
<button class='btn btn-circle btn-w' hover-class="btn-hover" @click="customerService(orderInfo.order_id)" v-if="orderInfo.bill_aftersales_id == false">申请售后</button>
<button class='btn btn-circle btn-w' hover-class="btn-hover" @click="showCustomerService(orderInfo.bill_aftersales_id)"
v-else-if="orderInfo.bill_aftersales_id && orderInfo.bill_aftersales_id != false">查看售后</button>
</view>
<view class="button-bottom" v-if="orderInfo.text_status === 3">
<button class='btn btn-circle btn-g' hover-class="btn-hover" @click="customerService(orderInfo.order_id)" v-if="orderInfo.bill_aftersales_id == false">申请售后</button>
<button class='btn btn-circle btn-g' hover-class="btn-hover" @click="showCustomerService(orderInfo.bill_aftersales_id)"
v-else-if="orderInfo.bill_aftersales_id && orderInfo.bill_aftersales_id != false">查看售后</button>
<button class='btn btn-circle btn-g' hover-class="btn-hover" @click="logistics">查看物流</button>
<button class='btn btn-circle btn-w' hover-class="btn-hover" @click="tackDeliery(orderInfo.order_id)">确认收货</button>
</view>
<view class="button-bottom" v-if="orderInfo.text_status === 4">
<button class='btn btn-circle btn-g' hover-class="btn-hover" @click="customerService(orderInfo.order_id)" v-if="orderInfo.bill_aftersales_id == false">申请售后</button>
<button class='btn btn-circle btn-g' hover-class="btn-hover" @click="showCustomerService(orderInfo.bill_aftersales_id)"
v-else-if="orderInfo.bill_aftersales_id && orderInfo.bill_aftersales_id != false">查看售后</button>
<button class='btn btn-circle btn-w' hover-class="btn-hover" @click="toEvaluate(orderInfo.order_id)">立即评价</button>
</view>
<view class="button-bottom" v-if="orderInfo.text_status === 5">
<button class='btn btn-circle btn-w' hover-class="btn-hover" @click="customerService(orderInfo.order_id)" v-if="orderInfo.bill_aftersales_id == false">申请售后</button>
<button class='btn btn-circle btn-w' hover-class="btn-hover" @click="showCustomerService(orderInfo.bill_aftersales_id)"
v-else-if="orderInfo.bill_aftersales_id && orderInfo.bill_aftersales_id != false">查看售后</button>
</view>
</view>
</template>
<script>
import {
orders,
goods,
tools
} from '@/config/mixins.js'
export default {
mixins: [orders, goods,tools],
data() {
return {
orderId: 0,
orderInfo: {}, // 订单详情
teamInfo: [], //拼团团信息
lading: {
status: false,
code: ''
}, //提货信息
}
},
onLoad(options) {
this.orderId = options.order_id
if (this.orderId) {
//this.orderDetail()
} else {
this.$common.errorToShow('', () => {
uni.navigateBack({
delta: 1,
})
})
}
},
onShow() {
this.orderDetail();
},
computed: {
// 判断是否发货
isDelivery() {
if (this.orderInfo.text_status > 2 &&
this.orderInfo.express_delivery != null &&
this.orderInfo.hasOwnProperty('express_delivery') &&
Object.keys(this.orderInfo.express_delivery).length
) {
return true
} else {
return false
}
}
},
methods: {
// 获取订单详情
orderDetail() {
let _this = this
let data = {
order_id: _this.orderId
}
_this.$api.orderDetail(data, function(res) {
if (res.status) {
let data = res.data
// 订单状态文字转化
switch (data.text_status) {
case 1:
_this.$set(data, 'status_name', '待付款')
break
case 2:
_this.$set(data, 'status_name', '待发货')
break
case 3:
_this.$set(data, 'status_name', '待收货')
break
case 4:
_this.$set(data, 'status_name', '待评价')
break
case 6:
_this.$set(data, 'status_name', '交易完成')
break
case 7:
_this.$set(data, 'status_name', '交易取消')
break
case 8:
_this.$set(data, 'status_name', '待分享')
break
default:
_this.$set(data, 'status_name', '交易成功')
break
}
// 订单时间转换
data.ctime = _this.$common.timeToDate(data.ctime)
// 支付时间转换
if (data.payment_time !== null) {
data.payment_time = _this.$common.timeToDate(data.payment_time)
}
_this.orderInfo = data
if (data.order_type == 2 && (data.text_status == 2 || data.text_status == 1)) {
_this.getTeam(data.order_id);
}
if(data.ladingItem[0]){
_this.lading = {
status: true,
code: data.ladingItem[0].id
}
}
} else {
_this.$common.errorToShow(res.msg)
}
})
},
// 取消订单
cancelOrder(orderId) {
this.$common.modelShow('提示', '确认要取消订单吗?', () => {
let data = {
order_ids: orderId
}
this.$api.cancelOrder(data, res => {
if (res.status) {
this.$common.successToShow(res.msg, () => {
this.orderDetail()
})
} else {
this.$common.errorToShow(res.msg)
}
})
})
},
// 确认收货
tackDeliery(orderId) {
this.$common.modelShow('提示', '确认收货操作吗?', () => {
let data = {
order_id: orderId
}
this.$api.confirmOrder(data, res => {
if (res.status) {
this.$common.successToShow('确认收货成功', () => {
// 更改订单列表页的订单状态
let pages = getCurrentPages(); // 当前页
let beforePage = pages[pages.length - 2]; // 上个页面
if (beforePage !== undefined && beforePage.route === 'pages/member/order/orderlist') {
// #ifdef MP-WEIXIN
beforePage.$vm.isReload = true
// #endif
// #ifdef H5
beforePage.isReload = true
// #endif
// #ifdef MP-ALIPAY
beforePage.rootVM.isReload = true
// #endif
}
this.orderDetail()
})
} else {
this.$common.errorToShow(res.msg)
}
})
})
},
formatPormotions(promotion) {
let obj = {}
obj = JSON.parse(promotion)
return obj
},
//申请售后
customerService(id) {
this.$common.navigateTo('../after_sale/index?order_id=' + id);
},
//快递信息
logistics() {
let address1 = this.orderInfo.ship_area_name ? this.orderInfo.ship_area_name : ''
let address2 = this.orderInfo.ship_address ? this.orderInfo.ship_address : ''
let address = address1 + address2
this.showExpress(this.orderInfo.delivery[0].logi_code, this.orderInfo.delivery[0].logi_no, address)
},
//查看售后
showCustomerService(id) {
this.$common.navigateTo('../after_sale/detail?aftersales_id=' + id);
},
goInvition() {
uni.navigateTo({
url: './invitation_group?order_id=' + this.orderInfo.order_id + '&close_time=' + this.teamInfo.close_time
})
},
//拼团信息
getTeam(id) {
this.$api.getOrderPintuanTeamInfo({
order_id: id
}, res => {
if (res.status) {
this.teamInfo = {
list: res.data.teams,
current_count: res.data.teams.length,
people_number: res.data.people_number,
team_nums: res.data.team_nums, //剩余
close_time: res.data.close_time, //关闭时间
id: res.data.id, //拼团id
team_id: res.data.team_id, //拼团团队id
rule_id: res.data.rule_id,
status: res.data.status
};
} else {
this.$common.errorToShow(res.msg)
}
});
}
}
}
</script>
<style>
.cell-group {
margin-bottom: 20upx;
}
.cell-bd-view {
margin-bottom: 8upx;
}
.cell-bd-view .cell-bd-text {
font-size: 22upx;
color: #999;
}
.black-text .cell-bd-text {
font-size: 28upx;
color: #333;
}
.button-bottom {
padding: 15upx 26upx;
text-align: right;
display: block;
}
.button-bottom .btn {
margin-left: 20upx;
}
.order-price {
padding: 10upx 0 20upx;
}
.order-price .cell-item {
border-bottom: none;
padding-bottom: 0;
padding-top: 0;
min-height: 40upx;
}
.order-price .cell-bd-view {
margin-bottom: 0;
}
.order-offer .cell-item-hd {
vertical-align: top;
padding-top: 8upx;
}
.order-offer .cell-item-bd {
padding: 0;
}
.order-promotion {
font-size: 24upx;
color: #fff;
background-color: #ff7159;
margin: 0 0 4upx 6upx;
padding: 2upx 10upx;
display: inline-block;
float: right;
}
.tax_name {}
.tax_code {}
.user-head-img-c {
position: relative;
width: 80upx;
height: 80upx;
border-radius: 50%;
margin-right: 20upx;
box-sizing: border-box;
display: inline-block;
float: left;
border: 1px solid #f3f3f3;
}
.user-head-img-tip {
position: absolute;
top: -6upx;
left: -10upx;
display: inline-block;
background-color: #FF7159;
color: #fff;
font-size: 22upx;
z-index: 99;
padding: 0 10upx;
border-radius: 10upx;
transform: scale(.8);
}
.group-swiper .cell-item .user-head-img {
width: 100%;
height: 100%;
border-radius: 50%;
}
.group-swiper .cell-item .user-head-img-c:first-child {
border: 1px solid #FF7159;
}
.uhihn {
width: 80upx;
height: 80upx;
border-radius: 50%;
margin-right: 20upx;
display: inline-block;
border: 2upx dashed #e1e1e1;
text-align: center;
line-height: 80upx;
color: #d1d1d1;
font-size: 40upx;
box-sizing: border-box;
}
.group-swiper .cell-item .cell-item-ft .btn {
font-size: 26upx;
color: #fff;
background-color: #FF7159;
/* padding: 0; */
text-align: center;
}
.add-title-item .cell-item-hd {
min-width: 20px;
color: #666;
font-size: 14px;
}
</style>
orderlist.vue
<template>
<view class="content">
<uni-segmented-control
:current="tab"
:values="items"
@clickItem="onClickItem"
style-type="text"
active-color="#333"
></uni-segmented-control>
<view class="order-list">
<view class="goods-detail"
v-if="list.length">
<view class="order-item"
v-for="(item, index) in list"
:key="index"
>
<view class='cell-group'>
<view class='cell-item'
@click="orderDetail(item.order_id)"
>
<view class='cell-item-hd'>
<view class='cell-hd-title'>订单编号:{{ item.order_id }}</view>
</view>
<view class='cell-item-ft'>
<text class='cell-ft-text'>{{ item.order_status_name }}</text>
</view>
</view>
</view>
<view class='img-list'>
<view class='img-list-item'
v-for="(goods, key) in item.items"
:key="key"
>
<image class='img-list-item-l little-img have-none' :src='goods.image_url' mode='aspectFill'></image>
<view class='img-list-item-r little-right'>
<view class='little-right-t'>
<view class='goods-name list-goods-name'
@click="orderDetail(item.order_id)"
>{{ goods.name }}</view>
<view class='goods-price'>¥{{ goods.price }}</view>
</view>
<view class="romotion-tip">
<view class="romotion-tip-item"
v-for="(promotion, k) in formatPromotions(goods.promotion_list)"
:key="k"
>
{{ promotion }}
</view>
</view>
<view class='goods-item-c'>
<view class='goods-buy'>
<view class='goods-salesvolume'
v-if="goods.addon !== null"
>{{ goods.addon }}</view>
<view class='goods-num'>× {{ goods.nums }}</view>
</view>
</view>
</view>
</view>
</view>
<view class='cell-group'>
<view class='cell-item'>
<view class='cell-item-ft goods-num'>
<text class='cell-ft-text'>合计<text class="red-price">¥ {{ item.order_amount }}</text></text>
<text class='cell-ft-text'>共 {{ item.items.length }} 件</text>
</view>
</view>
</view>
<view class='order-list-button'>
<button class='btn btn-circle btn-g' hover-class="btn-hover" @click="orderDetail(item.order_id)">查看详情</button>
<button class='btn btn-circle btn-w'
hover-class="btn-hover"
v-if="item.status === 1 && item.pay_status === 1"
@click="toPay(item.order_id)"
>立即支付</button>
<button class='btn btn-circle btn-w'
hover-class="btn-hover"
v-if="item.status === 1 && item.pay_status === 2 && item.ship_status === 3 && item.confirm === 1"
@click="tackDelivery(index)"
>确认收货</button>
<button class='btn btn-circle btn-w'
hover-class="btn-hover"
v-if="item.status === 1 && item.pay_status === 2 && item.ship_status === 3 && item.confirm === 2 && item.is_comment === 1"
@click="toEvaluate(item.order_id)"
>立即评价</button>
</view>
</view>
<uni-load-more
:status="loadStatus"
></uni-load-more>
</view>
<view class="order-none" v-else>
<image class="order-none-img" src="/static/image/order.png" mode=""></image>
</view>
<!-- <view class="goods-detail" v-show="current === 1">
<view class="order-none">
<image class="order-none-img" src="/static/image/order.png" mode=""></image>
</view>
</view>
<view class="goods-detail" v-show="current === 2">
3
</view>
<view class="goods-detail" v-show="current === 3">
4
</view>
<view class="goods-detail" v-show="current === 4">
5
</view> -->
</view>
</view>
</template>
<script>
import uniSegmentedControl from "@/components/uni-segmented-control/uni-segmented-control.vue"
import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue'
import { orders, goods } from '@/config/mixins.js'
export default {
mixins: [orders, goods],
components: {
uniSegmentedControl, uniLoadMore
},
data() {
return {
items: [
'全部',
'待付款',
'待发货',
'待收货',
'待评价',
],
list: [],
page: 1,
limit: 5, // 每页订单显示数量
loadStatus: 'more',
status: [0, 1, 2, 3, 4] ,// 订单状态 0全部 1待付款 2待发货 3待收货 4待评价
isReload: false, // 页面是否刷新?重载
}
},
onLoad () {
this.initData()
},
onShow () {
if (this.isReload) {
this.initData()
}
},
computed: {
// 获取订单列表tab
tab () {
return this.$store.state.orderTab
}
},
methods: {
// 初始化数据并获取订单列表
initData (page = 1) {
this.page = page
this.list = []
this.orderList()
},
// 订单状态切换
onClickItem(index) {
if (this.tab !== index) {
this.$store.commit('orderTab', index)
this.initData()
}
},
// 获取订单列表
orderList () {
let data = {
page: this.page,
limit: this.limit,
status: this.status[this.tab]
}
this.loadStatus = 'loading'
this.$api.orderList(data, res => {
if (res.status) {
let _list = res.data.list
if (res.data.status == this.status[this.tab]) {
this.list = [...this.list, ...this.formatOrderStatus(_list)]
// 判断所有数据是否请求完毕
if (res.data.count > this.list.length) {
this.page ++
this.loadStatus = 'more'
} else {
this.loadStatus = 'noMore'
}
}
} else {
this.$common.errorToShow(res.msg)
}
})
if (this.isReload) {
this.isReload = false
}
},
// 确认收货
tackDelivery (index) {
this.$common.modelShow('提示', '确认执行收货操作吗?', () => {
let data = {
order_id: this.list[index].order_id
}
this.$api.confirmOrder(data, res => {
if (res.status) {
this.$common.successToShow('确认收货成功', () => {
if (this.tab !== 0) {
this.list.splice(index, 1)
} else {
this.initData()
}
})
} else {
this.$common.errorToShow(res.msg)
}
})
})
},
// 订单状态统一在这处理
formatOrderStatus (orderList) {
orderList.forEach (item => {
switch (item.status) {
case 1:
if (item.pay_status === 1) {
this.$set(item, 'order_status_name', '待付款')
}
if (item.pay_status === 2 && item.ship_status === 1){
this.$set(item, 'order_status_name', '待发货')
}
if (item.pay_status === 2 && item.ship_status === 3 && item.confirm === 1) {
this.$set(item, 'order_status_name', '待收货')
}
if (item.pay_status === 2 && item.ship_status === 3 && item.confirm === 2 && item.is_comment === 1) {
this.$set(item, 'order_status_name', '待评价')
}
if (item.pay_status === 2 && item.ship_status === 3 && item.confirm === 2 && item.is_comment === 2) {
this.$set(item, 'order_status_name', '已评价')
}
if (item.pay_status === 4) {
this.$set(item, 'order_status_name', '售后单')
}
break
case 2:
this.$set(item, 'order_status_name', '已完成')
break
case 3:
this.$set(item, 'order_status_name', '已取消')
break
}
})
return orderList
},
formatPromotions (promotions) {
let obj = {}
obj = JSON.parse(promotions)
return obj
}
},
// 页面下拉到底部触发
onReachBottom () {
if (this.loadStatus == 'more') {
this.orderList()
}
}
}
</script>
<style>
.segmented-control {
/* #ifdef H5 */
top: 44px;
/* #endif */
/* #ifndef H5 */
top: 0;
/* #endif */
width: 100%;
background-color: #fff;
position: fixed;
z-index: 999;
}
.segmented-control-item{
line-height: 70upx;
}
.order-list{
margin-top: 64upx;
}
.order-item{
margin-bottom: 20upx;
}
.img-list{
margin-top: 2upx;
}
.cell-group,.img-list-item {
background-color: #fff;
}
.cell-hd-title{
font-size: 22upx;
color: #666;
}
.cell-ft-text{
top: 0;
font-size: 22upx;
color: #333;
}
.order-list-button{
width: 100%;
background-color: #fff;
text-align: right;
padding: 10upx 26upx;
/* border-top: 2upx solid #f8f8f8; */
}
.order-list-button .btn{
height: 50upx;
line-height: 50upx;
}
.order-list-button .btn-w{
margin-left: 20upx;
}
.goods-num .cell-ft-text{
color: #999;
line-height: 32upx;
}
.goods-num .cell-ft-text:first-child{
margin-left: 10upx;
}
.order-none{
text-align: center;
padding: 200upx 0;
}
.order-none-img{
width: 274upx;
height: 274upx;
}
.goods-name{
min-height: 74upx;
}
</style>
setting
index.vue
<template>
<view class="content">
<view class="content-top">
<view class='cell-group right-img'>
<view class='cell-item'>
<view class='cell-item-hd' @click="navigateToHandle('./user_info/index')">
<!-- <image class='cell-hd-icon' src=''></image> -->
<view class='cell-hd-title'>个人信息</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd' @click="navigateToHandle('./user_info/password')">
<view class='cell-hd-title'>修改密码</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' src='../../../static/image/right.png'></image>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd' @click="clearCache">
<!-- <image class='cell-hd-icon' src=''></image> -->
<view class='cell-hd-title'>清除缓存</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd' @click="aboutUs">
<!-- <image class='cell-hd-icon' src='/static/image/me-ic-about.png'></image> -->
<view class='cell-hd-title'>关于我们</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd' @click="logOff">
<!-- <image class='cell-hd-icon' src='/static/image/me-ic-about.png'></image> -->
<view class='cell-hd-title'>退出</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' src='/static/image/right.png'></image>
</view>
</view>
</view>
</view>
<!-- <view class="button-bottom">
<button class="btn btn-b">退出登录</button>
</view> -->
</view>
</template>
<script>
export default {
methods: {
navigateToHandle(pageUrl) {
this.$common.navigateTo(pageUrl)
},
// 清除缓存
clearCache() {
// 重新获取统一配置信息
this.$api.shopConfig(res => {
this.$store.commit('config', res)
})
// 删除地区缓存信息
this.$db.del('areaList')
setTimeout(() => {
this.$common.successToShow('清除成功')
}, 500)
},
// 关于我们
aboutUs() {
let articleId = this.$store.state.config.about_article_id;
this.$common.navigateTo('/pages/article/index?id_type=1&id=' + articleId);
},
// 退出登录
logOff() {
this.$common.modelShow('退出', '确认退出登录吗?', () => {
this.$db.del('userToken')
uni.reLaunch({
url: '/pages/index/index'
})
})
}
}
}
</script>
<style>
</style>
user_info
index.vue
<template>
<view class="content">
<view class="content-top">
<view class='cell-group'>
<view class='cell-item user-head'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>头像</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next user-head-img have-none' mode="aspectFill" :src="avatar" @click="uploadAvatar"></image>
</view>
</view>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>昵称</view>
</view>
<view class='cell-item-bd'>
<input class='cell-bd-input' placeholder='' v-model="nickname" ></input>
</view>
</view>
<view class='cell-item right-img'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>性别</view>
</view>
<view class='cell-item-bd'>
<view class="uni-list">
<view class="uni-list-cell-db">
<picker @change="bindPickerChange" :value="index" :range="objectSex">
<view class="uni-input">{{objectSex[sex]}}</view>
</picker>
</view>
</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' src='/static/image/ic-pull-down.png'></image>
</view>
</view>
<view class='cell-item right-img'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>生日</view>
</view>
<view class='cell-item-bd'>
<view class="uni-list">
<view class="uni-list-cell-db">
<picker mode="date" :value="date" :start="startDate" :end="endDate" @change="bindDateChange">
<view class="uni-input">{{birthday}}</view>
</picker>
</view>
</view>
</view>
<view class='cell-item-ft'>
<image class='cell-ft-next icon' src='/static/image/ic-pull-down.png'></image>
</view>
</view>
</view>
</view>
<view class="button-bottom">
<button class="btn btn-square btn-b" hover-class="btn-hover2" @click="submitHandler()" :disabled='submitStatus' :loading='submitStatus'>保存</button>
</view>
</view>
</template>
<script>
export default {
data() {
return {
title: 'picker',
avatar: '',
objectSex: ['男', '女', '未知'],
index: 2,
nickname: '',
mobile: '',
date: '1990-01-01',
birthday: '请选择',
sex: 0,
submitStatus: false
}
},
computed: {
startDate() {
return this.getDate('start');
},
endDate() {
return this.getDate('end');
}
},
methods: {
//性别
bindPickerChange: function(e) {
this.sex = e.target.value;
},
//生日
bindDateChange: function(e) {
this.birthday = e.target.value;
},
getDate(type) {
const date = new Date();
let year = date.getFullYear();
let month = date.getMonth() + 1;
let day = date.getDate();
if (type === 'start') {
year = year - 60;
} else if (type === 'end') {
year = year + 2;
}
month = month > 9 ? month : '0' + month;;
day = day > 9 ? day : '0' + day;
return `${year}-${month}-${day}`;
},
// 用户上传头像
uploadAvatar () {
this.$api.uploadFiles(res => {
if (res.status) {
let avatar = res.data.url // 上传成功的图片地址
// 执行头像修改
this.$api.changeAvatar({
avatar: avatar
}, res => {
if (res.status) {
this.$common.successToShow('上传成功', () => {
this.avatar = res.data.avatar
})
} else {
this.$common.errorToShow(res.msg)
}
})
} else {
this.$common.errorToShow(res.msg)
}
})
},
// 保存资料
submitHandler() {
this.submitStatus = true;
let sex = this.sex +1;
if(this.birthday == '请选择'){
this.$common.successToShow('请选择出生日期');
this.submitStatus = false;
return false;
}else{
this.$api.editInfo({
sex: sex,
birthday: this.birthday,
nickname: this.nickname
}, res => {
this.$common.successToShow(res.msg, result => {
this.submitStatus = false;
uni.navigateBack({
delta: 1
});
});
}
);
}
}
},
onLoad: function() {
var _this = this;
_this.$api.userInfo({}, function(res) {
if (res.status) {
var the_sex = res.data.sex - 1;
if (res.data.birthday == null) {
res.data.birthday = '请选择';
}
_this.nickname = res.data.nickname;
_this.mobile = res.data.mobile;
_this.sex = the_sex;
_this.index = the_sex;
_this.birthday = res.data.birthday;
_this.avatar = res.data.avatar;
if(_this.birthday!='请选择'){
_this.date = _this.birthday;
}
} else {
//报错了
_this.$common.errorToShow(res.msg);
}
});
}
}
</script>
<style>
.user-head{
height: 100upx;
}
.user-head-img{
height: 90upx;
width: 90upx;
border-radius: 50%;
}
.cell-hd-title{
color: #333;
}
.cell-item-bd{
color: #666;
font-size: 26upx;
}
</style>
password.vue
<template>
<view class="content">
<view class="content-top">
<view class='cell-group'>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>旧密码</view>
</view>
<view class='cell-item-bd'>
<input class='cell-bd-input' placeholder='' v-model="pwd"></input>
</view>
</view>
</view>
<view class='cell-group'>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>新密码</view>
</view>
<view class='cell-item-bd'>
<input class='cell-bd-input' placeholder='' v-model="newPwd"></input>
</view>
</view>
</view>
<view class='cell-group'>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>确认密码</view>
</view>
<view class='cell-item-bd'>
<input class='cell-bd-input' placeholder='' v-model="rePwd"></input>
</view>
</view>
</view>
</view>
<view class="button-bottom">
<button class="btn btn-square btn-b" hover-class="btn-hover2" @click="submitHandler()" :disabled='submitStatus'
:loading='submitStatus'>保存</button>
</view>
</view>
</template>
<script>
export default {
data() {
return {
pwd: '',
newPwd: '',
rePwd: '',
sex: 0,
submitStatus: false
}
},
computed: {},
methods: {
// 保存资料
submitHandler() {
this.submitStatus = true;
if (this.pwd === '') {
this.$common.errorToShow('请输入旧密码')
this.submitStatus = false;
} else if (this.newPwd === '') {
this.$common.errorToShow('请输入新密码')
this.submitStatus = false;
} else if (this.rePwd === '') {
this.$common.errorToShow('请输入重复密码')
this.submitStatus = false;
} else {
this.$api.editPwd({
pwd: this.pwd,
newpwd: this.newPwd,
repwd: this.rePwd
}, res => {
this.submitStatus = false;
this.$common.successToShow(res.msg)
this.pwd = this.newPwd = this.rePwd = '';
})
}
}
},
onLoad: function() {
var _this = this;
_this.$api.userInfo({}, function(res) {
if (res.status) {
var the_sex = res.data.sex - 1;
if (res.data.birthday == null) {
res.data.birthday = '请选择';
}
_this.nickname = res.data.nickname;
_this.mobile = res.data.mobile;
_this.sex = the_sex;
_this.index = the_sex;
_this.birthday = res.data.birthday;
_this.avatar = res.data.avatar;
if (_this.birthday != '请选择') {
_this.date = _this.birthday;
}
} else {
//报错了
_this.$common.errorToShow(res.msg);
}
});
}
}
</script>
<style>
.user-head {
height: 100upx;
}
.user-head-img {
height: 90upx;
width: 90upx;
border-radius: 50%;
}
.cell-hd-title {
color: #333;
}
.cell-item-bd {
color: #666;
font-size: 26upx;
}
</style>
take_delivery
index.vue
<template>
<view class="content">
<view class="content-top">
<view class="ad" >
<image class="ad-img" src="/static/demo-img/banner.png" mode="widthFix" ></image>
</view>
<view class='search'>
<view class='search-c'>
<image class='icon search-icon' src='/static/image/zoom.png'></image>
<input class='search-input' placeholder-class='search-input-p' placeholder='请输入完整提货单号、订单号、提货手机号' v-model="key"></input>
</view>
<button class="btn btn-g" hover-class="btn-hover2" @click="search">查询</button>
</view>
<view v-if="allData.length">
<checkbox-group @change="checkboxChange">
<view class="img-list">
<view class="img-list-c" v-for="(item, index) in allData" :key="index">
<view class="img-list-title">
<view class="ilt-left">
<text class="color-6">订单号:</text><text class="color-9">{{ item.order_id }}</text>
</view>
<view class="ilt-right color-9">
{{ item.status_name }}
</view>
</view>
<view class="img-list-bot">
<label class="uni-list-cell uni-list-cell-pd">
<view v-if="!item.disabled" class="img-list-checkbox">
<checkbox color="#FF7159" :value="item.id" :checked="item.checked" :disabled="item.disabled" v-if="item.disabled" class="checkboxNo"/>
<checkbox color="#FF7159" :value="item.id" :checked="item.checked" :disabled="item.disabled" v-else/>
</view>
</label>
<view class="img-list-right">
<view class="img-list-content" v-for="(i, key) in item.goods" :key="key">
<view class="img-list-item">
<image class="img-list-item-l" :src="i.image_url" mode='aspectFill'></image>
<view class="img-list-item-r">
<view class="goods-name list-goods-name">{{i.name}}</view>
<view class="goods-item-c">
<view class="goods-buy">
<view class="goods-salesvolume">规格:{{i.addon}}</view>
<view class="goods-salesvolume">数量:{{i.nums}}</view>
<view class="goods-salesvolume">SN码:{{i.sn}}</view>
<view class="goods-salesvolume">BN码:{{i.bn}}</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</checkbox-group>
</view>
</view>
<view class="button-bottom" v-if="allData.length">
<button class="btn btn-b btn-square" @click="write" v-if="checkedIds.length">确认核销</button>
<button class="btn btn-b btn-square completed" v-else>请选择待核销订单</button>
</view>
</view>
</template>
<script>
export default {
data(){
return {
key: '', // 筛选条件
isgo: false,
isgotext: '确认核销',
allData: [] // 提货单列表
}
},
onLoad(e){
if(e.id){
this.key = e.id;
}
this.getLadingInfo();
},
computed: {
// 获取选中的提货单id
checkedIds () {
let ids = []
this.allData.forEach(item => {
// 判断不是禁用状态 并且是选中状态 并且是未核销状态
if (!item.disabled && item.checked && item.status === 1) {
ids.push(item.id)
}
})
return ids
},
},
methods: {
// 多选框点击事件处理
checkboxChange (e) {
var values = e.detail.value;
this.allData.forEach(item => {
if (values.includes(item.id)) {
item.checked = true
} else {
item.checked = false
}
})
},
//获取提货单详情
getLadingInfo() {
if(this.key){
let data = {
'key': this.key
}
this.$api.ladingInfo(data, e => {
if (e.status) {
this.allData = this.formatData(e.data);
} else {
this.allData = []; // 清空数据
this.$common.modelShow('提示', e.msg, function(){});
}
});
}
},
//搜索
search() {
if(this.key != ''){
this.getLadingInfo();
}else{
this.$common.errorToShow('请输入查询关键字');
return false;
}
},
//查询判断是否可以核销
isGoWrite(data) {
let isgo = false;
if (data.order_info.pay_status == 2 && data.order_info.ship_status == 3){
isgo = true;
this.lading_id = data.id;
this.goodsList = data.goods;
this.allData = data;
} else {
this.$common.modelShow('无法核销', '订单必须支付并已发货才可以核销', function(){});
}
this.isgo = isgo;
},
// 数据转化
formatData (data){
data.forEach (item => {
if (item.status === 2) {
// 已提货
this.$set(item, 'checked', false)
this.$set(item, 'disabled', true)
} else {
// 未提货
this.$set(item, 'checked', true)
this.$set(item, 'disabled', false)
}
})
return data
},
//去核销
write() {
let _this = this;
this.$common.modelShow('提示', '您确认核销吗?', function(res){
//去核销
let data = {
lading_ids: _this.checkedIds.join()
}
_this.$api.ladingExec(data, res => {
if(res.status) {
_this.$common.successToShow(res.msg, _this.afterChangeDataStatus())
}
});
});
},
// 核销完成后更改数据状态
afterChangeDataStatus () {
this.allData.forEach(item => {
if (this.checkedIds.indexOf(item.id) > -1) {
item.status = 2
item.checked = false
item.disabled = true
}
})
}
}
}
</script>
<style>
.ad {
width: 100%;
/* margin: 20upx 0; */
overflow: hidden;
}
.ad-img{
width: 100%;
float: left;
margin-bottom: 20upx;
}
.ad-img:last-child{
margin-bottom: 0;
}
.search{
display: flex;
}
.search-c{
width: 85%;
margin-right: 2%;
}
.search-icon{
left: 20upx;
}
.search-input {
padding: 10upx 30upx 10upx 70upx;
}
.search-input-p{
padding: 0 !important;
}
.search .btn{
width: 15%;
border: none;
background-color: #f1f1f1;
font-size: 26upx;
color: #333;
border-radius: 6upx;
line-height: 72upx;
padding-left: 18upx;
padding-right: 18upx;
}
.list-goods-name{
margin-bottom: 8upx;
}
.goods-salesvolume{
display: block;
margin-bottom: 6upx;
}
.completed{
background-color: #d9d9d9;
color: #4e4e4e;
}
.img-list-bot{
background-color: #fff;
display: flex;
padding: 30upx 26upx;
}
.img-list-title{
padding: 26upx 26upx 0;
background-color: #fff;
font-size: 28upx;
overflow: hidden;
}
.ilt-left{
float: left;
}
.ilt-right{
float: right;
}
.img-list-checkbox{
/* display: inline-block; */
position: relative;
height: 100%;
}
.img-list-checkbox uni-checkbox{
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.img-list-right{
/* display: inline-block; */
margin-left: 60upx;
}
.img-list-item{
padding: 0;
}
.img-list-item-r{
width: 360upx;
}
</style>
list.vue
<template>
<view class="content">
<view class="order-list">
<view class="goods-detail">
<view class="order-item" v-for="(item, key) in ladingList" :key="key">
<view class='cell-group'>
<view class='cell-item' style="padding: 10upx 26upx 0 0;">
<view class='cell-item-hd'>
<view class='cell-hd-title'>提货码:{{item.id}}</view>
</view>
<view class='cell-item-ft'>
<text class='cell-ft-text'>{{item.status_name}}</text>
</view>
</view>
</view>
<view class='cell-group'>
<view class='cell-item'>
<view class='cell-item-hd'>
<view class='cell-hd-title'>订单编号:{{item.order_id}}</view>
</view>
<view class='cell-item-ft'>
<!-- <text class='cell-ft-text' v-if="item.status == 1">待提货</text>
<text class='cell-ft-text' v-else-if="item.status === 2">已提货</text>
<text class='cell-ft-text' v-else>未知状态</text> -->
</view>
</view>
</view>
<view class='img-list'>
<view class='img-list-item' v-for="(v, k) in item.order_items" :key="k">
<image class='img-list-item-l little-img have-none' :src='v.image_url' mode='aspectFill'></image>
<view class='img-list-item-r little-right'>
<view class='little-right-t'>
<view class='goods-name list-goods-name'>{{v.name}}</view>
<view class='goods-price'>¥{{v.price}}</view>
</view>
<view class='goods-item-c'>
<view class='goods-buy'>
<view class='goods-salesvolume' v-show="v.addon">{{v.addon}}</view>
<view class='goods-num'>×{{v.nums}}</view>
</view>
</view>
</view>
</view>
</view>
<view class='order-list-button'>
<button class='btn btn-circle btn-g' hover-class="btn-hover" v-if="item.status == 2" @click="ladingDel(item.id)">删除</button>
<button class='btn btn-circle btn-w' hover-class="btn-hover" v-if="item.status == 1" @click="ladingWrite(item.id)">提货单核销</button>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data(){
return {
ladingList: [],
}
},
onShow(){
this.getLadingList();
},
methods: {
//获取提货单列表
getLadingList() {
this.$api.storeLadingList({}, res => {
this.ladingList = res.data;
});
},
//提货单核销
ladingWrite(id) {
this.$common.navigateTo('./index?id=' + id);
},
//删除
ladingDel(id) {
this.$common.modelShow('提示', '删除提货单后将无法找回!', res => {
let data = {
'lading_id': id
}
this.$api.ladingDel(data, res => {
this.$common.successToShow(res.msg, res => {
this.getLadingList();
});
});
});
}
}
}
</script>
<style>
.segmented-control {
/* #ifdef H5 */
top: 44px;
/* #endif */
/* #ifndef H5 */
top: 0;
/* #endif */
width: 100%;
background-color: #fff;
position: fixed;
z-index: 999;
}
.segmented-control-item{
line-height: 70upx;
}
.order-list{
/* margin-top: 64upx; */
}
.order-item{
margin-bottom: 20upx;
}
.img-list{
margin-top: 2upx;
}
.cell-group,.img-list-item {
background-color: #fff;
}
.cell-hd-title{
font-size: 22upx;
color: #666;
}
.cell-ft-text{
top: 0;
font-size: 22upx;
color: #333;
}
.order-list-button{
width: 100%;
background-color: #fff;
text-align: right;
padding: 10upx 26upx;
/* border-top: 2upx solid #f8f8f8; */
}
.order-list-button .btn{
height: 50upx;
line-height: 50upx;
}
.order-list-button .btn-w{
margin-left: 20upx;
}
.goods-num .cell-ft-text{
color: #999;
line-height: 32upx;
}
.goods-num .cell-ft-text:first-child{
margin-left: 10upx;
}
.order-none{
text-align: center;
padding: 200upx 0;
}
.order-none-img{
width: 274upx;
height: 274upx;
}
</style>
model
index.vue
share
jump.vue
<template>
<view></view>
</template>
<script>
export default {
data() {
return {};
},
onLoad(e) {
let url = this.$common.shareParameterEncode(e.scene);
let arr1 = url.split('&');
let type = '',
invite = '',
page_code = '',
id = '',
id_type = '',
group_id = '',
team_id = '';
for (var i = 0; i < arr1.length; i++) {
let key = arr1[i].split('=')[0]
if (key == 'type') {
type = arr1[i].split('=')[1]
}
if (key == 'invite') {
invite = arr1[i].split('=')[1]
}
if (key == 'page_code') {
page_code = arr1[i].split('=')[1]
}
if (key == 'id') {
id = arr1[i].split('=')[1]
}
if (key == 'id_type') {
id_type = arr1[i].split('=')[1]
}
if (key == 'group_id') {
group_id = arr1[i].split('=')[1]
}
if (key == 'team_id') {//拼团参团id
team_id = arr1[i].split('=')[1]
}
}
this.saveInviteCode(invite); //存储邀请码
switch (type) {
case '1': //首页
this.gotoIndex();
break;
case '2': //商品详情页面
this.gotoGoods(id);
break;
case '3': //首页
this.gotoIndex();
break;
case '4': //文章页面
this.gotoArticle(id, id_type);
break;
case '5': //拼团页面
this.gotoPinTuan(id, team_id);
break;
case '6': //团购页面
this.gotoGroup(id, group_id);
break;
case '7': //参团页面
// todo:: 功能暂无后续开发
// this.gotoInvitationGroup(id, group_id, team_id);
break;
case '8': //自定义页面
this.gotoCustom(page_code);
break;
case '9': //店铺邀请
this.gotoStore(id);
break;
case '10': //智能表单
this.gotoForm(id);
break;
default:
this.gotoIndex();
break;
}
},
methods: {
//存储邀请码
saveInviteCode(invite) {
if (invite && invite != '') {
this.$db.set('invitecode', invite);
}
},
//跳转到首页
gotoIndex() {
uni.switchTab({
url: '/pages/index/index'
});
},
//跳转到商品
gotoGoods(id) {
if(id && id != ''){
let url = '/pages/goods/index/index?id=' + id;
this.$common.redirectTo(url);
}else{
this.gotoIndex();
}
},
//跳转到文章
gotoArticle(id, id_type) {
if(id && id != ''){
let url = '/pages/article/index?id=' + id + '&id_type=' + id_type;
this.$common.redirectTo(url);
}else{
this.gotoIndex();
}
},
//跳转到拼团
gotoPinTuan(id, team_id) {
if(id && id != ''){
let url = '/pages/goods/index/pintuan?id=' + id + '&team_id=' + team_id;
this.$common.redirectTo(url);
}else{
this.gotoIndex();
}
},
//跳转到团购
gotoGroup(id, group_id) {
if(id && id != ''){
let url = '/pages/goods/index/group?id=' + id + '&group_id=' + group_id;
this.$common.redirectTo(url);
}else{
this.gotoIndex();
}
},
//跳转到参团
//todo:: 功能暂无后续开发
// gotoInvitationGroup(id, group_id, team_id) {
// if(id && id != '' && group_id && group_id != '' && team_id && team_id != ''){
// let url = '/pages/member/order/invitation_group?id=' + id + '&group_id=' + group_id + '&team_id=' + team_id;
// this.$common.redirectTo(url);
// }else{
// this.gotoIndex();
// }
// },
//跳转到自定义页
gotoCustom(page_code) {
if(page_code && page_code != ''){
let url = '/pages/index/custom?page_code=' + page_code;
this.$common.redirectTo(url);
}else{
this.gotoIndex();
}
},
gotoStore(id) {
if(id && id != ''){
let url = '/pages/member/distribution/my_store?store=' + id;
this.$common.redirectTo(url);
}else{
this.gotoIndex();
}
},
//跳转表单
gotoForm(id){
if(id && id != ''){
let url = '/pages/form/detail/form?id=' + id;
this.$common.redirectTo(url);
}else{
this.gotoIndex();
}
}
}
};
</script>
share.vue
<template>
<view class="content">
<view class="share-top"><img class="share-img" :src="poster" mode="widthFix"/></view>
<view class="share-bot">
<button class="btn btn-b" v-if="weiXinBrowser">长按图片保存到手机</button>
<button class="btn btn-b" @click="savePoster()" v-else>保存到本地</button>
<button class="btn btn-w" @click="goBack()">返回</button>
</view>
</view>
</template>
<script>
export default {
data() {
return {
poster: ''
};
},
onLoad(options) {
this.poster = options.poster;
},
computed: {
weiXinBrowser () {
return this.$common.isWeiXinBrowser()
}
},
methods: {
goBack() {
uni.navigateBack({
delta: 1
});
},
// 保存海报到本地
savePoster() {
let _this = this;
// #ifdef H5
_this.downloadIamge(_this.poster, 'image');
// #endif
// #ifdef MP || MP-ALIPAY || APP-PLUS || APP-PLUS-NVUE
_this.downloadImageOfMp(_this.poster)
// #endif
},
//下载图片地址和图片名
downloadIamge(imgsrc, name) {
var image = new Image();
// 解决跨域 Canvas 污染问题
image.setAttribute('crossorigin', 'anonymous');
image.onload = () => {
var canvas = document.createElement('canvas');
canvas.width = image.width;
canvas.height = image.height;
var context = canvas.getContext('2d');
context.drawImage(image, 0, 0, image.width, image.height);
var url = canvas.toDataURL('image/png'); //得到图片的base64编码数据
var a = document.createElement('a'); // 生成一个a元素
var event = new MouseEvent('click'); // 创建一个单击事件
a.download = name || 'photo'; // 设置图片名称
a.href = url; // 将生成的URL设置为a.href属性
a.dispatchEvent(event); // 触发a的单击事件
};
image.src = imgsrc;
},
downloadImageOfMp (image) {
let _this = this
// #ifdef APP-PLUS
uni.downloadFile({
url: image,
success (res) {
uni.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success() {
_this.$common.successToShow('保存成功')
},
fail() {
_this.$common.errorToShow('图片保存失败')
}
});
},
fail () {
_this.$common.errorToShow('下载失败')
}
})
// #endif
// #ifdef MP
uni.authorize({
scope: 'scope.writePhotosAlbum',
success() {
// 先下载到本地
uni.downloadFile({
url: image,
success (res) {
uni.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success() {
_this.$common.successToShow('保存成功')
},
fail() {
_this.$common.errorToShow('图片保存失败')
}
});
},
fail () {
_this.$common.errorToShow('下载失败')
}
})
},
fail() {
//console.log('授权失败')
}
})
// #endif
}
}
};
</script>
<style>
.share-top {
margin-bottom: 50upx;
padding-top: 50upx;
text-align: center;
}
.share-img {
box-shadow: 0 0 20upx #ccc;
width: 80%;
}
.share-bot {
width: 80%;
margin: 0 auto;
}
.share-bot .btn {
width: 100%;
margin: 20upx 0;
}
</style>
store_map
index.vue
<template>
<view class="content">
<view class="map-body">
<cover-view></cover-view>
<map id="storeMap" :latitude="latitude" :longitude="longitude" :markers="covers" style="width: 100%;height: 100%;"></map>
</view>
<scroll-view class="store-list" scroll-y>
<view class="cell-item add-title-item" v-for="(item, index) in storeList" :key="index" @click="goMarkers(item.id)">
<view class="cell-item-hd"><image class="store-img" :src="item.logo"></image></view>
<view class="cell-item-bd">
<view class="cell-bd-view">
<text class="cell-bd-text fsz30">{{ item.store_name }}</text>
</view>
<view class="cell-bd-view">
<text class="cell-bd-text color-6 fsz24">电话:{{ item.mobile }}</text>
</view>
<view class="cell-bd-view">
<text class="cell-bd-text color-6 fsz24">地址:{{ item.all_address }}</text>
</view>
</view>
<view class="cell-item-ft"><image class="cell-ft-next icon" src="/static/image/right.png"></image></view>
</view>
</scroll-view>
</view>
</template>
<script>
export default {
data() {
return {
storeList: [],
longitude: 0,
latitude: 0,
covers: [{
'longitude': 0,
'latitude': 0
}]
};
},
onLoad() {
this.getMyLocation();
this.getStoreList();
},
methods: {
// 获取自己的位置信息
getMyLocation() {
let _this = this;
uni.getLocation({
type: 'wgs84',
success: function (res) {
_this.longitude = res.longitude;
_this.latitude = res.latitude;
},
fail: function () {
_this.$common.errorToShow("获取位置信息失败")
}
});
},
// 获取店铺列表信息
getStoreList() {
let _this = this;
_this.$api.storeList({}, res => {
if (res.status) {
_this.storeList = res.data;
let storeList = res.data;
let covers = [];
for (let i=0; i < storeList.length; i++) {
let newArr = {}
newArr.latitude = storeList[i].latitude;
newArr.longitude = storeList[i].longitude;
newArr.width = '50rpx';
newArr.height = '50rpx';
newArr.iconPath = '/static/image/gps-blue.png'
covers.push(newArr)
}
console.log(covers)
_this.covers = covers;
} else {
}
// console.log(res)
});
}
}
};
</script>
<style scoped>
.content {
width: 100%;
/* #ifdef H5 */
height: calc(100vh - 44px);
/* #endif */
/* height: 100vh; */
}
.map-body {
width: 100%;
height: 700rpx;
position: relative;
}
.store-list {
background-color: #fff;
height: calc(100vh - 44px - 700rpx);
}
.store-item {
display: flex;
}
.store-img {
width: 140rpx;
height: 140rpx;
}
.store-right {
flex: 1;
}
</style>
pages.json
{
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "首页",
// #ifdef H5
"titleNView": false,
// #endif
"enablePullDownRefresh": true
}
},
{
"path": "pages/index/custom",
"style": {
"navigationBarTitleText": "页面",
// #ifdef H5
"titleNView": false,
// #endif
"enablePullDownRefresh": true
}
},
{
"path": "pages/index/search",
"style": {
"navigationBarTitleText": "搜索"
}
},
{
"path": "pages/classify/classify",
"style": {
"navigationBarTitleText": "分类"
}
},
{
"path": "pages/classify/index",
"style": {
"navigationBarTitleText": "商品列表"
}
},
{
"path": "pages/cart/index/index",
"style": {
"navigationBarTitleText": "购物车"
}
},
{
"path": "pages/member/index/index",
"style": {
// #ifdef H5
"titleNView": false,
// #endif
"navigationBarTitleText": "个人中心"
}
},
{
"path": "pages/member/coupon/index",
"style": {
"navigationBarTitleText": "我的优惠券"
}
},
{
"path": "pages/member/balance/index",
"style": {
"navigationBarTitleText": "我的余额"
}
},
{
"path": "pages/member/balance/recharge",
"style": {
"navigationBarTitleText": "充值"
}
},
{
"path": "pages/member/balance/withdraw_cash",
"style": {
"navigationBarTitleText": "提现"
}
},
{
"path": "pages/member/balance/details",
"style": {
"navigationBarTitleText": "余额明细"
}
},
{
"path": "pages/member/balance/cashlist",
"style": {
"navigationBarTitleText": "提现记录"
}
},
{
"path": "pages/member/balance/bankcard",
"style": {
"navigationBarTitleText": "我的银行卡"
}
},
{
"path": "pages/member/balance/add_bankcard",
"style": {
"navigationBarTitleText": "添加银行卡"
}
},
{
"path": "pages/member/collection/index",
"style": {
"navigationBarTitleText": "我的收藏"
}
},
{
"path": "pages/member/history/index",
"style": {
"navigationBarTitleText": "我的足迹"
}
},
{
"path": "pages/member/address/list",
"style": {
"navigationBarTitleText": "地址管理"
}
},
{
"path": "pages/member/address/index",
"style": {
"navigationBarTitleText": "修改地址"
}
},
{
"path": "pages/member/setting/index",
"style": {
"navigationBarTitleText": "设置"
}
},
{
"path": "pages/member/setting/user_info/index",
"style": {
"navigationBarTitleText": "个人信息"
}
},
{
"path": "pages/member/setting/user_info/password",
"style": {
"navigationBarTitleText": "修改密码"
}
},
{
"path": "pages/member/integral/index",
"style": {
"navigationBarTitleText": "我的积分"
}
},
{
"path": "pages/member/invite/index",
"style": {
"navigationBarTitleText": "邀请好友"
}
},
{
"path": "pages/member/invite/list",
"style": {
"navigationBarTitleText": "邀请列表"
}
},
{
"path": "pages/member/take_delivery/index",
"style": {
"navigationBarTitleText": "提货单核销"
}
},
{
"path": "pages/member/take_delivery/list",
"style": {
"navigationBarTitleText": "提货单列表"
}
},
{
"path": "pages/goods/index/index",
"style": {
// #ifdef H5
"titleNView": false,
// #endif
"navigationBarTitleText": "商品详情",
"navigationStyle": "custom"
}
},
{
"path": "pages/goods/index/group",
"style": {
"navigationBarTitleText": "促销详情",
"navigationStyle": "custom"
}
},
{
"path": "pages/goods/place-order/index",
"style": {
"navigationBarTitleText": "提交订单"
}
},
{
"path": "pages/goods/place-order/invoice",
"style": {
"navigationBarTitleText": "发票"
}
},
{
"path": "pages/goods/place-order/storelist",
"style": {
"navigationBarTitleText": "门店列表"
}
},
{
"path": "pages/goods/payment/index",
"style": {
"navigationBarTitleText": "支付"
}
},
{
"path": "pages/goods/payment/auth",
"style": {
"navigationBarTitleText": "等待支付"
}
},
{
"path": "pages/goods/payment/result",
"style": {
"navigationBarTitleText": "支付结果"
}
},
{
"path": "pages/member/order/orderlist",
"style": {
"navigationBarTitleText": "订单列表"
}
},
{
"path": "pages/member/order/orderdetail",
"style": {
"navigationBarTitleText": "订单详情"
}
},
{
"path": "pages/member/order/invitation_group",
"style": {
"navigationBarTitleText": "邀请拼单"
}
},
{
"path": "pages/member/after_sale/index",
"style": {
"navigationBarTitleText": "申请售后"
}
},
{
"path": "pages/member/after_sale/list",
"style": {
"navigationBarTitleText": "售后列表"
}
},
{
"path": "pages/member/after_sale/detail",
"style": {
"navigationBarTitleText": "售后详情"
}
},
{
"path": "pages/member/order/evaluate",
"style": {
"navigationBarTitleText": "订单评价"
}
},
{
"path": "pages/member/order/express_delivery",
"style": {
"navigationBarTitleText": "物流信息"
}
},
{
"path": "pages/article/index",
"style": {
"navigationBarTitleText": "文章详情"
}
},
{
"path": "pages/article/list",
"style": {
"navigationBarTitleText": "文章列表"
}
},
{
"path": "pages/login/choose/index",
"style": {
"navigationBarTitleText": "授权登录"
}
},
{
"path": "pages/login/login/index",
"style": {
"navigationBarTitleText": "登录"
}
},
{
"path": "pages/login/login/index1",
"style": {
"navigationBarTitleText": "登录"
}
},
{
"path": "pages/share",
"style": {
"navigationBarTitleText": "分享"
}
},
{
"path": "pages/author",
"style": {
// #ifdef H5
"titleNView": false,
// #endif
"navigationBarTitleText": "获取授权中"
}
},
{
"path": "pages/login/register/index",
"style": {
"navigationBarTitleText": "注册"
}
},
{
"path": "pages/classify/pintuan_list",
"style": {
"navigationBarTitleText": "拼团列表"
}
},
{
"path": "pages/goods/index/pintuan",
"style": {
"navigationBarTitleText": "拼团详情",
"navigationStyle": "custom"
}
},
{
"path": "pages/form/detail/form",
"style": {
"navigationBarTitleText": "万能表单"
}
},
{
"path": "pages/member/distribution/index",
"style": {
"navigationBarTitleText": "分销中心"
}
},
{
"path": "pages/member/distribution/apply",
"style": {
"navigationBarTitleText": "申请成为分销"
}
},
{
"path": "pages/member/distribution/apply_state",
"style": {
"navigationBarTitleText": "审核状态"
}
},
{
"path": "pages/member/distribution/user",
"style": {
"navigationBarTitleText": "分销中心"
}
},
{
"path": "pages/member/distribution/agreement",
"style": {
"navigationBarTitleText": "分销协议"
}
},
{
"path": "pages/member/distribution/order",
"style": {
"navigationBarTitleText": "推广订单"
}
},
{
"path": "pages/member/distribution/popularize",
"style": {
"navigationBarTitleText": "我要推广"
}
},
{
"path": "pages/member/distribution/my_store",
"style": {
"navigationBarTitleText": "我的店铺"
}
},
{
"path": "pages/member/distribution/store_setting",
"style": {
"navigationBarTitleText": "店铺设置"
}
},
{
"path": "pages/activity/index",
"style": {
"navigationBarTitleText": "转盘抽奖"
}
},
{
"path": "pages/share/jump",
"style": {
// #ifdef H5
"titleNView": false,
// #endif
"navigationBarTitleText": "加载中..."
}
},
{
"path": "pages/store_map/index",
"style": {
"navigationBarTitleText": "门店列表"
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "新模板",
"navigationBarBackgroundColor": "#fff",
"backgroundColor": "#F8F8F8"
},
"tabBar": {
"color": "#999",
"selectedColor": "#333",
"backgroundColor": "#fff",
"list": [
{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "static/image/index_gray.png",
"selectedIconPath": "static/image/index_black.png"
},
{
"pagePath": "pages/classify/classify",
"text": "分类",
"iconPath": "static/image/classify_gray.png",
"selectedIconPath": "static/image/classify_black.png"
},
{
"pagePath": "pages/cart/index/index",
"text": "购物车",
"iconPath": "static/image/cart_gray.png",
"selectedIconPath": "static/image/cart_black.png"
},
{
"pagePath": "pages/member/index/index",
"text": "我的",
"iconPath": "static/image/user_gray.png",
"selectedIconPath": "static/image/user_black.png"
}
]
},
"condition": {
//模式配置,仅开发期间生效
"current": 0, //当前激活的模式(list 的索引项)
"list": [
{
"name": "", //模式名称
"path": "", //启动页面,必选
"query": "" //启动参数,在页面的onLoad函数里面得到
}
]
}
}
README.md
# Jshop小程序uniapp前台简约模板
#### 介绍
当前版本已支持可视化操作首页
uni-app简约前台H5+小程序模板,全新UI设计,更多交互细节,我们倾尽全力为您提供更加流畅舒爽的体验。
增加对支付宝小程序、APP的支持,实现一个后台,管理5个前端。
同时又实现了一套前端代码,发布多个平台,为您的业务可以提供更加强有力的支撑!
#### Jshop小程序商城介绍
Jshop小程序商城,是一款开源的电商系统,包含微信小程序和H5端,为大中小企业提供移动电子商务优秀的解决方案。
后台采用Thinkphp5.1框架开发,执行效率、扩展性、稳定性值得信赖。并且Jshop小程序商城上手难度低,可大量节省定制化开发周期。
前台H5使用Vue开发,在页面的打开和渲染效率上更快,下单流程流畅自然,可大大增加用户体验,提升订单量。
强大的促销引擎,多种促销方式自由搭配,满足各种场景的促销方式需求,做活动更灵活简单,并且在促销的扩展上也非常方便。
#### 关于开源
这不是一款免费的系统,商用记得授权哦。
之所以不彻底免费,一方面是可以让我们有持续维护下去的动力和资源,另外一方面也是不想让您有后顾之忧,避免后期尴尬。
我们的团队水平有限,也是在探索中学习,在改进。之所以开源,就是为了方便大家,也是为了提升下该项目的质量,我们相信有您的参与,可以使我们的系统更加完善和健壮。
#### 功能介绍
+ 商品管理,单规格、多规格商品管理,品牌、分类管理、商品评价
+ 订单管理,订单支付、发货、取消、售后等
+ 会员管理,会员列表,消息管理等
+ 运营管理,广告管理、文章管理
+ 微信管理,小程序管理、微信公众号管理、模板列表、公众号菜单管理
+ 促销管理,商品促销、订单促销、优惠券、团购秒杀
+ 财务管理,支付单、退款单管理、提现管理、账户资金管理
+ 控制面板,计划任务、插件、图片、地区、消息、店铺配置、支付方式、配送方式、物流公司管理。信任登录插件、阿里云OSS插件、阿里云短信插件、微信消息模板插件、分销功能
+ 门店管理,门店列表。门店核销、店员管理、提货单管理。
+ 智能表单,表单列表、表单统计、表单提交管理、表单小程序码等
+ 统计报表,商品销量统计、财务收款统计、订单销量统计
+ 页面管理,布局管理,页面可视化操作
#### 项目演示
- H5体验地址:https://demo.jihainet.com/wap/
- 后台项目地址:https://gitee.com/hnjihai/jshop_mall
- QQ交流群:823732583(开发手册、接口文档、操作手册请进群查看哦~)
- 交流社区:[https://bbs.jihainet.com/](https://bbs.jihainet.com/)
- H5体验二维码
![输入图片说明](https://gitee.com/uploads/images/2019/0426/090608_1a1f0073_8503.png "H5.png")
- APP体验二维码
![输入图片说明](https://gitee.com/uploads/images/2019/0426/090622_d1d4b372_8503.png "app.png")
- 微信小程序体验码
![输入图片说明](https://gitee.com/uploads/images/2019/0426/082533_e2f315f9_8503.jpeg "gh_f9fafa5a7066_344.jpg")
#### 项目截图
![输入图片说明](https://gitee.com/uploads/images/2019/0404/180847_9615f414_8503.png "未标题-1.png")
#### 目录结构
初始的目录结构如下:
wap WEB部署目录(或者子目录)
├─components uniapp组件目录
├─pages 应用页面
│ ├─article 文章相关页面
│ ├─cart 购物车相关页面
│ ├─classify 分类以及商品列表页面
│ ├─goods 商品详情页等相关页面
│ ├─index 首页以及搜索页
│ ├─login 登录相关页面
│ ├─member 会员中心相关页面
│
├─config 配置文件目录
├─static 静态文件目录
├─unpackage 编译后目录
├─index.html 入口文件模板
#### 更新说明
2019-07-31 v1.0.6
更新日志
1. 可视化图片分组添加最小高度
2. 禁止可视化垃圾桶拖拽
3. 1086短信接口改为curl
4. 增加是否绑定手机号码选项,优化后台生成用户方法
5. 修复购物车数量加减的问题
6. 生成订单的时候,有几个值没有保存成功的bug,感谢@打酱油网友提供的bug
7. 修复运费包邮bug
8. 开启规格处增加提示
9. 新增拼团功能
10. 微信登陆免手机号码校验
11. 第三方登录的时候,免手机号码验证登陆的时候,保存推荐人信息
12. 如果是第三方微信登陆,增加直接登陆
13. 用户列表显示编号
14. 修复团购秒杀删除商品后依然显示问题
15. 门店表距离获取 表前缀bug修复
16. 修复商品商品详情页品牌为空的时候,显示null的问题
17. 门店列表表前缀sql修复
18. 小程序可视化单图组件添加按钮功能
19. 订单列表加类型筛选
20. 商品详情显示优化
21. 修复库存问题
22. 可视化编辑添加文字按钮颜色
23. 小程序价格区间问题修复
24. 微信公众号无感登陆支付
25. 公众号自动登陆调整
26. 修复售后单详情查询的时候必填user_id的问题
27. 商品分类排序问题修复
28. 文章详情接口修改(文章发布时间修改为相对时间)
29. 手机号验证规则修复
30. 修复后台用户信息保存推荐人信息错误的bug
31. 修复多规格商品添加时,第一次无法保存库存问题
32. 修改可视化商品组件手动选择数据绑定
33. 修复团购秒杀问题
34. 微信和支付宝同步回调地址增加上支付单号
35. 修复门店订单有运费问题
36. 后台提货单操作,提货单详情接口修改
37. 订单售后状态简单修改
38. 修复首页多个商品组件时问题
39. 商品列表问题修复
40. 商品列表筛选调整
41. 商品分类优化
42. 页面布局修改
43. 修改商品和货品库存显示
44. 优化权限问题,修复订单支付无权限bug
45. 优化角色权限选择,可以单独选择父节点
46. 商品添加扩展分类
47. 后台商品列表动态计算库存
48. 修复公众号菜单问题
49. 修复关键词菜单
50. 图文编辑原文地址必填项问题修复,增加系统图文地址
51. 商品增加批量出库库存,改价
52. 修复商品评论,评论优化
53. 分类增加是否显示
54. 页面增加添加功能
55. 会员增加批量删除
56. 新增分销插件
57. 增加每日提现上限
58. 接口增加全局安全过滤
59. 后台登录添加背景动画,优化后台登录
60. 后台管理弹框显示修改
61. 余额变动优化,增加余额当前页统计,余额筛选类型修复
62. 修复收货地址前端输入换行问题
63. 修复后台修改管理员密码问题
64. 优化后台优化输出结构,避免节点无权限时乱码
65. 优化公众号配置地址
66. 修复原生小程序商品列表翻页问题
67. 海报生成提出来,统一处理
68. 订单发货问题优化
69. 修复vue,H5底部遮挡问题
70. 优化添加商品按钮
71. 增加加解密函数
72. 增加图片缓存,路由缓存
73. 优化分享设置,后台可设置分享
74. 后台商品列表修复高级筛选
75. 商品评价列表优化
76. 表单功能修复
77. uniapp增加智能表单
78. 表单增加提交次数限制
79. uniapp增加微信模板消息
80. 增加关于我们后台可直接配置
81. 添加批量购物车接口
82. 修复商品规格编辑问题
83. 购物车和促销价格使用精确计算
84. 微信图文增加创建和更新时间
85. 最低提现金额不能小于0.01
86. 自定义页面增加操作说明
87. 配置统一获取方法优化确保只查询一次数据库
88. 修复广告位
89. 修复编辑文章时分类问题
90. 可视化单图组件增加按钮以及颜色
2019-05-23 v1.0.5
1.修复图片组件跳转问题
2019-05-22 v1.0.4
1.增加可视化支持
2019-04-25 v1.0.3
1. 修复海报生成
2. 修复支付宝支付问题
3. 微信授权登录修复
4. 修复app登录返回问题
5. 修复支付宝绑定账户时短信验证码ip问题
#### 安装教程
1. 小程序发布教程
具体配置稍后提供
开发相关介绍:https://uniapp.dcloud.io/
2. H5发布教程
具体配置稍后提供
开发相关开发介绍:https://uniapp.dcloud.io/
## 配置
### 服务器地址
config/config.js中
export const baseUrl = 'http://www.b2c.com/';//注意最后斜杠,填写你的域名地址
export const entId = '';//客服ID 在https://www.jihainet.com中找客服开通
### 海报H5中保存图片跨域
nginx中添加以下配置
location ~ .*\.(gif|jpg|jpeg|png)$ {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers X-Requested-With;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
}
#### 安全&缺陷
如果你发现了一个安全漏洞或缺陷,请发送邮件到 jima@jihainet.com。所有的安全漏洞都将及时得到解决。
#### License
Jshop小程序商城遵循JPPL(吉海科技Jshop系列付费产品许可)协议。
本项目包含的第三方源码和二进制文件之版权信息另行标注。
版权所有Copyright © 2019 by 吉海科技 (https://www.jihainet.com)
All rights reserved。
吉海科技Jshop系列付费产品许可协议详情请参阅 [LICENSE.txt](LICENSE.txt)
static
css
style.css
body{
background-color: #f8f8f8;
font-size: 28upx;
}
view{
box-sizing: border-box;
}
/* #ifdef MP-ALIPAY */
image{
background-size: 100% 100%;
}
button{
height: auto;
border: none;
line-height: 2.55555556;
padding: 0 28upx;
}
input{
background: none;
padding: 0;
}
shared-checkbox{
border-radius: 50%;
}
shared-checkbox{
border-radius: 50%;
height: 36rpx;
width: 36rpx;
margin-top: -4rpx;
border: 1rpx solid #d1d1d1;
color: #FF7159;
}
shared-checkbox:checked {
/* width: 36rpx;
height: 36rpx;
line-height: 36rpx;
border-radius: 50%;
text-align: center;
font-size: 28rpx;
color: #fff;
background: transparent;
transform: translate(-50%, -50%) scale(1);
-webkit-transform: translate(-50%, -50%) scale(1);
background-color: #FF7159;
border: 1rpx solid #FF7159; */
background-color: #000;
color: #000;
}
._radio{
border-radius: 50%;/* 圆角 */
width: 36rpx;
height: 36rpx;
margin-top: -4rpx;
border: 1rpx solid #d1d1d1;
}
/* 选中后的 背景样式 (红色背景 无边框 可根据UI需求自己修改) */
._radio:checked{
border: 1rpx solid #FF7159;
background: #FF7159;
}
/* 选中后的 对勾样式 (白色对勾 可根据UI需求自己修改) */
._radio:checked::before{
border-radius: 50%;/* 圆角 */
width: 36rpx; /* 选中后对勾大小,不要超过背景的尺寸 */
height: 36rpx; /* 选中后对勾大小,不要超过背景的尺寸 */
line-height: 36rpx;
text-align: center;
font-size:28rpx; /* 对勾大小 30rpx */
color:#fff; /* 对勾颜色 白色 */
background: transparent;
transform:translate(-50%, -50%) scale(1);
-webkit-transform:translate(-50%, -50%) scale(1);
}
/* #endif */
uni-toast .uni-toast{
/* width: 6em; */
font-size: 24upx;
border-radius: 10px;
background: rgba(17,17,17,.5);
}
uni-input div, uni-input div div,uni-input, uni-input input{
/* min-height: 1rem !important; */
}
uni-input{
/* height: 1rem; */
}
uni-input div div.input-placeholder{
/* padding: 8upx 0; */
}
.content-top{
margin-bottom: 116upx;
}
.have-none{
background-color: #f3f3f3;
}
.color-o{
color: #FF7159 !important;
}
.color-f{
color: #fff !important;
}
.color-d{
color: #ddd !important;
}
.color-3{
color: #333 !important;
}
.color-6{
color: #666 !important;
}
.color-9{
color: #999 !important;
}
.fsz24{
font-size: 24upx !important;
}
.fsz26{
font-size: 26upx !important;
}
.fsz28{
font-size: 28upx !important;
}
.fsz30{
font-size: 30upx !important;
}
.fsz32{
font-size: 32upx !important;
}
.fsz34{
font-size: 34upx !important;
}
.fsz36{
font-size: 36upx !important;
}
.fsz38{
font-size: 38upx !important;
}
.fsz50{
font-size: 50upx !important;
}
.search{
width: 100%;
height: 104upx;
padding: 16upx 26upx;
background-color: rgba(255,255,255,1);
z-index: 999;
transition: all .5s;
}
.search-c{
width: 100%;
height: 100%;
position: relative;
}
.search-input{
background-color: #E9E9E9;
width: 100%;
height: 100%;
box-sizing: border-box;
line-height: 52upx;
padding: 10upx 90upx 10upx 40upx;
border-radius: 50upx;
font-size: 24upx;
transition: all .5s;
}
.search-input-p{
color: #999;
width: 100%;
height: 100%;
}
.search-input-p-c{
position: relative;
top: 50%;
transform: translateY(-50%);
}
.search-icon{
position: absolute;
top: 50%;
right: 30upx;
transform: translateY(-50%);
z-index: 99;
}
.swiper-c{
height: 100%;
}
.swiper-c image{
height: 100%;
width: 100%;
}
.btn{
display: inline-block;
box-sizing: border-box;
border-radius: 0;
font-size: 28upx;
transform: scale(1);
transition: all .5s;
}
/*按钮按下缩小变色*/
.btn-hover{
transform: scale(.90);
transition: all .5s;
opacity: .8;
}
/*按钮按下只变色*/
.btn-hover2{
/* transform: scale(.95); */
transition: all .1s;
opacity: .6;
}
.btn::after{
border: none;
}
.btn-circle{
padding: 0upx 20upx;
height: 60upx;
line-height: 60upx;
min-width: 140upx;
/* border-radius: 6upx; */
font-size: 22upx;
}
.btn-square{
padding: 0upx 40upx;
height: 90upx;
line-height: 90upx;
min-width: 150upx;
border: none !important;
}
.btn-fillet{
border-radius: 50upx;
}
.btn-c{
background-color: #f7f7f7;
}
.btn-w{
border: 2upx solid #333;
color: #333;
background-color: #fff;
}
.btn-g{
border: 2upx solid #E0E0E0;
color: #999;
background-color: #fff;
}
.btn-b{
border: 2upx solid #333;
background-color: #333;
color: #fff;
}
.btn-o{
border: 2upx solid #FF7159;
background-color: #FF7159;
color: #fff;
}
.btn-half{
width: 50%;
}
.btn-all{
width: 100%;
}
.img-grids{
overflow: hidden;
/* padding-bottom: 26upx; */
}
.img-grids .goods-name{
height: 72upx;
}
.column3.img-grids .goods-name{
height: 68upx;
}
.img-grids-item{
width: 336upx;
margin: 26upx;
display: inline-block;
background-color: #fff;
float: left;
min-height: 130upx;
/* #ifdef MP-ALIPAY */
width: 330rpx;
margin: 25rpx;
min-height: 130rpx;
/* #endif */
}
.img-grids-item:nth-child(2n-1){
margin-right: 0;
}
.img-grids-item-t{
width: 336upx;
height: 336upx;
/* #ifdef MP-ALIPAY */
width: 330rpx;
height: 330rpx;
/* #endif */
}
.img-grids-item-b{
padding: 0 10upx 10upx;
}
.goods-name{
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
color: #333;
width: 100%;
/* height: 72upx; */
/* #ifdef MP-ALIPAY */
min-height: 20px;
/* #endif */
}
.grids-goods-name{
font-size: 26upx;
}
.goods-item-c{
overflow: hidden;
margin-top: 10upx;
}
.goods-price{
min-width: 120upx;
min-height: 40upx;
color: #333;
font-size: 28upx;
display: inline-block;
float: left;
}
.red-price{
color: #FF7159 !important;
}
.img-list{
}
.img-list .goods-name{
min-height: 74upx;
}
.img-list-item{
padding: 30upx 26upx;
background-color: #fff;
margin-bottom: 2upx;
overflow: hidden;
}
.img-list-item-l{
width: 250upx;
height: 250upx;
display: inline-block;
float: left;
}
.img-list-item-r{
width: 410upx;
min-height: 250upx;
display: inline-block;
margin-left: 26upx;
float: left;
padding: 10upx 0;
position: relative;
}
.list-goods-name{
font-size: 28upx;
}
.img-list-item .goods-item-c{
/* position: absolute; */
/* bottom: 0; */
width: 100%;
margin-top: 0;
}
.img-list-item .goods-price{
min-width: 150upx;
min-height: 50upx;
font-size: 38upx;
float: none;
}
.goods-buy{
overflow: hidden;
}
.goods-salesvolume{
min-width: 100upx;
height: 30upx;
font-size: 20upx;
color: #999;
display: inline-block;
}
.goods-cart{
width: 40upx;
height: 40upx;
float: right;
}
.medium-img{
width: 196upx;
height: 196upx;
}
.little-img{
width: 140upx;
height: 140upx;
}
.small-img{
width: 120upx;
height: 120upx;
}
.medium-right{
width: 340upx;
min-height: 140upx;
}
.little-right{
width: 520upx;
min-height: 140upx;
padding: 0;
}
.small-right{
width: 540upx;
height: 120upx;
padding: 0;
min-height: 60upx;
}
.little-right-t{
overflow: hidden;
}
.little-right .list-goods-name{
float: left;
width: 360upx;
margin-bottom: 6upx;
}
.small-right .list-goods-name{
width: 100%;
}
.little-right .goods-price{
float: right;
font-size: 28upx;
text-align: right;
min-width: 120upx;
max-width: 150upx;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
min-height: 40upx;
}
.goods-num{
float: right;
color: #999;
font-size: 24upx;
height: 30upx;
min-width: 50upx;
}
.goods-numbox{
float: right;
}
.little-right .goods-salesvolume{
font-size: 24upx;
/* float: left; */
}
.cell-group{
background-color: #fff;
}
.cell-item{
padding: 20upx 26upx 20upx 0;
width: 724upx;
margin-left: 26upx;
border-bottom: 2upx solid #f3f3f3;
position: relative;
overflow: hidden;
background-color: #fff;
color: #333;
display: table;
min-height: 90upx;
}
.cell-item:last-child{
border: none;
}
.cell-item-hd{
display: table-cell;
vertical-align: middle;
min-width: 160upx;
max-width: 180upx;
font-size: 28upx;
position: relative;
}
.cell-hd-icon{
width: 40upx;
height: 40upx;
display: inline-block;
float: left;
margin-right: 8upx;
}
.cell-hd-title{
float: left;
display: inline-block;
position: relative;
/* #ifdef MP-ALIPAY */
top: 4upx;
/* #endif */
/* word-wrap: break-word; */
}
.cell-item-bd{
display: table-cell;
vertical-align: middle;
margin-left: 20upx;
min-height: 30upx;
overflow: hidden;
min-width: 440upx;
max-width: 480upx;
padding-right: 50upx;
}
.cell-bd-view {
position: relative;
overflow: hidden;
}
.cell-bd-text{
float: left;
position: relative;
font-size: 24upx;
}
.cell-bd-text-right{
float: right;
}
.cell-bd-input{
display: inline-block;
float: left;
font-size: 26upx;
}
.cell-item-ft{
display: inline-block;
position: absolute;
top: 50%;
right: 26upx;
transform: translateY(-50%);
overflow: hidden;
}
.right-img .cell-item-ft{
right: 8upx;
height: 50upx;
}
.cell-ft-view{
position: relative;
overflow: hidden;
color: #666;
font-size: 28upx;
text-align: right;
}
.cell-ft-p{
font-size: 24upx;
color: #666;
}
.cell-ft-text{
font-size: 28upx;
float: right;
position: relative;
/* top: 8upx; */
line-height: 50upx;
}
.cell-ft-next{
float: right;
}
.margin-cell-group{
margin: 20upx 0;
}
.bottom-cell-group{
margin-bottom: 20upx;
}
.min-cell-group{
margin-bottom: 1px;
padding: 20upx 0;
}
.min-cell-group .cell-item{
border-bottom: none;
min-height: 50upx;
padding: 0 26upx 0 0;
}
.icon{
width: 50upx;
height: 50upx;
/* #ifdef MP-ALIPAY */
background-size: 100% 100%;
/* #endif */
}
.swiper-grids .swiper-list{
white-space:nowrap;
width:100%;
min-height: 200upx;
}
.swiper-grids .img-grids-item{
float: none;
margin-right: 0;
width: 255upx;
margin-top: 0;
}
.swiper-grids .img-grids-item:last-child{
margin-right: 26upx;
}
.swiper-grids .img-grids-item-t{
width: 255upx;
height: 255upx;
}
.swiper-grids .goods-name{
white-space: normal;
}
.member-grid{
padding: 20upx 26upx;
/* overflow: hidden; */
width: 100%;
display: flex;
}
.member-item{
/* width: 20%; */
flex: 1;
/* float: left; */
/* display: inline-block; */
text-align: center;
position: relative;
}
/*会员中心图标按下事件*/
.member-item:active{
transform: scale(.90);
transition: all .5s;
opacity: .8;
}
.member-item-icon{
width: 50upx;
height: 50upx;
display: block;
margin: 0 auto;
}
.member-item-text{
font-size: 24upx;
color: #666;
display: block;
}
.cart-list{
}
.cart-checkbox{
position: relative;
height: 100%;
}
.cart-checkbox-c{
display: inline-block;
position: absolute;
top: 50%;
left: 26upx;
transform: translateY(-50%);
z-index: 99;
}
.cart-list .img-list-item{
padding-left: 90upx;
}
.cart-list .little-right{
width: 468upx;
}
.cart-list .little-right .list-goods-name{
width: 300upx;
}
.uni-checkbox-input{
border-radius: 50% !important;
color: #fff !important;
}
uni-radio .uni-radio-input,uni-checkbox .uni-checkbox-input{
width: 36upx;
height: 36upx;
}
uni-checkbox .uni-checkbox-input.uni-checkbox-input-checked,.uni-radio-input.uni-radio-input-checked{
background-color: #FF7159 !important;
border-color: #FF7159 !important;
width: 36upx;
height: 36upx;
}
uni-checkbox.checkboxNo .uni-checkbox-input{
background-color: #e1e1e1 !important;
border-color: #e1e1e1 !important;
}
uni-radio.radioNo .uni-radio-input{
background-color: #e1e1e1 !important;
border-color: #e1e1e1 !important;
}
uni-checkbox .uni-checkbox-input.uni-checkbox-input-checked:before{
font-size: 36rpx;
}
.login-item-i-p{
color: #999;
}
.two-line{
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
.badge{
display: inline-block;
position: absolute;
min-width:13px;
height:13px;
line-height:13px;
background-color:#FF7159;
color:#fff;
font-size:12px;
border-radius:50upx;
padding:0 3px;
z-index: 99;
}
.button-bottom{
background-color: #fff;
position: fixed;
bottom: 0;
height: 90upx;
width: 100%;
display: flex;
z-index: 66;
box-shadow: 0 0 10px #ccc;
}
.button-bottom .btn{
flex: 1;
}
.romotion-tip{
/* display: inline-block; */
overflow: hidden;
}
.romotion-tip-item{
display: inline-block;
float: left;
margin-right: 10upx;
margin-bottom: 4upx;
background-color: #FF7159;
color: #fff;
height: 34upx;
font-size: 24upx;
line-height: 34upx;
padding: 0 10upx;
}
.bg-gray{
background-color: #D0D0D0;
}
/* #ifdef MP */
checkbox .wx-checkbox-input{
border-radius: 50%;
height: 36rpx;
width: 36rpx;
margin-top: -4rpx;
border: 1rpx solid #d1d1d1;
}
checkbox .wx-checkbox-input.wx-checkbox-input-checked::before {
width: 36rpx;
height: 36rpx;
line-height: 36rpx;
border-radius: 50%;
text-align: center;
font-size: 28rpx;
color: #fff;
background: transparent;
transform: translate(-50%, -50%) scale(1);
-webkit-transform: translate(-50%, -50%) scale(1);
background-color: #FF7159;
border: 1rpx solid #FF7159;
}
radio .wx-radio-input{
border-radius: 50%;/* 圆角 */
width: 36rpx;
height: 36rpx;
margin-top: -4rpx;
border: 1rpx solid #d1d1d1;
}
/* 选中后的 背景样式 (红色背景 无边框 可根据UI需求自己修改) */
radio .wx-radio-input.wx-radio-input-checked{
border: 1rpx solid #FF7159;
background: #FF7159;
}
/* 选中后的 对勾样式 (白色对勾 可根据UI需求自己修改) */
radio .wx-radio-input.wx-radio-input-checked::before{
border-radius: 50%;/* 圆角 */
width: 36rpx; /* 选中后对勾大小,不要超过背景的尺寸 */
height: 36rpx; /* 选中后对勾大小,不要超过背景的尺寸 */
line-height: 36rpx;
text-align: center;
font-size:28rpx; /* 对勾大小 30rpx */
color:#fff; /* 对勾颜色 白色 */
background: transparent;
transform:translate(-50%, -50%) scale(1);
-webkit-transform:translate(-50%, -50%) scale(1);
}
/* #endif */
.goods-bottom{
z-index: 97;
}
.btn-small{
padding: 0 10rpx;
height: 36rpx;
line-height: 32rpx;
font-size: 24rpx;
margin: 0 10rpx;
}
image
img
store
index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
config: {}, // 店铺配置信息
orderTab: 0, // 选中的订单tab页
redirectPage: '',
uuid:'',//当前客户端
searchStyle: ''
},
mutations: {
config (state, payload) {
state.config = payload
},
orderTab (state, tab) {
state.orderTab = tab
},
redirect (state, payload) {
state.redirectPage = payload.page
},
searchStyle (state, style) {
state.searchStyle = style
}
},
actions: {
},
getters: {
shopConfig: state => state.config,
uuid: state => state.uuid,
}
})
export default store
uni.scss
/**
* 这里是uni-app内置的常用样式变量
*
* uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
* 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
*
*/
/**
* 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
*
* 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
*/
/* 颜色变量 */
/* 行为相关颜色 */
$uni-color-primary: #007aff;
$uni-color-success: #4cd964;
$uni-color-warning: #f0ad4e;
$uni-color-error: #dd524d;
/* 文字基本颜色 */
$uni-text-color:#333;//基本色
$uni-text-color-inverse:#fff;//反色
$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息
$uni-text-color-placeholder: #808080;
$uni-text-color-disable:#c0c0c0;
/* 背景颜色 */
$uni-bg-color:#ffffff;
$uni-bg-color-grey:#f8f8f8;
$uni-bg-color-hover:#f1f1f1;//点击状态颜色
$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
/* 边框颜色 */
$uni-border-color:#c8c7cc;
/* 尺寸变量 */
/* 文字尺寸 */
$uni-font-size-sm:24upx;
$uni-font-size-base:28upx;
$uni-font-size-lg:32upx;
/* 图片尺寸 */
$uni-img-size-sm:40upx;
$uni-img-size-base:52upx;
$uni-img-size-lg:80upx;
/* Border Radius */
$uni-border-radius-sm: 4upx;
$uni-border-radius-base: 6upx;
$uni-border-radius-lg: 12upx;
$uni-border-radius-circle: 50%;
/* 水平间距 */
$uni-spacing-row-sm: 10px;
$uni-spacing-row-base: 20upx;
$uni-spacing-row-lg: 30upx;
/* 垂直间距 */
$uni-spacing-col-sm: 8upx;
$uni-spacing-col-base: 16upx;
$uni-spacing-col-lg: 24upx;
/* 透明度 */
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
/* 文章场景相关 */
$uni-color-title: #2C405A; // 文章标题颜色
$uni-font-size-title:40upx;
$uni-color-subtitle: #555555; // 二级标题颜色
$uni-font-size-subtitle:36upx;
$uni-color-paragraph: #3F536E; // 文章段落颜色
$uni-font-size-paragraph:30upx;
//自定义变量
$theme-color: #28b8a1;
$bg-grey: #f4f4f4;
$bd-color: #f0f0f0;
$color-light: #5e5e5e;
$g2: #eeeeee;
$g5: #9e9e9e;
$fz12: 24upx;
$fz16: 32upx;
$fz18: 36upx;
$fz20: 40upx;
评论已关闭