连续复制
一键复制

App.vue

复制代码
  1. <script>
  2. export default {
  3. onLaunch() {
  4. // 获取店铺配置信息 全局只请求一次
  5. this.$api.shopConfig(res => {
  6. this.$store.commit('config', res)
  7. // #ifdef H5
  8. //百度统计
  9. if (res.statistics) {
  10. var script = document.createElement("script");
  11. script.innerHTML = res.statistics;
  12. document.getElementsByTagName("body")[0].appendChild(script);
  13. }
  14. // #endif
  15. })
  16. //获取地区信息
  17. this.$api.getAreaList({}, res => {
  18. if (res.status) {
  19. this.$db.set('areaList', res.data)
  20. }
  21. });
  22. // #ifdef APP-PLUS
  23. this.checkVersion()
  24. // #endif
  25. },
  26. onShow: function() {
  27. //console.log('App Show')
  28. },
  29. onHide: function() {
  30. //console.log('App Hide')
  31. },
  32. methods: {
  33. // #ifdef APP-PLUS
  34. // app更新检测
  35. checkVersion() {
  36. // 获取应用版本号
  37. let version = plus.runtime.version
  38. //检测当前平台,如果是安卓则启动安卓更新
  39. uni.getSystemInfo({
  40. success: res => {
  41. this.updateHandler(res.platform, version)
  42. }
  43. })
  44. },
  45. // 更新操作
  46. updateHandler(platform, version) {
  47. let data = {
  48. platform: platform,
  49. version: version
  50. }
  51. let _this = this;
  52. this.$api.getAppVersion(data,
  53. res => {
  54. if (res.status && res.data.lengh > 0) {
  55. const info = res.data[0]
  56. if (info.version !== '' && info.version > version) {
  57. uni.showModal({
  58. //提醒用户更新
  59. title: '更新提示',
  60. content: info.note,
  61. success: res => {
  62. if (res.confirm) {
  63. plus.runtime.openURL(info.download_url)
  64. }
  65. }
  66. })
  67. }
  68. }
  69. }
  70. )
  71. }
  72. // #endif
  73. }
  74. }
  75. </script>
  76. <style lang="scss">
  77. /*每个页面公共css */
  78. @import './static/css/style.css';
  79. .bgf {
  80. background: #FFF;
  81. }
  82. .flc {
  83. display: flex;
  84. justify-content: space-between;
  85. align-items: center;
  86. }
  87. .flc-inline {
  88. display: inline-flex;
  89. align-items: center;
  90. }
  91. .g5 {
  92. color: $g5;
  93. }
  94. .fz12 {
  95. font-size: $fz12;
  96. }
  97. </style>
  98. <style>
  99. @import url("/components/gaoyia-parse/parse.css");
  100. </style>

cli

复制代码
  1. <?php
  2. define('dir', __DIR__);
  3. $dirArr = explode('\\', dir);
  4. $md = dir . '\\' . $dirArr[count($dirArr) - 1] . '.md';
  5. if (is_file($md))
  6. unlink($md);
  7. // 生成md文件
  8. // file_put_contents($md, listdir(dir, '', 0));
  9. $listArr = listdir(dir);
  10. $content = getContent($listArr);
  11. $tree = "###目录###" . PHP_EOL . "```package" . PHP_EOL . listTree($listArr) . PHP_EOL . '```';
  12. file_put_contents($md, $content . PHP_EOL . $tree);
  13. function getContent($arr, $level = 0)
  14. {
  15. $content = '';
  16. foreach ($arr as $k => $v) {
  17. if (is_array($v)) {
  18. $content .= '###' . getPlaceholder($level, '#') . $k . "###" . getPlaceholder($level, '#') . PHP_EOL;
  19. $content .= getContent($v, $level + 1);
  20. } else if(!in_array(getExt($file),['.gif','.jpg','.png'])){
  21. echo getExt($file);
  22. $fileArr = explode('/', str_replace('\\', '/', $v));
  23. $file = $fileArr[count($fileArr) - 1];
  24. $content .= '###' . getPlaceholder($level, '#') . $file . "###" . getPlaceholder($level, '#') . PHP_EOL;
  25. $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;
  26. }
  27. }
  28. return $content;
  29. }
  30. function listTree($arr, $level = 0)
  31. {
  32. $content = '';
  33. $placeholder = getPlaceholder($level);
  34. foreach ($arr as $k => $v) {
  35. if (is_array($v)) {
  36. $content .= $placeholder . '└── ' . $k . PHP_EOL;
  37. $content .= listTree($v, $level + 1);
  38. } else {
  39. $fileArr = explode('/', str_replace('\\', '/', $v));
  40. $file = $fileArr[count($fileArr) - 1];
  41. $content .= $placeholder . '├── ' . $file . PHP_EOL;
  42. }
  43. }
  44. return $content;
  45. }
  46. function listdir($dir)
  47. {
  48. //定义一个数组
  49. $files = array();
  50. $notInArr = ['.', '..', '.git', '.idea', '.DS_Store', 'MD', 'MD.php', '.gitignore', '.gitignore'];
  51. $notExt = ['.exe', '.doc', '.docx', '.pdf', '.sh~', '.rar', '.zip', '.tar','.gif','.jpg','.png'];
  52. //检测是否存在文件
  53. if (is_dir($dir)) {
  54. //打开目录
  55. if ($handle = opendir($dir)) {
  56. //返回当前文件的条目
  57. while (($file = readdir($handle)) !== false) {
  58. //去除特殊目录
  59. if (!in_array($file, $notInArr)) {
  60. //判断子目录是否还存在子目录
  61. if (is_dir($dir . "/" . $file)) {
  62. // 递归调用本函数,再次获取目录
  63. $files[$file] = listdir($dir . "/" . $file);
  64. } else {
  65. if (in_array(getExt($file), $notExt))
  66. continue;
  67. // 获取目录数组
  68. $files[] = $dir . "/" . $file;
  69. }
  70. }
  71. }
  72. //关闭文件夹
  73. closedir($handle);
  74. //返回文件夹数组
  75. return $files;
  76. }
  77. }
  78. }
  79. /**
  80. * 获取占位符
  81. * @param $level
  82. * @param string $placeholder
  83. * @return string
  84. */
  85. function getPlaceholder($level, $placeholder = ' ')
  86. {
  87. for ($i = 0; $i < $level; $i++) {
  88. $placeholder .= $placeholder;
  89. }
  90. return substr($placeholder, 0, strlen($placeholder) - 1);
  91. }
  92. /**
  93. * 获取文件后戳
  94. * @param $filename
  95. * @return bool|string
  96. */
  97. function getExt($filename)
  98. {
  99. $pos = strrpos($filename, '.');
  100. $ext = substr($filename, $pos);
  101. return $ext;
  102. }

common

html-parser.js

复制代码
  1. /*
  2. * HTML5 Parser By Sam Blowes
  3. *
  4. * Designed for HTML5 documents
  5. *
  6. * Original code by John Resig (ejohn.org)
  7. * http://ejohn.org/blog/pure-javascript-html-parser/
  8. * Original code by Erik Arvidsson, Mozilla Public License
  9. * http://erik.eae.net/simplehtmlparser/simplehtmlparser.js
  10. *
  11. * ----------------------------------------------------------------------------
  12. * License
  13. * ----------------------------------------------------------------------------
  14. *
  15. * This code is triple licensed using Apache Software License 2.0,
  16. * Mozilla Public License or GNU Public License
  17. *
  18. * ////////////////////////////////////////////////////////////////////////////
  19. *
  20. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  21. * use this file except in compliance with the License. You may obtain a copy
  22. * of the License at http://www.apache.org/licenses/LICENSE-2.0
  23. *
  24. * ////////////////////////////////////////////////////////////////////////////
  25. *
  26. * The contents of this file are subject to the Mozilla Public License
  27. * Version 1.1 (the "License"); you may not use this file except in
  28. * compliance with the License. You may obtain a copy of the License at
  29. * http://www.mozilla.org/MPL/
  30. *
  31. * Software distributed under the License is distributed on an "AS IS"
  32. * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
  33. * License for the specific language governing rights and limitations
  34. * under the License.
  35. *
  36. * The Original Code is Simple HTML Parser.
  37. *
  38. * The Initial Developer of the Original Code is Erik Arvidsson.
  39. * Portions created by Erik Arvidssson are Copyright (C) 2004. All Rights
  40. * Reserved.
  41. *
  42. * ////////////////////////////////////////////////////////////////////////////
  43. *
  44. * This program is free software; you can redistribute it and/or
  45. * modify it under the terms of the GNU General Public License
  46. * as published by the Free Software Foundation; either version 2
  47. * of the License, or (at your option) any later version.
  48. *
  49. * This program is distributed in the hope that it will be useful,
  50. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  51. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  52. * GNU General Public License for more details.
  53. *
  54. * You should have received a copy of the GNU General Public License
  55. * along with this program; if not, write to the Free Software
  56. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  57. *
  58. * ----------------------------------------------------------------------------
  59. * Usage
  60. * ----------------------------------------------------------------------------
  61. *
  62. * // Use like so:
  63. * HTMLParser(htmlString, {
  64. * start: function(tag, attrs, unary) {},
  65. * end: function(tag) {},
  66. * chars: function(text) {},
  67. * comment: function(text) {}
  68. * });
  69. *
  70. * // or to get an XML string:
  71. * HTMLtoXML(htmlString);
  72. *
  73. * // or to get an XML DOM Document
  74. * HTMLtoDOM(htmlString);
  75. *
  76. * // or to inject into an existing document/DOM node
  77. * HTMLtoDOM(htmlString, document);
  78. * HTMLtoDOM(htmlString, document.body);
  79. *
  80. */
  81. // Regular Expressions for parsing tags and attributes
  82. var startTag = /^<([-A-Za-z0-9_]+)((?:\s+[a-zA-Z_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/;
  83. var endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/;
  84. var attr = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g; // Empty Elements - HTML 5
  85. 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
  86. // fixed by xxx 将 ins 标签从块级名单中移除
  87. 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
  88. 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
  89. // (and which close themselves)
  90. var closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr'); // Attributes that have their values filled in disabled="disabled"
  91. var fillAttrs = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected'); // Special Elements (can contain anything)
  92. var special = makeMap('script,style');
  93. function HTMLParser(html, handler) {
  94. var index;
  95. var chars;
  96. var match;
  97. var stack = [];
  98. var last = html;
  99. stack.last = function () {
  100. return this[this.length - 1];
  101. };
  102. while (html) {
  103. chars = true; // Make sure we're not in a script or style element
  104. if (!stack.last() || !special[stack.last()]) {
  105. // Comment
  106. if (html.indexOf('<!--') == 0) {
  107. index = html.indexOf('-->');
  108. if (index >= 0) {
  109. if (handler.comment) {
  110. handler.comment(html.substring(4, index));
  111. }
  112. html = html.substring(index + 3);
  113. chars = false;
  114. } // end tag
  115. } else if (html.indexOf('</') == 0) {
  116. match = html.match(endTag);
  117. if (match) {
  118. html = html.substring(match[0].length);
  119. match[0].replace(endTag, parseEndTag);
  120. chars = false;
  121. } // start tag
  122. } else if (html.indexOf('<') == 0) {
  123. match = html.match(startTag);
  124. if (match) {
  125. html = html.substring(match[0].length);
  126. match[0].replace(startTag, parseStartTag);
  127. chars = false;
  128. }
  129. }
  130. if (chars) {
  131. index = html.indexOf('<');
  132. var text = index < 0 ? html : html.substring(0, index);
  133. html = index < 0 ? '' : html.substring(index);
  134. if (handler.chars) {
  135. handler.chars(text);
  136. }
  137. }
  138. } else {
  139. html = html.replace(new RegExp('([\\s\\S]*?)<\/' + stack.last() + '[^>]*>'), function (all, text) {
  140. text = text.replace(/<!--([\s\S]*?)-->|<!\[CDATA\[([\s\S]*?)]]>/g, '$1$2');
  141. if (handler.chars) {
  142. handler.chars(text);
  143. }
  144. return '';
  145. });
  146. parseEndTag('', stack.last());
  147. }
  148. if (html == last) {
  149. throw 'Parse Error: ' + html;
  150. }
  151. last = html;
  152. } // Clean up any remaining tags
  153. parseEndTag();
  154. function parseStartTag(tag, tagName, rest, unary) {
  155. tagName = tagName.toLowerCase();
  156. if (block[tagName]) {
  157. while (stack.last() && inline[stack.last()]) {
  158. parseEndTag('', stack.last());
  159. }
  160. }
  161. if (closeSelf[tagName] && stack.last() == tagName) {
  162. parseEndTag('', tagName);
  163. }
  164. unary = empty[tagName] || !!unary;
  165. if (!unary) {
  166. stack.push(tagName);
  167. }
  168. if (handler.start) {
  169. var attrs = [];
  170. rest.replace(attr, function (match, name) {
  171. var value = arguments[2] ? arguments[2] : arguments[3] ? arguments[3] : arguments[4] ? arguments[4] : fillAttrs[name] ? name : '';
  172. attrs.push({
  173. name: name,
  174. value: value,
  175. escaped: value.replace(/(^|[^\\])"/g, '$1\\\"') // "
  176. });
  177. });
  178. if (handler.start) {
  179. handler.start(tagName, attrs, unary);
  180. }
  181. }
  182. }
  183. function parseEndTag(tag, tagName) {
  184. // If no tag name is provided, clean shop
  185. if (!tagName) {
  186. var pos = 0;
  187. } // Find the closest opened tag of the same type
  188. else {
  189. for (var pos = stack.length - 1; pos >= 0; pos--) {
  190. if (stack[pos] == tagName) {
  191. break;
  192. }
  193. }
  194. }
  195. if (pos >= 0) {
  196. // Close all the open elements, up the stack
  197. for (var i = stack.length - 1; i >= pos; i--) {
  198. if (handler.end) {
  199. handler.end(stack[i]);
  200. }
  201. } // Remove the open elements from the stack
  202. stack.length = pos;
  203. }
  204. }
  205. }
  206. function makeMap(str) {
  207. var obj = {};
  208. var items = str.split(',');
  209. for (var i = 0; i < items.length; i++) {
  210. obj[items[i]] = true;
  211. }
  212. return obj;
  213. }
  214. function removeDOCTYPE(html) {
  215. return html.replace(/<\?xml.*\?>\n/, '').replace(/<!doctype.*>\n/, '').replace(/<!DOCTYPE.*>\n/, '');
  216. }
  217. function parseAttrs(attrs) {
  218. return attrs.reduce(function (pre, attr) {
  219. var value = attr.value;
  220. var name = attr.name;
  221. if (pre[name]) {
  222. pre[name] = pre[name] + " " + value;
  223. } else {
  224. pre[name] = value;
  225. }
  226. return pre;
  227. }, {});
  228. }
  229. function parseHtml(html) {
  230. html = removeDOCTYPE(html);
  231. var stacks = [];
  232. var results = {
  233. node: 'root',
  234. children: []
  235. };
  236. HTMLParser(html, {
  237. start: function start(tag, attrs, unary) {
  238. var node = {
  239. name: tag
  240. };
  241. if (attrs.length !== 0) {
  242. node.attrs = parseAttrs(attrs);
  243. }
  244. if (unary) {
  245. var parent = stacks[0] || results;
  246. if (!parent.children) {
  247. parent.children = [];
  248. }
  249. parent.children.push(node);
  250. } else {
  251. stacks.unshift(node);
  252. }
  253. },
  254. end: function end(tag) {
  255. var node = stacks.shift();
  256. if (node.name !== tag) console.error('invalid state: mismatch end tag');
  257. if (stacks.length === 0) {
  258. results.children.push(node);
  259. } else {
  260. var parent = stacks[0];
  261. if (!parent.children) {
  262. parent.children = [];
  263. }
  264. parent.children.push(node);
  265. }
  266. },
  267. chars: function chars(text) {
  268. var node = {
  269. type: 'text',
  270. text: text
  271. };
  272. if (stacks.length === 0) {
  273. results.children.push(node);
  274. } else {
  275. var parent = stacks[0];
  276. if (!parent.children) {
  277. parent.children = [];
  278. }
  279. parent.children.push(node);
  280. }
  281. },
  282. comment: function comment(text) {
  283. var node = {
  284. node: 'comment',
  285. text: text
  286. };
  287. var parent = stacks[0];
  288. if (!parent.children) {
  289. parent.children = [];
  290. }
  291. parent.children.push(node);
  292. }
  293. });
  294. return results.children;
  295. }
  296. export default parseHtml;

uni-H5Api.js

复制代码
  1. //#ifdef H5
  2. /** clipboard.js v2.0.4**/
  3. !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}
  4. 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)}}
  5. 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}}
  6. 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}
  7. 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)}}
  8. 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)}}
  9. 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()}
  10. 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}
  11. 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()}
  12. return e}},function(t,e){function n(){}
  13. 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)}
  14. 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)}}}
  15. 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}
  16. 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)
  17. return type=='[object Function]'},isObject:function(obj){var type=Object.prototype.toString.call(obj)
  18. return type=='[object Object]'},isString:function(obj){var type=Object.prototype.toString.call(obj)
  19. return type=='[object String]'}}
  20. uni.setClipboardData=function(options){let emptyFun=function(){}
  21. let config={data:null,event:null,success:emptyFun,fail:emptyFun,complete:emptyFun}
  22. if(options&&Types.isObject(options)){config=Object.assign({},config,options)}
  23. if(options&&Types.isString(options)){config=Object.assign({},config,{data:options})}
  24. let data=config.data
  25. let success=config.success||emptyFun
  26. let fail=config.fail||emptyFun
  27. let complete=config.complete||emptyFun
  28. let e=config.event||window.event||{}
  29. let cb=new ClipboardJS('.null',{text:()=>data})
  30. cb.on('success',function(res){
  31. window.__clipboard__=data;
  32. success&&Types.isFunction(success)&&success({data:res.text})
  33. complete&&Types.isFunction(complete)&&complete()
  34. cb.off('error')
  35. cb.off('success')
  36. cb.destroy()})
  37. cb.on('error',function(err){fail&&Types.isFunction(fail)&&fail(err)
  38. complete&&Types.isFunction(complete)&&complete()
  39. cb.off('error')
  40. cb.off('success')
  41. cb.destroy()})
  42. cb.onClick(e)};
  43. uni.getClipboardData=function(options){let emptyFun=function(){}
  44. let config={data:null,event:null,success:emptyFun,fail:emptyFun,complete:emptyFun}
  45. if(options&&Types.isObject(options)){config=Object.assign({},config,options)}
  46. let success=config.success||emptyFun
  47. let fail=config.fail||emptyFun
  48. let complete=config.complete||emptyFun
  49. if(window.__clipboard__!==undefined){success&&Types.isFunction(success)&&success({data:window.__clipboard__})}else{fail&&Types.isFunction(fail)&&fail({data:null})}
  50. complete&&Types.isFunction(complete)&&complete()};
  51. function fileDownLoad(data){var linkElement=document.createElement('a')
  52. linkElement.setAttribute('href',data.blob)
  53. linkElement.setAttribute('downLoad',data.name)
  54. linkElement.click()}
  55. uni.saveImageToPhotosAlbum=uni.saveVideoToPhotosAlbum=function(options){let emptyFun=function(){}
  56. let config={filePath:null,success:emptyFun,fail:emptyFun,complete:emptyFun}
  57. if(options&&Types.isObject(options)){config=Object.assign({},config,options)}
  58. if(options&&Types.isString(options)){config=Object.assign({},config,{filePath:options})}
  59. let filePath=config.filePath
  60. let success=config.success||emptyFun
  61. let fail=config.fail||emptyFun
  62. let complete=config.complete||emptyFun
  63. if(!filePath){fail&&Types.isFunction(fail)&&fail({msg:'no File'})
  64. complete&&Types.isFunction(complete)&&complete()
  65. return}
  66. let names=filePath.split('/')
  67. let name=names[names.length-1]
  68. uni.downloadFile({url:filePath,success:function(res){let tempFilePath=res.tempFilePath
  69. fileDownLoad({name:name,blob:tempFilePath})
  70. success&&Types.isFunction(success)&&success({filePath:filePath})},fail:function(err){fail&&Types.isFunction(fail)&&fail({msg:err})},complete:function(){complete&&Types.isFunction(complete)&&complete()}})}
  71. //#endif

components

area-picker

areaPicker.vue
复制代码
  1. <template>
  2. <view>
  3. <view class="picker-mask" @click="closePicker" catchtouchmove="true" v-show="pickerShow" ></view>
  4. <view class="picker-content" :class="{'pickerShow':pickerShow}" >
  5. <view class="picker-button">
  6. <text @click="closePicker">取消</text>
  7. <text @click="confirm">确定</text>
  8. </view>
  9. <!-- 三列选择-联动 -->
  10. <picker-view class="picker-view" indicator-class="picker-view-selected-three" :value="pickerIndex" @change="pickerViewChangeThree">
  11. <picker-view-column>
  12. <view class="picker-item" v-for="(item, index) in pickerList" :key="index">{{item.label}}</view>
  13. </picker-view-column>
  14. <picker-view-column >
  15. <view class="picker-item" v-for="(item, index) in pickerList[pickerIndex[0]].children" :key="index">{{item.label}}</view>
  16. </picker-view-column>
  17. <picker-view-column>
  18. <view class="picker-item" v-for="(item, index) in pickerList[pickerIndex[0]].children[pickerIndex[1]].children"
  19. :key="index">{{item.label}}</view>
  20. </picker-view-column>
  21. </picker-view>
  22. </view>
  23. </view>
  24. </template>
  25. <script>
  26. // mode所有类型
  27. let pickerModeArray = ["one", "two_linkage", "two_nolinkage", "three"];
  28. export default {
  29. name: "area-picker",
  30. props: {
  31. areaId:{
  32. type: Number,
  33. required: true,
  34. },
  35. // 默认picker选中项索引
  36. defaultIndex: {
  37. type: Array,
  38. required: true,
  39. validator: (value) => {
  40. if (value.length > 0 && value.length <= 3) {
  41. return true;
  42. }
  43. return false;
  44. }
  45. }
  46. },
  47. data() {
  48. return {
  49. pickerIndex: [0,0,0], // picker索引值
  50. pickerShow: false,
  51. region: ['河南省', '郑州市', '中原区'], //开户行地区
  52. provinceKey:-1,//省份id
  53. cityKey:-1,//市id
  54. areaKey:-1,//区域id
  55. selectedData:[],
  56. pickerList:this.$db.get("areaList"),
  57. province:this.$db.get("areaList"),
  58. };
  59. },
  60. created() {
  61. this.init();
  62. },
  63. watch: {
  64. // 匹配选中索引
  65. mode() {
  66. this.pickerIndex = this.defaultIndex;
  67. }
  68. },
  69. methods: {
  70. init(){
  71. this.province = this.$db.get("areaList");
  72. //查找省市区 id
  73. this.getFullPath(this.areaId,this.province);
  74. this.pickerIndex = [this.provinceKey,this.cityKey,this.areaKey];
  75. },
  76. //倒查城市信息
  77. getFullPath(id,data){
  78. for(var i = 0;i<data.length;i++){
  79. if(id == data[i].value){
  80. if(!data[i].children){
  81. this.areaKey = i;
  82. return true;
  83. }else if(data[i].hasOwnProperty("children")){
  84. if(data[i].children[0] && !data[i].children[0].children){
  85. this.cityKey = i;
  86. return true;
  87. }else{
  88. this.provinceKey = i;
  89. return true;
  90. }
  91. }
  92. }else{
  93. if(data[i].hasOwnProperty("children")){
  94. if(data[i].children[0]!==undefined){
  95. if(data[i].children[0].hasOwnProperty("children")){
  96. this.provinceKey = i;
  97. }else{
  98. this.cityKey = i;
  99. }
  100. }
  101. if(typeof data[i].children !='undefined' ){
  102. var res = this.getFullPath(id,data[i].children);
  103. if(res){
  104. return true;
  105. }
  106. }
  107. }
  108. }
  109. }
  110. },
  111. // 三列联动选项变化
  112. pickerViewChangeThree(e) {
  113. let changeValue = e.detail.value;
  114. // 超规处理
  115. if (this.pickerList[changeValue[0]].children.length - 1 < changeValue[1]) {
  116. changeValue[1] = this.pickerList[changeValue[0]].children.length - 1;
  117. }
  118. if (this.pickerList[changeValue[0]].children[changeValue[1]].children.length - 1 < changeValue[2]) {
  119. changeValue[2] = this.pickerList[changeValue[0]].children[changeValue[1]].children.length - 1;
  120. }
  121. this.pickerIndex = changeValue;
  122. },
  123. // 显示组件
  124. showPicker() {
  125. // 隐藏软件盘
  126. uni.hideKeyboard();
  127. this.init();
  128. this.pickerShow = true;
  129. },
  130. // 确定事件——返回选中项的数组索引(也可以自定义其他返回数据,不过返回索引通用性更强)
  131. confirm() {
  132. this.pickerShow = false;
  133. this.selectedData = [
  134. {
  135. id:this.province[this.pickerIndex[0]].value,
  136. name:this.province[this.pickerIndex[0]].label,
  137. },
  138. {
  139. id:this.province[this.pickerIndex[0]].children[this.pickerIndex[1]].value,
  140. name:this.province[this.pickerIndex[0]].children[this.pickerIndex[1]].label,
  141. },
  142. {
  143. id:this.province[this.pickerIndex[0]].children[this.pickerIndex[1]].children[this.pickerIndex[2]].value,
  144. name:this.province[this.pickerIndex[0]].children[this.pickerIndex[1]].children[this.pickerIndex[2]].label,
  145. },
  146. ];
  147. this.$emit("onConfirm", this.selectedData);
  148. },
  149. // 隐藏组件
  150. closePicker() {
  151. this.pickerShow = false;
  152. }
  153. }
  154. }
  155. </script>
  156. <style>
  157. .picker-mask {
  158. position: fixed;
  159. top: 0;
  160. right: 0;
  161. left: 0;
  162. bottom: 0;
  163. z-index: 50;
  164. width: 100%;
  165. height: 100%;
  166. background-color: rgba(0, 0, 0, 0.3);
  167. }
  168. .picker-content {
  169. flex-direction: column;
  170. position: fixed;
  171. bottom: 0;
  172. left: 0;
  173. z-index: 100;
  174. width: 100%;
  175. height: 600upx;
  176. background-color: #FFFFFF;
  177. transform: translateY(100%);
  178. transition: all 200ms ease;
  179. }
  180. .pickerShow {
  181. transform: translateY(0) !important;
  182. }
  183. .picker-content .picker-button {
  184. justify-content: space-between;
  185. height: 80upx;
  186. line-height: 80upx;
  187. }
  188. .picker-button text {
  189. width: 180upx;
  190. font-size: 28upx;
  191. font-weight: 500;
  192. display: block;
  193. text-align: center;
  194. overflow: hidden;
  195. }
  196. .picker-button text:first-child {
  197. color: #A1A1A1;
  198. float: left;
  199. }
  200. .picker-button text:last-child {
  201. color: #FF7159;
  202. float: right;
  203. }
  204. .picker-content .picker-view {
  205. width: 100%;
  206. height: 500upx;
  207. }
  208. .picker-content .picker-view-selected-one,
  209. .picker-content .picker-view-selected-two,
  210. .picker-content .picker-view-selected-three {
  211. height: 68upx;
  212. line-height: 68upx;
  213. border-top: #1AAD19 1upx solid;
  214. border-bottom: #1AAD19 1upx solid;
  215. }
  216. .picker-content .picker-view-selected-one {
  217. position: relative;
  218. left: 25%;
  219. width: 50%;
  220. }
  221. .picker-content .picker-view-selected-two {
  222. position: relative;
  223. left: 15%;
  224. width: 70%;
  225. }
  226. .picker-content .picker-view-selected-three {
  227. position: relative;
  228. left: 5%;
  229. width: 90%;
  230. }
  231. .picker-view .picker-item {
  232. width: 100%;
  233. height: 34px;
  234. line-height: 34px;
  235. font-size: 15px;
  236. font-weight: 600;
  237. display: block;
  238. text-align: center;
  239. }
  240. </style>

cmd-progress

cmd-progress.vue
复制代码
  1. <template>
  2. <view class="cmd-progress cmd-progress-default" :class="setStatusClass">
  3. <block v-if="type == 'circle' || type == 'dashboard'">
  4. <view class="cmd-progress cmd-progress-default" :class="setStatusClass">
  5. <view class="cmd-progress-inner" :style="setCircleStyle">
  6. <!-- 绘制圈 start -->
  7. <!-- #ifdef H5 -->
  8. <svg viewBox="0 0 100 100" class="cmd-progress-circle">
  9. <path :d="setCirclePath" stroke="#f3f3f3" :stroke-linecap="strokeShape" :stroke-width="strokeWidth"
  10. fill-opacity="0" class="cmd-progress-circle-trail" :style="setCircleTrailStyle"></path>
  11. <path :d="setCirclePath" :stroke-linecap="strokeShape" :stroke-width="strokeWidth" fill-opacity="0" class="cmd-progress-circle-path"
  12. :style="setCirclePathStyle"></path>
  13. </svg>
  14. <!-- #endif -->
  15. <!-- #ifndef H5 -->
  16. <text :style="setCircle"></text>
  17. <!-- #endif -->
  18. <!-- 绘制圈 end -->
  19. <!-- 状态文本 start -->
  20. <block v-if="showInfo && !custom">
  21. <text class="cmd-progress-text" :title="setFormat">
  22. <block v-if="status != 'success' && status != 'exception' && setProgress < 100">{{setFormat}}</block>
  23. <!-- #ifdef H5 -->
  24. <svg v-if="status == 'exception'" viewBox="64 64 896 896" data-icon="close" width="1.5em" height="1.5em" fill="currentColor"
  25. aria-hidden="true">
  26. <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>
  27. </svg>
  28. <svg v-if="status == 'success' || setProgress == 100" viewBox="64 64 896 896" data-icon="check" width="1.5em"
  29. height="1.5em" fill="currentColor" aria-hidden="true" :style="{'color': strokeColor ? strokeColor : ''}">
  30. <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>
  31. </svg>
  32. <!-- #endif -->
  33. <!-- #ifndef H5 -->
  34. <text v-if="status == 'exception' || status == 'success' || setProgress == 100" :style="setCircleIcon"></text>
  35. <!-- #endif -->
  36. </text>
  37. </block>
  38. <block v-else>
  39. <view class="cmd-progress-custom">
  40. <slot></slot>
  41. </view>
  42. </block>
  43. <!-- 状态文本 end -->
  44. </view>
  45. </view>
  46. </block>
  47. <block v-if="type == 'line'">
  48. <!-- 进度条 start -->
  49. <view class="cmd-progress-outer">
  50. <view class="cmd-progress-inner" :style="{'border-radius': strokeShape == 'square' ? 0 : '100px'}">
  51. <view class="cmd-progress-bg" :style="setLineStyle"></view>
  52. <view v-if="successPercent" class="cmd-progress-success-bg" :style="setLineSuccessStyle"></view>
  53. </view>
  54. </view>
  55. <!-- 进度条 end -->
  56. <!-- 进度条是否显示信息 start -->
  57. <block v-if="showInfo && !custom">
  58. <text class="cmd-progress-text" :title="setFormat">
  59. <block v-if="status != 'success' && status != 'exception' && setProgress < 100">{{setFormat}}</block>
  60. <!-- #ifdef H5 -->
  61. <svg v-if="status == 'exception'" viewBox="64 64 896 896" data-icon="close-circle" width="1.5em" height="1.5em"
  62. fill="currentColor" aria-hidden="true">
  63. <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>
  64. </svg>
  65. <svg v-if="status == 'success' || setProgress == 100" viewBox="64 64 896 896" data-icon="check-circle" width="1.5em"
  66. height="1.5em" fill="currentColor" aria-hidden="true" :style="{'color': strokeColor ? strokeColor : ''}">
  67. <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>
  68. </svg>
  69. <!-- #endif -->
  70. <!-- #ifndef H5 -->
  71. <text v-if="status == 'exception' || status == 'success' || setProgress == 100" :style="setLineStatusIcon"></text>
  72. <!-- #endif -->
  73. </text>
  74. </block>
  75. <block v-else>
  76. <view class="cmd-progress-custom">
  77. <slot></slot>
  78. </view>
  79. </block>
  80. <!-- 进度条是否显示信息 end -->
  81. </block>
  82. </view>
  83. </template>
  84. <script>
  85. /**
  86. * 进度条组件
  87. * @description 显示一个操作完成的百分比时,为用户显示该操作的当前进度和状态。
  88. * @tutorial https://ext.dcloud.net.cn/plugin?id=259
  89. * @property {String} type 进度类型 - 线型:line、圆圈形:circle、仪表盘:dashboard,默认线型:line
  90. * @property {Number} percent 进度百分比值 - 显示范围0-100 ,可能数比较大就需要自己转成百分比的值
  91. * @property {Number} success-percent 进度已完成的百分几 - 仅支持进度线型:line
  92. * @property {String} status 进度状态 - 涌动:active(仅支持线型:line)、正常:normal、完成:success、失败:exception,默认正常:normal
  93. * @property {Boolean} show-info 进度状态信息 - 是否显示进度数值或状态图标,默认true
  94. * @property {Number} stroke-width 进度线条的宽度 - 建议在条线的宽度范围:1-50,与进度条显示宽度有关,默认8
  95. * @property {String} stroke-color 进度线条的颜色 - 渐变色仅支持线型:line
  96. * @property {String} stroke-shape 进度线条两端的形状 - 圆:round、方块直角:square,默认圆:round
  97. * @property {Number} width 进度画布宽度 - 仅支持圆圈形:circle、仪表盘:dashboard,默认80
  98. * @property {String} gap-degree 进度圆形缺口角度 - 可取值 0 ~ 360,仅支持圆圈形:circle、仪表盘:dashboard
  99. * @property {String} gap-position 进度圆形缺口位置 - 可取值'top', 'bottom', 'left', 'right',仅支持圆圈形:circle、仪表盘:dashboard
  100. * @property {Boolean} custom 自定义文本格式插槽,条line:圈circle 仪表板dashboard
  101. * @example <cmd-progress :percent="30"></cmd-progress>
  102. */
  103. export default {
  104. name: 'cmd-progress',
  105. props: {
  106. /**
  107. * 类型默认:line,可选 line circle dashboard
  108. */
  109. type: {
  110. validator: val => {
  111. return ['line', 'circle', 'dashboard'].includes(val);
  112. },
  113. default: 'line'
  114. },
  115. /**
  116. * 百分比
  117. */
  118. percent: {
  119. type: Number,
  120. default: 0
  121. },
  122. /**
  123. * 已完成的分段百分,仅支持类型line
  124. */
  125. successPercent: {
  126. type: Number,
  127. default: 0
  128. },
  129. /**
  130. * 是否显示进度数值或状态图标
  131. */
  132. showInfo: {
  133. type: Boolean,
  134. default: true
  135. },
  136. /**
  137. * 自定义文本格式插槽,条line:圈circle 仪表板dashboard
  138. */
  139. custom: {
  140. type: Boolean,
  141. default: false
  142. },
  143. /**
  144. * 进度状态,可选:normal success exception (active仅支持类型line
  145. */
  146. status: {
  147. validator: val => {
  148. return ['normal', 'success', 'exception', 'active'].includes(val);
  149. },
  150. default: 'normal'
  151. },
  152. /**
  153. * 条线的宽度1-50,与width有关
  154. */
  155. strokeWidth: {
  156. type: Number,
  157. default: 6
  158. },
  159. /**
  160. * 条线的颜色,渐变色仅支持类型line
  161. */
  162. strokeColor: {
  163. type: String,
  164. default: ''
  165. },
  166. /**
  167. * 条线两端的形状 可选:'round', 'square'
  168. */
  169. strokeShape: {
  170. validator: val => {
  171. return ['round', 'square'].includes(val);
  172. },
  173. default: 'round'
  174. },
  175. /**
  176. * 圆形进度条画布宽度,支持类型circle dashboard
  177. */
  178. width: {
  179. type: Number,
  180. default: 80
  181. },
  182. /**
  183. * 圆形进度条缺口角度,可取值 0 ~ 360,支持类型circle dashboard
  184. */
  185. gapDegree: {
  186. type: Number,
  187. default: 0
  188. },
  189. /**
  190. * 圆形进度条缺口位置,可取值'top', 'bottom', 'left', 'right' ,支持类型circle dashboard
  191. */
  192. gapPosition: {
  193. validator: val => {
  194. return ['top', 'bottom', 'left', 'right'].includes(val);
  195. },
  196. default: 'top'
  197. }
  198. },
  199. computed: {
  200. /**
  201. * 百分比格式
  202. */
  203. setFormat() {
  204. return `${this.setProgress}%`;
  205. },
  206. /**
  207. * 设置显示进度值,禁止小于0和超过100
  208. */
  209. setProgress() {
  210. let percent = this.percent;
  211. if (!this.percent || this.percent < 0) {
  212. percent = 0;
  213. } else if (this.percent >= 100) {
  214. percent = 100;
  215. }
  216. return percent;
  217. },
  218. /**
  219. * 进度圈svg大小
  220. */
  221. setCircleStyle() {
  222. return `width: ${this.width}px;
  223. height: ${this.width}px;
  224. fontSize: ${this.width * 0.15 + 6}px;`
  225. },
  226. /**
  227. * 圈底色
  228. */
  229. setCircleTrailStyle() {
  230. const radius = 50 - this.strokeWidth / 2;
  231. const len = Math.PI * 2 * radius;
  232. const gapDeg = this.gapDegree || (this.type === 'dashboard' && 75);
  233. return `stroke-dasharray: ${len - (gapDeg||0)}px, ${len}px;
  234. stroke-dashoffset: -${(gapDeg||0) / 2}px;
  235. transition: stroke-dashoffset 0.3s ease 0s, stroke-dasharray 0.3s ease 0s, stroke 0.3s;`
  236. },
  237. /**
  238. * 圈进度
  239. */
  240. setCirclePathStyle() {
  241. const radius = 50 - this.strokeWidth / 2;
  242. const len = Math.PI * 2 * radius;
  243. const gapDeg = this.gapDegree || (this.type === 'dashboard' && 75);
  244. return `stroke: ${this.strokeColor};
  245. stroke-dasharray: ${(this.setProgress / 100) * (len - (gapDeg||0))}px, ${len}px;
  246. stroke-dashoffset: -${(gapDeg||0) / 2}px;
  247. transition: stroke-dashoffset 0.3s ease 0s, stroke-dasharray 0.3s ease 0s, stroke 0.3s, stroke-width 0.06s ease 0.3s;`
  248. },
  249. /**
  250. * 绘制圈
  251. */
  252. setCirclePath() {
  253. const radius = 50 - this.strokeWidth / 2;
  254. let beginPositionX = 0;
  255. let beginPositionY = -radius;
  256. let endPositionX = 0;
  257. let endPositionY = -2 * radius;
  258. const gapPos = (this.type === 'dashboard' && 'bottom') || this.gapPosition || 'top';
  259. switch (gapPos) {
  260. case 'left':
  261. beginPositionX = -radius;
  262. beginPositionY = 0;
  263. endPositionX = 2 * radius;
  264. endPositionY = 0;
  265. break;
  266. case 'right':
  267. beginPositionX = radius;
  268. beginPositionY = 0;
  269. endPositionX = -2 * radius;
  270. endPositionY = 0;
  271. break;
  272. case 'bottom':
  273. beginPositionY = radius;
  274. endPositionY = 2 * radius;
  275. break;
  276. default:
  277. break;
  278. }
  279. return `M 50,50 m ${beginPositionX},${beginPositionY} a ${radius},${radius} 0 1 1 ${endPositionX},${-endPositionY} a ${radius},${radius} 0 1 1 ${-endPositionX},${endPositionY}`;
  280. },
  281. // #ifndef H5
  282. /**
  283. * 非H5端,绘制进度圈svg转base URL
  284. */
  285. setCircle() {
  286. const radius = 50 - this.strokeWidth / 2;
  287. const len = Math.PI * 2 * radius;
  288. const gapDeg = this.gapDegree || (this.type === 'dashboard' && 75);
  289. let currentColor = '#108ee9'
  290. // 异常进度
  291. if (this.status == 'exception') {
  292. currentColor = '#f5222d'
  293. }
  294. // 完成进度
  295. if (this.status == 'success' || this.setProgress >= 100 || this.strokeColor) {
  296. currentColor = this.strokeColor || '#fff'
  297. }
  298. let svgToBase =
  299. `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`
  300. return `background-image: url("${svgToBase}");
  301. background-size: cover;
  302. display: inline-block;
  303. ${this.setCircleStyle}`;
  304. },
  305. /**
  306. * 设置进度圈状态图标
  307. */
  308. setCircleIcon() {
  309. let currentColor = '#108ee9'
  310. let svgToBase = ''
  311. // 异常进度
  312. if (this.status == 'exception') {
  313. currentColor = '#f5222d'
  314. svgToBase =
  315. `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`;
  316. }
  317. // 完成进度
  318. if (this.status == 'success' || this.setProgress >= 100) {
  319. currentColor = this.strokeColor || '#fff'
  320. svgToBase =
  321. `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`;
  322. }
  323. return `background-image: url("${svgToBase}");
  324. background-size: cover;
  325. display: inline-block;
  326. width: 1.5em;
  327. height: 1.5em;`;
  328. },
  329. // #endif
  330. /**
  331. * 设置进度条样式
  332. */
  333. setLineStyle() {
  334. return `width: ${this.setProgress}%;
  335. height: ${this.strokeWidth}px;
  336. background: ${this.strokeColor};
  337. border-radius: ${this.strokeShape === 'square' ? 0 : '100px'};`;
  338. },
  339. /**
  340. * 设置已完成分段进度
  341. */
  342. setLineSuccessStyle() {
  343. let successPercent = this.successPercent;
  344. if (!this.successPercent || this.successPercent < 0 || this.setProgress < this.successPercent) {
  345. successPercent = 0;
  346. } else if (this.successPercent >= 100) {
  347. successPercent = 100;
  348. }
  349. return `width: ${successPercent}%;
  350. height: ${this.strokeWidth}px;
  351. border-radius: ${this.strokeShape === 'square' ? 0 : '100px'};`;
  352. },
  353. // #ifndef H5
  354. /**
  355. * 设置进度条状态图标
  356. */
  357. setLineStatusIcon() {
  358. let currentColor = '#108ee9'
  359. let svgToBase = ''
  360. // 异常进度
  361. if (this.status == 'exception') {
  362. currentColor = '#f5222d'
  363. svgToBase =
  364. `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`;
  365. }
  366. // 完成进度
  367. if (this.status == 'success' || this.setProgress >= 100) {
  368. currentColor = this.strokeColor || '#fff'
  369. svgToBase =
  370. `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`;
  371. }
  372. return `background-image: url("${svgToBase}");
  373. background-size: cover;
  374. display: inline-block;
  375. width: 1.5em;
  376. height: 1.5em;`;
  377. },
  378. // #endif
  379. /**
  380. * 状态样式
  381. */
  382. setStatusClass() {
  383. let statusClass = [];
  384. // 异常进度
  385. if (this.status == 'exception') {
  386. statusClass.push('cmd-progress-status-exception')
  387. }
  388. // 完成进度
  389. if (this.status == 'success' || this.setProgress >= 100) {
  390. statusClass.push('cmd-progress-status-success')
  391. }
  392. // 活动进度条
  393. if (this.status == 'active') {
  394. statusClass.push('cmd-progress-status-active')
  395. }
  396. // 是否显示信息
  397. if (this.showInfo) {
  398. statusClass.push('cmd-progress-show-info')
  399. }
  400. // 进度条类型
  401. if (this.type === 'line') {
  402. statusClass.push('cmd-progress-line')
  403. }
  404. // 进度圈、仪表盘类型
  405. if (this.type === 'circle' || this.type === 'dashboard') {
  406. statusClass.push('cmd-progress-circle')
  407. }
  408. statusClass.push('cmd-progress-status-normal')
  409. return statusClass;
  410. }
  411. }
  412. }
  413. </script>
  414. <style>
  415. .cmd-progress {
  416. 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";
  417. font-size: 28upx;
  418. font-variant: tabular-nums;
  419. line-height: 1.5;
  420. color: rgba(0, 0, 0, 0.65);
  421. box-sizing: border-box;
  422. margin: 0;
  423. padding: 0;
  424. list-style: none;
  425. display: inline-block;
  426. }
  427. .cmd-progress-line {
  428. width: 100%;
  429. font-size: 28upx;
  430. position: relative;
  431. display: flex;
  432. flex-direction: row;
  433. justify-content: center;
  434. align-items: center;
  435. }
  436. .cmd-progress-outer {
  437. display: inline-block;
  438. width: 100%;
  439. margin-right: 0;
  440. padding-right: 0;
  441. }
  442. .cmd-progress-show-info .cmd-progress-outer {
  443. flex: 1;
  444. }
  445. .cmd-progress-inner {
  446. display: inline-block;
  447. width: 100%;
  448. background-color: #f5f5f5;
  449. border-radius: 200upx;
  450. vertical-align: middle;
  451. position: relative;
  452. }
  453. .cmd-progress-circle-trail {
  454. stroke: #f5f5f5;
  455. }
  456. .cmd-progress-circle-path {
  457. stroke: #1890ff;
  458. animation: appear 0.3s;
  459. }
  460. .cmd-progress-success-bg,
  461. .cmd-progress-bg {
  462. background-color: #1890ff;
  463. transition: all 0.4s cubic-bezier(0.08, 0.82, 0.17, 1) 0s;
  464. position: relative;
  465. }
  466. .cmd-progress-success-bg {
  467. background-color: #fff;
  468. position: absolute;
  469. top: 0;
  470. left: 0;
  471. }
  472. .cmd-progress-custom {
  473. max-width: 50%;
  474. margin-left: 16upx;
  475. vertical-align: middle;
  476. display: inline-block;
  477. white-space: normal;
  478. word-wrap: break-word;
  479. word-break: break-all;
  480. line-height: 1;
  481. }
  482. .cmd-progress-text {
  483. min-width: 60upx;
  484. text-align: left;
  485. margin-left: 16upx;
  486. vertical-align: middle;
  487. display: inline-block;
  488. white-space: normal;
  489. color: rgba(255, 255, 255, 0.8);
  490. line-height: 1;
  491. }
  492. .cmd-progress-status-active .cmd-progress-bg:before {
  493. content: "";
  494. opacity: 0;
  495. position: absolute;
  496. top: 0;
  497. left: 0;
  498. right: 0;
  499. bottom: 0;
  500. background: #fff;
  501. border-radius: 20upx;
  502. -webkit-animation: cmd-progress-active 2.4s cubic-bezier(0.23, 1, 0.32, 1) infinite;
  503. animation: cmd-progress-active 2.4s cubic-bezier(0.23, 1, 0.32, 1) infinite;
  504. }
  505. .cmd-progress-status-exception .cmd-progress-bg {
  506. background-color: #f5222d;
  507. }
  508. .cmd-progress-status-exception .cmd-progress-text {
  509. color: #f5222d;
  510. }
  511. .cmd-progress-status-exception .cmd-progress-circle-path {
  512. stroke: #f5222d;
  513. }
  514. .cmd-progress-status-success .cmd-progress-bg {
  515. background-color: #fff;
  516. }
  517. .cmd-progress-status-success .cmd-progress-text {
  518. color: #fff;
  519. }
  520. .cmd-progress-status-success .cmd-progress-circle-path {
  521. stroke: #fff;
  522. }
  523. .cmd-progress-circle .cmd-progress-inner {
  524. position: relative;
  525. line-height: 1;
  526. background-color: transparent;
  527. }
  528. .cmd-progress-circle .cmd-progress-custom {
  529. display: block;
  530. position: absolute;
  531. line-height: 1;
  532. top: 50%;
  533. -webkit-transform: translateY(-50%);
  534. transform: translateY(-50%);
  535. left: 25%;
  536. right: 25%;
  537. margin: 0;
  538. overflow: hidden;
  539. white-space: normal;
  540. word-wrap: break-word;
  541. word-break: break-all;
  542. }
  543. .cmd-progress-circle .cmd-progress-text {
  544. display: block;
  545. position: absolute;
  546. width: 100%;
  547. text-align: center;
  548. line-height: 1;
  549. top: 50%;
  550. -webkit-transform: translateY(-50%);
  551. transform: translateY(-50%);
  552. left: 0;
  553. margin: 0;
  554. color: rgba(0, 0, 0, 0.65);
  555. white-space: normal;
  556. }
  557. .cmd-progress-circle .cmd-progress-status-exception .cmd-progress-text {
  558. color: #f5222d;
  559. }
  560. .cmd-progress-circle .cmd-progress-status-success .cmd-progress-text {
  561. color: #fff;
  562. }
  563. @keyframes cmd-progress-active {
  564. 0% {
  565. opacity: 0.1;
  566. width: 0;
  567. }
  568. 20% {
  569. opacity: 0.5;
  570. width: 0;
  571. }
  572. 100% {
  573. opacity: 0;
  574. width: 100%;
  575. }
  576. }
  577. </style>

gaoyia-parse

components
wxParseAudio.vue
复制代码
  1. <template>
  2. <!-- '<audio/>' 组件不再维护,建议使用能力更强的 'uni.createInnerAudioContext' 接口 有时间再改-->
  3. <!--增加audio标签支持-->
  4. <audio
  5. :id="node.attr.id"
  6. :class="node.classStr"
  7. :style="node.styleStr"
  8. :src="node.attr.src"
  9. :loop="node.attr.loop"
  10. :poster="node.attr.poster"
  11. :name="node.attr.name"
  12. :author="node.attr.author"
  13. controls></audio>
  14. </template>
  15. <script>
  16. export default {
  17. name: 'wxParseAudio',
  18. props: {
  19. node: {
  20. type: Object,
  21. default() {
  22. return {};
  23. },
  24. },
  25. },
  26. };
  27. </script>
wxParseImg.vue
复制代码
  1. <template>
  2. <image
  3. :mode="node.attr.mode"
  4. :lazy-load="node.attr.lazyLoad"
  5. :class="node.classStr"
  6. :style="newStyleStr || node.styleStr"
  7. :data-src="node.attr.src"
  8. :src="node.attr.src"
  9. @tap="wxParseImgTap"
  10. @load="wxParseImgLoad"
  11. />
  12. </template>
  13. <script>
  14. export default {
  15. name: 'wxParseImg',
  16. data() {
  17. return {
  18. newStyleStr: '',
  19. preview: true
  20. };
  21. },
  22. inject: ['parseWidth'],
  23. mounted() {},
  24. props: {
  25. node: {
  26. type: Object,
  27. default() {
  28. return {};
  29. }
  30. }
  31. },
  32. methods: {
  33. wxParseImgTap(e) {
  34. if (!this.preview) return;
  35. const { src } = e.currentTarget.dataset;
  36. if (!src) return;
  37. let parent = this.$parent;
  38. while (!parent.preview || typeof parent.preview !== 'function') {
  39. // TODO 遍历获取父节点执行方法
  40. parent = parent.$parent;
  41. }
  42. parent.preview(src, e);
  43. },
  44. // 图片视觉宽高计算函数区
  45. wxParseImgLoad(e) {
  46. const { src } = e.currentTarget.dataset;
  47. if (!src) return;
  48. let { width, height } = e.mp.detail;
  49. const recal = this.wxAutoImageCal(width, height);
  50. const { imageheight, imageWidth } = recal;
  51. const { padding, mode } = this.node.attr;//删除padding
  52. // const { mode } = this.node.attr;
  53. const { styleStr } = this.node;
  54. const imageHeightStyle = mode === 'widthFix' ? '' : `height: ${imageheight}px;`;
  55. this.newStyleStr = `${styleStr}; ${imageHeightStyle}; width: ${imageWidth}px; padding: 0 ${+padding}px;`;//删除padding
  56. // this.newStyleStr = `${styleStr}; ${imageHeightStyle}; width: ${imageWidth}px;`;
  57. },
  58. // 计算视觉优先的图片宽高
  59. wxAutoImageCal(originalWidth, originalHeight) {
  60. // 获取图片的原始长宽
  61. const windowWidth = this.parseWidth.value;
  62. const results = {};
  63. if (originalWidth < 60 || originalHeight < 60) {
  64. const { src } = this.node.attr;
  65. let parent = this.$parent;
  66. while (!parent.preview || typeof parent.preview !== 'function') {
  67. parent = parent.$parent;
  68. }
  69. parent.removeImageUrl(src);
  70. this.preview = false;
  71. }
  72. // 判断按照那种方式进行缩放
  73. if (originalWidth > windowWidth) {
  74. // 在图片width大于手机屏幕width时候
  75. results.imageWidth = windowWidth;
  76. results.imageheight = windowWidth * (originalHeight / originalWidth);
  77. } else {
  78. // 否则展示原来的数据
  79. results.imageWidth = originalWidth;
  80. results.imageheight = originalHeight;
  81. }
  82. return results;
  83. }
  84. }
  85. };
  86. </script>
wxParseTable.vue
复制代码
  1. <template>
  2. <rich-text :nodes="nodes"></rich-text>
  3. </template>
  4. <script>
  5. export default {
  6. name: 'wxParseTable',
  7. props: {
  8. node: {
  9. type: Object,
  10. default() {
  11. return {};
  12. },
  13. },
  14. },
  15. data() {
  16. return {
  17. nodes:[]
  18. };
  19. },
  20. mounted() {
  21. this.nodes=this.loadNode([this.node]);
  22. },
  23. methods: {
  24. loadNode(node) {
  25. let obj = [];
  26. for (let children of node) {
  27. // console.log(children)
  28. if (children.node=='element') {
  29. let t = {
  30. name:children.tag,
  31. attrs: {
  32. class: children.classStr,
  33. // style: children.styleStr,
  34. },
  35. children: children.nodes?this.loadNode(children.nodes):[]
  36. }
  37. obj.push(t)
  38. } else if(children.node=='text'){
  39. obj.push({
  40. type: 'text',
  41. text: children.text
  42. })
  43. }
  44. }
  45. return obj
  46. }
  47. }
  48. };
  49. </script>
wxParseTemplate0.vue
复制代码
  1. <template>
  2. <!--判断是否是标签节点-->
  3. <block v-if="node.node == 'element'">
  4. <!--button类型-->
  5. <button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
  6. <wx-parse-template :node="node" />
  7. </button>
  8. <!--a类型-->
  9. <view v-else-if="node.tag == 'a'" @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  10. <block v-for="(node, index) of node.nodes" :key="index">
  11. <wx-parse-template :node="node" />
  12. </block>
  13. </view>
  14. <!--li类型-->
  15. <view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
  16. <block v-for="(node, index) of node.nodes" :key="index">
  17. <wx-parse-template :node="node" />
  18. </block>
  19. </view>
  20. <!--table类型-->
  21. <wx-parse-table v-else-if="node.tag == 'table'" :node="node" />
  22. <!--br类型-->
  23. <!-- #ifndef H5 -->
  24. <text v-else-if="node.tag == 'br'">\n</text>
  25. <!-- #endif -->
  26. <!-- #ifdef H5 -->
  27. <br v-else-if="node.tag == 'br'">
  28. <!-- #endif -->
  29. <!--video类型-->
  30. <wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
  31. <!--audio类型-->
  32. <wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
  33. <!--img类型-->
  34. <wx-parse-img :node="node" v-else-if="node.tag == 'img'"/>
  35. <!--其他标签-->
  36. <view v-else :class="node.classStr" :style="node.styleStr">
  37. <block v-for="(node, index) of node.nodes" :key="index">
  38. <wx-parse-template :node="node" />
  39. </block>
  40. </view>
  41. </block>
  42. <!--判断是否是文本节点-->
  43. <block v-else-if="node.node == 'text'">{{node.text}}</block>
  44. </template>
  45. <script>
  46. import wxParseTemplate from './wxParseTemplate1';
  47. import wxParseImg from './wxParseImg';
  48. import wxParseVideo from './wxParseVideo';
  49. import wxParseAudio from './wxParseAudio';
  50. import wxParseTable from './wxParseTable';
  51. export default {
  52. name: 'wxParseTemplate0',
  53. props: {
  54. node: {},
  55. },
  56. components: {
  57. wxParseTemplate,
  58. wxParseImg,
  59. wxParseVideo,
  60. wxParseAudio,
  61. wxParseTable
  62. },
  63. methods: {
  64. wxParseATap(e) {
  65. const {
  66. href
  67. } = e.currentTarget.dataset;// TODO currentTarget才有dataset
  68. if (!href) return;
  69. let parent = this.$parent;
  70. while(!parent.preview || typeof parent.preview !== 'function') {// TODO 遍历获取父节点执行方法
  71. parent = parent.$parent;
  72. }
  73. parent.navigate(href, e);
  74. },
  75. }
  76. };
  77. </script>
wxParseTemplate1.vue
复制代码
  1. <template>
  2. <!--判断是否是标签节点-->
  3. <block v-if="node.node == 'element'">
  4. <!--button类型-->
  5. <button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
  6. <wx-parse-template :node="node" />
  7. </button>
  8. <!--a类型-->
  9. <view v-else-if="node.tag == 'a'" @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  10. <block v-for="(node, index) of node.nodes" :key="index">
  11. <wx-parse-template :node="node" />
  12. </block>
  13. </view>
  14. <!--li类型-->
  15. <view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
  16. <block v-for="(node, index) of node.nodes" :key="index">
  17. <wx-parse-template :node="node" />
  18. </block>
  19. </view>
  20. <!--table类型-->
  21. <wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
  22. <!--br类型-->
  23. <!-- #ifndef H5 -->
  24. <text v-else-if="node.tag == 'br'">\n</text>
  25. <!-- #endif -->
  26. <!-- #ifdef H5 -->
  27. <br v-else-if="node.tag == 'br'">
  28. <!-- #endif -->
  29. <!--video类型-->
  30. <wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
  31. <!--audio类型-->
  32. <wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
  33. <!--img类型-->
  34. <wx-parse-img :node="node" v-else-if="node.tag == 'img'"/>
  35. <!--其他标签-->
  36. <view v-else :class="node.classStr" :style="node.styleStr">
  37. <block v-for="(node, index) of node.nodes" :key="index">
  38. <wx-parse-template :node="node" />
  39. </block>
  40. </view>
  41. </block>
  42. <!--判断是否是文本节点-->
  43. <block v-else-if="node.node == 'text'">{{node.text}}</block>
  44. </template>
  45. <script>
  46. import wxParseTemplate from './wxParseTemplate2';
  47. import wxParseImg from './wxParseImg';
  48. import wxParseVideo from './wxParseVideo';
  49. import wxParseAudio from './wxParseAudio';
  50. import wxParseTable from './wxParseTable';
  51. export default {
  52. name: 'wxParseTemplate1',
  53. props: {
  54. node: {},
  55. },
  56. components: {
  57. wxParseTemplate,
  58. wxParseImg,
  59. wxParseVideo,
  60. wxParseAudio,
  61. wxParseTable
  62. },
  63. methods: {
  64. wxParseATap(e) {
  65. const {
  66. href
  67. } = e.currentTarget.dataset;
  68. if (!href) return;
  69. let parent = this.$parent;
  70. while(!parent.preview || typeof parent.preview !== 'function') {
  71. parent = parent.$parent;
  72. }
  73. parent.navigate(href, e);
  74. },
  75. },
  76. };
  77. </script>
wxParseTemplate10.vue
复制代码
  1. <template>
  2. <!--判断是否是标签节点-->
  3. <block v-if="node.node == 'element'">
  4. <!--button类型-->
  5. <button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
  6. <wx-parse-template :node="node" />
  7. </button>
  8. <!--a类型-->
  9. <view v-else-if="node.tag == 'a'" @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  10. <block v-for="(node, index) of node.nodes" :key="index">
  11. <wx-parse-template :node="node" />
  12. </block>
  13. </view>
  14. <!--li类型-->
  15. <view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
  16. <block v-for="(node, index) of node.nodes" :key="index">
  17. <wx-parse-template :node="node" />
  18. </block>
  19. </view>
  20. <!--table类型-->
  21. <wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
  22. <!--br类型-->
  23. <!-- #ifndef H5 -->
  24. <text v-else-if="node.tag == 'br'">\n</text>
  25. <!-- #endif -->
  26. <!-- #ifdef H5 -->
  27. <br v-else-if="node.tag == 'br'">
  28. <!-- #endif -->
  29. <!--video类型-->
  30. <wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
  31. <!--audio类型-->
  32. <wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
  33. <!--img类型-->
  34. <wx-parse-img :node="node" v-else-if="node.tag == 'img'"/>
  35. <!--其他标签-->
  36. <view v-else :class="node.classStr" :style="node.styleStr">
  37. <block v-for="(node, index) of node.nodes" :key="index">
  38. <wx-parse-template :node="node" />
  39. </block>
  40. </view>
  41. </block>
  42. <!--判断是否是文本节点-->
  43. <block v-else-if="node.node == 'text'">{{node.text}}</block>
  44. </template>
  45. <script>
  46. import wxParseTemplate from './wxParseTemplate11';
  47. import wxParseImg from './wxParseImg';
  48. import wxParseVideo from './wxParseVideo';
  49. import wxParseAudio from './wxParseAudio';
  50. import wxParseTable from './wxParseTable';
  51. export default {
  52. name: 'wxParseTemplate10',
  53. props: {
  54. node: {},
  55. },
  56. components: {
  57. wxParseTemplate,
  58. wxParseImg,
  59. wxParseVideo,
  60. wxParseAudio,
  61. wxParseTable
  62. },
  63. methods: {
  64. wxParseATap(e) {
  65. const {
  66. href
  67. } = e.currentTarget.dataset;
  68. if (!href) return;
  69. let parent = this.$parent;
  70. while(!parent.preview || typeof parent.preview !== 'function') {
  71. parent = parent.$parent;
  72. }
  73. parent.navigate(href, e);
  74. },
  75. },
  76. };
  77. </script>
wxParseTemplate11.vue
复制代码
  1. <template>
  2. <!--判断是否是标签节点-->
  3. <block v-if="node.node == 'element'">
  4. <!--button类型-->
  5. <button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
  6. </button>
  7. <!--a类型-->
  8. <view v-else-if="node.tag == 'a'" @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  9. <block v-for="(node, index) of node.nodes" :key="index">
  10. </block>
  11. </view>
  12. <!--li类型-->
  13. <view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
  14. <block v-for="(node, index) of node.nodes" :key="index">
  15. </block>
  16. </view>
  17. <!--table类型-->
  18. <wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
  19. <!--br类型-->
  20. <!-- #ifndef H5 -->
  21. <text v-else-if="node.tag == 'br'">\n</text>
  22. <!-- #endif -->
  23. <!-- #ifdef H5 -->
  24. <br v-else-if="node.tag == 'br'">
  25. <!-- #endif -->
  26. <!--video类型-->
  27. <wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
  28. <!--audio类型-->
  29. <wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
  30. <!--img类型-->
  31. <wx-parse-img :node="node" v-else-if="node.tag == 'img'"/>
  32. <!--其他标签-->
  33. <view v-else :class="node.classStr" :style="node.styleStr">
  34. <block v-for="(node, index) of node.nodes" :key="index">
  35. </block>
  36. </view>
  37. </block>
  38. <!--判断是否是文本节点-->
  39. <block v-else-if="node.node == 'text'">{{node.text}}</block>
  40. </template>
  41. <script>
  42. import wxParseImg from './wxParseImg';
  43. import wxParseVideo from './wxParseVideo';
  44. import wxParseAudio from './wxParseAudio';
  45. import wxParseTable from './wxParseTable';
  46. export default {
  47. name: 'wxParseTemplate11',
  48. props: {
  49. node: {},
  50. },
  51. components: {
  52. wxParseImg,
  53. wxParseVideo,
  54. wxParseAudio,
  55. wxParseTable
  56. },
  57. methods: {
  58. wxParseATap(e) {
  59. const {
  60. href
  61. } = e.currentTarget.dataset;
  62. if (!href) return;
  63. let parent = this.$parent;
  64. while(!parent.preview || typeof parent.preview !== 'function') {
  65. parent = parent.$parent;
  66. }
  67. parent.navigate(href, e);
  68. },
  69. },
  70. };
  71. </script>
wxParseTemplate2.vue
复制代码
  1. <template>
  2. <!--判断是否是标签节点-->
  3. <block v-if="node.node == 'element'">
  4. <!--button类型-->
  5. <button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
  6. <wx-parse-template :node="node" />
  7. </button>
  8. <!--a类型-->
  9. <view v-else-if="node.tag == 'a'" @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  10. <block v-for="(node, index) of node.nodes" :key="index">
  11. <wx-parse-template :node="node" />
  12. </block>
  13. </view>
  14. <!--li类型-->
  15. <view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
  16. <block v-for="(node, index) of node.nodes" :key="index">
  17. <wx-parse-template :node="node" />
  18. </block>
  19. </view>
  20. <!--table类型-->
  21. <wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
  22. <!--br类型-->
  23. <!-- #ifndef H5 -->
  24. <text v-else-if="node.tag == 'br'">\n</text>
  25. <!-- #endif -->
  26. <!-- #ifdef H5 -->
  27. <br v-else-if="node.tag == 'br'">
  28. <!-- #endif -->
  29. <!--video类型-->
  30. <wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
  31. <!--audio类型-->
  32. <wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
  33. <!--img类型-->
  34. <wx-parse-img :node="node" v-else-if="node.tag == 'img'"/>
  35. <!--其他标签-->
  36. <view v-else :class="node.classStr" :style="node.styleStr">
  37. <block v-for="(node, index) of node.nodes" :key="index">
  38. <wx-parse-template :node="node" />
  39. </block>
  40. </view>
  41. </block>
  42. <!--判断是否是文本节点-->
  43. <block v-else-if="node.node == 'text'">{{node.text}}</block>
  44. </template>
  45. <script>
  46. import wxParseTemplate from './wxParseTemplate3';
  47. import wxParseImg from './wxParseImg';
  48. import wxParseVideo from './wxParseVideo';
  49. import wxParseAudio from './wxParseAudio';
  50. import wxParseTable from './wxParseTable';
  51. export default {
  52. name: 'wxParseTemplate2',
  53. props: {
  54. node: {},
  55. },
  56. components: {
  57. wxParseTemplate,
  58. wxParseImg,
  59. wxParseVideo,
  60. wxParseAudio,
  61. wxParseTable
  62. },
  63. methods: {
  64. wxParseATap(e) {
  65. const {
  66. href
  67. } = e.currentTarget.dataset;
  68. if (!href) return;
  69. let parent = this.$parent;
  70. while(!parent.preview || typeof parent.preview !== 'function') {
  71. parent = parent.$parent;
  72. }
  73. parent.navigate(href, e);
  74. },
  75. },
  76. };
  77. </script>
wxParseTemplate3.vue
复制代码
  1. <template>
  2. <!--判断是否是标签节点-->
  3. <block v-if="node.node == 'element'">
  4. <!--button类型-->
  5. <button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
  6. <wx-parse-template :node="node" />
  7. </button>
  8. <!--a类型-->
  9. <view v-else-if="node.tag == 'a'" @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  10. <block v-for="(node, index) of node.nodes" :key="index">
  11. <wx-parse-template :node="node" />
  12. </block>
  13. </view>
  14. <!--li类型-->
  15. <view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
  16. <block v-for="(node, index) of node.nodes" :key="index">
  17. <wx-parse-template :node="node" />
  18. </block>
  19. </view>
  20. <!--table类型-->
  21. <wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
  22. <!--br类型-->
  23. <!-- #ifndef H5 -->
  24. <text v-else-if="node.tag == 'br'">\n</text>
  25. <!-- #endif -->
  26. <!-- #ifdef H5 -->
  27. <br v-else-if="node.tag == 'br'">
  28. <!-- #endif -->
  29. <!--video类型-->
  30. <wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
  31. <!--audio类型-->
  32. <wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
  33. <!--img类型-->
  34. <wx-parse-img :node="node" v-else-if="node.tag == 'img'"/>
  35. <!--其他标签-->
  36. <view v-else :class="node.classStr" :style="node.styleStr">
  37. <block v-for="(node, index) of node.nodes" :key="index">
  38. <wx-parse-template :node="node" />
  39. </block>
  40. </view>
  41. </block>
  42. <!--判断是否是文本节点-->
  43. <block v-else-if="node.node == 'text'">{{node.text}}</block>
  44. </template>
  45. <script>
  46. import wxParseTemplate from './wxParseTemplate4';
  47. import wxParseImg from './wxParseImg';
  48. import wxParseVideo from './wxParseVideo';
  49. import wxParseAudio from './wxParseAudio';
  50. import wxParseTable from './wxParseTable';
  51. export default {
  52. name: 'wxParseTemplate3',
  53. props: {
  54. node: {},
  55. },
  56. components: {
  57. wxParseTemplate,
  58. wxParseImg,
  59. wxParseVideo,
  60. wxParseAudio,
  61. wxParseTable
  62. },
  63. methods: {
  64. wxParseATap(e) {
  65. const {
  66. href
  67. } = e.currentTarget.dataset;
  68. if (!href) return;
  69. let parent = this.$parent;
  70. while(!parent.preview || typeof parent.preview !== 'function') {
  71. parent = parent.$parent;
  72. }
  73. parent.navigate(href, e);
  74. },
  75. },
  76. };
  77. </script>
wxParseTemplate4.vue
复制代码
  1. <template>
  2. <!--判断是否是标签节点-->
  3. <block v-if="node.node == 'element'">
  4. <!--button类型-->
  5. <button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
  6. <wx-parse-template :node="node" />
  7. </button>
  8. <!--a类型-->
  9. <view v-else-if="node.tag == 'a'" @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  10. <block v-for="(node, index) of node.nodes" :key="index">
  11. <wx-parse-template :node="node" />
  12. </block>
  13. </view>
  14. <!--li类型-->
  15. <view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
  16. <block v-for="(node, index) of node.nodes" :key="index">
  17. <wx-parse-template :node="node" />
  18. </block>
  19. </view>
  20. <!--table类型-->
  21. <wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
  22. <!--br类型-->
  23. <!-- #ifndef H5 -->
  24. <text v-else-if="node.tag == 'br'">\n</text>
  25. <!-- #endif -->
  26. <!-- #ifdef H5 -->
  27. <br v-else-if="node.tag == 'br'">
  28. <!-- #endif -->
  29. <!--video类型-->
  30. <wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
  31. <!--audio类型-->
  32. <wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
  33. <!--img类型-->
  34. <wx-parse-img :node="node" v-else-if="node.tag == 'img'"/>
  35. <!--其他标签-->
  36. <view v-else :class="node.classStr" :style="node.styleStr">
  37. <block v-for="(node, index) of node.nodes" :key="index">
  38. <wx-parse-template :node="node" />
  39. </block>
  40. </view>
  41. </block>
  42. <!--判断是否是文本节点-->
  43. <block v-else-if="node.node == 'text'">{{node.text}}</block>
  44. </template>
  45. <script>
  46. import wxParseTemplate from './wxParseTemplate5';
  47. import wxParseImg from './wxParseImg';
  48. import wxParseVideo from './wxParseVideo';
  49. import wxParseAudio from './wxParseAudio';
  50. import wxParseTable from './wxParseTable';
  51. export default {
  52. name: 'wxParseTemplate4',
  53. props: {
  54. node: {},
  55. },
  56. components: {
  57. wxParseTemplate,
  58. wxParseImg,
  59. wxParseVideo,
  60. wxParseAudio,
  61. wxParseTable
  62. },
  63. methods: {
  64. wxParseATap(e) {
  65. const {
  66. href
  67. } = e.currentTarget.dataset;
  68. if (!href) return;
  69. let parent = this.$parent;
  70. while(!parent.preview || typeof parent.preview !== 'function') {
  71. parent = parent.$parent;
  72. }
  73. parent.navigate(href, e);
  74. },
  75. },
  76. };
  77. </script>
wxParseTemplate5.vue
复制代码
  1. <template>
  2. <!--判断是否是标签节点-->
  3. <block v-if="node.node == 'element'">
  4. <!--button类型-->
  5. <button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
  6. <wx-parse-template :node="node" />
  7. </button>
  8. <!--a类型-->
  9. <view v-else-if="node.tag == 'a'" @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  10. <block v-for="(node, index) of node.nodes" :key="index">
  11. <wx-parse-template :node="node" />
  12. </block>
  13. </view>
  14. <!--li类型-->
  15. <view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
  16. <block v-for="(node, index) of node.nodes" :key="index">
  17. <wx-parse-template :node="node" />
  18. </block>
  19. </view>
  20. <!--table类型-->
  21. <wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
  22. <!--br类型-->
  23. <!-- #ifndef H5 -->
  24. <text v-else-if="node.tag == 'br'">\n</text>
  25. <!-- #endif -->
  26. <!-- #ifdef H5 -->
  27. <br v-else-if="node.tag == 'br'">
  28. <!-- #endif -->
  29. <!--video类型-->
  30. <wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
  31. <!--audio类型-->
  32. <wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
  33. <!--img类型-->
  34. <wx-parse-img :node="node" v-else-if="node.tag == 'img'"/>
  35. <!--其他标签-->
  36. <view v-else :class="node.classStr" :style="node.styleStr">
  37. <block v-for="(node, index) of node.nodes" :key="index">
  38. <wx-parse-template :node="node" />
  39. </block>
  40. </view>
  41. </block>
  42. <!--判断是否是文本节点-->
  43. <block v-else-if="node.node == 'text'">{{node.text}}</block>
  44. </template>
  45. <script>
  46. import wxParseTemplate from './wxParseTemplate6';
  47. import wxParseImg from './wxParseImg';
  48. import wxParseVideo from './wxParseVideo';
  49. import wxParseAudio from './wxParseAudio';
  50. import wxParseTable from './wxParseTable';
  51. export default {
  52. name: 'wxParseTemplate5',
  53. props: {
  54. node: {},
  55. },
  56. components: {
  57. wxParseTemplate,
  58. wxParseImg,
  59. wxParseVideo,
  60. wxParseAudio,
  61. wxParseTable
  62. },
  63. methods: {
  64. wxParseATap(e) {
  65. const {
  66. href
  67. } = e.currentTarget.dataset;
  68. if (!href) return;
  69. let parent = this.$parent;
  70. while(!parent.preview || typeof parent.preview !== 'function') {
  71. parent = parent.$parent;
  72. }
  73. parent.navigate(href, e);
  74. },
  75. },
  76. };
  77. </script>
wxParseTemplate6.vue
复制代码
  1. <template>
  2. <!--判断是否是标签节点-->
  3. <block v-if="node.node == 'element'">
  4. <!--button类型-->
  5. <button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
  6. <wx-parse-template :node="node" />
  7. </button>
  8. <!--a类型-->
  9. <view v-else-if="node.tag == 'a'" @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  10. <block v-for="(node, index) of node.nodes" :key="index">
  11. <wx-parse-template :node="node" />
  12. </block>
  13. </view>
  14. <!--li类型-->
  15. <view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
  16. <block v-for="(node, index) of node.nodes" :key="index">
  17. <wx-parse-template :node="node" />
  18. </block>
  19. </view>
  20. <!--table类型-->
  21. <wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
  22. <!--br类型-->
  23. <!-- #ifndef H5 -->
  24. <text v-else-if="node.tag == 'br'">\n</text>
  25. <!-- #endif -->
  26. <!-- #ifdef H5 -->
  27. <br v-else-if="node.tag == 'br'">
  28. <!-- #endif -->
  29. <!--video类型-->
  30. <wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
  31. <!--audio类型-->
  32. <wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
  33. <!--img类型-->
  34. <wx-parse-img :node="node" v-else-if="node.tag == 'img'"/>
  35. <!--其他标签-->
  36. <view v-else :class="node.classStr" :style="node.styleStr">
  37. <block v-for="(node, index) of node.nodes" :key="index">
  38. <wx-parse-template :node="node" />
  39. </block>
  40. </view>
  41. </block>
  42. <!--判断是否是文本节点-->
  43. <block v-else-if="node.node == 'text'">{{node.text}}</block>
  44. </template>
  45. <script>
  46. import wxParseTemplate from './wxParseTemplate7';
  47. import wxParseImg from './wxParseImg';
  48. import wxParseVideo from './wxParseVideo';
  49. import wxParseAudio from './wxParseAudio';
  50. import wxParseTable from './wxParseTable';
  51. export default {
  52. name: 'wxParseTemplate6',
  53. props: {
  54. node: {},
  55. },
  56. components: {
  57. wxParseTemplate,
  58. wxParseImg,
  59. wxParseVideo,
  60. wxParseAudio,
  61. wxParseTable
  62. },
  63. methods: {
  64. wxParseATap(e) {
  65. const {
  66. href
  67. } = e.currentTarget.dataset;
  68. if (!href) return;
  69. let parent = this.$parent;
  70. while(!parent.preview || typeof parent.preview !== 'function') {
  71. parent = parent.$parent;
  72. }
  73. parent.navigate(href, e);
  74. },
  75. },
  76. };
  77. </script>
wxParseTemplate7.vue
复制代码
  1. <template>
  2. <!--判断是否是标签节点-->
  3. <block v-if="node.node == 'element'">
  4. <!--button类型-->
  5. <button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
  6. <wx-parse-template :node="node" />
  7. </button>
  8. <!--a类型-->
  9. <view v-else-if="node.tag == 'a'" @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  10. <block v-for="(node, index) of node.nodes" :key="index">
  11. <wx-parse-template :node="node" />
  12. </block>
  13. </view>
  14. <!--li类型-->
  15. <view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
  16. <block v-for="(node, index) of node.nodes" :key="index">
  17. <wx-parse-template :node="node" />
  18. </block>
  19. </view>
  20. <!--table类型-->
  21. <wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
  22. <!--br类型-->
  23. <!-- #ifndef H5 -->
  24. <text v-else-if="node.tag == 'br'">\n</text>
  25. <!-- #endif -->
  26. <!-- #ifdef H5 -->
  27. <br v-else-if="node.tag == 'br'">
  28. <!-- #endif -->
  29. <!--video类型-->
  30. <wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
  31. <!--audio类型-->
  32. <wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
  33. <!--img类型-->
  34. <wx-parse-img :node="node" v-else-if="node.tag == 'img'"/>
  35. <!--其他标签-->
  36. <view v-else :class="node.classStr" :style="node.styleStr">
  37. <block v-for="(node, index) of node.nodes" :key="index">
  38. <wx-parse-template :node="node" />
  39. </block>
  40. </view>
  41. </block>
  42. <!--判断是否是文本节点-->
  43. <block v-else-if="node.node == 'text'">{{node.text}}</block>
  44. </template>
  45. <script>
  46. import wxParseTemplate from './wxParseTemplate8';
  47. import wxParseImg from './wxParseImg';
  48. import wxParseVideo from './wxParseVideo';
  49. import wxParseAudio from './wxParseAudio';
  50. import wxParseTable from './wxParseTable';
  51. export default {
  52. name: 'wxParseTemplate7',
  53. props: {
  54. node: {},
  55. },
  56. components: {
  57. wxParseTemplate,
  58. wxParseImg,
  59. wxParseVideo,
  60. wxParseAudio,
  61. wxParseTable
  62. },
  63. methods: {
  64. wxParseATap(e) {
  65. const {
  66. href
  67. } = e.currentTarget.dataset;
  68. if (!href) return;
  69. let parent = this.$parent;
  70. while(!parent.preview || typeof parent.preview !== 'function') {
  71. parent = parent.$parent;
  72. }
  73. parent.navigate(href, e);
  74. },
  75. },
  76. };
  77. </script>
wxParseTemplate8.vue
复制代码
  1. <template>
  2. <!--判断是否是标签节点-->
  3. <block v-if="node.node == 'element'">
  4. <!--button类型-->
  5. <button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
  6. <wx-parse-template :node="node" />
  7. </button>
  8. <!--a类型-->
  9. <view v-else-if="node.tag == 'a'" @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  10. <block v-for="(node, index) of node.nodes" :key="index">
  11. <wx-parse-template :node="node" />
  12. </block>
  13. </view>
  14. <!--li类型-->
  15. <view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
  16. <block v-for="(node, index) of node.nodes" :key="index">
  17. <wx-parse-template :node="node" />
  18. </block>
  19. </view>
  20. <!--table类型-->
  21. <wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
  22. <!--br类型-->
  23. <!-- #ifndef H5 -->
  24. <text v-else-if="node.tag == 'br'">\n</text>
  25. <!-- #endif -->
  26. <!-- #ifdef H5 -->
  27. <br v-else-if="node.tag == 'br'">
  28. <!-- #endif -->
  29. <!--video类型-->
  30. <wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
  31. <!--audio类型-->
  32. <wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
  33. <!--img类型-->
  34. <wx-parse-img :node="node" v-else-if="node.tag == 'img'"/>
  35. <!--其他标签-->
  36. <view v-else :class="node.classStr" :style="node.styleStr">
  37. <block v-for="(node, index) of node.nodes" :key="index">
  38. <wx-parse-template :node="node" />
  39. </block>
  40. </view>
  41. </block>
  42. <!--判断是否是文本节点-->
  43. <block v-else-if="node.node == 'text'">{{node.text}}</block>
  44. </template>
  45. <script>
  46. import wxParseTemplate from './wxParseTemplate9';
  47. import wxParseImg from './wxParseImg';
  48. import wxParseVideo from './wxParseVideo';
  49. import wxParseAudio from './wxParseAudio';
  50. import wxParseTable from './wxParseTable';
  51. export default {
  52. name: 'wxParseTemplate8',
  53. props: {
  54. node: {},
  55. },
  56. components: {
  57. wxParseTemplate,
  58. wxParseImg,
  59. wxParseVideo,
  60. wxParseAudio,
  61. wxParseTable
  62. },
  63. methods: {
  64. wxParseATap(e) {
  65. const {
  66. href
  67. } = e.currentTarget.dataset;
  68. if (!href) return;
  69. let parent = this.$parent;
  70. while(!parent.preview || typeof parent.preview !== 'function') {
  71. parent = parent.$parent;
  72. }
  73. parent.navigate(href, e);
  74. },
  75. },
  76. };
  77. </script>
wxParseTemplate9.vue
复制代码
  1. <template>
  2. <!--判断是否是标签节点-->
  3. <block v-if="node.node == 'element'">
  4. <!--button类型-->
  5. <button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
  6. <wx-parse-template :node="node" />
  7. </button>
  8. <!--a类型-->
  9. <view v-else-if="node.tag == 'a'" @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  10. <block v-for="(node, index) of node.nodes" :key="index">
  11. <wx-parse-template :node="node" />
  12. </block>
  13. </view>
  14. <!--li类型-->
  15. <view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
  16. <block v-for="(node, index) of node.nodes" :key="index">
  17. <wx-parse-template :node="node" />
  18. </block>
  19. </view>
  20. <!--table类型-->
  21. <wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
  22. <!--br类型-->
  23. <!-- #ifndef H5 -->
  24. <text v-else-if="node.tag == 'br'">\n</text>
  25. <!-- #endif -->
  26. <!-- #ifdef H5 -->
  27. <br v-else-if="node.tag == 'br'">
  28. <!-- #endif -->
  29. <!--video类型-->
  30. <wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
  31. <!--audio类型-->
  32. <wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
  33. <!--img类型-->
  34. <wx-parse-img :node="node" v-else-if="node.tag == 'img'"/>
  35. <!--其他标签-->
  36. <view v-else :class="node.classStr" :style="node.styleStr">
  37. <block v-for="(node, index) of node.nodes" :key="index">
  38. <wx-parse-template :node="node" />
  39. </block>
  40. </view>
  41. </block>
  42. <!--判断是否是文本节点-->
  43. <block v-else-if="node.node == 'text'">{{node.text}}</block>
  44. </template>
  45. <script>
  46. import wxParseTemplate from './wxParseTemplate10';
  47. import wxParseImg from './wxParseImg';
  48. import wxParseVideo from './wxParseVideo';
  49. import wxParseAudio from './wxParseAudio';
  50. import wxParseTable from './wxParseTable';
  51. export default {
  52. name: 'wxParseTemplate9',
  53. props: {
  54. node: {},
  55. },
  56. components: {
  57. wxParseTemplate,
  58. wxParseImg,
  59. wxParseVideo,
  60. wxParseAudio,
  61. wxParseTable
  62. },
  63. methods: {
  64. wxParseATap(e) {
  65. const {
  66. href
  67. } = e.currentTarget.dataset;
  68. if (!href) return;
  69. let parent = this.$parent;
  70. while(!parent.preview || typeof parent.preview !== 'function') {
  71. parent = parent.$parent;
  72. }
  73. parent.navigate(href, e);
  74. },
  75. },
  76. };
  77. </script>
wxParseVideo.vue
复制代码
  1. <template>
  2. <!--增加video标签支持,并循环添加-->
  3. <view :class="node.classStr" :style="node.styleStr">
  4. <video :class="node.classStr" :style="node.styleStr" class="video-video" :src="node.attr.src" :poster="node.attr.poster"></video>
  5. </view>
  6. </template>
  7. <script>
  8. export default {
  9. name: 'wxParseVideo',
  10. props: {
  11. node: {},
  12. },
  13. };
  14. </script>
libs
html2json.js
复制代码
  1. /**
  2. * html2Json 改造来自: https://github.com/Jxck/html2json
  3. *
  4. *
  5. * author: Di (微信小程序开发工程师)
  6. * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
  7. * 垂直微信小程序开发交流社区
  8. *
  9. * github地址: https://github.com/icindy/wxParse
  10. *
  11. * for: 微信小程序富文本解析
  12. * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
  13. */
  14. import wxDiscode from './wxDiscode';
  15. import HTMLParser from './htmlparser';
  16. function makeMap(str) {
  17. const obj = {};
  18. const items = str.split(',');
  19. for (let i = 0; i < items.length; i += 1) obj[items[i]] = true;
  20. return obj;
  21. }
  22. // Block Elements - HTML 5
  23. 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');
  24. // Inline Elements - HTML 5
  25. 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');
  26. // Elements that you can, intentionally, leave open
  27. // (and which close themselves)
  28. const closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr');
  29. function removeDOCTYPE(html) {
  30. const isDocument = /<body.*>([^]*)<\/body>/.test(html);
  31. return isDocument ? RegExp.$1 : html;
  32. }
  33. function trimHtml(html) {
  34. return html
  35. .replace(/<!--.*?-->/gi, '')
  36. .replace(/\/\*.*?\*\//gi, '')
  37. .replace(/[ ]+</gi, '<')
  38. .replace(/<script[^]*<\/script>/gi, '')
  39. .replace(/<style[^]*<\/style>/gi, '');
  40. }
  41. function getScreenInfo() {
  42. const screen = {};
  43. wx.getSystemInfo({
  44. success: (res) => {
  45. screen.width = res.windowWidth;
  46. screen.height = res.windowHeight;
  47. },
  48. });
  49. return screen;
  50. }
  51. function html2json(html, customHandler, imageProp, host) {
  52. // 处理字符串
  53. html = removeDOCTYPE(html);
  54. html = trimHtml(html);
  55. html = wxDiscode.strDiscode(html);
  56. // 生成node节点
  57. const bufArray = [];
  58. const results = {
  59. nodes: [],
  60. imageUrls: [],
  61. };
  62. const screen = getScreenInfo();
  63. function Node(tag) {
  64. this.node = 'element';
  65. this.tag = tag;
  66. this.$screen = screen;
  67. }
  68. HTMLParser(html, {
  69. start(tag, attrs, unary) {
  70. // node for this element
  71. const node = new Node(tag);
  72. if (bufArray.length !== 0) {
  73. const parent = bufArray[0];
  74. if (parent.nodes === undefined) {
  75. parent.nodes = [];
  76. }
  77. }
  78. if (block[tag]) {
  79. node.tagType = 'block';
  80. } else if (inline[tag]) {
  81. node.tagType = 'inline';
  82. } else if (closeSelf[tag]) {
  83. node.tagType = 'closeSelf';
  84. }
  85. node.attr = attrs.reduce((pre, attr) => {
  86. const { name } = attr;
  87. let { value } = attr;
  88. if (name === 'class') {
  89. node.classStr = value;
  90. }
  91. // has multi attibutes
  92. // make it array of attribute
  93. if (name === 'style') {
  94. node.styleStr = value;
  95. }
  96. if (value.match(/ /)) {
  97. value = value.split(' ');
  98. }
  99. // if attr already exists
  100. // merge it
  101. if (pre[name]) {
  102. if (Array.isArray(pre[name])) {
  103. // already array, push to last
  104. pre[name].push(value);
  105. } else {
  106. // single value, make it array
  107. pre[name] = [pre[name], value];
  108. }
  109. } else {
  110. // not exist, put it
  111. pre[name] = value;
  112. }
  113. return pre;
  114. }, {});
  115. // 优化样式相关属性
  116. if (node.classStr) {
  117. node.classStr += ` ${node.tag}`;
  118. } else {
  119. node.classStr = node.tag;
  120. }
  121. if (node.tagType === 'inline') {
  122. node.classStr += ' inline';
  123. }
  124. // 对img添加额外数据
  125. if (node.tag === 'img') {
  126. let imgUrl = node.attr.src;
  127. imgUrl = wxDiscode.urlToHttpUrl(imgUrl, imageProp.domain);
  128. Object.assign(node.attr, imageProp, {
  129. src: imgUrl || '',
  130. });
  131. if (imgUrl) {
  132. results.imageUrls.push(imgUrl);
  133. }
  134. }
  135. // 处理a标签属性
  136. if (node.tag === 'a') {
  137. node.attr.href = node.attr.href || '';
  138. }
  139. // 处理font标签样式属性
  140. if (node.tag === 'font') {
  141. const fontSize = [
  142. 'x-small',
  143. 'small',
  144. 'medium',
  145. 'large',
  146. 'x-large',
  147. 'xx-large',
  148. '-webkit-xxx-large',
  149. ];
  150. const styleAttrs = {
  151. color: 'color',
  152. face: 'font-family',
  153. size: 'font-size',
  154. };
  155. if (!node.styleStr) node.styleStr = '';
  156. Object.keys(styleAttrs).forEach((key) => {
  157. if (node.attr[key]) {
  158. const value = key === 'size' ? fontSize[node.attr[key] - 1] : node.attr[key];
  159. node.styleStr += `${styleAttrs[key]}: ${value};`;
  160. }
  161. });
  162. }
  163. // 临时记录source资源
  164. if (node.tag === 'source') {
  165. results.source = node.attr.src;
  166. }
  167. if (customHandler.start) {
  168. customHandler.start(node, results);
  169. }
  170. if (unary) {
  171. // if this tag doesn't have end tag
  172. // like <img src="hoge.png"/>
  173. // add to parents
  174. const parent = bufArray[0] || results;
  175. if (parent.nodes === undefined) {
  176. parent.nodes = [];
  177. }
  178. parent.nodes.push(node);
  179. } else {
  180. bufArray.unshift(node);
  181. }
  182. },
  183. end(tag) {
  184. // merge into parent tag
  185. const node = bufArray.shift();
  186. if (node.tag !== tag) {
  187. console.error('invalid state: mismatch end tag');
  188. }
  189. // 当有缓存source资源时于于video补上src资源
  190. if (node.tag === 'video' && results.source) {
  191. node.attr.src = results.source;
  192. delete results.source;
  193. }
  194. if (customHandler.end) {
  195. customHandler.end(node, results);
  196. }
  197. if (bufArray.length === 0) {
  198. results.nodes.push(node);
  199. } else {
  200. const parent = bufArray[0];
  201. if (!parent.nodes) {
  202. parent.nodes = [];
  203. }
  204. parent.nodes.push(node);
  205. }
  206. },
  207. chars(text) {
  208. if (!text.trim()) return;
  209. const node = {
  210. node: 'text',
  211. text,
  212. };
  213. if (customHandler.chars) {
  214. customHandler.chars(node, results);
  215. }
  216. if (bufArray.length === 0) {
  217. results.nodes.push(node);
  218. } else {
  219. const parent = bufArray[0];
  220. if (parent.nodes === undefined) {
  221. parent.nodes = [];
  222. }
  223. parent.nodes.push(node);
  224. }
  225. },
  226. });
  227. return results;
  228. }
  229. export default html2json;
htmlparser.js
复制代码
  1. /**
  2. *
  3. * htmlParser改造自: https://github.com/blowsie/Pure-JavaScript-HTML5-Parser
  4. *
  5. * author: Di (微信小程序开发工程师)
  6. * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
  7. * 垂直微信小程序开发交流社区
  8. *
  9. * github地址: https://github.com/icindy/wxParse
  10. *
  11. * for: 微信小程序富文本解析
  12. * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
  13. */
  14. // Regular Expressions for parsing tags and attributes
  15. const startTag = /^<([-A-Za-z0-9_]+)((?:\s+[a-zA-Z0-9_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/;
  16. const endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/;
  17. const attr = /([a-zA-Z0-9_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g;
  18. function makeMap(str) {
  19. const obj = {};
  20. const items = str.split(',');
  21. for (let i = 0; i < items.length; i += 1) obj[items[i]] = true;
  22. return obj;
  23. }
  24. // Empty Elements - HTML 5
  25. const empty = makeMap('area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr');
  26. // Block Elements - HTML 5
  27. 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');
  28. // Inline Elements - HTML 5
  29. 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');
  30. // Elements that you can, intentionally, leave open
  31. // (and which close themselves)
  32. const closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr');
  33. // Attributes that have their values filled in disabled="disabled"
  34. const fillAttrs = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected');
  35. function HTMLParser(html, handler) {
  36. let index;
  37. let chars;
  38. let match;
  39. let last = html;
  40. const stack = [];
  41. stack.last = () => stack[stack.length - 1];
  42. function parseEndTag(tag, tagName) {
  43. // If no tag name is provided, clean shop
  44. let pos;
  45. if (!tagName) {
  46. pos = 0;
  47. } else {
  48. // Find the closest opened tag of the same type
  49. tagName = tagName.toLowerCase();
  50. for (pos = stack.length - 1; pos >= 0; pos -= 1) {
  51. if (stack[pos] === tagName) break;
  52. }
  53. }
  54. if (pos >= 0) {
  55. // Close all the open elements, up the stack
  56. for (let i = stack.length - 1; i >= pos; i -= 1) {
  57. if (handler.end) handler.end(stack[i]);
  58. }
  59. // Remove the open elements from the stack
  60. stack.length = pos;
  61. }
  62. }
  63. function parseStartTag(tag, tagName, rest, unary) {
  64. tagName = tagName.toLowerCase();
  65. if (block[tagName]) {
  66. while (stack.last() && inline[stack.last()]) {
  67. parseEndTag('', stack.last());
  68. }
  69. }
  70. if (closeSelf[tagName] && stack.last() === tagName) {
  71. parseEndTag('', tagName);
  72. }
  73. unary = empty[tagName] || !!unary;
  74. if (!unary) stack.push(tagName);
  75. if (handler.start) {
  76. const attrs = [];
  77. rest.replace(attr, function genAttr(matches, name) {
  78. const value = arguments[2] || arguments[3] || arguments[4] || (fillAttrs[name] ? name : '');
  79. attrs.push({
  80. name,
  81. value,
  82. escaped: value.replace(/(^|[^\\])"/g, '$1\\"'), // "
  83. });
  84. });
  85. if (handler.start) {
  86. handler.start(tagName, attrs, unary);
  87. }
  88. }
  89. }
  90. while (html) {
  91. chars = true;
  92. if (html.indexOf('</') === 0) {
  93. match = html.match(endTag);
  94. if (match) {
  95. html = html.substring(match[0].length);
  96. match[0].replace(endTag, parseEndTag);
  97. chars = false;
  98. }
  99. // start tag
  100. } else if (html.indexOf('<') === 0) {
  101. match = html.match(startTag);
  102. if (match) {
  103. html = html.substring(match[0].length);
  104. match[0].replace(startTag, parseStartTag);
  105. chars = false;
  106. }
  107. }
  108. if (chars) {
  109. index = html.indexOf('<');
  110. let text = '';
  111. while (index === 0) {
  112. text += '<';
  113. html = html.substring(1);
  114. index = html.indexOf('<');
  115. }
  116. text += index < 0 ? html : html.substring(0, index);
  117. html = index < 0 ? '' : html.substring(index);
  118. if (handler.chars) handler.chars(text);
  119. }
  120. if (html === last) throw new Error(`Parse Error: ${html}`);
  121. last = html;
  122. }
  123. // Clean up any remaining tags
  124. parseEndTag();
  125. }
  126. export default HTMLParser;
wxDiscode.js
复制代码
  1. // HTML 支持的数学符号
  2. function strNumDiscode(str) {
  3. str = str.replace(/&forall;/g, '∀');
  4. str = str.replace(/&part;/g, '∂');
  5. str = str.replace(/&exist;/g, '∃');
  6. str = str.replace(/&empty;/g, '∅');
  7. str = str.replace(/&nabla;/g, '∇');
  8. str = str.replace(/&isin;/g, '∈');
  9. str = str.replace(/&notin;/g, '∉');
  10. str = str.replace(/&ni;/g, '∋');
  11. str = str.replace(/&prod;/g, '∏');
  12. str = str.replace(/&sum;/g, '∑');
  13. str = str.replace(/&minus;/g, '−');
  14. str = str.replace(/&lowast;/g, '∗');
  15. str = str.replace(/&radic;/g, '√');
  16. str = str.replace(/&prop;/g, '∝');
  17. str = str.replace(/&infin;/g, '∞');
  18. str = str.replace(/&ang;/g, '∠');
  19. str = str.replace(/&and;/g, '∧');
  20. str = str.replace(/&or;/g, '∨');
  21. str = str.replace(/&cap;/g, '∩');
  22. str = str.replace(/&cup;/g, '∪');
  23. str = str.replace(/&int;/g, '∫');
  24. str = str.replace(/&there4;/g, '∴');
  25. str = str.replace(/&sim;/g, '∼');
  26. str = str.replace(/&cong;/g, '≅');
  27. str = str.replace(/&asymp;/g, '≈');
  28. str = str.replace(/&ne;/g, '≠');
  29. str = str.replace(/&le;/g, '≤');
  30. str = str.replace(/&ge;/g, '≥');
  31. str = str.replace(/&sub;/g, '⊂');
  32. str = str.replace(/&sup;/g, '⊃');
  33. str = str.replace(/&nsub;/g, '⊄');
  34. str = str.replace(/&sube;/g, '⊆');
  35. str = str.replace(/&supe;/g, '⊇');
  36. str = str.replace(/&oplus;/g, '⊕');
  37. str = str.replace(/&otimes;/g, '⊗');
  38. str = str.replace(/&perp;/g, '⊥');
  39. str = str.replace(/&sdot;/g, '⋅');
  40. return str;
  41. }
  42. // HTML 支持的希腊字母
  43. function strGreeceDiscode(str) {
  44. str = str.replace(/&Alpha;/g, 'Α');
  45. str = str.replace(/&Beta;/g, 'Β');
  46. str = str.replace(/&Gamma;/g, 'Γ');
  47. str = str.replace(/&Delta;/g, 'Δ');
  48. str = str.replace(/&Epsilon;/g, 'Ε');
  49. str = str.replace(/&Zeta;/g, 'Ζ');
  50. str = str.replace(/&Eta;/g, 'Η');
  51. str = str.replace(/&Theta;/g, 'Θ');
  52. str = str.replace(/&Iota;/g, 'Ι');
  53. str = str.replace(/&Kappa;/g, 'Κ');
  54. str = str.replace(/&Lambda;/g, 'Λ');
  55. str = str.replace(/&Mu;/g, 'Μ');
  56. str = str.replace(/&Nu;/g, 'Ν');
  57. str = str.replace(/&Xi;/g, 'Ν');
  58. str = str.replace(/&Omicron;/g, 'Ο');
  59. str = str.replace(/&Pi;/g, 'Π');
  60. str = str.replace(/&Rho;/g, 'Ρ');
  61. str = str.replace(/&Sigma;/g, 'Σ');
  62. str = str.replace(/&Tau;/g, 'Τ');
  63. str = str.replace(/&Upsilon;/g, 'Υ');
  64. str = str.replace(/&Phi;/g, 'Φ');
  65. str = str.replace(/&Chi;/g, 'Χ');
  66. str = str.replace(/&Psi;/g, 'Ψ');
  67. str = str.replace(/&Omega;/g, 'Ω');
  68. str = str.replace(/&alpha;/g, 'α');
  69. str = str.replace(/&beta;/g, 'β');
  70. str = str.replace(/&gamma;/g, 'γ');
  71. str = str.replace(/&delta;/g, 'δ');
  72. str = str.replace(/&epsilon;/g, 'ε');
  73. str = str.replace(/&zeta;/g, 'ζ');
  74. str = str.replace(/&eta;/g, 'η');
  75. str = str.replace(/&theta;/g, 'θ');
  76. str = str.replace(/&iota;/g, 'ι');
  77. str = str.replace(/&kappa;/g, 'κ');
  78. str = str.replace(/&lambda;/g, 'λ');
  79. str = str.replace(/&mu;/g, 'μ');
  80. str = str.replace(/&nu;/g, 'ν');
  81. str = str.replace(/&xi;/g, 'ξ');
  82. str = str.replace(/&omicron;/g, 'ο');
  83. str = str.replace(/&pi;/g, 'π');
  84. str = str.replace(/&rho;/g, 'ρ');
  85. str = str.replace(/&sigmaf;/g, 'ς');
  86. str = str.replace(/&sigma;/g, 'σ');
  87. str = str.replace(/&tau;/g, 'τ');
  88. str = str.replace(/&upsilon;/g, 'υ');
  89. str = str.replace(/&phi;/g, 'φ');
  90. str = str.replace(/&chi;/g, 'χ');
  91. str = str.replace(/&psi;/g, 'ψ');
  92. str = str.replace(/&omega;/g, 'ω');
  93. str = str.replace(/&thetasym;/g, 'ϑ');
  94. str = str.replace(/&upsih;/g, 'ϒ');
  95. str = str.replace(/&piv;/g, 'ϖ');
  96. str = str.replace(/&middot;/g, '·');
  97. return str;
  98. }
  99. function strcharacterDiscode(str) {
  100. // 加入常用解析
  101. str = str.replace(/&nbsp;/g, ' ');
  102. str = str.replace(/&ensp;/g, ' ');
  103. str = str.replace(/&emsp;/g, ' ');
  104. str = str.replace(/&quot;/g, "'");
  105. str = str.replace(/&amp;/g, '&');
  106. str = str.replace(/&lt;/g, '<');
  107. str = str.replace(/&gt;/g, '>');
  108. str = str.replace(/&#8226;/g, '•');
  109. return str;
  110. }
  111. // HTML 支持的其他实体
  112. function strOtherDiscode(str) {
  113. str = str.replace(/&OElig;/g, 'Œ');
  114. str = str.replace(/&oelig;/g, 'œ');
  115. str = str.replace(/&Scaron;/g, 'Š');
  116. str = str.replace(/&scaron;/g, 'š');
  117. str = str.replace(/&Yuml;/g, 'Ÿ');
  118. str = str.replace(/&fnof;/g, 'ƒ');
  119. str = str.replace(/&circ;/g, 'ˆ');
  120. str = str.replace(/&tilde;/g, '˜');
  121. str = str.replace(/&ensp;/g, '');
  122. str = str.replace(/&emsp;/g, '');
  123. str = str.replace(/&thinsp;/g, '');
  124. str = str.replace(/&zwnj;/g, '');
  125. str = str.replace(/&zwj;/g, '');
  126. str = str.replace(/&lrm;/g, '');
  127. str = str.replace(/&rlm;/g, '');
  128. str = str.replace(/&ndash;/g, '–');
  129. str = str.replace(/&mdash;/g, '—');
  130. str = str.replace(/&lsquo;/g, '‘');
  131. str = str.replace(/&rsquo;/g, '’');
  132. str = str.replace(/&sbquo;/g, '‚');
  133. str = str.replace(/&ldquo;/g, '“');
  134. str = str.replace(/&rdquo;/g, '”');
  135. str = str.replace(/&bdquo;/g, '„');
  136. str = str.replace(/&dagger;/g, '†');
  137. str = str.replace(/&Dagger;/g, '‡');
  138. str = str.replace(/&bull;/g, '•');
  139. str = str.replace(/&hellip;/g, '…');
  140. str = str.replace(/&permil;/g, '‰');
  141. str = str.replace(/&prime;/g, '′');
  142. str = str.replace(/&Prime;/g, '″');
  143. str = str.replace(/&lsaquo;/g, '‹');
  144. str = str.replace(/&rsaquo;/g, '›');
  145. str = str.replace(/&oline;/g, '‾');
  146. str = str.replace(/&euro;/g, '€');
  147. str = str.replace(/&trade;/g, '™');
  148. str = str.replace(/&larr;/g, '←');
  149. str = str.replace(/&uarr;/g, '↑');
  150. str = str.replace(/&rarr;/g, '→');
  151. str = str.replace(/&darr;/g, '↓');
  152. str = str.replace(/&harr;/g, '↔');
  153. str = str.replace(/&crarr;/g, '↵');
  154. str = str.replace(/&lceil;/g, '⌈');
  155. str = str.replace(/&rceil;/g, '⌉');
  156. str = str.replace(/&lfloor;/g, '⌊');
  157. str = str.replace(/&rfloor;/g, '⌋');
  158. str = str.replace(/&loz;/g, '◊');
  159. str = str.replace(/&spades;/g, '♠');
  160. str = str.replace(/&clubs;/g, '♣');
  161. str = str.replace(/&hearts;/g, '♥');
  162. str = str.replace(/&diams;/g, '♦');
  163. str = str.replace(/&#39;/g, "'");
  164. return str;
  165. }
  166. function strDiscode(str) {
  167. str = strNumDiscode(str);
  168. str = strGreeceDiscode(str);
  169. str = strcharacterDiscode(str);
  170. str = strOtherDiscode(str);
  171. return str;
  172. }
  173. function urlToHttpUrl(url, domain) {
  174. if (/^\/\//.test(url)) {
  175. return `https:${url}`;
  176. } else if (/^\//.test(url)) {
  177. return `https://${domain}${url}`;
  178. }
  179. return url;
  180. }
  181. export default {
  182. strDiscode,
  183. urlToHttpUrl,
  184. };
parse.css
复制代码
  1. /**
  2. * author: Di (微信小程序开发工程师)
  3. * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
  4. * 垂直微信小程序开发交流社区
  5. *
  6. * github地址: https://github.com/icindy/wxParse
  7. *
  8. * for: 微信小程序富文本解析
  9. * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
  10. */
  11. /**
  12. * 请在全局下引入该文件,@import '/static/wxParse.css';
  13. */
  14. .wxParse {
  15. user-select:none;
  16. width: 100%;
  17. font-family: Helvetica, "PingFangSC", 'Microsoft Yahei', '微软雅黑', Arial, sans-serif;
  18. color: #333;
  19. line-height: 1.5;
  20. font-size: 1em;
  21. text-align:justify;/* //左右两端对齐 */
  22. word-wrap: break-word;/*超出自动换行*/
  23. }
  24. .wxParse view ,.wxParse uni-view{
  25. word-break: break-word;
  26. }
  27. .wxParse .p {
  28. padding-bottom: 1em;
  29. clear: both;
  30. /* letter-spacing: 0;//字间距 */
  31. }
  32. .wxParse .inline {
  33. display: inline;
  34. margin: 0;
  35. padding: 0;
  36. }
  37. .wxParse .div {
  38. margin: 0;
  39. padding: 0;
  40. display: block;
  41. }
  42. .wxParse .h1{
  43. font-size: 2em;
  44. line-height: 1.2em;
  45. margin: 0.67em 0;
  46. }
  47. .wxParse .h2{
  48. font-size: 1.5em;
  49. margin: 0.83em 0;
  50. }
  51. .wxParse .h3{
  52. font-size: 1.17em;
  53. margin: 1em 0;
  54. }
  55. .wxParse .h4{
  56. margin: 1.33em 0;
  57. }
  58. .wxParse .h5{
  59. font-size: 0.83em;
  60. margin: 1.67em 0;
  61. }
  62. .wxParse .h6{
  63. font-size: 0.83em;
  64. margin: 1.67em 0;
  65. }
  66. .wxParse .h1,
  67. .wxParse .h2,
  68. .wxParse .h3,
  69. .wxParse .h4,
  70. .wxParse .h5,
  71. .wxParse .h6,
  72. .wxParse .b,
  73. .wxParse .strong{
  74. font-weight: bolder;
  75. }
  76. .wxParse .i,
  77. .wxParse .cite,
  78. .wxParse .em,
  79. .wxParse .var,
  80. .wxParse .address {
  81. font-style: italic;
  82. }
  83. .wxParse .pre,
  84. .wxParse .tt,
  85. .wxParse .code,
  86. .wxParse .kbd,
  87. .wxParse .samp {
  88. font-family: monospace;
  89. }
  90. .wxParse .pre {
  91. overflow: auto;
  92. background: #f5f5f5;
  93. padding: 16upx;
  94. white-space: pre;
  95. margin: 1em 0upx;
  96. }
  97. .wxParse .code {
  98. display: inline;
  99. background: #f5f5f5;
  100. }
  101. .wxParse .big {
  102. font-size: 1.17em;
  103. }
  104. .wxParse .small,
  105. .wxParse .sub,
  106. .wxParse .sup {
  107. font-size: 0.83em;
  108. }
  109. .wxParse .sub {
  110. vertical-align: sub;
  111. }
  112. .wxParse .sup {
  113. vertical-align: super;
  114. }
  115. .wxParse .s,
  116. .wxParse .strike,
  117. .wxParse .del {
  118. text-decoration: line-through;
  119. }
  120. .wxParse .strong,
  121. .wxParse .s {
  122. display: inline;
  123. }
  124. .wxParse .a {
  125. color: deepskyblue;
  126. }
  127. .wxParse .video {
  128. text-align: center;
  129. margin: 22upx 0;
  130. }
  131. .wxParse .video-video {
  132. width: 100%;
  133. }
  134. .wxParse .uni-image{
  135. max-width: 100%;
  136. }
  137. .wxParse .img {
  138. display: block;
  139. max-width: 100%;
  140. margin-bottom: -1em;/* //与p标签底部padding同时修改 */
  141. overflow: hidden;
  142. }
  143. .wxParse .blockquote {
  144. margin: 10upx 0;
  145. padding: 22upx 0 22upx 22upx;
  146. font-family: Courier, Calibri, "宋体";
  147. background: #f5f5f5;
  148. border-left: 6upx solid #dbdbdb;
  149. }
  150. .wxParse .blockquote .p {
  151. margin: 0;
  152. }
  153. .wxParse .ul, .wxParse .ol {
  154. display: block;
  155. margin: 1em 0;
  156. padding-left: 2em;
  157. }
  158. .wxParse .ol {
  159. list-style-type: disc;
  160. }
  161. .wxParse .ol {
  162. list-style-type: decimal;
  163. }
  164. .wxParse .ol>weixin-parse-template,.wxParse .ul>weixin-parse-template {
  165. display: list-item;
  166. align-items: baseline;
  167. text-align: match-parent;
  168. }
  169. .wxParse .ol>.li,.wxParse .ul>.li {
  170. display: list-item;
  171. align-items: baseline;
  172. text-align: match-parent;
  173. }
  174. .wxParse .ul .ul, .wxParse .ol .ul {
  175. list-style-type: circle;
  176. }
  177. .wxParse .ol .ol .ul, .wxParse .ol .ul .ul, .wxParse .ul .ol .ul, .wxParse .ul .ul .ul {
  178. list-style-type: square;
  179. }
  180. .wxParse .u {
  181. text-decoration: underline;
  182. }
  183. .wxParse .hide {
  184. display: none;
  185. }
  186. .wxParse .del {
  187. display: inline;
  188. }
  189. .wxParse .figure {
  190. overflow: hidden;
  191. }
  192. .wxParse .table {
  193. border-collapse:collapse;
  194. box-sizing: border-box;
  195. /* 内边框 */
  196. border: 1px solid #dadada;
  197. width: 100%;
  198. }
  199. .wxParse .tbody{
  200. border-collapse:collapse;
  201. box-sizing: border-box;
  202. /* 内边框 */
  203. border: 1px solid #dadada;
  204. }
  205. .wxParse .thead, .wxParse .tfoot, .wxParse .th{
  206. border-collapse:collapse;
  207. box-sizing: border-box;
  208. background: #ececec;
  209. font-weight: 40;
  210. }
  211. .wxParse .tr {
  212. border-collapse:collapse;
  213. box-sizing: border-box;
  214. /* border: 2px solid #F0AD4E; */
  215. overflow:auto;
  216. }
  217. .wxParse .th,
  218. .wxParse .td{
  219. border-collapse:collapse;
  220. box-sizing: border-box;
  221. border: 2upx solid #dadada;
  222. overflow:auto;
  223. }
  224. .wxParse .audio, .wxParse .uni-audio-default{
  225. display: block;
  226. }
  227. .textarea ._div{
  228. background-color:#fff !important;
  229. }
parse.vue
复制代码
  1. <!--**
  2. * forked from:https://github.com/F-loat/mpvue-wxParse
  3. *
  4. * github地址: https://github.com/dcloudio/uParse
  5. *
  6. * for: uni-app框架下 富文本解析
  7. *
  8. * 优化 by gaoyia@qq.com https://github.com/gaoyia/parse
  9. */-->
  10. <template>
  11. <!--基础元素-->
  12. <div class="wxParse" :class="className" :style="'user-select:' + userSelect">
  13. <block v-for="(node, index) of nodes" :key="index" v-if="!loading">
  14. <wxParseTemplate :node="node" />
  15. </block>
  16. </div>
  17. </template>
  18. <script>
  19. import HtmlToJson from './libs/html2json';
  20. import wxParseTemplate from './components/wxParseTemplate0';
  21. export default {
  22. name: 'wxParse',
  23. props: {
  24. // user-select:none;
  25. userSelect: {
  26. type: String,
  27. default: 'text' //none |text| all | element
  28. },
  29. imgOptions: {
  30. type: [Object, Boolean],
  31. default: function() {
  32. return {
  33. loop: false,
  34. indicator: 'number',
  35. longPressActions: false
  36. // longPressActions: {
  37. // itemList: ['发送给朋友', '保存图片', '收藏'],
  38. // success: function (res) {
  39. // console.log('选中了第' + (res.tapIndex + 1) + '个按钮');
  40. // },
  41. // fail: function (res) {
  42. // console.log(res.errMsg);
  43. // }
  44. // }
  45. // }
  46. }
  47. }
  48. },
  49. loading: {
  50. type: Boolean,
  51. default: false
  52. },
  53. className: {
  54. type: String,
  55. default: ''
  56. },
  57. content: {
  58. type: String,
  59. default: ''
  60. },
  61. noData: {
  62. type: String,
  63. default: '<div style="color: red;">数据不能为空</div>'
  64. },
  65. startHandler: {
  66. type: Function,
  67. default () {
  68. return node => {
  69. node.attr.class = null;
  70. node.attr.style = null;
  71. };
  72. }
  73. },
  74. endHandler: {
  75. type: Function,
  76. default: null
  77. },
  78. charsHandler: {
  79. type: Function,
  80. default: null
  81. },
  82. imageProp: {
  83. type: Object,
  84. default () {
  85. return {
  86. mode: 'aspectFit',
  87. padding: 0,
  88. lazyLoad: false,
  89. domain: ''
  90. };
  91. }
  92. }
  93. },
  94. components: {
  95. wxParseTemplate
  96. },
  97. data() {
  98. return {
  99. nodes: {},
  100. imageUrls: [],
  101. wxParseWidth: {
  102. value: 0
  103. }
  104. };
  105. },
  106. computed: {},
  107. mounted() {
  108. let that = this
  109. this.getWidth().then(function(data) {
  110. that.wxParseWidth.value = data;
  111. })
  112. this.setHtml()
  113. },
  114. methods: {
  115. setHtml() {
  116. let {
  117. content,
  118. noData,
  119. imageProp,
  120. startHandler,
  121. endHandler,
  122. charsHandler
  123. } = this;
  124. let parseData = content || noData;
  125. let customHandler = {
  126. start: startHandler,
  127. end: endHandler,
  128. chars: charsHandler
  129. };
  130. let results = HtmlToJson(parseData, customHandler, imageProp, this);
  131. this.imageUrls = results.imageUrls;
  132. this.nodes = results.nodes;
  133. },
  134. getWidth() {
  135. return new Promise((res, rej) => {
  136. // #ifndef MP-ALIPAY || MP-BAIDU
  137. var view = uni.createSelectorQuery().select(".content");
  138. view.boundingClientRect(data => {
  139. if(data.width){
  140. res(data.width);
  141. }else{
  142. res('100%');
  143. }
  144. }).exec();
  145. /* uni.createSelectorQuery()
  146. .in(this)
  147. .select('.wxParse')
  148. .fields({size: true,scrollOffset: true},data => {
  149. console.log(data);
  150. //res(data.width);
  151. }
  152. ).exec(); */
  153. // #endif
  154. // #ifdef MP-BAIDU
  155. swan.createSelectorQuery().select('.wxParse').boundingClientRect(function(rect) {
  156. rect[0].width
  157. }).exec()
  158. // #endif
  159. // #ifdef MP-ALIPAY
  160. my.createSelectorQuery()
  161. .select('.wxParse')
  162. .boundingClientRect().exec((ret) => {
  163. res(ret[0].width);
  164. });
  165. // #endif
  166. });
  167. },
  168. navigate(href, $event) {
  169. this.$emit('navigate', href, $event);
  170. },
  171. preview(src, $event) {
  172. if (!this.imageUrls.length || typeof this.imgOptions === 'boolean') {
  173. } else {
  174. uni.previewImage({
  175. current: src,
  176. urls: this.imageUrls,
  177. loop: this.imgOptions.loop,
  178. indicator: this.imgOptions.indicator,
  179. longPressActions: this.imgOptions.longPressActions
  180. });
  181. }
  182. this.$emit('preview', src, $event);
  183. },
  184. removeImageUrl(src) {
  185. const {
  186. imageUrls
  187. } = this;
  188. imageUrls.splice(imageUrls.indexOf(src), 1);
  189. }
  190. },
  191. // 父组件中提供
  192. provide() {
  193. return {
  194. parseWidth: this.wxParseWidth
  195. // 提示:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的。
  196. };
  197. },
  198. watch: {
  199. content() {
  200. this.setHtml()
  201. }
  202. }
  203. };
  204. </script>

jihai-copyright

jihaiCopyright.vue
复制代码
  1. <template>
  2. <view class="cpr">
  3. <view class="color-9">
  4. 吉海科技 © jihainet.com
  5. </view>
  6. <view class="color-9">
  7. 版权所有
  8. </view>
  9. </view>
  10. </template>
  11. <script>
  12. </script>
  13. <style>
  14. .cpr{
  15. text-align: center;
  16. font-size: 24upx;
  17. margin: 20upx 0;
  18. }
  19. </style>

jihai-lable.vue

复制代码
  1. <template>
  2. <view>
  3. <radio-group class="uni-list" @change="radioChange">
  4. <label class="uni-list-cell uni-list-cell-pd" v-for="(item, index) in type_list" :key="index">
  5. <view class="invoice-type-icon">
  6. <radio class="a-radio" :id="item.name" :value="item.value" :checked="item.checked" :disabled="item.disabled"></radio>
  7. </view>
  8. <view class="invoice-type-c">
  9. <label class="label-2-text" :for="item.name">
  10. <text>{{item.name}}</text>
  11. </label>
  12. </view>
  13. </label>
  14. </radio-group>
  15. </view>
  16. </template>
  17. <script>
  18. export default {
  19. data() {
  20. return {
  21. type_list: [
  22. { value: '1', name: '仅退款', checked: true, disabled: false },
  23. { value: '2', name: '退货退款', checked: false, disabled:false },
  24. ],
  25. };
  26. },
  27. methods:{
  28. radioChange: function(evt) {
  29. this.type_list.forEach(item => {
  30. if (item.value === evt.target.value) {
  31. item.checked = true;
  32. this.aftersale_type = evt.target.value;
  33. }else{
  34. item.checked = false;
  35. }
  36. });
  37. if(this.type_list[0].checked){
  38. this.refund_input_noedit = true;
  39. }else{
  40. this.refund_input_noedit = false;
  41. }
  42. },
  43. }
  44. }
  45. </script>
  46. <style>
  47. </style>

jshop

image
jshop-article.vue
复制代码
  1. <template>
  2. <view class='index-article cell-group bottom-cell-group' v-if="data.params.list && data.params.list.length > 0">
  3. <view class='cell-item'
  4. v-for="item in data.params.list"
  5. :key="item.id"
  6. @click="articleDetail(item.id)"
  7. >
  8. <view class="cell-item-bd">
  9. <view class="article-title ">
  10. {{ item.title }}
  11. </view>
  12. <view class="article-time">
  13. {{ item.ctime }}
  14. </view>
  15. </view>
  16. <view class="cell-title-img">
  17. <image :src="item.cover" mode="aspectFill"></image>
  18. </view>
  19. </view>
  20. </view>
  21. </template>
  22. <script>
  23. export default {
  24. name: "jshoparticle",
  25. props: {
  26. data:{
  27. // type: Array,
  28. required: true,
  29. }
  30. },
  31. methods: {
  32. // 查看文章详情
  33. articleDetail (articleId) {
  34. this.$common.navigateTo('/pages/article/index?id=' + articleId+'&id_type=1')
  35. }
  36. }
  37. }
  38. </script>
  39. <style>
  40. .index-article .cell-title-img{
  41. width: 160upx;
  42. height: 160upx;
  43. float: right;
  44. }
  45. .index-article .cell-title-img image{
  46. width: 100%;
  47. height: 100%;
  48. }
  49. .index-article .cell-item-bd{
  50. padding-right: 0;
  51. vertical-align: top;
  52. position: relative;
  53. }
  54. .index-article .article-title{
  55. font-size: 28upx;
  56. color: #333;
  57. width: 100%;
  58. min-height: 80upx;
  59. display: -webkit-box;
  60. -webkit-box-orient: vertical;
  61. -webkit-line-clamp: 2;
  62. overflow: hidden;
  63. }
  64. .index-article .article-time{
  65. font-size: 24upx;
  66. color: #999;
  67. display: inline-block;
  68. min-width: 220upx;
  69. min-height: 32upx;
  70. position: absolute;
  71. bottom: 0;
  72. }
  73. </style>
jshop-articleClassify.vue
复制代码
  1. <template>
  2. <view class='index-article cell-group bottom-cell-group' v-if="data.params.list && data.params.list.length > 0">
  3. <view class='cell-item'
  4. v-for="item in data.params.list"
  5. :key="item.id"
  6. @click="articleDetail(item.id)"
  7. >
  8. <view class="cell-item-bd">
  9. <view class="article-title ">
  10. {{ item.title }}
  11. </view>
  12. <view class="article-time">
  13. {{ item.ctime }}
  14. </view>
  15. </view>
  16. <view class="cell-title-img">
  17. <image :src="item.cover" mode="aspectFill"></image>
  18. </view>
  19. </view>
  20. </view>
  21. </template>
  22. <script>
  23. export default {
  24. name: "jshoparticleclassify",
  25. props: {
  26. data:{
  27. // type: Array,
  28. required: true,
  29. }
  30. },
  31. methods: {
  32. // 查看文章详情
  33. articleDetail (articleId) {
  34. this.$common.navigateTo('/pages/article/index?id=' + articleId+'&id_type=1')
  35. }
  36. }
  37. }
  38. </script>
  39. <style>
  40. .index-article .cell-title-img{
  41. width: 160upx;
  42. height: 160upx;
  43. float: right;
  44. }
  45. .index-article .cell-title-img image{
  46. width: 100%;
  47. height: 100%;
  48. }
  49. .index-article .cell-item-bd{
  50. padding-right: 0;
  51. vertical-align: top;
  52. position: relative;
  53. }
  54. .index-article .article-title{
  55. font-size: 28upx;
  56. color: #333;
  57. width: 100%;
  58. min-height: 80upx;
  59. display: -webkit-box;
  60. -webkit-box-orient: vertical;
  61. -webkit-line-clamp: 2;
  62. overflow: hidden;
  63. }
  64. .index-article .article-time{
  65. font-size: 24upx;
  66. color: #999;
  67. display: inline-block;
  68. min-width: 220upx;
  69. min-height: 32upx;
  70. position: absolute;
  71. bottom: 0;
  72. }
  73. </style>
jshop-blank.vue
复制代码
  1. <template>
  2. <view class="blank" :style="{background:data.params.backgroundColor,height:data.params.height*2+'rpx'}"></view>
  3. </template>
  4. <script>
  5. export default {
  6. name: "jshopblank",
  7. props: {
  8. data:{
  9. // type: Array,
  10. required: true,
  11. }
  12. },
  13. methods: {
  14. }
  15. }
  16. </script>
  17. <style>
  18. </style>
jshop-content.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <u-parse :content="content" @preview="preview" @navigate="navigate" />
  4. </view>
  5. </template>
  6. <script>
  7. //视频和文本解析组件
  8. import uParse from '@/components/gaoyia-parse/parse.vue'
  9. export default {
  10. name: 'jshop-content',
  11. components: {
  12. uParse
  13. },
  14. props: {
  15. content: {}
  16. },
  17. created() {},
  18. methods: {
  19. preview(src, e) {
  20. // do something
  21. },
  22. navigate(href, e) {
  23. // do something
  24. }
  25. }
  26. }
  27. </script>
jshop-coupon.vue
复制代码
  1. <template>
  2. <view class="coupon bottom-cell-group" v-if="data.params.list.length > 0">
  3. <view class="coupon-item" v-for="item in data.params.list" :key="item.id" @click="receiveCoupon(item.id)">
  4. <view class="coupon-i-l">
  5. <view class="coupon-i-l-t">
  6. <image class="icon" src="/static/image/element-ic.png" mode=""></image>
  7. <text>{{ item.name }}</text>
  8. </view>
  9. <view class="coupon-i-l-b">
  10. {{ item.expression1 + item.expression2 }}
  11. </view>
  12. </view>
  13. <view class="coupon-i-r">
  14. <image class="coupon-logo" src="/static/image/coupon-element.png" mode=""></image>
  15. </view>
  16. </view>
  17. </view>
  18. </template>
  19. <script>
  20. export default {
  21. name: "jshopcoupon",
  22. props: {
  23. data:{
  24. // type: Array,
  25. required: true,
  26. }
  27. },
  28. methods: {
  29. // 用户领取优惠券
  30. receiveCoupon(couponId) {
  31. let data = {
  32. promotion_id: couponId
  33. }
  34. this.$api.getCoupon(data, res => {
  35. if (res.status) {
  36. this.$common.successToShow(res.msg)
  37. } else {
  38. this.$common.errorToShow(res.msg)
  39. }
  40. })
  41. },
  42. }
  43. }
  44. </script>
  45. <style>
  46. .coupon {
  47. padding: 0 26upx;
  48. background-color: #f8f8f8;
  49. }
  50. .coupon-item {
  51. padding: 20upx;
  52. margin-bottom: 20upx;
  53. background-color: #fff;
  54. }
  55. .coupon-i-l {
  56. width: 400upx;
  57. display: inline-block;
  58. }
  59. .coupon-i-l-t {
  60. font-size: 32upx;
  61. position: relative;
  62. margin-bottom: 10upx;
  63. }
  64. .coupon-i-l-t .icon {
  65. position: absolute;
  66. top: 50%;
  67. transform: translateY(-50%);
  68. }
  69. .coupon-i-l-t text {
  70. margin-left: 60upx;
  71. }
  72. .coupon-i-l-b {
  73. font-size: 24upx;
  74. color: #999;
  75. }
  76. .coupon-i-r {
  77. width: 258upx;
  78. display: inline-block;
  79. text-align: center;
  80. }
  81. .coupon-logo {
  82. width: 130upx;
  83. height: 100upx;
  84. }
  85. </style>
jshop-goods.vue
复制代码
  1. <template>
  2. <view class="index-goods">
  3. <!-- 列表平铺两列三列 -->
  4. <view class='img-grids bottom-cell-group'
  5. v-if="data.params.column == '2' && data.params.display == 'list' || data.params.column == '3' && data.params.display == 'list'"
  6. v-bind:class="'column'+data.params.column">
  7. <view class='cell-item right-img' v-if="data.params.title != ''">
  8. <view class='cell-item-hd'>
  9. <view class='cell-hd-title'>{{data.params.title}}</view>
  10. </view>
  11. <view class='cell-item-bd'>
  12. </view>
  13. <view class='cell-item-ft' v-if="data.params.lookMore == 'true'">
  14. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  15. <text class='cell-ft-text' @click="goodsList({cat_id: data.params.classifyId,brand_id:data.params.brandId})">查看更多</text>
  16. </view>
  17. </view>
  18. <!-- <view class='img-grids'> -->
  19. <view class="" v-if="data.params.list.length">
  20. <view class="img-grids-item" v-for="item in data.params.list" :key="item.id" @click="goodsDetail(item.id)">
  21. <image
  22. class="img-grids-item-t have-none"
  23. :src="item.image_url"
  24. mode='aspectFill'
  25. ></image>
  26. <view class="img-grids-item-b">
  27. <view class="goods-name grids-goods-name">
  28. {{item.name}}
  29. </view>
  30. <view class="goods-item-c">
  31. <view class="goods-price red-price">¥{{item.price}}</view>
  32. </view>
  33. </view>
  34. </view>
  35. </view>
  36. <view v-else-if="!data.params.list.length && !data.params.listAjax">
  37. <view class='img-grids-item'>
  38. <image class='img-grids-item-t have-none' src='' mode=''></image>
  39. <view class='img-grids-item-b'>
  40. <view class='goods-name grids-goods-name have-none'></view>
  41. <view class='goods-item-c'>
  42. <view class='goods-price red-price have-none'></view>
  43. </view>
  44. </view>
  45. </view>
  46. <view class='img-grids-item'>
  47. <image class='img-grids-item-t have-none' src='' mode=''></image>
  48. <view class='img-grids-item-b'>
  49. <view class='goods-name grids-goods-name have-none'></view>
  50. <view class='goods-item-c'>
  51. <view class='goods-price red-price have-none'></view>
  52. </view>
  53. </view>
  54. </view>
  55. <view class='img-grids-item'>
  56. <image class='img-grids-item-t have-none' src='' mode=''></image>
  57. <view class='img-grids-item-b'>
  58. <view class='goods-name grids-goods-name have-none'></view>
  59. <view class='goods-item-c'>
  60. <view class='goods-price red-price have-none'></view>
  61. </view>
  62. </view>
  63. </view>
  64. </view>
  65. <!-- <view v-else="">
  66. <scroll-view class='swiper-list' scroll-x="true"></scroll-view>
  67. </view> -->
  68. <!-- </view> -->
  69. </view>
  70. <!-- 列表平铺单列 -->
  71. <view class="img-list bottom-cell-group"
  72. v-if="data.params.column == '1' && data.params.display == 'list'" >
  73. <view class='cell-item right-img' v-if="data.params.title != ''">
  74. <view class='cell-item-hd'>
  75. <view class='cell-hd-title'>{{data.params.title}}</view>
  76. </view>
  77. <view class='cell-item-bd'>
  78. </view>
  79. <view class='cell-item-ft' v-if="data.params.lookMore == 'true'">
  80. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  81. <text class='cell-ft-text' @click="goodsList({cat_id: data.params.classifyId,brand_id:data.params.brandId})">查看更多</text>
  82. </view>
  83. </view>
  84. <view v-if="data.params.list.length>0">
  85. <view class="img-list-item" v-for="(item, index) in data.params.list" :key="index" @click="goodsDetail(item.id)">
  86. <image class="img-list-item-l have-none" :src="item.image_url" mode='aspectFill'></image>
  87. <view class="img-list-item-r">
  88. <view class="goods-name list-goods-name">
  89. {{item.name}}
  90. </view>
  91. <view class="goods-item-c">
  92. <view class="goods-price red-price">¥{{item.price}}</view>
  93. <view class="goods-buy">
  94. <view class="goods-salesvolume" v-if="item.comments_count > 0">{{item.comments_count}}条评论</view>
  95. <view class="goods-salesvolume" v-else-if="item.comments_count <= 0">暂无评论</view>
  96. <image class="goods-cart" src="/static/image/ic-car.png"></image>
  97. </view>
  98. </view>
  99. </view>
  100. </view>
  101. </view>
  102. <view class="order-none" v-else>
  103. <image class="order-none-img" src="/static/image/order.png" mode=""></image>
  104. </view>
  105. </view>
  106. <!-- 横向滚动 -->
  107. <view class='img-grids bottom-cell-group'
  108. v-if="data.params.column == '2' && data.params.display == 'slide' || data.params.column == '3' && data.params.display == 'slide'"
  109. v-bind:class="'slide'+data.params.column">
  110. <view class='cell-item right-img' v-if="data.params.title != ''">
  111. <view class='cell-item-hd'>
  112. <view class='cell-hd-title'>{{data.params.title}}</view>
  113. </view>
  114. <view class='cell-item-bd'>
  115. </view>
  116. <view class='cell-item-ft' v-if="data.params.lookMore == 'true'">
  117. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  118. <text class='cell-ft-text' @click="goodsList({cat_id: data.params.classifyId,brand_id:data.params.brandId})">查看更多</text>
  119. </view>
  120. </view>
  121. <view class='swiper-grids'>
  122. <scroll-view class='swiper-list' scroll-x="true" v-if="data.params.list.length">
  123. <view class='img-grids-item' v-for="item in data.params.list" :key="item.id" @click="goodsDetail(item.id)">
  124. <image class='img-grids-item-t have-none' :src='item.image_url' mode='aspectFill'></image>
  125. <view class='img-grids-item-b'>
  126. <view class='goods-name grids-goods-name'>{{ item.name }}</view>
  127. <view class='goods-item-c'>
  128. <view class='goods-price red-price'>¥{{ item.price }}</view>
  129. </view>
  130. </view>
  131. </view>
  132. </scroll-view>
  133. <view v-else-if="!goodsListOfHotAjax && !goodsListOfHot.length">
  134. <scroll-view class='swiper-list' scroll-x="true">
  135. <view class='img-grids-item'>
  136. <image class='img-grids-item-t have-none' src='' mode='aspectFill'></image>
  137. <view class='img-grids-item-b'>
  138. <view class='goods-name grids-goods-name have-none'></view>
  139. <view class='goods-item-c'>
  140. <view class='goods-price red-price have-none'></view>
  141. </view>
  142. </view>
  143. </view>
  144. <view class='img-grids-item'>
  145. <image class='img-grids-item-t have-none' src='' mode='aspectFill'></image>
  146. <view class='img-grids-item-b'>
  147. <view class='goods-name grids-goods-name have-none'></view>
  148. <view class='goods-item-c'>
  149. <view class='goods-price red-price have-none'></view>
  150. </view>
  151. </view>
  152. </view>
  153. <view class='img-grids-item'>
  154. <image class='img-grids-item-t have-none' src='' mode=''></image>
  155. <view class='img-grids-item-b'>
  156. <view class='goods-name grids-goods-name have-none'></view>
  157. <view class='goods-item-c'>
  158. <view class='goods-price red-price have-none'></view>
  159. </view>
  160. </view>
  161. </view>
  162. </scroll-view>
  163. </view>
  164. <view v-else="">
  165. <scroll-view class='swiper-list' scroll-x="true"></scroll-view>
  166. </view>
  167. </view>
  168. </view>
  169. </view>
  170. </template>
  171. <script>
  172. import {goods} from '@/config/mixins.js'
  173. export default {
  174. mixins: [goods],
  175. name: "jshopgoods",
  176. props: {
  177. data:{
  178. // type: Array,
  179. required: true,
  180. }
  181. },
  182. methods: {
  183. //跳转到商品详情页面
  184. goodsDetail: function(id) {
  185. let url = '/pages/goods/index/index?id=' + id;
  186. this.$common.navigateTo(url);
  187. },
  188. },
  189. }
  190. </script>
  191. <style>
  192. .cell-item {
  193. border: none;
  194. /* padding-bottom: 0; */
  195. }
  196. .cell-ft-text {
  197. font-size: 22upx;
  198. color: #999;
  199. }
  200. .img-grids,.img-list{
  201. /* margin-top: 20upx; */
  202. background-color: #fff;
  203. }
  204. .img-grids-item{
  205. display: inline-table;
  206. margin-top: 0;
  207. margin-bottom: 14upx;
  208. }
  209. .column3 .img-grids-item{
  210. width: 230upx;
  211. margin: 15upx;
  212. margin-right: 0;
  213. margin-top: 0;
  214. margin-bottom: 6upx;
  215. }
  216. .column3 .img-grids-item:nth-child(3n){
  217. margin-right: 15upx;
  218. }
  219. .column3 .img-grids-item-t{
  220. width: 230upx;
  221. height: 230upx;
  222. }
  223. .column3 .grids-goods-name{
  224. font-size: 24upx;
  225. height: 68upx;
  226. }
  227. .column3 .img-grids-item-b{
  228. padding: 0 8upx 8upx;
  229. }
  230. .column3 .goods-price{
  231. font-size: 26upx;
  232. }
  233. .slide3 .img-grids-item{
  234. width: 200upx;
  235. }
  236. .slide3 .img-grids-item-t{
  237. width: 200upx;
  238. height: 200upx;
  239. }
  240. .slide3 .grids-goods-name{
  241. font-size: 24upx;
  242. }
  243. .index-goods .img-grids-item{
  244. display: inline-block;
  245. margin-top: 0;
  246. }
  247. .index-goods .img-list-item{
  248. padding: 0upx 26upx;
  249. margin-bottom: 14upx;
  250. }
  251. .index-goods .img-list{
  252. padding-bottom: 10upx;
  253. }
  254. </style>
jshop-groupPurchase.vue
复制代码
  1. <template>
  2. <!-- 团购秒杀 -->
  3. <view class="img-list bottom-cell-group group-buying" v-if="data.params.list && data.params.list.length > 0">
  4. <view class='cell-item right-img'>
  5. <view class='cell-item-hd group-title'>
  6. {{data.params.title}}
  7. <!-- <view class='cell-hd-title'></view> -->
  8. </view>
  9. </view>
  10. <view class='swiper-grids'>
  11. <scroll-view class='swiper-list' scroll-x="true">
  12. <view class="img-list-item" v-if="item.goods !== 'undefined' && item.goods" v-for="(item, key) in data.params.list"
  13. :key="key">
  14. <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>
  15. <view class="img-list-item-r medium-right">
  16. <view class="goods-name list-goods-name" @click="groupDetail(item.goods.id, item.goods.group_id)">{{item.goods.name}}</view>
  17. <view class="goods-item-c">
  18. <view class="goods-price red-price">¥{{item.goods.product.price}}</view>
  19. <view class="goods-buy">
  20. <view class="goods-salesvolume red-price" v-if="(item.goods.lasttime != '已经结束' || item.goods.lasttime != '即将开始') && item.goods.lasttime">剩余:<uni-countdown
  21. :show-day="false" :hour="item.goods.lasttime.hour" :minute="item.goods.lasttime.minute" :second="item.goods.lasttime.second"></uni-countdown>
  22. </view>
  23. <view class="goods-salesvolume red-price" v-if="item.goods.lasttime == '已经结束'">已结束</view>
  24. <view class="goods-salesvolume red-price" v-if="item.goods.lasttime == '即将开始'">即将开始</view>
  25. <image class="goods-cart" src="/static/image/ic-car.png" @click="groupDetail(item.goods.id, item.goods.group_id)"></image>
  26. </view>
  27. </view>
  28. </view>
  29. </view>
  30. </scroll-view>
  31. </view>
  32. </view>
  33. </template>
  34. <script>
  35. import uniCountdown from "@/components/uni-countdown/uni-countdown.vue"
  36. import {
  37. goods
  38. } from '@/config/mixins.js'
  39. export default {
  40. mixins: [goods],
  41. components: {
  42. uniCountdown
  43. },
  44. name: "jshopgrouppurchase",
  45. props: {
  46. data: {
  47. // type: Array,
  48. required: false,
  49. }
  50. },
  51. methods: {
  52. showSliderInfo(type, val) {
  53. if (type == 1) {
  54. if (val.indexOf('http') != -1) {
  55. // #ifdef H5
  56. window.location.href = val
  57. // #endif
  58. } else {
  59. // #ifdef H5 || APP-PLUS || APP-PLUS-NVUE || MP
  60. if (val == '/pages/classify/classify' || val == '/pages/cart/index/index' || val == '/pages/member/index/index') {
  61. uni.switchTab({
  62. url: val
  63. });
  64. return;
  65. } else {
  66. this.$common.navigateTo(val);
  67. return;
  68. }
  69. // #endif
  70. }
  71. } else if (type == 2) {
  72. // 商品详情
  73. this.goodsDetail(val)
  74. } else if (type == 3) {
  75. // 文章详情
  76. this.$common.navigateTo('/pages/article/index?id=' + val +'&id_type=1')
  77. } else if (type == 4) {
  78. // 文章列表
  79. this.$common.navigateTo('/pages/article/list?cid=' + val)
  80. } else if (type == 5) {
  81. //智能表单
  82. this.$common.navigateTo('/pages/form/detail/form?id=' + val)
  83. }
  84. },
  85. //跳转到商品详情页面
  86. // goodsDetail: function(id) {
  87. // let url = '/pages/goods/index/index?id=' + id;
  88. // this.$common.navigateTo(url);
  89. // },
  90. },
  91. }
  92. </script>
  93. <style>
  94. .img-list,
  95. .img-grids {
  96. background-color: #fff;
  97. }
  98. .cell-item {
  99. border: none;
  100. }
  101. .group-buying .img-list-item {
  102. min-height: 236upx;
  103. padding: 20upx;
  104. margin-left: 26upx;
  105. margin-bottom: 26upx;
  106. display: inline-table;
  107. background-color: #f9f9f9;
  108. }
  109. .swiper-grids .img-list-item:last-child {
  110. margin-right: 26upx;
  111. }
  112. /* .group-buying .goods-name{
  113. min-height: 74upx;
  114. } */
  115. .group-buying .group-title {
  116. width: 100%;
  117. overflow: hidden;
  118. text-overflow: ellipsis;
  119. white-space: nowrap;
  120. }
  121. </style>
jshop-imgSingle.vue
复制代码
  1. <template>
  2. <!-- 单图 -->
  3. <view class="ad jshop-imgsingle" v-if="data.params.list && data.params.list.length > 0">
  4. <view class="" v-for="item in data.params.list" :key="item.id">
  5. <image class="ad-img" :src="item.image" mode="widthFix" @click="showSliderInfo(item.linkType, item.linkValue)"></image>
  6. <view class="imgup-btn" v-if="item.buttonText != ''" @click="showSliderInfo(item.linkType, item.linkValue)">
  7. <button class="btn btn-fillet" :style="{background:item.buttonColor,color:item.textColor}">{{item.buttonText}}</button>
  8. </view>
  9. </view>
  10. </view>
  11. </template>
  12. <script>
  13. export default {
  14. name: "jshopimgsingle",
  15. props: {
  16. data: {
  17. // type: Object,
  18. required: true,
  19. }
  20. },
  21. methods: {
  22. showSliderInfo(type, val) {
  23. if (!val) {
  24. return;
  25. }
  26. if (type == 1) {
  27. if (val.indexOf('http') != -1) {
  28. // #ifdef H5
  29. window.location.href = val
  30. // #endif
  31. } else {
  32. // #ifdef H5 || APP-PLUS || APP-PLUS-NVUE || MP
  33. if (val == '/pages/index/index' || val == '/pages/classify/classify' || val == '/pages/cart/index/index' || val == '/pages/member/index/index') {
  34. uni.switchTab({
  35. url: val
  36. });
  37. return;
  38. } else {
  39. this.$common.navigateTo(val);
  40. return;
  41. }
  42. // #endif
  43. }
  44. } else if (type == 2) {
  45. // 商品详情
  46. this.goodsDetail(val)
  47. } else if (type == 3) {
  48. // 文章详情
  49. this.$common.navigateTo('/pages/article/index?id=' + val + '&id_type=1')
  50. } else if (type == 4) {
  51. // 文章列表
  52. this.$common.navigateTo('/pages/article/list?cid=' + val)
  53. } else if (type == 5) {
  54. //智能表单
  55. this.$common.navigateTo('/pages/form/detail/form?id=' + val)
  56. }
  57. },
  58. //跳转到商品详情页面
  59. goodsDetail: function(id) {
  60. // let ins = encodeURIComponent('id='+id);
  61. let url = '/pages/goods/index/index?id=' + id;
  62. this.$common.navigateTo(url);
  63. },
  64. },
  65. }
  66. </script>
  67. <style>
  68. /* .ad {
  69. width: 100%;
  70. overflow: hidden;
  71. }
  72. .ad-img{
  73. width: 100%;
  74. float: left;
  75. margin-bottom: 20upx;
  76. }
  77. .ad-img:last-child{
  78. margin-bottom: 0;
  79. } */
  80. .jshop-imgsingle.ad {
  81. width: 100%;
  82. overflow: hidden;
  83. position: relative;
  84. }
  85. .jshop-imgsingle .ad-img {
  86. width: 100%;
  87. float: left;
  88. position: relative;
  89. z-index: 667;
  90. /* margin-bottom: 20upx; */
  91. }
  92. .jshop-imgsingle .ad-img:last-child {
  93. margin-bottom: 0;
  94. }
  95. .jshop-imgsingle .imgup-btn {
  96. position: absolute;
  97. z-index: 668;
  98. bottom: 80upx;
  99. left: 40upx;
  100. }
  101. .jshop-imgsingle .imgup-btn .btn {
  102. line-height: 2;
  103. font-size: 28upx;
  104. padding: 0 50upx;
  105. }
  106. </style>
jshop-imgSlide.vue
复制代码
  1. <template>
  2. <view class='swiper bottom-cell-group' v-if="data.params.list && data.params.list.length > 0">
  3. <swiper class="swiper-c" :indicator-dots="swiper.indicatorDots" :autoplay="swiper.autoplay" :interval="data.params.duration"
  4. :duration="swiper.duration">
  5. <swiper-item class="have-none" v-for="(item, index) in data.params.list" :key="index">
  6. <image class='' :src="item.image" @click="showSliderInfo(item.linkType, item.linkValue)" mode="aspectFill"></image>
  7. </swiper-item>
  8. </swiper>
  9. </view>
  10. </template>
  11. <script>
  12. export default {
  13. name: "jshopimgSlide",
  14. props: {
  15. data: {
  16. // type: Object,
  17. required: true,
  18. }
  19. },
  20. data() {
  21. return {
  22. swiper: {
  23. indicatorDots: true,
  24. autoplay: true,
  25. // interval: 2000,
  26. duration: 500,
  27. },
  28. };
  29. },
  30. created() {},
  31. watch: {},
  32. methods: {
  33. // 广告点击查看详情
  34. showSliderInfo(type, val) {
  35. if (!val) {
  36. return;
  37. }
  38. if (type == 1) {
  39. if (val.indexOf('http') != -1) {
  40. // #ifdef H5
  41. window.location.href = val
  42. // #endif
  43. } else {
  44. // #ifdef H5 || APP-PLUS || APP-PLUS-NVUE || MP
  45. if (val == '/pages/index/index' || val == '/pages/classify/classify' || val == '/pages/cart/index/index' || val == '/pages/member/index/index') {
  46. uni.switchTab({
  47. url: val
  48. });
  49. return;
  50. } else {
  51. this.$common.navigateTo(val);
  52. return;
  53. }
  54. // #endif
  55. }
  56. } else if (type == 2) {
  57. // 商品详情
  58. this.goodsDetail(val)
  59. } else if (type == 3) {
  60. // 文章详情
  61. this.$common.navigateTo('/pages/article/index?id=' + val + '&id_type=1')
  62. } else if (type == 4) {
  63. // 文章列表
  64. this.$common.navigateTo('/pages/article/list?cid=' + val)
  65. } else if (type == 5) {
  66. //智能表单
  67. this.$common.navigateTo('/pages/form/detail/form?id=' + val)
  68. }
  69. },
  70. //跳转到商品详情页面
  71. goodsDetail: function(id) {
  72. let url = '/pages/goods/index/index?id=' + id;
  73. this.$common.navigateTo(url);
  74. },
  75. }
  76. }
  77. </script>
  78. <style>
  79. .swiper {
  80. height: 340upx;
  81. }
  82. </style>
jshop-imgWindow.vue
复制代码
  1. <template>
  2. <view class="imgwindow bottom-cell-group">
  3. <view class="imgwindow-list" v-if="data.params.style == '2' ||data.params.style == '3' ||data.params.style == '4'"
  4. v-bind:class="'row'+data.params.style" :style="{margin:-data.params.margin+'px'}">
  5. <view class="imgwindow-item" ref="imgwitem" :style="{height:height+'px',padding:data.params.margin+'px'}" v-for="(item, index) in data.params.list"
  6. :key="index">
  7. <image :src="item.image" mode="aspectFill" @click="showSliderInfo(item.linkType, item.linkValue)"></image>
  8. </view>
  9. </view>
  10. <view class="imgwindow-list" v-if="data.params.style == '0'" v-bind:class="'row'+data.params.style" :style="{margin:-data.params.margin+'px'}">
  11. <view class="imgwindow-item" ref="imgwitem" :style="{height:height+'px',padding:data.params.margin+'px'}" v-for="(item, index) in data.params.list"
  12. :key="index" v-if="index == 0">
  13. <image :src="item.image" mode="aspectFill" @click="showSliderInfo(item.linkType, item.linkValue)"></image>
  14. </view>
  15. <view class="imgwindow-item" ref="imgwitem" :style="{height:height1+'px',padding:data.params.margin+'px'}" v-for="(item, index) in data.params.list"
  16. :key="index" v-if="index !== 0">
  17. <image :src="item.image" mode="aspectFill" @click="showSliderInfo(item.linkType, item.linkValue)"></image>
  18. </view>
  19. </view>
  20. </view>
  21. </template>
  22. <script>
  23. export default {
  24. name: "jshopimgwindow",
  25. props: {
  26. data: {
  27. // type: Object,
  28. required: true,
  29. }
  30. },
  31. data() {
  32. return {
  33. height: '',
  34. height1: '',
  35. padding: '3'
  36. }
  37. },
  38. mounted() {
  39. // #ifdef H5 || APP-PLUS || APP-PLUS-NVUE
  40. var view = uni.createSelectorQuery().in(this).select(".imgwindow-item");
  41. view.boundingClientRect(data => {
  42. this.height = data.width;
  43. // 橱窗小图高度
  44. this.height1 = data.width / 2;
  45. }).exec();
  46. // #endif
  47. // #ifdef MP-ALIPAY
  48. var view = uni.createSelectorQuery().select(".content").boundingClientRect().exec(data => {
  49. this.height1 = data[0].width / 4;
  50. if (this.data.params.style == '3') {
  51. this.height = data[0].width / 3;
  52. } else if (this.data.params.style == '2') {
  53. this.height = data[0].width / 2;
  54. } else if (this.data.params.style == '4') {
  55. this.height = data[0].width / 4;
  56. } else if (this.data.params.style == '0') {
  57. this.height = data[0].width / 2;
  58. }
  59. });
  60. // #endif
  61. // #ifdef MP-WEIXIN
  62. var view = uni.createSelectorQuery().select(".content");
  63. view.boundingClientRect(data => {
  64. this.height1 = data.width / 4;
  65. if (this.data.params.style == '3') {
  66. this.height = data.width / 3;
  67. } else if (this.data.params.style == '2') {
  68. this.height = data.width / 2;
  69. } else if (this.data.params.style == '4') {
  70. this.height = data.width / 4;
  71. } else if (this.data.params.style == '0') {
  72. this.height = data.width / 2;
  73. }
  74. }).exec();
  75. // #endif
  76. },
  77. methods: {
  78. showSliderInfo(type, val) {
  79. if (!val) {
  80. return;
  81. }
  82. if (type == 1) {
  83. if (val.indexOf('http') != -1) {
  84. // #ifdef H5
  85. window.location.href = val
  86. // #endif
  87. } else {
  88. // #ifdef H5 || APP-PLUS || APP-PLUS-NVUE || MP
  89. if (val == '/pages/index/index' || val == '/pages/classify/classify' || val == '/pages/cart/index/index' || val ==
  90. '/pages/member/index/index') {
  91. uni.switchTab({
  92. url: val
  93. });
  94. return;
  95. } else {
  96. this.$common.navigateTo(val);
  97. return;
  98. }
  99. // #endif
  100. }
  101. } else if (type == 2) {
  102. // 商品详情
  103. this.goodsDetail(val)
  104. } else if (type == 3) {
  105. // 文章详情
  106. this.$common.navigateTo('/pages/article/index?id=' + val + '&id_type=1')
  107. } else if (type == 4) {
  108. // 文章列表
  109. this.$common.navigateTo('/pages/article/list?cid=' + val)
  110. } else if (type == 5) {
  111. //智能表单
  112. this.$common.navigateTo('/pages/form/detail/form?id=' + val)
  113. }
  114. },
  115. //跳转到商品详情页面
  116. goodsDetail: function(id) {
  117. let url = '/pages/goods/index/index?id=' + id;
  118. this.$common.navigateTo(url);
  119. },
  120. }
  121. }
  122. </script>
  123. <style>
  124. .imgwindow {
  125. width: 100%;
  126. }
  127. .imgwindow-list {
  128. overflow: hidden;
  129. /* margin: -16upx; */
  130. }
  131. /* 堆积两列 */
  132. .imgwindow-list .imgwindow-item {
  133. height: auto;
  134. float: left;
  135. /* padding: 8upx; */
  136. }
  137. .imgwindow-list .imgwindow-item image {
  138. width: 100%;
  139. height: 100%;
  140. }
  141. .imgwindow-list.row0 .imgwindow-item:first-child {
  142. width: 50%;
  143. }
  144. .imgwindow-list.row0 .imgwindow-item:nth-child(2) {
  145. width: 50%;
  146. }
  147. .imgwindow-list.row0 .imgwindow-item:nth-child(3),
  148. .imgwindow-list.row0 .imgwindow-item:nth-child(4) {
  149. width: 25%;
  150. }
  151. .imgwindow-list.row2 .imgwindow-item {
  152. width: 50%;
  153. }
  154. .imgwindow-list.row3 .imgwindow-item {
  155. width: 33.3%;
  156. }
  157. .imgwindow-list.row4 .imgwindow-item {
  158. width: 25%;
  159. }
  160. </style>
jshop-navBar.vue
复制代码
  1. <template>
  2. <view class="imgnavbar bottom-cell-group">
  3. <view class="imgnavbar-list" v-if="data.params.limit == '3' ||data.params.limit == '4' ||data.params.limit == '5'"
  4. v-bind:class="'row'+data.params.limit">
  5. <view class="imgnavbar-item" ref="imgwitem" v-for="(item, index) in data.params.list" :key="index">
  6. <image class="imgnavbar-item-img" :src="item.image" mode="aspectFill" @click="showSliderInfo(item.linkType, item.linkValue)"></image>
  7. <view class="imgnavbar-item-text">{{item.text}}</view>
  8. </view>
  9. </view>
  10. </view>
  11. </template>
  12. <script>
  13. export default {
  14. name: "jshopnavbar",
  15. props: {
  16. data: {
  17. // type: Object,
  18. required: true,
  19. }
  20. },
  21. data() {
  22. return {
  23. height: '',
  24. height1: ''
  25. }
  26. },
  27. onLoad() {
  28. },
  29. mounted() {
  30. },
  31. methods: {
  32. showSliderInfo(type, val) {
  33. if (!val) {
  34. return;
  35. }
  36. if (type == 1) {
  37. if (val.indexOf('http') != -1) {
  38. // #ifdef H5
  39. window.location.href = val
  40. // #endif
  41. } else {
  42. // #ifdef H5 || APP-PLUS || APP-PLUS-NVUE || MP
  43. if (val == '/pages/index/index' || val == '/pages/classify/classify' || val == '/pages/cart/index/index' || val == '/pages/member/index/index') {
  44. uni.switchTab({
  45. url: val
  46. });
  47. return;
  48. } else {
  49. this.$common.navigateTo(val);
  50. return;
  51. }
  52. // #endif
  53. }
  54. } else if (type == 2) {
  55. // 商品详情
  56. this.goodsDetail(val)
  57. } else if (type == 3) {
  58. // 文章详情
  59. this.$common.navigateTo('/pages/article/index?id=' + val + '&id_type=1')
  60. } else if (type == 4) {
  61. // 文章列表
  62. this.$common.navigateTo('/pages/article/list?cid=' + val)
  63. } else if (type == 5) {
  64. //智能表单
  65. this.$common.navigateTo('/pages/form/detail/form?id=' + val)
  66. }
  67. },
  68. //跳转到商品详情页面
  69. goodsDetail: function(id) {
  70. let url = '/pages/goods/index/index?id=' + id;
  71. this.$common.navigateTo(url);
  72. },
  73. }
  74. }
  75. </script>
  76. <style>
  77. .imgnavbar {
  78. width: 100%;
  79. background-color: #fff;
  80. }
  81. .imgnavbar-list {
  82. overflow: hidden;
  83. padding: 24upx 0 0;
  84. }
  85. /* 堆积两列 */
  86. .imgnavbar-list .imgnavbar-item {
  87. height: auto;
  88. float: left;
  89. padding: 0upx 10upx;
  90. margin-bottom: 20upx;
  91. text-align: center;
  92. }
  93. .imgnavbar-list .imgnavbar-item image {
  94. width: 90upx;
  95. height: 90upx;
  96. margin-bottom: 6upx;
  97. }
  98. .imgnavbar-item-text {
  99. font-size: 26upx;
  100. color: #666;
  101. width: 100%;
  102. overflow: hidden;
  103. text-overflow: ellipsis;
  104. white-space: nowrap;
  105. }
  106. .imgnavbar-list.row3 .imgnavbar-item {
  107. width: 33.3%;
  108. }
  109. .imgnavbar-list.row4 .imgnavbar-item {
  110. width: 25%;
  111. }
  112. .imgnavbar-list.row5 .imgnavbar-item {
  113. width: 20%;
  114. }
  115. .imgnavbar-list.row5 .imgnavbar-item .imgnavbar-item-text {
  116. font-size: 24upx;
  117. }
  118. </style>
jshop-notice.vue
复制代码
  1. <template>
  2. <view class="notice bottom-cell-group" v-if="data.params.list && data.params.list.length > 0">
  3. <view class="notice-icon">
  4. <image class="icon news-icon" src="/static/image/news.png" mode=""></image>
  5. </view>
  6. <swiper class="notice-c" :indicator-dots="false" :autoplay="true" :interval="3000" :duration="1000" :vertical="true" :circular="true">
  7. <swiper-item v-for="item in data.params.list" :key="item.id">
  8. <view class="swiper-item" @click="goNotice(item.id)">{{ item.title }}</view>
  9. </swiper-item>
  10. </swiper>
  11. </view>
  12. </template>
  13. <script>
  14. export default {
  15. name: "jshopnotice",
  16. props: {
  17. data:{
  18. // type: Object,
  19. required: true,
  20. }
  21. },
  22. methods: {
  23. // 点击公告
  24. goNotice(id) {
  25. // 文章详情
  26. this.$common.navigateTo('/pages/article/index?id=' + id+'&id_type=2')
  27. },
  28. },
  29. }
  30. </script>
  31. <style>
  32. .notice {
  33. padding: 6upx 26upx 6upx 60upx;
  34. position: relative;
  35. overflow: hidden;
  36. background-color: #fff;
  37. color: #333;
  38. }
  39. .notice-icon {
  40. display: inline-block;
  41. height: 40upx;
  42. position: absolute;
  43. top: 59%;
  44. left: 26upx;
  45. transform: translateY(-50%);
  46. overflow: hidden;
  47. }
  48. .news-icon {
  49. width: 30upx;
  50. height: 30upx;
  51. float: left;
  52. }
  53. .notice-c {
  54. margin-left: 10upx;
  55. height: 50upx;
  56. line-height: 50upx;
  57. width: 630upx;
  58. display: inline-block;
  59. font-size: 28upx;
  60. float: left;
  61. }
  62. </style>
jshop-pintuan.vue
复制代码
  1. <template>
  2. <!-- 拼团 -->
  3. <view class="img-list bottom-cell-group group-buying" v-if="data.params.list && data.params.list.length > 0">
  4. <view class='cell-item right-img'>
  5. <view class='cell-item-hd group-title'>
  6. {{data.params.title}}
  7. </view>
  8. </view>
  9. <view class='swiper-grids' >
  10. <scroll-view class='swiper-list' scroll-x="true">
  11. <view class="img-list-item" v-if="item.goods_id !== 'undefined' && item.goods_id" v-for="(item, key) in data.params.list" :key="key">
  12. <image class="img-list-item-l medium-img have-none" :src="item.goods_image" mode='aspectFill' @click="pintuanDetail(item.goods_id)"></image>
  13. <view class="img-list-item-r medium-right">
  14. <view class="goods-name list-goods-name" @click="pintuanDetail(item.goods_id)">{{item.goods_name}}</view>
  15. <view class="goods-item-c">
  16. <view class="goods-price red-price">¥{{item.pintuan_price}}</view>
  17. <view class="goods-buy">
  18. <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>
  19. <view class="goods-salesvolume red-price" v-if="item.pintuan_start_status == 3">已结束</view>
  20. <view class="goods-salesvolume red-price" v-if="item.pintuan_start_status == 2">即将开团</view>
  21. <image class="goods-cart" src="/static/image/ic-car.png" @click="pintuanDetail(item.goods.id)"></image>
  22. </view>
  23. </view>
  24. </view>
  25. </view>
  26. </scroll-view>
  27. </view>
  28. </view>
  29. </template>
  30. <script>
  31. import uniCountdown from "@/components/uni-countdown/uni-countdown.vue"
  32. import {goods} from '@/config/mixins.js'
  33. export default {
  34. mixins: [goods],
  35. components:{uniCountdown},
  36. name: "jshoppintuan",
  37. props: {
  38. data:{
  39. // type: Array,
  40. required: false,
  41. }
  42. },
  43. methods: {
  44. },
  45. }
  46. </script>
  47. <style>
  48. .img-list, .img-grids {
  49. background-color: #fff;
  50. }
  51. .cell-item{
  52. border: none;
  53. }
  54. .group-buying .img-list-item{
  55. min-height: 236upx;
  56. padding: 20upx;
  57. margin-left: 26upx;
  58. margin-bottom: 26upx;
  59. display: inline-table;
  60. background-color: #f9f9f9;
  61. }
  62. .swiper-grids .img-list-item:last-child{
  63. margin-right: 26upx;
  64. }
  65. /* .group-buying .goods-name{
  66. min-height: 74upx;
  67. } */
  68. .group-buying .group-title{
  69. width: 100%;
  70. overflow: hidden;
  71. text-overflow: ellipsis;
  72. white-space: nowrap;
  73. }
  74. </style>
jshop-record.vue
复制代码
  1. <template>
  2. <view class="adbrathing"
  3. v-show="adbshow"
  4. v-bind:class="['adbrathing'+data.params.style.align,!hideanimation?'pc':hideanimation?'hc':'']"
  5. :style="{top:data.params.style.top+'%'}" >
  6. <view class="adbrathing-c">
  7. <view class="adbrathing-l">
  8. <image class="user-head-img" :src="log.avatar" mode="aspectFill"></image>
  9. <view class="user-name">
  10. {{log.nickname}}
  11. </view>
  12. </view>
  13. <view class="adbrathing-r">
  14. {{log.ctime}}{{log.desc}}
  15. </view>
  16. </view>
  17. </view>
  18. </template>
  19. <script>
  20. import { apiBaseUrl } from '@/config/config.js';
  21. export default {
  22. name: "jshoprecord",
  23. props: {
  24. data:{
  25. // type: Object,
  26. required: true,
  27. },
  28. //记录显示的位置类型
  29. ltype:{
  30. type: String,
  31. required: false,
  32. default:'home',
  33. },
  34. //记录显示的位置的值
  35. lvalue:{
  36. type: String,
  37. required: false,
  38. default:'0',
  39. }
  40. },
  41. data() {
  42. return {
  43. adbshow:false,
  44. hideanimation: true,
  45. log:{
  46. avatar:'/static/demo-img/user-head.jpg',
  47. nickname:'',
  48. desc:'',
  49. ctime:'',
  50. },
  51. times:{},//定时器
  52. };
  53. },
  54. methods:{
  55. //隐藏
  56. hideLog(){
  57. var _this = this;
  58. _this.times = setInterval(function(){
  59. _this.adbshow = !_this.adbshow;
  60. _this.hideanimation = !_this.hideanimation;
  61. clearInterval(_this.times);
  62. _this.times = setInterval(function(){
  63. _this.getRecod();
  64. },5000);
  65. },3000)
  66. },
  67. //获取日志
  68. getRecod(){
  69. var _this = this;
  70. if(_this.times !={}){
  71. clearInterval(_this.times);
  72. }
  73. var data = {
  74. type:_this.ltype,
  75. value:_this.lvalue,
  76. method:'pages.getrecod',
  77. };
  78. uni.request({
  79. url: apiBaseUrl+'api.html',
  80. data: data,
  81. header: {
  82. 'Accept': 'application/json',
  83. 'Content-Type': 'application/json',
  84. },
  85. method: 'POST',
  86. success: (response) => {
  87. var res = response.data;
  88. if(res.status == true){
  89. if(res.data){
  90. _this.log = res.data;
  91. _this.adbshow = true;
  92. _this.hideanimation = false;
  93. _this.hideLog();
  94. }
  95. }
  96. }
  97. });
  98. }
  99. },
  100. mounted() {
  101. this.getRecod();
  102. }
  103. }
  104. </script>
  105. <style lang="scss">
  106. .adbrathing{
  107. position: fixed;
  108. // top: 100px;
  109. // right: 30upx;
  110. // max-width: 400upx;
  111. height: 70upx;
  112. background-color: rgba(0,0,0,.5);
  113. border-radius: 10upx;
  114. padding: 10upx;
  115. z-index: 666;
  116. .adbrathing-c{
  117. width: 100%;
  118. height: 100%;
  119. overflow: hidden;
  120. color: #fff;
  121. font-size: 24upx;
  122. .adbrathing-l{
  123. display: inline-block;
  124. height: 100%;
  125. float: left;
  126. overflow: hidden;
  127. .user-head-img{
  128. width: 50upx;
  129. height: 50upx;
  130. border-radius: 50%;
  131. float: left;
  132. }
  133. .user-name{
  134. float: left;
  135. display: inline-block;
  136. height: 100%;
  137. line-height: 50upx;
  138. margin: 0 4upx 0 10upx;
  139. max-width: 120upx;
  140. overflow: hidden;
  141. text-overflow: ellipsis;
  142. white-space: nowrap;
  143. }
  144. }
  145. .adbrathing-r{
  146. float: left;
  147. height: 100%;
  148. display: inline-block;
  149. line-height: 50upx;
  150. }
  151. }
  152. }
  153. .adbrathingleft{
  154. left: 30upx
  155. }
  156. .adbrathingright{
  157. right: 30upx
  158. }
  159. .pc{
  160. animation: showcenter .55s;
  161. }
  162. .hc{
  163. animation: hidecenter .55s;
  164. }
  165. @keyframes showcenter{
  166. 0% {
  167. opacity: 0;
  168. }
  169. 100% {
  170. opacity: 1;
  171. }
  172. }
  173. @keyframes hidecenter{
  174. 0% {
  175. opacity: 1;
  176. }
  177. 100% {
  178. opacity: 0;
  179. }
  180. }
  181. </style>
jshop-search.vue
复制代码
  1. <template>
  2. <view class="" >
  3. <!-- 搜索框 -->
  4. <view class="search" ref="searchBar" id="search">
  5. <view class='search-c' @click='goSearch()'>
  6. <view class='search-input search-input-p' v-bind:class="data.params.style">
  7. <view class="search-input-p-c">
  8. {{data.params.keywords}}
  9. </view>
  10. </view>
  11. <image class='icon search-icon' src='/static/image/zoom.png'></image>
  12. </view>
  13. </view>
  14. <!-- 搜索框 -->
  15. <view class="search search-fixed" v-show="searchFixed">
  16. <view class='search-c' @click='goSearch()'>
  17. <view class='search-input search-input-p' v-bind:class="data.params.style">
  18. <view class="search-input-p-c">
  19. {{data.params.keywords}}
  20. </view>
  21. </view>
  22. <image class='icon search-icon' src='/static/image/zoom.png'></image>
  23. </view>
  24. </view>
  25. </view>
  26. </template>
  27. <script>
  28. export default {
  29. name: "jshopsearch",
  30. props: {
  31. data:{
  32. // type: Object,
  33. required: true,
  34. }
  35. },
  36. data() {
  37. return {
  38. keyword:'',
  39. searchTop: 0,
  40. scrollTop: 0,
  41. searchFixed: false
  42. };
  43. },
  44. onLoad() {
  45. },
  46. created() {
  47. //#ifdef H5
  48. this.$nextTick(() => {
  49. this.searchTop = this.$refs.searchBar.$el.offsetTop;
  50. })
  51. // #endif
  52. this.searchStyle()
  53. },
  54. mounted() {
  55. // #ifdef H5
  56. window.addEventListener('scroll', this.handleScroll)
  57. // #endif
  58. },
  59. methods: {
  60. searchStyle (){
  61. this.$store.commit('searchStyle',this.data.params.style)
  62. // console.log(this.data.params.style)
  63. },
  64. goSearch() {
  65. uni.navigateTo({
  66. url: '/pages/index/search'
  67. });
  68. },
  69. handleScroll() {
  70. this.scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
  71. this.scrollTop >= this.searchTop? this.searchFixed = true : this.searchFixed = false;
  72. },
  73. },
  74. onPageScroll(){
  75. var _this = this;
  76. // #ifdef MP-WEIXIN || APP-PLUS
  77. const query = uni.createSelectorQuery().in(this)
  78. query.select('.search').boundingClientRect(function(res){
  79. if(res.top<0){
  80. _this.searchFixed = true ;
  81. }else{
  82. _this.searchFixed = false;
  83. }
  84. }).exec()
  85. // #endif
  86. }
  87. }
  88. </script>
  89. <style>
  90. .search-input-p {
  91. color: #888;
  92. }
  93. .square{
  94. border-radius: 0;
  95. }
  96. .radius{
  97. border-radius: 12upx;
  98. }
  99. .search-fixed{
  100. position: fixed;
  101. top: 0;
  102. /* background: linear-gradient(rgba(0, 0, 0, .5), rgba(0, 0, 0, 0)); */
  103. transition: all .5s;
  104. }
  105. /* .isOpacity {
  106. background: linear-gradient(rgba(0, 0, 0, .5), rgba(0, 0, 0, 0));
  107. transition: all .5s;
  108. }
  109. .isOpacity .search-input {
  110. background-color: rgba(255, 255, 255, .5);
  111. transition: all .5s;
  112. } */
  113. </style>
jshop-textarea.vue
复制代码
  1. <template>
  2. <view class="textarea bottom-cell-group" >
  3. <jshopContent :content="data.params" v-if="data.params"></jshopContent>
  4. </view>
  5. </template>
  6. <script>
  7. import htmlParser from '@/common/html-parser'
  8. import jshopContent from '@/components/jshop/jshop-content.vue'//视频和文本解析组件
  9. export default {
  10. components: {
  11. jshopContent
  12. },
  13. name: "jshoptextarea",
  14. props: {
  15. data:{
  16. // type: Object,
  17. required: true,
  18. }
  19. },
  20. created() {
  21. //this.data.params = htmlParser(this.data.params)
  22. },
  23. onLoad() {
  24. },
  25. methods: {
  26. }
  27. }
  28. </script>
  29. <style>
  30. .textarea{
  31. width: 100%;
  32. background-color: #fff;
  33. padding: 10upx 26upx;
  34. /* height: 40upx; */
  35. }
  36. .textarea p img{
  37. width: 100% !important;
  38. }
  39. .textarea div{
  40. background-color: #000;
  41. }
  42. .textarea p {
  43. background-color: #000;
  44. }
  45. </style>
jshop-video.vue
复制代码
  1. <template>
  2. <view class="video bottom-cell-group" >
  3. <video :src="data.params.list[0].url" :poster="data.params.list[0].image" controls :autoplay='data.params.autoplay'></video>
  4. </view>
  5. </template>
  6. <script>
  7. export default {
  8. name: "jshopvideo",
  9. props: {
  10. data:{
  11. type: Object,
  12. required: true,
  13. }
  14. },
  15. onLoad(){
  16. },
  17. methods: {
  18. }
  19. }
  20. </script>
  21. <style>
  22. .video video{
  23. width: 100%;
  24. min-height: 200upx;
  25. }
  26. </style>
jshop.vue
复制代码
  1. <template>
  2. <view>
  3. <block v-for="(item,index) in data" :key="index">
  4. <jshopsearch :data="item" v-if="item.widget_code=='search' "></jshopsearch>
  5. <jshopnotice :data="item" v-if="item.widget_code=='notice' "></jshopnotice>
  6. <jshopimgSlide :data="item" v-if="item.widget_code=='imgSlide' "></jshopimgSlide>
  7. <jshopcoupon :data="item" v-if="item.widget_code=='coupon' "></jshopcoupon>
  8. <jshopblank :data="item" v-if="item.widget_code=='blank' "></jshopblank>
  9. <jshoptextarea :data="item" v-if="item.widget_code=='textarea' "></jshoptextarea>
  10. <jshopvideo :data="item" v-if="item.widget_code=='video' "></jshopvideo>
  11. <jshopimgWindow :data="item" v-if="item.widget_code=='imgWindow' "></jshopimgWindow>
  12. <jshopimgSingle :data="item" v-if="item.widget_code=='imgSingle' "></jshopimgSingle>
  13. <jshopgoods :data="item" v-if="item.widget_code=='goods' "></jshopgoods>
  14. <jshoparticle :data="item" v-if="item.widget_code=='article' "></jshoparticle>
  15. <jshoparticleClassify :data="item" v-if="item.widget_code=='articleClassify' "></jshoparticleClassify>
  16. <jshopnavBar :data="item" v-if="item.widget_code=='navBar' "></jshopnavBar>
  17. <jshopgroupPurchase :data="item" v-if="item.widget_code=='groupPurchase' "></jshopgroupPurchase>
  18. <jshoprecord :data="item" v-if="item.widget_code=='record' "></jshoprecord>
  19. <jshoppintuan :data="item" v-if="item.widget_code=='pintuan' "></jshoppintuan>
  20. </block>
  21. </view>
  22. </template>
  23. <script>
  24. /**
  25. * 吉海科技jshop小程序插件集合。
  26. * author:novice
  27. * date:2019:05:20
  28. */
  29. import uniCountdown from '@/components/uni-countdown/uni-countdown.vue'
  30. import jshopimgSlide from '@/components/jshop/jshop-imgSlide.vue'
  31. import jshopsearch from '@/components/jshop/jshop-search.vue'
  32. import jshopnotice from '@/components/jshop/jshop-notice.vue'
  33. import jshopcoupon from '@/components/jshop/jshop-coupon.vue'
  34. import jshopblank from '@/components/jshop/jshop-blank.vue'
  35. import jshoptextarea from '@/components/jshop/jshop-textarea.vue'
  36. import jshopvideo from '@/components/jshop/jshop-video.vue'
  37. import jshopimgWindow from '@/components/jshop/jshop-imgWindow.vue'
  38. import jshopimgSingle from '@/components/jshop/jshop-imgSingle.vue'
  39. import jshopgoods from '@/components/jshop/jshop-goods.vue'
  40. import jshoparticle from '@/components/jshop/jshop-article.vue'
  41. import jshoparticleClassify from '@/components/jshop/jshop-articleClassify.vue'
  42. import jshopnavBar from '@/components/jshop/jshop-navBar.vue'
  43. import jshopgroupPurchase from '@/components/jshop/jshop-groupPurchase.vue'
  44. import jshoprecord from '@/components/jshop/jshop-record.vue'
  45. import jshoppintuan from '@/components/jshop/jshop-pintuan.vue'
  46. export default {
  47. name: 'jshop',
  48. components: {
  49. jshopimgSlide,
  50. jshopsearch,
  51. jshopnotice,
  52. jshopcoupon,
  53. jshopblank,
  54. jshoptextarea,
  55. jshopvideo,
  56. jshopimgWindow,
  57. jshopimgSingle,
  58. jshopgoods,
  59. jshoparticle,
  60. jshoparticleClassify,
  61. jshopnavBar,
  62. jshopgroupPurchase,
  63. jshoprecord,
  64. jshoppintuan
  65. },
  66. props: {
  67. data: {
  68. default: function() {
  69. return []
  70. }
  71. }
  72. }
  73. }
  74. </script>

lvv-popup

lvv-popup.vue
复制代码
  1. <template>
  2. <view class="lvv-popup" v-show="popshow" @touchmove.prevent>
  3. <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>
  4. <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':''">
  5. <view class="realcontent" @click.stop="">
  6. <slot></slot>
  7. </view>
  8. </view>
  9. </view>
  10. </template>
  11. <script>
  12. export default {
  13. props:{
  14. position:{
  15. type:String,
  16. default:null
  17. }
  18. },
  19. data() {
  20. return {
  21. popshow:false,
  22. hideanimation:false,
  23. };
  24. },
  25. methods:{
  26. // Toshow popup page
  27. show:function(){
  28. this.popshow = true;
  29. },
  30. // Tohide popup page
  31. close:function(){
  32. let that = this;
  33. this.$emit("close");
  34. that.hideanimation = true;
  35. if(that.position==null){
  36. that.popshow = false;
  37. }else{
  38. setTimeout(function(){
  39. that.popshow = false;
  40. that.hideanimation = false;
  41. },500)
  42. }
  43. }
  44. },
  45. }
  46. </script>
  47. <style lang="scss">
  48. .lvv-popup{
  49. top:0;
  50. left: 0;
  51. width: 100%;
  52. height: 100%;
  53. position: fixed;
  54. z-index: 98;
  55. .lvv-popupmark{
  56. top: 0;
  57. left: 0;
  58. width: 100%;
  59. height: 100%;
  60. z-index: 99;
  61. position: absolute;
  62. background: rgba(0,0,0,0.5);
  63. }
  64. .lvv-popupmark.pt,.lvv-popupmark.ht{
  65. background: none
  66. }
  67. .lvv-popupcontent{
  68. width: 100%;
  69. height: 100%;
  70. top:0;
  71. left:0;
  72. position: absolute;
  73. z-index: 100;
  74. // overflow-y:;
  75. }
  76. .pt{
  77. animation: showtop 0.5s;
  78. }
  79. .pl{
  80. animation: showleft 0.5s;
  81. }
  82. .pr{
  83. animation: showright 0.5s;
  84. }
  85. .pb{
  86. animation: showbottom .5s;
  87. }
  88. .ht{
  89. animation: hidetop 0.5s;
  90. }
  91. .hl{
  92. animation: hideleft 0.55s;
  93. }
  94. .hr{
  95. animation: hideright 0.55s;
  96. }
  97. .hb{
  98. animation: hidebottom 1s;
  99. }
  100. .pc{
  101. animation: showcontent .55s;
  102. }
  103. .hc{
  104. animation: hidecontent .55s;
  105. }
  106. }
  107. @keyframes showtop{
  108. 0% {
  109. // top: -0px;
  110. transform: translateY(-100%);
  111. // height: 0;
  112. opacity: 1;
  113. }
  114. 100% {
  115. top: 0px;
  116. // height: 100%;
  117. transform: translateY(0%);
  118. opacity: 1;
  119. }
  120. }
  121. @keyframes showleft{
  122. 0% {
  123. transform: translateX(-100%);
  124. opacity: 1;
  125. }
  126. 50% {
  127. opacity: 0;
  128. }
  129. 100% {
  130. transform: translateX(0);
  131. }
  132. }
  133. @keyframes showright{
  134. 0% {
  135. transform: translateX(100%);
  136. opacity: 1;
  137. }
  138. 50% {
  139. opacity: 0;
  140. }
  141. 100% {
  142. transform: translateX(0);
  143. }
  144. }
  145. @keyframes showbottom{
  146. 0% {
  147. transform: translateY(100%);
  148. opacity: 1;
  149. }
  150. 50% {
  151. opacity: 0.5;
  152. }
  153. 100% {
  154. transform: translateY(0);
  155. }
  156. }
  157. @keyframes hidetop{
  158. 0% {
  159. transform: translateY(0%);
  160. // height: 100%;
  161. opacity: 1;
  162. }
  163. 100% {
  164. transform: translateY(-100%);
  165. // height: 0;
  166. opacity: 1;
  167. }
  168. }
  169. @keyframes hideleft{
  170. 0% {
  171. transform: translateX(0);
  172. }
  173. 50% {
  174. opacity: 0;
  175. }
  176. 100% {
  177. transform: translateX(-100%);
  178. opacity: 1;
  179. }
  180. }
  181. @keyframes hideright{
  182. 0% {
  183. transform: translateX(0);
  184. }
  185. 50% {
  186. opacity: 0;
  187. }
  188. 100% {
  189. transform: translateX(100%);
  190. opacity: 1;
  191. }
  192. }
  193. @keyframes hidebottom{
  194. 0% {
  195. transform: translateY(0);
  196. }
  197. 50% {
  198. opacity: 0;
  199. }
  200. 100% {
  201. transform: translateY(100%);
  202. opacity: 1;
  203. }
  204. }
  205. @keyframes showcontent{
  206. 0% {
  207. opacity: 0;
  208. }
  209. 100% {
  210. opacity: 1;
  211. }
  212. }
  213. @keyframes hidecontent{
  214. 0% {
  215. opacity: 1;
  216. }
  217. 100% {
  218. opacity: 0;
  219. }
  220. }
  221. </style>

mpvue-citypicker

city-data
area.js
复制代码
  1. /* eslint-disable */
  2. var areaData = [
  3. [
  4. [{
  5. "label": "东城区",
  6. "value": "110101"
  7. }, {
  8. "label": "西城区",
  9. "value": "110102"
  10. }, {
  11. "label": "朝阳区",
  12. "value": "110105"
  13. }, {
  14. "label": "丰台区",
  15. "value": "110106"
  16. }, {
  17. "label": "石景山区",
  18. "value": "110107"
  19. }, {
  20. "label": "海淀区",
  21. "value": "110108"
  22. }, {
  23. "label": "门头沟区",
  24. "value": "110109"
  25. }, {
  26. "label": "房山区",
  27. "value": "110111"
  28. }, {
  29. "label": "通州区",
  30. "value": "110112"
  31. }, {
  32. "label": "顺义区",
  33. "value": "110113"
  34. }, {
  35. "label": "昌平区",
  36. "value": "110114"
  37. }, {
  38. "label": "大兴区",
  39. "value": "110115"
  40. }, {
  41. "label": "怀柔区",
  42. "value": "110116"
  43. }, {
  44. "label": "平谷区",
  45. "value": "110117"
  46. }, {
  47. "label": "密云区",
  48. "value": "110118"
  49. }, {
  50. "label": "延庆区",
  51. "value": "110119"
  52. }]
  53. ],
  54. [
  55. [{
  56. "label": "和平区",
  57. "value": "120101"
  58. }, {
  59. "label": "河东区",
  60. "value": "120102"
  61. }, {
  62. "label": "河西区",
  63. "value": "120103"
  64. }, {
  65. "label": "南开区",
  66. "value": "120104"
  67. }, {
  68. "label": "河北区",
  69. "value": "120105"
  70. }, {
  71. "label": "红桥区",
  72. "value": "120106"
  73. }, {
  74. "label": "东丽区",
  75. "value": "120110"
  76. }, {
  77. "label": "西青区",
  78. "value": "120111"
  79. }, {
  80. "label": "津南区",
  81. "value": "120112"
  82. }, {
  83. "label": "北辰区",
  84. "value": "120113"
  85. }, {
  86. "label": "武清区",
  87. "value": "120114"
  88. }, {
  89. "label": "宝坻区",
  90. "value": "120115"
  91. }, {
  92. "label": "滨海新区",
  93. "value": "120116"
  94. }, {
  95. "label": "宁河区",
  96. "value": "120117"
  97. }, {
  98. "label": "静海区",
  99. "value": "120118"
  100. }, {
  101. "label": "蓟州区",
  102. "value": "120119"
  103. }]
  104. ],
  105. [
  106. [{
  107. "label": "市辖区",
  108. "value": "130101"
  109. }, {
  110. "label": "长安区",
  111. "value": "130102"
  112. }, {
  113. "label": "桥西区",
  114. "value": "130104"
  115. }, {
  116. "label": "新华区",
  117. "value": "130105"
  118. }, {
  119. "label": "井陉矿区",
  120. "value": "130107"
  121. }, {
  122. "label": "裕华区",
  123. "value": "130108"
  124. }, {
  125. "label": "藁城区",
  126. "value": "130109"
  127. }, {
  128. "label": "鹿泉区",
  129. "value": "130110"
  130. }, {
  131. "label": "栾城区",
  132. "value": "130111"
  133. }, {
  134. "label": "井陉县",
  135. "value": "130121"
  136. }, {
  137. "label": "正定县",
  138. "value": "130123"
  139. }, {
  140. "label": "行唐县",
  141. "value": "130125"
  142. }, {
  143. "label": "灵寿县",
  144. "value": "130126"
  145. }, {
  146. "label": "高邑县",
  147. "value": "130127"
  148. }, {
  149. "label": "深泽县",
  150. "value": "130128"
  151. }, {
  152. "label": "赞皇县",
  153. "value": "130129"
  154. }, {
  155. "label": "无极县",
  156. "value": "130130"
  157. }, {
  158. "label": "平山县",
  159. "value": "130131"
  160. }, {
  161. "label": "元氏县",
  162. "value": "130132"
  163. }, {
  164. "label": "赵县",
  165. "value": "130133"
  166. }, {
  167. "label": "晋州市",
  168. "value": "130183"
  169. }, {
  170. "label": "新乐市",
  171. "value": "130184"
  172. }],
  173. [{
  174. "label": "市辖区",
  175. "value": "130201"
  176. }, {
  177. "label": "路南区",
  178. "value": "130202"
  179. }, {
  180. "label": "路北区",
  181. "value": "130203"
  182. }, {
  183. "label": "古冶区",
  184. "value": "130204"
  185. }, {
  186. "label": "开平区",
  187. "value": "130205"
  188. }, {
  189. "label": "丰南区",
  190. "value": "130207"
  191. }, {
  192. "label": "丰润区",
  193. "value": "130208"
  194. }, {
  195. "label": "曹妃甸区",
  196. "value": "130209"
  197. }, {
  198. "label": "滦县",
  199. "value": "130223"
  200. }, {
  201. "label": "滦南县",
  202. "value": "130224"
  203. }, {
  204. "label": "乐亭县",
  205. "value": "130225"
  206. }, {
  207. "label": "迁西县",
  208. "value": "130227"
  209. }, {
  210. "label": "玉田县",
  211. "value": "130229"
  212. }, {
  213. "label": "遵化市",
  214. "value": "130281"
  215. }, {
  216. "label": "迁安市",
  217. "value": "130283"
  218. }],
  219. [{
  220. "label": "市辖区",
  221. "value": "130301"
  222. }, {
  223. "label": "海港区",
  224. "value": "130302"
  225. }, {
  226. "label": "山海关区",
  227. "value": "130303"
  228. }, {
  229. "label": "北戴河区",
  230. "value": "130304"
  231. }, {
  232. "label": "抚宁区",
  233. "value": "130306"
  234. }, {
  235. "label": "青龙满族自治县",
  236. "value": "130321"
  237. }, {
  238. "label": "昌黎县",
  239. "value": "130322"
  240. }, {
  241. "label": "卢龙县",
  242. "value": "130324"
  243. }],
  244. [{
  245. "label": "市辖区",
  246. "value": "130401"
  247. }, {
  248. "label": "邯山区",
  249. "value": "130402"
  250. }, {
  251. "label": "丛台区",
  252. "value": "130403"
  253. }, {
  254. "label": "复兴区",
  255. "value": "130404"
  256. }, {
  257. "label": "峰峰矿区",
  258. "value": "130406"
  259. }, {
  260. "label": "邯郸县",
  261. "value": "130421"
  262. }, {
  263. "label": "临漳县",
  264. "value": "130423"
  265. }, {
  266. "label": "成安县",
  267. "value": "130424"
  268. }, {
  269. "label": "大名县",
  270. "value": "130425"
  271. }, {
  272. "label": "涉县",
  273. "value": "130426"
  274. }, {
  275. "label": "磁县",
  276. "value": "130427"
  277. }, {
  278. "label": "肥乡县",
  279. "value": "130428"
  280. }, {
  281. "label": "永年县",
  282. "value": "130429"
  283. }, {
  284. "label": "邱县",
  285. "value": "130430"
  286. }, {
  287. "label": "鸡泽县",
  288. "value": "130431"
  289. }, {
  290. "label": "广平县",
  291. "value": "130432"
  292. }, {
  293. "label": "馆陶县",
  294. "value": "130433"
  295. }, {
  296. "label": "魏县",
  297. "value": "130434"
  298. }, {
  299. "label": "曲周县",
  300. "value": "130435"
  301. }, {
  302. "label": "武安市",
  303. "value": "130481"
  304. }],
  305. [{
  306. "label": "市辖区",
  307. "value": "130501"
  308. }, {
  309. "label": "桥东区",
  310. "value": "130502"
  311. }, {
  312. "label": "桥西区",
  313. "value": "130503"
  314. }, {
  315. "label": "邢台县",
  316. "value": "130521"
  317. }, {
  318. "label": "临城县",
  319. "value": "130522"
  320. }, {
  321. "label": "内丘县",
  322. "value": "130523"
  323. }, {
  324. "label": "柏乡县",
  325. "value": "130524"
  326. }, {
  327. "label": "隆尧县",
  328. "value": "130525"
  329. }, {
  330. "label": "任县",
  331. "value": "130526"
  332. }, {
  333. "label": "南和县",
  334. "value": "130527"
  335. }, {
  336. "label": "宁晋县",
  337. "value": "130528"
  338. }, {
  339. "label": "巨鹿县",
  340. "value": "130529"
  341. }, {
  342. "label": "新河县",
  343. "value": "130530"
  344. }, {
  345. "label": "广宗县",
  346. "value": "130531"
  347. }, {
  348. "label": "平乡县",
  349. "value": "130532"
  350. }, {
  351. "label": "威县",
  352. "value": "130533"
  353. }, {
  354. "label": "清河县",
  355. "value": "130534"
  356. }, {
  357. "label": "临西县",
  358. "value": "130535"
  359. }, {
  360. "label": "南宫市",
  361. "value": "130581"
  362. }, {
  363. "label": "沙河市",
  364. "value": "130582"
  365. }],
  366. [{
  367. "label": "市辖区",
  368. "value": "130601"
  369. }, {
  370. "label": "竞秀区",
  371. "value": "130602"
  372. }, {
  373. "label": "莲池区",
  374. "value": "130606"
  375. }, {
  376. "label": "满城区",
  377. "value": "130607"
  378. }, {
  379. "label": "清苑区",
  380. "value": "130608"
  381. }, {
  382. "label": "徐水区",
  383. "value": "130609"
  384. }, {
  385. "label": "涞水县",
  386. "value": "130623"
  387. }, {
  388. "label": "阜平县",
  389. "value": "130624"
  390. }, {
  391. "label": "定兴县",
  392. "value": "130626"
  393. }, {
  394. "label": "唐县",
  395. "value": "130627"
  396. }, {
  397. "label": "高阳县",
  398. "value": "130628"
  399. }, {
  400. "label": "容城县",
  401. "value": "130629"
  402. }, {
  403. "label": "涞源县",
  404. "value": "130630"
  405. }, {
  406. "label": "望都县",
  407. "value": "130631"
  408. }, {
  409. "label": "安新县",
  410. "value": "130632"
  411. }, {
  412. "label": "易县",
  413. "value": "130633"
  414. }, {
  415. "label": "曲阳县",
  416. "value": "130634"
  417. }, {
  418. "label": "蠡县",
  419. "value": "130635"
  420. }, {
  421. "label": "顺平县",
  422. "value": "130636"
  423. }, {
  424. "label": "博野县",
  425. "value": "130637"
  426. }, {
  427. "label": "雄县",
  428. "value": "130638"
  429. }, {
  430. "label": "涿州市",
  431. "value": "130681"
  432. }, {
  433. "label": "安国市",
  434. "value": "130683"
  435. }, {
  436. "label": "高碑店市",
  437. "value": "130684"
  438. }],
  439. [{
  440. "label": "市辖区",
  441. "value": "130701"
  442. }, {
  443. "label": "桥东区",
  444. "value": "130702"
  445. }, {
  446. "label": "桥西区",
  447. "value": "130703"
  448. }, {
  449. "label": "宣化区",
  450. "value": "130705"
  451. }, {
  452. "label": "下花园区",
  453. "value": "130706"
  454. }, {
  455. "label": "万全区",
  456. "value": "130708"
  457. }, {
  458. "label": "崇礼区",
  459. "value": "130709"
  460. }, {
  461. "label": "张北县",
  462. "value": "130722"
  463. }, {
  464. "label": "康保县",
  465. "value": "130723"
  466. }, {
  467. "label": "沽源县",
  468. "value": "130724"
  469. }, {
  470. "label": "尚义县",
  471. "value": "130725"
  472. }, {
  473. "label": "蔚县",
  474. "value": "130726"
  475. }, {
  476. "label": "阳原县",
  477. "value": "130727"
  478. }, {
  479. "label": "怀安县",
  480. "value": "130728"
  481. }, {
  482. "label": "怀来县",
  483. "value": "130730"
  484. }, {
  485. "label": "涿鹿县",
  486. "value": "130731"
  487. }, {
  488. "label": "赤城县",
  489. "value": "130732"
  490. }],
  491. [{
  492. "label": "市辖区",
  493. "value": "130801"
  494. }, {
  495. "label": "双桥区",
  496. "value": "130802"
  497. }, {
  498. "label": "双滦区",
  499. "value": "130803"
  500. }, {
  501. "label": "鹰手营子矿区",
  502. "value": "130804"
  503. }, {
  504. "label": "承德县",
  505. "value": "130821"
  506. }, {
  507. "label": "兴隆县",
  508. "value": "130822"
  509. }, {
  510. "label": "平泉县",
  511. "value": "130823"
  512. }, {
  513. "label": "滦平县",
  514. "value": "130824"
  515. }, {
  516. "label": "隆化县",
  517. "value": "130825"
  518. }, {
  519. "label": "丰宁满族自治县",
  520. "value": "130826"
  521. }, {
  522. "label": "宽城满族自治县",
  523. "value": "130827"
  524. }, {
  525. "label": "围场满族蒙古族自治县",
  526. "value": "130828"
  527. }],
  528. [{
  529. "label": "市辖区",
  530. "value": "130901"
  531. }, {
  532. "label": "新华区",
  533. "value": "130902"
  534. }, {
  535. "label": "运河区",
  536. "value": "130903"
  537. }, {
  538. "label": "沧县",
  539. "value": "130921"
  540. }, {
  541. "label": "青县",
  542. "value": "130922"
  543. }, {
  544. "label": "东光县",
  545. "value": "130923"
  546. }, {
  547. "label": "海兴县",
  548. "value": "130924"
  549. }, {
  550. "label": "盐山县",
  551. "value": "130925"
  552. }, {
  553. "label": "肃宁县",
  554. "value": "130926"
  555. }, {
  556. "label": "南皮县",
  557. "value": "130927"
  558. }, {
  559. "label": "吴桥县",
  560. "value": "130928"
  561. }, {
  562. "label": "献县",
  563. "value": "130929"
  564. }, {
  565. "label": "孟村回族自治县",
  566. "value": "130930"
  567. }, {
  568. "label": "泊头市",
  569. "value": "130981"
  570. }, {
  571. "label": "任丘市",
  572. "value": "130982"
  573. }, {
  574. "label": "黄骅市",
  575. "value": "130983"
  576. }, {
  577. "label": "河间市",
  578. "value": "130984"
  579. }],
  580. [{
  581. "label": "市辖区",
  582. "value": "131001"
  583. }, {
  584. "label": "安次区",
  585. "value": "131002"
  586. }, {
  587. "label": "广阳区",
  588. "value": "131003"
  589. }, {
  590. "label": "固安县",
  591. "value": "131022"
  592. }, {
  593. "label": "永清县",
  594. "value": "131023"
  595. }, {
  596. "label": "香河县",
  597. "value": "131024"
  598. }, {
  599. "label": "大城县",
  600. "value": "131025"
  601. }, {
  602. "label": "文安县",
  603. "value": "131026"
  604. }, {
  605. "label": "大厂回族自治县",
  606. "value": "131028"
  607. }, {
  608. "label": "霸州市",
  609. "value": "131081"
  610. }, {
  611. "label": "三河市",
  612. "value": "131082"
  613. }],
  614. [{
  615. "label": "市辖区",
  616. "value": "131101"
  617. }, {
  618. "label": "桃城区",
  619. "value": "131102"
  620. }, {
  621. "label": "冀州区",
  622. "value": "131103"
  623. }, {
  624. "label": "枣强县",
  625. "value": "131121"
  626. }, {
  627. "label": "武邑县",
  628. "value": "131122"
  629. }, {
  630. "label": "武强县",
  631. "value": "131123"
  632. }, {
  633. "label": "饶阳县",
  634. "value": "131124"
  635. }, {
  636. "label": "安平县",
  637. "value": "131125"
  638. }, {
  639. "label": "故城县",
  640. "value": "131126"
  641. }, {
  642. "label": "景县",
  643. "value": "131127"
  644. }, {
  645. "label": "阜城县",
  646. "value": "131128"
  647. }, {
  648. "label": "深州市",
  649. "value": "131182"
  650. }],
  651. [{
  652. "label": "市辖区",
  653. "value": "139001"
  654. }, {
  655. "label": "辛集市",
  656. "value": "139002"
  657. }]
  658. ],
  659. [
  660. [{
  661. "label": "市辖区",
  662. "value": "140101"
  663. }, {
  664. "label": "小店区",
  665. "value": "140105"
  666. }, {
  667. "label": "迎泽区",
  668. "value": "140106"
  669. }, {
  670. "label": "杏花岭区",
  671. "value": "140107"
  672. }, {
  673. "label": "尖草坪区",
  674. "value": "140108"
  675. }, {
  676. "label": "万柏林区",
  677. "value": "140109"
  678. }, {
  679. "label": "晋源区",
  680. "value": "140110"
  681. }, {
  682. "label": "清徐县",
  683. "value": "140121"
  684. }, {
  685. "label": "阳曲县",
  686. "value": "140122"
  687. }, {
  688. "label": "娄烦县",
  689. "value": "140123"
  690. }, {
  691. "label": "古交市",
  692. "value": "140181"
  693. }],
  694. [{
  695. "label": "市辖区",
  696. "value": "140201"
  697. }, {
  698. "label": "城区",
  699. "value": "140202"
  700. }, {
  701. "label": "矿区",
  702. "value": "140203"
  703. }, {
  704. "label": "南郊区",
  705. "value": "140211"
  706. }, {
  707. "label": "新荣区",
  708. "value": "140212"
  709. }, {
  710. "label": "阳高县",
  711. "value": "140221"
  712. }, {
  713. "label": "天镇县",
  714. "value": "140222"
  715. }, {
  716. "label": "广灵县",
  717. "value": "140223"
  718. }, {
  719. "label": "灵丘县",
  720. "value": "140224"
  721. }, {
  722. "label": "浑源县",
  723. "value": "140225"
  724. }, {
  725. "label": "左云县",
  726. "value": "140226"
  727. }, {
  728. "label": "大同县",
  729. "value": "140227"
  730. }],
  731. [{
  732. "label": "市辖区",
  733. "value": "140301"
  734. }, {
  735. "label": "城区",
  736. "value": "140302"
  737. }, {
  738. "label": "矿区",
  739. "value": "140303"
  740. }, {
  741. "label": "郊区",
  742. "value": "140311"
  743. }, {
  744. "label": "平定县",
  745. "value": "140321"
  746. }, {
  747. "label": "盂县",
  748. "value": "140322"
  749. }],
  750. [{
  751. "label": "市辖区",
  752. "value": "140401"
  753. }, {
  754. "label": "城区",
  755. "value": "140402"
  756. }, {
  757. "label": "郊区",
  758. "value": "140411"
  759. }, {
  760. "label": "长治县",
  761. "value": "140421"
  762. }, {
  763. "label": "襄垣县",
  764. "value": "140423"
  765. }, {
  766. "label": "屯留县",
  767. "value": "140424"
  768. }, {
  769. "label": "平顺县",
  770. "value": "140425"
  771. }, {
  772. "label": "黎城县",
  773. "value": "140426"
  774. }, {
  775. "label": "壶关县",
  776. "value": "140427"
  777. }, {
  778. "label": "长子县",
  779. "value": "140428"
  780. }, {
  781. "label": "武乡县",
  782. "value": "140429"
  783. }, {
  784. "label": "沁县",
  785. "value": "140430"
  786. }, {
  787. "label": "沁源县",
  788. "value": "140431"
  789. }, {
  790. "label": "潞城市",
  791. "value": "140481"
  792. }],
  793. [{
  794. "label": "市辖区",
  795. "value": "140501"
  796. }, {
  797. "label": "城区",
  798. "value": "140502"
  799. }, {
  800. "label": "沁水县",
  801. "value": "140521"
  802. }, {
  803. "label": "阳城县",
  804. "value": "140522"
  805. }, {
  806. "label": "陵川县",
  807. "value": "140524"
  808. }, {
  809. "label": "泽州县",
  810. "value": "140525"
  811. }, {
  812. "label": "高平市",
  813. "value": "140581"
  814. }],
  815. [{
  816. "label": "市辖区",
  817. "value": "140601"
  818. }, {
  819. "label": "朔城区",
  820. "value": "140602"
  821. }, {
  822. "label": "平鲁区",
  823. "value": "140603"
  824. }, {
  825. "label": "山阴县",
  826. "value": "140621"
  827. }, {
  828. "label": "应县",
  829. "value": "140622"
  830. }, {
  831. "label": "右玉县",
  832. "value": "140623"
  833. }, {
  834. "label": "怀仁县",
  835. "value": "140624"
  836. }],
  837. [{
  838. "label": "市辖区",
  839. "value": "140701"
  840. }, {
  841. "label": "榆次区",
  842. "value": "140702"
  843. }, {
  844. "label": "榆社县",
  845. "value": "140721"
  846. }, {
  847. "label": "左权县",
  848. "value": "140722"
  849. }, {
  850. "label": "和顺县",
  851. "value": "140723"
  852. }, {
  853. "label": "昔阳县",
  854. "value": "140724"
  855. }, {
  856. "label": "寿阳县",
  857. "value": "140725"
  858. }, {
  859. "label": "太谷县",
  860. "value": "140726"
  861. }, {
  862. "label": "祁县",
  863. "value": "140727"
  864. }, {
  865. "label": "平遥县",
  866. "value": "140728"
  867. }, {
  868. "label": "灵石县",
  869. "value": "140729"
  870. }, {
  871. "label": "介休市",
  872. "value": "140781"
  873. }],
  874. [{
  875. "label": "市辖区",
  876. "value": "140801"
  877. }, {
  878. "label": "盐湖区",
  879. "value": "140802"
  880. }, {
  881. "label": "临猗县",
  882. "value": "140821"
  883. }, {
  884. "label": "万荣县",
  885. "value": "140822"
  886. }, {
  887. "label": "闻喜县",
  888. "value": "140823"
  889. }, {
  890. "label": "稷山县",
  891. "value": "140824"
  892. }, {
  893. "label": "新绛县",
  894. "value": "140825"
  895. }, {
  896. "label": "绛县",
  897. "value": "140826"
  898. }, {
  899. "label": "垣曲县",
  900. "value": "140827"
  901. }, {
  902. "label": "夏县",
  903. "value": "140828"
  904. }, {
  905. "label": "平陆县",
  906. "value": "140829"
  907. }, {
  908. "label": "芮城县",
  909. "value": "140830"
  910. }, {
  911. "label": "永济市",
  912. "value": "140881"
  913. }, {
  914. "label": "河津市",
  915. "value": "140882"
  916. }],
  917. [{
  918. "label": "市辖区",
  919. "value": "140901"
  920. }, {
  921. "label": "忻府区",
  922. "value": "140902"
  923. }, {
  924. "label": "定襄县",
  925. "value": "140921"
  926. }, {
  927. "label": "五台县",
  928. "value": "140922"
  929. }, {
  930. "label": "代县",
  931. "value": "140923"
  932. }, {
  933. "label": "繁峙县",
  934. "value": "140924"
  935. }, {
  936. "label": "宁武县",
  937. "value": "140925"
  938. }, {
  939. "label": "静乐县",
  940. "value": "140926"
  941. }, {
  942. "label": "神池县",
  943. "value": "140927"
  944. }, {
  945. "label": "五寨县",
  946. "value": "140928"
  947. }, {
  948. "label": "岢岚县",
  949. "value": "140929"
  950. }, {
  951. "label": "河曲县",
  952. "value": "140930"
  953. }, {
  954. "label": "保德县",
  955. "value": "140931"
  956. }, {
  957. "label": "偏关县",
  958. "value": "140932"
  959. }, {
  960. "label": "原平市",
  961. "value": "140981"
  962. }],
  963. [{
  964. "label": "市辖区",
  965. "value": "141001"
  966. }, {
  967. "label": "尧都区",
  968. "value": "141002"
  969. }, {
  970. "label": "曲沃县",
  971. "value": "141021"
  972. }, {
  973. "label": "翼城县",
  974. "value": "141022"
  975. }, {
  976. "label": "襄汾县",
  977. "value": "141023"
  978. }, {
  979. "label": "洪洞县",
  980. "value": "141024"
  981. }, {
  982. "label": "古县",
  983. "value": "141025"
  984. }, {
  985. "label": "安泽县",
  986. "value": "141026"
  987. }, {
  988. "label": "浮山县",
  989. "value": "141027"
  990. }, {
  991. "label": "吉县",
  992. "value": "141028"
  993. }, {
  994. "label": "乡宁县",
  995. "value": "141029"
  996. }, {
  997. "label": "大宁县",
  998. "value": "141030"
  999. }, {
  1000. "label": "隰县",
  1001. "value": "141031"
  1002. }, {
  1003. "label": "永和县",
  1004. "value": "141032"
  1005. }, {
  1006. "label": "蒲县",
  1007. "value": "141033"
  1008. }, {
  1009. "label": "汾西县",
  1010. "value": "141034"
  1011. }, {
  1012. "label": "侯马市",
  1013. "value": "141081"
  1014. }, {
  1015. "label": "霍州市",
  1016. "value": "141082"
  1017. }],
  1018. [{
  1019. "label": "市辖区",
  1020. "value": "141101"
  1021. }, {
  1022. "label": "离石区",
  1023. "value": "141102"
  1024. }, {
  1025. "label": "文水县",
  1026. "value": "141121"
  1027. }, {
  1028. "label": "交城县",
  1029. "value": "141122"
  1030. }, {
  1031. "label": "兴县",
  1032. "value": "141123"
  1033. }, {
  1034. "label": "临县",
  1035. "value": "141124"
  1036. }, {
  1037. "label": "柳林县",
  1038. "value": "141125"
  1039. }, {
  1040. "label": "石楼县",
  1041. "value": "141126"
  1042. }, {
  1043. "label": "岚县",
  1044. "value": "141127"
  1045. }, {
  1046. "label": "方山县",
  1047. "value": "141128"
  1048. }, {
  1049. "label": "中阳县",
  1050. "value": "141129"
  1051. }, {
  1052. "label": "交口县",
  1053. "value": "141130"
  1054. }, {
  1055. "label": "孝义市",
  1056. "value": "141181"
  1057. }, {
  1058. "label": "汾阳市",
  1059. "value": "141182"
  1060. }]
  1061. ],
  1062. [
  1063. [{
  1064. "label": "市辖区",
  1065. "value": "150101"
  1066. }, {
  1067. "label": "新城区",
  1068. "value": "150102"
  1069. }, {
  1070. "label": "回民区",
  1071. "value": "150103"
  1072. }, {
  1073. "label": "玉泉区",
  1074. "value": "150104"
  1075. }, {
  1076. "label": "赛罕区",
  1077. "value": "150105"
  1078. }, {
  1079. "label": "土默特左旗",
  1080. "value": "150121"
  1081. }, {
  1082. "label": "托克托县",
  1083. "value": "150122"
  1084. }, {
  1085. "label": "和林格尔县",
  1086. "value": "150123"
  1087. }, {
  1088. "label": "清水河县",
  1089. "value": "150124"
  1090. }, {
  1091. "label": "武川县",
  1092. "value": "150125"
  1093. }],
  1094. [{
  1095. "label": "市辖区",
  1096. "value": "150201"
  1097. }, {
  1098. "label": "东河区",
  1099. "value": "150202"
  1100. }, {
  1101. "label": "昆都仑区",
  1102. "value": "150203"
  1103. }, {
  1104. "label": "青山区",
  1105. "value": "150204"
  1106. }, {
  1107. "label": "石拐区",
  1108. "value": "150205"
  1109. }, {
  1110. "label": "白云鄂博矿区",
  1111. "value": "150206"
  1112. }, {
  1113. "label": "九原区",
  1114. "value": "150207"
  1115. }, {
  1116. "label": "土默特右旗",
  1117. "value": "150221"
  1118. }, {
  1119. "label": "固阳县",
  1120. "value": "150222"
  1121. }, {
  1122. "label": "达尔罕茂明安联合旗",
  1123. "value": "150223"
  1124. }],
  1125. [{
  1126. "label": "市辖区",
  1127. "value": "150301"
  1128. }, {
  1129. "label": "海勃湾区",
  1130. "value": "150302"
  1131. }, {
  1132. "label": "海南区",
  1133. "value": "150303"
  1134. }, {
  1135. "label": "乌达区",
  1136. "value": "150304"
  1137. }],
  1138. [{
  1139. "label": "市辖区",
  1140. "value": "150401"
  1141. }, {
  1142. "label": "红山区",
  1143. "value": "150402"
  1144. }, {
  1145. "label": "元宝山区",
  1146. "value": "150403"
  1147. }, {
  1148. "label": "松山区",
  1149. "value": "150404"
  1150. }, {
  1151. "label": "阿鲁科尔沁旗",
  1152. "value": "150421"
  1153. }, {
  1154. "label": "巴林左旗",
  1155. "value": "150422"
  1156. }, {
  1157. "label": "巴林右旗",
  1158. "value": "150423"
  1159. }, {
  1160. "label": "林西县",
  1161. "value": "150424"
  1162. }, {
  1163. "label": "克什克腾旗",
  1164. "value": "150425"
  1165. }, {
  1166. "label": "翁牛特旗",
  1167. "value": "150426"
  1168. }, {
  1169. "label": "喀喇沁旗",
  1170. "value": "150428"
  1171. }, {
  1172. "label": "宁城县",
  1173. "value": "150429"
  1174. }, {
  1175. "label": "敖汉旗",
  1176. "value": "150430"
  1177. }],
  1178. [{
  1179. "label": "市辖区",
  1180. "value": "150501"
  1181. }, {
  1182. "label": "科尔沁区",
  1183. "value": "150502"
  1184. }, {
  1185. "label": "科尔沁左翼中旗",
  1186. "value": "150521"
  1187. }, {
  1188. "label": "科尔沁左翼后旗",
  1189. "value": "150522"
  1190. }, {
  1191. "label": "开鲁县",
  1192. "value": "150523"
  1193. }, {
  1194. "label": "库伦旗",
  1195. "value": "150524"
  1196. }, {
  1197. "label": "奈曼旗",
  1198. "value": "150525"
  1199. }, {
  1200. "label": "扎鲁特旗",
  1201. "value": "150526"
  1202. }, {
  1203. "label": "霍林郭勒市",
  1204. "value": "150581"
  1205. }],
  1206. [{
  1207. "label": "市辖区",
  1208. "value": "150601"
  1209. }, {
  1210. "label": "东胜区",
  1211. "value": "150602"
  1212. }, {
  1213. "label": "康巴什区",
  1214. "value": "150603"
  1215. }, {
  1216. "label": "达拉特旗",
  1217. "value": "150621"
  1218. }, {
  1219. "label": "准格尔旗",
  1220. "value": "150622"
  1221. }, {
  1222. "label": "鄂托克前旗",
  1223. "value": "150623"
  1224. }, {
  1225. "label": "鄂托克旗",
  1226. "value": "150624"
  1227. }, {
  1228. "label": "杭锦旗",
  1229. "value": "150625"
  1230. }, {
  1231. "label": "乌审旗",
  1232. "value": "150626"
  1233. }, {
  1234. "label": "伊金霍洛旗",
  1235. "value": "150627"
  1236. }],
  1237. [{
  1238. "label": "市辖区",
  1239. "value": "150701"
  1240. }, {
  1241. "label": "海拉尔区",
  1242. "value": "150702"
  1243. }, {
  1244. "label": "扎赉诺尔区",
  1245. "value": "150703"
  1246. }, {
  1247. "label": "阿荣旗",
  1248. "value": "150721"
  1249. }, {
  1250. "label": "莫力达瓦达斡尔族自治旗",
  1251. "value": "150722"
  1252. }, {
  1253. "label": "鄂伦春自治旗",
  1254. "value": "150723"
  1255. }, {
  1256. "label": "鄂温克族自治旗",
  1257. "value": "150724"
  1258. }, {
  1259. "label": "陈巴尔虎旗",
  1260. "value": "150725"
  1261. }, {
  1262. "label": "新巴尔虎左旗",
  1263. "value": "150726"
  1264. }, {
  1265. "label": "新巴尔虎右旗",
  1266. "value": "150727"
  1267. }, {
  1268. "label": "满洲里市",
  1269. "value": "150781"
  1270. }, {
  1271. "label": "牙克石市",
  1272. "value": "150782"
  1273. }, {
  1274. "label": "扎兰屯市",
  1275. "value": "150783"
  1276. }, {
  1277. "label": "额尔古纳市",
  1278. "value": "150784"
  1279. }, {
  1280. "label": "根河市",
  1281. "value": "150785"
  1282. }],
  1283. [{
  1284. "label": "市辖区",
  1285. "value": "150801"
  1286. }, {
  1287. "label": "临河区",
  1288. "value": "150802"
  1289. }, {
  1290. "label": "五原县",
  1291. "value": "150821"
  1292. }, {
  1293. "label": "磴口县",
  1294. "value": "150822"
  1295. }, {
  1296. "label": "乌拉特前旗",
  1297. "value": "150823"
  1298. }, {
  1299. "label": "乌拉特中旗",
  1300. "value": "150824"
  1301. }, {
  1302. "label": "乌拉特后旗",
  1303. "value": "150825"
  1304. }, {
  1305. "label": "杭锦后旗",
  1306. "value": "150826"
  1307. }],
  1308. [{
  1309. "label": "市辖区",
  1310. "value": "150901"
  1311. }, {
  1312. "label": "集宁区",
  1313. "value": "150902"
  1314. }, {
  1315. "label": "卓资县",
  1316. "value": "150921"
  1317. }, {
  1318. "label": "化德县",
  1319. "value": "150922"
  1320. }, {
  1321. "label": "商都县",
  1322. "value": "150923"
  1323. }, {
  1324. "label": "兴和县",
  1325. "value": "150924"
  1326. }, {
  1327. "label": "凉城县",
  1328. "value": "150925"
  1329. }, {
  1330. "label": "察哈尔右翼前旗",
  1331. "value": "150926"
  1332. }, {
  1333. "label": "察哈尔右翼中旗",
  1334. "value": "150927"
  1335. }, {
  1336. "label": "察哈尔右翼后旗",
  1337. "value": "150928"
  1338. }, {
  1339. "label": "四子王旗",
  1340. "value": "150929"
  1341. }, {
  1342. "label": "丰镇市",
  1343. "value": "150981"
  1344. }],
  1345. [{
  1346. "label": "市辖区",
  1347. "value": "152201"
  1348. }, {
  1349. "label": "阿尔山市",
  1350. "value": "152202"
  1351. }, {
  1352. "label": "科尔沁右翼前旗",
  1353. "value": "152221"
  1354. }, {
  1355. "label": "科尔沁右翼中旗",
  1356. "value": "152222"
  1357. }, {
  1358. "label": "扎赉特旗",
  1359. "value": "152223"
  1360. }, {
  1361. "label": "突泉县",
  1362. "value": "152224"
  1363. }],
  1364. [{
  1365. "label": "市辖区",
  1366. "value": "152501"
  1367. }, {
  1368. "label": "锡林浩特市",
  1369. "value": "152502"
  1370. }, {
  1371. "label": "阿巴嘎旗",
  1372. "value": "152522"
  1373. }, {
  1374. "label": "苏尼特左旗",
  1375. "value": "152523"
  1376. }, {
  1377. "label": "苏尼特右旗",
  1378. "value": "152524"
  1379. }, {
  1380. "label": "东乌珠穆沁旗",
  1381. "value": "152525"
  1382. }, {
  1383. "label": "西乌珠穆沁旗",
  1384. "value": "152526"
  1385. }, {
  1386. "label": "太仆寺旗",
  1387. "value": "152527"
  1388. }, {
  1389. "label": "镶黄旗",
  1390. "value": "152528"
  1391. }, {
  1392. "label": "正镶白旗",
  1393. "value": "152529"
  1394. }, {
  1395. "label": "正蓝旗",
  1396. "value": "152530"
  1397. }, {
  1398. "label": "多伦县",
  1399. "value": "152531"
  1400. }],
  1401. [{
  1402. "label": "阿拉善左旗",
  1403. "value": "152921"
  1404. }, {
  1405. "label": "阿拉善右旗",
  1406. "value": "152922"
  1407. }, {
  1408. "label": "额济纳旗",
  1409. "value": "152923"
  1410. }]
  1411. ],
  1412. [
  1413. [{
  1414. "label": "市辖区",
  1415. "value": "210101"
  1416. }, {
  1417. "label": "和平区",
  1418. "value": "210102"
  1419. }, {
  1420. "label": "沈河区",
  1421. "value": "210103"
  1422. }, {
  1423. "label": "大东区",
  1424. "value": "210104"
  1425. }, {
  1426. "label": "皇姑区",
  1427. "value": "210105"
  1428. }, {
  1429. "label": "铁西区",
  1430. "value": "210106"
  1431. }, {
  1432. "label": "苏家屯区",
  1433. "value": "210111"
  1434. }, {
  1435. "label": "浑南区",
  1436. "value": "210112"
  1437. }, {
  1438. "label": "沈北新区",
  1439. "value": "210113"
  1440. }, {
  1441. "label": "于洪区",
  1442. "value": "210114"
  1443. }, {
  1444. "label": "辽中区",
  1445. "value": "210115"
  1446. }, {
  1447. "label": "康平县",
  1448. "value": "210123"
  1449. }, {
  1450. "label": "法库县",
  1451. "value": "210124"
  1452. }, {
  1453. "label": "新民市",
  1454. "value": "210181"
  1455. }],
  1456. [{
  1457. "label": "市辖区",
  1458. "value": "210201"
  1459. }, {
  1460. "label": "中山区",
  1461. "value": "210202"
  1462. }, {
  1463. "label": "西岗区",
  1464. "value": "210203"
  1465. }, {
  1466. "label": "沙河口区",
  1467. "value": "210204"
  1468. }, {
  1469. "label": "甘井子区",
  1470. "value": "210211"
  1471. }, {
  1472. "label": "旅顺口区",
  1473. "value": "210212"
  1474. }, {
  1475. "label": "金州区",
  1476. "value": "210213"
  1477. }, {
  1478. "label": "普兰店区",
  1479. "value": "210214"
  1480. }, {
  1481. "label": "长海县",
  1482. "value": "210224"
  1483. }, {
  1484. "label": "瓦房店市",
  1485. "value": "210281"
  1486. }, {
  1487. "label": "庄河市",
  1488. "value": "210283"
  1489. }],
  1490. [{
  1491. "label": "市辖区",
  1492. "value": "210301"
  1493. }, {
  1494. "label": "铁东区",
  1495. "value": "210302"
  1496. }, {
  1497. "label": "铁西区",
  1498. "value": "210303"
  1499. }, {
  1500. "label": "立山区",
  1501. "value": "210304"
  1502. }, {
  1503. "label": "千山区",
  1504. "value": "210311"
  1505. }, {
  1506. "label": "台安县",
  1507. "value": "210321"
  1508. }, {
  1509. "label": "岫岩满族自治县",
  1510. "value": "210323"
  1511. }, {
  1512. "label": "海城市",
  1513. "value": "210381"
  1514. }],
  1515. [{
  1516. "label": "市辖区",
  1517. "value": "210401"
  1518. }, {
  1519. "label": "新抚区",
  1520. "value": "210402"
  1521. }, {
  1522. "label": "东洲区",
  1523. "value": "210403"
  1524. }, {
  1525. "label": "望花区",
  1526. "value": "210404"
  1527. }, {
  1528. "label": "顺城区",
  1529. "value": "210411"
  1530. }, {
  1531. "label": "抚顺县",
  1532. "value": "210421"
  1533. }, {
  1534. "label": "新宾满族自治县",
  1535. "value": "210422"
  1536. }, {
  1537. "label": "清原满族自治县",
  1538. "value": "210423"
  1539. }],
  1540. [{
  1541. "label": "市辖区",
  1542. "value": "210501"
  1543. }, {
  1544. "label": "平山区",
  1545. "value": "210502"
  1546. }, {
  1547. "label": "溪湖区",
  1548. "value": "210503"
  1549. }, {
  1550. "label": "明山区",
  1551. "value": "210504"
  1552. }, {
  1553. "label": "南芬区",
  1554. "value": "210505"
  1555. }, {
  1556. "label": "本溪满族自治县",
  1557. "value": "210521"
  1558. }, {
  1559. "label": "桓仁满族自治县",
  1560. "value": "210522"
  1561. }],
  1562. [{
  1563. "label": "市辖区",
  1564. "value": "210601"
  1565. }, {
  1566. "label": "元宝区",
  1567. "value": "210602"
  1568. }, {
  1569. "label": "振兴区",
  1570. "value": "210603"
  1571. }, {
  1572. "label": "振安区",
  1573. "value": "210604"
  1574. }, {
  1575. "label": "宽甸满族自治县",
  1576. "value": "210624"
  1577. }, {
  1578. "label": "东港市",
  1579. "value": "210681"
  1580. }, {
  1581. "label": "凤城市",
  1582. "value": "210682"
  1583. }],
  1584. [{
  1585. "label": "市辖区",
  1586. "value": "210701"
  1587. }, {
  1588. "label": "古塔区",
  1589. "value": "210702"
  1590. }, {
  1591. "label": "凌河区",
  1592. "value": "210703"
  1593. }, {
  1594. "label": "太和区",
  1595. "value": "210711"
  1596. }, {
  1597. "label": "黑山县",
  1598. "value": "210726"
  1599. }, {
  1600. "label": "义县",
  1601. "value": "210727"
  1602. }, {
  1603. "label": "凌海市",
  1604. "value": "210781"
  1605. }, {
  1606. "label": "北镇市",
  1607. "value": "210782"
  1608. }],
  1609. [{
  1610. "label": "市辖区",
  1611. "value": "210801"
  1612. }, {
  1613. "label": "站前区",
  1614. "value": "210802"
  1615. }, {
  1616. "label": "西市区",
  1617. "value": "210803"
  1618. }, {
  1619. "label": "鲅鱼圈区",
  1620. "value": "210804"
  1621. }, {
  1622. "label": "老边区",
  1623. "value": "210811"
  1624. }, {
  1625. "label": "盖州市",
  1626. "value": "210881"
  1627. }, {
  1628. "label": "大石桥市",
  1629. "value": "210882"
  1630. }],
  1631. [{
  1632. "label": "市辖区",
  1633. "value": "210901"
  1634. }, {
  1635. "label": "海州区",
  1636. "value": "210902"
  1637. }, {
  1638. "label": "新邱区",
  1639. "value": "210903"
  1640. }, {
  1641. "label": "太平区",
  1642. "value": "210904"
  1643. }, {
  1644. "label": "清河门区",
  1645. "value": "210905"
  1646. }, {
  1647. "label": "细河区",
  1648. "value": "210911"
  1649. }, {
  1650. "label": "阜新蒙古族自治县",
  1651. "value": "210921"
  1652. }, {
  1653. "label": "彰武县",
  1654. "value": "210922"
  1655. }],
  1656. [{
  1657. "label": "市辖区",
  1658. "value": "211001"
  1659. }, {
  1660. "label": "白塔区",
  1661. "value": "211002"
  1662. }, {
  1663. "label": "文圣区",
  1664. "value": "211003"
  1665. }, {
  1666. "label": "宏伟区",
  1667. "value": "211004"
  1668. }, {
  1669. "label": "弓长岭区",
  1670. "value": "211005"
  1671. }, {
  1672. "label": "太子河区",
  1673. "value": "211011"
  1674. }, {
  1675. "label": "辽阳县",
  1676. "value": "211021"
  1677. }, {
  1678. "label": "灯塔市",
  1679. "value": "211081"
  1680. }],
  1681. [{
  1682. "label": "市辖区",
  1683. "value": "211101"
  1684. }, {
  1685. "label": "双台子区",
  1686. "value": "211102"
  1687. }, {
  1688. "label": "兴隆台区",
  1689. "value": "211103"
  1690. }, {
  1691. "label": "大洼区",
  1692. "value": "211104"
  1693. }, {
  1694. "label": "盘山县",
  1695. "value": "211122"
  1696. }],
  1697. [{
  1698. "label": "市辖区",
  1699. "value": "211201"
  1700. }, {
  1701. "label": "银州区",
  1702. "value": "211202"
  1703. }, {
  1704. "label": "清河区",
  1705. "value": "211204"
  1706. }, {
  1707. "label": "铁岭县",
  1708. "value": "211221"
  1709. }, {
  1710. "label": "西丰县",
  1711. "value": "211223"
  1712. }, {
  1713. "label": "昌图县",
  1714. "value": "211224"
  1715. }, {
  1716. "label": "调兵山市",
  1717. "value": "211281"
  1718. }, {
  1719. "label": "开原市",
  1720. "value": "211282"
  1721. }],
  1722. [{
  1723. "label": "市辖区",
  1724. "value": "211301"
  1725. }, {
  1726. "label": "双塔区",
  1727. "value": "211302"
  1728. }, {
  1729. "label": "龙城区",
  1730. "value": "211303"
  1731. }, {
  1732. "label": "朝阳县",
  1733. "value": "211321"
  1734. }, {
  1735. "label": "建平县",
  1736. "value": "211322"
  1737. }, {
  1738. "label": "喀喇沁左翼蒙古族自治县",
  1739. "value": "211324"
  1740. }, {
  1741. "label": "北票市",
  1742. "value": "211381"
  1743. }, {
  1744. "label": "凌源市",
  1745. "value": "211382"
  1746. }],
  1747. [{
  1748. "label": "市辖区",
  1749. "value": "211401"
  1750. }, {
  1751. "label": "连山区",
  1752. "value": "211402"
  1753. }, {
  1754. "label": "龙港区",
  1755. "value": "211403"
  1756. }, {
  1757. "label": "南票区",
  1758. "value": "211404"
  1759. }, {
  1760. "label": "绥中县",
  1761. "value": "211421"
  1762. }, {
  1763. "label": "建昌县",
  1764. "value": "211422"
  1765. }, {
  1766. "label": "兴城市",
  1767. "value": "211481"
  1768. }]
  1769. ],
  1770. [
  1771. [{
  1772. "label": "市辖区",
  1773. "value": "220101"
  1774. }, {
  1775. "label": "南关区",
  1776. "value": "220102"
  1777. }, {
  1778. "label": "宽城区",
  1779. "value": "220103"
  1780. }, {
  1781. "label": "朝阳区",
  1782. "value": "220104"
  1783. }, {
  1784. "label": "二道区",
  1785. "value": "220105"
  1786. }, {
  1787. "label": "绿园区",
  1788. "value": "220106"
  1789. }, {
  1790. "label": "双阳区",
  1791. "value": "220112"
  1792. }, {
  1793. "label": "九台区",
  1794. "value": "220113"
  1795. }, {
  1796. "label": "农安县",
  1797. "value": "220122"
  1798. }, {
  1799. "label": "榆树市",
  1800. "value": "220182"
  1801. }, {
  1802. "label": "德惠市",
  1803. "value": "220183"
  1804. }],
  1805. [{
  1806. "label": "市辖区",
  1807. "value": "220201"
  1808. }, {
  1809. "label": "昌邑区",
  1810. "value": "220202"
  1811. }, {
  1812. "label": "龙潭区",
  1813. "value": "220203"
  1814. }, {
  1815. "label": "船营区",
  1816. "value": "220204"
  1817. }, {
  1818. "label": "丰满区",
  1819. "value": "220211"
  1820. }, {
  1821. "label": "永吉县",
  1822. "value": "220221"
  1823. }, {
  1824. "label": "蛟河市",
  1825. "value": "220281"
  1826. }, {
  1827. "label": "桦甸市",
  1828. "value": "220282"
  1829. }, {
  1830. "label": "舒兰市",
  1831. "value": "220283"
  1832. }, {
  1833. "label": "磐石市",
  1834. "value": "220284"
  1835. }],
  1836. [{
  1837. "label": "市辖区",
  1838. "value": "220301"
  1839. }, {
  1840. "label": "铁西区",
  1841. "value": "220302"
  1842. }, {
  1843. "label": "铁东区",
  1844. "value": "220303"
  1845. }, {
  1846. "label": "梨树县",
  1847. "value": "220322"
  1848. }, {
  1849. "label": "伊通满族自治县",
  1850. "value": "220323"
  1851. }, {
  1852. "label": "公主岭市",
  1853. "value": "220381"
  1854. }, {
  1855. "label": "双辽市",
  1856. "value": "220382"
  1857. }],
  1858. [{
  1859. "label": "市辖区",
  1860. "value": "220401"
  1861. }, {
  1862. "label": "龙山区",
  1863. "value": "220402"
  1864. }, {
  1865. "label": "西安区",
  1866. "value": "220403"
  1867. }, {
  1868. "label": "东丰县",
  1869. "value": "220421"
  1870. }, {
  1871. "label": "东辽县",
  1872. "value": "220422"
  1873. }],
  1874. [{
  1875. "label": "市辖区",
  1876. "value": "220501"
  1877. }, {
  1878. "label": "东昌区",
  1879. "value": "220502"
  1880. }, {
  1881. "label": "二道江区",
  1882. "value": "220503"
  1883. }, {
  1884. "label": "通化县",
  1885. "value": "220521"
  1886. }, {
  1887. "label": "辉南县",
  1888. "value": "220523"
  1889. }, {
  1890. "label": "柳河县",
  1891. "value": "220524"
  1892. }, {
  1893. "label": "梅河口市",
  1894. "value": "220581"
  1895. }, {
  1896. "label": "集安市",
  1897. "value": "220582"
  1898. }],
  1899. [{
  1900. "label": "市辖区",
  1901. "value": "220601"
  1902. }, {
  1903. "label": "浑江区",
  1904. "value": "220602"
  1905. }, {
  1906. "label": "江源区",
  1907. "value": "220605"
  1908. }, {
  1909. "label": "抚松县",
  1910. "value": "220621"
  1911. }, {
  1912. "label": "靖宇县",
  1913. "value": "220622"
  1914. }, {
  1915. "label": "长白朝鲜族自治县",
  1916. "value": "220623"
  1917. }, {
  1918. "label": "临江市",
  1919. "value": "220681"
  1920. }],
  1921. [{
  1922. "label": "市辖区",
  1923. "value": "220701"
  1924. }, {
  1925. "label": "宁江区",
  1926. "value": "220702"
  1927. }, {
  1928. "label": "前郭尔罗斯蒙古族自治县",
  1929. "value": "220721"
  1930. }, {
  1931. "label": "长岭县",
  1932. "value": "220722"
  1933. }, {
  1934. "label": "乾安县",
  1935. "value": "220723"
  1936. }, {
  1937. "label": "扶余市",
  1938. "value": "220781"
  1939. }],
  1940. [{
  1941. "label": "市辖区",
  1942. "value": "220801"
  1943. }, {
  1944. "label": "洮北区",
  1945. "value": "220802"
  1946. }, {
  1947. "label": "镇赉县",
  1948. "value": "220821"
  1949. }, {
  1950. "label": "通榆县",
  1951. "value": "220822"
  1952. }, {
  1953. "label": "洮南市",
  1954. "value": "220881"
  1955. }, {
  1956. "label": "大安市",
  1957. "value": "220882"
  1958. }],
  1959. [{
  1960. "label": "市辖区",
  1961. "value": "222401"
  1962. }, {
  1963. "label": "图们市",
  1964. "value": "222402"
  1965. }, {
  1966. "label": "敦化市",
  1967. "value": "222403"
  1968. }, {
  1969. "label": "珲春市",
  1970. "value": "222404"
  1971. }, {
  1972. "label": "龙井市",
  1973. "value": "222405"
  1974. }, {
  1975. "label": "和龙市",
  1976. "value": "222406"
  1977. }, {
  1978. "label": "汪清县",
  1979. "value": "222424"
  1980. }, {
  1981. "label": "安图县",
  1982. "value": "222426"
  1983. }]
  1984. ],
  1985. [
  1986. [{
  1987. "label": "市辖区",
  1988. "value": "230101"
  1989. }, {
  1990. "label": "道里区",
  1991. "value": "230102"
  1992. }, {
  1993. "label": "南岗区",
  1994. "value": "230103"
  1995. }, {
  1996. "label": "道外区",
  1997. "value": "230104"
  1998. }, {
  1999. "label": "平房区",
  2000. "value": "230108"
  2001. }, {
  2002. "label": "松北区",
  2003. "value": "230109"
  2004. }, {
  2005. "label": "香坊区",
  2006. "value": "230110"
  2007. }, {
  2008. "label": "呼兰区",
  2009. "value": "230111"
  2010. }, {
  2011. "label": "阿城区",
  2012. "value": "230112"
  2013. }, {
  2014. "label": "双城区",
  2015. "value": "230113"
  2016. }, {
  2017. "label": "依兰县",
  2018. "value": "230123"
  2019. }, {
  2020. "label": "方正县",
  2021. "value": "230124"
  2022. }, {
  2023. "label": "宾县",
  2024. "value": "230125"
  2025. }, {
  2026. "label": "巴彦县",
  2027. "value": "230126"
  2028. }, {
  2029. "label": "木兰县",
  2030. "value": "230127"
  2031. }, {
  2032. "label": "通河县",
  2033. "value": "230128"
  2034. }, {
  2035. "label": "延寿县",
  2036. "value": "230129"
  2037. }, {
  2038. "label": "尚志市",
  2039. "value": "230183"
  2040. }, {
  2041. "label": "五常市",
  2042. "value": "230184"
  2043. }],
  2044. [{
  2045. "label": "市辖区",
  2046. "value": "230201"
  2047. }, {
  2048. "label": "龙沙区",
  2049. "value": "230202"
  2050. }, {
  2051. "label": "建华区",
  2052. "value": "230203"
  2053. }, {
  2054. "label": "铁锋区",
  2055. "value": "230204"
  2056. }, {
  2057. "label": "昂昂溪区",
  2058. "value": "230205"
  2059. }, {
  2060. "label": "富拉尔基区",
  2061. "value": "230206"
  2062. }, {
  2063. "label": "碾子山区",
  2064. "value": "230207"
  2065. }, {
  2066. "label": "梅里斯达斡尔族区",
  2067. "value": "230208"
  2068. }, {
  2069. "label": "龙江县",
  2070. "value": "230221"
  2071. }, {
  2072. "label": "依安县",
  2073. "value": "230223"
  2074. }, {
  2075. "label": "泰来县",
  2076. "value": "230224"
  2077. }, {
  2078. "label": "甘南县",
  2079. "value": "230225"
  2080. }, {
  2081. "label": "富裕县",
  2082. "value": "230227"
  2083. }, {
  2084. "label": "克山县",
  2085. "value": "230229"
  2086. }, {
  2087. "label": "克东县",
  2088. "value": "230230"
  2089. }, {
  2090. "label": "拜泉县",
  2091. "value": "230231"
  2092. }, {
  2093. "label": "讷河市",
  2094. "value": "230281"
  2095. }],
  2096. [{
  2097. "label": "市辖区",
  2098. "value": "230301"
  2099. }, {
  2100. "label": "鸡冠区",
  2101. "value": "230302"
  2102. }, {
  2103. "label": "恒山区",
  2104. "value": "230303"
  2105. }, {
  2106. "label": "滴道区",
  2107. "value": "230304"
  2108. }, {
  2109. "label": "梨树区",
  2110. "value": "230305"
  2111. }, {
  2112. "label": "城子河区",
  2113. "value": "230306"
  2114. }, {
  2115. "label": "麻山区",
  2116. "value": "230307"
  2117. }, {
  2118. "label": "鸡东县",
  2119. "value": "230321"
  2120. }, {
  2121. "label": "虎林市",
  2122. "value": "230381"
  2123. }, {
  2124. "label": "密山市",
  2125. "value": "230382"
  2126. }],
  2127. [{
  2128. "label": "市辖区",
  2129. "value": "230401"
  2130. }, {
  2131. "label": "向阳区",
  2132. "value": "230402"
  2133. }, {
  2134. "label": "工农区",
  2135. "value": "230403"
  2136. }, {
  2137. "label": "南山区",
  2138. "value": "230404"
  2139. }, {
  2140. "label": "兴安区",
  2141. "value": "230405"
  2142. }, {
  2143. "label": "东山区",
  2144. "value": "230406"
  2145. }, {
  2146. "label": "兴山区",
  2147. "value": "230407"
  2148. }, {
  2149. "label": "萝北县",
  2150. "value": "230421"
  2151. }, {
  2152. "label": "绥滨县",
  2153. "value": "230422"
  2154. }],
  2155. [{
  2156. "label": "市辖区",
  2157. "value": "230501"
  2158. }, {
  2159. "label": "尖山区",
  2160. "value": "230502"
  2161. }, {
  2162. "label": "岭东区",
  2163. "value": "230503"
  2164. }, {
  2165. "label": "四方台区",
  2166. "value": "230505"
  2167. }, {
  2168. "label": "宝山区",
  2169. "value": "230506"
  2170. }, {
  2171. "label": "集贤县",
  2172. "value": "230521"
  2173. }, {
  2174. "label": "友谊县",
  2175. "value": "230522"
  2176. }, {
  2177. "label": "宝清县",
  2178. "value": "230523"
  2179. }, {
  2180. "label": "饶河县",
  2181. "value": "230524"
  2182. }],
  2183. [{
  2184. "label": "市辖区",
  2185. "value": "230601"
  2186. }, {
  2187. "label": "萨尔图区",
  2188. "value": "230602"
  2189. }, {
  2190. "label": "龙凤区",
  2191. "value": "230603"
  2192. }, {
  2193. "label": "让胡路区",
  2194. "value": "230604"
  2195. }, {
  2196. "label": "红岗区",
  2197. "value": "230605"
  2198. }, {
  2199. "label": "大同区",
  2200. "value": "230606"
  2201. }, {
  2202. "label": "肇州县",
  2203. "value": "230621"
  2204. }, {
  2205. "label": "肇源县",
  2206. "value": "230622"
  2207. }, {
  2208. "label": "林甸县",
  2209. "value": "230623"
  2210. }, {
  2211. "label": "杜尔伯特蒙古族自治县",
  2212. "value": "230624"
  2213. }],
  2214. [{
  2215. "label": "市辖区",
  2216. "value": "230701"
  2217. }, {
  2218. "label": "伊春区",
  2219. "value": "230702"
  2220. }, {
  2221. "label": "南岔区",
  2222. "value": "230703"
  2223. }, {
  2224. "label": "友好区",
  2225. "value": "230704"
  2226. }, {
  2227. "label": "西林区",
  2228. "value": "230705"
  2229. }, {
  2230. "label": "翠峦区",
  2231. "value": "230706"
  2232. }, {
  2233. "label": "新青区",
  2234. "value": "230707"
  2235. }, {
  2236. "label": "美溪区",
  2237. "value": "230708"
  2238. }, {
  2239. "label": "金山屯区",
  2240. "value": "230709"
  2241. }, {
  2242. "label": "五营区",
  2243. "value": "230710"
  2244. }, {
  2245. "label": "乌马河区",
  2246. "value": "230711"
  2247. }, {
  2248. "label": "汤旺河区",
  2249. "value": "230712"
  2250. }, {
  2251. "label": "带岭区",
  2252. "value": "230713"
  2253. }, {
  2254. "label": "乌伊岭区",
  2255. "value": "230714"
  2256. }, {
  2257. "label": "红星区",
  2258. "value": "230715"
  2259. }, {
  2260. "label": "上甘岭区",
  2261. "value": "230716"
  2262. }, {
  2263. "label": "嘉荫县",
  2264. "value": "230722"
  2265. }, {
  2266. "label": "铁力市",
  2267. "value": "230781"
  2268. }],
  2269. [{
  2270. "label": "市辖区",
  2271. "value": "230801"
  2272. }, {
  2273. "label": "向阳区",
  2274. "value": "230803"
  2275. }, {
  2276. "label": "前进区",
  2277. "value": "230804"
  2278. }, {
  2279. "label": "东风区",
  2280. "value": "230805"
  2281. }, {
  2282. "label": "郊区",
  2283. "value": "230811"
  2284. }, {
  2285. "label": "桦南县",
  2286. "value": "230822"
  2287. }, {
  2288. "label": "桦川县",
  2289. "value": "230826"
  2290. }, {
  2291. "label": "汤原县",
  2292. "value": "230828"
  2293. }, {
  2294. "label": "同江市",
  2295. "value": "230881"
  2296. }, {
  2297. "label": "富锦市",
  2298. "value": "230882"
  2299. }, {
  2300. "label": "抚远市",
  2301. "value": "230883"
  2302. }],
  2303. [{
  2304. "label": "市辖区",
  2305. "value": "230901"
  2306. }, {
  2307. "label": "新兴区",
  2308. "value": "230902"
  2309. }, {
  2310. "label": "桃山区",
  2311. "value": "230903"
  2312. }, {
  2313. "label": "茄子河区",
  2314. "value": "230904"
  2315. }, {
  2316. "label": "勃利县",
  2317. "value": "230921"
  2318. }],
  2319. [{
  2320. "label": "市辖区",
  2321. "value": "231001"
  2322. }, {
  2323. "label": "东安区",
  2324. "value": "231002"
  2325. }, {
  2326. "label": "阳明区",
  2327. "value": "231003"
  2328. }, {
  2329. "label": "爱民区",
  2330. "value": "231004"
  2331. }, {
  2332. "label": "西安区",
  2333. "value": "231005"
  2334. }, {
  2335. "label": "林口县",
  2336. "value": "231025"
  2337. }, {
  2338. "label": "绥芬河市",
  2339. "value": "231081"
  2340. }, {
  2341. "label": "海林市",
  2342. "value": "231083"
  2343. }, {
  2344. "label": "宁安市",
  2345. "value": "231084"
  2346. }, {
  2347. "label": "穆棱市",
  2348. "value": "231085"
  2349. }, {
  2350. "label": "东宁市",
  2351. "value": "231086"
  2352. }],
  2353. [{
  2354. "label": "市辖区",
  2355. "value": "231101"
  2356. }, {
  2357. "label": "爱辉区",
  2358. "value": "231102"
  2359. }, {
  2360. "label": "嫩江县",
  2361. "value": "231121"
  2362. }, {
  2363. "label": "逊克县",
  2364. "value": "231123"
  2365. }, {
  2366. "label": "孙吴县",
  2367. "value": "231124"
  2368. }, {
  2369. "label": "北安市",
  2370. "value": "231181"
  2371. }, {
  2372. "label": "五大连池市",
  2373. "value": "231182"
  2374. }],
  2375. [{
  2376. "label": "市辖区",
  2377. "value": "231201"
  2378. }, {
  2379. "label": "北林区",
  2380. "value": "231202"
  2381. }, {
  2382. "label": "望奎县",
  2383. "value": "231221"
  2384. }, {
  2385. "label": "兰西县",
  2386. "value": "231222"
  2387. }, {
  2388. "label": "青冈县",
  2389. "value": "231223"
  2390. }, {
  2391. "label": "庆安县",
  2392. "value": "231224"
  2393. }, {
  2394. "label": "明水县",
  2395. "value": "231225"
  2396. }, {
  2397. "label": "绥棱县",
  2398. "value": "231226"
  2399. }, {
  2400. "label": "安达市",
  2401. "value": "231281"
  2402. }, {
  2403. "label": "肇东市",
  2404. "value": "231282"
  2405. }, {
  2406. "label": "海伦市",
  2407. "value": "231283"
  2408. }],
  2409. [{
  2410. "label": "呼玛县",
  2411. "value": "232721"
  2412. }, {
  2413. "label": "塔河县",
  2414. "value": "232722"
  2415. }, {
  2416. "label": "漠河县",
  2417. "value": "232723"
  2418. }]
  2419. ],
  2420. [
  2421. [{
  2422. "label": "黄浦区",
  2423. "value": "310101"
  2424. }, {
  2425. "label": "徐汇区",
  2426. "value": "310104"
  2427. }, {
  2428. "label": "长宁区",
  2429. "value": "310105"
  2430. }, {
  2431. "label": "静安区",
  2432. "value": "310106"
  2433. }, {
  2434. "label": "普陀区",
  2435. "value": "310107"
  2436. }, {
  2437. "label": "虹口区",
  2438. "value": "310109"
  2439. }, {
  2440. "label": "杨浦区",
  2441. "value": "310110"
  2442. }, {
  2443. "label": "闵行区",
  2444. "value": "310112"
  2445. }, {
  2446. "label": "宝山区",
  2447. "value": "310113"
  2448. }, {
  2449. "label": "嘉定区",
  2450. "value": "310114"
  2451. }, {
  2452. "label": "浦东新区",
  2453. "value": "310115"
  2454. }, {
  2455. "label": "金山区",
  2456. "value": "310116"
  2457. }, {
  2458. "label": "松江区",
  2459. "value": "310117"
  2460. }, {
  2461. "label": "青浦区",
  2462. "value": "310118"
  2463. }, {
  2464. "label": "奉贤区",
  2465. "value": "310120"
  2466. }, {
  2467. "label": "崇明区",
  2468. "value": "310151"
  2469. }]
  2470. ],
  2471. [
  2472. [{
  2473. "label": "市辖区",
  2474. "value": "320101"
  2475. }, {
  2476. "label": "玄武区",
  2477. "value": "320102"
  2478. }, {
  2479. "label": "秦淮区",
  2480. "value": "320104"
  2481. }, {
  2482. "label": "建邺区",
  2483. "value": "320105"
  2484. }, {
  2485. "label": "鼓楼区",
  2486. "value": "320106"
  2487. }, {
  2488. "label": "浦口区",
  2489. "value": "320111"
  2490. }, {
  2491. "label": "栖霞区",
  2492. "value": "320113"
  2493. }, {
  2494. "label": "雨花台区",
  2495. "value": "320114"
  2496. }, {
  2497. "label": "江宁区",
  2498. "value": "320115"
  2499. }, {
  2500. "label": "六合区",
  2501. "value": "320116"
  2502. }, {
  2503. "label": "溧水区",
  2504. "value": "320117"
  2505. }, {
  2506. "label": "高淳区",
  2507. "value": "320118"
  2508. }],
  2509. [{
  2510. "label": "市辖区",
  2511. "value": "320201"
  2512. }, {
  2513. "label": "锡山区",
  2514. "value": "320205"
  2515. }, {
  2516. "label": "惠山区",
  2517. "value": "320206"
  2518. }, {
  2519. "label": "滨湖区",
  2520. "value": "320211"
  2521. }, {
  2522. "label": "梁溪区",
  2523. "value": "320213"
  2524. }, {
  2525. "label": "新吴区",
  2526. "value": "320214"
  2527. }, {
  2528. "label": "江阴市",
  2529. "value": "320281"
  2530. }, {
  2531. "label": "宜兴市",
  2532. "value": "320282"
  2533. }],
  2534. [{
  2535. "label": "市辖区",
  2536. "value": "320301"
  2537. }, {
  2538. "label": "鼓楼区",
  2539. "value": "320302"
  2540. }, {
  2541. "label": "云龙区",
  2542. "value": "320303"
  2543. }, {
  2544. "label": "贾汪区",
  2545. "value": "320305"
  2546. }, {
  2547. "label": "泉山区",
  2548. "value": "320311"
  2549. }, {
  2550. "label": "铜山区",
  2551. "value": "320312"
  2552. }, {
  2553. "label": "丰县",
  2554. "value": "320321"
  2555. }, {
  2556. "label": "沛县",
  2557. "value": "320322"
  2558. }, {
  2559. "label": "睢宁县",
  2560. "value": "320324"
  2561. }, {
  2562. "label": "新沂市",
  2563. "value": "320381"
  2564. }, {
  2565. "label": "邳州市",
  2566. "value": "320382"
  2567. }],
  2568. [{
  2569. "label": "市辖区",
  2570. "value": "320401"
  2571. }, {
  2572. "label": "天宁区",
  2573. "value": "320402"
  2574. }, {
  2575. "label": "钟楼区",
  2576. "value": "320404"
  2577. }, {
  2578. "label": "新北区",
  2579. "value": "320411"
  2580. }, {
  2581. "label": "武进区",
  2582. "value": "320412"
  2583. }, {
  2584. "label": "金坛区",
  2585. "value": "320413"
  2586. }, {
  2587. "label": "溧阳市",
  2588. "value": "320481"
  2589. }],
  2590. [{
  2591. "label": "市辖区",
  2592. "value": "320501"
  2593. }, {
  2594. "label": "虎丘区",
  2595. "value": "320505"
  2596. }, {
  2597. "label": "吴中区",
  2598. "value": "320506"
  2599. }, {
  2600. "label": "相城区",
  2601. "value": "320507"
  2602. }, {
  2603. "label": "姑苏区",
  2604. "value": "320508"
  2605. }, {
  2606. "label": "吴江区",
  2607. "value": "320509"
  2608. }, {
  2609. "label": "常熟市",
  2610. "value": "320581"
  2611. }, {
  2612. "label": "张家港市",
  2613. "value": "320582"
  2614. }, {
  2615. "label": "昆山市",
  2616. "value": "320583"
  2617. }, {
  2618. "label": "太仓市",
  2619. "value": "320585"
  2620. }],
  2621. [{
  2622. "label": "市辖区",
  2623. "value": "320601"
  2624. }, {
  2625. "label": "崇川区",
  2626. "value": "320602"
  2627. }, {
  2628. "label": "港闸区",
  2629. "value": "320611"
  2630. }, {
  2631. "label": "通州区",
  2632. "value": "320612"
  2633. }, {
  2634. "label": "海安县",
  2635. "value": "320621"
  2636. }, {
  2637. "label": "如东县",
  2638. "value": "320623"
  2639. }, {
  2640. "label": "启东市",
  2641. "value": "320681"
  2642. }, {
  2643. "label": "如皋市",
  2644. "value": "320682"
  2645. }, {
  2646. "label": "海门市",
  2647. "value": "320684"
  2648. }],
  2649. [{
  2650. "label": "市辖区",
  2651. "value": "320701"
  2652. }, {
  2653. "label": "连云区",
  2654. "value": "320703"
  2655. }, {
  2656. "label": "海州区",
  2657. "value": "320706"
  2658. }, {
  2659. "label": "赣榆区",
  2660. "value": "320707"
  2661. }, {
  2662. "label": "东海县",
  2663. "value": "320722"
  2664. }, {
  2665. "label": "灌云县",
  2666. "value": "320723"
  2667. }, {
  2668. "label": "灌南县",
  2669. "value": "320724"
  2670. }],
  2671. [{
  2672. "label": "市辖区",
  2673. "value": "320801"
  2674. }, {
  2675. "label": "淮安区",
  2676. "value": "320803"
  2677. }, {
  2678. "label": "淮阴区",
  2679. "value": "320804"
  2680. }, {
  2681. "label": "清江浦区",
  2682. "value": "320812"
  2683. }, {
  2684. "label": "洪泽区",
  2685. "value": "320813"
  2686. }, {
  2687. "label": "涟水县",
  2688. "value": "320826"
  2689. }, {
  2690. "label": "盱眙县",
  2691. "value": "320830"
  2692. }, {
  2693. "label": "金湖县",
  2694. "value": "320831"
  2695. }],
  2696. [{
  2697. "label": "市辖区",
  2698. "value": "320901"
  2699. }, {
  2700. "label": "亭湖区",
  2701. "value": "320902"
  2702. }, {
  2703. "label": "盐都区",
  2704. "value": "320903"
  2705. }, {
  2706. "label": "大丰区",
  2707. "value": "320904"
  2708. }, {
  2709. "label": "响水县",
  2710. "value": "320921"
  2711. }, {
  2712. "label": "滨海县",
  2713. "value": "320922"
  2714. }, {
  2715. "label": "阜宁县",
  2716. "value": "320923"
  2717. }, {
  2718. "label": "射阳县",
  2719. "value": "320924"
  2720. }, {
  2721. "label": "建湖县",
  2722. "value": "320925"
  2723. }, {
  2724. "label": "东台市",
  2725. "value": "320981"
  2726. }],
  2727. [{
  2728. "label": "市辖区",
  2729. "value": "321001"
  2730. }, {
  2731. "label": "广陵区",
  2732. "value": "321002"
  2733. }, {
  2734. "label": "邗江区",
  2735. "value": "321003"
  2736. }, {
  2737. "label": "江都区",
  2738. "value": "321012"
  2739. }, {
  2740. "label": "宝应县",
  2741. "value": "321023"
  2742. }, {
  2743. "label": "仪征市",
  2744. "value": "321081"
  2745. }, {
  2746. "label": "高邮市",
  2747. "value": "321084"
  2748. }],
  2749. [{
  2750. "label": "市辖区",
  2751. "value": "321101"
  2752. }, {
  2753. "label": "京口区",
  2754. "value": "321102"
  2755. }, {
  2756. "label": "润州区",
  2757. "value": "321111"
  2758. }, {
  2759. "label": "丹徒区",
  2760. "value": "321112"
  2761. }, {
  2762. "label": "丹阳市",
  2763. "value": "321181"
  2764. }, {
  2765. "label": "扬中市",
  2766. "value": "321182"
  2767. }, {
  2768. "label": "句容市",
  2769. "value": "321183"
  2770. }],
  2771. [{
  2772. "label": "市辖区",
  2773. "value": "321201"
  2774. }, {
  2775. "label": "海陵区",
  2776. "value": "321202"
  2777. }, {
  2778. "label": "高港区",
  2779. "value": "321203"
  2780. }, {
  2781. "label": "姜堰区",
  2782. "value": "321204"
  2783. }, {
  2784. "label": "兴化市",
  2785. "value": "321281"
  2786. }, {
  2787. "label": "靖江市",
  2788. "value": "321282"
  2789. }, {
  2790. "label": "泰兴市",
  2791. "value": "321283"
  2792. }],
  2793. [{
  2794. "label": "市辖区",
  2795. "value": "321301"
  2796. }, {
  2797. "label": "宿城区",
  2798. "value": "321302"
  2799. }, {
  2800. "label": "宿豫区",
  2801. "value": "321311"
  2802. }, {
  2803. "label": "沭阳县",
  2804. "value": "321322"
  2805. }, {
  2806. "label": "泗阳县",
  2807. "value": "321323"
  2808. }, {
  2809. "label": "泗洪县",
  2810. "value": "321324"
  2811. }]
  2812. ],
  2813. [
  2814. [{
  2815. "label": "市辖区",
  2816. "value": "330101"
  2817. }, {
  2818. "label": "上城区",
  2819. "value": "330102"
  2820. }, {
  2821. "label": "下城区",
  2822. "value": "330103"
  2823. }, {
  2824. "label": "江干区",
  2825. "value": "330104"
  2826. }, {
  2827. "label": "拱墅区",
  2828. "value": "330105"
  2829. }, {
  2830. "label": "西湖区",
  2831. "value": "330106"
  2832. }, {
  2833. "label": "滨江区",
  2834. "value": "330108"
  2835. }, {
  2836. "label": "萧山区",
  2837. "value": "330109"
  2838. }, {
  2839. "label": "余杭区",
  2840. "value": "330110"
  2841. }, {
  2842. "label": "富阳区",
  2843. "value": "330111"
  2844. }, {
  2845. "label": "桐庐县",
  2846. "value": "330122"
  2847. }, {
  2848. "label": "淳安县",
  2849. "value": "330127"
  2850. }, {
  2851. "label": "建德市",
  2852. "value": "330182"
  2853. }, {
  2854. "label": "临安市",
  2855. "value": "330185"
  2856. }, {
  2857. "label": "富阳市",
  2858. "value": "920001"
  2859. }],
  2860. [{
  2861. "label": "市辖区",
  2862. "value": "330201"
  2863. }, {
  2864. "label": "海曙区",
  2865. "value": "330203"
  2866. }, {
  2867. "label": "江东区",
  2868. "value": "330204"
  2869. }, {
  2870. "label": "江北区",
  2871. "value": "330205"
  2872. }, {
  2873. "label": "北仑区",
  2874. "value": "330206"
  2875. }, {
  2876. "label": "镇海区",
  2877. "value": "330211"
  2878. }, {
  2879. "label": "鄞州区",
  2880. "value": "330212"
  2881. }, {
  2882. "label": "象山县",
  2883. "value": "330225"
  2884. }, {
  2885. "label": "宁海县",
  2886. "value": "330226"
  2887. }, {
  2888. "label": "余姚市",
  2889. "value": "330281"
  2890. }, {
  2891. "label": "慈溪市",
  2892. "value": "330282"
  2893. }, {
  2894. "label": "奉化市",
  2895. "value": "330283"
  2896. }],
  2897. [{
  2898. "label": "市辖区",
  2899. "value": "330301"
  2900. }, {
  2901. "label": "鹿城区",
  2902. "value": "330302"
  2903. }, {
  2904. "label": "龙湾区",
  2905. "value": "330303"
  2906. }, {
  2907. "label": "瓯海区",
  2908. "value": "330304"
  2909. }, {
  2910. "label": "洞头区",
  2911. "value": "330305"
  2912. }, {
  2913. "label": "永嘉县",
  2914. "value": "330324"
  2915. }, {
  2916. "label": "平阳县",
  2917. "value": "330326"
  2918. }, {
  2919. "label": "苍南县",
  2920. "value": "330327"
  2921. }, {
  2922. "label": "文成县",
  2923. "value": "330328"
  2924. }, {
  2925. "label": "泰顺县",
  2926. "value": "330329"
  2927. }, {
  2928. "label": "瑞安市",
  2929. "value": "330381"
  2930. }, {
  2931. "label": "乐清市",
  2932. "value": "330382"
  2933. }],
  2934. [{
  2935. "label": "市辖区",
  2936. "value": "330401"
  2937. }, {
  2938. "label": "南湖区",
  2939. "value": "330402"
  2940. }, {
  2941. "label": "秀洲区",
  2942. "value": "330411"
  2943. }, {
  2944. "label": "嘉善县",
  2945. "value": "330421"
  2946. }, {
  2947. "label": "海盐县",
  2948. "value": "330424"
  2949. }, {
  2950. "label": "海宁市",
  2951. "value": "330481"
  2952. }, {
  2953. "label": "平湖市",
  2954. "value": "330482"
  2955. }, {
  2956. "label": "桐乡市",
  2957. "value": "330483"
  2958. }],
  2959. [{
  2960. "label": "市辖区",
  2961. "value": "330501"
  2962. }, {
  2963. "label": "吴兴区",
  2964. "value": "330502"
  2965. }, {
  2966. "label": "南浔区",
  2967. "value": "330503"
  2968. }, {
  2969. "label": "德清县",
  2970. "value": "330521"
  2971. }, {
  2972. "label": "长兴县",
  2973. "value": "330522"
  2974. }, {
  2975. "label": "安吉县",
  2976. "value": "330523"
  2977. }],
  2978. [{
  2979. "label": "市辖区",
  2980. "value": "330601"
  2981. }, {
  2982. "label": "越城区",
  2983. "value": "330602"
  2984. }, {
  2985. "label": "柯桥区",
  2986. "value": "330603"
  2987. }, {
  2988. "label": "上虞区",
  2989. "value": "330604"
  2990. }, {
  2991. "label": "新昌县",
  2992. "value": "330624"
  2993. }, {
  2994. "label": "诸暨市",
  2995. "value": "330681"
  2996. }, {
  2997. "label": "嵊州市",
  2998. "value": "330683"
  2999. }],
  3000. [{
  3001. "label": "市辖区",
  3002. "value": "330701"
  3003. }, {
  3004. "label": "婺城区",
  3005. "value": "330702"
  3006. }, {
  3007. "label": "金东区",
  3008. "value": "330703"
  3009. }, {
  3010. "label": "武义县",
  3011. "value": "330723"
  3012. }, {
  3013. "label": "浦江县",
  3014. "value": "330726"
  3015. }, {
  3016. "label": "磐安县",
  3017. "value": "330727"
  3018. }, {
  3019. "label": "兰溪市",
  3020. "value": "330781"
  3021. }, {
  3022. "label": "义乌市",
  3023. "value": "330782"
  3024. }, {
  3025. "label": "东阳市",
  3026. "value": "330783"
  3027. }, {
  3028. "label": "永康市",
  3029. "value": "330784"
  3030. }],
  3031. [{
  3032. "label": "市辖区",
  3033. "value": "330801"
  3034. }, {
  3035. "label": "柯城区",
  3036. "value": "330802"
  3037. }, {
  3038. "label": "衢江区",
  3039. "value": "330803"
  3040. }, {
  3041. "label": "常山县",
  3042. "value": "330822"
  3043. }, {
  3044. "label": "开化县",
  3045. "value": "330824"
  3046. }, {
  3047. "label": "龙游县",
  3048. "value": "330825"
  3049. }, {
  3050. "label": "江山市",
  3051. "value": "330881"
  3052. }],
  3053. [{
  3054. "label": "市辖区",
  3055. "value": "330901"
  3056. }, {
  3057. "label": "定海区",
  3058. "value": "330902"
  3059. }, {
  3060. "label": "普陀区",
  3061. "value": "330903"
  3062. }, {
  3063. "label": "岱山县",
  3064. "value": "330921"
  3065. }, {
  3066. "label": "嵊泗县",
  3067. "value": "330922"
  3068. }],
  3069. [{
  3070. "label": "市辖区",
  3071. "value": "331001"
  3072. }, {
  3073. "label": "椒江区",
  3074. "value": "331002"
  3075. }, {
  3076. "label": "黄岩区",
  3077. "value": "331003"
  3078. }, {
  3079. "label": "路桥区",
  3080. "value": "331004"
  3081. }, {
  3082. "label": "玉环县",
  3083. "value": "331021"
  3084. }, {
  3085. "label": "三门县",
  3086. "value": "331022"
  3087. }, {
  3088. "label": "天台县",
  3089. "value": "331023"
  3090. }, {
  3091. "label": "仙居县",
  3092. "value": "331024"
  3093. }, {
  3094. "label": "温岭市",
  3095. "value": "331081"
  3096. }, {
  3097. "label": "临海市",
  3098. "value": "331082"
  3099. }],
  3100. [{
  3101. "label": "市辖区",
  3102. "value": "331101"
  3103. }, {
  3104. "label": "莲都区",
  3105. "value": "331102"
  3106. }, {
  3107. "label": "青田县",
  3108. "value": "331121"
  3109. }, {
  3110. "label": "缙云县",
  3111. "value": "331122"
  3112. }, {
  3113. "label": "遂昌县",
  3114. "value": "331123"
  3115. }, {
  3116. "label": "松阳县",
  3117. "value": "331124"
  3118. }, {
  3119. "label": "云和县",
  3120. "value": "331125"
  3121. }, {
  3122. "label": "庆元县",
  3123. "value": "331126"
  3124. }, {
  3125. "label": "景宁畲族自治县",
  3126. "value": "331127"
  3127. }, {
  3128. "label": "龙泉市",
  3129. "value": "331181"
  3130. }]
  3131. ],
  3132. [
  3133. [{
  3134. "label": "市辖区",
  3135. "value": "340101"
  3136. }, {
  3137. "label": "瑶海区",
  3138. "value": "340102"
  3139. }, {
  3140. "label": "庐阳区",
  3141. "value": "340103"
  3142. }, {
  3143. "label": "蜀山区",
  3144. "value": "340104"
  3145. }, {
  3146. "label": "包河区",
  3147. "value": "340111"
  3148. }, {
  3149. "label": "长丰县",
  3150. "value": "340121"
  3151. }, {
  3152. "label": "肥东县",
  3153. "value": "340122"
  3154. }, {
  3155. "label": "肥西县",
  3156. "value": "340123"
  3157. }, {
  3158. "label": "庐江县",
  3159. "value": "340124"
  3160. }, {
  3161. "label": "巢湖市",
  3162. "value": "340181"
  3163. }],
  3164. [{
  3165. "label": "市辖区",
  3166. "value": "340201"
  3167. }, {
  3168. "label": "镜湖区",
  3169. "value": "340202"
  3170. }, {
  3171. "label": "弋江区",
  3172. "value": "340203"
  3173. }, {
  3174. "label": "鸠江区",
  3175. "value": "340207"
  3176. }, {
  3177. "label": "三山区",
  3178. "value": "340208"
  3179. }, {
  3180. "label": "芜湖县",
  3181. "value": "340221"
  3182. }, {
  3183. "label": "繁昌县",
  3184. "value": "340222"
  3185. }, {
  3186. "label": "南陵县",
  3187. "value": "340223"
  3188. }, {
  3189. "label": "无为县",
  3190. "value": "340225"
  3191. }],
  3192. [{
  3193. "label": "市辖区",
  3194. "value": "340301"
  3195. }, {
  3196. "label": "龙子湖区",
  3197. "value": "340302"
  3198. }, {
  3199. "label": "蚌山区",
  3200. "value": "340303"
  3201. }, {
  3202. "label": "禹会区",
  3203. "value": "340304"
  3204. }, {
  3205. "label": "淮上区",
  3206. "value": "340311"
  3207. }, {
  3208. "label": "怀远县",
  3209. "value": "340321"
  3210. }, {
  3211. "label": "五河县",
  3212. "value": "340322"
  3213. }, {
  3214. "label": "固镇县",
  3215. "value": "340323"
  3216. }],
  3217. [{
  3218. "label": "市辖区",
  3219. "value": "340401"
  3220. }, {
  3221. "label": "大通区",
  3222. "value": "340402"
  3223. }, {
  3224. "label": "田家庵区",
  3225. "value": "340403"
  3226. }, {
  3227. "label": "谢家集区",
  3228. "value": "340404"
  3229. }, {
  3230. "label": "八公山区",
  3231. "value": "340405"
  3232. }, {
  3233. "label": "潘集区",
  3234. "value": "340406"
  3235. }, {
  3236. "label": "凤台县",
  3237. "value": "340421"
  3238. }, {
  3239. "label": "寿县",
  3240. "value": "340422"
  3241. }],
  3242. [{
  3243. "label": "市辖区",
  3244. "value": "340501"
  3245. }, {
  3246. "label": "花山区",
  3247. "value": "340503"
  3248. }, {
  3249. "label": "雨山区",
  3250. "value": "340504"
  3251. }, {
  3252. "label": "博望区",
  3253. "value": "340506"
  3254. }, {
  3255. "label": "当涂县",
  3256. "value": "340521"
  3257. }, {
  3258. "label": "含山县",
  3259. "value": "340522"
  3260. }, {
  3261. "label": "和县",
  3262. "value": "340523"
  3263. }],
  3264. [{
  3265. "label": "市辖区",
  3266. "value": "340601"
  3267. }, {
  3268. "label": "杜集区",
  3269. "value": "340602"
  3270. }, {
  3271. "label": "相山区",
  3272. "value": "340603"
  3273. }, {
  3274. "label": "烈山区",
  3275. "value": "340604"
  3276. }, {
  3277. "label": "濉溪县",
  3278. "value": "340621"
  3279. }],
  3280. [{
  3281. "label": "市辖区",
  3282. "value": "340701"
  3283. }, {
  3284. "label": "铜官区",
  3285. "value": "340705"
  3286. }, {
  3287. "label": "义安区",
  3288. "value": "340706"
  3289. }, {
  3290. "label": "郊区",
  3291. "value": "340711"
  3292. }, {
  3293. "label": "枞阳县",
  3294. "value": "340722"
  3295. }],
  3296. [{
  3297. "label": "市辖区",
  3298. "value": "340801"
  3299. }, {
  3300. "label": "迎江区",
  3301. "value": "340802"
  3302. }, {
  3303. "label": "大观区",
  3304. "value": "340803"
  3305. }, {
  3306. "label": "宜秀区",
  3307. "value": "340811"
  3308. }, {
  3309. "label": "怀宁县",
  3310. "value": "340822"
  3311. }, {
  3312. "label": "潜山县",
  3313. "value": "340824"
  3314. }, {
  3315. "label": "太湖县",
  3316. "value": "340825"
  3317. }, {
  3318. "label": "宿松县",
  3319. "value": "340826"
  3320. }, {
  3321. "label": "望江县",
  3322. "value": "340827"
  3323. }, {
  3324. "label": "岳西县",
  3325. "value": "340828"
  3326. }, {
  3327. "label": "桐城市",
  3328. "value": "340881"
  3329. }],
  3330. [{
  3331. "label": "市辖区",
  3332. "value": "341001"
  3333. }, {
  3334. "label": "屯溪区",
  3335. "value": "341002"
  3336. }, {
  3337. "label": "黄山区",
  3338. "value": "341003"
  3339. }, {
  3340. "label": "徽州区",
  3341. "value": "341004"
  3342. }, {
  3343. "label": "歙县",
  3344. "value": "341021"
  3345. }, {
  3346. "label": "休宁县",
  3347. "value": "341022"
  3348. }, {
  3349. "label": "黟县",
  3350. "value": "341023"
  3351. }, {
  3352. "label": "祁门县",
  3353. "value": "341024"
  3354. }],
  3355. [{
  3356. "label": "市辖区",
  3357. "value": "341101"
  3358. }, {
  3359. "label": "琅琊区",
  3360. "value": "341102"
  3361. }, {
  3362. "label": "南谯区",
  3363. "value": "341103"
  3364. }, {
  3365. "label": "来安县",
  3366. "value": "341122"
  3367. }, {
  3368. "label": "全椒县",
  3369. "value": "341124"
  3370. }, {
  3371. "label": "定远县",
  3372. "value": "341125"
  3373. }, {
  3374. "label": "凤阳县",
  3375. "value": "341126"
  3376. }, {
  3377. "label": "天长市",
  3378. "value": "341181"
  3379. }, {
  3380. "label": "明光市",
  3381. "value": "341182"
  3382. }],
  3383. [{
  3384. "label": "市辖区",
  3385. "value": "341201"
  3386. }, {
  3387. "label": "颍州区",
  3388. "value": "341202"
  3389. }, {
  3390. "label": "颍东区",
  3391. "value": "341203"
  3392. }, {
  3393. "label": "颍泉区",
  3394. "value": "341204"
  3395. }, {
  3396. "label": "临泉县",
  3397. "value": "341221"
  3398. }, {
  3399. "label": "太和县",
  3400. "value": "341222"
  3401. }, {
  3402. "label": "阜南县",
  3403. "value": "341225"
  3404. }, {
  3405. "label": "颍上县",
  3406. "value": "341226"
  3407. }, {
  3408. "label": "界首市",
  3409. "value": "341282"
  3410. }],
  3411. [{
  3412. "label": "市辖区",
  3413. "value": "341301"
  3414. }, {
  3415. "label": "埇桥区",
  3416. "value": "341302"
  3417. }, {
  3418. "label": "砀山县",
  3419. "value": "341321"
  3420. }, {
  3421. "label": "萧县",
  3422. "value": "341322"
  3423. }, {
  3424. "label": "灵璧县",
  3425. "value": "341323"
  3426. }, {
  3427. "label": "泗县",
  3428. "value": "341324"
  3429. }],
  3430. [{
  3431. "label": "市辖区",
  3432. "value": "341501"
  3433. }, {
  3434. "label": "金安区",
  3435. "value": "341502"
  3436. }, {
  3437. "label": "裕安区",
  3438. "value": "341503"
  3439. }, {
  3440. "label": "叶集区",
  3441. "value": "341504"
  3442. }, {
  3443. "label": "霍邱县",
  3444. "value": "341522"
  3445. }, {
  3446. "label": "舒城县",
  3447. "value": "341523"
  3448. }, {
  3449. "label": "金寨县",
  3450. "value": "341524"
  3451. }, {
  3452. "label": "霍山县",
  3453. "value": "341525"
  3454. }],
  3455. [{
  3456. "label": "市辖区",
  3457. "value": "341601"
  3458. }, {
  3459. "label": "谯城区",
  3460. "value": "341602"
  3461. }, {
  3462. "label": "涡阳县",
  3463. "value": "341621"
  3464. }, {
  3465. "label": "蒙城县",
  3466. "value": "341622"
  3467. }, {
  3468. "label": "利辛县",
  3469. "value": "341623"
  3470. }],
  3471. [{
  3472. "label": "市辖区",
  3473. "value": "341701"
  3474. }, {
  3475. "label": "贵池区",
  3476. "value": "341702"
  3477. }, {
  3478. "label": "东至县",
  3479. "value": "341721"
  3480. }, {
  3481. "label": "石台县",
  3482. "value": "341722"
  3483. }, {
  3484. "label": "青阳县",
  3485. "value": "341723"
  3486. }],
  3487. [{
  3488. "label": "市辖区",
  3489. "value": "341801"
  3490. }, {
  3491. "label": "宣州区",
  3492. "value": "341802"
  3493. }, {
  3494. "label": "郎溪县",
  3495. "value": "341821"
  3496. }, {
  3497. "label": "广德县",
  3498. "value": "341822"
  3499. }, {
  3500. "label": "泾县",
  3501. "value": "341823"
  3502. }, {
  3503. "label": "绩溪县",
  3504. "value": "341824"
  3505. }, {
  3506. "label": "旌德县",
  3507. "value": "341825"
  3508. }, {
  3509. "label": "宁国市",
  3510. "value": "341881"
  3511. }]
  3512. ],
  3513. [
  3514. [{
  3515. "label": "市辖区",
  3516. "value": "350101"
  3517. }, {
  3518. "label": "鼓楼区",
  3519. "value": "350102"
  3520. }, {
  3521. "label": "台江区",
  3522. "value": "350103"
  3523. }, {
  3524. "label": "仓山区",
  3525. "value": "350104"
  3526. }, {
  3527. "label": "马尾区",
  3528. "value": "350105"
  3529. }, {
  3530. "label": "晋安区",
  3531. "value": "350111"
  3532. }, {
  3533. "label": "闽侯县",
  3534. "value": "350121"
  3535. }, {
  3536. "label": "连江县",
  3537. "value": "350122"
  3538. }, {
  3539. "label": "罗源县",
  3540. "value": "350123"
  3541. }, {
  3542. "label": "闽清县",
  3543. "value": "350124"
  3544. }, {
  3545. "label": "永泰县",
  3546. "value": "350125"
  3547. }, {
  3548. "label": "平潭县",
  3549. "value": "350128"
  3550. }, {
  3551. "label": "福清市",
  3552. "value": "350181"
  3553. }, {
  3554. "label": "长乐市",
  3555. "value": "350182"
  3556. }],
  3557. [{
  3558. "label": "市辖区",
  3559. "value": "350201"
  3560. }, {
  3561. "label": "思明区",
  3562. "value": "350203"
  3563. }, {
  3564. "label": "海沧区",
  3565. "value": "350205"
  3566. }, {
  3567. "label": "湖里区",
  3568. "value": "350206"
  3569. }, {
  3570. "label": "集美区",
  3571. "value": "350211"
  3572. }, {
  3573. "label": "同安区",
  3574. "value": "350212"
  3575. }, {
  3576. "label": "翔安区",
  3577. "value": "350213"
  3578. }],
  3579. [{
  3580. "label": "市辖区",
  3581. "value": "350301"
  3582. }, {
  3583. "label": "城厢区",
  3584. "value": "350302"
  3585. }, {
  3586. "label": "涵江区",
  3587. "value": "350303"
  3588. }, {
  3589. "label": "荔城区",
  3590. "value": "350304"
  3591. }, {
  3592. "label": "秀屿区",
  3593. "value": "350305"
  3594. }, {
  3595. "label": "仙游县",
  3596. "value": "350322"
  3597. }],
  3598. [{
  3599. "label": "市辖区",
  3600. "value": "350401"
  3601. }, {
  3602. "label": "梅列区",
  3603. "value": "350402"
  3604. }, {
  3605. "label": "三元区",
  3606. "value": "350403"
  3607. }, {
  3608. "label": "明溪县",
  3609. "value": "350421"
  3610. }, {
  3611. "label": "清流县",
  3612. "value": "350423"
  3613. }, {
  3614. "label": "宁化县",
  3615. "value": "350424"
  3616. }, {
  3617. "label": "大田县",
  3618. "value": "350425"
  3619. }, {
  3620. "label": "尤溪县",
  3621. "value": "350426"
  3622. }, {
  3623. "label": "沙县",
  3624. "value": "350427"
  3625. }, {
  3626. "label": "将乐县",
  3627. "value": "350428"
  3628. }, {
  3629. "label": "泰宁县",
  3630. "value": "350429"
  3631. }, {
  3632. "label": "建宁县",
  3633. "value": "350430"
  3634. }, {
  3635. "label": "永安市",
  3636. "value": "350481"
  3637. }],
  3638. [{
  3639. "label": "市辖区",
  3640. "value": "350501"
  3641. }, {
  3642. "label": "鲤城区",
  3643. "value": "350502"
  3644. }, {
  3645. "label": "丰泽区",
  3646. "value": "350503"
  3647. }, {
  3648. "label": "洛江区",
  3649. "value": "350504"
  3650. }, {
  3651. "label": "泉港区",
  3652. "value": "350505"
  3653. }, {
  3654. "label": "惠安县",
  3655. "value": "350521"
  3656. }, {
  3657. "label": "安溪县",
  3658. "value": "350524"
  3659. }, {
  3660. "label": "永春县",
  3661. "value": "350525"
  3662. }, {
  3663. "label": "德化县",
  3664. "value": "350526"
  3665. }, {
  3666. "label": "金门县",
  3667. "value": "350527"
  3668. }, {
  3669. "label": "石狮市",
  3670. "value": "350581"
  3671. }, {
  3672. "label": "晋江市",
  3673. "value": "350582"
  3674. }, {
  3675. "label": "南安市",
  3676. "value": "350583"
  3677. }],
  3678. [{
  3679. "label": "市辖区",
  3680. "value": "350601"
  3681. }, {
  3682. "label": "芗城区",
  3683. "value": "350602"
  3684. }, {
  3685. "label": "龙文区",
  3686. "value": "350603"
  3687. }, {
  3688. "label": "云霄县",
  3689. "value": "350622"
  3690. }, {
  3691. "label": "漳浦县",
  3692. "value": "350623"
  3693. }, {
  3694. "label": "诏安县",
  3695. "value": "350624"
  3696. }, {
  3697. "label": "长泰县",
  3698. "value": "350625"
  3699. }, {
  3700. "label": "东山县",
  3701. "value": "350626"
  3702. }, {
  3703. "label": "南靖县",
  3704. "value": "350627"
  3705. }, {
  3706. "label": "平和县",
  3707. "value": "350628"
  3708. }, {
  3709. "label": "华安县",
  3710. "value": "350629"
  3711. }, {
  3712. "label": "龙海市",
  3713. "value": "350681"
  3714. }],
  3715. [{
  3716. "label": "市辖区",
  3717. "value": "350701"
  3718. }, {
  3719. "label": "延平区",
  3720. "value": "350702"
  3721. }, {
  3722. "label": "建阳区",
  3723. "value": "350703"
  3724. }, {
  3725. "label": "顺昌县",
  3726. "value": "350721"
  3727. }, {
  3728. "label": "浦城县",
  3729. "value": "350722"
  3730. }, {
  3731. "label": "光泽县",
  3732. "value": "350723"
  3733. }, {
  3734. "label": "松溪县",
  3735. "value": "350724"
  3736. }, {
  3737. "label": "政和县",
  3738. "value": "350725"
  3739. }, {
  3740. "label": "邵武市",
  3741. "value": "350781"
  3742. }, {
  3743. "label": "武夷山市",
  3744. "value": "350782"
  3745. }, {
  3746. "label": "建瓯市",
  3747. "value": "350783"
  3748. }],
  3749. [{
  3750. "label": "市辖区",
  3751. "value": "350801"
  3752. }, {
  3753. "label": "新罗区",
  3754. "value": "350802"
  3755. }, {
  3756. "label": "永定区",
  3757. "value": "350803"
  3758. }, {
  3759. "label": "长汀县",
  3760. "value": "350821"
  3761. }, {
  3762. "label": "上杭县",
  3763. "value": "350823"
  3764. }, {
  3765. "label": "武平县",
  3766. "value": "350824"
  3767. }, {
  3768. "label": "连城县",
  3769. "value": "350825"
  3770. }, {
  3771. "label": "漳平市",
  3772. "value": "350881"
  3773. }],
  3774. [{
  3775. "label": "市辖区",
  3776. "value": "350901"
  3777. }, {
  3778. "label": "蕉城区",
  3779. "value": "350902"
  3780. }, {
  3781. "label": "霞浦县",
  3782. "value": "350921"
  3783. }, {
  3784. "label": "古田县",
  3785. "value": "350922"
  3786. }, {
  3787. "label": "屏南县",
  3788. "value": "350923"
  3789. }, {
  3790. "label": "寿宁县",
  3791. "value": "350924"
  3792. }, {
  3793. "label": "周宁县",
  3794. "value": "350925"
  3795. }, {
  3796. "label": "柘荣县",
  3797. "value": "350926"
  3798. }, {
  3799. "label": "福安市",
  3800. "value": "350981"
  3801. }, {
  3802. "label": "福鼎市",
  3803. "value": "350982"
  3804. }]
  3805. ],
  3806. [
  3807. [{
  3808. "label": "市辖区",
  3809. "value": "360101"
  3810. }, {
  3811. "label": "东湖区",
  3812. "value": "360102"
  3813. }, {
  3814. "label": "西湖区",
  3815. "value": "360103"
  3816. }, {
  3817. "label": "青云谱区",
  3818. "value": "360104"
  3819. }, {
  3820. "label": "湾里区",
  3821. "value": "360105"
  3822. }, {
  3823. "label": "青山湖区",
  3824. "value": "360111"
  3825. }, {
  3826. "label": "新建区",
  3827. "value": "360112"
  3828. }, {
  3829. "label": "南昌县",
  3830. "value": "360121"
  3831. }, {
  3832. "label": "安义县",
  3833. "value": "360123"
  3834. }, {
  3835. "label": "进贤县",
  3836. "value": "360124"
  3837. }],
  3838. [{
  3839. "label": "市辖区",
  3840. "value": "360201"
  3841. }, {
  3842. "label": "昌江区",
  3843. "value": "360202"
  3844. }, {
  3845. "label": "珠山区",
  3846. "value": "360203"
  3847. }, {
  3848. "label": "浮梁县",
  3849. "value": "360222"
  3850. }, {
  3851. "label": "乐平市",
  3852. "value": "360281"
  3853. }],
  3854. [{
  3855. "label": "市辖区",
  3856. "value": "360301"
  3857. }, {
  3858. "label": "安源区",
  3859. "value": "360302"
  3860. }, {
  3861. "label": "湘东区",
  3862. "value": "360313"
  3863. }, {
  3864. "label": "莲花县",
  3865. "value": "360321"
  3866. }, {
  3867. "label": "上栗县",
  3868. "value": "360322"
  3869. }, {
  3870. "label": "芦溪县",
  3871. "value": "360323"
  3872. }],
  3873. [{
  3874. "label": "市辖区",
  3875. "value": "360401"
  3876. }, {
  3877. "label": "濂溪区",
  3878. "value": "360402"
  3879. }, {
  3880. "label": "浔阳区",
  3881. "value": "360403"
  3882. }, {
  3883. "label": "九江县",
  3884. "value": "360421"
  3885. }, {
  3886. "label": "武宁县",
  3887. "value": "360423"
  3888. }, {
  3889. "label": "修水县",
  3890. "value": "360424"
  3891. }, {
  3892. "label": "永修县",
  3893. "value": "360425"
  3894. }, {
  3895. "label": "德安县",
  3896. "value": "360426"
  3897. }, {
  3898. "label": "都昌县",
  3899. "value": "360428"
  3900. }, {
  3901. "label": "湖口县",
  3902. "value": "360429"
  3903. }, {
  3904. "label": "彭泽县",
  3905. "value": "360430"
  3906. }, {
  3907. "label": "瑞昌市",
  3908. "value": "360481"
  3909. }, {
  3910. "label": "共青城市",
  3911. "value": "360482"
  3912. }, {
  3913. "label": "庐山市",
  3914. "value": "360483"
  3915. }],
  3916. [{
  3917. "label": "市辖区",
  3918. "value": "360501"
  3919. }, {
  3920. "label": "渝水区",
  3921. "value": "360502"
  3922. }, {
  3923. "label": "分宜县",
  3924. "value": "360521"
  3925. }],
  3926. [{
  3927. "label": "市辖区",
  3928. "value": "360601"
  3929. }, {
  3930. "label": "月湖区",
  3931. "value": "360602"
  3932. }, {
  3933. "label": "余江县",
  3934. "value": "360622"
  3935. }, {
  3936. "label": "贵溪市",
  3937. "value": "360681"
  3938. }],
  3939. [{
  3940. "label": "市辖区",
  3941. "value": "360701"
  3942. }, {
  3943. "label": "章贡区",
  3944. "value": "360702"
  3945. }, {
  3946. "label": "南康区",
  3947. "value": "360703"
  3948. }, {
  3949. "label": "赣县",
  3950. "value": "360721"
  3951. }, {
  3952. "label": "信丰县",
  3953. "value": "360722"
  3954. }, {
  3955. "label": "大余县",
  3956. "value": "360723"
  3957. }, {
  3958. "label": "上犹县",
  3959. "value": "360724"
  3960. }, {
  3961. "label": "崇义县",
  3962. "value": "360725"
  3963. }, {
  3964. "label": "安远县",
  3965. "value": "360726"
  3966. }, {
  3967. "label": "龙南县",
  3968. "value": "360727"
  3969. }, {
  3970. "label": "定南县",
  3971. "value": "360728"
  3972. }, {
  3973. "label": "全南县",
  3974. "value": "360729"
  3975. }, {
  3976. "label": "宁都县",
  3977. "value": "360730"
  3978. }, {
  3979. "label": "于都县",
  3980. "value": "360731"
  3981. }, {
  3982. "label": "兴国县",
  3983. "value": "360732"
  3984. }, {
  3985. "label": "会昌县",
  3986. "value": "360733"
  3987. }, {
  3988. "label": "寻乌县",
  3989. "value": "360734"
  3990. }, {
  3991. "label": "石城县",
  3992. "value": "360735"
  3993. }, {
  3994. "label": "瑞金市",
  3995. "value": "360781"
  3996. }],
  3997. [{
  3998. "label": "市辖区",
  3999. "value": "360801"
  4000. }, {
  4001. "label": "吉州区",
  4002. "value": "360802"
  4003. }, {
  4004. "label": "青原区",
  4005. "value": "360803"
  4006. }, {
  4007. "label": "吉安县",
  4008. "value": "360821"
  4009. }, {
  4010. "label": "吉水县",
  4011. "value": "360822"
  4012. }, {
  4013. "label": "峡江县",
  4014. "value": "360823"
  4015. }, {
  4016. "label": "新干县",
  4017. "value": "360824"
  4018. }, {
  4019. "label": "永丰县",
  4020. "value": "360825"
  4021. }, {
  4022. "label": "泰和县",
  4023. "value": "360826"
  4024. }, {
  4025. "label": "遂川县",
  4026. "value": "360827"
  4027. }, {
  4028. "label": "万安县",
  4029. "value": "360828"
  4030. }, {
  4031. "label": "安福县",
  4032. "value": "360829"
  4033. }, {
  4034. "label": "永新县",
  4035. "value": "360830"
  4036. }, {
  4037. "label": "井冈山市",
  4038. "value": "360881"
  4039. }],
  4040. [{
  4041. "label": "市辖区",
  4042. "value": "360901"
  4043. }, {
  4044. "label": "袁州区",
  4045. "value": "360902"
  4046. }, {
  4047. "label": "奉新县",
  4048. "value": "360921"
  4049. }, {
  4050. "label": "万载县",
  4051. "value": "360922"
  4052. }, {
  4053. "label": "上高县",
  4054. "value": "360923"
  4055. }, {
  4056. "label": "宜丰县",
  4057. "value": "360924"
  4058. }, {
  4059. "label": "靖安县",
  4060. "value": "360925"
  4061. }, {
  4062. "label": "铜鼓县",
  4063. "value": "360926"
  4064. }, {
  4065. "label": "丰城市",
  4066. "value": "360981"
  4067. }, {
  4068. "label": "樟树市",
  4069. "value": "360982"
  4070. }, {
  4071. "label": "高安市",
  4072. "value": "360983"
  4073. }],
  4074. [{
  4075. "label": "市辖区",
  4076. "value": "361001"
  4077. }, {
  4078. "label": "临川区",
  4079. "value": "361002"
  4080. }, {
  4081. "label": "南城县",
  4082. "value": "361021"
  4083. }, {
  4084. "label": "黎川县",
  4085. "value": "361022"
  4086. }, {
  4087. "label": "南丰县",
  4088. "value": "361023"
  4089. }, {
  4090. "label": "崇仁县",
  4091. "value": "361024"
  4092. }, {
  4093. "label": "乐安县",
  4094. "value": "361025"
  4095. }, {
  4096. "label": "宜黄县",
  4097. "value": "361026"
  4098. }, {
  4099. "label": "金溪县",
  4100. "value": "361027"
  4101. }, {
  4102. "label": "资溪县",
  4103. "value": "361028"
  4104. }, {
  4105. "label": "东乡县",
  4106. "value": "361029"
  4107. }, {
  4108. "label": "广昌县",
  4109. "value": "361030"
  4110. }],
  4111. [{
  4112. "label": "市辖区",
  4113. "value": "361101"
  4114. }, {
  4115. "label": "信州区",
  4116. "value": "361102"
  4117. }, {
  4118. "label": "广丰区",
  4119. "value": "361103"
  4120. }, {
  4121. "label": "上饶县",
  4122. "value": "361121"
  4123. }, {
  4124. "label": "玉山县",
  4125. "value": "361123"
  4126. }, {
  4127. "label": "铅山县",
  4128. "value": "361124"
  4129. }, {
  4130. "label": "横峰县",
  4131. "value": "361125"
  4132. }, {
  4133. "label": "弋阳县",
  4134. "value": "361126"
  4135. }, {
  4136. "label": "余干县",
  4137. "value": "361127"
  4138. }, {
  4139. "label": "鄱阳县",
  4140. "value": "361128"
  4141. }, {
  4142. "label": "万年县",
  4143. "value": "361129"
  4144. }, {
  4145. "label": "婺源县",
  4146. "value": "361130"
  4147. }, {
  4148. "label": "德兴市",
  4149. "value": "361181"
  4150. }]
  4151. ],
  4152. [
  4153. [{
  4154. "label": "市辖区",
  4155. "value": "370101"
  4156. }, {
  4157. "label": "历下区",
  4158. "value": "370102"
  4159. }, {
  4160. "label": "市中区",
  4161. "value": "370103"
  4162. }, {
  4163. "label": "槐荫区",
  4164. "value": "370104"
  4165. }, {
  4166. "label": "天桥区",
  4167. "value": "370105"
  4168. }, {
  4169. "label": "历城区",
  4170. "value": "370112"
  4171. }, {
  4172. "label": "长清区",
  4173. "value": "370113"
  4174. }, {
  4175. "label": "平阴县",
  4176. "value": "370124"
  4177. }, {
  4178. "label": "济阳县",
  4179. "value": "370125"
  4180. }, {
  4181. "label": "商河县",
  4182. "value": "370126"
  4183. }, {
  4184. "label": "章丘市",
  4185. "value": "370181"
  4186. }],
  4187. [{
  4188. "label": "市辖区",
  4189. "value": "370201"
  4190. }, {
  4191. "label": "市南区",
  4192. "value": "370202"
  4193. }, {
  4194. "label": "市北区",
  4195. "value": "370203"
  4196. }, {
  4197. "label": "黄岛区",
  4198. "value": "370211"
  4199. }, {
  4200. "label": "崂山区",
  4201. "value": "370212"
  4202. }, {
  4203. "label": "李沧区",
  4204. "value": "370213"
  4205. }, {
  4206. "label": "城阳区",
  4207. "value": "370214"
  4208. }, {
  4209. "label": "胶州市",
  4210. "value": "370281"
  4211. }, {
  4212. "label": "即墨市",
  4213. "value": "370282"
  4214. }, {
  4215. "label": "平度市",
  4216. "value": "370283"
  4217. }, {
  4218. "label": "莱西市",
  4219. "value": "370285"
  4220. }],
  4221. [{
  4222. "label": "市辖区",
  4223. "value": "370301"
  4224. }, {
  4225. "label": "淄川区",
  4226. "value": "370302"
  4227. }, {
  4228. "label": "张店区",
  4229. "value": "370303"
  4230. }, {
  4231. "label": "博山区",
  4232. "value": "370304"
  4233. }, {
  4234. "label": "临淄区",
  4235. "value": "370305"
  4236. }, {
  4237. "label": "周村区",
  4238. "value": "370306"
  4239. }, {
  4240. "label": "桓台县",
  4241. "value": "370321"
  4242. }, {
  4243. "label": "高青县",
  4244. "value": "370322"
  4245. }, {
  4246. "label": "沂源县",
  4247. "value": "370323"
  4248. }],
  4249. [{
  4250. "label": "市辖区",
  4251. "value": "370401"
  4252. }, {
  4253. "label": "市中区",
  4254. "value": "370402"
  4255. }, {
  4256. "label": "薛城区",
  4257. "value": "370403"
  4258. }, {
  4259. "label": "峄城区",
  4260. "value": "370404"
  4261. }, {
  4262. "label": "台儿庄区",
  4263. "value": "370405"
  4264. }, {
  4265. "label": "山亭区",
  4266. "value": "370406"
  4267. }, {
  4268. "label": "滕州市",
  4269. "value": "370481"
  4270. }],
  4271. [{
  4272. "label": "市辖区",
  4273. "value": "370501"
  4274. }, {
  4275. "label": "东营区",
  4276. "value": "370502"
  4277. }, {
  4278. "label": "河口区",
  4279. "value": "370503"
  4280. }, {
  4281. "label": "垦利区",
  4282. "value": "370505"
  4283. }, {
  4284. "label": "利津县",
  4285. "value": "370522"
  4286. }, {
  4287. "label": "广饶县",
  4288. "value": "370523"
  4289. }],
  4290. [{
  4291. "label": "市辖区",
  4292. "value": "370601"
  4293. }, {
  4294. "label": "芝罘区",
  4295. "value": "370602"
  4296. }, {
  4297. "label": "福山区",
  4298. "value": "370611"
  4299. }, {
  4300. "label": "牟平区",
  4301. "value": "370612"
  4302. }, {
  4303. "label": "莱山区",
  4304. "value": "370613"
  4305. }, {
  4306. "label": "长岛县",
  4307. "value": "370634"
  4308. }, {
  4309. "label": "龙口市",
  4310. "value": "370681"
  4311. }, {
  4312. "label": "莱阳市",
  4313. "value": "370682"
  4314. }, {
  4315. "label": "莱州市",
  4316. "value": "370683"
  4317. }, {
  4318. "label": "蓬莱市",
  4319. "value": "370684"
  4320. }, {
  4321. "label": "招远市",
  4322. "value": "370685"
  4323. }, {
  4324. "label": "栖霞市",
  4325. "value": "370686"
  4326. }, {
  4327. "label": "海阳市",
  4328. "value": "370687"
  4329. }],
  4330. [{
  4331. "label": "市辖区",
  4332. "value": "370701"
  4333. }, {
  4334. "label": "潍城区",
  4335. "value": "370702"
  4336. }, {
  4337. "label": "寒亭区",
  4338. "value": "370703"
  4339. }, {
  4340. "label": "坊子区",
  4341. "value": "370704"
  4342. }, {
  4343. "label": "奎文区",
  4344. "value": "370705"
  4345. }, {
  4346. "label": "临朐县",
  4347. "value": "370724"
  4348. }, {
  4349. "label": "昌乐县",
  4350. "value": "370725"
  4351. }, {
  4352. "label": "青州市",
  4353. "value": "370781"
  4354. }, {
  4355. "label": "诸城市",
  4356. "value": "370782"
  4357. }, {
  4358. "label": "寿光市",
  4359. "value": "370783"
  4360. }, {
  4361. "label": "安丘市",
  4362. "value": "370784"
  4363. }, {
  4364. "label": "高密市",
  4365. "value": "370785"
  4366. }, {
  4367. "label": "昌邑市",
  4368. "value": "370786"
  4369. }],
  4370. [{
  4371. "label": "市辖区",
  4372. "value": "370801"
  4373. }, {
  4374. "label": "任城区",
  4375. "value": "370811"
  4376. }, {
  4377. "label": "兖州区",
  4378. "value": "370812"
  4379. }, {
  4380. "label": "微山县",
  4381. "value": "370826"
  4382. }, {
  4383. "label": "鱼台县",
  4384. "value": "370827"
  4385. }, {
  4386. "label": "金乡县",
  4387. "value": "370828"
  4388. }, {
  4389. "label": "嘉祥县",
  4390. "value": "370829"
  4391. }, {
  4392. "label": "汶上县",
  4393. "value": "370830"
  4394. }, {
  4395. "label": "泗水县",
  4396. "value": "370831"
  4397. }, {
  4398. "label": "梁山县",
  4399. "value": "370832"
  4400. }, {
  4401. "label": "曲阜市",
  4402. "value": "370881"
  4403. }, {
  4404. "label": "邹城市",
  4405. "value": "370883"
  4406. }],
  4407. [{
  4408. "label": "市辖区",
  4409. "value": "370901"
  4410. }, {
  4411. "label": "泰山区",
  4412. "value": "370902"
  4413. }, {
  4414. "label": "岱岳区",
  4415. "value": "370911"
  4416. }, {
  4417. "label": "宁阳县",
  4418. "value": "370921"
  4419. }, {
  4420. "label": "东平县",
  4421. "value": "370923"
  4422. }, {
  4423. "label": "新泰市",
  4424. "value": "370982"
  4425. }, {
  4426. "label": "肥城市",
  4427. "value": "370983"
  4428. }],
  4429. [{
  4430. "label": "市辖区",
  4431. "value": "371001"
  4432. }, {
  4433. "label": "环翠区",
  4434. "value": "371002"
  4435. }, {
  4436. "label": "文登区",
  4437. "value": "371003"
  4438. }, {
  4439. "label": "荣成市",
  4440. "value": "371082"
  4441. }, {
  4442. "label": "乳山市",
  4443. "value": "371083"
  4444. }],
  4445. [{
  4446. "label": "市辖区",
  4447. "value": "371101"
  4448. }, {
  4449. "label": "东港区",
  4450. "value": "371102"
  4451. }, {
  4452. "label": "岚山区",
  4453. "value": "371103"
  4454. }, {
  4455. "label": "五莲县",
  4456. "value": "371121"
  4457. }, {
  4458. "label": "莒县",
  4459. "value": "371122"
  4460. }],
  4461. [{
  4462. "label": "市辖区",
  4463. "value": "371201"
  4464. }, {
  4465. "label": "莱城区",
  4466. "value": "371202"
  4467. }, {
  4468. "label": "钢城区",
  4469. "value": "371203"
  4470. }],
  4471. [{
  4472. "label": "市辖区",
  4473. "value": "371301"
  4474. }, {
  4475. "label": "兰山区",
  4476. "value": "371302"
  4477. }, {
  4478. "label": "罗庄区",
  4479. "value": "371311"
  4480. }, {
  4481. "label": "河东区",
  4482. "value": "371312"
  4483. }, {
  4484. "label": "沂南县",
  4485. "value": "371321"
  4486. }, {
  4487. "label": "郯城县",
  4488. "value": "371322"
  4489. }, {
  4490. "label": "沂水县",
  4491. "value": "371323"
  4492. }, {
  4493. "label": "兰陵县",
  4494. "value": "371324"
  4495. }, {
  4496. "label": "费县",
  4497. "value": "371325"
  4498. }, {
  4499. "label": "平邑县",
  4500. "value": "371326"
  4501. }, {
  4502. "label": "莒南县",
  4503. "value": "371327"
  4504. }, {
  4505. "label": "蒙阴县",
  4506. "value": "371328"
  4507. }, {
  4508. "label": "临沭县",
  4509. "value": "371329"
  4510. }],
  4511. [{
  4512. "label": "市辖区",
  4513. "value": "371401"
  4514. }, {
  4515. "label": "德城区",
  4516. "value": "371402"
  4517. }, {
  4518. "label": "陵城区",
  4519. "value": "371403"
  4520. }, {
  4521. "label": "宁津县",
  4522. "value": "371422"
  4523. }, {
  4524. "label": "庆云县",
  4525. "value": "371423"
  4526. }, {
  4527. "label": "临邑县",
  4528. "value": "371424"
  4529. }, {
  4530. "label": "齐河县",
  4531. "value": "371425"
  4532. }, {
  4533. "label": "平原县",
  4534. "value": "371426"
  4535. }, {
  4536. "label": "夏津县",
  4537. "value": "371427"
  4538. }, {
  4539. "label": "武城县",
  4540. "value": "371428"
  4541. }, {
  4542. "label": "乐陵市",
  4543. "value": "371481"
  4544. }, {
  4545. "label": "禹城市",
  4546. "value": "371482"
  4547. }],
  4548. [{
  4549. "label": "市辖区",
  4550. "value": "371501"
  4551. }, {
  4552. "label": "东昌府区",
  4553. "value": "371502"
  4554. }, {
  4555. "label": "阳谷县",
  4556. "value": "371521"
  4557. }, {
  4558. "label": "莘县",
  4559. "value": "371522"
  4560. }, {
  4561. "label": "茌平县",
  4562. "value": "371523"
  4563. }, {
  4564. "label": "东阿县",
  4565. "value": "371524"
  4566. }, {
  4567. "label": "冠县",
  4568. "value": "371525"
  4569. }, {
  4570. "label": "高唐县",
  4571. "value": "371526"
  4572. }, {
  4573. "label": "临清市",
  4574. "value": "371581"
  4575. }],
  4576. [{
  4577. "label": "市辖区",
  4578. "value": "371601"
  4579. }, {
  4580. "label": "滨城区",
  4581. "value": "371602"
  4582. }, {
  4583. "label": "沾化区",
  4584. "value": "371603"
  4585. }, {
  4586. "label": "惠民县",
  4587. "value": "371621"
  4588. }, {
  4589. "label": "阳信县",
  4590. "value": "371622"
  4591. }, {
  4592. "label": "无棣县",
  4593. "value": "371623"
  4594. }, {
  4595. "label": "博兴县",
  4596. "value": "371625"
  4597. }, {
  4598. "label": "邹平县",
  4599. "value": "371626"
  4600. }],
  4601. [{
  4602. "label": "市辖区",
  4603. "value": "371701"
  4604. }, {
  4605. "label": "牡丹区",
  4606. "value": "371702"
  4607. }, {
  4608. "label": "定陶区",
  4609. "value": "371703"
  4610. }, {
  4611. "label": "曹县",
  4612. "value": "371721"
  4613. }, {
  4614. "label": "单县",
  4615. "value": "371722"
  4616. }, {
  4617. "label": "成武县",
  4618. "value": "371723"
  4619. }, {
  4620. "label": "巨野县",
  4621. "value": "371724"
  4622. }, {
  4623. "label": "郓城县",
  4624. "value": "371725"
  4625. }, {
  4626. "label": "鄄城县",
  4627. "value": "371726"
  4628. }, {
  4629. "label": "东明县",
  4630. "value": "371728"
  4631. }]
  4632. ],
  4633. [
  4634. [{
  4635. "label": "市辖区",
  4636. "value": "410101"
  4637. }, {
  4638. "label": "中原区",
  4639. "value": "410102"
  4640. }, {
  4641. "label": "二七区",
  4642. "value": "410103"
  4643. }, {
  4644. "label": "管城回族区",
  4645. "value": "410104"
  4646. }, {
  4647. "label": "金水区",
  4648. "value": "410105"
  4649. }, {
  4650. "label": "上街区",
  4651. "value": "410106"
  4652. }, {
  4653. "label": "惠济区",
  4654. "value": "410108"
  4655. }, {
  4656. "label": "中牟县",
  4657. "value": "410122"
  4658. }, {
  4659. "label": "巩义市",
  4660. "value": "410181"
  4661. }, {
  4662. "label": "荥阳市",
  4663. "value": "410182"
  4664. }, {
  4665. "label": "新密市",
  4666. "value": "410183"
  4667. }, {
  4668. "label": "新郑市",
  4669. "value": "410184"
  4670. }, {
  4671. "label": "登封市",
  4672. "value": "410185"
  4673. }, {
  4674. "label": "郑东新区",
  4675. "value": "920002"
  4676. }],
  4677. [{
  4678. "label": "市辖区",
  4679. "value": "410201"
  4680. }, {
  4681. "label": "龙亭区",
  4682. "value": "410202"
  4683. }, {
  4684. "label": "顺河回族区",
  4685. "value": "410203"
  4686. }, {
  4687. "label": "鼓楼区",
  4688. "value": "410204"
  4689. }, {
  4690. "label": "禹王台区",
  4691. "value": "410205"
  4692. }, {
  4693. "label": "金明区",
  4694. "value": "410211"
  4695. }, {
  4696. "label": "祥符区",
  4697. "value": "410212"
  4698. }, {
  4699. "label": "杞县",
  4700. "value": "410221"
  4701. }, {
  4702. "label": "通许县",
  4703. "value": "410222"
  4704. }, {
  4705. "label": "尉氏县",
  4706. "value": "410223"
  4707. }, {
  4708. "label": "兰考县",
  4709. "value": "410225"
  4710. }],
  4711. [{
  4712. "label": "市辖区",
  4713. "value": "410301"
  4714. }, {
  4715. "label": "老城区",
  4716. "value": "410302"
  4717. }, {
  4718. "label": "西工区",
  4719. "value": "410303"
  4720. }, {
  4721. "label": "瀍河回族区",
  4722. "value": "410304"
  4723. }, {
  4724. "label": "涧西区",
  4725. "value": "410305"
  4726. }, {
  4727. "label": "吉利区",
  4728. "value": "410306"
  4729. }, {
  4730. "label": "洛龙区",
  4731. "value": "410311"
  4732. }, {
  4733. "label": "孟津县",
  4734. "value": "410322"
  4735. }, {
  4736. "label": "新安县",
  4737. "value": "410323"
  4738. }, {
  4739. "label": "栾川县",
  4740. "value": "410324"
  4741. }, {
  4742. "label": "嵩县",
  4743. "value": "410325"
  4744. }, {
  4745. "label": "汝阳县",
  4746. "value": "410326"
  4747. }, {
  4748. "label": "宜阳县",
  4749. "value": "410327"
  4750. }, {
  4751. "label": "洛宁县",
  4752. "value": "410328"
  4753. }, {
  4754. "label": "伊川县",
  4755. "value": "410329"
  4756. }, {
  4757. "label": "偃师市",
  4758. "value": "410381"
  4759. }],
  4760. [{
  4761. "label": "市辖区",
  4762. "value": "410401"
  4763. }, {
  4764. "label": "新华区",
  4765. "value": "410402"
  4766. }, {
  4767. "label": "卫东区",
  4768. "value": "410403"
  4769. }, {
  4770. "label": "石龙区",
  4771. "value": "410404"
  4772. }, {
  4773. "label": "湛河区",
  4774. "value": "410411"
  4775. }, {
  4776. "label": "宝丰县",
  4777. "value": "410421"
  4778. }, {
  4779. "label": "叶县",
  4780. "value": "410422"
  4781. }, {
  4782. "label": "鲁山县",
  4783. "value": "410423"
  4784. }, {
  4785. "label": "郏县",
  4786. "value": "410425"
  4787. }, {
  4788. "label": "舞钢市",
  4789. "value": "410481"
  4790. }, {
  4791. "label": "汝州市",
  4792. "value": "410482"
  4793. }],
  4794. [{
  4795. "label": "市辖区",
  4796. "value": "410501"
  4797. }, {
  4798. "label": "文峰区",
  4799. "value": "410502"
  4800. }, {
  4801. "label": "北关区",
  4802. "value": "410503"
  4803. }, {
  4804. "label": "殷都区",
  4805. "value": "410505"
  4806. }, {
  4807. "label": "龙安区",
  4808. "value": "410506"
  4809. }, {
  4810. "label": "安阳县",
  4811. "value": "410522"
  4812. }, {
  4813. "label": "汤阴县",
  4814. "value": "410523"
  4815. }, {
  4816. "label": "滑县",
  4817. "value": "410526"
  4818. }, {
  4819. "label": "内黄县",
  4820. "value": "410527"
  4821. }, {
  4822. "label": "林州市",
  4823. "value": "410581"
  4824. }],
  4825. [{
  4826. "label": "市辖区",
  4827. "value": "410601"
  4828. }, {
  4829. "label": "鹤山区",
  4830. "value": "410602"
  4831. }, {
  4832. "label": "山城区",
  4833. "value": "410603"
  4834. }, {
  4835. "label": "淇滨区",
  4836. "value": "410611"
  4837. }, {
  4838. "label": "浚县",
  4839. "value": "410621"
  4840. }, {
  4841. "label": "淇县",
  4842. "value": "410622"
  4843. }],
  4844. [{
  4845. "label": "市辖区",
  4846. "value": "410701"
  4847. }, {
  4848. "label": "红旗区",
  4849. "value": "410702"
  4850. }, {
  4851. "label": "卫滨区",
  4852. "value": "410703"
  4853. }, {
  4854. "label": "凤泉区",
  4855. "value": "410704"
  4856. }, {
  4857. "label": "牧野区",
  4858. "value": "410711"
  4859. }, {
  4860. "label": "新乡县",
  4861. "value": "410721"
  4862. }, {
  4863. "label": "获嘉县",
  4864. "value": "410724"
  4865. }, {
  4866. "label": "原阳县",
  4867. "value": "410725"
  4868. }, {
  4869. "label": "延津县",
  4870. "value": "410726"
  4871. }, {
  4872. "label": "封丘县",
  4873. "value": "410727"
  4874. }, {
  4875. "label": "长垣县",
  4876. "value": "410728"
  4877. }, {
  4878. "label": "卫辉市",
  4879. "value": "410781"
  4880. }, {
  4881. "label": "辉县市",
  4882. "value": "410782"
  4883. }],
  4884. [{
  4885. "label": "市辖区",
  4886. "value": "410801"
  4887. }, {
  4888. "label": "解放区",
  4889. "value": "410802"
  4890. }, {
  4891. "label": "中站区",
  4892. "value": "410803"
  4893. }, {
  4894. "label": "马村区",
  4895. "value": "410804"
  4896. }, {
  4897. "label": "山阳区",
  4898. "value": "410811"
  4899. }, {
  4900. "label": "修武县",
  4901. "value": "410821"
  4902. }, {
  4903. "label": "博爱县",
  4904. "value": "410822"
  4905. }, {
  4906. "label": "武陟县",
  4907. "value": "410823"
  4908. }, {
  4909. "label": "温县",
  4910. "value": "410825"
  4911. }, {
  4912. "label": "沁阳市",
  4913. "value": "410882"
  4914. }, {
  4915. "label": "孟州市",
  4916. "value": "410883"
  4917. }],
  4918. [{
  4919. "label": "市辖区",
  4920. "value": "410901"
  4921. }, {
  4922. "label": "华龙区",
  4923. "value": "410902"
  4924. }, {
  4925. "label": "清丰县",
  4926. "value": "410922"
  4927. }, {
  4928. "label": "南乐县",
  4929. "value": "410923"
  4930. }, {
  4931. "label": "范县",
  4932. "value": "410926"
  4933. }, {
  4934. "label": "台前县",
  4935. "value": "410927"
  4936. }, {
  4937. "label": "濮阳县",
  4938. "value": "410928"
  4939. }],
  4940. [{
  4941. "label": "市辖区",
  4942. "value": "411001"
  4943. }, {
  4944. "label": "魏都区",
  4945. "value": "411002"
  4946. }, {
  4947. "label": "许昌县",
  4948. "value": "411023"
  4949. }, {
  4950. "label": "鄢陵县",
  4951. "value": "411024"
  4952. }, {
  4953. "label": "襄城县",
  4954. "value": "411025"
  4955. }, {
  4956. "label": "禹州市",
  4957. "value": "411081"
  4958. }, {
  4959. "label": "长葛市",
  4960. "value": "411082"
  4961. }],
  4962. [{
  4963. "label": "市辖区",
  4964. "value": "411101"
  4965. }, {
  4966. "label": "源汇区",
  4967. "value": "411102"
  4968. }, {
  4969. "label": "郾城区",
  4970. "value": "411103"
  4971. }, {
  4972. "label": "召陵区",
  4973. "value": "411104"
  4974. }, {
  4975. "label": "舞阳县",
  4976. "value": "411121"
  4977. }, {
  4978. "label": "临颍县",
  4979. "value": "411122"
  4980. }],
  4981. [{
  4982. "label": "市辖区",
  4983. "value": "411201"
  4984. }, {
  4985. "label": "湖滨区",
  4986. "value": "411202"
  4987. }, {
  4988. "label": "陕州区",
  4989. "value": "411203"
  4990. }, {
  4991. "label": "渑池县",
  4992. "value": "411221"
  4993. }, {
  4994. "label": "卢氏县",
  4995. "value": "411224"
  4996. }, {
  4997. "label": "义马市",
  4998. "value": "411281"
  4999. }, {
  5000. "label": "灵宝市",
  5001. "value": "411282"
  5002. }],
  5003. [{
  5004. "label": "市辖区",
  5005. "value": "411301"
  5006. }, {
  5007. "label": "宛城区",
  5008. "value": "411302"
  5009. }, {
  5010. "label": "卧龙区",
  5011. "value": "411303"
  5012. }, {
  5013. "label": "南召县",
  5014. "value": "411321"
  5015. }, {
  5016. "label": "方城县",
  5017. "value": "411322"
  5018. }, {
  5019. "label": "西峡县",
  5020. "value": "411323"
  5021. }, {
  5022. "label": "镇平县",
  5023. "value": "411324"
  5024. }, {
  5025. "label": "内乡县",
  5026. "value": "411325"
  5027. }, {
  5028. "label": "淅川县",
  5029. "value": "411326"
  5030. }, {
  5031. "label": "社旗县",
  5032. "value": "411327"
  5033. }, {
  5034. "label": "唐河县",
  5035. "value": "411328"
  5036. }, {
  5037. "label": "新野县",
  5038. "value": "411329"
  5039. }, {
  5040. "label": "桐柏县",
  5041. "value": "411330"
  5042. }, {
  5043. "label": "邓州市",
  5044. "value": "411381"
  5045. }],
  5046. [{
  5047. "label": "市辖区",
  5048. "value": "411401"
  5049. }, {
  5050. "label": "梁园区",
  5051. "value": "411402"
  5052. }, {
  5053. "label": "睢阳区",
  5054. "value": "411403"
  5055. }, {
  5056. "label": "民权县",
  5057. "value": "411421"
  5058. }, {
  5059. "label": "睢县",
  5060. "value": "411422"
  5061. }, {
  5062. "label": "宁陵县",
  5063. "value": "411423"
  5064. }, {
  5065. "label": "柘城县",
  5066. "value": "411424"
  5067. }, {
  5068. "label": "虞城县",
  5069. "value": "411425"
  5070. }, {
  5071. "label": "夏邑县",
  5072. "value": "411426"
  5073. }, {
  5074. "label": "永城市",
  5075. "value": "411481"
  5076. }],
  5077. [{
  5078. "label": "市辖区",
  5079. "value": "411501"
  5080. }, {
  5081. "label": "浉河区",
  5082. "value": "411502"
  5083. }, {
  5084. "label": "平桥区",
  5085. "value": "411503"
  5086. }, {
  5087. "label": "罗山县",
  5088. "value": "411521"
  5089. }, {
  5090. "label": "光山县",
  5091. "value": "411522"
  5092. }, {
  5093. "label": "新县",
  5094. "value": "411523"
  5095. }, {
  5096. "label": "商城县",
  5097. "value": "411524"
  5098. }, {
  5099. "label": "固始县",
  5100. "value": "411525"
  5101. }, {
  5102. "label": "潢川县",
  5103. "value": "411526"
  5104. }, {
  5105. "label": "淮滨县",
  5106. "value": "411527"
  5107. }, {
  5108. "label": "息县",
  5109. "value": "411528"
  5110. }],
  5111. [{
  5112. "label": "市辖区",
  5113. "value": "411601"
  5114. }, {
  5115. "label": "川汇区",
  5116. "value": "411602"
  5117. }, {
  5118. "label": "扶沟县",
  5119. "value": "411621"
  5120. }, {
  5121. "label": "西华县",
  5122. "value": "411622"
  5123. }, {
  5124. "label": "商水县",
  5125. "value": "411623"
  5126. }, {
  5127. "label": "沈丘县",
  5128. "value": "411624"
  5129. }, {
  5130. "label": "郸城县",
  5131. "value": "411625"
  5132. }, {
  5133. "label": "淮阳县",
  5134. "value": "411626"
  5135. }, {
  5136. "label": "太康县",
  5137. "value": "411627"
  5138. }, {
  5139. "label": "鹿邑县",
  5140. "value": "411628"
  5141. }, {
  5142. "label": "项城市",
  5143. "value": "411681"
  5144. }],
  5145. [{
  5146. "label": "市辖区",
  5147. "value": "411701"
  5148. }, {
  5149. "label": "驿城区",
  5150. "value": "411702"
  5151. }, {
  5152. "label": "西平县",
  5153. "value": "411721"
  5154. }, {
  5155. "label": "上蔡县",
  5156. "value": "411722"
  5157. }, {
  5158. "label": "平舆县",
  5159. "value": "411723"
  5160. }, {
  5161. "label": "正阳县",
  5162. "value": "411724"
  5163. }, {
  5164. "label": "确山县",
  5165. "value": "411725"
  5166. }, {
  5167. "label": "泌阳县",
  5168. "value": "411726"
  5169. }, {
  5170. "label": "汝南县",
  5171. "value": "411727"
  5172. }, {
  5173. "label": "遂平县",
  5174. "value": "411728"
  5175. }, {
  5176. "label": "新蔡县",
  5177. "value": "411729"
  5178. }],
  5179. [{
  5180. "label": "市辖区",
  5181. "value": "419001"
  5182. }]
  5183. ],
  5184. [
  5185. [{
  5186. "label": "市辖区",
  5187. "value": "420101"
  5188. }, {
  5189. "label": "江岸区",
  5190. "value": "420102"
  5191. }, {
  5192. "label": "江汉区",
  5193. "value": "420103"
  5194. }, {
  5195. "label": "硚口区",
  5196. "value": "420104"
  5197. }, {
  5198. "label": "汉阳区",
  5199. "value": "420105"
  5200. }, {
  5201. "label": "武昌区",
  5202. "value": "420106"
  5203. }, {
  5204. "label": "青山区",
  5205. "value": "420107"
  5206. }, {
  5207. "label": "洪山区",
  5208. "value": "420111"
  5209. }, {
  5210. "label": "东西湖区",
  5211. "value": "420112"
  5212. }, {
  5213. "label": "汉南区",
  5214. "value": "420113"
  5215. }, {
  5216. "label": "蔡甸区",
  5217. "value": "420114"
  5218. }, {
  5219. "label": "江夏区",
  5220. "value": "420115"
  5221. }, {
  5222. "label": "黄陂区",
  5223. "value": "420116"
  5224. }, {
  5225. "label": "新洲区",
  5226. "value": "420117"
  5227. }],
  5228. [{
  5229. "label": "市辖区",
  5230. "value": "420201"
  5231. }, {
  5232. "label": "黄石港区",
  5233. "value": "420202"
  5234. }, {
  5235. "label": "西塞山区",
  5236. "value": "420203"
  5237. }, {
  5238. "label": "下陆区",
  5239. "value": "420204"
  5240. }, {
  5241. "label": "铁山区",
  5242. "value": "420205"
  5243. }, {
  5244. "label": "阳新县",
  5245. "value": "420222"
  5246. }, {
  5247. "label": "大冶市",
  5248. "value": "420281"
  5249. }],
  5250. [{
  5251. "label": "市辖区",
  5252. "value": "420301"
  5253. }, {
  5254. "label": "茅箭区",
  5255. "value": "420302"
  5256. }, {
  5257. "label": "张湾区",
  5258. "value": "420303"
  5259. }, {
  5260. "label": "郧阳区",
  5261. "value": "420304"
  5262. }, {
  5263. "label": "郧西县",
  5264. "value": "420322"
  5265. }, {
  5266. "label": "竹山县",
  5267. "value": "420323"
  5268. }, {
  5269. "label": "竹溪县",
  5270. "value": "420324"
  5271. }, {
  5272. "label": "房县",
  5273. "value": "420325"
  5274. }, {
  5275. "label": "丹江口市",
  5276. "value": "420381"
  5277. }],
  5278. [{
  5279. "label": "市辖区",
  5280. "value": "420501"
  5281. }, {
  5282. "label": "西陵区",
  5283. "value": "420502"
  5284. }, {
  5285. "label": "伍家岗区",
  5286. "value": "420503"
  5287. }, {
  5288. "label": "点军区",
  5289. "value": "420504"
  5290. }, {
  5291. "label": "猇亭区",
  5292. "value": "420505"
  5293. }, {
  5294. "label": "夷陵区",
  5295. "value": "420506"
  5296. }, {
  5297. "label": "远安县",
  5298. "value": "420525"
  5299. }, {
  5300. "label": "兴山县",
  5301. "value": "420526"
  5302. }, {
  5303. "label": "秭归县",
  5304. "value": "420527"
  5305. }, {
  5306. "label": "长阳土家族自治县",
  5307. "value": "420528"
  5308. }, {
  5309. "label": "五峰土家族自治县",
  5310. "value": "420529"
  5311. }, {
  5312. "label": "宜都市",
  5313. "value": "420581"
  5314. }, {
  5315. "label": "当阳市",
  5316. "value": "420582"
  5317. }, {
  5318. "label": "枝江市",
  5319. "value": "420583"
  5320. }],
  5321. [{
  5322. "label": "市辖区",
  5323. "value": "420601"
  5324. }, {
  5325. "label": "襄城区",
  5326. "value": "420602"
  5327. }, {
  5328. "label": "樊城区",
  5329. "value": "420606"
  5330. }, {
  5331. "label": "襄州区",
  5332. "value": "420607"
  5333. }, {
  5334. "label": "南漳县",
  5335. "value": "420624"
  5336. }, {
  5337. "label": "谷城县",
  5338. "value": "420625"
  5339. }, {
  5340. "label": "保康县",
  5341. "value": "420626"
  5342. }, {
  5343. "label": "老河口市",
  5344. "value": "420682"
  5345. }, {
  5346. "label": "枣阳市",
  5347. "value": "420683"
  5348. }, {
  5349. "label": "宜城市",
  5350. "value": "420684"
  5351. }],
  5352. [{
  5353. "label": "市辖区",
  5354. "value": "420701"
  5355. }, {
  5356. "label": "梁子湖区",
  5357. "value": "420702"
  5358. }, {
  5359. "label": "华容区",
  5360. "value": "420703"
  5361. }, {
  5362. "label": "鄂城区",
  5363. "value": "420704"
  5364. }],
  5365. [{
  5366. "label": "市辖区",
  5367. "value": "420801"
  5368. }, {
  5369. "label": "东宝区",
  5370. "value": "420802"
  5371. }, {
  5372. "label": "掇刀区",
  5373. "value": "420804"
  5374. }, {
  5375. "label": "京山县",
  5376. "value": "420821"
  5377. }, {
  5378. "label": "沙洋县",
  5379. "value": "420822"
  5380. }, {
  5381. "label": "钟祥市",
  5382. "value": "420881"
  5383. }],
  5384. [{
  5385. "label": "市辖区",
  5386. "value": "420901"
  5387. }, {
  5388. "label": "孝南区",
  5389. "value": "420902"
  5390. }, {
  5391. "label": "孝昌县",
  5392. "value": "420921"
  5393. }, {
  5394. "label": "大悟县",
  5395. "value": "420922"
  5396. }, {
  5397. "label": "云梦县",
  5398. "value": "420923"
  5399. }, {
  5400. "label": "应城市",
  5401. "value": "420981"
  5402. }, {
  5403. "label": "安陆市",
  5404. "value": "420982"
  5405. }, {
  5406. "label": "汉川市",
  5407. "value": "420984"
  5408. }],
  5409. [{
  5410. "label": "市辖区",
  5411. "value": "421001"
  5412. }, {
  5413. "label": "沙市区",
  5414. "value": "421002"
  5415. }, {
  5416. "label": "荆州区",
  5417. "value": "421003"
  5418. }, {
  5419. "label": "公安县",
  5420. "value": "421022"
  5421. }, {
  5422. "label": "监利县",
  5423. "value": "421023"
  5424. }, {
  5425. "label": "江陵县",
  5426. "value": "421024"
  5427. }, {
  5428. "label": "石首市",
  5429. "value": "421081"
  5430. }, {
  5431. "label": "洪湖市",
  5432. "value": "421083"
  5433. }, {
  5434. "label": "松滋市",
  5435. "value": "421087"
  5436. }],
  5437. [{
  5438. "label": "市辖区",
  5439. "value": "421101"
  5440. }, {
  5441. "label": "黄州区",
  5442. "value": "421102"
  5443. }, {
  5444. "label": "团风县",
  5445. "value": "421121"
  5446. }, {
  5447. "label": "红安县",
  5448. "value": "421122"
  5449. }, {
  5450. "label": "罗田县",
  5451. "value": "421123"
  5452. }, {
  5453. "label": "英山县",
  5454. "value": "421124"
  5455. }, {
  5456. "label": "浠水县",
  5457. "value": "421125"
  5458. }, {
  5459. "label": "蕲春县",
  5460. "value": "421126"
  5461. }, {
  5462. "label": "黄梅县",
  5463. "value": "421127"
  5464. }, {
  5465. "label": "麻城市",
  5466. "value": "421181"
  5467. }, {
  5468. "label": "武穴市",
  5469. "value": "421182"
  5470. }],
  5471. [{
  5472. "label": "市辖区",
  5473. "value": "421201"
  5474. }, {
  5475. "label": "咸安区",
  5476. "value": "421202"
  5477. }, {
  5478. "label": "嘉鱼县",
  5479. "value": "421221"
  5480. }, {
  5481. "label": "通城县",
  5482. "value": "421222"
  5483. }, {
  5484. "label": "崇阳县",
  5485. "value": "421223"
  5486. }, {
  5487. "label": "通山县",
  5488. "value": "421224"
  5489. }, {
  5490. "label": "赤壁市",
  5491. "value": "421281"
  5492. }],
  5493. [{
  5494. "label": "市辖区",
  5495. "value": "421301"
  5496. }, {
  5497. "label": "曾都区",
  5498. "value": "421303"
  5499. }, {
  5500. "label": "随县",
  5501. "value": "421321"
  5502. }, {
  5503. "label": "广水市",
  5504. "value": "421381"
  5505. }],
  5506. [{
  5507. "label": "市辖区",
  5508. "value": "422801"
  5509. }, {
  5510. "label": "利川市",
  5511. "value": "422802"
  5512. }, {
  5513. "label": "建始县",
  5514. "value": "422822"
  5515. }, {
  5516. "label": "巴东县",
  5517. "value": "422823"
  5518. }, {
  5519. "label": "宣恩县",
  5520. "value": "422825"
  5521. }, {
  5522. "label": "咸丰县",
  5523. "value": "422826"
  5524. }, {
  5525. "label": "来凤县",
  5526. "value": "422827"
  5527. }, {
  5528. "label": "鹤峰县",
  5529. "value": "422828"
  5530. }],
  5531. [{
  5532. "label": "仙桃市",
  5533. "value": "429004"
  5534. }, {
  5535. "label": "潜江市",
  5536. "value": "429005"
  5537. }, {
  5538. "label": "天门市",
  5539. "value": "429006"
  5540. }, {
  5541. "label": "神农架林区",
  5542. "value": "429021"
  5543. }]
  5544. ],
  5545. [
  5546. [{
  5547. "label": "市辖区",
  5548. "value": "430101"
  5549. }, {
  5550. "label": "芙蓉区",
  5551. "value": "430102"
  5552. }, {
  5553. "label": "天心区",
  5554. "value": "430103"
  5555. }, {
  5556. "label": "岳麓区",
  5557. "value": "430104"
  5558. }, {
  5559. "label": "开福区",
  5560. "value": "430105"
  5561. }, {
  5562. "label": "雨花区",
  5563. "value": "430111"
  5564. }, {
  5565. "label": "望城区",
  5566. "value": "430112"
  5567. }, {
  5568. "label": "长沙县",
  5569. "value": "430121"
  5570. }, {
  5571. "label": "宁乡县",
  5572. "value": "430124"
  5573. }, {
  5574. "label": "浏阳市",
  5575. "value": "430181"
  5576. }],
  5577. [{
  5578. "label": "市辖区",
  5579. "value": "430201"
  5580. }, {
  5581. "label": "荷塘区",
  5582. "value": "430202"
  5583. }, {
  5584. "label": "芦淞区",
  5585. "value": "430203"
  5586. }, {
  5587. "label": "石峰区",
  5588. "value": "430204"
  5589. }, {
  5590. "label": "天元区",
  5591. "value": "430211"
  5592. }, {
  5593. "label": "株洲县",
  5594. "value": "430221"
  5595. }, {
  5596. "label": "攸县",
  5597. "value": "430223"
  5598. }, {
  5599. "label": "茶陵县",
  5600. "value": "430224"
  5601. }, {
  5602. "label": "炎陵县",
  5603. "value": "430225"
  5604. }, {
  5605. "label": "醴陵市",
  5606. "value": "430281"
  5607. }],
  5608. [{
  5609. "label": "市辖区",
  5610. "value": "430301"
  5611. }, {
  5612. "label": "雨湖区",
  5613. "value": "430302"
  5614. }, {
  5615. "label": "岳塘区",
  5616. "value": "430304"
  5617. }, {
  5618. "label": "湘潭县",
  5619. "value": "430321"
  5620. }, {
  5621. "label": "湘乡市",
  5622. "value": "430381"
  5623. }, {
  5624. "label": "韶山市",
  5625. "value": "430382"
  5626. }],
  5627. [{
  5628. "label": "市辖区",
  5629. "value": "430401"
  5630. }, {
  5631. "label": "珠晖区",
  5632. "value": "430405"
  5633. }, {
  5634. "label": "雁峰区",
  5635. "value": "430406"
  5636. }, {
  5637. "label": "石鼓区",
  5638. "value": "430407"
  5639. }, {
  5640. "label": "蒸湘区",
  5641. "value": "430408"
  5642. }, {
  5643. "label": "南岳区",
  5644. "value": "430412"
  5645. }, {
  5646. "label": "衡阳县",
  5647. "value": "430421"
  5648. }, {
  5649. "label": "衡南县",
  5650. "value": "430422"
  5651. }, {
  5652. "label": "衡山县",
  5653. "value": "430423"
  5654. }, {
  5655. "label": "衡东县",
  5656. "value": "430424"
  5657. }, {
  5658. "label": "祁东县",
  5659. "value": "430426"
  5660. }, {
  5661. "label": "耒阳市",
  5662. "value": "430481"
  5663. }, {
  5664. "label": "常宁市",
  5665. "value": "430482"
  5666. }],
  5667. [{
  5668. "label": "市辖区",
  5669. "value": "430501"
  5670. }, {
  5671. "label": "双清区",
  5672. "value": "430502"
  5673. }, {
  5674. "label": "大祥区",
  5675. "value": "430503"
  5676. }, {
  5677. "label": "北塔区",
  5678. "value": "430511"
  5679. }, {
  5680. "label": "邵东县",
  5681. "value": "430521"
  5682. }, {
  5683. "label": "新邵县",
  5684. "value": "430522"
  5685. }, {
  5686. "label": "邵阳县",
  5687. "value": "430523"
  5688. }, {
  5689. "label": "隆回县",
  5690. "value": "430524"
  5691. }, {
  5692. "label": "洞口县",
  5693. "value": "430525"
  5694. }, {
  5695. "label": "绥宁县",
  5696. "value": "430527"
  5697. }, {
  5698. "label": "新宁县",
  5699. "value": "430528"
  5700. }, {
  5701. "label": "城步苗族自治县",
  5702. "value": "430529"
  5703. }, {
  5704. "label": "武冈市",
  5705. "value": "430581"
  5706. }],
  5707. [{
  5708. "label": "市辖区",
  5709. "value": "430601"
  5710. }, {
  5711. "label": "岳阳楼区",
  5712. "value": "430602"
  5713. }, {
  5714. "label": "云溪区",
  5715. "value": "430603"
  5716. }, {
  5717. "label": "君山区",
  5718. "value": "430611"
  5719. }, {
  5720. "label": "岳阳县",
  5721. "value": "430621"
  5722. }, {
  5723. "label": "华容县",
  5724. "value": "430623"
  5725. }, {
  5726. "label": "湘阴县",
  5727. "value": "430624"
  5728. }, {
  5729. "label": "平江县",
  5730. "value": "430626"
  5731. }, {
  5732. "label": "汨罗市",
  5733. "value": "430681"
  5734. }, {
  5735. "label": "临湘市",
  5736. "value": "430682"
  5737. }],
  5738. [{
  5739. "label": "市辖区",
  5740. "value": "430701"
  5741. }, {
  5742. "label": "武陵区",
  5743. "value": "430702"
  5744. }, {
  5745. "label": "鼎城区",
  5746. "value": "430703"
  5747. }, {
  5748. "label": "安乡县",
  5749. "value": "430721"
  5750. }, {
  5751. "label": "汉寿县",
  5752. "value": "430722"
  5753. }, {
  5754. "label": "澧县",
  5755. "value": "430723"
  5756. }, {
  5757. "label": "临澧县",
  5758. "value": "430724"
  5759. }, {
  5760. "label": "桃源县",
  5761. "value": "430725"
  5762. }, {
  5763. "label": "石门县",
  5764. "value": "430726"
  5765. }, {
  5766. "label": "津市市",
  5767. "value": "430781"
  5768. }],
  5769. [{
  5770. "label": "市辖区",
  5771. "value": "430801"
  5772. }, {
  5773. "label": "永定区",
  5774. "value": "430802"
  5775. }, {
  5776. "label": "武陵源区",
  5777. "value": "430811"
  5778. }, {
  5779. "label": "慈利县",
  5780. "value": "430821"
  5781. }, {
  5782. "label": "桑植县",
  5783. "value": "430822"
  5784. }],
  5785. [{
  5786. "label": "市辖区",
  5787. "value": "430901"
  5788. }, {
  5789. "label": "资阳区",
  5790. "value": "430902"
  5791. }, {
  5792. "label": "赫山区",
  5793. "value": "430903"
  5794. }, {
  5795. "label": "南县",
  5796. "value": "430921"
  5797. }, {
  5798. "label": "桃江县",
  5799. "value": "430922"
  5800. }, {
  5801. "label": "安化县",
  5802. "value": "430923"
  5803. }, {
  5804. "label": "沅江市",
  5805. "value": "430981"
  5806. }],
  5807. [{
  5808. "label": "市辖区",
  5809. "value": "431001"
  5810. }, {
  5811. "label": "北湖区",
  5812. "value": "431002"
  5813. }, {
  5814. "label": "苏仙区",
  5815. "value": "431003"
  5816. }, {
  5817. "label": "桂阳县",
  5818. "value": "431021"
  5819. }, {
  5820. "label": "宜章县",
  5821. "value": "431022"
  5822. }, {
  5823. "label": "永兴县",
  5824. "value": "431023"
  5825. }, {
  5826. "label": "嘉禾县",
  5827. "value": "431024"
  5828. }, {
  5829. "label": "临武县",
  5830. "value": "431025"
  5831. }, {
  5832. "label": "汝城县",
  5833. "value": "431026"
  5834. }, {
  5835. "label": "桂东县",
  5836. "value": "431027"
  5837. }, {
  5838. "label": "安仁县",
  5839. "value": "431028"
  5840. }, {
  5841. "label": "资兴市",
  5842. "value": "431081"
  5843. }],
  5844. [{
  5845. "label": "市辖区",
  5846. "value": "431101"
  5847. }, {
  5848. "label": "零陵区",
  5849. "value": "431102"
  5850. }, {
  5851. "label": "冷水滩区",
  5852. "value": "431103"
  5853. }, {
  5854. "label": "祁阳县",
  5855. "value": "431121"
  5856. }, {
  5857. "label": "东安县",
  5858. "value": "431122"
  5859. }, {
  5860. "label": "双牌县",
  5861. "value": "431123"
  5862. }, {
  5863. "label": "道县",
  5864. "value": "431124"
  5865. }, {
  5866. "label": "江永县",
  5867. "value": "431125"
  5868. }, {
  5869. "label": "宁远县",
  5870. "value": "431126"
  5871. }, {
  5872. "label": "蓝山县",
  5873. "value": "431127"
  5874. }, {
  5875. "label": "新田县",
  5876. "value": "431128"
  5877. }, {
  5878. "label": "江华瑶族自治县",
  5879. "value": "431129"
  5880. }],
  5881. [{
  5882. "label": "市辖区",
  5883. "value": "431201"
  5884. }, {
  5885. "label": "鹤城区",
  5886. "value": "431202"
  5887. }, {
  5888. "label": "中方县",
  5889. "value": "431221"
  5890. }, {
  5891. "label": "沅陵县",
  5892. "value": "431222"
  5893. }, {
  5894. "label": "辰溪县",
  5895. "value": "431223"
  5896. }, {
  5897. "label": "溆浦县",
  5898. "value": "431224"
  5899. }, {
  5900. "label": "会同县",
  5901. "value": "431225"
  5902. }, {
  5903. "label": "麻阳苗族自治县",
  5904. "value": "431226"
  5905. }, {
  5906. "label": "新晃侗族自治县",
  5907. "value": "431227"
  5908. }, {
  5909. "label": "芷江侗族自治县",
  5910. "value": "431228"
  5911. }, {
  5912. "label": "靖州苗族侗族自治县",
  5913. "value": "431229"
  5914. }, {
  5915. "label": "通道侗族自治县",
  5916. "value": "431230"
  5917. }, {
  5918. "label": "洪江市",
  5919. "value": "431281"
  5920. }],
  5921. [{
  5922. "label": "市辖区",
  5923. "value": "431301"
  5924. }, {
  5925. "label": "娄星区",
  5926. "value": "431302"
  5927. }, {
  5928. "label": "双峰县",
  5929. "value": "431321"
  5930. }, {
  5931. "label": "新化县",
  5932. "value": "431322"
  5933. }, {
  5934. "label": "冷水江市",
  5935. "value": "431381"
  5936. }, {
  5937. "label": "涟源市",
  5938. "value": "431382"
  5939. }],
  5940. [{
  5941. "label": "市辖区",
  5942. "value": "433101"
  5943. }, {
  5944. "label": "泸溪县",
  5945. "value": "433122"
  5946. }, {
  5947. "label": "凤凰县",
  5948. "value": "433123"
  5949. }, {
  5950. "label": "花垣县",
  5951. "value": "433124"
  5952. }, {
  5953. "label": "保靖县",
  5954. "value": "433125"
  5955. }, {
  5956. "label": "古丈县",
  5957. "value": "433126"
  5958. }, {
  5959. "label": "永顺县",
  5960. "value": "433127"
  5961. }, {
  5962. "label": "龙山县",
  5963. "value": "433130"
  5964. }]
  5965. ], {
  5966. "0": [{
  5967. "label": "市辖区",
  5968. "value": "440101"
  5969. }, {
  5970. "label": "荔湾区",
  5971. "value": "440103"
  5972. }, {
  5973. "label": "越秀区",
  5974. "value": "440104"
  5975. }, {
  5976. "label": "海珠区",
  5977. "value": "440105"
  5978. }, {
  5979. "label": "天河区",
  5980. "value": "440106"
  5981. }, {
  5982. "label": "白云区",
  5983. "value": "440111"
  5984. }, {
  5985. "label": "黄埔区",
  5986. "value": "440112"
  5987. }, {
  5988. "label": "番禺区",
  5989. "value": "440113"
  5990. }, {
  5991. "label": "花都区",
  5992. "value": "440114"
  5993. }, {
  5994. "label": "南沙区",
  5995. "value": "440115"
  5996. }, {
  5997. "label": "从化区",
  5998. "value": "440117"
  5999. }, {
  6000. "label": "增城区",
  6001. "value": "440118"
  6002. }, {
  6003. "label": "萝岗区",
  6004. "value": "920003"
  6005. }],
  6006. "1": [{
  6007. "label": "市辖区",
  6008. "value": "440201"
  6009. }, {
  6010. "label": "武江区",
  6011. "value": "440203"
  6012. }, {
  6013. "label": "浈江区",
  6014. "value": "440204"
  6015. }, {
  6016. "label": "曲江区",
  6017. "value": "440205"
  6018. }, {
  6019. "label": "始兴县",
  6020. "value": "440222"
  6021. }, {
  6022. "label": "仁化县",
  6023. "value": "440224"
  6024. }, {
  6025. "label": "翁源县",
  6026. "value": "440229"
  6027. }, {
  6028. "label": "乳源瑶族自治县",
  6029. "value": "440232"
  6030. }, {
  6031. "label": "新丰县",
  6032. "value": "440233"
  6033. }, {
  6034. "label": "乐昌市",
  6035. "value": "440281"
  6036. }, {
  6037. "label": "南雄市",
  6038. "value": "440282"
  6039. }],
  6040. "2": [{
  6041. "label": "市辖区",
  6042. "value": "440301"
  6043. }, {
  6044. "label": "罗湖区",
  6045. "value": "440303"
  6046. }, {
  6047. "label": "福田区",
  6048. "value": "440304"
  6049. }, {
  6050. "label": "南山区",
  6051. "value": "440305"
  6052. }, {
  6053. "label": "宝安区",
  6054. "value": "440306"
  6055. }, {
  6056. "label": "龙岗区",
  6057. "value": "440307"
  6058. }, {
  6059. "label": "盐田区",
  6060. "value": "440308"
  6061. }],
  6062. "3": [{
  6063. "label": "市辖区",
  6064. "value": "440401"
  6065. }, {
  6066. "label": "香洲区",
  6067. "value": "440402"
  6068. }, {
  6069. "label": "斗门区",
  6070. "value": "440403"
  6071. }, {
  6072. "label": "金湾区",
  6073. "value": "440404"
  6074. }],
  6075. "4": [{
  6076. "label": "市辖区",
  6077. "value": "440501"
  6078. }, {
  6079. "label": "龙湖区",
  6080. "value": "440507"
  6081. }, {
  6082. "label": "金平区",
  6083. "value": "440511"
  6084. }, {
  6085. "label": "濠江区",
  6086. "value": "440512"
  6087. }, {
  6088. "label": "潮阳区",
  6089. "value": "440513"
  6090. }, {
  6091. "label": "潮南区",
  6092. "value": "440514"
  6093. }, {
  6094. "label": "澄海区",
  6095. "value": "440515"
  6096. }, {
  6097. "label": "南澳县",
  6098. "value": "440523"
  6099. }],
  6100. "5": [{
  6101. "label": "市辖区",
  6102. "value": "440601"
  6103. }, {
  6104. "label": "禅城区",
  6105. "value": "440604"
  6106. }, {
  6107. "label": "南海区",
  6108. "value": "440605"
  6109. }, {
  6110. "label": "顺德区",
  6111. "value": "440606"
  6112. }, {
  6113. "label": "三水区",
  6114. "value": "440607"
  6115. }, {
  6116. "label": "高明区",
  6117. "value": "440608"
  6118. }],
  6119. "6": [{
  6120. "label": "市辖区",
  6121. "value": "440701"
  6122. }, {
  6123. "label": "蓬江区",
  6124. "value": "440703"
  6125. }, {
  6126. "label": "江海区",
  6127. "value": "440704"
  6128. }, {
  6129. "label": "新会区",
  6130. "value": "440705"
  6131. }, {
  6132. "label": "台山市",
  6133. "value": "440781"
  6134. }, {
  6135. "label": "开平市",
  6136. "value": "440783"
  6137. }, {
  6138. "label": "鹤山市",
  6139. "value": "440784"
  6140. }, {
  6141. "label": "恩平市",
  6142. "value": "440785"
  6143. }],
  6144. "7": [{
  6145. "label": "市辖区",
  6146. "value": "440801"
  6147. }, {
  6148. "label": "赤坎区",
  6149. "value": "440802"
  6150. }, {
  6151. "label": "霞山区",
  6152. "value": "440803"
  6153. }, {
  6154. "label": "坡头区",
  6155. "value": "440804"
  6156. }, {
  6157. "label": "麻章区",
  6158. "value": "440811"
  6159. }, {
  6160. "label": "遂溪县",
  6161. "value": "440823"
  6162. }, {
  6163. "label": "徐闻县",
  6164. "value": "440825"
  6165. }, {
  6166. "label": "廉江市",
  6167. "value": "440881"
  6168. }, {
  6169. "label": "雷州市",
  6170. "value": "440882"
  6171. }, {
  6172. "label": "吴川市",
  6173. "value": "440883"
  6174. }],
  6175. "8": [{
  6176. "label": "市辖区",
  6177. "value": "440901"
  6178. }, {
  6179. "label": "茂南区",
  6180. "value": "440902"
  6181. }, {
  6182. "label": "电白区",
  6183. "value": "440904"
  6184. }, {
  6185. "label": "高州市",
  6186. "value": "440981"
  6187. }, {
  6188. "label": "化州市",
  6189. "value": "440982"
  6190. }, {
  6191. "label": "信宜市",
  6192. "value": "440983"
  6193. }],
  6194. "9": [{
  6195. "label": "市辖区",
  6196. "value": "441201"
  6197. }, {
  6198. "label": "端州区",
  6199. "value": "441202"
  6200. }, {
  6201. "label": "鼎湖区",
  6202. "value": "441203"
  6203. }, {
  6204. "label": "高要区",
  6205. "value": "441204"
  6206. }, {
  6207. "label": "广宁县",
  6208. "value": "441223"
  6209. }, {
  6210. "label": "怀集县",
  6211. "value": "441224"
  6212. }, {
  6213. "label": "封开县",
  6214. "value": "441225"
  6215. }, {
  6216. "label": "德庆县",
  6217. "value": "441226"
  6218. }, {
  6219. "label": "四会市",
  6220. "value": "441284"
  6221. }],
  6222. "10": [{
  6223. "label": "市辖区",
  6224. "value": "441301"
  6225. }, {
  6226. "label": "惠城区",
  6227. "value": "441302"
  6228. }, {
  6229. "label": "惠阳区",
  6230. "value": "441303"
  6231. }, {
  6232. "label": "博罗县",
  6233. "value": "441322"
  6234. }, {
  6235. "label": "惠东县",
  6236. "value": "441323"
  6237. }, {
  6238. "label": "龙门县",
  6239. "value": "441324"
  6240. }],
  6241. "11": [{
  6242. "label": "市辖区",
  6243. "value": "441401"
  6244. }, {
  6245. "label": "梅江区",
  6246. "value": "441402"
  6247. }, {
  6248. "label": "梅县区",
  6249. "value": "441403"
  6250. }, {
  6251. "label": "大埔县",
  6252. "value": "441422"
  6253. }, {
  6254. "label": "丰顺县",
  6255. "value": "441423"
  6256. }, {
  6257. "label": "五华县",
  6258. "value": "441424"
  6259. }, {
  6260. "label": "平远县",
  6261. "value": "441426"
  6262. }, {
  6263. "label": "蕉岭县",
  6264. "value": "441427"
  6265. }, {
  6266. "label": "兴宁市",
  6267. "value": "441481"
  6268. }],
  6269. "12": [{
  6270. "label": "市辖区",
  6271. "value": "441501"
  6272. }, {
  6273. "label": "城区",
  6274. "value": "441502"
  6275. }, {
  6276. "label": "海丰县",
  6277. "value": "441521"
  6278. }, {
  6279. "label": "陆河县",
  6280. "value": "441523"
  6281. }, {
  6282. "label": "陆丰市",
  6283. "value": "441581"
  6284. }],
  6285. "13": [{
  6286. "label": "市辖区",
  6287. "value": "441601"
  6288. }, {
  6289. "label": "源城区",
  6290. "value": "441602"
  6291. }, {
  6292. "label": "紫金县",
  6293. "value": "441621"
  6294. }, {
  6295. "label": "龙川县",
  6296. "value": "441622"
  6297. }, {
  6298. "label": "连平县",
  6299. "value": "441623"
  6300. }, {
  6301. "label": "和平县",
  6302. "value": "441624"
  6303. }, {
  6304. "label": "东源县",
  6305. "value": "441625"
  6306. }],
  6307. "14": [{
  6308. "label": "市辖区",
  6309. "value": "441701"
  6310. }, {
  6311. "label": "江城区",
  6312. "value": "441702"
  6313. }, {
  6314. "label": "阳东区",
  6315. "value": "441704"
  6316. }, {
  6317. "label": "阳西县",
  6318. "value": "441721"
  6319. }, {
  6320. "label": "阳春市",
  6321. "value": "441781"
  6322. }],
  6323. "15": [{
  6324. "label": "市辖区",
  6325. "value": "441801"
  6326. }, {
  6327. "label": "清城区",
  6328. "value": "441802"
  6329. }, {
  6330. "label": "清新区",
  6331. "value": "441803"
  6332. }, {
  6333. "label": "佛冈县",
  6334. "value": "441821"
  6335. }, {
  6336. "label": "阳山县",
  6337. "value": "441823"
  6338. }, {
  6339. "label": "连山壮族瑶族自治县",
  6340. "value": "441825"
  6341. }, {
  6342. "label": "连南瑶族自治县",
  6343. "value": "441826"
  6344. }, {
  6345. "label": "英德市",
  6346. "value": "441881"
  6347. }, {
  6348. "label": "连州市",
  6349. "value": "441882"
  6350. }],
  6351. "18": [{
  6352. "label": "市辖区",
  6353. "value": "445101"
  6354. }, {
  6355. "label": "湘桥区",
  6356. "value": "445102"
  6357. }, {
  6358. "label": "潮安区",
  6359. "value": "445103"
  6360. }, {
  6361. "label": "饶平县",
  6362. "value": "445122"
  6363. }],
  6364. "19": [{
  6365. "label": "市辖区",
  6366. "value": "445201"
  6367. }, {
  6368. "label": "榕城区",
  6369. "value": "445202"
  6370. }, {
  6371. "label": "揭东区",
  6372. "value": "445203"
  6373. }, {
  6374. "label": "揭西县",
  6375. "value": "445222"
  6376. }, {
  6377. "label": "惠来县",
  6378. "value": "445224"
  6379. }, {
  6380. "label": "普宁市",
  6381. "value": "445281"
  6382. }],
  6383. "20": [{
  6384. "label": "市辖区",
  6385. "value": "445301"
  6386. }, {
  6387. "label": "云城区",
  6388. "value": "445302"
  6389. }, {
  6390. "label": "云安区",
  6391. "value": "445303"
  6392. }, {
  6393. "label": "新兴县",
  6394. "value": "445321"
  6395. }, {
  6396. "label": "郁南县",
  6397. "value": "445322"
  6398. }, {
  6399. "label": "罗定市",
  6400. "value": "445381"
  6401. }]
  6402. },
  6403. [
  6404. [{
  6405. "label": "市辖区",
  6406. "value": "450101"
  6407. }, {
  6408. "label": "兴宁区",
  6409. "value": "450102"
  6410. }, {
  6411. "label": "青秀区",
  6412. "value": "450103"
  6413. }, {
  6414. "label": "江南区",
  6415. "value": "450105"
  6416. }, {
  6417. "label": "西乡塘区",
  6418. "value": "450107"
  6419. }, {
  6420. "label": "良庆区",
  6421. "value": "450108"
  6422. }, {
  6423. "label": "邕宁区",
  6424. "value": "450109"
  6425. }, {
  6426. "label": "武鸣区",
  6427. "value": "450110"
  6428. }, {
  6429. "label": "隆安县",
  6430. "value": "450123"
  6431. }, {
  6432. "label": "马山县",
  6433. "value": "450124"
  6434. }, {
  6435. "label": "上林县",
  6436. "value": "450125"
  6437. }, {
  6438. "label": "宾阳县",
  6439. "value": "450126"
  6440. }, {
  6441. "label": "横县",
  6442. "value": "450127"
  6443. }],
  6444. [{
  6445. "label": "市辖区",
  6446. "value": "450201"
  6447. }, {
  6448. "label": "城中区",
  6449. "value": "450202"
  6450. }, {
  6451. "label": "鱼峰区",
  6452. "value": "450203"
  6453. }, {
  6454. "label": "柳南区",
  6455. "value": "450204"
  6456. }, {
  6457. "label": "柳北区",
  6458. "value": "450205"
  6459. }, {
  6460. "label": "柳江区",
  6461. "value": "450206"
  6462. }, {
  6463. "label": "柳城县",
  6464. "value": "450222"
  6465. }, {
  6466. "label": "鹿寨县",
  6467. "value": "450223"
  6468. }, {
  6469. "label": "融安县",
  6470. "value": "450224"
  6471. }, {
  6472. "label": "融水苗族自治县",
  6473. "value": "450225"
  6474. }, {
  6475. "label": "三江侗族自治县",
  6476. "value": "450226"
  6477. }],
  6478. [{
  6479. "label": "市辖区",
  6480. "value": "450301"
  6481. }, {
  6482. "label": "秀峰区",
  6483. "value": "450302"
  6484. }, {
  6485. "label": "叠彩区",
  6486. "value": "450303"
  6487. }, {
  6488. "label": "象山区",
  6489. "value": "450304"
  6490. }, {
  6491. "label": "七星区",
  6492. "value": "450305"
  6493. }, {
  6494. "label": "雁山区",
  6495. "value": "450311"
  6496. }, {
  6497. "label": "临桂区",
  6498. "value": "450312"
  6499. }, {
  6500. "label": "阳朔县",
  6501. "value": "450321"
  6502. }, {
  6503. "label": "灵川县",
  6504. "value": "450323"
  6505. }, {
  6506. "label": "全州县",
  6507. "value": "450324"
  6508. }, {
  6509. "label": "兴安县",
  6510. "value": "450325"
  6511. }, {
  6512. "label": "永福县",
  6513. "value": "450326"
  6514. }, {
  6515. "label": "灌阳县",
  6516. "value": "450327"
  6517. }, {
  6518. "label": "龙胜各族自治县",
  6519. "value": "450328"
  6520. }, {
  6521. "label": "资源县",
  6522. "value": "450329"
  6523. }, {
  6524. "label": "平乐县",
  6525. "value": "450330"
  6526. }, {
  6527. "label": "荔浦县",
  6528. "value": "450331"
  6529. }, {
  6530. "label": "恭城瑶族自治县",
  6531. "value": "450332"
  6532. }],
  6533. [{
  6534. "label": "市辖区",
  6535. "value": "450401"
  6536. }, {
  6537. "label": "万秀区",
  6538. "value": "450403"
  6539. }, {
  6540. "label": "长洲区",
  6541. "value": "450405"
  6542. }, {
  6543. "label": "龙圩区",
  6544. "value": "450406"
  6545. }, {
  6546. "label": "苍梧县",
  6547. "value": "450421"
  6548. }, {
  6549. "label": "藤县",
  6550. "value": "450422"
  6551. }, {
  6552. "label": "蒙山县",
  6553. "value": "450423"
  6554. }, {
  6555. "label": "岑溪市",
  6556. "value": "450481"
  6557. }],
  6558. [{
  6559. "label": "市辖区",
  6560. "value": "450501"
  6561. }, {
  6562. "label": "海城区",
  6563. "value": "450502"
  6564. }, {
  6565. "label": "银海区",
  6566. "value": "450503"
  6567. }, {
  6568. "label": "铁山港区",
  6569. "value": "450512"
  6570. }, {
  6571. "label": "合浦县",
  6572. "value": "450521"
  6573. }],
  6574. [{
  6575. "label": "市辖区",
  6576. "value": "450601"
  6577. }, {
  6578. "label": "港口区",
  6579. "value": "450602"
  6580. }, {
  6581. "label": "防城区",
  6582. "value": "450603"
  6583. }, {
  6584. "label": "上思县",
  6585. "value": "450621"
  6586. }, {
  6587. "label": "东兴市",
  6588. "value": "450681"
  6589. }],
  6590. [{
  6591. "label": "市辖区",
  6592. "value": "450701"
  6593. }, {
  6594. "label": "钦南区",
  6595. "value": "450702"
  6596. }, {
  6597. "label": "钦北区",
  6598. "value": "450703"
  6599. }, {
  6600. "label": "灵山县",
  6601. "value": "450721"
  6602. }, {
  6603. "label": "浦北县",
  6604. "value": "450722"
  6605. }],
  6606. [{
  6607. "label": "市辖区",
  6608. "value": "450801"
  6609. }, {
  6610. "label": "港北区",
  6611. "value": "450802"
  6612. }, {
  6613. "label": "港南区",
  6614. "value": "450803"
  6615. }, {
  6616. "label": "覃塘区",
  6617. "value": "450804"
  6618. }, {
  6619. "label": "平南县",
  6620. "value": "450821"
  6621. }, {
  6622. "label": "桂平市",
  6623. "value": "450881"
  6624. }],
  6625. [{
  6626. "label": "市辖区",
  6627. "value": "450901"
  6628. }, {
  6629. "label": "玉州区",
  6630. "value": "450902"
  6631. }, {
  6632. "label": "福绵区",
  6633. "value": "450903"
  6634. }, {
  6635. "label": "容县",
  6636. "value": "450921"
  6637. }, {
  6638. "label": "陆川县",
  6639. "value": "450922"
  6640. }, {
  6641. "label": "博白县",
  6642. "value": "450923"
  6643. }, {
  6644. "label": "兴业县",
  6645. "value": "450924"
  6646. }, {
  6647. "label": "北流市",
  6648. "value": "450981"
  6649. }],
  6650. [{
  6651. "label": "市辖区",
  6652. "value": "451001"
  6653. }, {
  6654. "label": "右江区",
  6655. "value": "451002"
  6656. }, {
  6657. "label": "田阳县",
  6658. "value": "451021"
  6659. }, {
  6660. "label": "田东县",
  6661. "value": "451022"
  6662. }, {
  6663. "label": "平果县",
  6664. "value": "451023"
  6665. }, {
  6666. "label": "德保县",
  6667. "value": "451024"
  6668. }, {
  6669. "label": "那坡县",
  6670. "value": "451026"
  6671. }, {
  6672. "label": "凌云县",
  6673. "value": "451027"
  6674. }, {
  6675. "label": "乐业县",
  6676. "value": "451028"
  6677. }, {
  6678. "label": "田林县",
  6679. "value": "451029"
  6680. }, {
  6681. "label": "西林县",
  6682. "value": "451030"
  6683. }, {
  6684. "label": "隆林各族自治县",
  6685. "value": "451031"
  6686. }, {
  6687. "label": "靖西市",
  6688. "value": "451081"
  6689. }],
  6690. [{
  6691. "label": "市辖区",
  6692. "value": "451101"
  6693. }, {
  6694. "label": "八步区",
  6695. "value": "451102"
  6696. }, {
  6697. "label": "平桂区",
  6698. "value": "451103"
  6699. }, {
  6700. "label": "昭平县",
  6701. "value": "451121"
  6702. }, {
  6703. "label": "钟山县",
  6704. "value": "451122"
  6705. }, {
  6706. "label": "富川瑶族自治县",
  6707. "value": "451123"
  6708. }],
  6709. [{
  6710. "label": "市辖区",
  6711. "value": "451201"
  6712. }, {
  6713. "label": "金城江区",
  6714. "value": "451202"
  6715. }, {
  6716. "label": "南丹县",
  6717. "value": "451221"
  6718. }, {
  6719. "label": "天峨县",
  6720. "value": "451222"
  6721. }, {
  6722. "label": "凤山县",
  6723. "value": "451223"
  6724. }, {
  6725. "label": "东兰县",
  6726. "value": "451224"
  6727. }, {
  6728. "label": "罗城仫佬族自治县",
  6729. "value": "451225"
  6730. }, {
  6731. "label": "环江毛南族自治县",
  6732. "value": "451226"
  6733. }, {
  6734. "label": "巴马瑶族自治县",
  6735. "value": "451227"
  6736. }, {
  6737. "label": "都安瑶族自治县",
  6738. "value": "451228"
  6739. }, {
  6740. "label": "大化瑶族自治县",
  6741. "value": "451229"
  6742. }, {
  6743. "label": "宜州市",
  6744. "value": "451281"
  6745. }],
  6746. [{
  6747. "label": "市辖区",
  6748. "value": "451301"
  6749. }, {
  6750. "label": "兴宾区",
  6751. "value": "451302"
  6752. }, {
  6753. "label": "忻城县",
  6754. "value": "451321"
  6755. }, {
  6756. "label": "象州县",
  6757. "value": "451322"
  6758. }, {
  6759. "label": "武宣县",
  6760. "value": "451323"
  6761. }, {
  6762. "label": "金秀瑶族自治县",
  6763. "value": "451324"
  6764. }, {
  6765. "label": "合山市",
  6766. "value": "451381"
  6767. }],
  6768. [{
  6769. "label": "市辖区",
  6770. "value": "451401"
  6771. }, {
  6772. "label": "江州区",
  6773. "value": "451402"
  6774. }, {
  6775. "label": "扶绥县",
  6776. "value": "451421"
  6777. }, {
  6778. "label": "宁明县",
  6779. "value": "451422"
  6780. }, {
  6781. "label": "龙州县",
  6782. "value": "451423"
  6783. }, {
  6784. "label": "大新县",
  6785. "value": "451424"
  6786. }, {
  6787. "label": "天等县",
  6788. "value": "451425"
  6789. }, {
  6790. "label": "凭祥市",
  6791. "value": "451481"
  6792. }]
  6793. ], {
  6794. "0": [{
  6795. "label": "市辖区",
  6796. "value": "460101"
  6797. }, {
  6798. "label": "秀英区",
  6799. "value": "460105"
  6800. }, {
  6801. "label": "龙华区",
  6802. "value": "460106"
  6803. }, {
  6804. "label": "琼山区",
  6805. "value": "460107"
  6806. }, {
  6807. "label": "美兰区",
  6808. "value": "460108"
  6809. }],
  6810. "1": [{
  6811. "label": "市辖区",
  6812. "value": "460201"
  6813. }, {
  6814. "label": "海棠区",
  6815. "value": "460202"
  6816. }, {
  6817. "label": "吉阳区",
  6818. "value": "460203"
  6819. }, {
  6820. "label": "天涯区",
  6821. "value": "460204"
  6822. }, {
  6823. "label": "崖州区",
  6824. "value": "460205"
  6825. }],
  6826. "4": [{
  6827. "label": "市辖区",
  6828. "value": "469001"
  6829. }, {
  6830. "label": "琼海市",
  6831. "value": "469002"
  6832. }, {
  6833. "label": "文昌市",
  6834. "value": "469005"
  6835. }, {
  6836. "label": "万宁市",
  6837. "value": "469006"
  6838. }, {
  6839. "label": "东方市",
  6840. "value": "469007"
  6841. }, {
  6842. "label": "定安县",
  6843. "value": "469021"
  6844. }, {
  6845. "label": "屯昌县",
  6846. "value": "469022"
  6847. }, {
  6848. "label": "澄迈县",
  6849. "value": "469023"
  6850. }, {
  6851. "label": "临高县",
  6852. "value": "469024"
  6853. }, {
  6854. "label": "白沙黎族自治县",
  6855. "value": "469025"
  6856. }, {
  6857. "label": "昌江黎族自治县",
  6858. "value": "469026"
  6859. }, {
  6860. "label": "乐东黎族自治县",
  6861. "value": "469027"
  6862. }, {
  6863. "label": "陵水黎族自治县",
  6864. "value": "469028"
  6865. }, {
  6866. "label": "保亭黎族苗族自治县",
  6867. "value": "469029"
  6868. }, {
  6869. "label": "琼中黎族苗族自治县",
  6870. "value": "469030"
  6871. }]
  6872. },
  6873. [
  6874. [{
  6875. "label": "万州区",
  6876. "value": "500101"
  6877. }, {
  6878. "label": "涪陵区",
  6879. "value": "500102"
  6880. }, {
  6881. "label": "渝中区",
  6882. "value": "500103"
  6883. }, {
  6884. "label": "大渡口区",
  6885. "value": "500104"
  6886. }, {
  6887. "label": "江北区",
  6888. "value": "500105"
  6889. }, {
  6890. "label": "沙坪坝区",
  6891. "value": "500106"
  6892. }, {
  6893. "label": "九龙坡区",
  6894. "value": "500107"
  6895. }, {
  6896. "label": "南岸区",
  6897. "value": "500108"
  6898. }, {
  6899. "label": "北碚区",
  6900. "value": "500109"
  6901. }, {
  6902. "label": "綦江区",
  6903. "value": "500110"
  6904. }, {
  6905. "label": "大足区",
  6906. "value": "500111"
  6907. }, {
  6908. "label": "渝北区",
  6909. "value": "500112"
  6910. }, {
  6911. "label": "巴南区",
  6912. "value": "500113"
  6913. }, {
  6914. "label": "黔江区",
  6915. "value": "500114"
  6916. }, {
  6917. "label": "长寿区",
  6918. "value": "500115"
  6919. }, {
  6920. "label": "江津区",
  6921. "value": "500116"
  6922. }, {
  6923. "label": "合川区",
  6924. "value": "500117"
  6925. }, {
  6926. "label": "永川区",
  6927. "value": "500118"
  6928. }, {
  6929. "label": "南川区",
  6930. "value": "500119"
  6931. }, {
  6932. "label": "璧山区",
  6933. "value": "500120"
  6934. }, {
  6935. "label": "铜梁区",
  6936. "value": "500151"
  6937. }, {
  6938. "label": "潼南区",
  6939. "value": "500152"
  6940. }, {
  6941. "label": "荣昌区",
  6942. "value": "500153"
  6943. }, {
  6944. "label": "开州区",
  6945. "value": "500154"
  6946. }],
  6947. [{
  6948. "label": "梁平县",
  6949. "value": "500228"
  6950. }, {
  6951. "label": "城口县",
  6952. "value": "500229"
  6953. }, {
  6954. "label": "丰都县",
  6955. "value": "500230"
  6956. }, {
  6957. "label": "垫江县",
  6958. "value": "500231"
  6959. }, {
  6960. "label": "武隆县",
  6961. "value": "500232"
  6962. }, {
  6963. "label": "忠县",
  6964. "value": "500233"
  6965. }, {
  6966. "label": "云阳县",
  6967. "value": "500235"
  6968. }, {
  6969. "label": "奉节县",
  6970. "value": "500236"
  6971. }, {
  6972. "label": "巫山县",
  6973. "value": "500237"
  6974. }, {
  6975. "label": "巫溪县",
  6976. "value": "500238"
  6977. }, {
  6978. "label": "石柱土家族自治县",
  6979. "value": "500240"
  6980. }, {
  6981. "label": "秀山土家族苗族自治县",
  6982. "value": "500241"
  6983. }, {
  6984. "label": "酉阳土家族苗族自治县",
  6985. "value": "500242"
  6986. }, {
  6987. "label": "彭水苗族土家族自治县",
  6988. "value": "500243"
  6989. }, {
  6990. "label": "静海县",
  6991. "value": "920000"
  6992. }]
  6993. ],
  6994. [
  6995. [{
  6996. "label": "市辖区",
  6997. "value": "510101"
  6998. }, {
  6999. "label": "锦江区",
  7000. "value": "510104"
  7001. }, {
  7002. "label": "青羊区",
  7003. "value": "510105"
  7004. }, {
  7005. "label": "金牛区",
  7006. "value": "510106"
  7007. }, {
  7008. "label": "武侯区",
  7009. "value": "510107"
  7010. }, {
  7011. "label": "成华区",
  7012. "value": "510108"
  7013. }, {
  7014. "label": "龙泉驿区",
  7015. "value": "510112"
  7016. }, {
  7017. "label": "青白江区",
  7018. "value": "510113"
  7019. }, {
  7020. "label": "新都区",
  7021. "value": "510114"
  7022. }, {
  7023. "label": "温江区",
  7024. "value": "510115"
  7025. }, {
  7026. "label": "双流区",
  7027. "value": "510116"
  7028. }, {
  7029. "label": "金堂县",
  7030. "value": "510121"
  7031. }, {
  7032. "label": "郫县",
  7033. "value": "510124"
  7034. }, {
  7035. "label": "大邑县",
  7036. "value": "510129"
  7037. }, {
  7038. "label": "蒲江县",
  7039. "value": "510131"
  7040. }, {
  7041. "label": "新津县",
  7042. "value": "510132"
  7043. }, {
  7044. "label": "都江堰市",
  7045. "value": "510181"
  7046. }, {
  7047. "label": "彭州市",
  7048. "value": "510182"
  7049. }, {
  7050. "label": "邛崃市",
  7051. "value": "510183"
  7052. }, {
  7053. "label": "崇州市",
  7054. "value": "510184"
  7055. }, {
  7056. "label": "简阳市",
  7057. "value": "510185"
  7058. }],
  7059. [{
  7060. "label": "市辖区",
  7061. "value": "510301"
  7062. }, {
  7063. "label": "自流井区",
  7064. "value": "510302"
  7065. }, {
  7066. "label": "贡井区",
  7067. "value": "510303"
  7068. }, {
  7069. "label": "大安区",
  7070. "value": "510304"
  7071. }, {
  7072. "label": "沿滩区",
  7073. "value": "510311"
  7074. }, {
  7075. "label": "荣县",
  7076. "value": "510321"
  7077. }, {
  7078. "label": "富顺县",
  7079. "value": "510322"
  7080. }],
  7081. [{
  7082. "label": "市辖区",
  7083. "value": "510401"
  7084. }, {
  7085. "label": "东区",
  7086. "value": "510402"
  7087. }, {
  7088. "label": "西区",
  7089. "value": "510403"
  7090. }, {
  7091. "label": "仁和区",
  7092. "value": "510411"
  7093. }, {
  7094. "label": "米易县",
  7095. "value": "510421"
  7096. }, {
  7097. "label": "盐边县",
  7098. "value": "510422"
  7099. }],
  7100. [{
  7101. "label": "市辖区",
  7102. "value": "510501"
  7103. }, {
  7104. "label": "江阳区",
  7105. "value": "510502"
  7106. }, {
  7107. "label": "纳溪区",
  7108. "value": "510503"
  7109. }, {
  7110. "label": "龙马潭区",
  7111. "value": "510504"
  7112. }, {
  7113. "label": "泸县",
  7114. "value": "510521"
  7115. }, {
  7116. "label": "合江县",
  7117. "value": "510522"
  7118. }, {
  7119. "label": "叙永县",
  7120. "value": "510524"
  7121. }, {
  7122. "label": "古蔺县",
  7123. "value": "510525"
  7124. }],
  7125. [{
  7126. "label": "市辖区",
  7127. "value": "510601"
  7128. }, {
  7129. "label": "旌阳区",
  7130. "value": "510603"
  7131. }, {
  7132. "label": "中江县",
  7133. "value": "510623"
  7134. }, {
  7135. "label": "罗江县",
  7136. "value": "510626"
  7137. }, {
  7138. "label": "广汉市",
  7139. "value": "510681"
  7140. }, {
  7141. "label": "什邡市",
  7142. "value": "510682"
  7143. }, {
  7144. "label": "绵竹市",
  7145. "value": "510683"
  7146. }],
  7147. [{
  7148. "label": "市辖区",
  7149. "value": "510701"
  7150. }, {
  7151. "label": "涪城区",
  7152. "value": "510703"
  7153. }, {
  7154. "label": "游仙区",
  7155. "value": "510704"
  7156. }, {
  7157. "label": "安州区",
  7158. "value": "510705"
  7159. }, {
  7160. "label": "三台县",
  7161. "value": "510722"
  7162. }, {
  7163. "label": "盐亭县",
  7164. "value": "510723"
  7165. }, {
  7166. "label": "梓潼县",
  7167. "value": "510725"
  7168. }, {
  7169. "label": "北川羌族自治县",
  7170. "value": "510726"
  7171. }, {
  7172. "label": "平武县",
  7173. "value": "510727"
  7174. }, {
  7175. "label": "江油市",
  7176. "value": "510781"
  7177. }],
  7178. [{
  7179. "label": "市辖区",
  7180. "value": "510801"
  7181. }, {
  7182. "label": "利州区",
  7183. "value": "510802"
  7184. }, {
  7185. "label": "昭化区",
  7186. "value": "510811"
  7187. }, {
  7188. "label": "朝天区",
  7189. "value": "510812"
  7190. }, {
  7191. "label": "旺苍县",
  7192. "value": "510821"
  7193. }, {
  7194. "label": "青川县",
  7195. "value": "510822"
  7196. }, {
  7197. "label": "剑阁县",
  7198. "value": "510823"
  7199. }, {
  7200. "label": "苍溪县",
  7201. "value": "510824"
  7202. }],
  7203. [{
  7204. "label": "市辖区",
  7205. "value": "510901"
  7206. }, {
  7207. "label": "船山区",
  7208. "value": "510903"
  7209. }, {
  7210. "label": "安居区",
  7211. "value": "510904"
  7212. }, {
  7213. "label": "蓬溪县",
  7214. "value": "510921"
  7215. }, {
  7216. "label": "射洪县",
  7217. "value": "510922"
  7218. }, {
  7219. "label": "大英县",
  7220. "value": "510923"
  7221. }],
  7222. [{
  7223. "label": "市辖区",
  7224. "value": "511001"
  7225. }, {
  7226. "label": "市中区",
  7227. "value": "511002"
  7228. }, {
  7229. "label": "东兴区",
  7230. "value": "511011"
  7231. }, {
  7232. "label": "威远县",
  7233. "value": "511024"
  7234. }, {
  7235. "label": "资中县",
  7236. "value": "511025"
  7237. }, {
  7238. "label": "隆昌县",
  7239. "value": "511028"
  7240. }],
  7241. [{
  7242. "label": "市辖区",
  7243. "value": "511101"
  7244. }, {
  7245. "label": "市中区",
  7246. "value": "511102"
  7247. }, {
  7248. "label": "沙湾区",
  7249. "value": "511111"
  7250. }, {
  7251. "label": "五通桥区",
  7252. "value": "511112"
  7253. }, {
  7254. "label": "金口河区",
  7255. "value": "511113"
  7256. }, {
  7257. "label": "犍为县",
  7258. "value": "511123"
  7259. }, {
  7260. "label": "井研县",
  7261. "value": "511124"
  7262. }, {
  7263. "label": "夹江县",
  7264. "value": "511126"
  7265. }, {
  7266. "label": "沐川县",
  7267. "value": "511129"
  7268. }, {
  7269. "label": "峨边彝族自治县",
  7270. "value": "511132"
  7271. }, {
  7272. "label": "马边彝族自治县",
  7273. "value": "511133"
  7274. }, {
  7275. "label": "峨眉山市",
  7276. "value": "511181"
  7277. }],
  7278. [{
  7279. "label": "市辖区",
  7280. "value": "511301"
  7281. }, {
  7282. "label": "顺庆区",
  7283. "value": "511302"
  7284. }, {
  7285. "label": "高坪区",
  7286. "value": "511303"
  7287. }, {
  7288. "label": "嘉陵区",
  7289. "value": "511304"
  7290. }, {
  7291. "label": "南部县",
  7292. "value": "511321"
  7293. }, {
  7294. "label": "营山县",
  7295. "value": "511322"
  7296. }, {
  7297. "label": "蓬安县",
  7298. "value": "511323"
  7299. }, {
  7300. "label": "仪陇县",
  7301. "value": "511324"
  7302. }, {
  7303. "label": "西充县",
  7304. "value": "511325"
  7305. }, {
  7306. "label": "阆中市",
  7307. "value": "511381"
  7308. }],
  7309. [{
  7310. "label": "市辖区",
  7311. "value": "511401"
  7312. }, {
  7313. "label": "东坡区",
  7314. "value": "511402"
  7315. }, {
  7316. "label": "彭山区",
  7317. "value": "511403"
  7318. }, {
  7319. "label": "仁寿县",
  7320. "value": "511421"
  7321. }, {
  7322. "label": "洪雅县",
  7323. "value": "511423"
  7324. }, {
  7325. "label": "丹棱县",
  7326. "value": "511424"
  7327. }, {
  7328. "label": "青神县",
  7329. "value": "511425"
  7330. }],
  7331. [{
  7332. "label": "市辖区",
  7333. "value": "511501"
  7334. }, {
  7335. "label": "翠屏区",
  7336. "value": "511502"
  7337. }, {
  7338. "label": "南溪区",
  7339. "value": "511503"
  7340. }, {
  7341. "label": "宜宾县",
  7342. "value": "511521"
  7343. }, {
  7344. "label": "江安县",
  7345. "value": "511523"
  7346. }, {
  7347. "label": "长宁县",
  7348. "value": "511524"
  7349. }, {
  7350. "label": "高县",
  7351. "value": "511525"
  7352. }, {
  7353. "label": "珙县",
  7354. "value": "511526"
  7355. }, {
  7356. "label": "筠连县",
  7357. "value": "511527"
  7358. }, {
  7359. "label": "兴文县",
  7360. "value": "511528"
  7361. }, {
  7362. "label": "屏山县",
  7363. "value": "511529"
  7364. }],
  7365. [{
  7366. "label": "市辖区",
  7367. "value": "511601"
  7368. }, {
  7369. "label": "广安区",
  7370. "value": "511602"
  7371. }, {
  7372. "label": "前锋区",
  7373. "value": "511603"
  7374. }, {
  7375. "label": "岳池县",
  7376. "value": "511621"
  7377. }, {
  7378. "label": "武胜县",
  7379. "value": "511622"
  7380. }, {
  7381. "label": "邻水县",
  7382. "value": "511623"
  7383. }, {
  7384. "label": "华蓥市",
  7385. "value": "511681"
  7386. }],
  7387. [{
  7388. "label": "市辖区",
  7389. "value": "511701"
  7390. }, {
  7391. "label": "通川区",
  7392. "value": "511702"
  7393. }, {
  7394. "label": "达川区",
  7395. "value": "511703"
  7396. }, {
  7397. "label": "宣汉县",
  7398. "value": "511722"
  7399. }, {
  7400. "label": "开江县",
  7401. "value": "511723"
  7402. }, {
  7403. "label": "大竹县",
  7404. "value": "511724"
  7405. }, {
  7406. "label": "渠县",
  7407. "value": "511725"
  7408. }, {
  7409. "label": "万源市",
  7410. "value": "511781"
  7411. }],
  7412. [{
  7413. "label": "市辖区",
  7414. "value": "511801"
  7415. }, {
  7416. "label": "雨城区",
  7417. "value": "511802"
  7418. }, {
  7419. "label": "名山区",
  7420. "value": "511803"
  7421. }, {
  7422. "label": "荥经县",
  7423. "value": "511822"
  7424. }, {
  7425. "label": "汉源县",
  7426. "value": "511823"
  7427. }, {
  7428. "label": "石棉县",
  7429. "value": "511824"
  7430. }, {
  7431. "label": "天全县",
  7432. "value": "511825"
  7433. }, {
  7434. "label": "芦山县",
  7435. "value": "511826"
  7436. }, {
  7437. "label": "宝兴县",
  7438. "value": "511827"
  7439. }],
  7440. [{
  7441. "label": "市辖区",
  7442. "value": "511901"
  7443. }, {
  7444. "label": "巴州区",
  7445. "value": "511902"
  7446. }, {
  7447. "label": "恩阳区",
  7448. "value": "511903"
  7449. }, {
  7450. "label": "通江县",
  7451. "value": "511921"
  7452. }, {
  7453. "label": "南江县",
  7454. "value": "511922"
  7455. }, {
  7456. "label": "平昌县",
  7457. "value": "511923"
  7458. }],
  7459. [{
  7460. "label": "市辖区",
  7461. "value": "512001"
  7462. }, {
  7463. "label": "雁江区",
  7464. "value": "512002"
  7465. }, {
  7466. "label": "安岳县",
  7467. "value": "512021"
  7468. }, {
  7469. "label": "乐至县",
  7470. "value": "512022"
  7471. }],
  7472. [{
  7473. "label": "市辖区",
  7474. "value": "513201"
  7475. }, {
  7476. "label": "汶川县",
  7477. "value": "513221"
  7478. }, {
  7479. "label": "理县",
  7480. "value": "513222"
  7481. }, {
  7482. "label": "茂县",
  7483. "value": "513223"
  7484. }, {
  7485. "label": "松潘县",
  7486. "value": "513224"
  7487. }, {
  7488. "label": "九寨沟县",
  7489. "value": "513225"
  7490. }, {
  7491. "label": "金川县",
  7492. "value": "513226"
  7493. }, {
  7494. "label": "小金县",
  7495. "value": "513227"
  7496. }, {
  7497. "label": "黑水县",
  7498. "value": "513228"
  7499. }, {
  7500. "label": "壤塘县",
  7501. "value": "513230"
  7502. }, {
  7503. "label": "阿坝县",
  7504. "value": "513231"
  7505. }, {
  7506. "label": "若尔盖县",
  7507. "value": "513232"
  7508. }, {
  7509. "label": "红原县",
  7510. "value": "513233"
  7511. }],
  7512. [{
  7513. "label": "市辖区",
  7514. "value": "513301"
  7515. }, {
  7516. "label": "泸定县",
  7517. "value": "513322"
  7518. }, {
  7519. "label": "丹巴县",
  7520. "value": "513323"
  7521. }, {
  7522. "label": "九龙县",
  7523. "value": "513324"
  7524. }, {
  7525. "label": "雅江县",
  7526. "value": "513325"
  7527. }, {
  7528. "label": "道孚县",
  7529. "value": "513326"
  7530. }, {
  7531. "label": "炉霍县",
  7532. "value": "513327"
  7533. }, {
  7534. "label": "甘孜县",
  7535. "value": "513328"
  7536. }, {
  7537. "label": "新龙县",
  7538. "value": "513329"
  7539. }, {
  7540. "label": "德格县",
  7541. "value": "513330"
  7542. }, {
  7543. "label": "白玉县",
  7544. "value": "513331"
  7545. }, {
  7546. "label": "石渠县",
  7547. "value": "513332"
  7548. }, {
  7549. "label": "色达县",
  7550. "value": "513333"
  7551. }, {
  7552. "label": "理塘县",
  7553. "value": "513334"
  7554. }, {
  7555. "label": "巴塘县",
  7556. "value": "513335"
  7557. }, {
  7558. "label": "乡城县",
  7559. "value": "513336"
  7560. }, {
  7561. "label": "稻城县",
  7562. "value": "513337"
  7563. }, {
  7564. "label": "得荣县",
  7565. "value": "513338"
  7566. }],
  7567. [{
  7568. "label": "市辖区",
  7569. "value": "513401"
  7570. }, {
  7571. "label": "木里藏族自治县",
  7572. "value": "513422"
  7573. }, {
  7574. "label": "盐源县",
  7575. "value": "513423"
  7576. }, {
  7577. "label": "德昌县",
  7578. "value": "513424"
  7579. }, {
  7580. "label": "会理县",
  7581. "value": "513425"
  7582. }, {
  7583. "label": "会东县",
  7584. "value": "513426"
  7585. }, {
  7586. "label": "宁南县",
  7587. "value": "513427"
  7588. }, {
  7589. "label": "普格县",
  7590. "value": "513428"
  7591. }, {
  7592. "label": "布拖县",
  7593. "value": "513429"
  7594. }, {
  7595. "label": "金阳县",
  7596. "value": "513430"
  7597. }, {
  7598. "label": "昭觉县",
  7599. "value": "513431"
  7600. }, {
  7601. "label": "喜德县",
  7602. "value": "513432"
  7603. }, {
  7604. "label": "冕宁县",
  7605. "value": "513433"
  7606. }, {
  7607. "label": "越西县",
  7608. "value": "513434"
  7609. }, {
  7610. "label": "甘洛县",
  7611. "value": "513435"
  7612. }, {
  7613. "label": "美姑县",
  7614. "value": "513436"
  7615. }, {
  7616. "label": "雷波县",
  7617. "value": "513437"
  7618. }]
  7619. ],
  7620. [
  7621. [{
  7622. "label": "市辖区",
  7623. "value": "520101"
  7624. }, {
  7625. "label": "南明区",
  7626. "value": "520102"
  7627. }, {
  7628. "label": "云岩区",
  7629. "value": "520103"
  7630. }, {
  7631. "label": "花溪区",
  7632. "value": "520111"
  7633. }, {
  7634. "label": "乌当区",
  7635. "value": "520112"
  7636. }, {
  7637. "label": "白云区",
  7638. "value": "520113"
  7639. }, {
  7640. "label": "观山湖区",
  7641. "value": "520115"
  7642. }, {
  7643. "label": "开阳县",
  7644. "value": "520121"
  7645. }, {
  7646. "label": "息烽县",
  7647. "value": "520122"
  7648. }, {
  7649. "label": "修文县",
  7650. "value": "520123"
  7651. }, {
  7652. "label": "清镇市",
  7653. "value": "520181"
  7654. }],
  7655. [{
  7656. "label": "钟山区",
  7657. "value": "520201"
  7658. }, {
  7659. "label": "六枝特区",
  7660. "value": "520203"
  7661. }, {
  7662. "label": "水城县",
  7663. "value": "520221"
  7664. }, {
  7665. "label": "盘县",
  7666. "value": "520222"
  7667. }],
  7668. [{
  7669. "label": "市辖区",
  7670. "value": "520301"
  7671. }, {
  7672. "label": "红花岗区",
  7673. "value": "520302"
  7674. }, {
  7675. "label": "汇川区",
  7676. "value": "520303"
  7677. }, {
  7678. "label": "播州区",
  7679. "value": "520304"
  7680. }, {
  7681. "label": "桐梓县",
  7682. "value": "520322"
  7683. }, {
  7684. "label": "绥阳县",
  7685. "value": "520323"
  7686. }, {
  7687. "label": "正安县",
  7688. "value": "520324"
  7689. }, {
  7690. "label": "道真仡佬族苗族自治县",
  7691. "value": "520325"
  7692. }, {
  7693. "label": "务川仡佬族苗族自治县",
  7694. "value": "520326"
  7695. }, {
  7696. "label": "凤冈县",
  7697. "value": "520327"
  7698. }, {
  7699. "label": "湄潭县",
  7700. "value": "520328"
  7701. }, {
  7702. "label": "余庆县",
  7703. "value": "520329"
  7704. }, {
  7705. "label": "习水县",
  7706. "value": "520330"
  7707. }, {
  7708. "label": "赤水市",
  7709. "value": "520381"
  7710. }, {
  7711. "label": "仁怀市",
  7712. "value": "520382"
  7713. }],
  7714. [{
  7715. "label": "市辖区",
  7716. "value": "520401"
  7717. }, {
  7718. "label": "西秀区",
  7719. "value": "520402"
  7720. }, {
  7721. "label": "平坝区",
  7722. "value": "520403"
  7723. }, {
  7724. "label": "普定县",
  7725. "value": "520422"
  7726. }, {
  7727. "label": "镇宁布依族苗族自治县",
  7728. "value": "520423"
  7729. }, {
  7730. "label": "关岭布依族苗族自治县",
  7731. "value": "520424"
  7732. }, {
  7733. "label": "紫云苗族布依族自治县",
  7734. "value": "520425"
  7735. }],
  7736. [{
  7737. "label": "市辖区",
  7738. "value": "520501"
  7739. }, {
  7740. "label": "七星关区",
  7741. "value": "520502"
  7742. }, {
  7743. "label": "大方县",
  7744. "value": "520521"
  7745. }, {
  7746. "label": "黔西县",
  7747. "value": "520522"
  7748. }, {
  7749. "label": "金沙县",
  7750. "value": "520523"
  7751. }, {
  7752. "label": "织金县",
  7753. "value": "520524"
  7754. }, {
  7755. "label": "纳雍县",
  7756. "value": "520525"
  7757. }, {
  7758. "label": "威宁彝族回族苗族自治县",
  7759. "value": "520526"
  7760. }, {
  7761. "label": "赫章县",
  7762. "value": "520527"
  7763. }],
  7764. [{
  7765. "label": "市辖区",
  7766. "value": "520601"
  7767. }, {
  7768. "label": "碧江区",
  7769. "value": "520602"
  7770. }, {
  7771. "label": "万山区",
  7772. "value": "520603"
  7773. }, {
  7774. "label": "江口县",
  7775. "value": "520621"
  7776. }, {
  7777. "label": "玉屏侗族自治县",
  7778. "value": "520622"
  7779. }, {
  7780. "label": "石阡县",
  7781. "value": "520623"
  7782. }, {
  7783. "label": "思南县",
  7784. "value": "520624"
  7785. }, {
  7786. "label": "印江土家族苗族自治县",
  7787. "value": "520625"
  7788. }, {
  7789. "label": "德江县",
  7790. "value": "520626"
  7791. }, {
  7792. "label": "沿河土家族自治县",
  7793. "value": "520627"
  7794. }, {
  7795. "label": "松桃苗族自治县",
  7796. "value": "520628"
  7797. }],
  7798. [{
  7799. "label": "市辖区",
  7800. "value": "522301"
  7801. }, {
  7802. "label": "兴仁县",
  7803. "value": "522322"
  7804. }, {
  7805. "label": "普安县",
  7806. "value": "522323"
  7807. }, {
  7808. "label": "晴隆县",
  7809. "value": "522324"
  7810. }, {
  7811. "label": "贞丰县",
  7812. "value": "522325"
  7813. }, {
  7814. "label": "望谟县",
  7815. "value": "522326"
  7816. }, {
  7817. "label": "册亨县",
  7818. "value": "522327"
  7819. }, {
  7820. "label": "安龙县",
  7821. "value": "522328"
  7822. }],
  7823. [{
  7824. "label": "市辖区",
  7825. "value": "522601"
  7826. }, {
  7827. "label": "黄平县",
  7828. "value": "522622"
  7829. }, {
  7830. "label": "施秉县",
  7831. "value": "522623"
  7832. }, {
  7833. "label": "三穗县",
  7834. "value": "522624"
  7835. }, {
  7836. "label": "镇远县",
  7837. "value": "522625"
  7838. }, {
  7839. "label": "岑巩县",
  7840. "value": "522626"
  7841. }, {
  7842. "label": "天柱县",
  7843. "value": "522627"
  7844. }, {
  7845. "label": "锦屏县",
  7846. "value": "522628"
  7847. }, {
  7848. "label": "剑河县",
  7849. "value": "522629"
  7850. }, {
  7851. "label": "台江县",
  7852. "value": "522630"
  7853. }, {
  7854. "label": "黎平县",
  7855. "value": "522631"
  7856. }, {
  7857. "label": "榕江县",
  7858. "value": "522632"
  7859. }, {
  7860. "label": "从江县",
  7861. "value": "522633"
  7862. }, {
  7863. "label": "雷山县",
  7864. "value": "522634"
  7865. }, {
  7866. "label": "麻江县",
  7867. "value": "522635"
  7868. }, {
  7869. "label": "丹寨县",
  7870. "value": "522636"
  7871. }],
  7872. [{
  7873. "label": "市辖区",
  7874. "value": "522701"
  7875. }, {
  7876. "label": "福泉市",
  7877. "value": "522702"
  7878. }, {
  7879. "label": "荔波县",
  7880. "value": "522722"
  7881. }, {
  7882. "label": "贵定县",
  7883. "value": "522723"
  7884. }, {
  7885. "label": "瓮安县",
  7886. "value": "522725"
  7887. }, {
  7888. "label": "独山县",
  7889. "value": "522726"
  7890. }, {
  7891. "label": "平塘县",
  7892. "value": "522727"
  7893. }, {
  7894. "label": "罗甸县",
  7895. "value": "522728"
  7896. }, {
  7897. "label": "长顺县",
  7898. "value": "522729"
  7899. }, {
  7900. "label": "龙里县",
  7901. "value": "522730"
  7902. }, {
  7903. "label": "惠水县",
  7904. "value": "522731"
  7905. }, {
  7906. "label": "三都水族自治县",
  7907. "value": "522732"
  7908. }]
  7909. ],
  7910. [
  7911. [{
  7912. "label": "市辖区",
  7913. "value": "530101"
  7914. }, {
  7915. "label": "五华区",
  7916. "value": "530102"
  7917. }, {
  7918. "label": "盘龙区",
  7919. "value": "530103"
  7920. }, {
  7921. "label": "官渡区",
  7922. "value": "530111"
  7923. }, {
  7924. "label": "西山区",
  7925. "value": "530112"
  7926. }, {
  7927. "label": "东川区",
  7928. "value": "530113"
  7929. }, {
  7930. "label": "呈贡区",
  7931. "value": "530114"
  7932. }, {
  7933. "label": "晋宁县",
  7934. "value": "530122"
  7935. }, {
  7936. "label": "富民县",
  7937. "value": "530124"
  7938. }, {
  7939. "label": "宜良县",
  7940. "value": "530125"
  7941. }, {
  7942. "label": "石林彝族自治县",
  7943. "value": "530126"
  7944. }, {
  7945. "label": "嵩明县",
  7946. "value": "530127"
  7947. }, {
  7948. "label": "禄劝彝族苗族自治县",
  7949. "value": "530128"
  7950. }, {
  7951. "label": "寻甸回族彝族自治县",
  7952. "value": "530129"
  7953. }, {
  7954. "label": "安宁市",
  7955. "value": "530181"
  7956. }],
  7957. [{
  7958. "label": "市辖区",
  7959. "value": "530301"
  7960. }, {
  7961. "label": "麒麟区",
  7962. "value": "530302"
  7963. }, {
  7964. "label": "沾益区",
  7965. "value": "530303"
  7966. }, {
  7967. "label": "马龙县",
  7968. "value": "530321"
  7969. }, {
  7970. "label": "陆良县",
  7971. "value": "530322"
  7972. }, {
  7973. "label": "师宗县",
  7974. "value": "530323"
  7975. }, {
  7976. "label": "罗平县",
  7977. "value": "530324"
  7978. }, {
  7979. "label": "富源县",
  7980. "value": "530325"
  7981. }, {
  7982. "label": "会泽县",
  7983. "value": "530326"
  7984. }, {
  7985. "label": "宣威市",
  7986. "value": "530381"
  7987. }],
  7988. [{
  7989. "label": "市辖区",
  7990. "value": "530401"
  7991. }, {
  7992. "label": "红塔区",
  7993. "value": "530402"
  7994. }, {
  7995. "label": "江川区",
  7996. "value": "530403"
  7997. }, {
  7998. "label": "澄江县",
  7999. "value": "530422"
  8000. }, {
  8001. "label": "通海县",
  8002. "value": "530423"
  8003. }, {
  8004. "label": "华宁县",
  8005. "value": "530424"
  8006. }, {
  8007. "label": "易门县",
  8008. "value": "530425"
  8009. }, {
  8010. "label": "峨山彝族自治县",
  8011. "value": "530426"
  8012. }, {
  8013. "label": "新平彝族傣族自治县",
  8014. "value": "530427"
  8015. }, {
  8016. "label": "元江哈尼族彝族傣族自治县",
  8017. "value": "530428"
  8018. }],
  8019. [{
  8020. "label": "市辖区",
  8021. "value": "530501"
  8022. }, {
  8023. "label": "隆阳区",
  8024. "value": "530502"
  8025. }, {
  8026. "label": "施甸县",
  8027. "value": "530521"
  8028. }, {
  8029. "label": "龙陵县",
  8030. "value": "530523"
  8031. }, {
  8032. "label": "昌宁县",
  8033. "value": "530524"
  8034. }, {
  8035. "label": "腾冲市",
  8036. "value": "530581"
  8037. }],
  8038. [{
  8039. "label": "市辖区",
  8040. "value": "530601"
  8041. }, {
  8042. "label": "昭阳区",
  8043. "value": "530602"
  8044. }, {
  8045. "label": "鲁甸县",
  8046. "value": "530621"
  8047. }, {
  8048. "label": "巧家县",
  8049. "value": "530622"
  8050. }, {
  8051. "label": "盐津县",
  8052. "value": "530623"
  8053. }, {
  8054. "label": "大关县",
  8055. "value": "530624"
  8056. }, {
  8057. "label": "永善县",
  8058. "value": "530625"
  8059. }, {
  8060. "label": "绥江县",
  8061. "value": "530626"
  8062. }, {
  8063. "label": "镇雄县",
  8064. "value": "530627"
  8065. }, {
  8066. "label": "彝良县",
  8067. "value": "530628"
  8068. }, {
  8069. "label": "威信县",
  8070. "value": "530629"
  8071. }, {
  8072. "label": "水富县",
  8073. "value": "530630"
  8074. }],
  8075. [{
  8076. "label": "市辖区",
  8077. "value": "530701"
  8078. }, {
  8079. "label": "古城区",
  8080. "value": "530702"
  8081. }, {
  8082. "label": "玉龙纳西族自治县",
  8083. "value": "530721"
  8084. }, {
  8085. "label": "永胜县",
  8086. "value": "530722"
  8087. }, {
  8088. "label": "华坪县",
  8089. "value": "530723"
  8090. }, {
  8091. "label": "宁蒗彝族自治县",
  8092. "value": "530724"
  8093. }],
  8094. [{
  8095. "label": "市辖区",
  8096. "value": "530801"
  8097. }, {
  8098. "label": "思茅区",
  8099. "value": "530802"
  8100. }, {
  8101. "label": "宁洱哈尼族彝族自治县",
  8102. "value": "530821"
  8103. }, {
  8104. "label": "墨江哈尼族自治县",
  8105. "value": "530822"
  8106. }, {
  8107. "label": "景东彝族自治县",
  8108. "value": "530823"
  8109. }, {
  8110. "label": "景谷傣族彝族自治县",
  8111. "value": "530824"
  8112. }, {
  8113. "label": "镇沅彝族哈尼族拉祜族自治县",
  8114. "value": "530825"
  8115. }, {
  8116. "label": "江城哈尼族彝族自治县",
  8117. "value": "530826"
  8118. }, {
  8119. "label": "孟连傣族拉祜族佤族自治县",
  8120. "value": "530827"
  8121. }, {
  8122. "label": "澜沧拉祜族自治县",
  8123. "value": "530828"
  8124. }, {
  8125. "label": "西盟佤族自治县",
  8126. "value": "530829"
  8127. }],
  8128. [{
  8129. "label": "市辖区",
  8130. "value": "530901"
  8131. }, {
  8132. "label": "临翔区",
  8133. "value": "530902"
  8134. }, {
  8135. "label": "凤庆县",
  8136. "value": "530921"
  8137. }, {
  8138. "label": "云县",
  8139. "value": "530922"
  8140. }, {
  8141. "label": "永德县",
  8142. "value": "530923"
  8143. }, {
  8144. "label": "镇康县",
  8145. "value": "530924"
  8146. }, {
  8147. "label": "双江拉祜族佤族布朗族傣族自治县",
  8148. "value": "530925"
  8149. }, {
  8150. "label": "耿马傣族佤族自治县",
  8151. "value": "530926"
  8152. }, {
  8153. "label": "沧源佤族自治县",
  8154. "value": "530927"
  8155. }],
  8156. [{
  8157. "label": "市辖区",
  8158. "value": "532301"
  8159. }, {
  8160. "label": "双柏县",
  8161. "value": "532322"
  8162. }, {
  8163. "label": "牟定县",
  8164. "value": "532323"
  8165. }, {
  8166. "label": "南华县",
  8167. "value": "532324"
  8168. }, {
  8169. "label": "姚安县",
  8170. "value": "532325"
  8171. }, {
  8172. "label": "大姚县",
  8173. "value": "532326"
  8174. }, {
  8175. "label": "永仁县",
  8176. "value": "532327"
  8177. }, {
  8178. "label": "元谋县",
  8179. "value": "532328"
  8180. }, {
  8181. "label": "武定县",
  8182. "value": "532329"
  8183. }, {
  8184. "label": "禄丰县",
  8185. "value": "532331"
  8186. }],
  8187. [{
  8188. "label": "市辖区",
  8189. "value": "532501"
  8190. }, {
  8191. "label": "开远市",
  8192. "value": "532502"
  8193. }, {
  8194. "label": "蒙自市",
  8195. "value": "532503"
  8196. }, {
  8197. "label": "弥勒市",
  8198. "value": "532504"
  8199. }, {
  8200. "label": "屏边苗族自治县",
  8201. "value": "532523"
  8202. }, {
  8203. "label": "建水县",
  8204. "value": "532524"
  8205. }, {
  8206. "label": "石屏县",
  8207. "value": "532525"
  8208. }, {
  8209. "label": "泸西县",
  8210. "value": "532527"
  8211. }, {
  8212. "label": "元阳县",
  8213. "value": "532528"
  8214. }, {
  8215. "label": "红河县",
  8216. "value": "532529"
  8217. }, {
  8218. "label": "金平苗族瑶族傣族自治县",
  8219. "value": "532530"
  8220. }, {
  8221. "label": "绿春县",
  8222. "value": "532531"
  8223. }, {
  8224. "label": "河口瑶族自治县",
  8225. "value": "532532"
  8226. }],
  8227. [{
  8228. "label": "市辖区",
  8229. "value": "532601"
  8230. }, {
  8231. "label": "砚山县",
  8232. "value": "532622"
  8233. }, {
  8234. "label": "西畴县",
  8235. "value": "532623"
  8236. }, {
  8237. "label": "麻栗坡县",
  8238. "value": "532624"
  8239. }, {
  8240. "label": "马关县",
  8241. "value": "532625"
  8242. }, {
  8243. "label": "丘北县",
  8244. "value": "532626"
  8245. }, {
  8246. "label": "广南县",
  8247. "value": "532627"
  8248. }, {
  8249. "label": "富宁县",
  8250. "value": "532628"
  8251. }],
  8252. [{
  8253. "label": "市辖区",
  8254. "value": "532801"
  8255. }, {
  8256. "label": "勐海县",
  8257. "value": "532822"
  8258. }, {
  8259. "label": "勐腊县",
  8260. "value": "532823"
  8261. }],
  8262. [{
  8263. "label": "市辖区",
  8264. "value": "532901"
  8265. }, {
  8266. "label": "漾濞彝族自治县",
  8267. "value": "532922"
  8268. }, {
  8269. "label": "祥云县",
  8270. "value": "532923"
  8271. }, {
  8272. "label": "宾川县",
  8273. "value": "532924"
  8274. }, {
  8275. "label": "弥渡县",
  8276. "value": "532925"
  8277. }, {
  8278. "label": "南涧彝族自治县",
  8279. "value": "532926"
  8280. }, {
  8281. "label": "巍山彝族回族自治县",
  8282. "value": "532927"
  8283. }, {
  8284. "label": "永平县",
  8285. "value": "532928"
  8286. }, {
  8287. "label": "云龙县",
  8288. "value": "532929"
  8289. }, {
  8290. "label": "洱源县",
  8291. "value": "532930"
  8292. }, {
  8293. "label": "剑川县",
  8294. "value": "532931"
  8295. }, {
  8296. "label": "鹤庆县",
  8297. "value": "532932"
  8298. }],
  8299. [{
  8300. "label": "瑞丽市",
  8301. "value": "533102"
  8302. }, {
  8303. "label": "芒市",
  8304. "value": "533103"
  8305. }, {
  8306. "label": "梁河县",
  8307. "value": "533122"
  8308. }, {
  8309. "label": "盈江县",
  8310. "value": "533123"
  8311. }, {
  8312. "label": "陇川县",
  8313. "value": "533124"
  8314. }],
  8315. [{
  8316. "label": "市辖区",
  8317. "value": "533301"
  8318. }, {
  8319. "label": "福贡县",
  8320. "value": "533323"
  8321. }, {
  8322. "label": "贡山独龙族怒族自治县",
  8323. "value": "533324"
  8324. }, {
  8325. "label": "兰坪白族普米族自治县",
  8326. "value": "533325"
  8327. }],
  8328. [{
  8329. "label": "市辖区",
  8330. "value": "533401"
  8331. }, {
  8332. "label": "德钦县",
  8333. "value": "533422"
  8334. }, {
  8335. "label": "维西傈僳族自治县",
  8336. "value": "533423"
  8337. }]
  8338. ],
  8339. [
  8340. [{
  8341. "label": "市辖区",
  8342. "value": "540101"
  8343. }, {
  8344. "label": "城关区",
  8345. "value": "540102"
  8346. }, {
  8347. "label": "堆龙德庆区",
  8348. "value": "540103"
  8349. }, {
  8350. "label": "林周县",
  8351. "value": "540121"
  8352. }, {
  8353. "label": "当雄县",
  8354. "value": "540122"
  8355. }, {
  8356. "label": "尼木县",
  8357. "value": "540123"
  8358. }, {
  8359. "label": "曲水县",
  8360. "value": "540124"
  8361. }, {
  8362. "label": "达孜县",
  8363. "value": "540126"
  8364. }, {
  8365. "label": "墨竹工卡县",
  8366. "value": "540127"
  8367. }],
  8368. [{
  8369. "label": "桑珠孜区",
  8370. "value": "540202"
  8371. }, {
  8372. "label": "南木林县",
  8373. "value": "540221"
  8374. }, {
  8375. "label": "江孜县",
  8376. "value": "540222"
  8377. }, {
  8378. "label": "定日县",
  8379. "value": "540223"
  8380. }, {
  8381. "label": "萨迦县",
  8382. "value": "540224"
  8383. }, {
  8384. "label": "拉孜县",
  8385. "value": "540225"
  8386. }, {
  8387. "label": "昂仁县",
  8388. "value": "540226"
  8389. }, {
  8390. "label": "谢通门县",
  8391. "value": "540227"
  8392. }, {
  8393. "label": "白朗县",
  8394. "value": "540228"
  8395. }, {
  8396. "label": "仁布县",
  8397. "value": "540229"
  8398. }, {
  8399. "label": "康马县",
  8400. "value": "540230"
  8401. }, {
  8402. "label": "定结县",
  8403. "value": "540231"
  8404. }, {
  8405. "label": "仲巴县",
  8406. "value": "540232"
  8407. }, {
  8408. "label": "亚东县",
  8409. "value": "540233"
  8410. }, {
  8411. "label": "吉隆县",
  8412. "value": "540234"
  8413. }, {
  8414. "label": "聂拉木县",
  8415. "value": "540235"
  8416. }, {
  8417. "label": "萨嘎县",
  8418. "value": "540236"
  8419. }, {
  8420. "label": "岗巴县",
  8421. "value": "540237"
  8422. }],
  8423. [{
  8424. "label": "卡若区",
  8425. "value": "540302"
  8426. }, {
  8427. "label": "江达县",
  8428. "value": "540321"
  8429. }, {
  8430. "label": "贡觉县",
  8431. "value": "540322"
  8432. }, {
  8433. "label": "类乌齐县",
  8434. "value": "540323"
  8435. }, {
  8436. "label": "丁青县",
  8437. "value": "540324"
  8438. }, {
  8439. "label": "察雅县",
  8440. "value": "540325"
  8441. }, {
  8442. "label": "八宿县",
  8443. "value": "540326"
  8444. }, {
  8445. "label": "左贡县",
  8446. "value": "540327"
  8447. }, {
  8448. "label": "芒康县",
  8449. "value": "540328"
  8450. }, {
  8451. "label": "洛隆县",
  8452. "value": "540329"
  8453. }, {
  8454. "label": "边坝县",
  8455. "value": "540330"
  8456. }],
  8457. [{
  8458. "label": "巴宜区",
  8459. "value": "540402"
  8460. }, {
  8461. "label": "工布江达县",
  8462. "value": "540421"
  8463. }, {
  8464. "label": "米林县",
  8465. "value": "540422"
  8466. }, {
  8467. "label": "墨脱县",
  8468. "value": "540423"
  8469. }, {
  8470. "label": "波密县",
  8471. "value": "540424"
  8472. }, {
  8473. "label": "察隅县",
  8474. "value": "540425"
  8475. }, {
  8476. "label": "朗县",
  8477. "value": "540426"
  8478. }],
  8479. [{
  8480. "label": "市辖区",
  8481. "value": "540501"
  8482. }, {
  8483. "label": "乃东区",
  8484. "value": "540502"
  8485. }, {
  8486. "label": "扎囊县",
  8487. "value": "540521"
  8488. }, {
  8489. "label": "贡嘎县",
  8490. "value": "540522"
  8491. }, {
  8492. "label": "桑日县",
  8493. "value": "540523"
  8494. }, {
  8495. "label": "琼结县",
  8496. "value": "540524"
  8497. }, {
  8498. "label": "曲松县",
  8499. "value": "540525"
  8500. }, {
  8501. "label": "措美县",
  8502. "value": "540526"
  8503. }, {
  8504. "label": "洛扎县",
  8505. "value": "540527"
  8506. }, {
  8507. "label": "加查县",
  8508. "value": "540528"
  8509. }, {
  8510. "label": "隆子县",
  8511. "value": "540529"
  8512. }, {
  8513. "label": "错那县",
  8514. "value": "540530"
  8515. }, {
  8516. "label": "浪卡子县",
  8517. "value": "540531"
  8518. }],
  8519. [{
  8520. "label": "那曲县",
  8521. "value": "542421"
  8522. }, {
  8523. "label": "嘉黎县",
  8524. "value": "542422"
  8525. }, {
  8526. "label": "比如县",
  8527. "value": "542423"
  8528. }, {
  8529. "label": "聂荣县",
  8530. "value": "542424"
  8531. }, {
  8532. "label": "安多县",
  8533. "value": "542425"
  8534. }, {
  8535. "label": "申扎县",
  8536. "value": "542426"
  8537. }, {
  8538. "label": "索县",
  8539. "value": "542427"
  8540. }, {
  8541. "label": "班戈县",
  8542. "value": "542428"
  8543. }, {
  8544. "label": "巴青县",
  8545. "value": "542429"
  8546. }, {
  8547. "label": "尼玛县",
  8548. "value": "542430"
  8549. }, {
  8550. "label": "双湖县",
  8551. "value": "542431"
  8552. }],
  8553. [{
  8554. "label": "普兰县",
  8555. "value": "542521"
  8556. }, {
  8557. "label": "札达县",
  8558. "value": "542522"
  8559. }, {
  8560. "label": "噶尔县",
  8561. "value": "542523"
  8562. }, {
  8563. "label": "日土县",
  8564. "value": "542524"
  8565. }, {
  8566. "label": "革吉县",
  8567. "value": "542525"
  8568. }, {
  8569. "label": "改则县",
  8570. "value": "542526"
  8571. }, {
  8572. "label": "措勤县",
  8573. "value": "542527"
  8574. }]
  8575. ],
  8576. [
  8577. [{
  8578. "label": "市辖区",
  8579. "value": "610101"
  8580. }, {
  8581. "label": "新城区",
  8582. "value": "610102"
  8583. }, {
  8584. "label": "碑林区",
  8585. "value": "610103"
  8586. }, {
  8587. "label": "莲湖区",
  8588. "value": "610104"
  8589. }, {
  8590. "label": "灞桥区",
  8591. "value": "610111"
  8592. }, {
  8593. "label": "未央区",
  8594. "value": "610112"
  8595. }, {
  8596. "label": "雁塔区",
  8597. "value": "610113"
  8598. }, {
  8599. "label": "阎良区",
  8600. "value": "610114"
  8601. }, {
  8602. "label": "临潼区",
  8603. "value": "610115"
  8604. }, {
  8605. "label": "长安区",
  8606. "value": "610116"
  8607. }, {
  8608. "label": "高陵区",
  8609. "value": "610117"
  8610. }, {
  8611. "label": "蓝田县",
  8612. "value": "610122"
  8613. }, {
  8614. "label": "周至县",
  8615. "value": "610124"
  8616. }, {
  8617. "label": "户县",
  8618. "value": "610125"
  8619. }],
  8620. [{
  8621. "label": "市辖区",
  8622. "value": "610201"
  8623. }, {
  8624. "label": "王益区",
  8625. "value": "610202"
  8626. }, {
  8627. "label": "印台区",
  8628. "value": "610203"
  8629. }, {
  8630. "label": "耀州区",
  8631. "value": "610204"
  8632. }, {
  8633. "label": "宜君县",
  8634. "value": "610222"
  8635. }],
  8636. [{
  8637. "label": "市辖区",
  8638. "value": "610301"
  8639. }, {
  8640. "label": "渭滨区",
  8641. "value": "610302"
  8642. }, {
  8643. "label": "金台区",
  8644. "value": "610303"
  8645. }, {
  8646. "label": "陈仓区",
  8647. "value": "610304"
  8648. }, {
  8649. "label": "凤翔县",
  8650. "value": "610322"
  8651. }, {
  8652. "label": "岐山县",
  8653. "value": "610323"
  8654. }, {
  8655. "label": "扶风县",
  8656. "value": "610324"
  8657. }, {
  8658. "label": "眉县",
  8659. "value": "610326"
  8660. }, {
  8661. "label": "陇县",
  8662. "value": "610327"
  8663. }, {
  8664. "label": "千阳县",
  8665. "value": "610328"
  8666. }, {
  8667. "label": "麟游县",
  8668. "value": "610329"
  8669. }, {
  8670. "label": "凤县",
  8671. "value": "610330"
  8672. }, {
  8673. "label": "太白县",
  8674. "value": "610331"
  8675. }],
  8676. [{
  8677. "label": "市辖区",
  8678. "value": "610401"
  8679. }, {
  8680. "label": "秦都区",
  8681. "value": "610402"
  8682. }, {
  8683. "label": "杨陵区",
  8684. "value": "610403"
  8685. }, {
  8686. "label": "渭城区",
  8687. "value": "610404"
  8688. }, {
  8689. "label": "三原县",
  8690. "value": "610422"
  8691. }, {
  8692. "label": "泾阳县",
  8693. "value": "610423"
  8694. }, {
  8695. "label": "乾县",
  8696. "value": "610424"
  8697. }, {
  8698. "label": "礼泉县",
  8699. "value": "610425"
  8700. }, {
  8701. "label": "永寿县",
  8702. "value": "610426"
  8703. }, {
  8704. "label": "彬县",
  8705. "value": "610427"
  8706. }, {
  8707. "label": "长武县",
  8708. "value": "610428"
  8709. }, {
  8710. "label": "旬邑县",
  8711. "value": "610429"
  8712. }, {
  8713. "label": "淳化县",
  8714. "value": "610430"
  8715. }, {
  8716. "label": "武功县",
  8717. "value": "610431"
  8718. }, {
  8719. "label": "兴平市",
  8720. "value": "610481"
  8721. }],
  8722. [{
  8723. "label": "市辖区",
  8724. "value": "610501"
  8725. }, {
  8726. "label": "临渭区",
  8727. "value": "610502"
  8728. }, {
  8729. "label": "华州区",
  8730. "value": "610503"
  8731. }, {
  8732. "label": "潼关县",
  8733. "value": "610522"
  8734. }, {
  8735. "label": "大荔县",
  8736. "value": "610523"
  8737. }, {
  8738. "label": "合阳县",
  8739. "value": "610524"
  8740. }, {
  8741. "label": "澄城县",
  8742. "value": "610525"
  8743. }, {
  8744. "label": "蒲城县",
  8745. "value": "610526"
  8746. }, {
  8747. "label": "白水县",
  8748. "value": "610527"
  8749. }, {
  8750. "label": "富平县",
  8751. "value": "610528"
  8752. }, {
  8753. "label": "韩城市",
  8754. "value": "610581"
  8755. }, {
  8756. "label": "华阴市",
  8757. "value": "610582"
  8758. }],
  8759. [{
  8760. "label": "市辖区",
  8761. "value": "610601"
  8762. }, {
  8763. "label": "宝塔区",
  8764. "value": "610602"
  8765. }, {
  8766. "label": "安塞区",
  8767. "value": "610603"
  8768. }, {
  8769. "label": "延长县",
  8770. "value": "610621"
  8771. }, {
  8772. "label": "延川县",
  8773. "value": "610622"
  8774. }, {
  8775. "label": "子长县",
  8776. "value": "610623"
  8777. }, {
  8778. "label": "志丹县",
  8779. "value": "610625"
  8780. }, {
  8781. "label": "吴起县",
  8782. "value": "610626"
  8783. }, {
  8784. "label": "甘泉县",
  8785. "value": "610627"
  8786. }, {
  8787. "label": "富县",
  8788. "value": "610628"
  8789. }, {
  8790. "label": "洛川县",
  8791. "value": "610629"
  8792. }, {
  8793. "label": "宜川县",
  8794. "value": "610630"
  8795. }, {
  8796. "label": "黄龙县",
  8797. "value": "610631"
  8798. }, {
  8799. "label": "黄陵县",
  8800. "value": "610632"
  8801. }],
  8802. [{
  8803. "label": "市辖区",
  8804. "value": "610701"
  8805. }, {
  8806. "label": "汉台区",
  8807. "value": "610702"
  8808. }, {
  8809. "label": "南郑县",
  8810. "value": "610721"
  8811. }, {
  8812. "label": "城固县",
  8813. "value": "610722"
  8814. }, {
  8815. "label": "洋县",
  8816. "value": "610723"
  8817. }, {
  8818. "label": "西乡县",
  8819. "value": "610724"
  8820. }, {
  8821. "label": "勉县",
  8822. "value": "610725"
  8823. }, {
  8824. "label": "宁强县",
  8825. "value": "610726"
  8826. }, {
  8827. "label": "略阳县",
  8828. "value": "610727"
  8829. }, {
  8830. "label": "镇巴县",
  8831. "value": "610728"
  8832. }, {
  8833. "label": "留坝县",
  8834. "value": "610729"
  8835. }, {
  8836. "label": "佛坪县",
  8837. "value": "610730"
  8838. }],
  8839. [{
  8840. "label": "市辖区",
  8841. "value": "610801"
  8842. }, {
  8843. "label": "榆阳区",
  8844. "value": "610802"
  8845. }, {
  8846. "label": "横山区",
  8847. "value": "610803"
  8848. }, {
  8849. "label": "神木县",
  8850. "value": "610821"
  8851. }, {
  8852. "label": "府谷县",
  8853. "value": "610822"
  8854. }, {
  8855. "label": "靖边县",
  8856. "value": "610824"
  8857. }, {
  8858. "label": "定边县",
  8859. "value": "610825"
  8860. }, {
  8861. "label": "绥德县",
  8862. "value": "610826"
  8863. }, {
  8864. "label": "米脂县",
  8865. "value": "610827"
  8866. }, {
  8867. "label": "佳县",
  8868. "value": "610828"
  8869. }, {
  8870. "label": "吴堡县",
  8871. "value": "610829"
  8872. }, {
  8873. "label": "清涧县",
  8874. "value": "610830"
  8875. }, {
  8876. "label": "子洲县",
  8877. "value": "610831"
  8878. }],
  8879. [{
  8880. "label": "市辖区",
  8881. "value": "610901"
  8882. }, {
  8883. "label": "汉滨区",
  8884. "value": "610902"
  8885. }, {
  8886. "label": "汉阴县",
  8887. "value": "610921"
  8888. }, {
  8889. "label": "石泉县",
  8890. "value": "610922"
  8891. }, {
  8892. "label": "宁陕县",
  8893. "value": "610923"
  8894. }, {
  8895. "label": "紫阳县",
  8896. "value": "610924"
  8897. }, {
  8898. "label": "岚皋县",
  8899. "value": "610925"
  8900. }, {
  8901. "label": "平利县",
  8902. "value": "610926"
  8903. }, {
  8904. "label": "镇坪县",
  8905. "value": "610927"
  8906. }, {
  8907. "label": "旬阳县",
  8908. "value": "610928"
  8909. }, {
  8910. "label": "白河县",
  8911. "value": "610929"
  8912. }],
  8913. [{
  8914. "label": "市辖区",
  8915. "value": "611001"
  8916. }, {
  8917. "label": "商州区",
  8918. "value": "611002"
  8919. }, {
  8920. "label": "洛南县",
  8921. "value": "611021"
  8922. }, {
  8923. "label": "丹凤县",
  8924. "value": "611022"
  8925. }, {
  8926. "label": "商南县",
  8927. "value": "611023"
  8928. }, {
  8929. "label": "山阳县",
  8930. "value": "611024"
  8931. }, {
  8932. "label": "镇安县",
  8933. "value": "611025"
  8934. }, {
  8935. "label": "柞水县",
  8936. "value": "611026"
  8937. }]
  8938. ],
  8939. [
  8940. [{
  8941. "label": "市辖区",
  8942. "value": "620101"
  8943. }, {
  8944. "label": "城关区",
  8945. "value": "620102"
  8946. }, {
  8947. "label": "七里河区",
  8948. "value": "620103"
  8949. }, {
  8950. "label": "西固区",
  8951. "value": "620104"
  8952. }, {
  8953. "label": "安宁区",
  8954. "value": "620105"
  8955. }, {
  8956. "label": "红古区",
  8957. "value": "620111"
  8958. }, {
  8959. "label": "永登县",
  8960. "value": "620121"
  8961. }, {
  8962. "label": "皋兰县",
  8963. "value": "620122"
  8964. }, {
  8965. "label": "榆中县",
  8966. "value": "620123"
  8967. }],
  8968. [{
  8969. "label": "市辖区",
  8970. "value": "620201"
  8971. }],
  8972. [{
  8973. "label": "市辖区",
  8974. "value": "620301"
  8975. }, {
  8976. "label": "金川区",
  8977. "value": "620302"
  8978. }, {
  8979. "label": "永昌县",
  8980. "value": "620321"
  8981. }],
  8982. [{
  8983. "label": "市辖区",
  8984. "value": "620401"
  8985. }, {
  8986. "label": "白银区",
  8987. "value": "620402"
  8988. }, {
  8989. "label": "平川区",
  8990. "value": "620403"
  8991. }, {
  8992. "label": "靖远县",
  8993. "value": "620421"
  8994. }, {
  8995. "label": "会宁县",
  8996. "value": "620422"
  8997. }, {
  8998. "label": "景泰县",
  8999. "value": "620423"
  9000. }],
  9001. [{
  9002. "label": "市辖区",
  9003. "value": "620501"
  9004. }, {
  9005. "label": "秦州区",
  9006. "value": "620502"
  9007. }, {
  9008. "label": "麦积区",
  9009. "value": "620503"
  9010. }, {
  9011. "label": "清水县",
  9012. "value": "620521"
  9013. }, {
  9014. "label": "秦安县",
  9015. "value": "620522"
  9016. }, {
  9017. "label": "甘谷县",
  9018. "value": "620523"
  9019. }, {
  9020. "label": "武山县",
  9021. "value": "620524"
  9022. }, {
  9023. "label": "张家川回族自治县",
  9024. "value": "620525"
  9025. }],
  9026. [{
  9027. "label": "市辖区",
  9028. "value": "620601"
  9029. }, {
  9030. "label": "凉州区",
  9031. "value": "620602"
  9032. }, {
  9033. "label": "民勤县",
  9034. "value": "620621"
  9035. }, {
  9036. "label": "古浪县",
  9037. "value": "620622"
  9038. }, {
  9039. "label": "天祝藏族自治县",
  9040. "value": "620623"
  9041. }],
  9042. [{
  9043. "label": "市辖区",
  9044. "value": "620701"
  9045. }, {
  9046. "label": "甘州区",
  9047. "value": "620702"
  9048. }, {
  9049. "label": "肃南裕固族自治县",
  9050. "value": "620721"
  9051. }, {
  9052. "label": "民乐县",
  9053. "value": "620722"
  9054. }, {
  9055. "label": "临泽县",
  9056. "value": "620723"
  9057. }, {
  9058. "label": "高台县",
  9059. "value": "620724"
  9060. }, {
  9061. "label": "山丹县",
  9062. "value": "620725"
  9063. }],
  9064. [{
  9065. "label": "市辖区",
  9066. "value": "620801"
  9067. }, {
  9068. "label": "崆峒区",
  9069. "value": "620802"
  9070. }, {
  9071. "label": "泾川县",
  9072. "value": "620821"
  9073. }, {
  9074. "label": "灵台县",
  9075. "value": "620822"
  9076. }, {
  9077. "label": "崇信县",
  9078. "value": "620823"
  9079. }, {
  9080. "label": "华亭县",
  9081. "value": "620824"
  9082. }, {
  9083. "label": "庄浪县",
  9084. "value": "620825"
  9085. }, {
  9086. "label": "静宁县",
  9087. "value": "620826"
  9088. }],
  9089. [{
  9090. "label": "市辖区",
  9091. "value": "620901"
  9092. }, {
  9093. "label": "肃州区",
  9094. "value": "620902"
  9095. }, {
  9096. "label": "金塔县",
  9097. "value": "620921"
  9098. }, {
  9099. "label": "瓜州县",
  9100. "value": "620922"
  9101. }, {
  9102. "label": "肃北蒙古族自治县",
  9103. "value": "620923"
  9104. }, {
  9105. "label": "阿克塞哈萨克族自治县",
  9106. "value": "620924"
  9107. }, {
  9108. "label": "玉门市",
  9109. "value": "620981"
  9110. }, {
  9111. "label": "敦煌市",
  9112. "value": "620982"
  9113. }],
  9114. [{
  9115. "label": "市辖区",
  9116. "value": "621001"
  9117. }, {
  9118. "label": "西峰区",
  9119. "value": "621002"
  9120. }, {
  9121. "label": "庆城县",
  9122. "value": "621021"
  9123. }, {
  9124. "label": "环县",
  9125. "value": "621022"
  9126. }, {
  9127. "label": "华池县",
  9128. "value": "621023"
  9129. }, {
  9130. "label": "合水县",
  9131. "value": "621024"
  9132. }, {
  9133. "label": "正宁县",
  9134. "value": "621025"
  9135. }, {
  9136. "label": "宁县",
  9137. "value": "621026"
  9138. }, {
  9139. "label": "镇原县",
  9140. "value": "621027"
  9141. }],
  9142. [{
  9143. "label": "市辖区",
  9144. "value": "621101"
  9145. }, {
  9146. "label": "安定区",
  9147. "value": "621102"
  9148. }, {
  9149. "label": "通渭县",
  9150. "value": "621121"
  9151. }, {
  9152. "label": "陇西县",
  9153. "value": "621122"
  9154. }, {
  9155. "label": "渭源县",
  9156. "value": "621123"
  9157. }, {
  9158. "label": "临洮县",
  9159. "value": "621124"
  9160. }, {
  9161. "label": "漳县",
  9162. "value": "621125"
  9163. }, {
  9164. "label": "岷县",
  9165. "value": "621126"
  9166. }],
  9167. [{
  9168. "label": "市辖区",
  9169. "value": "621201"
  9170. }, {
  9171. "label": "武都区",
  9172. "value": "621202"
  9173. }, {
  9174. "label": "成县",
  9175. "value": "621221"
  9176. }, {
  9177. "label": "文县",
  9178. "value": "621222"
  9179. }, {
  9180. "label": "宕昌县",
  9181. "value": "621223"
  9182. }, {
  9183. "label": "康县",
  9184. "value": "621224"
  9185. }, {
  9186. "label": "西和县",
  9187. "value": "621225"
  9188. }, {
  9189. "label": "礼县",
  9190. "value": "621226"
  9191. }, {
  9192. "label": "徽县",
  9193. "value": "621227"
  9194. }, {
  9195. "label": "两当县",
  9196. "value": "621228"
  9197. }],
  9198. [{
  9199. "label": "市辖区",
  9200. "value": "622901"
  9201. }, {
  9202. "label": "临夏县",
  9203. "value": "622921"
  9204. }, {
  9205. "label": "康乐县",
  9206. "value": "622922"
  9207. }, {
  9208. "label": "永靖县",
  9209. "value": "622923"
  9210. }, {
  9211. "label": "广河县",
  9212. "value": "622924"
  9213. }, {
  9214. "label": "和政县",
  9215. "value": "622925"
  9216. }, {
  9217. "label": "东乡族自治县",
  9218. "value": "622926"
  9219. }, {
  9220. "label": "积石山保安族东乡族撒拉族自治县",
  9221. "value": "622927"
  9222. }],
  9223. [{
  9224. "label": "市辖区",
  9225. "value": "623001"
  9226. }, {
  9227. "label": "临潭县",
  9228. "value": "623021"
  9229. }, {
  9230. "label": "卓尼县",
  9231. "value": "623022"
  9232. }, {
  9233. "label": "舟曲县",
  9234. "value": "623023"
  9235. }, {
  9236. "label": "迭部县",
  9237. "value": "623024"
  9238. }, {
  9239. "label": "玛曲县",
  9240. "value": "623025"
  9241. }, {
  9242. "label": "碌曲县",
  9243. "value": "623026"
  9244. }, {
  9245. "label": "夏河县",
  9246. "value": "623027"
  9247. }]
  9248. ],
  9249. [
  9250. [{
  9251. "label": "市辖区",
  9252. "value": "630101"
  9253. }, {
  9254. "label": "城东区",
  9255. "value": "630102"
  9256. }, {
  9257. "label": "城中区",
  9258. "value": "630103"
  9259. }, {
  9260. "label": "城西区",
  9261. "value": "630104"
  9262. }, {
  9263. "label": "城北区",
  9264. "value": "630105"
  9265. }, {
  9266. "label": "大通回族土族自治县",
  9267. "value": "630121"
  9268. }, {
  9269. "label": "湟中县",
  9270. "value": "630122"
  9271. }, {
  9272. "label": "湟源县",
  9273. "value": "630123"
  9274. }],
  9275. [{
  9276. "label": "乐都区",
  9277. "value": "630202"
  9278. }, {
  9279. "label": "平安区",
  9280. "value": "630203"
  9281. }, {
  9282. "label": "民和回族土族自治县",
  9283. "value": "630222"
  9284. }, {
  9285. "label": "互助土族自治县",
  9286. "value": "630223"
  9287. }, {
  9288. "label": "化隆回族自治县",
  9289. "value": "630224"
  9290. }, {
  9291. "label": "循化撒拉族自治县",
  9292. "value": "630225"
  9293. }],
  9294. [{
  9295. "label": "门源回族自治县",
  9296. "value": "632221"
  9297. }, {
  9298. "label": "祁连县",
  9299. "value": "632222"
  9300. }, {
  9301. "label": "海晏县",
  9302. "value": "632223"
  9303. }, {
  9304. "label": "刚察县",
  9305. "value": "632224"
  9306. }],
  9307. [{
  9308. "label": "同仁县",
  9309. "value": "632321"
  9310. }, {
  9311. "label": "尖扎县",
  9312. "value": "632322"
  9313. }, {
  9314. "label": "泽库县",
  9315. "value": "632323"
  9316. }, {
  9317. "label": "河南蒙古族自治县",
  9318. "value": "632324"
  9319. }],
  9320. [{
  9321. "label": "共和县",
  9322. "value": "632521"
  9323. }, {
  9324. "label": "同德县",
  9325. "value": "632522"
  9326. }, {
  9327. "label": "贵德县",
  9328. "value": "632523"
  9329. }, {
  9330. "label": "兴海县",
  9331. "value": "632524"
  9332. }, {
  9333. "label": "贵南县",
  9334. "value": "632525"
  9335. }],
  9336. [{
  9337. "label": "玛沁县",
  9338. "value": "632621"
  9339. }, {
  9340. "label": "班玛县",
  9341. "value": "632622"
  9342. }, {
  9343. "label": "甘德县",
  9344. "value": "632623"
  9345. }, {
  9346. "label": "达日县",
  9347. "value": "632624"
  9348. }, {
  9349. "label": "久治县",
  9350. "value": "632625"
  9351. }, {
  9352. "label": "玛多县",
  9353. "value": "632626"
  9354. }],
  9355. [{
  9356. "label": "市辖区",
  9357. "value": "632701"
  9358. }, {
  9359. "label": "杂多县",
  9360. "value": "632722"
  9361. }, {
  9362. "label": "称多县",
  9363. "value": "632723"
  9364. }, {
  9365. "label": "治多县",
  9366. "value": "632724"
  9367. }, {
  9368. "label": "囊谦县",
  9369. "value": "632725"
  9370. }, {
  9371. "label": "曲麻莱县",
  9372. "value": "632726"
  9373. }],
  9374. [{
  9375. "label": "市辖区",
  9376. "value": "632801"
  9377. }, {
  9378. "label": "德令哈市",
  9379. "value": "632802"
  9380. }, {
  9381. "label": "乌兰县",
  9382. "value": "632821"
  9383. }, {
  9384. "label": "都兰县",
  9385. "value": "632822"
  9386. }, {
  9387. "label": "天峻县",
  9388. "value": "632823"
  9389. }]
  9390. ],
  9391. [
  9392. [{
  9393. "label": "市辖区",
  9394. "value": "640101"
  9395. }, {
  9396. "label": "兴庆区",
  9397. "value": "640104"
  9398. }, {
  9399. "label": "西夏区",
  9400. "value": "640105"
  9401. }, {
  9402. "label": "金凤区",
  9403. "value": "640106"
  9404. }, {
  9405. "label": "永宁县",
  9406. "value": "640121"
  9407. }, {
  9408. "label": "贺兰县",
  9409. "value": "640122"
  9410. }, {
  9411. "label": "灵武市",
  9412. "value": "640181"
  9413. }],
  9414. [{
  9415. "label": "市辖区",
  9416. "value": "640201"
  9417. }, {
  9418. "label": "大武口区",
  9419. "value": "640202"
  9420. }, {
  9421. "label": "惠农区",
  9422. "value": "640205"
  9423. }, {
  9424. "label": "平罗县",
  9425. "value": "640221"
  9426. }],
  9427. [{
  9428. "label": "市辖区",
  9429. "value": "640301"
  9430. }, {
  9431. "label": "利通区",
  9432. "value": "640302"
  9433. }, {
  9434. "label": "红寺堡区",
  9435. "value": "640303"
  9436. }, {
  9437. "label": "盐池县",
  9438. "value": "640323"
  9439. }, {
  9440. "label": "同心县",
  9441. "value": "640324"
  9442. }, {
  9443. "label": "青铜峡市",
  9444. "value": "640381"
  9445. }],
  9446. [{
  9447. "label": "市辖区",
  9448. "value": "640401"
  9449. }, {
  9450. "label": "原州区",
  9451. "value": "640402"
  9452. }, {
  9453. "label": "西吉县",
  9454. "value": "640422"
  9455. }, {
  9456. "label": "隆德县",
  9457. "value": "640423"
  9458. }, {
  9459. "label": "泾源县",
  9460. "value": "640424"
  9461. }, {
  9462. "label": "彭阳县",
  9463. "value": "640425"
  9464. }],
  9465. [{
  9466. "label": "市辖区",
  9467. "value": "640501"
  9468. }, {
  9469. "label": "沙坡头区",
  9470. "value": "640502"
  9471. }, {
  9472. "label": "中宁县",
  9473. "value": "640521"
  9474. }, {
  9475. "label": "海原县",
  9476. "value": "640522"
  9477. }]
  9478. ],
  9479. [
  9480. [{
  9481. "label": "市辖区",
  9482. "value": "650101"
  9483. }, {
  9484. "label": "天山区",
  9485. "value": "650102"
  9486. }, {
  9487. "label": "沙依巴克区",
  9488. "value": "650103"
  9489. }, {
  9490. "label": "新市区",
  9491. "value": "650104"
  9492. }, {
  9493. "label": "水磨沟区",
  9494. "value": "650105"
  9495. }, {
  9496. "label": "头屯河区",
  9497. "value": "650106"
  9498. }, {
  9499. "label": "达坂城区",
  9500. "value": "650107"
  9501. }, {
  9502. "label": "米东区",
  9503. "value": "650109"
  9504. }, {
  9505. "label": "乌鲁木齐县",
  9506. "value": "650121"
  9507. }],
  9508. [{
  9509. "label": "市辖区",
  9510. "value": "650201"
  9511. }, {
  9512. "label": "独山子区",
  9513. "value": "650202"
  9514. }, {
  9515. "label": "克拉玛依区",
  9516. "value": "650203"
  9517. }, {
  9518. "label": "白碱滩区",
  9519. "value": "650204"
  9520. }, {
  9521. "label": "乌尔禾区",
  9522. "value": "650205"
  9523. }],
  9524. [{
  9525. "label": "高昌区",
  9526. "value": "650402"
  9527. }, {
  9528. "label": "鄯善县",
  9529. "value": "650421"
  9530. }, {
  9531. "label": "托克逊县",
  9532. "value": "650422"
  9533. }],
  9534. [{
  9535. "label": "伊州区",
  9536. "value": "650502"
  9537. }, {
  9538. "label": "巴里坤哈萨克自治县",
  9539. "value": "650521"
  9540. }, {
  9541. "label": "伊吾县",
  9542. "value": "650522"
  9543. }],
  9544. [{
  9545. "label": "市辖区",
  9546. "value": "652301"
  9547. }, {
  9548. "label": "阜康市",
  9549. "value": "652302"
  9550. }, {
  9551. "label": "呼图壁县",
  9552. "value": "652323"
  9553. }, {
  9554. "label": "玛纳斯县",
  9555. "value": "652324"
  9556. }, {
  9557. "label": "奇台县",
  9558. "value": "652325"
  9559. }, {
  9560. "label": "吉木萨尔县",
  9561. "value": "652327"
  9562. }, {
  9563. "label": "木垒哈萨克自治县",
  9564. "value": "652328"
  9565. }],
  9566. [{
  9567. "label": "市辖区",
  9568. "value": "652701"
  9569. }, {
  9570. "label": "阿拉山口市",
  9571. "value": "652702"
  9572. }, {
  9573. "label": "精河县",
  9574. "value": "652722"
  9575. }, {
  9576. "label": "温泉县",
  9577. "value": "652723"
  9578. }],
  9579. [{
  9580. "label": "市辖区",
  9581. "value": "652801"
  9582. }, {
  9583. "label": "轮台县",
  9584. "value": "652822"
  9585. }, {
  9586. "label": "尉犁县",
  9587. "value": "652823"
  9588. }, {
  9589. "label": "若羌县",
  9590. "value": "652824"
  9591. }, {
  9592. "label": "且末县",
  9593. "value": "652825"
  9594. }, {
  9595. "label": "焉耆回族自治县",
  9596. "value": "652826"
  9597. }, {
  9598. "label": "和静县",
  9599. "value": "652827"
  9600. }, {
  9601. "label": "和硕县",
  9602. "value": "652828"
  9603. }, {
  9604. "label": "博湖县",
  9605. "value": "652829"
  9606. }],
  9607. [{
  9608. "label": "市辖区",
  9609. "value": "652901"
  9610. }, {
  9611. "label": "温宿县",
  9612. "value": "652922"
  9613. }, {
  9614. "label": "库车县",
  9615. "value": "652923"
  9616. }, {
  9617. "label": "沙雅县",
  9618. "value": "652924"
  9619. }, {
  9620. "label": "新和县",
  9621. "value": "652925"
  9622. }, {
  9623. "label": "拜城县",
  9624. "value": "652926"
  9625. }, {
  9626. "label": "乌什县",
  9627. "value": "652927"
  9628. }, {
  9629. "label": "阿瓦提县",
  9630. "value": "652928"
  9631. }, {
  9632. "label": "柯坪县",
  9633. "value": "652929"
  9634. }],
  9635. [{
  9636. "label": "市辖区",
  9637. "value": "653001"
  9638. }, {
  9639. "label": "阿克陶县",
  9640. "value": "653022"
  9641. }, {
  9642. "label": "阿合奇县",
  9643. "value": "653023"
  9644. }, {
  9645. "label": "乌恰县",
  9646. "value": "653024"
  9647. }],
  9648. [{
  9649. "label": "市辖区",
  9650. "value": "653101"
  9651. }, {
  9652. "label": "疏附县",
  9653. "value": "653121"
  9654. }, {
  9655. "label": "疏勒县",
  9656. "value": "653122"
  9657. }, {
  9658. "label": "英吉沙县",
  9659. "value": "653123"
  9660. }, {
  9661. "label": "泽普县",
  9662. "value": "653124"
  9663. }, {
  9664. "label": "莎车县",
  9665. "value": "653125"
  9666. }, {
  9667. "label": "叶城县",
  9668. "value": "653126"
  9669. }, {
  9670. "label": "麦盖提县",
  9671. "value": "653127"
  9672. }, {
  9673. "label": "岳普湖县",
  9674. "value": "653128"
  9675. }, {
  9676. "label": "伽师县",
  9677. "value": "653129"
  9678. }, {
  9679. "label": "巴楚县",
  9680. "value": "653130"
  9681. }, {
  9682. "label": "塔什库尔干塔吉克自治县",
  9683. "value": "653131"
  9684. }],
  9685. [{
  9686. "label": "市辖区",
  9687. "value": "653201"
  9688. }, {
  9689. "label": "和田县",
  9690. "value": "653221"
  9691. }, {
  9692. "label": "墨玉县",
  9693. "value": "653222"
  9694. }, {
  9695. "label": "皮山县",
  9696. "value": "653223"
  9697. }, {
  9698. "label": "洛浦县",
  9699. "value": "653224"
  9700. }, {
  9701. "label": "策勒县",
  9702. "value": "653225"
  9703. }, {
  9704. "label": "于田县",
  9705. "value": "653226"
  9706. }, {
  9707. "label": "民丰县",
  9708. "value": "653227"
  9709. }],
  9710. [{
  9711. "label": "伊宁市",
  9712. "value": "654002"
  9713. }, {
  9714. "label": "奎屯市",
  9715. "value": "654003"
  9716. }, {
  9717. "label": "霍尔果斯市",
  9718. "value": "654004"
  9719. }, {
  9720. "label": "伊宁县",
  9721. "value": "654021"
  9722. }, {
  9723. "label": "察布查尔锡伯自治县",
  9724. "value": "654022"
  9725. }, {
  9726. "label": "霍城县",
  9727. "value": "654023"
  9728. }, {
  9729. "label": "巩留县",
  9730. "value": "654024"
  9731. }, {
  9732. "label": "新源县",
  9733. "value": "654025"
  9734. }, {
  9735. "label": "昭苏县",
  9736. "value": "654026"
  9737. }, {
  9738. "label": "特克斯县",
  9739. "value": "654027"
  9740. }, {
  9741. "label": "尼勒克县",
  9742. "value": "654028"
  9743. }],
  9744. [{
  9745. "label": "市辖区",
  9746. "value": "654201"
  9747. }, {
  9748. "label": "乌苏市",
  9749. "value": "654202"
  9750. }, {
  9751. "label": "额敏县",
  9752. "value": "654221"
  9753. }, {
  9754. "label": "沙湾县",
  9755. "value": "654223"
  9756. }, {
  9757. "label": "托里县",
  9758. "value": "654224"
  9759. }, {
  9760. "label": "裕民县",
  9761. "value": "654225"
  9762. }, {
  9763. "label": "和布克赛尔蒙古自治县",
  9764. "value": "654226"
  9765. }],
  9766. [{
  9767. "label": "市辖区",
  9768. "value": "654301"
  9769. }, {
  9770. "label": "布尔津县",
  9771. "value": "654321"
  9772. }, {
  9773. "label": "富蕴县",
  9774. "value": "654322"
  9775. }, {
  9776. "label": "福海县",
  9777. "value": "654323"
  9778. }, {
  9779. "label": "哈巴河县",
  9780. "value": "654324"
  9781. }, {
  9782. "label": "青河县",
  9783. "value": "654325"
  9784. }, {
  9785. "label": "吉木乃县",
  9786. "value": "654326"
  9787. }],
  9788. [{
  9789. "label": "市辖区",
  9790. "value": "659001"
  9791. }, {
  9792. "label": "阿拉尔市",
  9793. "value": "659002"
  9794. }, {
  9795. "label": "图木舒克市",
  9796. "value": "659003"
  9797. }, {
  9798. "label": "五家渠市",
  9799. "value": "659004"
  9800. }, {
  9801. "label": "铁门关市",
  9802. "value": "659006"
  9803. }]
  9804. ]
  9805. ]
  9806. export default areaData;
city.js
复制代码
  1. /* eslint-disable */
  2. var cityData = [
  3. [{
  4. "label": "北京市",
  5. "value": "110100"
  6. }],
  7. [{
  8. "label": "天津市",
  9. "value": "120100"
  10. }],
  11. [{
  12. "label": "石家庄市",
  13. "value": "130100"
  14. }, {
  15. "label": "唐山市",
  16. "value": "130200"
  17. }, {
  18. "label": "秦皇岛市",
  19. "value": "130300"
  20. }, {
  21. "label": "邯郸市",
  22. "value": "130400"
  23. }, {
  24. "label": "邢台市",
  25. "value": "130500"
  26. }, {
  27. "label": "保定市",
  28. "value": "130600"
  29. }, {
  30. "label": "张家口市",
  31. "value": "130700"
  32. }, {
  33. "label": "承德市",
  34. "value": "130800"
  35. }, {
  36. "label": "沧州市",
  37. "value": "130900"
  38. }, {
  39. "label": "廊坊市",
  40. "value": "131000"
  41. }, {
  42. "label": "衡水市",
  43. "value": "131100"
  44. }, {
  45. "label": "省直辖县级行政区划",
  46. "value": "139000"
  47. }],
  48. [{
  49. "label": "太原市",
  50. "value": "140100"
  51. }, {
  52. "label": "大同市",
  53. "value": "140200"
  54. }, {
  55. "label": "阳泉市",
  56. "value": "140300"
  57. }, {
  58. "label": "长治市",
  59. "value": "140400"
  60. }, {
  61. "label": "晋城市",
  62. "value": "140500"
  63. }, {
  64. "label": "朔州市",
  65. "value": "140600"
  66. }, {
  67. "label": "晋中市",
  68. "value": "140700"
  69. }, {
  70. "label": "运城市",
  71. "value": "140800"
  72. }, {
  73. "label": "忻州市",
  74. "value": "140900"
  75. }, {
  76. "label": "临汾市",
  77. "value": "141000"
  78. }, {
  79. "label": "吕梁市",
  80. "value": "141100"
  81. }],
  82. [{
  83. "label": "呼和浩特市",
  84. "value": "150100"
  85. }, {
  86. "label": "包头市",
  87. "value": "150200"
  88. }, {
  89. "label": "乌海市",
  90. "value": "150300"
  91. }, {
  92. "label": "赤峰市",
  93. "value": "150400"
  94. }, {
  95. "label": "通辽市",
  96. "value": "150500"
  97. }, {
  98. "label": "鄂尔多斯市",
  99. "value": "150600"
  100. }, {
  101. "label": "呼伦贝尔市",
  102. "value": "150700"
  103. }, {
  104. "label": "巴彦淖尔市",
  105. "value": "150800"
  106. }, {
  107. "label": "乌兰察布市",
  108. "value": "150900"
  109. }, {
  110. "label": "兴安盟",
  111. "value": "152200"
  112. }, {
  113. "label": "锡林郭勒盟",
  114. "value": "152500"
  115. }, {
  116. "label": "阿拉善盟",
  117. "value": "152900"
  118. }],
  119. [{
  120. "label": "沈阳市",
  121. "value": "210100"
  122. }, {
  123. "label": "大连市",
  124. "value": "210200"
  125. }, {
  126. "label": "鞍山市",
  127. "value": "210300"
  128. }, {
  129. "label": "抚顺市",
  130. "value": "210400"
  131. }, {
  132. "label": "本溪市",
  133. "value": "210500"
  134. }, {
  135. "label": "丹东市",
  136. "value": "210600"
  137. }, {
  138. "label": "锦州市",
  139. "value": "210700"
  140. }, {
  141. "label": "营口市",
  142. "value": "210800"
  143. }, {
  144. "label": "阜新市",
  145. "value": "210900"
  146. }, {
  147. "label": "辽阳市",
  148. "value": "211000"
  149. }, {
  150. "label": "盘锦市",
  151. "value": "211100"
  152. }, {
  153. "label": "铁岭市",
  154. "value": "211200"
  155. }, {
  156. "label": "朝阳市",
  157. "value": "211300"
  158. }, {
  159. "label": "葫芦岛市",
  160. "value": "211400"
  161. }],
  162. [{
  163. "label": "长春市",
  164. "value": "220100"
  165. }, {
  166. "label": "吉林市",
  167. "value": "220200"
  168. }, {
  169. "label": "四平市",
  170. "value": "220300"
  171. }, {
  172. "label": "辽源市",
  173. "value": "220400"
  174. }, {
  175. "label": "通化市",
  176. "value": "220500"
  177. }, {
  178. "label": "白山市",
  179. "value": "220600"
  180. }, {
  181. "label": "松原市",
  182. "value": "220700"
  183. }, {
  184. "label": "白城市",
  185. "value": "220800"
  186. }, {
  187. "label": "延边朝鲜族自治州",
  188. "value": "222400"
  189. }],
  190. [{
  191. "label": "哈尔滨市",
  192. "value": "230100"
  193. }, {
  194. "label": "齐齐哈尔市",
  195. "value": "230200"
  196. }, {
  197. "label": "鸡西市",
  198. "value": "230300"
  199. }, {
  200. "label": "鹤岗市",
  201. "value": "230400"
  202. }, {
  203. "label": "双鸭山市",
  204. "value": "230500"
  205. }, {
  206. "label": "大庆市",
  207. "value": "230600"
  208. }, {
  209. "label": "伊春市",
  210. "value": "230700"
  211. }, {
  212. "label": "佳木斯市",
  213. "value": "230800"
  214. }, {
  215. "label": "七台河市",
  216. "value": "230900"
  217. }, {
  218. "label": "牡丹江市",
  219. "value": "231000"
  220. }, {
  221. "label": "黑河市",
  222. "value": "231100"
  223. }, {
  224. "label": "绥化市",
  225. "value": "231200"
  226. }, {
  227. "label": "大兴安岭地区",
  228. "value": "232700"
  229. }],
  230. [{
  231. "label": "上海市",
  232. "value": "310100"
  233. }],
  234. [{
  235. "label": "南京市",
  236. "value": "320100"
  237. }, {
  238. "label": "无锡市",
  239. "value": "320200"
  240. }, {
  241. "label": "徐州市",
  242. "value": "320300"
  243. }, {
  244. "label": "常州市",
  245. "value": "320400"
  246. }, {
  247. "label": "苏州市",
  248. "value": "320500"
  249. }, {
  250. "label": "南通市",
  251. "value": "320600"
  252. }, {
  253. "label": "连云港市",
  254. "value": "320700"
  255. }, {
  256. "label": "淮安市",
  257. "value": "320800"
  258. }, {
  259. "label": "盐城市",
  260. "value": "320900"
  261. }, {
  262. "label": "扬州市",
  263. "value": "321000"
  264. }, {
  265. "label": "镇江市",
  266. "value": "321100"
  267. }, {
  268. "label": "泰州市",
  269. "value": "321200"
  270. }, {
  271. "label": "宿迁市",
  272. "value": "321300"
  273. }],
  274. [{
  275. "label": "杭州市",
  276. "value": "330100"
  277. }, {
  278. "label": "宁波市",
  279. "value": "330200"
  280. }, {
  281. "label": "温州市",
  282. "value": "330300"
  283. }, {
  284. "label": "嘉兴市",
  285. "value": "330400"
  286. }, {
  287. "label": "湖州市",
  288. "value": "330500"
  289. }, {
  290. "label": "绍兴市",
  291. "value": "330600"
  292. }, {
  293. "label": "金华市",
  294. "value": "330700"
  295. }, {
  296. "label": "衢州市",
  297. "value": "330800"
  298. }, {
  299. "label": "舟山市",
  300. "value": "330900"
  301. }, {
  302. "label": "台州市",
  303. "value": "331000"
  304. }, {
  305. "label": "丽水市",
  306. "value": "331100"
  307. }],
  308. [{
  309. "label": "合肥市",
  310. "value": "340100"
  311. }, {
  312. "label": "芜湖市",
  313. "value": "340200"
  314. }, {
  315. "label": "蚌埠市",
  316. "value": "340300"
  317. }, {
  318. "label": "淮南市",
  319. "value": "340400"
  320. }, {
  321. "label": "马鞍山市",
  322. "value": "340500"
  323. }, {
  324. "label": "淮北市",
  325. "value": "340600"
  326. }, {
  327. "label": "铜陵市",
  328. "value": "340700"
  329. }, {
  330. "label": "安庆市",
  331. "value": "340800"
  332. }, {
  333. "label": "黄山市",
  334. "value": "341000"
  335. }, {
  336. "label": "滁州市",
  337. "value": "341100"
  338. }, {
  339. "label": "阜阳市",
  340. "value": "341200"
  341. }, {
  342. "label": "宿州市",
  343. "value": "341300"
  344. }, {
  345. "label": "六安市",
  346. "value": "341500"
  347. }, {
  348. "label": "亳州市",
  349. "value": "341600"
  350. }, {
  351. "label": "池州市",
  352. "value": "341700"
  353. }, {
  354. "label": "宣城市",
  355. "value": "341800"
  356. }],
  357. [{
  358. "label": "福州市",
  359. "value": "350100"
  360. }, {
  361. "label": "厦门市",
  362. "value": "350200"
  363. }, {
  364. "label": "莆田市",
  365. "value": "350300"
  366. }, {
  367. "label": "三明市",
  368. "value": "350400"
  369. }, {
  370. "label": "泉州市",
  371. "value": "350500"
  372. }, {
  373. "label": "漳州市",
  374. "value": "350600"
  375. }, {
  376. "label": "南平市",
  377. "value": "350700"
  378. }, {
  379. "label": "龙岩市",
  380. "value": "350800"
  381. }, {
  382. "label": "宁德市",
  383. "value": "350900"
  384. }],
  385. [{
  386. "label": "南昌市",
  387. "value": "360100"
  388. }, {
  389. "label": "景德镇市",
  390. "value": "360200"
  391. }, {
  392. "label": "萍乡市",
  393. "value": "360300"
  394. }, {
  395. "label": "九江市",
  396. "value": "360400"
  397. }, {
  398. "label": "新余市",
  399. "value": "360500"
  400. }, {
  401. "label": "鹰潭市",
  402. "value": "360600"
  403. }, {
  404. "label": "赣州市",
  405. "value": "360700"
  406. }, {
  407. "label": "吉安市",
  408. "value": "360800"
  409. }, {
  410. "label": "宜春市",
  411. "value": "360900"
  412. }, {
  413. "label": "抚州市",
  414. "value": "361000"
  415. }, {
  416. "label": "上饶市",
  417. "value": "361100"
  418. }],
  419. [{
  420. "label": "济南市",
  421. "value": "370100"
  422. }, {
  423. "label": "青岛市",
  424. "value": "370200"
  425. }, {
  426. "label": "淄博市",
  427. "value": "370300"
  428. }, {
  429. "label": "枣庄市",
  430. "value": "370400"
  431. }, {
  432. "label": "东营市",
  433. "value": "370500"
  434. }, {
  435. "label": "烟台市",
  436. "value": "370600"
  437. }, {
  438. "label": "潍坊市",
  439. "value": "370700"
  440. }, {
  441. "label": "济宁市",
  442. "value": "370800"
  443. }, {
  444. "label": "泰安市",
  445. "value": "370900"
  446. }, {
  447. "label": "威海市",
  448. "value": "371000"
  449. }, {
  450. "label": "日照市",
  451. "value": "371100"
  452. }, {
  453. "label": "莱芜市",
  454. "value": "371200"
  455. }, {
  456. "label": "临沂市",
  457. "value": "371300"
  458. }, {
  459. "label": "德州市",
  460. "value": "371400"
  461. }, {
  462. "label": "聊城市",
  463. "value": "371500"
  464. }, {
  465. "label": "滨州市",
  466. "value": "371600"
  467. }, {
  468. "label": "菏泽市",
  469. "value": "371700"
  470. }],
  471. [{
  472. "label": "郑州市",
  473. "value": "410100"
  474. }, {
  475. "label": "开封市",
  476. "value": "410200"
  477. }, {
  478. "label": "洛阳市",
  479. "value": "410300"
  480. }, {
  481. "label": "平顶山市",
  482. "value": "410400"
  483. }, {
  484. "label": "安阳市",
  485. "value": "410500"
  486. }, {
  487. "label": "鹤壁市",
  488. "value": "410600"
  489. }, {
  490. "label": "新乡市",
  491. "value": "410700"
  492. }, {
  493. "label": "焦作市",
  494. "value": "410800"
  495. }, {
  496. "label": "濮阳市",
  497. "value": "410900"
  498. }, {
  499. "label": "许昌市",
  500. "value": "411000"
  501. }, {
  502. "label": "漯河市",
  503. "value": "411100"
  504. }, {
  505. "label": "三门峡市",
  506. "value": "411200"
  507. }, {
  508. "label": "南阳市",
  509. "value": "411300"
  510. }, {
  511. "label": "商丘市",
  512. "value": "411400"
  513. }, {
  514. "label": "信阳市",
  515. "value": "411500"
  516. }, {
  517. "label": "周口市",
  518. "value": "411600"
  519. }, {
  520. "label": "驻马店市",
  521. "value": "411700"
  522. }, {
  523. "label": "省直辖县级行政区划",
  524. "value": "419000"
  525. }],
  526. [{
  527. "label": "武汉市",
  528. "value": "420100"
  529. }, {
  530. "label": "黄石市",
  531. "value": "420200"
  532. }, {
  533. "label": "十堰市",
  534. "value": "420300"
  535. }, {
  536. "label": "宜昌市",
  537. "value": "420500"
  538. }, {
  539. "label": "襄阳市",
  540. "value": "420600"
  541. }, {
  542. "label": "鄂州市",
  543. "value": "420700"
  544. }, {
  545. "label": "荆门市",
  546. "value": "420800"
  547. }, {
  548. "label": "孝感市",
  549. "value": "420900"
  550. }, {
  551. "label": "荆州市",
  552. "value": "421000"
  553. }, {
  554. "label": "黄冈市",
  555. "value": "421100"
  556. }, {
  557. "label": "咸宁市",
  558. "value": "421200"
  559. }, {
  560. "label": "随州市",
  561. "value": "421300"
  562. }, {
  563. "label": "恩施土家族苗族自治州",
  564. "value": "422800"
  565. }, {
  566. "label": "省直辖县级行政区划",
  567. "value": "429000"
  568. }],
  569. [{
  570. "label": "长沙市",
  571. "value": "430100"
  572. }, {
  573. "label": "株洲市",
  574. "value": "430200"
  575. }, {
  576. "label": "湘潭市",
  577. "value": "430300"
  578. }, {
  579. "label": "衡阳市",
  580. "value": "430400"
  581. }, {
  582. "label": "邵阳市",
  583. "value": "430500"
  584. }, {
  585. "label": "岳阳市",
  586. "value": "430600"
  587. }, {
  588. "label": "常德市",
  589. "value": "430700"
  590. }, {
  591. "label": "张家界市",
  592. "value": "430800"
  593. }, {
  594. "label": "益阳市",
  595. "value": "430900"
  596. }, {
  597. "label": "郴州市",
  598. "value": "431000"
  599. }, {
  600. "label": "永州市",
  601. "value": "431100"
  602. }, {
  603. "label": "怀化市",
  604. "value": "431200"
  605. }, {
  606. "label": "娄底市",
  607. "value": "431300"
  608. }, {
  609. "label": "湘西土家族苗族自治州",
  610. "value": "433100"
  611. }],
  612. [{
  613. "label": "广州市",
  614. "value": "440100"
  615. }, {
  616. "label": "韶关市",
  617. "value": "440200"
  618. }, {
  619. "label": "深圳市",
  620. "value": "440300"
  621. }, {
  622. "label": "珠海市",
  623. "value": "440400"
  624. }, {
  625. "label": "汕头市",
  626. "value": "440500"
  627. }, {
  628. "label": "佛山市",
  629. "value": "440600"
  630. }, {
  631. "label": "江门市",
  632. "value": "440700"
  633. }, {
  634. "label": "湛江市",
  635. "value": "440800"
  636. }, {
  637. "label": "茂名市",
  638. "value": "440900"
  639. }, {
  640. "label": "肇庆市",
  641. "value": "441200"
  642. }, {
  643. "label": "惠州市",
  644. "value": "441300"
  645. }, {
  646. "label": "梅州市",
  647. "value": "441400"
  648. }, {
  649. "label": "汕尾市",
  650. "value": "441500"
  651. }, {
  652. "label": "河源市",
  653. "value": "441600"
  654. }, {
  655. "label": "阳江市",
  656. "value": "441700"
  657. }, {
  658. "label": "清远市",
  659. "value": "441800"
  660. }, {
  661. "label": "东莞市",
  662. "value": "441900"
  663. }, {
  664. "label": "中山市",
  665. "value": "442000"
  666. }, {
  667. "label": "潮州市",
  668. "value": "445100"
  669. }, {
  670. "label": "揭阳市",
  671. "value": "445200"
  672. }, {
  673. "label": "云浮市",
  674. "value": "445300"
  675. }],
  676. [{
  677. "label": "南宁市",
  678. "value": "450100"
  679. }, {
  680. "label": "柳州市",
  681. "value": "450200"
  682. }, {
  683. "label": "桂林市",
  684. "value": "450300"
  685. }, {
  686. "label": "梧州市",
  687. "value": "450400"
  688. }, {
  689. "label": "北海市",
  690. "value": "450500"
  691. }, {
  692. "label": "防城港市",
  693. "value": "450600"
  694. }, {
  695. "label": "钦州市",
  696. "value": "450700"
  697. }, {
  698. "label": "贵港市",
  699. "value": "450800"
  700. }, {
  701. "label": "玉林市",
  702. "value": "450900"
  703. }, {
  704. "label": "百色市",
  705. "value": "451000"
  706. }, {
  707. "label": "贺州市",
  708. "value": "451100"
  709. }, {
  710. "label": "河池市",
  711. "value": "451200"
  712. }, {
  713. "label": "来宾市",
  714. "value": "451300"
  715. }, {
  716. "label": "崇左市",
  717. "value": "451400"
  718. }],
  719. [{
  720. "label": "海口市",
  721. "value": "460100"
  722. }, {
  723. "label": "三亚市",
  724. "value": "460200"
  725. }, {
  726. "label": "三沙市",
  727. "value": "460300"
  728. }, {
  729. "label": "儋州市",
  730. "value": "460400"
  731. }, {
  732. "label": "省直辖县级行政区划",
  733. "value": "469000"
  734. }],
  735. [{
  736. "label": "重庆市",
  737. "value": "500100"
  738. }, {
  739. "label": "县",
  740. "value": "500200"
  741. }],
  742. [{
  743. "label": "成都市",
  744. "value": "510100"
  745. }, {
  746. "label": "自贡市",
  747. "value": "510300"
  748. }, {
  749. "label": "攀枝花市",
  750. "value": "510400"
  751. }, {
  752. "label": "泸州市",
  753. "value": "510500"
  754. }, {
  755. "label": "德阳市",
  756. "value": "510600"
  757. }, {
  758. "label": "绵阳市",
  759. "value": "510700"
  760. }, {
  761. "label": "广元市",
  762. "value": "510800"
  763. }, {
  764. "label": "遂宁市",
  765. "value": "510900"
  766. }, {
  767. "label": "内江市",
  768. "value": "511000"
  769. }, {
  770. "label": "乐山市",
  771. "value": "511100"
  772. }, {
  773. "label": "南充市",
  774. "value": "511300"
  775. }, {
  776. "label": "眉山市",
  777. "value": "511400"
  778. }, {
  779. "label": "宜宾市",
  780. "value": "511500"
  781. }, {
  782. "label": "广安市",
  783. "value": "511600"
  784. }, {
  785. "label": "达州市",
  786. "value": "511700"
  787. }, {
  788. "label": "雅安市",
  789. "value": "511800"
  790. }, {
  791. "label": "巴中市",
  792. "value": "511900"
  793. }, {
  794. "label": "资阳市",
  795. "value": "512000"
  796. }, {
  797. "label": "阿坝藏族羌族自治州",
  798. "value": "513200"
  799. }, {
  800. "label": "甘孜藏族自治州",
  801. "value": "513300"
  802. }, {
  803. "label": "凉山彝族自治州",
  804. "value": "513400"
  805. }],
  806. [{
  807. "label": "贵阳市",
  808. "value": "520100"
  809. }, {
  810. "label": "六盘水市",
  811. "value": "520200"
  812. }, {
  813. "label": "遵义市",
  814. "value": "520300"
  815. }, {
  816. "label": "安顺市",
  817. "value": "520400"
  818. }, {
  819. "label": "毕节市",
  820. "value": "520500"
  821. }, {
  822. "label": "铜仁市",
  823. "value": "520600"
  824. }, {
  825. "label": "黔西南布依族苗族自治州",
  826. "value": "522300"
  827. }, {
  828. "label": "黔东南苗族侗族自治州",
  829. "value": "522600"
  830. }, {
  831. "label": "黔南布依族苗族自治州",
  832. "value": "522700"
  833. }],
  834. [{
  835. "label": "昆明市",
  836. "value": "530100"
  837. }, {
  838. "label": "曲靖市",
  839. "value": "530300"
  840. }, {
  841. "label": "玉溪市",
  842. "value": "530400"
  843. }, {
  844. "label": "保山市",
  845. "value": "530500"
  846. }, {
  847. "label": "昭通市",
  848. "value": "530600"
  849. }, {
  850. "label": "丽江市",
  851. "value": "530700"
  852. }, {
  853. "label": "普洱市",
  854. "value": "530800"
  855. }, {
  856. "label": "临沧市",
  857. "value": "530900"
  858. }, {
  859. "label": "楚雄彝族自治州",
  860. "value": "532300"
  861. }, {
  862. "label": "红河哈尼族彝族自治州",
  863. "value": "532500"
  864. }, {
  865. "label": "文山壮族苗族自治州",
  866. "value": "532600"
  867. }, {
  868. "label": "西双版纳傣族自治州",
  869. "value": "532800"
  870. }, {
  871. "label": "大理白族自治州",
  872. "value": "532900"
  873. }, {
  874. "label": "德宏傣族景颇族自治州",
  875. "value": "533100"
  876. }, {
  877. "label": "怒江傈僳族自治州",
  878. "value": "533300"
  879. }, {
  880. "label": "迪庆藏族自治州",
  881. "value": "533400"
  882. }],
  883. [{
  884. "label": "拉萨市",
  885. "value": "540100"
  886. }, {
  887. "label": "日喀则市",
  888. "value": "540200"
  889. }, {
  890. "label": "昌都市",
  891. "value": "540300"
  892. }, {
  893. "label": "林芝市",
  894. "value": "540400"
  895. }, {
  896. "label": "山南市",
  897. "value": "540500"
  898. }, {
  899. "label": "那曲地区",
  900. "value": "542400"
  901. }, {
  902. "label": "阿里地区",
  903. "value": "542500"
  904. }],
  905. [{
  906. "label": "西安市",
  907. "value": "610100"
  908. }, {
  909. "label": "铜川市",
  910. "value": "610200"
  911. }, {
  912. "label": "宝鸡市",
  913. "value": "610300"
  914. }, {
  915. "label": "咸阳市",
  916. "value": "610400"
  917. }, {
  918. "label": "渭南市",
  919. "value": "610500"
  920. }, {
  921. "label": "延安市",
  922. "value": "610600"
  923. }, {
  924. "label": "汉中市",
  925. "value": "610700"
  926. }, {
  927. "label": "榆林市",
  928. "value": "610800"
  929. }, {
  930. "label": "安康市",
  931. "value": "610900"
  932. }, {
  933. "label": "商洛市",
  934. "value": "611000"
  935. }],
  936. [{
  937. "label": "兰州市",
  938. "value": "620100"
  939. }, {
  940. "label": "嘉峪关市",
  941. "value": "620200"
  942. }, {
  943. "label": "金昌市",
  944. "value": "620300"
  945. }, {
  946. "label": "白银市",
  947. "value": "620400"
  948. }, {
  949. "label": "天水市",
  950. "value": "620500"
  951. }, {
  952. "label": "武威市",
  953. "value": "620600"
  954. }, {
  955. "label": "张掖市",
  956. "value": "620700"
  957. }, {
  958. "label": "平凉市",
  959. "value": "620800"
  960. }, {
  961. "label": "酒泉市",
  962. "value": "620900"
  963. }, {
  964. "label": "庆阳市",
  965. "value": "621000"
  966. }, {
  967. "label": "定西市",
  968. "value": "621100"
  969. }, {
  970. "label": "陇南市",
  971. "value": "621200"
  972. }, {
  973. "label": "临夏回族自治州",
  974. "value": "622900"
  975. }, {
  976. "label": "甘南藏族自治州",
  977. "value": "623000"
  978. }],
  979. [{
  980. "label": "西宁市",
  981. "value": "630100"
  982. }, {
  983. "label": "海东市",
  984. "value": "630200"
  985. }, {
  986. "label": "海北藏族自治州",
  987. "value": "632200"
  988. }, {
  989. "label": "黄南藏族自治州",
  990. "value": "632300"
  991. }, {
  992. "label": "海南藏族自治州",
  993. "value": "632500"
  994. }, {
  995. "label": "果洛藏族自治州",
  996. "value": "632600"
  997. }, {
  998. "label": "玉树藏族自治州",
  999. "value": "632700"
  1000. }, {
  1001. "label": "海西蒙古族藏族自治州",
  1002. "value": "632800"
  1003. }],
  1004. [{
  1005. "label": "银川市",
  1006. "value": "640100"
  1007. }, {
  1008. "label": "石嘴山市",
  1009. "value": "640200"
  1010. }, {
  1011. "label": "吴忠市",
  1012. "value": "640300"
  1013. }, {
  1014. "label": "固原市",
  1015. "value": "640400"
  1016. }, {
  1017. "label": "中卫市",
  1018. "value": "640500"
  1019. }],
  1020. [{
  1021. "label": "乌鲁木齐市",
  1022. "value": "650100"
  1023. }, {
  1024. "label": "克拉玛依市",
  1025. "value": "650200"
  1026. }, {
  1027. "label": "吐鲁番市",
  1028. "value": "650400"
  1029. }, {
  1030. "label": "哈密市",
  1031. "value": "650500"
  1032. }, {
  1033. "label": "昌吉回族自治州",
  1034. "value": "652300"
  1035. }, {
  1036. "label": "博尔塔拉蒙古自治州",
  1037. "value": "652700"
  1038. }, {
  1039. "label": "巴音郭楞蒙古自治州",
  1040. "value": "652800"
  1041. }, {
  1042. "label": "阿克苏地区",
  1043. "value": "652900"
  1044. }, {
  1045. "label": "克孜勒苏柯尔克孜自治州",
  1046. "value": "653000"
  1047. }, {
  1048. "label": "喀什地区",
  1049. "value": "653100"
  1050. }, {
  1051. "label": "和田地区",
  1052. "value": "653200"
  1053. }, {
  1054. "label": "伊犁哈萨克自治州",
  1055. "value": "654000"
  1056. }, {
  1057. "label": "塔城地区",
  1058. "value": "654200"
  1059. }, {
  1060. "label": "阿勒泰地区",
  1061. "value": "654300"
  1062. }, {
  1063. "label": "自治区直辖县级行政区划",
  1064. "value": "659000"
  1065. }]
  1066. ]
  1067. export default cityData;
province.js
复制代码
  1. /* eslint-disable */
  2. var provinceData = [{
  3. "label": "北京市",
  4. "value": "110000"
  5. }, {
  6. "label": "天津市",
  7. "value": "120000"
  8. }, {
  9. "label": "河北省",
  10. "value": "130000"
  11. }, {
  12. "label": "山西省",
  13. "value": "140000"
  14. }, {
  15. "label": "内蒙古自治区",
  16. "value": "150000"
  17. }, {
  18. "label": "辽宁省",
  19. "value": "210000"
  20. }, {
  21. "label": "吉林省",
  22. "value": "220000"
  23. }, {
  24. "label": "黑龙江省",
  25. "value": "230000"
  26. }, {
  27. "label": "上海市",
  28. "value": "310000"
  29. }, {
  30. "label": "江苏省",
  31. "value": "320000"
  32. }, {
  33. "label": "浙江省",
  34. "value": "330000"
  35. }, {
  36. "label": "安徽省",
  37. "value": "340000"
  38. }, {
  39. "label": "福建省",
  40. "value": "350000"
  41. }, {
  42. "label": "江西省",
  43. "value": "360000"
  44. }, {
  45. "label": "山东省",
  46. "value": "370000"
  47. }, {
  48. "label": "河南省",
  49. "value": "410000"
  50. }, {
  51. "label": "湖北省",
  52. "value": "420000"
  53. }, {
  54. "label": "湖南省",
  55. "value": "430000"
  56. }, {
  57. "label": "广东省",
  58. "value": "440000"
  59. }, {
  60. "label": "广西壮族自治区",
  61. "value": "450000"
  62. }, {
  63. "label": "海南省",
  64. "value": "460000"
  65. }, {
  66. "label": "重庆市",
  67. "value": "500000"
  68. }, {
  69. "label": "四川省",
  70. "value": "510000"
  71. }, {
  72. "label": "贵州省",
  73. "value": "520000"
  74. }, {
  75. "label": "云南省",
  76. "value": "530000"
  77. }, {
  78. "label": "西藏自治区",
  79. "value": "540000"
  80. }, {
  81. "label": "陕西省",
  82. "value": "610000"
  83. }, {
  84. "label": "甘肃省",
  85. "value": "620000"
  86. }, {
  87. "label": "青海省",
  88. "value": "630000"
  89. }, {
  90. "label": "宁夏回族自治区",
  91. "value": "640000"
  92. }, {
  93. "label": "新疆维吾尔自治区",
  94. "value": "650000"
  95. }, {
  96. "label": "台湾省",
  97. "value": "710000"
  98. }, {
  99. "label": "香港特别行政区",
  100. "value": "810000"
  101. }, {
  102. "label": "澳门特别行政区",
  103. "value": "820000"
  104. }]
  105. export default provinceData;
mpvueCityPicker.vue
复制代码
  1. <template>
  2. <div class="mpvue-picker">
  3. <div :class="{'pickerMask':showPicker}" @click="maskClick" catchtouchmove="true"></div>
  4. <div class="mpvue-picker-content " :class="{'mpvue-picker-view-show':showPicker}">
  5. <div class="mpvue-picker__hd" catchtouchmove="true">
  6. <div class="mpvue-picker__action" @click="pickerCancel">取消</div>
  7. <div class="mpvue-picker__action" :style="{color:themeColor}" @click="pickerConfirm">确定</div>
  8. </div>
  9. <picker-view indicator-style="height: 40px;" class="mpvue-picker-view" :value="pickerValue" @change="pickerChange">
  10. <block>
  11. <picker-view-column>
  12. <div class="picker-item" v-for="(item,index) in provinceDataList" :key="index">{{item.label}}</div>
  13. </picker-view-column>
  14. <picker-view-column>
  15. <div class="picker-item" v-for="(item,index) in cityDataList" :key="index">{{item.label}}</div>
  16. </picker-view-column>
  17. <picker-view-column>
  18. <div class="picker-item" v-for="(item,index) in areaDataList" :key="index">{{item.label}}</div>
  19. </picker-view-column>
  20. </block>
  21. </picker-view>
  22. </div>
  23. </div>
  24. </template>
  25. <script>
  26. import provinceData from './city-data/province.js';
  27. import cityData from './city-data/city.js';
  28. import areaData from './city-data/area.js';
  29. export default {
  30. data() {
  31. return {
  32. pickerValue: [0, 0, 0],
  33. provinceDataList: [],
  34. cityDataList: [],
  35. areaDataList: [],
  36. /* 是否显示控件 */
  37. showPicker: false,
  38. };
  39. },
  40. created() {
  41. this.init()
  42. },
  43. props: {
  44. /* 默认值 */
  45. pickerValueDefault: {
  46. type: Array,
  47. default(){
  48. return [0, 0, 0]
  49. }
  50. },
  51. /* 主题色 */
  52. themeColor: String
  53. },
  54. watch:{
  55. pickerValueDefault(){
  56. this.init();
  57. }
  58. },
  59. methods: {
  60. init() {
  61. this.handPickValueDefault(); // 对 pickerValueDefault 做兼容处理
  62. this.provinceDataList = provinceData;
  63. this.cityDataList = cityData[this.pickerValueDefault[0]];
  64. this.areaDataList = areaData[this.pickerValueDefault[0]][this.pickerValueDefault[1]];
  65. this.pickerValue = this.pickerValueDefault;
  66. },
  67. show() {
  68. setTimeout(() => {
  69. this.showPicker = true;
  70. }, 0);
  71. },
  72. maskClick() {
  73. this.pickerCancel();
  74. },
  75. pickerCancel() {
  76. this.showPicker = false;
  77. this._$emit('onCancel');
  78. },
  79. pickerConfirm(e) {
  80. this.showPicker = false;
  81. this._$emit('onConfirm');
  82. },
  83. showPickerView() {
  84. this.showPicker = true;
  85. },
  86. handPickValueDefault() {
  87. if (this.pickerValueDefault !== [0, 0, 0]) {
  88. if (this.pickerValueDefault[0] > provinceData.length - 1) {
  89. this.pickerValueDefault[0] = provinceData.length - 1;
  90. }
  91. if (this.pickerValueDefault[1] > cityData[this.pickerValueDefault[0]].length - 1) {
  92. this.pickerValueDefault[1] = cityData[this.pickerValueDefault[0]].length - 1;
  93. }
  94. if (this.pickerValueDefault[2] > areaData[this.pickerValueDefault[0]][this.pickerValueDefault[1]].length - 1) {
  95. this.pickerValueDefault[2] = areaData[this.pickerValueDefault[0]][this.pickerValueDefault[1]].length - 1;
  96. }
  97. }
  98. },
  99. pickerChange(e) {
  100. let changePickerValue = e.mp.detail.value;
  101. if (this.pickerValue[0] !== changePickerValue[0]) {
  102. // 第一级发生滚动
  103. this.cityDataList = cityData[changePickerValue[0]];
  104. this.areaDataList = areaData[changePickerValue[0]][0];
  105. changePickerValue[1] = 0;
  106. changePickerValue[2] = 0;
  107. } else if (this.pickerValue[1] !== changePickerValue[1]) {
  108. // 第二级滚动
  109. this.areaDataList =
  110. areaData[changePickerValue[0]][changePickerValue[1]];
  111. changePickerValue[2] = 0;
  112. }
  113. this.pickerValue = changePickerValue;
  114. this._$emit('onChange');
  115. },
  116. _$emit(emitName) {
  117. let pickObj = {
  118. label: this._getLabel(),
  119. value: this.pickerValue,
  120. cityCode: this._getCityCode()
  121. };
  122. this.$emit(emitName, pickObj);
  123. },
  124. _getLabel() {
  125. let pcikerLabel =
  126. this.provinceDataList[this.pickerValue[0]].label +
  127. '-' +
  128. this.cityDataList[this.pickerValue[1]].label +
  129. '-' +
  130. this.areaDataList[this.pickerValue[2]].label;
  131. return pcikerLabel;
  132. },
  133. _getCityCode() {
  134. return this.areaDataList[this.pickerValue[2]].value;
  135. }
  136. }
  137. };
  138. </script>
  139. <style>
  140. .pickerMask {
  141. position: fixed;
  142. z-index: 1000;
  143. top: 0;
  144. right: 0;
  145. left: 0;
  146. bottom: 0;
  147. background: rgba(0, 0, 0, 0.6);
  148. }
  149. .mpvue-picker-content {
  150. position: fixed;
  151. bottom: 0;
  152. left: 0;
  153. width: 100%;
  154. transition: all 0.3s ease;
  155. transform: translateY(100%);
  156. z-index: 3000;
  157. }
  158. .mpvue-picker-view-show {
  159. transform: translateY(0);
  160. }
  161. .mpvue-picker__hd {
  162. display: flex;
  163. padding: 9px 15px;
  164. background-color: #fff;
  165. position: relative;
  166. text-align: center;
  167. font-size: 17px;
  168. }
  169. .mpvue-picker__hd:after {
  170. content: ' ';
  171. position: absolute;
  172. left: 0;
  173. bottom: 0;
  174. right: 0;
  175. height: 1px;
  176. border-bottom: 1px solid #e5e5e5;
  177. color: #e5e5e5;
  178. transform-origin: 0 100%;
  179. transform: scaleY(0.5);
  180. }
  181. .mpvue-picker__action {
  182. display: block;
  183. flex: 1;
  184. color: #1aad19;
  185. }
  186. .mpvue-picker__action:first-child {
  187. text-align: left;
  188. color: #888;
  189. }
  190. .mpvue-picker__action:last-child {
  191. text-align: right;
  192. }
  193. .picker-item {
  194. text-align: center;
  195. line-height: 40px;
  196. text-overflow: ellipsis;
  197. white-space: nowrap;
  198. font-size: 16px;
  199. }
  200. .mpvue-picker-view {
  201. position: relative;
  202. bottom: 0;
  203. left: 0;
  204. width: 100%;
  205. height: 238px;
  206. background-color: rgba(255, 255, 255, 1);
  207. }
  208. </style>

mpvue-picker

mpvuePicker.vue
复制代码
  1. <template>
  2. <view class="mpvue-picker">
  3. <view :class="{'pickerMask':showPicker}" @click="maskClick" catchtouchmove="true"></view>
  4. <view class="mpvue-picker-content " :class="{'mpvue-picker-view-show':showPicker}">
  5. <view class="mpvue-picker__hd" catchtouchmove="true">
  6. <view class="mpvue-picker__action" @click="pickerCancel">取消</view>
  7. <view class="mpvue-picker__action" :style="{color:themeColor}" @click="pickerConfirm">确定</view>
  8. </view>
  9. <!-- 单列 -->
  10. <picker-view indicator-style="height: 40px;" class="mpvue-picker-view" :value="pickerValue" @change="pickerChange" v-if="mode==='selector' && pickerValueSingleArray.length > 0">
  11. <block>
  12. <picker-view-column>
  13. <view class="picker-item" v-for="(item,index) in pickerValueSingleArray" :key="index">{{item.label}}</view>
  14. </picker-view-column>
  15. </block>
  16. </picker-view>
  17. <!-- 时间选择器 -->
  18. <picker-view indicator-style="height: 40px;" class="mpvue-picker-view" :value="pickerValue" @change="pickerChange" v-if="mode==='timeSelector'">
  19. <block>
  20. <picker-view-column>
  21. <view class="picker-item" v-for="(item,index) in pickerValueHour" :key="index">{{item.label}}</view>
  22. </picker-view-column>
  23. <picker-view-column>
  24. <view class="picker-item" v-for="(item,index) in pickerValueMinute" :key="index">{{item.label}}</view>
  25. </picker-view-column>
  26. </block>
  27. </picker-view>
  28. <!-- 多列选择 -->
  29. <picker-view indicator-style="height: 40px;" class="mpvue-picker-view" :value="pickerValue" @change="pickerChange" v-if="mode==='multiSelector'">
  30. <block v-for="(n,index) in pickerValueMulArray.length" :key="index">
  31. <picker-view-column>
  32. <view class="picker-item" v-for="(item,index1) in pickerValueMulArray[n]" :key="index1">{{item.label}}</view>
  33. </picker-view-column>
  34. </block>
  35. </picker-view>
  36. <!-- 二级联动 -->
  37. <picker-view indicator-style="height: 40px;" class="mpvue-picker-view" :value="pickerValue" @change="pickerChangeMul" v-if="mode==='multiLinkageSelector' && deepLength===2">
  38. <block>
  39. <picker-view-column>
  40. <view class="picker-item" v-for="(item,index) in pickerValueMulTwoOne" :key="index">{{item.label}}</view>
  41. </picker-view-column>
  42. <picker-view-column>
  43. <view class="picker-item" v-for="(item,index) in pickerValueMulTwoTwo" :key="index">{{item.label}}</view>
  44. </picker-view-column>
  45. </block>
  46. </picker-view>
  47. <!-- 三级联动 -->
  48. <picker-view indicator-style="height: 40px;" class="mpvue-picker-view" :value="pickerValue" @change="pickerChangeMul" v-if="mode==='multiLinkageSelector' && deepLength===3">
  49. <block>
  50. <picker-view-column>
  51. <view class="picker-item" v-for="(item,index) in pickerValueMulThreeOne" :key="index">{{item.label}}</view>
  52. </picker-view-column>
  53. <picker-view-column>
  54. <view class="picker-item" v-for="(item,index) in pickerValueMulThreeTwo" :key="index">{{item.label}}</view>
  55. </picker-view-column>
  56. <picker-view-column>
  57. <view class="picker-item" v-for="(item,index) in pickerValueMulThreeThree" :key="index">{{item.label}}</view>
  58. </picker-view-column>
  59. </block>
  60. </picker-view>
  61. </view>
  62. </view>
  63. </template>
  64. <script>
  65. export default {
  66. data() {
  67. return {
  68. pickerChangeValue: [],
  69. pickerValue: [],
  70. pickerValueArrayChange: true,
  71. modeChange: false,
  72. pickerValueSingleArray: [],
  73. pickerValueHour: [],
  74. pickerValueMinute: [],
  75. pickerValueMulArray: [],
  76. pickerValueMulTwoOne: [],
  77. pickerValueMulTwoTwo: [],
  78. pickerValueMulThreeOne: [],
  79. pickerValueMulThreeTwo: [],
  80. pickerValueMulThreeThree: [],
  81. /* 是否显示控件 */
  82. showPicker: false,
  83. };
  84. },
  85. props: {
  86. /* mode */
  87. mode: {
  88. type: String,
  89. default: 'selector'
  90. },
  91. /* picker 数值 */
  92. pickerValueArray: {
  93. type: Array,
  94. default(){
  95. return []
  96. }
  97. },
  98. /* 默认值 */
  99. pickerValueDefault: {
  100. type: Array,
  101. default(){
  102. return []
  103. }
  104. },
  105. /* 几级联动 */
  106. deepLength: {
  107. type: Number,
  108. default: 2
  109. },
  110. /* 主题色 */
  111. themeColor: String
  112. },
  113. watch: {
  114. pickerValueArray(oldVal, newVal) {
  115. this.pickerValueArrayChange = true;
  116. },
  117. mode(oldVal, newVal) {
  118. this.modeChange = true;
  119. },
  120. pickerValueArray(val){
  121. this.initPicker(val);
  122. }
  123. },
  124. methods: {
  125. initPicker(valueArray) {
  126. let pickerValueArray = valueArray;
  127. this.pickerValue = this.pickerValueDefault;
  128. // 初始化多级联动
  129. if (this.mode === 'selector') {
  130. this.pickerValueSingleArray = valueArray;
  131. } else if (this.mode === 'timeSelector') {
  132. this.modeChange = false;
  133. let hourArray = [];
  134. let minuteArray = [];
  135. for (let i = 0; i < 24; i++) {
  136. hourArray.push({
  137. value: i,
  138. label: i > 9 ? `${i} 时` : `0${i} 时`
  139. });
  140. }
  141. for (let i = 0; i < 60; i++) {
  142. minuteArray.push({
  143. value: i,
  144. label: i > 9 ? `${i} 分` : `0${i} 分`
  145. });
  146. }
  147. this.pickerValueHour = hourArray;
  148. this.pickerValueMinute = minuteArray;
  149. } else if (this.mode === 'multiSelector') {
  150. this.pickerValueMulArray = valueArray;
  151. } else if (this.mode === 'multiLinkageSelector' && this.deepLength === 2) {
  152. // 两级联动
  153. let pickerValueMulTwoOne = [];
  154. let pickerValueMulTwoTwo = [];
  155. // 第一列
  156. for (let i = 0, length = pickerValueArray.length; i < length; i++) {
  157. pickerValueMulTwoOne.push(pickerValueArray[i]);
  158. }
  159. // 渲染第二列
  160. // 如果有设定的默认值
  161. if (this.pickerValueDefault.length === 2) {
  162. let num = this.pickerValueDefault[0];
  163. for (
  164. let i = 0, length = pickerValueArray[num].children.length; i < length; i++
  165. ) {
  166. pickerValueMulTwoTwo.push(pickerValueArray[num].children[i]);
  167. }
  168. } else {
  169. for (
  170. let i = 0, length = pickerValueArray[0].children.length; i < length; i++
  171. ) {
  172. pickerValueMulTwoTwo.push(pickerValueArray[0].children[i]);
  173. }
  174. }
  175. this.pickerValueMulTwoOne = pickerValueMulTwoOne;
  176. this.pickerValueMulTwoTwo = pickerValueMulTwoTwo;
  177. } else if (
  178. this.mode === 'multiLinkageSelector' &&
  179. this.deepLength === 3
  180. ) {
  181. let pickerValueMulThreeOne = [];
  182. let pickerValueMulThreeTwo = [];
  183. let pickerValueMulThreeThree = [];
  184. // 第一列
  185. for (let i = 0, length = pickerValueArray.length; i < length; i++) {
  186. pickerValueMulThreeOne.push(pickerValueArray[i]);
  187. }
  188. // 渲染第二列
  189. this.pickerValueDefault =
  190. this.pickerValueDefault.length === 3 ?
  191. this.pickerValueDefault :
  192. [0, 0, 0];
  193. if (this.pickerValueDefault.length === 3) {
  194. let num = this.pickerValueDefault[0];
  195. for (
  196. let i = 0, length = pickerValueArray[num].children.length; i < length; i++
  197. ) {
  198. pickerValueMulThreeTwo.push(pickerValueArray[num].children[i]);
  199. }
  200. // 第三列
  201. let numSecond = this.pickerValueDefault[1];
  202. for (let i = 0, length = pickerValueArray[num].children[numSecond].children.length; i < length; i++) {
  203. pickerValueMulThreeThree.push(
  204. pickerValueArray[num].children[numSecond].children[i]
  205. );
  206. }
  207. }
  208. this.pickerValueMulThreeOne = pickerValueMulThreeOne;
  209. this.pickerValueMulThreeTwo = pickerValueMulThreeTwo;
  210. this.pickerValueMulThreeThree = pickerValueMulThreeThree;
  211. }
  212. },
  213. show() {
  214. setTimeout(() => {
  215. if (this.pickerValueArrayChange || this.modeChange) {
  216. this.initPicker(this.pickerValueArray);
  217. this.showPicker = true;
  218. this.pickerValueArrayChange = false;
  219. this.modeChange = false;
  220. } else {
  221. this.showPicker = true;
  222. }
  223. }, 0);
  224. },
  225. maskClick() {
  226. this.pickerCancel();
  227. },
  228. pickerCancel() {
  229. this.showPicker = false;
  230. this._initPickerVale();
  231. let pickObj = {
  232. index: this.pickerValue,
  233. value: this._getPickerLabelAndValue(this.pickerValue, this.mode).value,
  234. label: this._getPickerLabelAndValue(this.pickerValue, this.mode).label
  235. };
  236. this.$emit('onCancel', pickObj);
  237. },
  238. pickerConfirm(e) {
  239. this.showPicker = false;
  240. this._initPickerVale();
  241. let pickObj = {
  242. index: this.pickerValue,
  243. value: this._getPickerLabelAndValue(this.pickerValue, this.mode).value,
  244. label: this._getPickerLabelAndValue(this.pickerValue, this.mode).label
  245. };
  246. this.$emit('onConfirm', pickObj);
  247. },
  248. showPickerView() {
  249. this.showPicker = true;
  250. },
  251. pickerChange(e) {
  252. this.pickerValue = e.mp.detail.value;
  253. let pickObj = {
  254. index: this.pickerValue,
  255. value: this._getPickerLabelAndValue(this.pickerValue, this.mode).value,
  256. label: this._getPickerLabelAndValue(this.pickerValue, this.mode).label
  257. };
  258. this.$emit('onChange', pickObj);
  259. },
  260. pickerChangeMul(e) {
  261. if (this.deepLength === 2) {
  262. let pickerValueArray = this.pickerValueArray;
  263. let changeValue = e.mp.detail.value;
  264. // 处理第一列滚动
  265. if (changeValue[0] !== this.pickerValue[0]) {
  266. let pickerValueMulTwoTwo = [];
  267. // 第一列滚动第二列数据更新
  268. for (let i = 0, length = pickerValueArray[changeValue[0]].children.length; i < length; i++) {
  269. pickerValueMulTwoTwo.push(pickerValueArray[changeValue[0]].children[i]);
  270. }
  271. this.pickerValueMulTwoTwo = pickerValueMulTwoTwo;
  272. // 第二列初始化为 0
  273. changeValue[1] = 0;
  274. }
  275. this.pickerValue = changeValue;
  276. } else if (this.deepLength === 3) {
  277. let pickerValueArray = this.pickerValueArray;
  278. let changeValue = e.mp.detail.value;
  279. let pickerValueMulThreeTwo = [];
  280. let pickerValueMulThreeThree = [];
  281. // 重新渲染第二列
  282. // 如果是第一列滚动
  283. if (changeValue[0] !== this.pickerValue[0]) {
  284. this.pickerValueMulThreeTwo = [];
  285. for (let i = 0, length = pickerValueArray[changeValue[0]].children.length; i < length; i++) {
  286. pickerValueMulThreeTwo.push(pickerValueArray[changeValue[0]].children[i]);
  287. }
  288. // 重新渲染第三列
  289. for (let i = 0, length = pickerValueArray[changeValue[0]].children[0].children.length; i <
  290. length; i++) {
  291. pickerValueMulThreeThree.push(pickerValueArray[changeValue[0]].children[0].children[i]);
  292. }
  293. changeValue[1] = 0;
  294. changeValue[2] = 0;
  295. this.pickerValueMulThreeTwo = pickerValueMulThreeTwo;
  296. this.pickerValueMulThreeThree = pickerValueMulThreeThree;
  297. } else if (changeValue[1] !== this.pickerValue[1]) {
  298. // 第二列滚动
  299. // 重新渲染第三列
  300. this.pickerValueMulThreeThree = [];
  301. pickerValueMulThreeTwo = this.pickerValueMulThreeTwo;
  302. for (let i = 0, length = pickerValueArray[changeValue[0]].children[changeValue[1]].children.length; i <
  303. length; i++) {
  304. pickerValueMulThreeThree.push(pickerValueArray[changeValue[0]].children[changeValue[1]].children[
  305. i]);
  306. }
  307. changeValue[2] = 0;
  308. this.pickerValueMulThreeThree = pickerValueMulThreeThree;
  309. }
  310. this.pickerValue = changeValue;
  311. }
  312. let pickObj = {
  313. index: this.pickerValue,
  314. value: this._getPickerLabelAndValue(this.pickerValue, this.mode).value,
  315. label: this._getPickerLabelAndValue(this.pickerValue, this.mode).label
  316. };
  317. this.$emit('onChange', pickObj);
  318. },
  319. // 获取 pxikerLabel
  320. _getPickerLabelAndValue(value, mode) {
  321. let pickerLable;
  322. let pickerGetValue = [];
  323. // selector
  324. if (mode === 'selector') {
  325. pickerLable = this.pickerValueSingleArray[value].label;
  326. pickerGetValue.push(this.pickerValueSingleArray[value].value);
  327. } else if (mode === 'timeSelector') {
  328. pickerLable = `${this.pickerValueHour[value[0]].label}-${this.pickerValueMinute[value[1]].label}`;
  329. pickerGetValue.push(this.pickerValueHour[value[0]].value);
  330. pickerGetValue.push(this.pickerValueHour[value[1]].value);
  331. } else if (mode === 'multiSelector') {
  332. for (let i = 0; i < value.length; i++) {
  333. if (i > 0) {
  334. pickerLable += this.pickerValueMulArray[i][value[i]].label + (i === value.length - 1 ? '' :
  335. '-');
  336. } else {
  337. pickerLable = this.pickerValueMulArray[i][value[i]].label + '-';
  338. }
  339. pickerGetValue.push(this.pickerValueMulArray[i][value[i]].value);
  340. }
  341. } else if (mode === 'multiLinkageSelector') {
  342. /* eslint-disable indent */
  343. pickerLable =
  344. this.deepLength === 2 ?
  345. `${this.pickerValueMulTwoOne[value[0]].label}-${this.pickerValueMulTwoTwo[value[1]].label}` :
  346. `${this.pickerValueMulThreeOne[value[0]].label}-${this.pickerValueMulThreeTwo[value[1]].label}-${this.pickerValueMulThreeThree[value[2]].label}`;
  347. if (this.deepLength === 2) {
  348. pickerGetValue.push(this.pickerValueMulTwoOne[value[0]].value);
  349. pickerGetValue.push(this.pickerValueMulTwoTwo[value[1]].value);
  350. } else {
  351. pickerGetValue.push(this.pickerValueMulThreeOne[value[0]].value);
  352. pickerGetValue.push(this.pickerValueMulThreeTwo[value[1]].value);
  353. pickerGetValue.push(this.pickerValueMulThreeThree[value[2]].value);
  354. }
  355. /* eslint-enable indent */
  356. }
  357. return {
  358. label: pickerLable,
  359. value: pickerGetValue
  360. };
  361. },
  362. // 初始化 pickerValue 默认值
  363. _initPickerVale() {
  364. if (this.pickerValue.length === 0) {
  365. if (this.mode === 'selector') {
  366. this.pickerValue = [0];
  367. } else if (this.mode === 'multiSelector') {
  368. this.pickerValue = new Int8Array(this.pickerValueArray.length);
  369. } else if (
  370. this.mode === 'multiLinkageSelector' &&
  371. this.deepLength === 2
  372. ) {
  373. this.pickerValue = [0, 0];
  374. } else if (
  375. this.mode === 'multiLinkageSelector' &&
  376. this.deepLength === 3
  377. ) {
  378. this.pickerValue = [0, 0, 0];
  379. }
  380. }
  381. }
  382. }
  383. };
  384. </script>
  385. <style>
  386. .pickerMask {
  387. position: fixed;
  388. z-index: 1000;
  389. top: 0;
  390. right: 0;
  391. left: 0;
  392. bottom: 0;
  393. background: rgba(0, 0, 0, 0.6);
  394. }
  395. .mpvue-picker-content {
  396. position: fixed;
  397. bottom: 0;
  398. left: 0;
  399. width: 100%;
  400. transition: all 0.3s ease;
  401. transform: translateY(100%);
  402. z-index: 3000;
  403. }
  404. .mpvue-picker-view-show {
  405. transform: translateY(0);
  406. }
  407. .mpvue-picker__hd {
  408. display: flex;
  409. padding: 9px 15px;
  410. background-color: #fff;
  411. position: relative;
  412. text-align: center;
  413. font-size: 17px;
  414. }
  415. .mpvue-picker__hd:after {
  416. content: ' ';
  417. position: absolute;
  418. left: 0;
  419. bottom: 0;
  420. right: 0;
  421. height: 1px;
  422. border-bottom: 1px solid #e5e5e5;
  423. color: #e5e5e5;
  424. transform-origin: 0 100%;
  425. transform: scaleY(0.5);
  426. }
  427. .mpvue-picker__action {
  428. display: block;
  429. flex: 1;
  430. color: #1aad19;
  431. }
  432. .mpvue-picker__action:first-child {
  433. text-align: left;
  434. color: #888;
  435. }
  436. .mpvue-picker__action:last-child {
  437. text-align: right;
  438. }
  439. .picker-item {
  440. text-align: center;
  441. line-height: 40px;
  442. font-size: 16px;
  443. }
  444. .mpvue-picker-view {
  445. position: relative;
  446. bottom: 0;
  447. left: 0;
  448. width: 100%;
  449. height: 238px;
  450. background-color: rgba(255, 255, 255, 1);
  451. }
  452. </style>

payments

paymentsByAli.vue
复制代码
  1. <template>
  2. <view class='cell-group payment-method'>
  3. <view class='cell-item add-title-item' v-for="item in payments" :key="item.code" @click="toPayHandler(item.code)"
  4. v-if="!(type == 2 && item.code == 'balancepay')">
  5. <view class='cell-item-hd'>
  6. <image class='cell-hd-icon' :src='item.icon'></image>
  7. </view>
  8. <view class='cell-item-bd'>
  9. <view class="cell-bd-view">
  10. <text class="cell-bd-text">{{ item.name }}</text>
  11. </view>
  12. <view class="cell-bd-view">
  13. <text class="cell-bd-text address">{{ item.memo }}</text>
  14. </view>
  15. </view>
  16. <view class='cell-item-ft'>
  17. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  18. </view>
  19. </view>
  20. <view class="payment-pop" v-show="popShow">
  21. <view class="payment-pop-c">
  22. <image src="/static/image/wait-pay.png" style="width: 30px;
  23. height: 30px;"></image>
  24. <view class="text">支付中,请稍后...</view>
  25. </view>
  26. <view class="payment-pop-b">
  27. <button class="btn btn-c" @click="popBtn">支付失败</button>
  28. <button class="btn btn-o" @click="popBtn">支付成功</button>
  29. </view>
  30. </view>
  31. </view>
  32. </template>
  33. <script>
  34. import {
  35. apiBaseUrl
  36. } from '@/config/config.js';
  37. export default {
  38. props: {
  39. // 如果是商品订单此参数必须
  40. orderId: {
  41. type: String,
  42. default () {
  43. return '';
  44. }
  45. },
  46. // 如果是充值订单此参数必须
  47. recharge: {
  48. type: Number,
  49. default () {
  50. return 0;
  51. }
  52. },
  53. // 用户id
  54. uid: {
  55. type: Number,
  56. default () {
  57. return 0;
  58. }
  59. },
  60. // 订单类型
  61. type: {
  62. type: Number,
  63. default () {
  64. return 1;
  65. }
  66. }
  67. },
  68. data() {
  69. return {
  70. payments: [],
  71. popShow: false
  72. }
  73. },
  74. mounted() {
  75. this.getPayments();
  76. },
  77. methods: {
  78. // 获取可用支付方式列表
  79. getPayments() {
  80. this.$api.paymentList({}, res => {
  81. if (res.status) {
  82. this.payments = this.formatPayments(res.data);
  83. }
  84. })
  85. },
  86. // 支付方式处理
  87. formatPayments(payments) {
  88. payments = payments.filter(item => item.code !== 'wechatpay');
  89. // 如果是充值订单 过滤余额支付 过滤非线上支付方式
  90. if (this.type === 2) {
  91. payments = payments.filter(item => item.code !== 'balancepay' || item.is_online === 1)
  92. }
  93. // 设置logo图片
  94. payments.forEach(item => {
  95. this.$set(item, 'icon', '/static/image/' + item.code + '.png');
  96. });
  97. return payments;
  98. },
  99. // 用户点击支付方式处理
  100. toPayHandler(code) {
  101. this.popShow = true;
  102. let data = {
  103. payment_code: code,
  104. payment_type: this.type
  105. }
  106. data['ids'] = (this.type == 1 || this.type == 5 || this.type == 6) ? this.orderId : this.uid
  107. // 判断订单支付类型
  108. if (this.type == 2 && this.recharge) {
  109. data['params'] = {
  110. money: this.recharge,
  111. trade_type: 'JSAPI'
  112. }
  113. } else if ((this.type == 5 || this.type == 6) && this.recharge) {
  114. data['params'] = {
  115. trade_type: 'JSAPI',
  116. formid: this.orderId
  117. }
  118. } else {
  119. data['params'] = {
  120. trade_type: 'JSAPI'
  121. }
  122. }
  123. let _this = this;
  124. switch (code) {
  125. case 'alipay':
  126. this.$api.pay(data, res => {
  127. if (res.status) {
  128. uni.requestPayment({
  129. provider: 'alipay',
  130. tradeNO: res.data.trade_no,
  131. success: function(e) {
  132. if (e.errMsg === 'requestPayment:ok') {
  133. _this.$common.successToShow(res.msg, () => {
  134. _this.$common.redirectTo('/pages/goods/payment/result?id=' + res.data.payment_id);
  135. });
  136. }
  137. }
  138. });
  139. } else {
  140. this.$common.errorToShow(res.msg);
  141. }
  142. })
  143. break
  144. case 'balancepay':
  145. //用户余额支付
  146. this.$api.pay(data, res => {
  147. if (res.status) {
  148. this.$common.redirectTo('/pages/goods/payment/result?id=' + res.data.payment_id);
  149. } else {
  150. this.$common.errorToShow(res.msg);
  151. }
  152. })
  153. break;
  154. case 'offline':
  155. //线下支付
  156. this.$common.modelShow('线下支付说明', '请联系客服进行线下支付', () => {}, false, '取消', '确定')
  157. break;
  158. }
  159. },
  160. ,
  161. // 支付中显示隐藏
  162. popBtn() {
  163. this.popShow = false
  164. }
  165. }
  166. }
  167. </script>
  168. <style>
  169. .payment-method .cell-item-hd {
  170. min-width: 70upx;
  171. }
  172. .payment-method .cell-hd-icon {
  173. width: 70upx;
  174. height: 70upx;
  175. }
  176. .payment-method .cell-item-bd {
  177. border-left: 2upx solid #F0F0F0;
  178. padding-left: 30upx;
  179. }
  180. .payment-method .cell-bd-text {
  181. font-size: 28upx;
  182. color: #666;
  183. }
  184. .payment-method .address {
  185. font-size: 24upx;
  186. color: #999;
  187. }
  188. .payment-pop {
  189. position: fixed;
  190. top: 50%;
  191. left: 50%;
  192. transform: translate(-50%, -50%);
  193. width: 400rpx;
  194. height: 272rpx;
  195. background-color: #fff;
  196. text-align: center;
  197. box-shadow: 0 0 20rpx #ccc;
  198. /* border-radius: 10rpx; */
  199. }
  200. .payment-pop-c {
  201. padding: 50rpx 30rpx;
  202. /* line-height: 300rpx; */
  203. font-size: 32rpx;
  204. color: #999;
  205. }
  206. .payment-pop-b {
  207. position: absolute;
  208. bottom: 0;
  209. display: flex;
  210. width: 100%;
  211. justify-content: space-between;
  212. }
  213. .payment-pop-b .btn {
  214. flex: 1;
  215. }
  216. .payment-pop .text {
  217. font-size: 24upx;
  218. }
  219. </style>
paymentsByApp.vue
复制代码
  1. <template>
  2. <view class='cell-group payment-method'>
  3. <view class='cell-item add-title-item' v-for="item in payments" :key="item.code" @click="toPayHandler(item.code)"
  4. v-if="!(type == 2 && item.code == 'balancepay')">
  5. <view class='cell-item-hd'>
  6. <image class='cell-hd-icon' :src='item.icon'></image>
  7. </view>
  8. <view class='cell-item-bd'>
  9. <view class="cell-bd-view">
  10. <text class="cell-bd-text">{{ item.name }}</text>
  11. </view>
  12. <view class="cell-bd-view">
  13. <text class="cell-bd-text address">{{ item.memo }}</text>
  14. </view>
  15. </view>
  16. <view class='cell-item-ft'>
  17. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  18. </view>
  19. </view>
  20. <view class="payment-pop" v-show="popShow">
  21. <view class="payment-pop-c">
  22. <image src="/static/image/wait-pay.png" style="width: 30px;
  23. height: 30px;"></image>
  24. <view class="text">支付中,请稍后...</view>
  25. </view>
  26. <view class="payment-pop-b">
  27. <button class="btn btn-c" @click="popBtn">支付失败</button>
  28. <button class="btn btn-o" @click="popBtn">支付成功</button>
  29. </view>
  30. </view>
  31. </view>
  32. </template>
  33. <script>
  34. import {
  35. apiBaseUrl
  36. } from '@/config/config.js'
  37. export default {
  38. props: {
  39. // 如果是商品订单此参数必须
  40. orderId: {
  41. type: String,
  42. default () {
  43. return ''
  44. }
  45. },
  46. // 如果是充值订单此参数必须
  47. recharge: {
  48. type: Number,
  49. default () {
  50. return 0
  51. }
  52. },
  53. // 用户id
  54. uid: {
  55. type: Number,
  56. default () {
  57. return 0
  58. }
  59. },
  60. // 订单类型
  61. type: {
  62. type: Number,
  63. default () {
  64. return 1
  65. }
  66. }
  67. },
  68. data() {
  69. return {
  70. payments: [],
  71. popShow: false
  72. }
  73. },
  74. mounted() {
  75. this.getPayments()
  76. },
  77. methods: {
  78. // 获取可用支付方式列表
  79. getPayments() {
  80. this.$api.paymentList({}, res => {
  81. if (res.status) {
  82. this.payments = this.formatPayments(res.data)
  83. }
  84. })
  85. },
  86. // 支付方式处理
  87. formatPayments(payments) {
  88. // 如果是充值订单 过滤余额支付 过滤非线上支付方式
  89. if (this.type === 2) {
  90. payments = payments.filter(item => item.code !== 'balancepay' || item.is_online === 1)
  91. }
  92. // 设置logo图片
  93. payments.forEach(item => {
  94. this.$set(item, 'icon', '/static/image/' + item.code + '.png')
  95. })
  96. return payments
  97. },
  98. // 用户点击支付方式处理
  99. toPayHandler(code) {
  100. this.popShow = true;
  101. let _this = this
  102. let data = {
  103. payment_code: code,
  104. payment_type: _this.type
  105. }
  106. data['ids'] = (this.type == 1 || this.type == 5 || this.type == 6) ? this.orderId : this.uid
  107. if ((this.type == 5 || this.type == 6) && this.recharge) {
  108. data['params'] = {
  109. trade_type: 'APP',
  110. formid: this.orderId
  111. }
  112. }
  113. switch (code) {
  114. case 'alipay':
  115. /**
  116. * 支付宝支付需要模拟GET提交数据
  117. */
  118. if (_this.type == 1 && _this.orderId) {
  119. data['params'] = {
  120. trade_type: 'APP'
  121. }
  122. } else if (_this.type == 2 && _this.recharge) {
  123. data['params'] = {
  124. trade_type: 'APP',
  125. money: _this.recharge
  126. }
  127. }
  128. _this.$api.pay(data, res => {
  129. if (res.status) {
  130. uni.requestPayment({
  131. provider: "alipay",
  132. orderInfo: res.data.data,
  133. success: function(data) {
  134. _this.$common.successToShow('支付成功', () => {
  135. _this.redirectHandler(res.data.payment_id)
  136. })
  137. }
  138. });
  139. } else {
  140. _this.$comon.errorToShow(res.msg)
  141. }
  142. })
  143. break
  144. case 'wechatpay':
  145. // 微信 H5支付
  146. if (_this.type == 1 && _this.orderId) {
  147. data['params'] = {
  148. trade_type: 'APP'
  149. }
  150. } else if (_this.type == 2 && _this.recharge) {
  151. data['params'] = {
  152. trade_type: 'APP',
  153. money: _this.recharge
  154. }
  155. }
  156. // 微信app支付
  157. _this.$api.pay(data, res => {
  158. if (res.status) {
  159. console.log(JSON.stringify(res));
  160. // 调用微信支付
  161. uni.requestPayment({
  162. provider: "wxpay",
  163. orderInfo: {
  164. appid: res.data.appid,
  165. noncestr: res.data.noncestr,
  166. package: res.data.package,
  167. partnerid: res.data.partnerid,
  168. prepayid: res.data.prepayid,
  169. timestamp: res.data.timestamp,
  170. sign: res.data.sign,
  171. },
  172. success: function(data) {
  173. _this.$common.successToShow('支付成功', () => {
  174. _this.redirectHandler(res.data.payment_id)
  175. })
  176. },
  177. fail: function(res) {
  178. console.log(JSON.stringify(res));
  179. }
  180. });
  181. } else {
  182. _this.$common.errorToShow(res.msg)
  183. }
  184. })
  185. break
  186. case 'balancepay':
  187. /**
  188. * 用户余额支付
  189. *
  190. */
  191. _this.$api.pay(data, res => {
  192. if (res.status) {
  193. _this.redirectHandler(res.data.payment_id)
  194. } else {
  195. _this.$common.errorToShow(res.msg)
  196. }
  197. })
  198. break
  199. case 'offline':
  200. /**
  201. * 线下支付
  202. */
  203. _this.$common.modelShow('线下支付说明', '请联系客服进行线下支付', () => {}, false, '取消', '确定')
  204. break
  205. }
  206. },
  207. // 支付成功后跳转操作
  208. redirectHandler(paymentId) {
  209. this.$common.redirectTo('/pages/goods/payment/result?id=' + paymentId)
  210. },
  211. // 支付中显示隐藏
  212. popBtn() {
  213. this.popShow = false
  214. }
  215. }
  216. }
  217. </script>
  218. <style>
  219. .payment-method .cell-item-hd {
  220. min-width: 70upx;
  221. }
  222. .payment-method .cell-hd-icon {
  223. width: 70upx;
  224. height: 70upx;
  225. }
  226. .payment-method .cell-item-bd {
  227. border-left: 2upx solid #F0F0F0;
  228. padding-left: 30upx;
  229. }
  230. .payment-method .cell-bd-text {
  231. font-size: 28upx;
  232. color: #666;
  233. }
  234. .payment-method .address {
  235. font-size: 24upx;
  236. color: #999;
  237. }
  238. .payment-pop {
  239. position: fixed;
  240. top: 50%;
  241. left: 50%;
  242. transform: translate(-50%, -50%);
  243. width: 400rpx;
  244. height: 272rpx;
  245. background-color: #fff;
  246. text-align: center;
  247. box-shadow: 0 0 20rpx #ccc;
  248. /* border-radius: 10rpx; */
  249. }
  250. .payment-pop-c {
  251. padding: 50rpx 30rpx;
  252. /* line-height: 300rpx; */
  253. font-size: 32rpx;
  254. color: #999;
  255. }
  256. .payment-pop-b {
  257. position: absolute;
  258. bottom: 0;
  259. display: flex;
  260. width: 100%;
  261. justify-content: space-between;
  262. }
  263. .payment-pop-b .btn {
  264. flex: 1;
  265. }
  266. .payment-pop .text {
  267. font-size: 24upx;
  268. }
  269. </style>
paymentsByH5.vue
复制代码
  1. <template>
  2. <view class='cell-group payment-method'>
  3. <view class='cell-item add-title-item' v-for="item in payments" :key="item.code" @click="toPayHandler(item.code)"
  4. v-if="!(type == 2 && item.code == 'balancepay')">
  5. <view class='cell-item-hd'>
  6. <image class='cell-hd-icon' :src='item.icon'></image>
  7. </view>
  8. <view class='cell-item-bd'>
  9. <view class="cell-bd-view">
  10. <text class="cell-bd-text">{{ item.name }}</text>
  11. </view>
  12. <view class="cell-bd-view">
  13. <text class="cell-bd-text address">{{ item.memo }}</text>
  14. </view>
  15. </view>
  16. <view class='cell-item-ft'>
  17. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  18. </view>
  19. </view>
  20. <view class="payment-pop" v-show="popShow">
  21. <view class="payment-pop-c">
  22. <image src="/static/image/wait-pay.png" style="width: 30px;
  23. height: 30px;"></image>
  24. <view class="text">支付中,请稍后...</view>
  25. </view>
  26. <view class="payment-pop-b">
  27. <button class="btn btn-c" @click="popBtn">支付失败</button>
  28. <button class="btn btn-o" @click="popBtn">支付成功</button>
  29. </view>
  30. </view>
  31. </view>
  32. </template>
  33. <script>
  34. import {
  35. baseUrl
  36. } from '@/config/config.js'
  37. export default {
  38. props: {
  39. // 如果是商品订单此参数必须
  40. orderId: {
  41. type: String,
  42. default () {
  43. return ''
  44. }
  45. },
  46. // 如果是充值订单此参数必须
  47. recharge: {
  48. type: Number,
  49. default () {
  50. return 0
  51. }
  52. },
  53. // 用户id
  54. uid: {
  55. type: Number,
  56. default () {
  57. return 0
  58. }
  59. },
  60. // 订单类型
  61. type: {
  62. type: Number,
  63. default () {
  64. return 1
  65. }
  66. }
  67. },
  68. data() {
  69. return {
  70. payments: [],
  71. openid: '',
  72. popShow: false
  73. }
  74. },
  75. mounted() {
  76. this.getPayments()
  77. },
  78. methods: {
  79. // 获取可用支付方式列表
  80. getPayments() {
  81. this.$api.paymentList({}, res => {
  82. if (res.status) {
  83. this.payments = this.formatPayments(res.data)
  84. }
  85. })
  86. },
  87. // 支付方式处理
  88. formatPayments(payments) {
  89. // h5支付并且是在微信浏览器内 过滤支付宝支付
  90. if (this.$common.isWeiXinBrowser()) {
  91. payments = payments.filter(item => item.code !== 'alipay')
  92. }
  93. // 如果是充值订单 过滤余额支付 过滤非线上支付方式
  94. if (this.type === 2) {
  95. payments = payments.filter(
  96. item => item.code !== 'balancepay' || item.is_online === 1
  97. )
  98. }
  99. // 设置logo图片
  100. payments.forEach(item => {
  101. this.$set(item, 'icon', '/static/image/' + item.code + '.png')
  102. })
  103. return payments
  104. },
  105. checkWXJSBridge(data) {
  106. let that = this
  107. let interval = setInterval(() => {
  108. if (typeof window.WeixinJSBridge != 'undefined') {
  109. clearTimeout(interval)
  110. that.onBridgeReady(data)
  111. }
  112. }, 200)
  113. },
  114. onBridgeReady(data) {
  115. var _this = this
  116. window.WeixinJSBridge.invoke(
  117. 'getBrandWCPayRequest', {
  118. appId: data.appid, // 公众号名称,由商户传入
  119. timeStamp: data.timeStamp, // 时间戳,自1970年以来的秒数
  120. nonceStr: data.nonceStr, // 随机串
  121. package: data.package,
  122. signType: data.signType, // 微信签名方式:
  123. paySign: data.paySign // 微信签名
  124. },
  125. function(res) {
  126. if (res.err_msg === 'get_brand_wcpay_request:ok') {
  127. _this.$common.successToShow('支付成功')
  128. } else if (res.err_msg === 'get_brand_wcpay_request:cancel') {
  129. _this.$common.errorToShow('取消支付')
  130. } else {
  131. _this.$common.errorToShow('支付失败')
  132. }
  133. setTimeout(() => {
  134. _this.$common.redirectTo(
  135. '/pages/goods/payment/result?id=' + data.payment_id
  136. )
  137. }, 1000)
  138. }
  139. )
  140. },
  141. // 用户点击支付方式处理
  142. toPayHandler(code) {
  143. this.popShow = true;
  144. let data = {
  145. payment_code: code,
  146. payment_type: this.type
  147. }
  148. data['ids'] = (this.type == 1 || this.type == 5 || this.type == 6) ? this.orderId : this.uid
  149. switch (code) {
  150. case 'alipay':
  151. /**
  152. * 支付宝支付需要模拟GET提交数据
  153. */
  154. if (this.type == 1 && this.orderId) {
  155. data['params'] = {
  156. trade_type: 'WAP',
  157. return_url: baseUrl +
  158. 'wap/pages/goods/payment/result'
  159. }
  160. } else if (this.type == 2 && this.recharge) {
  161. data['params'] = {
  162. money: this.recharge,
  163. return_url: baseUrl + 'wap/pages/goods/payment/result'
  164. }
  165. } else if ((this.type == 5 || this.type == 6) && this.recharge) {
  166. data['params'] = {
  167. formid: this.orderId
  168. }
  169. }
  170. this.$api.pay(data, res => {
  171. if (res.status) {
  172. const url = res.data.url
  173. const data = res.data.data
  174. // 模拟GET提交
  175. let tempForm = document.createElement('form')
  176. tempForm.id = 'aliPay'
  177. tempForm.methods = 'post'
  178. tempForm.action = url
  179. tempForm.target = '_self'
  180. let input = []
  181. for (let k in data) {
  182. input[k] = document.createElement('input')
  183. input[k].type = 'hidden'
  184. input[k].name = k
  185. input[k].value = data[k]
  186. tempForm.appendChild(input[k])
  187. }
  188. tempForm.addEventListener('submit', function() {}, false)
  189. document.body.appendChild(tempForm)
  190. tempForm.dispatchEvent(new Event('submit'))
  191. tempForm.submit()
  192. document.body.removeChild(tempForm)
  193. }
  194. })
  195. break
  196. case 'wechatpay':
  197. /**
  198. * 微信支付有两种
  199. * 判断是否在微信浏览器
  200. * 微信jsapi支付
  201. */
  202. let isWeiXin = this.$common.isWeiXinBrowser()
  203. if (isWeiXin) {
  204. var transitUrl =
  205. baseUrl +
  206. 'wap/pages/goods/payment/auth?order_id=' +
  207. this.orderId +
  208. '&type=' +
  209. this.type;
  210. if (this.type == 1 && this.orderId) {
  211. // 微信jsapi支付
  212. // if (this.openid) {
  213. // data['params'] = {
  214. // trade_type: 'JSAPI_OFFICIAL',
  215. // openid: this.openid
  216. // }
  217. // } else {
  218. // data['params'] = {
  219. // trade_type: 'JSAPI_OFFICIAL',
  220. // url: window.location.href
  221. // }
  222. // }
  223. data['params'] = {
  224. trade_type: 'JSAPI_OFFICIAL',
  225. url: transitUrl
  226. }
  227. } else if (this.type == 2 && this.recharge) {
  228. data['params'] = {
  229. trade_type: 'JSAPI_OFFICIAL',
  230. money: this.recharge,
  231. url: transitUrl + '&uid=' + this.uid + '&money=' + this.recharge
  232. }
  233. // if (this.openid) {
  234. // data['params'] = {
  235. // money: this.recharge,
  236. // openid: this.openid
  237. // }
  238. // } else {
  239. // data['params'] = {
  240. // money: this.recharge,
  241. // url: window.location.href
  242. // }
  243. // }
  244. } else if ((this.type == 5 || this.type == 6) && this.recharge) {
  245. data['params'] = {
  246. formid: this.orderId
  247. }
  248. }
  249. this.$api.pay(data, res => {
  250. if (!res.status && res.data == '10066') {
  251. window.location.href = res.msg
  252. return;
  253. }
  254. const data = res.data
  255. this.checkWXJSBridge(data)
  256. })
  257. } else {
  258. // 微信 H5支付
  259. if (this.type == 1 && this.orderId) {
  260. data['params'] = {
  261. trade_type: 'MWEB',
  262. return_url: baseUrl +
  263. 'wap/pages/goods/payment/result'
  264. }
  265. } else if (this.type == 2 && this.recharge) {
  266. data['params'] = {
  267. trade_type: 'MWEB',
  268. money: this.recharge,
  269. return_url: baseUrl + 'wap/pages/goods/payment/result'
  270. }
  271. } else if ((this.type == 5 || this.type == 6) && this.recharge) {
  272. data['params'] = {
  273. formid: this.orderId
  274. }
  275. }
  276. // 微信h5支付
  277. this.$api.pay(data, res => {
  278. if (res.status) {
  279. location.href = res.data.mweb_url
  280. } else {
  281. this.$common.errorToShow(res.msg)
  282. }
  283. })
  284. }
  285. break
  286. case 'balancepay':
  287. /**
  288. * 用户余额支付
  289. *
  290. */
  291. if ((this.type == 5 || this.type == 6) && this.recharge) {
  292. data['params'] = {
  293. formid: this.orderId
  294. }
  295. }
  296. this.$api.pay(data, res => {
  297. if (res.status) {
  298. this.$common.redirectTo(
  299. '/pages/goods/payment/result?id=' + res.data.payment_id
  300. )
  301. } else {
  302. this.$common.errorToShow(res.msg)
  303. }
  304. })
  305. break
  306. case 'offline':
  307. /**
  308. * 线下支付
  309. */
  310. this.$common.modelShow(
  311. '线下支付说明',
  312. '请联系客服进行线下支付',
  313. () => {},
  314. false,
  315. '取消',
  316. '确定'
  317. )
  318. break
  319. }
  320. },
  321. // 支付中显示隐藏
  322. popBtn() {
  323. this.popShow = false
  324. }
  325. }
  326. }
  327. </script>
  328. <style>
  329. .payment-method .cell-item-hd {
  330. min-width: 70upx;
  331. }
  332. .payment-method .cell-hd-icon {
  333. width: 70upx;
  334. height: 70upx;
  335. }
  336. .payment-method .cell-item-bd {
  337. border-left: 2upx solid #f0f0f0;
  338. padding-left: 30upx;
  339. }
  340. .payment-method .cell-bd-text {
  341. font-size: 28upx;
  342. color: #666;
  343. }
  344. .payment-method .address {
  345. font-size: 24upx;
  346. color: #999;
  347. }
  348. .payment-pop {
  349. position: fixed;
  350. top: 50%;
  351. left: 50%;
  352. transform: translate(-50%, -50%);
  353. width: 400rpx;
  354. height: 272rpx;
  355. background-color: #fff;
  356. text-align: center;
  357. box-shadow: 0 0 20rpx #ccc;
  358. /* border-radius: 10rpx; */
  359. }
  360. .payment-pop-c {
  361. padding: 50rpx 30rpx;
  362. /* line-height: 300rpx; */
  363. font-size: 32rpx;
  364. color: #999;
  365. }
  366. .payment-pop-b {
  367. position: absolute;
  368. bottom: 0;
  369. display: flex;
  370. width: 100%;
  371. justify-content: space-between;
  372. }
  373. .payment-pop-b .btn {
  374. flex: 1;
  375. }
  376. .payment-pop .text {
  377. font-size: 24upx;
  378. }
  379. </style>
paymentsByWx.vue
复制代码
  1. <template>
  2. <view class='cell-group payment-method payment-wx'>
  3. <form class='cell-item add-title-item' v-for="item in payments" :key="item.code" @submit="toPayHandler" report-submit="true"
  4. v-if="!(type == 2 && item.code == 'balancepay')">
  5. <input name="code" :value="item.code" class="no-show">
  6. <button class="btn" form-type="submit">
  7. <view class='cell-item-hd'>
  8. <image class='cell-hd-icon' :src='item.icon'></image>
  9. </view>
  10. <view class='cell-item-bd'>
  11. <view class="cell-bd-view">
  12. <text class="cell-bd-text">{{ item.name }}</text>
  13. </view>
  14. <view class="cell-bd-view">
  15. <text class="cell-bd-text address">{{ item.memo }}</text>
  16. </view>
  17. </view>
  18. <view class='cell-item-ft'>
  19. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  20. </view>
  21. </button>
  22. </form>
  23. <view class="payment-pop" v-show="popShow">
  24. <view class="payment-pop-c">
  25. <image src="/static/image/wait-pay.png"></image>
  26. <view class="text">支付中,请稍后...</view>
  27. </view>
  28. <view class="payment-pop-b">
  29. <button class="btn btn-c" @click="popBtn">支付失败</button>
  30. <button class="btn btn-o" @click="popBtn">支付成功</button>
  31. </view>
  32. </view>
  33. </view>
  34. </template>
  35. <script>
  36. import {
  37. apiBaseUrl
  38. } from '@/config/config.js'
  39. export default {
  40. props: {
  41. // 如果是商品订单此参数必须
  42. orderId: {
  43. type: String,
  44. default () {
  45. return ''
  46. }
  47. },
  48. // 如果是充值订单此参数必须
  49. recharge: {
  50. type: Number,
  51. default () {
  52. return 0
  53. }
  54. },
  55. // 用户id
  56. uid: {
  57. type: Number,
  58. default () {
  59. return 0
  60. }
  61. },
  62. // 订单类型
  63. type: {
  64. type: Number,
  65. default () {
  66. return 1
  67. }
  68. }
  69. },
  70. data() {
  71. return {
  72. payments: [],
  73. popShow: false
  74. }
  75. },
  76. mounted() {
  77. this.getPayments()
  78. },
  79. methods: {
  80. // 获取可用支付方式列表
  81. getPayments() {
  82. this.$api.paymentList({}, res => {
  83. if (res.status) {
  84. this.payments = this.formatPayments(res.data)
  85. }
  86. })
  87. },
  88. // 支付方式处理
  89. formatPayments(payments) {
  90. // 过滤支付宝支付
  91. payments = payments.filter(item => item.code !== 'alipay')
  92. // 如果是充值订单 过滤余额支付 过滤非线上支付方式
  93. if (this.type === 2) {
  94. payments = payments.filter(item => item.code !== 'balancepay' || item.is_online === 1)
  95. }
  96. // 设置logo图片
  97. payments.forEach(item => {
  98. this.$set(item, 'icon', '/static/image/' + item.code + '.png')
  99. })
  100. return payments
  101. },
  102. // 用户点击支付方式处理
  103. toPayHandler(e) {
  104. this.popShow = true;
  105. let code = e.target.value.code;
  106. let formId = e.detail.formId;
  107. let data = {
  108. payment_code: code,
  109. payment_type: this.type,
  110. params: {
  111. formid: formId
  112. }
  113. }
  114. data['ids'] = (this.type == 1 || this.type == 5 || this.type == 6) ? this.orderId : this.uid
  115. // 判断订单支付类型
  116. if (this.type == 2 && this.recharge) {
  117. data['params'] = {
  118. money: this.recharge
  119. }
  120. } else if ((this.type == 5 || this.type == 6) && this.recharge) {
  121. data['params'] = {
  122. formid: this.orderId
  123. }
  124. }
  125. let _this = this
  126. switch (code) {
  127. case 'wechatpay':
  128. this.$api.pay(data, res => {
  129. if (res.status) {
  130. uni.requestPayment({
  131. provider: 'wxpay',
  132. timeStamp: res.data.timeStamp,
  133. nonceStr: res.data.nonceStr,
  134. package: res.data.package,
  135. signType: res.data.signType,
  136. paySign: res.data.paySign,
  137. success: function(e) {
  138. if (e.errMsg === 'requestPayment:ok') {
  139. _this.$common.successToShow(res.msg, () => {
  140. _this.$common.redirectTo('/pages/goods/payment/result?id=' + res.data.payment_id)
  141. })
  142. }
  143. }
  144. });
  145. } else {
  146. this.$common.errorToShow(res.msg)
  147. }
  148. })
  149. break
  150. case 'balancepay':
  151. /**
  152. * 用户余额支付
  153. *
  154. */
  155. this.$api.pay(data, res => {
  156. if (res.status) {
  157. this.$common.redirectTo('/pages/goods/payment/result?id=' + res.data.payment_id)
  158. } else {
  159. this.$common.errorToShow(res.msg)
  160. }
  161. })
  162. break
  163. case 'offline':
  164. /**
  165. * 线下支付
  166. */
  167. this.$common.modelShow('线下支付说明', '请联系客服进行线下支付', () => {}, false, '取消', '确定')
  168. break
  169. }
  170. },
  171. // 支付中显示隐藏
  172. popBtn() {
  173. this.popShow = false
  174. }
  175. }
  176. }
  177. </script>
  178. <style>
  179. .payment-method .cell-item-hd {
  180. min-width: 70upx;
  181. }
  182. .payment-method .cell-hd-icon {
  183. width: 70upx;
  184. height: 70upx;
  185. }
  186. .payment-method .cell-item-bd {
  187. border-left: 2upx solid #F0F0F0;
  188. padding-left: 30upx;
  189. }
  190. .payment-method .cell-bd-text {
  191. font-size: 28upx;
  192. color: #666;
  193. }
  194. .payment-method .address {
  195. font-size: 24upx;
  196. color: #999;
  197. }
  198. .no-show {
  199. display: none;
  200. }
  201. .payment-wx .btn {
  202. background-color: #fff;
  203. line-height: 1.7;
  204. padding: 0;
  205. width: 724upx;
  206. position: relative;
  207. overflow: hidden;
  208. float: left;
  209. }
  210. .payment-wx .btn .cell-item-hd {
  211. min-width: 100upx;
  212. }
  213. .payment-pop {
  214. position: fixed;
  215. top: 50%;
  216. left: 50%;
  217. transform: translate(-50%, -50%);
  218. width: 400rpx;
  219. height: 272rpx;
  220. background-color: #fff;
  221. text-align: center;
  222. box-shadow: 0 0 20rpx #ccc;
  223. /* border-radius: 10rpx; */
  224. }
  225. .payment-pop-c {
  226. padding: 50rpx 30rpx;
  227. /* line-height: 300rpx; */
  228. font-size: 32rpx;
  229. color: #999;
  230. }
  231. .payment-pop-c image {
  232. width: 60upx;
  233. height: 60upx;
  234. }
  235. .payment-pop-b {
  236. position: absolute;
  237. bottom: 0;
  238. display: flex;
  239. width: 100%;
  240. justify-content: space-between;
  241. }
  242. .payment-pop-b .btn {
  243. flex: 1;
  244. }
  245. .payment-pop-b .btn-o {
  246. background-color: #FF7159;
  247. }
  248. .payment-pop .text {
  249. font-size: 24upx;
  250. }
  251. </style>

posters-layer

index.vue
复制代码
  1. <style lang="less">
  2. .posters-layer {
  3. position: fixed;
  4. top: -5000px;
  5. left: -5000px;
  6. // top: 0;
  7. // left: 0;
  8. }
  9. </style>
  10. <template>
  11. <canvas
  12. canvas-id="canvasdrawer"
  13. :style="{width: width + 'px', height: height + 'px'}"
  14. class="posters-layer">
  15. </canvas>
  16. </template>
  17. <script>
  18. const CACHE_KEYS = 'temp_canvasdrawer_pic_cache';
  19. export default {
  20. data() {
  21. return {
  22. width: 100,
  23. height: 100,
  24. paintingData: { views: [] },
  25. index: 0,
  26. imageList: [],
  27. tempFileList: [],
  28. isPainting: false,
  29. ctx: null,
  30. cache: {},
  31. }
  32. },
  33. props: {
  34. postersData: {
  35. type: Object,
  36. default() {
  37. return { views: [] };
  38. }
  39. }
  40. },
  41. watch: {
  42. postersData(newVal, oldVal) {
  43. newVal = newVal || { views: [] };
  44. this.createPosters(newVal);
  45. }
  46. },
  47. mounted() {
  48. uni.removeStorageSync('CACHE_KEYS');
  49. this.cache = uni.getStorageSync('CACHE_KEYS') || {};
  50. this.ctx = uni.createCanvasContext('canvasdrawer', this);
  51. this.createPosters(this.postersData);
  52. },
  53. methods: {
  54. createPosters(newVal) {
  55. if (!newVal.width || !newVal.height) {
  56. return;
  57. };
  58. // newVal = newVal || { views: [] };
  59. newVal.views = newVal.views || [];
  60. uni.removeStorageSync('CACHE_KEYS')
  61. this.paintingData = newVal;
  62. this.ctx && this.ctx.clearActions();
  63. if (!this.isPainting) {
  64. if (newVal.width && newVal.height) {
  65. this.isPainting = true;
  66. try {
  67. this.readyPigment();
  68. }
  69. catch(err) {
  70. this.$emit('error');
  71. }
  72. }
  73. }
  74. },
  75. readyPigment() {
  76. const { width, height, views, background, radius = 0 } = this.paintingData;
  77. this.width = width;
  78. this.height = height;
  79. const inter = setInterval(() => {
  80. if (this.ctx) {
  81. clearInterval(inter);
  82. this.ctx.clearActions();
  83. this.ctx.closePath();
  84. // begin another path
  85. this.ctx.beginPath();
  86. this.drawRect({
  87. // || 'rgba(255, 255, 255, 0)'
  88. background: background,
  89. top: 0,
  90. left: 0,
  91. radius,
  92. width,
  93. height
  94. })
  95. this.getImageList(views);
  96. this.downLoadImages(0);
  97. }
  98. }, 100);
  99. },
  100. getImageList(views) {
  101. const imageList = [];
  102. for (let i = 0; i < views.length; i++) {
  103. if (views[i].type === 'image') {
  104. imageList.push(views[i].url);
  105. }
  106. }
  107. this.imageList = imageList;
  108. },
  109. downLoadImages(index) {
  110. const imageList = this.imageList;
  111. const tempFileList = this.tempFileList;
  112. if (index < imageList.length) {
  113. // console.log(imageList[index])
  114. this.getImageInfo(imageList[index]).then(imgInfo => {
  115. tempFileList.push(imgInfo)
  116. this.tempFileList = tempFileList;
  117. this.downLoadImages(index + 1);
  118. })
  119. } else {
  120. this.startPainting();
  121. }
  122. },
  123. tailorImageDraw(view, imgInfo) {
  124. // _views.tailor == 'center'
  125. let px = 1;
  126. let wMultiple = (view.width * px) / imgInfo.originWidth;
  127. let hMultiple = (view.height * px) / imgInfo.originHeight;
  128. let sizeNormal = false;
  129. if (wMultiple <= 1 && hMultiple <= 1) {
  130. let multiple = wMultiple > hMultiple ? wMultiple : hMultiple;
  131. // let tempW = imgInfo.originWidth * multiple;
  132. // let tempH = imgInfo.originHeight * multiple;
  133. let tempW = (view.width * px) / multiple;
  134. let tempH = (view.height * px) / multiple;
  135. let sx = (imgInfo.originWidth - tempW) / 2;
  136. let sy = (imgInfo.originHeight - tempH) / 2;
  137. let ex = sx + tempW;
  138. let ey = sy + tempH;
  139. view['sx'] = sx || 0;
  140. view['sy'] = sy || 0;
  141. view['ex'] = ex || 0;
  142. view['ey'] = ey || 0;
  143. sizeNormal = true;
  144. }
  145. const data = {
  146. ...view,
  147. ow: imgInfo.originWidth,
  148. oh: imgInfo.originHeight
  149. };
  150. // console.log(JSON.stringify(data));
  151. if (!sizeNormal) {
  152. delete data.tailor;
  153. }
  154. // this.drawImage(data);
  155. return data;
  156. },
  157. async startPainting() {
  158. const { tempFileList, paintingData: { views } } = this;
  159. for (let i = 0, imageIndex = 0; i < views.length; i++) {
  160. if (views[i].type === 'image') {
  161. let _img = tempFileList[imageIndex];
  162. let _views = views[i];
  163. let drawData = {};
  164. if (_views.tailor) {
  165. _views = this.tailorImageDraw(_views, _img);
  166. }
  167. drawData = {
  168. ..._views,
  169. url: _img.localPath
  170. };
  171. this.drawImage(drawData);
  172. // if (_views.radius) {
  173. // this.drawRoundRect(drawData);
  174. // }
  175. // else {
  176. // }
  177. imageIndex++;
  178. } else if (views[i].type === 'text') {
  179. if (!this.ctx.measureText) {
  180. uni.showModal({
  181. title: '提示',
  182. content: '当前微信版本过低,无法使用 measureText 功能,请升级到最新微信版本后重试。'
  183. });
  184. } else {
  185. this.drawText(views[i]);
  186. }
  187. } else if (views[i].type === 'rect') {
  188. this.drawRect(views[i]);
  189. }
  190. else if (views[i].type === 'round') {
  191. this.drawRound(views[i]);
  192. }
  193. }
  194. this.ctx.draw(true, () => {
  195. uni.setStorageSync('CACHE_KEYS', this.cache);
  196. this.saveImageToLocal();
  197. })
  198. },
  199. old_drawImage(params) {
  200. // console.log(params)
  201. const {
  202. url,
  203. top = 0,
  204. left = 0,
  205. width = 0,
  206. height = 0,
  207. sx = 0,
  208. sy = 0,
  209. ex = 0,
  210. ey = 0
  211. } = params;
  212. if ('tailor' in params) {
  213. this.ctx.drawImage(url, sx, sy, ex, ey, left, top, width, height);
  214. }
  215. else if (params.round === true) {
  216. this.drawRoundImage(params);
  217. }
  218. else {
  219. this.ctx.drawImage(url, left, top, width, height);
  220. }
  221. },
  222. old_drawRoundImage(params) {
  223. let ctx = this.ctx;
  224. let x = params.left;
  225. let y = params.top;
  226. let w = params.width;
  227. let h = params.height;
  228. let url = params.url;
  229. let r = w / 2;
  230. ctx.save();
  231. ctx.beginPath();
  232. ctx.arc(x + r, y + r, r, 0, 2 * Math.PI);
  233. ctx.setFillStyle(params.background || '#ffffff');
  234. ctx.fill();
  235. ctx.clip();
  236. // 这个地方想要的是头像,简单点就放了个矩形
  237. ctx.drawImage(url, x, y, w, h);
  238. ctx.restore();
  239. },
  240. _drawRadiusRect(params) {
  241. const {
  242. top = 0,
  243. left = 0,
  244. width = 0,
  245. height = 0,
  246. radius = 0,
  247. } = params;
  248. let x = left;
  249. let y = top;
  250. let w = width;
  251. let h = height;
  252. // let bgc = background;
  253. let r = radius;
  254. // let br = radius;
  255. this.ctx.beginPath();
  256. this.ctx.moveTo(x + r, y); // 移动到左上角的点
  257. this.ctx.lineTo(x + w - r, y);
  258. this.ctx.arc(x + w - r, y + r, r, 2 * Math.PI * (3 / 4), 2 * Math.PI * (4 / 4));
  259. this.ctx.lineTo(x + w, y + h - r);
  260. this.ctx.arc(x + w - r, y + h - r, r, 0, 2 * Math.PI * (1 / 4));
  261. this.ctx.lineTo(x + r, y + h);
  262. this.ctx.arc(x + r, y + h - r, r, 2 * Math.PI * (1 / 4), 2 * Math.PI * (2 / 4));
  263. this.ctx.lineTo((x), (y + r));
  264. this.ctx.arc(x + r, y + r, r, 2 * Math.PI * (2 / 4), 2 * Math.PI * (3 / 4));
  265. // this.ctx.moveTo(x + r, y);
  266. // this.ctx.arcTo(x + w, y, x + w, y + h, r);
  267. // this.ctx.arcTo(x + w, y + h, x, y + h, r);
  268. // this.ctx.arcTo(x, y + h, x, y, r);
  269. // this.ctx.arcTo(x, y, x + w, y, r);
  270. },
  271. drawImage(params) {
  272. const {
  273. type = '',
  274. background,
  275. top = 0,
  276. left = 0,
  277. width = 0,
  278. height = 0,
  279. radius = 0,
  280. url = '',
  281. sx = 0,
  282. sy = 0,
  283. ex = 0,
  284. ey = 0
  285. } = params;
  286. let x = left;
  287. let y = top;
  288. let w = width;
  289. let h = height;
  290. let r = radius;
  291. this.ctx.save();
  292. if (radius) {
  293. this.ctx.beginPath();
  294. // if (radius === parseInt(width / 2)) {
  295. // console.log('圆');
  296. // this.ctx.beginPath();
  297. // this.ctx.arc(left + radius, top + radius, radius, 0, 2 * Math.PI);
  298. // this.ctx.setFillStyle(params.background || '#ffffff')
  299. // this.ctx.fill()
  300. // this.ctx.clip();
  301. // this.ctx.drawImage(url, x, y, w, h);
  302. // }
  303. // else {
  304. // }
  305. this._drawRadiusRect(params);
  306. this.ctx.fill();
  307. this.ctx.clip();
  308. }
  309. if ('tailor' in params) {
  310. this.ctx.drawImage(url, sx, sy, ex, ey, left, top, width, height);
  311. }
  312. else {
  313. this.ctx.drawImage(url, left, top, width, height);
  314. }
  315. // this.drawImage(params);
  316. this.ctx.restore();
  317. },
  318. old_drawRound(params) {
  319. let ctx = this.ctx;
  320. let x = params.left;
  321. let y = params.top;
  322. let w = params.width;
  323. let h = params.height;
  324. let r = params.radius;
  325. ctx.save();
  326. ctx.beginPath();
  327. ctx.arc(x + r, y + r, r, 0, 2 * Math.PI);
  328. ctx.setFillStyle(params.background || '#ffffff');
  329. ctx.fill();
  330. ctx.clip();
  331. ctx.restore();
  332. },
  333. drawText(params) {
  334. let {
  335. MaxLineNumber = 2,
  336. breakWord = false,
  337. color = 'black',
  338. content = '',
  339. fontSize = 16,
  340. top = 0,
  341. left = 0,
  342. lineHeight = 20,
  343. textAlign = 'left',
  344. width,
  345. bolder = false,
  346. textDecoration = 'none'
  347. } = params;
  348. if (bolder) {
  349. top -= 0.3;
  350. }
  351. // this.ctx.save();
  352. // this.ctx.beginPath();
  353. // this.ctx.stroke();
  354. let _setStyle = () => {
  355. // this.ctx.save();
  356. this.ctx.closePath();
  357. this.ctx.beginPath();
  358. this.ctx.setTextBaseline('top');
  359. this.ctx.setFillStyle(color);
  360. this.ctx.setFontSize(fontSize);
  361. this.ctx.setTextAlign(textAlign);
  362. }
  363. _setStyle();
  364. if (!breakWord) {
  365. this.ctx.fillText(content, left, top);
  366. this.drawTextLine(left, top, textDecoration, color, fontSize, content);
  367. } else {
  368. let fillText = '';
  369. let fillTop = top;
  370. let lineNum = 1;
  371. for (let i = 0; i < content.length; i++) {
  372. fillText += [content[i]];
  373. // _setStyle();
  374. if (this.ctx.measureText(fillText).width > width) {
  375. if (lineNum === MaxLineNumber) {
  376. if (i !== content.length) {
  377. fillText = fillText.substring(0, fillText.length - 1) + '...';
  378. // _setStyle();
  379. this.ctx.fillText(fillText, left, fillTop);
  380. this.drawTextLine(left, fillTop, textDecoration, color, fontSize, fillText);
  381. fillText = '';
  382. break;
  383. }
  384. }
  385. // _setStyle();
  386. this.ctx.fillText(fillText, left, fillTop);
  387. this.drawTextLine(left, fillTop, textDecoration, color, fontSize, fillText);
  388. fillText = '';
  389. fillTop += lineHeight;
  390. lineNum++;
  391. }
  392. }
  393. // _setStyle();
  394. this.ctx.fillText(fillText, left, fillTop);
  395. this.drawTextLine(left, fillTop, textDecoration, color, fontSize, fillText);
  396. }
  397. // this.ctx.draw();
  398. if (bolder) {
  399. this.drawText({
  400. ...params,
  401. left: left - 0.3,
  402. top: top,
  403. bolder: false,
  404. textDecoration: 'none'
  405. });
  406. }
  407. },
  408. drawTextLine(left, top, textDecoration, color, fontSize, content) {
  409. if (textDecoration === 'underline') {
  410. this.drawRect({
  411. background: color,
  412. top: top + fontSize * 1.2,
  413. left: left - 1,
  414. width: this.ctx.measureText(content).width + 2,
  415. height: 1
  416. });
  417. } else if (textDecoration === 'line-through') {
  418. this.drawRect({
  419. background: color,
  420. top: top + fontSize * 0.6,
  421. left: left - 1,
  422. width: this.ctx.measureText(content).width + 2,
  423. height: 1
  424. });
  425. }
  426. },
  427. drawRect(params) {
  428. // console.log(params)
  429. const { background, top = 0, left = 0, width = 0, height = 0 } = params
  430. this.ctx.save();
  431. this.ctx.setFillStyle(background);
  432. if (params.radius) {
  433. this._drawRadiusRect(params);
  434. this.ctx.fill();
  435. }
  436. else {
  437. this.ctx.setFillStyle(background);
  438. this.ctx.fillRect(left, top, width, height);
  439. }
  440. this.ctx.restore();
  441. },
  442. getImageInfo(url) {
  443. return new Promise((resolve, reject) => {
  444. /* 获得要在画布上绘制的图片 */
  445. if (this.cache[url]) {
  446. resolve(this.cache[url]);
  447. } else {
  448. const objExp = new RegExp(/^http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w- .\/?%&=]*)?/);
  449. if (objExp.test(url)) {
  450. uni.getImageInfo({
  451. src: url,
  452. complete: res => {
  453. if (res.errMsg === 'getImageInfo:ok') {
  454. const img = {
  455. url,
  456. originWidth: res.width,
  457. originHeight: res.height,
  458. localPath: res.path
  459. };
  460. this.cache[url] = img;
  461. // console.log(res);
  462. // resolve(res.path)
  463. resolve(img);
  464. } else {
  465. reject(new Error('getImageInfo fail'));
  466. }
  467. }
  468. });
  469. } else {
  470. this.cache[url] = {
  471. url,
  472. originWidth: 0,
  473. originHeight: 0,
  474. localPath: url
  475. };
  476. resolve(url);
  477. }
  478. }
  479. })
  480. },
  481. saveImageToLocal() {
  482. const { width, height } = this;
  483. uni.canvasToTempFilePath({
  484. x: 0,
  485. y: 0,
  486. width,
  487. height,
  488. canvasId: 'canvasdrawer',
  489. success: res => {
  490. if (res.errMsg === 'canvasToTempFilePath:ok') {
  491. this.isPainting = false;
  492. this.imageList = [];
  493. this.tempFileList = [];
  494. this.$emit('success', {
  495. width,
  496. height,
  497. path: res.tempFilePath
  498. });
  499. }
  500. }
  501. }, this);
  502. }
  503. }
  504. }
  505. </script>
README.md
复制代码
  1. # 海报生成组件
  2. ## 组件使用
  3. > 运行下面demo时,主要图片路径

<template>

复制代码
  1. <view>
  2. <posters-layer
  3. :postersData="postersData"
  4. @success="onSuccessCreatePosters"
  5. @error="onPostersError">
  6. </posters-layer>
  7. <img :src="posterImg.path" />
  8. </view>

</template>
<script>
import postersLayer from '../../components/posters-layer/index';
export default {

复制代码
  1. data() {
  2. return {
  3. postersData: {},
  4. posterImg: {}
  5. };
  6. },
  7. components: {
  8. postersLayer
  9. },
  10. onLoad() {
  11. this.initPostersConfig();
  12. },
  13. methods: {
  14. initPostersConfig() {
  15. const config = {
  16. clear: true,
  17. width: 660,
  18. height: 850,
  19. background: '#ffffff',
  20. views: [
  21. {
  22. type: 'image',
  23. width: 660,
  24. height: 660,
  25. top: 0,
  26. left: 0,
  27. // 封面图,测试的时候填上
  28. url: 'http://127.0.0.1:8080/static/images/test/1.jpg'
  29. },
  30. {
  31. type: 'text',
  32. width: 400,
  33. height: 50,
  34. left: 20,
  35. top: 680,
  36. fontSize: 30,
  37. lineHeight: 40,
  38. bolder: true,
  39. breakWord: true,
  40. content: ' Apple/苹果 iPhone XR 移动联通电信全网通版 苹果xr iphonexr 苹果xr手机 iphone xr',
  41. MaxLineNumber: 2
  42. },
  43. {
  44. type: 'rect',
  45. width: 70,
  46. height: 34,
  47. left: 20,
  48. top: 684,
  49. background: '#ff4201',
  50. radius: 8
  51. },
  52. {
  53. type: 'text',
  54. width: 400,
  55. height: 50,
  56. left: 20,
  57. top: 690,
  58. fontSize: 24,
  59. lineHeight: 40,
  60. bolder: true,
  61. breakWord: true,
  62. content: ' 活动',
  63. color: '#ffffff',
  64. MaxLineNumber: 2
  65. },
  66. {
  67. type: 'text',
  68. width: 400,
  69. left: 20,
  70. top: 770,
  71. fontSize: 54,
  72. bolder: true,
  73. breakWord: true,
  74. content: '¥0.0',
  75. color: '#F40',
  76. MaxLineNumber: 2
  77. },
  78. {
  79. type: 'image',
  80. width: 140,
  81. height: 140,
  82. top: 680,
  83. left: 500,
  84. // 二维码图片路径,测试的时候填上
  85. url: 'http://127.0.0.1:8080/static/images/test/qr.png'
  86. },
  87. ]
  88. };
  89. this.postersData = config;
  90. },
  91. onSuccessCreatePosters(res) {
  92. this.posterImg = res;
  93. },
  94. onPostersError(res) {}
  95. }

}
</script>

复制代码
  1. ## 组件参数解释
  2. ### config字段
  3. | 字段 | 类型 | 必填 | 描述 |
  4. | --------------- | ------------------------ | ---- | ------------------------------------------ |
  5. | width | Number(单位:px) | 是 | 画布宽度 |
  6. | height | Number(单位:px) || 画布高度 |
  7. | background | String | 否 | 画布背景颜色 |
  8. | radius | Number || 圆角 |
  9. | views | Array | 否 | 海报的所有元素 |
  10. ### views字段
  11. #### 文本
  12. | 字段 | 类型 | 必填 | 描述 |
  13. | --------------- | ------------------------ | ---- | ------------------------------------------ |
  14. | type | String || 类型,值:text |
  15. | width | Number(单位:px) | 是 | 宽度 |
  16. | height | Number(单位:px) || 高度 |
  17. | left | Number(单位:px) | 否 | 距离海报左边距 |
  18. | top | Number(单位:px) || 距离海报上边距 |
  19. | fontSize | Number(单位:px) | 否 | 字体大小,默认:16 |
  20. | lineHeight | Number(单位:px) || 行高,默认:20 |
  21. | breakWord | Boolean | 否 | 是否自动换行,默认:false |
  22. | bolder | Boolean || 是否加粗,默认:false |
  23. | textAlign | String | 否 | 对齐方式,可选值:left、center、right,默认:left |
  24. | color | String || 字体颜色 |
  25. | content | String | 是 | 文本内容 |
  26. | MaxLineNumber | Number || 显示多少行,超出省略 |
  27. ### 矩形
  28. | 字段 | 类型 | 必填 | 描述 |
  29. | --------------- | ------------------------ | ---- | ------------------------------------------ |
  30. | type | String | 是 | 类型,值:rect |
  31. | width | Number(单位:px) || 宽度 |
  32. | height | Number(单位:px) | 是 | 高度 |
  33. | left | Number(单位:px) || 距离海报左边距 |
  34. | top | Number(单位:px) | 否 | 距离海报上边距 |
  35. | radius | Number(单位:px) || 圆角半径,如果radius === width / 2,则是个圆,和CSS一样 |
  36. | background | String | 否 | 填充背景色 |
  37. ### 图片
  38. | 字段 | 类型 | 必填 | 描述 |
  39. | --------------- | ------------------------ | ---- | ------------------------------------------ |
  40. | type | String || 类型,值:image |
  41. | tailor | Number(单位:px) | 否 | 裁剪方式,可选值:center |
  42. | radius | Number(单位:px) || 圆角半径,如果radius === width / 2,则是个圆,和CSS一样 |
  43. | width | Number(单位:px) | 是 | 宽度 |
  44. | height | Number(单位:px) || 高度 |
  45. | left | Number(单位:px) | 否 | 距离海报左边距 |
  46. | top | Number(单位:px) || 距离海报上边距 |
  47. | url | String | 是 | 图片路径 |
  48. ## 事件
  49. ### `success` 海报生成成功时触发
  50. ### `error` 海报生成失败时触发

red-bag

index.vue
复制代码
  1. <template>
  2. <view class="wrapper" v-show="redBagShow">
  3. <view class="modal-bg" >
  4. </view>
  5. <view class="rb-wrapper">
  6. <view class="rb-content" @click="handleBtn">
  7. </view>
  8. <view class="close" @click="handleClose">
  9. <image src='../../static/image/close.png' class="img"></image>
  10. </view>
  11. </view>
  12. </view>
  13. </template>
  14. <script>
  15. export default {
  16. name: 'redBag',
  17. components: {},
  18. props: {
  19. },
  20. data() {
  21. return {
  22. redBagShow: true
  23. }
  24. },
  25. watch: {},
  26. computed: {},
  27. methods: {
  28. handleClose() {
  29. this.redBagShow=false
  30. },
  31. handleBtn() {
  32. this.$emit('click')
  33. this.redBagShow=false
  34. }
  35. },
  36. created() {},
  37. mounted() {}
  38. }
  39. </script>
  40. <style lang="scss" scoped>
  41. .modal-bg {
  42. position: absolute;
  43. width: 100%;
  44. height: 100%;
  45. top: 0;
  46. left: 0;
  47. background: rgba(0, 0, 0, 0.4);
  48. }
  49. .rb-wrapper {
  50. position: absolute;
  51. top: 50%;
  52. left: 50%;
  53. width: 60%;
  54. height: 600upx;
  55. transform: translate3d(-50%, -50%, 0);
  56. background: red;
  57. padding: 40upx;
  58. .rb-content{
  59. height: 100%;
  60. }
  61. .close {
  62. position: absolute;
  63. bottom: -120upx;
  64. left: 50%;
  65. margin-left: -30upx;
  66. width: 60upx;
  67. height: 60upx;
  68. border-radius: 50%;
  69. background: #ddd;
  70. .img {
  71. width: 100%;
  72. height: 100%;
  73. }
  74. }
  75. }
  76. </style>

share

share.vue
复制代码
  1. <template>
  2. <view style="width: 100%;height: 300upx;background: #FFFFFF;position: absolute;left:0;bottom: 0;">
  3. <!-- #ifdef H5 || APP-PLUS || MP-ALIPAY -->
  4. <view class="share-pop">
  5. <view class="share-item"
  6. v-for="(item, index) in providerList"
  7. :key="index"
  8. @click="clickHandler(item)">
  9. <image :src="item.img" mode=""></image>
  10. <view class="">{{ item.name }}</view>
  11. </view>
  12. </view>
  13. <view class="button-bottom">
  14. <button class="btn btn-w btn-square" @click="close()">关闭</button>
  15. </view>
  16. <!-- #endif -->
  17. <!-- #ifdef MP-WEIXIN -->
  18. <view class="share-pop">
  19. <view class="share-item">
  20. <button class="btn" open-type="share">
  21. <image src="../../../static/image/share-f.png" mode=""></image>
  22. <view class="">
  23. 分享微信好友
  24. </view>
  25. </button>
  26. </view>
  27. <view class="share-item" @click="createPoster()">
  28. <image src="../../../static/image/poster.png" mode=""></image>
  29. <view class="">生成海报</view>
  30. </view>
  31. </view>
  32. <view class="button-bottom">
  33. <button class="btn btn-w btn-square" @click="close()">关闭</button>
  34. </view>
  35. <!-- #endif -->
  36. <!-- #ifdef MP-ALIPAY -->
  37. <view class="share-pop">
  38. <view class="share-item">
  39. <image src="../../../static/image/share-f.png" mode=""></image>
  40. <button class="btn" open-type="share">分享给好友</button>
  41. </view>
  42. <view class="share-item" @click="createPoster()">
  43. <image src="../../../static/image/poster.png" mode=""></image>
  44. <view class="">生成海报</view>
  45. </view>
  46. </view>
  47. <view class="button-bottom">
  48. <button class="btn btn-w btn-square" @click="close()">关闭</button>
  49. </view>
  50. <!-- #endif -->
  51. </view>
  52. </template>
  53. <script>
  54. import { apiBaseUrl } from '@/config/config.js'
  55. export default {
  56. props: {
  57. // 商品id
  58. goodsId: {
  59. type: Number,
  60. default: 0
  61. },
  62. // 分享的图片
  63. shareImg: {
  64. type: String,
  65. default: ''
  66. },
  67. // 分享标题
  68. shareTitle: {
  69. type: String,
  70. default: ''
  71. },
  72. // 分享内容
  73. shareContent: {
  74. type: String,
  75. default: ''
  76. },
  77. // 分享链接
  78. shareHref: {
  79. type: String,
  80. default: ''
  81. }
  82. },
  83. data () {
  84. return {
  85. shareType: 0,
  86. providerList: [] // 分享通道 包含生成海报
  87. }
  88. },
  89. mounted () {
  90. /**
  91. *
  92. * H5端分享两种 (微信浏览器内引导用户去分享, 其他浏览器)
  93. *
  94. */
  95. // #ifdef H5
  96. if (this.$common.isWeiXinBrowser()) {
  97. // 微信浏览器里面
  98. } else {
  99. // 其他浏览器里面
  100. this.providerList = [
  101. {
  102. name: '分享给好友',
  103. cate: 'share',
  104. id: 'share',
  105. img: '../../../static/image/share-f.png',
  106. sort: 0
  107. },
  108. {
  109. name: '生成海报',
  110. cate: 'poster',
  111. id: 'poster',
  112. img: '../../../static/image/poster.png',
  113. sort: 1
  114. }
  115. ]
  116. }
  117. // #endif
  118. /**
  119. *
  120. * 支付宝小程序中的分享
  121. *
  122. */
  123. // #ifdef MP-ALIPAY
  124. this.providerList = [
  125. {
  126. name: '生成海报',
  127. cate: 'poster',
  128. id: 'poster',
  129. img: '../../../static/image/ic-img.png',
  130. sort: 1
  131. }
  132. ]
  133. // #endif
  134. /**
  135. *
  136. * H5+ 获取分享通道
  137. *
  138. */
  139. // #ifdef APP-PLUS
  140. uni.getProvider({
  141. service: 'share',
  142. success: (e) => {
  143. let data = []
  144. for (let i = 0; i < e.provider.length; i++) {
  145. switch (e.provider[i]) {
  146. case 'weixin':
  147. data.push({
  148. name: '分享到微信好友',
  149. cate: 'share',
  150. id: 'weixin',
  151. img: '../../../static/image/ic-wechat.png',
  152. sort: 0
  153. })
  154. data.push({
  155. name: '分享到微信朋友圈',
  156. cate: 'share',
  157. id: 'weixin',
  158. type:'WXSenceTimeline',
  159. img: '../../../static/image/circle-of-friends.png',
  160. sort:1
  161. })
  162. break;
  163. // case 'sinaweibo':
  164. // data.push({
  165. // name: '分享到新浪微博',
  166. // cate: 'share',
  167. // id: 'sinaweibo',
  168. // img: '../../../static/image/sina-weibo.png',
  169. // sort:2
  170. // })
  171. // break;
  172. case 'qq':
  173. data.push({
  174. name: '分享到QQ',
  175. cate: 'share',
  176. id: 'qq',
  177. img: '../../../static/image/qq.png',
  178. sort:3
  179. })
  180. break;
  181. default:
  182. break;
  183. }
  184. }
  185. data.push({
  186. name: '生成海报',
  187. cate: 'poster',
  188. id: 'poster',
  189. img: '../../../static/image/poster.png',
  190. sort: 5
  191. })
  192. this.providerList = data.sort((x,y) => {
  193. return x.sort - y.sort
  194. });
  195. },
  196. fail: (e) => {
  197. // console.log('获取分享通道失败', e)
  198. }
  199. });
  200. // #endif
  201. },
  202. methods: {
  203. // 关闭弹出层
  204. close () {
  205. this.$emit('close')
  206. },
  207. // 点击操作
  208. clickHandler (e) {
  209. if (e.cate === 'poster') {
  210. this.createPoster()
  211. } else {
  212. // 去分享
  213. this.share(e)
  214. }
  215. },
  216. // 生成海报
  217. createPoster () {
  218. let data = {
  219. id: this.goodsId,
  220. type: 1
  221. }
  222. let pages = getCurrentPages()
  223. let page = pages[pages.length - 1]
  224. // #ifdef H5
  225. data.source = 1;
  226. data.return_url = apiBaseUrl + 'wap/pages/share/jump';
  227. // #endif
  228. // #ifdef MP-WEIXIN
  229. data.source = 2;
  230. data.return_url = 'pages/share/jump'; //page.route;
  231. // #endif
  232. // #ifdef MP-ALIPAY
  233. data.source = 3;
  234. data.return_url = 'pages/share/jump';//page.__proto__.route;
  235. // #endif
  236. let userToken = this.$db.get('userToken')
  237. if (userToken) {
  238. data.user_id = userToken
  239. }
  240. this.$api.createPoster(data, res => {
  241. if (res.status) {
  242. this.close()
  243. this.$common.navigateTo('/pages/share?poster=' + res.data)
  244. } else {
  245. this.$common.errorToShow(res.msg)
  246. }
  247. })
  248. },
  249. // 分享操作
  250. async share (e) {
  251. // console.log('分享通道:'+ e.id +'; 分享类型:' + this.shareType);
  252. // if(!this.shareContent){
  253. // uni.showModal({
  254. // content:'分享内容不能为空',
  255. // showCancel:false
  256. // })
  257. // return;
  258. // }
  259. //
  260. // if(!this.shareImg){
  261. // uni.showModal({
  262. // content:'分享图片不能为空',
  263. // showCancel:false
  264. // })
  265. // return;
  266. // }
  267. // #ifdef APP-PLUS
  268. let shareOPtions = {
  269. provider: e.id,
  270. scene: e.type && e.type === 'WXSenceTimeline' ? 'WXSenceTimeline' : 'WXSceneSession', //WXSceneSession”分享到聊天界面,“WXSenceTimeline”分享到朋友圈,“WXSceneFavorite”分享到微信收藏
  271. type: this.shareType,
  272. success: (e) => {
  273. uni.showModal({
  274. content: '分享成功',
  275. showCancel:false
  276. })
  277. },
  278. fail: (e) => {
  279. uni.showModal({
  280. content: e.errMsg,
  281. showCancel:false
  282. })
  283. },
  284. complete:function(){
  285. // console.log('分享操作结束!')
  286. }
  287. }
  288. shareOPtions.summary = this.shareContent ? this.shareContent : ''
  289. shareOPtions.imageUrl = this.shareImg ? this.shareImg : ''
  290. shareOPtions.title = this.shareTitle ? this.shareTitle : ''
  291. shareOPtions.href = this.shareHref ? this.shareHref : ''
  292. if(shareOPtions.type === 0 && plus.os.name === 'iOS'){//如果是图文分享,且是ios平台,则压缩图片
  293. shareOPtions.imageUrl = await this.compress()
  294. }
  295. if(shareOPtions.type === 1 && shareOPtions.provider === 'qq'){//如果是分享文字到qq,则必须加上href和title
  296. shareOPtions.href = this.shareHref
  297. shareOPtions.title = this.shareTitle
  298. }
  299. uni.share(shareOPtions);
  300. // #endif
  301. },
  302. // 压缩图片 图文分享要求分享图片大小不能超过20Kb
  303. compress () {
  304. // console.log('开始压缩');
  305. let img = this.shareImg;
  306. return new Promise((res) => {
  307. var localPath = plus.io.convertAbsoluteFileSystem(img.replace('file://', ''));
  308. // console.log('after' + localPath);
  309. // 压缩size
  310. plus.io.resolveLocalFileSystemURL(localPath, (entry) => {
  311. entry.file((file) => {// 可通过entry对象操作图片
  312. // console.log('getFile:' + JSON.stringify(file));
  313. if(file.size > 20480) {// 压缩后size 大于20Kb
  314. plus.zip.compressImage({
  315. src: img,
  316. dst: img.replace('.jpg', '2222.jpg').replace('.JPG', '2222.JPG'),
  317. width: '10%',
  318. height: '10%',
  319. quality: 1,
  320. overwrite: true
  321. }, (event) => {
  322. // console.log('success zip****' + event.size);
  323. let newImg = img.replace('.jpg', '2222.jpg').replace('.JPG', '2222.JPG');
  324. res(newImg);
  325. }, function(error) {
  326. uni.showModal({
  327. content:'分享图片太大,需要请重新选择图片!',
  328. showCancel:false
  329. })
  330. });
  331. }
  332. });
  333. }, (e) => {
  334. // console.log('Resolve file URL failed: ' + e.message);
  335. uni.showModal({
  336. content:'分享图片太大,需要请重新选择图片!',
  337. showCancel:false
  338. })
  339. });
  340. })
  341. }
  342. }
  343. }
  344. </script>
  345. <style>
  346. .share-pop{
  347. height: 300upx;
  348. width: 100%;
  349. display: flex;
  350. }
  351. .share-item{
  352. flex: 1;
  353. text-align: center;
  354. font-size: 26upx;
  355. color: #333;
  356. padding: 20upx 0;
  357. }
  358. .share-item image{
  359. width: 80upx;
  360. height: 80upx;
  361. margin: 20upx;
  362. }
  363. .share-item .btn{
  364. line-height: 1;
  365. display: block;
  366. font-size: 26upx;
  367. background-color: #fff;
  368. }
  369. </style>
shareByAli.vue
复制代码
  1. <template>
  2. <view style="width: 100%;height: 300upx;background: #FFFFFF;position: absolute;left:0;bottom: 0;">
  3. <view class="share-pop">
  4. <view class="share-item">
  5. <button class="btn" open-type="share">
  6. <image src="../../../static/image/share-f.png" mode=""></image>
  7. <button class="btn" open-type="share">分享给好友</button>
  8. </button>
  9. </view>
  10. <view class="share-item" @click="createPoster()">
  11. <image src="../../../static/image/poster.png" mode=""></image>
  12. <view class="">生成海报</view>
  13. </view>
  14. </view>
  15. <view class="button-bottom">
  16. <button class="btn btn-w btn-square" @click="close()">关闭</button>
  17. </view>
  18. </view>
  19. </template>
  20. <script>
  21. import { apiBaseUrl } from '@/config/config.js'
  22. export default {
  23. props: {
  24. // 商品id
  25. goodsId: {
  26. type: Number,
  27. default: 0
  28. },
  29. // 分享的图片
  30. shareImg: {
  31. type: String,
  32. default: ''
  33. },
  34. // 分享标题
  35. shareTitle: {
  36. type: String,
  37. default: ''
  38. },
  39. // 分享内容
  40. shareContent: {
  41. type: String,
  42. default: ''
  43. },
  44. // 分享链接
  45. shareHref: {
  46. type: String,
  47. default: ''
  48. },
  49. //分享类型
  50. shareType:{
  51. type:Number,
  52. default:1
  53. },
  54. //拼团id
  55. groupId:{
  56. type:Number,
  57. default:0
  58. },
  59. //拼团的团队id
  60. teamId:{
  61. type:Number,
  62. default:0
  63. }
  64. },
  65. data () {
  66. return {
  67. shareType: 0,
  68. providerList: [] // 分享通道 包含生成海报
  69. }
  70. },
  71. mounted () {
  72. },
  73. methods: {
  74. // 关闭弹出层
  75. close () {
  76. this.$emit('close')
  77. },
  78. // 生成海报
  79. createPoster () {
  80. let data = {
  81. id: this.goodsId,
  82. type: this.shareType,
  83. group_id :this.groupId,
  84. team_id :this.teamId,
  85. }
  86. let pages = getCurrentPages()
  87. let page = pages[pages.length - 1]
  88. data.source = 3;
  89. data.return_url = 'pages/share/jump';//page.__proto__.route;
  90. let userToken = this.$db.get('userToken')
  91. if (userToken) {
  92. data.token = userToken
  93. }
  94. this.$api.createPoster(data, res => {
  95. if (res.status) {
  96. this.close()
  97. this.$common.navigateTo('/pages/share?poster=' + res.data)
  98. } else {
  99. this.$common.errorToShow(res.msg)
  100. }
  101. })
  102. },
  103. // 分享操作
  104. async share (e) {
  105. }
  106. }
  107. }
  108. </script>
  109. <style>
  110. .share-pop{
  111. height: 300upx;
  112. width: 100%;
  113. display: flex;
  114. }
  115. .share-item{
  116. flex: 1;
  117. text-align: center;
  118. font-size: 26upx;
  119. color: #333;
  120. padding: 20upx 0;
  121. }
  122. .share-item image{
  123. width: 80upx;
  124. height: 80upx;
  125. margin: 20upx;
  126. }
  127. .share-item .btn{
  128. line-height: 1;
  129. display: block;
  130. font-size: 26upx;
  131. background-color: #fff;
  132. }
  133. </style>
shareByApp.vue
复制代码
  1. <template>
  2. <view style="width: 100%;height: 300upx;background: #FFFFFF;position: absolute;left:0;bottom: 0;">
  3. <view class="share-pop">
  4. <view class="share-item"
  5. v-for="(item, index) in providerList"
  6. :key="index"
  7. @click="clickHandler(item)">
  8. <image :src="item.img" mode=""></image>
  9. <view class="">{{ item.name }}</view>
  10. </view>
  11. </view>
  12. <view class="button-bottom">
  13. <button class="btn btn-w btn-square" @click="close()">关闭</button>
  14. </view>
  15. </view>
  16. </template>
  17. <script>
  18. import { apiBaseUrl } from '@/config/config.js'
  19. export default {
  20. props: {
  21. // 商品id
  22. goodsId: {
  23. type: Number,
  24. default: 0
  25. },
  26. // 分享的图片
  27. shareImg: {
  28. type: String,
  29. default: ''
  30. },
  31. // 分享标题
  32. shareTitle: {
  33. type: String,
  34. default: ''
  35. },
  36. // 分享内容
  37. shareContent: {
  38. type: String,
  39. default: ''
  40. },
  41. // 分享链接
  42. shareHref: {
  43. type: String,
  44. default: ''
  45. }
  46. },
  47. data () {
  48. return {
  49. shareType: 0,
  50. providerList: [] // 分享通道 包含生成海报
  51. }
  52. },
  53. mounted () {
  54. /**
  55. *
  56. * H5+ 获取分享通道
  57. *
  58. */
  59. uni.getProvider({
  60. service: 'share',
  61. success: (e) => {
  62. let data = []
  63. for (let i = 0; i < e.provider.length; i++) {
  64. switch (e.provider[i]) {
  65. case 'weixin':
  66. data.push({
  67. name: '分享到微信好友',
  68. cate: 'share',
  69. id: 'weixin',
  70. img: '../../../static/image/ic-wechat.png',
  71. sort: 0
  72. })
  73. data.push({
  74. name: '分享到微信朋友圈',
  75. cate: 'share',
  76. id: 'weixin',
  77. type:'WXSenceTimeline',
  78. img: '../../../static/image/circle-of-friends.png',
  79. sort:1
  80. })
  81. break;
  82. // case 'sinaweibo':
  83. // data.push({
  84. // name: '分享到新浪微博',
  85. // cate: 'share',
  86. // id: 'sinaweibo',
  87. // img: '../../../static/image/sina-weibo.png',
  88. // sort:2
  89. // })
  90. // break;
  91. case 'qq':
  92. data.push({
  93. name: '分享到QQ',
  94. cate: 'share',
  95. id: 'qq',
  96. img: '../../../static/image/qq.png',
  97. sort:3
  98. })
  99. break;
  100. default:
  101. break;
  102. }
  103. }
  104. data.push({
  105. name: '生成海报',
  106. cate: 'poster',
  107. id: 'poster',
  108. img: '../../../static/image/poster.png',
  109. sort: 5
  110. })
  111. this.providerList = data.sort((x,y) => {
  112. return x.sort - y.sort
  113. });
  114. },
  115. fail: (e) => {
  116. // console.log('获取分享通道失败', e)
  117. }
  118. });
  119. },
  120. methods: {
  121. // 关闭弹出层
  122. close () {
  123. this.$emit('close')
  124. },
  125. // 点击操作
  126. clickHandler (e) {
  127. if (e.cate === 'poster') {
  128. this.createPoster()
  129. } else {
  130. // 去分享
  131. this.share(e)
  132. }
  133. },
  134. // 生成海报
  135. createPoster () {
  136. let data = {
  137. id: this.goodsId,
  138. type: 1
  139. }
  140. let pages = getCurrentPages()
  141. let page = pages[pages.length - 1]
  142. data.source = 1;
  143. data.return_url = apiBaseUrl + 'wap/' + page.route;
  144. let userToken = this.$db.get('userToken')
  145. if (userToken) {
  146. data.token = userToken
  147. }
  148. this.$api.createPoster(data, res => {
  149. if (res.status) {
  150. this.close()
  151. this.$common.navigateTo('/pages/share?poster=' + res.data)
  152. } else {
  153. this.$common.errorToShow(res.msg)
  154. }
  155. })
  156. },
  157. // 分享操作
  158. async share (e) {
  159. // console.log('分享通道:'+ e.id +'; 分享类型:' + this.shareType);
  160. // if(!this.shareContent){
  161. // uni.showModal({
  162. // content:'分享内容不能为空',
  163. // showCancel:false
  164. // })
  165. // return;
  166. // }
  167. //
  168. // if(!this.shareImg){
  169. // uni.showModal({
  170. // content:'分享图片不能为空',
  171. // showCancel:false
  172. // })
  173. // return;
  174. // }
  175. let shareOPtions = {
  176. provider: e.id,
  177. scene: e.type && e.type === 'WXSenceTimeline' ? 'WXSenceTimeline' : 'WXSceneSession', //WXSceneSession”分享到聊天界面,“WXSenceTimeline”分享到朋友圈,“WXSceneFavorite”分享到微信收藏
  178. type: this.shareType,
  179. success: (e) => {
  180. uni.showModal({
  181. content: '分享成功',
  182. showCancel:false
  183. })
  184. },
  185. fail: (e) => {
  186. uni.showModal({
  187. content: e.errMsg,
  188. showCancel:false
  189. })
  190. },
  191. complete:function(){
  192. // console.log('分享操作结束!')
  193. }
  194. }
  195. shareOPtions.summary = this.shareContent ? this.shareContent : ''
  196. shareOPtions.imageUrl = this.shareImg ? this.shareImg : ''
  197. shareOPtions.title = this.shareTitle ? this.shareTitle : ''
  198. shareOPtions.href = this.shareHref ? this.shareHref : ''
  199. if(shareOPtions.type === 0 && plus.os.name === 'iOS'){//如果是图文分享,且是ios平台,则压缩图片
  200. shareOPtions.imageUrl = await this.compress()
  201. }
  202. if(shareOPtions.type === 1 && shareOPtions.provider === 'qq'){//如果是分享文字到qq,则必须加上href和title
  203. shareOPtions.href = this.shareHref
  204. shareOPtions.title = this.shareTitle
  205. }
  206. uni.share(shareOPtions);
  207. },
  208. // 压缩图片 图文分享要求分享图片大小不能超过20Kb
  209. compress () {
  210. // console.log('开始压缩');
  211. let img = this.shareImg;
  212. return new Promise((res) => {
  213. var localPath = plus.io.convertAbsoluteFileSystem(img.replace('file://', ''));
  214. // console.log('after' + localPath);
  215. // 压缩size
  216. plus.io.resolveLocalFileSystemURL(localPath, (entry) => {
  217. entry.file((file) => {// 可通过entry对象操作图片
  218. // console.log('getFile:' + JSON.stringify(file));
  219. if(file.size > 20480) {// 压缩后size 大于20Kb
  220. plus.zip.compressImage({
  221. src: img,
  222. dst: img.replace('.jpg', '2222.jpg').replace('.JPG', '2222.JPG'),
  223. width: '10%',
  224. height: '10%',
  225. quality: 1,
  226. overwrite: true
  227. }, (event) => {
  228. // console.log('success zip****' + event.size);
  229. let newImg = img.replace('.jpg', '2222.jpg').replace('.JPG', '2222.JPG');
  230. res(newImg);
  231. }, function(error) {
  232. uni.showModal({
  233. content:'分享图片太大,需要请重新选择图片!',
  234. showCancel:false
  235. })
  236. });
  237. }
  238. });
  239. }, (e) => {
  240. // console.log('Resolve file URL failed: ' + e.message);
  241. uni.showModal({
  242. content:'分享图片太大,需要请重新选择图片!',
  243. showCancel:false
  244. })
  245. });
  246. })
  247. }
  248. }
  249. }
  250. </script>
  251. <style>
  252. .share-pop{
  253. height: 300upx;
  254. width: 100%;
  255. display: flex;
  256. }
  257. .share-item{
  258. flex: 1;
  259. text-align: center;
  260. font-size: 26upx;
  261. color: #333;
  262. padding: 20upx 0;
  263. }
  264. .share-item image{
  265. width: 80upx;
  266. height: 80upx;
  267. margin: 20upx;
  268. }
  269. .share-item .btn{
  270. line-height: 1;
  271. display: block;
  272. font-size: 26upx;
  273. background-color: #fff;
  274. }
  275. </style>
shareByh5.vue
复制代码
  1. <template>
  2. <view style="width: 100%;height: 300upx;background: #FFFFFF;position: absolute;left:0;bottom: 0;">
  3. <view class="share-pop">
  4. <view class="share-item" @click="copyUrl()">
  5. <image src="../../../static/image/share-f.png" mode=""></image>
  6. <view class="">复制链接</view>
  7. </view>
  8. <view class="share-item" @click="createPoster()">
  9. <image src="../../../static/image/poster.png" mode=""></image>
  10. <view class="">生成海报</view>
  11. </view>
  12. </view>
  13. <view class="button-bottom">
  14. <button class="btn btn-w btn-square" @click="close()">关闭</button>
  15. </view>
  16. </view>
  17. </template>
  18. <script>
  19. import { apiBaseUrl } from '@/config/config.js'
  20. export default {
  21. props: {
  22. // 商品id
  23. goodsId: {
  24. type: Number,
  25. default: 0
  26. },
  27. // 分享的图片
  28. shareImg: {
  29. type: String,
  30. default: ''
  31. },
  32. // 分享标题
  33. shareTitle: {
  34. type: String,
  35. default: ''
  36. },
  37. // 分享内容
  38. shareContent: {
  39. type: String,
  40. default: ''
  41. },
  42. // 分享链接
  43. shareHref: {
  44. type: String,
  45. default: ''
  46. },
  47. //分享类型
  48. shareType:{
  49. type:Number,
  50. default:1
  51. },
  52. //拼团id
  53. groupId:{
  54. type:Number,
  55. default:0
  56. },
  57. //拼团的团队id
  58. teamId:{
  59. type:Number,
  60. default:0
  61. }
  62. },
  63. mounted () {
  64. /**
  65. *
  66. * H5端分享两种 (微信浏览器内引导用户去分享, 其他浏览器)
  67. *
  68. */
  69. },
  70. methods: {
  71. // 关闭弹出层
  72. close () {
  73. this.$emit('close')
  74. },
  75. // 生成海报
  76. createPoster () {
  77. let data = {
  78. id: this.goodsId,
  79. type: this.shareType,
  80. group_id :this.groupId,
  81. team_id :this.teamId,
  82. }
  83. data.return_url = apiBaseUrl + 'wap/pages/share/jump';
  84. let userToken = this.$db.get('userToken')
  85. if (userToken) {
  86. data.token = userToken
  87. }
  88. this.$api.createPoster(data, res => {
  89. if (res.status) {
  90. this.close()
  91. this.$common.navigateTo('/pages/share?poster=' + res.data)
  92. } else {
  93. this.$common.errorToShow(res.msg)
  94. }
  95. });
  96. },
  97. copyUrl () {
  98. let data = {
  99. id: this.goodsId,
  100. type: this.shareType,
  101. group_id :this.groupId,
  102. team_id :this.teamId,
  103. }
  104. data.return_url = apiBaseUrl + 'wap/pages/share/jump';
  105. let userToken = this.$db.get('userToken')
  106. if (userToken) {
  107. data.token = userToken
  108. }
  109. let _this = this;
  110. _this.$api.createShareUrl(data, res => {
  111. if(res.status) {
  112. //todo::要复制的内容是 res.data
  113. uni.setClipboardData({
  114. data:res.data,
  115. success:function(data){
  116. _this.$common.successToShow('复制成功');
  117. },
  118. fail:function(err){
  119. _this.$common.errorToShow('复制分享URL失败');
  120. }
  121. })
  122. } else {
  123. _this.$common.errorToShow('复制分享URL失败');
  124. }
  125. });
  126. },
  127. // 分享操作
  128. share () {
  129. // h5分享 判断是否是微信浏览器 引导用户完成分享操作
  130. // 其他浏览器的分享
  131. }
  132. }
  133. }
  134. </script>
  135. <style>
  136. .share-pop{
  137. height: 300upx;
  138. width: 100%;
  139. display: flex;
  140. }
  141. .share-item{
  142. flex: 1;
  143. text-align: center;
  144. font-size: 26upx;
  145. color: #333;
  146. padding: 20upx 0;
  147. }
  148. .share-item image{
  149. width: 80upx;
  150. height: 80upx;
  151. margin: 20upx;
  152. }
  153. .share-item .btn{
  154. line-height: 1;
  155. display: block;
  156. font-size: 26upx;
  157. background-color: #fff;
  158. }
  159. </style>
shareByWx.vue
复制代码
  1. <template>
  2. <view style="width: 100%;height: 300upx;background: #FFFFFF;position: absolute;left:0;bottom: 0;">
  3. <view class="share-pop">
  4. <view class="share-item">
  5. <button class="btn" open-type="share">
  6. <image src="../../../static/image/share-f.png" mode=""></image>
  7. <view class="">
  8. 分享微信好友
  9. </view>
  10. </button>
  11. </view>
  12. <view class="share-item" @click="createPoster()">
  13. <image src="../../../static/image/poster.png" mode=""></image>
  14. <view class="">生成海报</view>
  15. </view>
  16. </view>
  17. <view class="button-bottom">
  18. <button class="btn btn-w btn-square" @click="close()">关闭</button>
  19. </view>
  20. </view>
  21. </template>
  22. <script>
  23. import { apiBaseUrl } from '@/config/config.js'
  24. export default {
  25. props: {
  26. // 商品id
  27. goodsId: {
  28. type: Number,
  29. default: 0
  30. },
  31. // 分享的图片
  32. shareImg: {
  33. type: String,
  34. default: ''
  35. },
  36. // 分享标题
  37. shareTitle: {
  38. type: String,
  39. default: ''
  40. },
  41. // 分享内容
  42. shareContent: {
  43. type: String,
  44. default: ''
  45. },
  46. // 分享链接
  47. shareHref: {
  48. type: String,
  49. default: ''
  50. },
  51. //分享类型
  52. shareType:{
  53. type:Number,
  54. default:1
  55. },
  56. //拼团id
  57. groupId:{
  58. type:Number,
  59. default:0
  60. },
  61. //拼团的团队id
  62. teamId:{
  63. type:Number,
  64. default:0
  65. }
  66. },
  67. data () {
  68. return {
  69. shareType: 0,
  70. providerList: [] // 分享通道 包含生成海报
  71. }
  72. },
  73. mounted () {
  74. },
  75. methods: {
  76. // 关闭弹出层
  77. close () {
  78. this.$emit('close')
  79. },
  80. // 生成海报
  81. createPoster () {
  82. let data = {
  83. id: this.goodsId,
  84. type: this.shareType,
  85. group_id :this.groupId,
  86. team_id :this.teamId,
  87. }
  88. let pages = getCurrentPages()
  89. let page = pages[pages.length - 1]
  90. data.source = 2;
  91. data.return_url = 'pages/share/jump';//page.route;
  92. let userToken = this.$db.get('userToken')
  93. if (userToken) {
  94. data.token = userToken
  95. }
  96. this.$api.createPoster(data, res => {
  97. if (res.status) {
  98. this.close()
  99. this.$common.navigateTo('/pages/share?poster=' + res.data)
  100. } else {
  101. this.$common.errorToShow(res.msg)
  102. }
  103. })
  104. }
  105. }
  106. }
  107. </script>
  108. <style>
  109. .share-pop{
  110. height: 300upx;
  111. width: 100%;
  112. display: flex;
  113. }
  114. .share-item{
  115. flex: 1;
  116. text-align: center;
  117. font-size: 26upx;
  118. color: #333;
  119. padding: 20upx 0;
  120. }
  121. .share-item image{
  122. width: 80upx;
  123. height: 80upx;
  124. margin: 20upx;
  125. }
  126. .share-item .btn{
  127. line-height: 1;
  128. display: block;
  129. font-size: 26upx;
  130. background-color: #fff;
  131. }
  132. </style>

spec

spec.vue
复制代码
  1. <template>
  2. <view>
  3. <view class="goods-specs" v-for="(item, index) in spesData" :key="index">
  4. <text class="pop-m-title">{{ index }}</text>
  5. <view class="pop-m-bd">
  6. <view :class="spes.cla" v-for="(spes, key) in item" :key="key" @click="specChangeSpes(index, key)">
  7. {{ spes.name }}
  8. </view>
  9. </view>
  10. </view>
  11. </view>
  12. </template>
  13. <script>
  14. export default {
  15. name: "spec",
  16. props: {
  17. // 默认picker选中项索引
  18. spesData: {
  19. required: true
  20. }
  21. },
  22. methods: {
  23. specChangeSpes(v, k){
  24. let newData = {
  25. v: v,
  26. k: k
  27. }
  28. this.$emit("changeSpes", newData);
  29. }
  30. }
  31. }
  32. </script>
  33. <style>
  34. .goods-specs,.goods-number{
  35. padding: 26upx;
  36. border-top: 1px solid #f3f3f3;
  37. }
  38. .goods-specs:first-child{
  39. border: none;
  40. }
  41. .pop-m-title{
  42. margin-right: 10upx;
  43. color: #666;
  44. }
  45. .pop-m-item{
  46. display: inline-block;
  47. float: left;
  48. padding: 6upx 16upx;
  49. background-color: #fff;
  50. color: #333;
  51. margin-right: 16upx;
  52. margin-bottom: 10upx;
  53. }
  54. .pop-m-bd{
  55. overflow: hidden;
  56. margin-top: 10upx;
  57. }
  58. .selected{
  59. border: 2upx solid #333;
  60. background-color: #333;
  61. color: #fff;
  62. }
  63. .not-selected{
  64. border: 2upx solid #ccc;
  65. }
  66. .none{
  67. border: 2upx dashed #ccc;
  68. color: #888;
  69. }
  70. </style>

tki-qrcode

qrcode.js
复制代码
  1. //---------------------------------------------------------------------
  2. //
  3. // QR Code Generator for JavaScript
  4. //
  5. // Copyright (c) 2009 Kazuhiko Arase
  6. //
  7. // URL: [url=http://www.d-project.com/]http://www.d-project.com/[/url]
  8. //
  9. // Licensed under the MIT license:
  10. // [url=http://www.opensource.org/licenses/mit-license.php]http://www.opensource.org/licenses/mit-license.php[/url]
  11. //
  12. // The word 'QR Code' is registered trademark of
  13. // DENSO WAVE INCORPORATED
  14. // [url=http://www.denso-wave.com/qrcode/faqpatent-e.html]http://www.denso-wave.com/qrcode/faqpatent-e.html[/url]
  15. //
  16. //---------------------------------------------------------------------
  17. //---------------------------------------------------------------------
  18. // qrcode
  19. //代码第1588行为补充代码
  20. //修改人:chenxing
  21. //2017-02-27 16:21:32
  22. //---------------------------------------------------------------------
  23. /**
  24. * qrcode
  25. * @param typeNumber 1 to 40
  26. * @param errorCorrectLevel 'L','M','Q','H'
  27. */
  28. var qrcode = function(typeNumber, errorCorrectLevel) {
  29. var PAD0 = 0xEC;
  30. var PAD1 = 0x11;
  31. var _typeNumber = typeNumber;
  32. var _errorCorrectLevel = QRErrorCorrectLevel[errorCorrectLevel];
  33. var _modules = null;
  34. var _moduleCount = 0;
  35. var _dataCache = null;
  36. var _dataList = new Array();
  37. var _this = {};
  38. var makeImpl = function(test, maskPattern) {
  39. _moduleCount = _typeNumber * 4 + 17;
  40. _modules = function(moduleCount) {
  41. var modules = new Array(moduleCount);
  42. for (var row = 0; row < moduleCount; row += 1) {
  43. modules[row] = new Array(moduleCount);
  44. for (var col = 0; col < moduleCount; col += 1) {
  45. modules[row][col] = null;
  46. }
  47. }
  48. return modules;
  49. }(_moduleCount);
  50. setupPositionProbePattern(0, 0);
  51. setupPositionProbePattern(_moduleCount - 7, 0);
  52. setupPositionProbePattern(0, _moduleCount - 7);
  53. setupPositionAdjustPattern();
  54. setupTimingPattern();
  55. setupTypeInfo(test, maskPattern);
  56. if (_typeNumber >= 7) {
  57. setupTypeNumber(test);
  58. }
  59. if (_dataCache == null) {
  60. _dataCache = createData(_typeNumber, _errorCorrectLevel, _dataList);
  61. }
  62. mapData(_dataCache, maskPattern);
  63. };
  64. var setupPositionProbePattern = function(row, col) {
  65. for (var r = -1; r <= 7; r += 1) {
  66. if (row + r <= -1 || _moduleCount <= row + r) continue;
  67. for (var c = -1; c <= 7; c += 1) {
  68. if (col + c <= -1 || _moduleCount <= col + c) continue;
  69. if ( (0 <= r && r <= 6 && (c == 0 || c == 6) )
  70. || (0 <= c && c <= 6 && (r == 0 || r == 6) )
  71. || (2 <= r && r <= 4 && 2 <= c && c <= 4) ) {
  72. _modules[row + r][col + c] = true;
  73. } else {
  74. _modules[row + r][col + c] = false;
  75. }
  76. }
  77. }
  78. };
  79. var getBestMaskPattern = function() {
  80. var minLostPoint = 0;
  81. var pattern = 0;
  82. for (var i = 0; i < 8; i += 1) {
  83. makeImpl(true, i);
  84. var lostPoint = QRUtil.getLostPoint(_this);
  85. if (i == 0 || minLostPoint > lostPoint) {
  86. minLostPoint = lostPoint;
  87. pattern = i;
  88. }
  89. }
  90. return pattern;
  91. };
  92. var setupTimingPattern = function() {
  93. for (var r = 8; r < _moduleCount - 8; r += 1) {
  94. if (_modules[r][6] != null) {
  95. continue;
  96. }
  97. _modules[r][6] = (r % 2 == 0);
  98. }
  99. for (var c = 8; c < _moduleCount - 8; c += 1) {
  100. if (_modules[6][c] != null) {
  101. continue;
  102. }
  103. _modules[6][c] = (c % 2 == 0);
  104. }
  105. };
  106. var setupPositionAdjustPattern = function() {
  107. var pos = QRUtil.getPatternPosition(_typeNumber);
  108. for (var i = 0; i < pos.length; i += 1) {
  109. for (var j = 0; j < pos.length; j += 1) {
  110. var row = pos[i];
  111. var col = pos[j];
  112. if (_modules[row][col] != null) {
  113. continue;
  114. }
  115. for (var r = -2; r <= 2; r += 1) {
  116. for (var c = -2; c <= 2; c += 1) {
  117. if (r == -2 || r == 2 || c == -2 || c == 2
  118. || (r == 0 && c == 0) ) {
  119. _modules[row + r][col + c] = true;
  120. } else {
  121. _modules[row + r][col + c] = false;
  122. }
  123. }
  124. }
  125. }
  126. }
  127. };
  128. var setupTypeNumber = function(test) {
  129. var bits = QRUtil.getBCHTypeNumber(_typeNumber);
  130. for (var i = 0; i < 18; i += 1) {
  131. var mod = (!test && ( (bits >> i) & 1) == 1);
  132. _modules[Math.floor(i / 3)][i % 3 + _moduleCount - 8 - 3] = mod;
  133. }
  134. for (var i = 0; i < 18; i += 1) {
  135. var mod = (!test && ( (bits >> i) & 1) == 1);
  136. _modules[i % 3 + _moduleCount - 8 - 3][Math.floor(i / 3)] = mod;
  137. }
  138. };
  139. var setupTypeInfo = function(test, maskPattern) {
  140. var data = (_errorCorrectLevel << 3) | maskPattern;
  141. var bits = QRUtil.getBCHTypeInfo(data);
  142. // vertical
  143. for (var i = 0; i < 15; i += 1) {
  144. var mod = (!test && ( (bits >> i) & 1) == 1);
  145. if (i < 6) {
  146. _modules[i][8] = mod;
  147. } else if (i < 8) {
  148. _modules[i + 1][8] = mod;
  149. } else {
  150. _modules[_moduleCount - 15 + i][8] = mod;
  151. }
  152. }
  153. // horizontal
  154. for (var i = 0; i < 15; i += 1) {
  155. var mod = (!test && ( (bits >> i) & 1) == 1);
  156. if (i < 8) {
  157. _modules[8][_moduleCount - i - 1] = mod;
  158. } else if (i < 9) {
  159. _modules[8][15 - i - 1 + 1] = mod;
  160. } else {
  161. _modules[8][15 - i - 1] = mod;
  162. }
  163. }
  164. // fixed module
  165. _modules[_moduleCount - 8][8] = (!test);
  166. };
  167. var mapData = function(data, maskPattern) {
  168. var inc = -1;
  169. var row = _moduleCount - 1;
  170. var bitIndex = 7;
  171. var byteIndex = 0;
  172. var maskFunc = QRUtil.getMaskFunction(maskPattern);
  173. for (var col = _moduleCount - 1; col > 0; col -= 2) {
  174. if (col == 6) col -= 1;
  175. while (true) {
  176. for (var c = 0; c < 2; c += 1) {
  177. if (_modules[row][col - c] == null) {
  178. var dark = false;
  179. if (byteIndex < data.length) {
  180. dark = ( ( (data[byteIndex] >>> bitIndex) & 1) == 1);
  181. }
  182. var mask = maskFunc(row, col - c);
  183. if (mask) {
  184. dark = !dark;
  185. }
  186. _modules[row][col - c] = dark;
  187. bitIndex -= 1;
  188. if (bitIndex == -1) {
  189. byteIndex += 1;
  190. bitIndex = 7;
  191. }
  192. }
  193. }
  194. row += inc;
  195. if (row < 0 || _moduleCount <= row) {
  196. row -= inc;
  197. inc = -inc;
  198. break;
  199. }
  200. }
  201. }
  202. };
  203. var createBytes = function(buffer, rsBlocks) {
  204. var offset = 0;
  205. var maxDcCount = 0;
  206. var maxEcCount = 0;
  207. var dcdata = new Array(rsBlocks.length);
  208. var ecdata = new Array(rsBlocks.length);
  209. for (var r = 0; r < rsBlocks.length; r += 1) {
  210. var dcCount = rsBlocks[r].dataCount;
  211. var ecCount = rsBlocks[r].totalCount - dcCount;
  212. maxDcCount = Math.max(maxDcCount, dcCount);
  213. maxEcCount = Math.max(maxEcCount, ecCount);
  214. dcdata[r] = new Array(dcCount);
  215. for (var i = 0; i < dcdata[r].length; i += 1) {
  216. dcdata[r][i] = 0xff & buffer.getBuffer()[i + offset];
  217. }
  218. offset += dcCount;
  219. var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
  220. var rawPoly = qrPolynomial(dcdata[r], rsPoly.getLength() - 1);
  221. var modPoly = rawPoly.mod(rsPoly);
  222. ecdata[r] = new Array(rsPoly.getLength() - 1);
  223. for (var i = 0; i < ecdata[r].length; i += 1) {
  224. var modIndex = i + modPoly.getLength() - ecdata[r].length;
  225. ecdata[r][i] = (modIndex >= 0)? modPoly.getAt(modIndex) : 0;
  226. }
  227. }
  228. var totalCodeCount = 0;
  229. for (var i = 0; i < rsBlocks.length; i += 1) {
  230. totalCodeCount += rsBlocks[i].totalCount;
  231. }
  232. var data = new Array(totalCodeCount);
  233. var index = 0;
  234. for (var i = 0; i < maxDcCount; i += 1) {
  235. for (var r = 0; r < rsBlocks.length; r += 1) {
  236. if (i < dcdata[r].length) {
  237. data[index] = dcdata[r][i];
  238. index += 1;
  239. }
  240. }
  241. }
  242. for (var i = 0; i < maxEcCount; i += 1) {
  243. for (var r = 0; r < rsBlocks.length; r += 1) {
  244. if (i < ecdata[r].length) {
  245. data[index] = ecdata[r][i];
  246. index += 1;
  247. }
  248. }
  249. }
  250. return data;
  251. };
  252. var createData = function(typeNumber, errorCorrectLevel, dataList) {
  253. var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
  254. var buffer = qrBitBuffer();
  255. for (var i = 0; i < dataList.length; i += 1) {
  256. var data = dataList[i];
  257. buffer.put(data.getMode(), 4);
  258. buffer.put(data.getLength(), QRUtil.getLengthInBits(data.getMode(), typeNumber) );
  259. data.write(buffer);
  260. }
  261. // calc num max data.
  262. var totalDataCount = 0;
  263. for (var i = 0; i < rsBlocks.length; i += 1) {
  264. totalDataCount += rsBlocks[i].dataCount;
  265. }
  266. if (buffer.getLengthInBits() > totalDataCount * 8) {
  267. throw new Error('code length overflow. ('
  268. + buffer.getLengthInBits()
  269. + '>'
  270. + totalDataCount * 8
  271. + ')');
  272. }
  273. // end code
  274. if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
  275. buffer.put(0, 4);
  276. }
  277. // padding
  278. while (buffer.getLengthInBits() % 8 != 0) {
  279. buffer.putBit(false);
  280. }
  281. // padding
  282. while (true) {
  283. if (buffer.getLengthInBits() >= totalDataCount * 8) {
  284. break;
  285. }
  286. buffer.put(PAD0, 8);
  287. if (buffer.getLengthInBits() >= totalDataCount * 8) {
  288. break;
  289. }
  290. buffer.put(PAD1, 8);
  291. }
  292. return createBytes(buffer, rsBlocks);
  293. };
  294. _this.addData = function(data) {
  295. var newData = qr8BitByte(data);
  296. _dataList.push(newData);
  297. _dataCache = null;
  298. };
  299. _this.isDark = function(row, col) {
  300. if (row < 0 || _moduleCount <= row || col < 0 || _moduleCount <= col) {
  301. throw new Error(row + ',' + col);
  302. }
  303. return _modules[row][col];
  304. };
  305. _this.getModuleCount = function() {
  306. return _moduleCount;
  307. };
  308. _this.make = function() {
  309. makeImpl(false, getBestMaskPattern() );
  310. };
  311. _this.createTableTag = function(cellSize, margin) {
  312. cellSize = cellSize || 2;
  313. margin = (typeof margin == 'undefined')? cellSize * 4 : margin;
  314. var qrHtml = '';
  315. qrHtml += '<table style="';
  316. qrHtml += ' border-width: 0px; border-style: none;';
  317. qrHtml += ' border-collapse: collapse;';
  318. qrHtml += ' padding: 0px; margin: ' + margin + 'px;';
  319. qrHtml += '">';
  320. qrHtml += '<tbody>';
  321. for (var r = 0; r < _this.getModuleCount(); r += 1) {
  322. qrHtml += '<tr>';
  323. for (var c = 0; c < _this.getModuleCount(); c += 1) {
  324. qrHtml += '<td style="';
  325. qrHtml += ' border-width: 0px; border-style: none;';
  326. qrHtml += ' border-collapse: collapse;';
  327. qrHtml += ' padding: 0px; margin: 0px;';
  328. qrHtml += ' width: ' + cellSize + 'px;';
  329. qrHtml += ' height: ' + cellSize + 'px;';
  330. qrHtml += ' background-color: ';
  331. qrHtml += _this.isDark(r, c)? '#000000' : '#ffffff';
  332. qrHtml += ';';
  333. qrHtml += '"/>';
  334. }
  335. qrHtml += '</tr>';
  336. }
  337. qrHtml += '</tbody>';
  338. qrHtml += '</table>';
  339. return qrHtml;
  340. };
  341. _this.createImgTag = function(cellSize, margin, size) {
  342. cellSize = cellSize || 2;
  343. margin = (typeof margin == 'undefined')? cellSize * 4 : margin;
  344. var min = margin;
  345. var max = _this.getModuleCount() * cellSize + margin;
  346. return createImgTag(size, size, function(x, y) {
  347. if (min <= x && x < max && min <= y && y < max) {
  348. var c = Math.floor( (x - min) / cellSize);
  349. var r = Math.floor( (y - min) / cellSize);
  350. return _this.isDark(r, c)? 0 : 1;
  351. } else {
  352. return 1;
  353. }
  354. } );
  355. };
  356. return _this;
  357. };
  358. //---------------------------------------------------------------------
  359. // qrcode.stringToBytes
  360. //---------------------------------------------------------------------
  361. qrcode.stringToBytes = function(s) {
  362. var bytes = new Array();
  363. for (var i = 0; i < s.length; i += 1) {
  364. var c = s.charCodeAt(i);
  365. bytes.push(c & 0xff);
  366. }
  367. return bytes;
  368. };
  369. //---------------------------------------------------------------------
  370. // qrcode.createStringToBytes
  371. //---------------------------------------------------------------------
  372. /**
  373. * @param unicodeData base64 string of byte array.
  374. * [16bit Unicode],[16bit Bytes], ...
  375. * @param numChars
  376. */
  377. qrcode.createStringToBytes = function(unicodeData, numChars) {
  378. // create conversion map.
  379. var unicodeMap = function() {
  380. var bin = base64DecodeInputStream(unicodeData);
  381. var read = function() {
  382. var b = bin.read();
  383. if (b == -1) throw new Error();
  384. return b;
  385. };
  386. var count = 0;
  387. var unicodeMap = {};
  388. while (true) {
  389. var b0 = bin.read();
  390. if (b0 == -1) break;
  391. var b1 = read();
  392. var b2 = read();
  393. var b3 = read();
  394. var k = String.fromCharCode( (b0 << 8) | b1);
  395. var v = (b2 << 8) | b3;
  396. unicodeMap[k] = v;
  397. count += 1;
  398. }
  399. if (count != numChars) {
  400. throw new Error(count + ' != ' + numChars);
  401. }
  402. return unicodeMap;
  403. }();
  404. var unknownChar = '?'.charCodeAt(0);
  405. return function(s) {
  406. var bytes = new Array();
  407. for (var i = 0; i < s.length; i += 1) {
  408. var c = s.charCodeAt(i);
  409. if (c < 128) {
  410. bytes.push(c);
  411. } else {
  412. var b = unicodeMap[s.charAt(i)];
  413. if (typeof b == 'number') {
  414. if ( (b & 0xff) == b) {
  415. // 1byte
  416. bytes.push(b);
  417. } else {
  418. // 2bytes
  419. bytes.push(b >>> 8);
  420. bytes.push(b & 0xff);
  421. }
  422. } else {
  423. bytes.push(unknownChar);
  424. }
  425. }
  426. }
  427. return bytes;
  428. };
  429. };
  430. //---------------------------------------------------------------------
  431. // QRMode
  432. //---------------------------------------------------------------------
  433. var QRMode = {
  434. MODE_NUMBER : 1 << 0,
  435. MODE_ALPHA_NUM : 1 << 1,
  436. MODE_8BIT_BYTE : 1 << 2,
  437. MODE_KANJI : 1 << 3
  438. };
  439. //---------------------------------------------------------------------
  440. // QRErrorCorrectLevel
  441. //---------------------------------------------------------------------
  442. var QRErrorCorrectLevel = {
  443. L : 1,
  444. M : 0,
  445. Q : 3,
  446. H : 2
  447. };
  448. //---------------------------------------------------------------------
  449. // QRMaskPattern
  450. //---------------------------------------------------------------------
  451. var QRMaskPattern = {
  452. PATTERN000 : 0,
  453. PATTERN001 : 1,
  454. PATTERN010 : 2,
  455. PATTERN011 : 3,
  456. PATTERN100 : 4,
  457. PATTERN101 : 5,
  458. PATTERN110 : 6,
  459. PATTERN111 : 7
  460. };
  461. //---------------------------------------------------------------------
  462. // QRUtil
  463. //---------------------------------------------------------------------
  464. var QRUtil = function() {
  465. var PATTERN_POSITION_TABLE = [
  466. [],
  467. [6, 18],
  468. [6, 22],
  469. [6, 26],
  470. [6, 30],
  471. [6, 34],
  472. [6, 22, 38],
  473. [6, 24, 42],
  474. [6, 26, 46],
  475. [6, 28, 50],
  476. [6, 30, 54],
  477. [6, 32, 58],
  478. [6, 34, 62],
  479. [6, 26, 46, 66],
  480. [6, 26, 48, 70],
  481. [6, 26, 50, 74],
  482. [6, 30, 54, 78],
  483. [6, 30, 56, 82],
  484. [6, 30, 58, 86],
  485. [6, 34, 62, 90],
  486. [6, 28, 50, 72, 94],
  487. [6, 26, 50, 74, 98],
  488. [6, 30, 54, 78, 102],
  489. [6, 28, 54, 80, 106],
  490. [6, 32, 58, 84, 110],
  491. [6, 30, 58, 86, 114],
  492. [6, 34, 62, 90, 118],
  493. [6, 26, 50, 74, 98, 122],
  494. [6, 30, 54, 78, 102, 126],
  495. [6, 26, 52, 78, 104, 130],
  496. [6, 30, 56, 82, 108, 134],
  497. [6, 34, 60, 86, 112, 138],
  498. [6, 30, 58, 86, 114, 142],
  499. [6, 34, 62, 90, 118, 146],
  500. [6, 30, 54, 78, 102, 126, 150],
  501. [6, 24, 50, 76, 102, 128, 154],
  502. [6, 28, 54, 80, 106, 132, 158],
  503. [6, 32, 58, 84, 110, 136, 162],
  504. [6, 26, 54, 82, 110, 138, 166],
  505. [6, 30, 58, 86, 114, 142, 170]
  506. ];
  507. var G15 = (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0);
  508. var G18 = (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0);
  509. var G15_MASK = (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1);
  510. var _this = {};
  511. var getBCHDigit = function(data) {
  512. var digit = 0;
  513. while (data != 0) {
  514. digit += 1;
  515. data >>>= 1;
  516. }
  517. return digit;
  518. };
  519. _this.getBCHTypeInfo = function(data) {
  520. var d = data << 10;
  521. while (getBCHDigit(d) - getBCHDigit(G15) >= 0) {
  522. d ^= (G15 << (getBCHDigit(d) - getBCHDigit(G15) ) );
  523. }
  524. return ( (data << 10) | d) ^ G15_MASK;
  525. };
  526. _this.getBCHTypeNumber = function(data) {
  527. var d = data << 12;
  528. while (getBCHDigit(d) - getBCHDigit(G18) >= 0) {
  529. d ^= (G18 << (getBCHDigit(d) - getBCHDigit(G18) ) );
  530. }
  531. return (data << 12) | d;
  532. };
  533. _this.getPatternPosition = function(typeNumber) {
  534. return PATTERN_POSITION_TABLE[typeNumber - 1];
  535. };
  536. _this.getMaskFunction = function(maskPattern) {
  537. switch (maskPattern) {
  538. case QRMaskPattern.PATTERN000 :
  539. return function(i, j) { return (i + j) % 2 == 0; };
  540. case QRMaskPattern.PATTERN001 :
  541. return function(i, j) { return i % 2 == 0; };
  542. case QRMaskPattern.PATTERN010 :
  543. return function(i, j) { return j % 3 == 0; };
  544. case QRMaskPattern.PATTERN011 :
  545. return function(i, j) { return (i + j) % 3 == 0; };
  546. case QRMaskPattern.PATTERN100 :
  547. return function(i, j) { return (Math.floor(i / 2) + Math.floor(j / 3) ) % 2 == 0; };
  548. case QRMaskPattern.PATTERN101 :
  549. return function(i, j) { return (i * j) % 2 + (i * j) % 3 == 0; };
  550. case QRMaskPattern.PATTERN110 :
  551. return function(i, j) { return ( (i * j) % 2 + (i * j) % 3) % 2 == 0; };
  552. case QRMaskPattern.PATTERN111 :
  553. return function(i, j) { return ( (i * j) % 3 + (i + j) % 2) % 2 == 0; };
  554. default :
  555. throw new Error('bad maskPattern:' + maskPattern);
  556. }
  557. };
  558. _this.getErrorCorrectPolynomial = function(errorCorrectLength) {
  559. var a = qrPolynomial([1], 0);
  560. for (var i = 0; i < errorCorrectLength; i += 1) {
  561. a = a.multiply(qrPolynomial([1, QRMath.gexp(i)], 0) );
  562. }
  563. return a;
  564. };
  565. _this.getLengthInBits = function(mode, type) {
  566. if (1 <= type && type < 10) {
  567. // 1 - 9
  568. switch(mode) {
  569. case QRMode.MODE_NUMBER : return 10;
  570. case QRMode.MODE_ALPHA_NUM : return 9;
  571. case QRMode.MODE_8BIT_BYTE : return 8;
  572. case QRMode.MODE_KANJI : return 8;
  573. default :
  574. throw new Error('mode:' + mode);
  575. }
  576. } else if (type < 27) {
  577. // 10 - 26
  578. switch(mode) {
  579. case QRMode.MODE_NUMBER : return 12;
  580. case QRMode.MODE_ALPHA_NUM : return 11;
  581. case QRMode.MODE_8BIT_BYTE : return 16;
  582. case QRMode.MODE_KANJI : return 10;
  583. default :
  584. throw new Error('mode:' + mode);
  585. }
  586. } else if (type < 41) {
  587. // 27 - 40
  588. switch(mode) {
  589. case QRMode.MODE_NUMBER : return 14;
  590. case QRMode.MODE_ALPHA_NUM : return 13;
  591. case QRMode.MODE_8BIT_BYTE : return 16;
  592. case QRMode.MODE_KANJI : return 12;
  593. default :
  594. throw new Error('mode:' + mode);
  595. }
  596. } else {
  597. throw new Error('type:' + type);
  598. }
  599. };
  600. _this.getLostPoint = function(qrcode) {
  601. var moduleCount = qrcode.getModuleCount();
  602. var lostPoint = 0;
  603. // LEVEL1
  604. for (var row = 0; row < moduleCount; row += 1) {
  605. for (var col = 0; col < moduleCount; col += 1) {
  606. var sameCount = 0;
  607. var dark = qrcode.isDark(row, col);
  608. for (var r = -1; r <= 1; r += 1) {
  609. if (row + r < 0 || moduleCount <= row + r) {
  610. continue;
  611. }
  612. for (var c = -1; c <= 1; c += 1) {
  613. if (col + c < 0 || moduleCount <= col + c) {
  614. continue;
  615. }
  616. if (r == 0 && c == 0) {
  617. continue;
  618. }
  619. if (dark == qrcode.isDark(row + r, col + c) ) {
  620. sameCount += 1;
  621. }
  622. }
  623. }
  624. if (sameCount > 5) {
  625. lostPoint += (3 + sameCount - 5);
  626. }
  627. }
  628. };
  629. // LEVEL2
  630. for (var row = 0; row < moduleCount - 1; row += 1) {
  631. for (var col = 0; col < moduleCount - 1; col += 1) {
  632. var count = 0;
  633. if (qrcode.isDark(row, col) ) count += 1;
  634. if (qrcode.isDark(row + 1, col) ) count += 1;
  635. if (qrcode.isDark(row, col + 1) ) count += 1;
  636. if (qrcode.isDark(row + 1, col + 1) ) count += 1;
  637. if (count == 0 || count == 4) {
  638. lostPoint += 3;
  639. }
  640. }
  641. }
  642. // LEVEL3
  643. for (var row = 0; row < moduleCount; row += 1) {
  644. for (var col = 0; col < moduleCount - 6; col += 1) {
  645. if (qrcode.isDark(row, col)
  646. && !qrcode.isDark(row, col + 1)
  647. && qrcode.isDark(row, col + 2)
  648. && qrcode.isDark(row, col + 3)
  649. && qrcode.isDark(row, col + 4)
  650. && !qrcode.isDark(row, col + 5)
  651. && qrcode.isDark(row, col + 6) ) {
  652. lostPoint += 40;
  653. }
  654. }
  655. }
  656. for (var col = 0; col < moduleCount; col += 1) {
  657. for (var row = 0; row < moduleCount - 6; row += 1) {
  658. if (qrcode.isDark(row, col)
  659. && !qrcode.isDark(row + 1, col)
  660. && qrcode.isDark(row + 2, col)
  661. && qrcode.isDark(row + 3, col)
  662. && qrcode.isDark(row + 4, col)
  663. && !qrcode.isDark(row + 5, col)
  664. && qrcode.isDark(row + 6, col) ) {
  665. lostPoint += 40;
  666. }
  667. }
  668. }
  669. // LEVEL4
  670. var darkCount = 0;
  671. for (var col = 0; col < moduleCount; col += 1) {
  672. for (var row = 0; row < moduleCount; row += 1) {
  673. if (qrcode.isDark(row, col) ) {
  674. darkCount += 1;
  675. }
  676. }
  677. }
  678. var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
  679. lostPoint += ratio * 10;
  680. return lostPoint;
  681. };
  682. return _this;
  683. }();
  684. //---------------------------------------------------------------------
  685. // QRMath
  686. //---------------------------------------------------------------------
  687. var QRMath = function() {
  688. var EXP_TABLE = new Array(256);
  689. var LOG_TABLE = new Array(256);
  690. // initialize tables
  691. for (var i = 0; i < 8; i += 1) {
  692. EXP_TABLE[i] = 1 << i;
  693. }
  694. for (var i = 8; i < 256; i += 1) {
  695. EXP_TABLE[i] = EXP_TABLE[i - 4]
  696. ^ EXP_TABLE[i - 5]
  697. ^ EXP_TABLE[i - 6]
  698. ^ EXP_TABLE[i - 8];
  699. }
  700. for (var i = 0; i < 255; i += 1) {
  701. LOG_TABLE[EXP_TABLE[i] ] = i;
  702. }
  703. var _this = {};
  704. _this.glog = function(n) {
  705. if (n < 1) {
  706. throw new Error('glog(' + n + ')');
  707. }
  708. return LOG_TABLE[n];
  709. };
  710. _this.gexp = function(n) {
  711. while (n < 0) {
  712. n += 255;
  713. }
  714. while (n >= 256) {
  715. n -= 255;
  716. }
  717. return EXP_TABLE[n];
  718. };
  719. return _this;
  720. }();
  721. //---------------------------------------------------------------------
  722. // qrPolynomial
  723. //---------------------------------------------------------------------
  724. function qrPolynomial(num, shift) {
  725. if (typeof num.length == 'undefined') {
  726. throw new Error(num.length + '/' + shift);
  727. }
  728. var _num = function() {
  729. var offset = 0;
  730. while (offset < num.length && num[offset] == 0) {
  731. offset += 1;
  732. }
  733. var _num = new Array(num.length - offset + shift);
  734. for (var i = 0; i < num.length - offset; i += 1) {
  735. _num[i] = num[i + offset];
  736. }
  737. return _num;
  738. }();
  739. var _this = {};
  740. _this.getAt = function(index) {
  741. return _num[index];
  742. };
  743. _this.getLength = function() {
  744. return _num.length;
  745. };
  746. _this.multiply = function(e) {
  747. var num = new Array(_this.getLength() + e.getLength() - 1);
  748. for (var i = 0; i < _this.getLength(); i += 1) {
  749. for (var j = 0; j < e.getLength(); j += 1) {
  750. num[i + j] ^= QRMath.gexp(QRMath.glog(_this.getAt(i) ) + QRMath.glog(e.getAt(j) ) );
  751. }
  752. }
  753. return qrPolynomial(num, 0);
  754. };
  755. _this.mod = function(e) {
  756. if (_this.getLength() - e.getLength() < 0) {
  757. return _this;
  758. }
  759. var ratio = QRMath.glog(_this.getAt(0) ) - QRMath.glog(e.getAt(0) );
  760. var num = new Array(_this.getLength() );
  761. for (var i = 0; i < _this.getLength(); i += 1) {
  762. num[i] = _this.getAt(i);
  763. }
  764. for (var i = 0; i < e.getLength(); i += 1) {
  765. num[i] ^= QRMath.gexp(QRMath.glog(e.getAt(i) ) + ratio);
  766. }
  767. // recursive call
  768. return qrPolynomial(num, 0).mod(e);
  769. };
  770. return _this;
  771. };
  772. //---------------------------------------------------------------------
  773. // QRRSBlock
  774. //---------------------------------------------------------------------
  775. var QRRSBlock = function() {
  776. // [1: [L, M, Q, H], ..]
  777. 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]];
  778. var qrRSBlock = function(totalCount, dataCount) {
  779. var _this = {};
  780. _this.totalCount = totalCount;
  781. _this.dataCount = dataCount;
  782. return _this;
  783. };
  784. var _this = {};
  785. var getRsBlockTable = function(typeNumber, errorCorrectLevel) {
  786. switch(errorCorrectLevel) {
  787. case QRErrorCorrectLevel.L :
  788. return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
  789. case QRErrorCorrectLevel.M :
  790. return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
  791. case QRErrorCorrectLevel.Q :
  792. return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
  793. case QRErrorCorrectLevel.H :
  794. return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
  795. default :
  796. return undefined;
  797. }
  798. };
  799. _this.getRSBlocks = function(typeNumber, errorCorrectLevel) {
  800. var rsBlock = getRsBlockTable(typeNumber, errorCorrectLevel);
  801. if (typeof rsBlock == 'undefined') {
  802. throw new Error('bad rs block [url=home.php?mod=space&uid=5302]@[/url] typeNumber:' + typeNumber +
  803. '/errorCorrectLevel:' + errorCorrectLevel);
  804. }
  805. var length = rsBlock.length / 3;
  806. var list = new Array();
  807. for (var i = 0; i < length; i += 1) {
  808. var count = rsBlock[i * 3 + 0];
  809. var totalCount = rsBlock[i * 3 + 1];
  810. var dataCount = rsBlock[i * 3 + 2];
  811. for (var j = 0; j < count; j += 1) {
  812. list.push(qrRSBlock(totalCount, dataCount) );
  813. }
  814. }
  815. return list;
  816. };
  817. return _this;
  818. }();
  819. //---------------------------------------------------------------------
  820. // qrBitBuffer
  821. //---------------------------------------------------------------------
  822. var qrBitBuffer = function() {
  823. var _buffer = new Array();
  824. var _length = 0;
  825. var _this = {};
  826. _this.getBuffer = function() {
  827. return _buffer;
  828. };
  829. _this.getAt = function(index) {
  830. var bufIndex = Math.floor(index / 8);
  831. return ( (_buffer[bufIndex] >>> (7 - index % 8) ) & 1) == 1;
  832. };
  833. _this.put = function(num, length) {
  834. for (var i = 0; i < length; i += 1) {
  835. _this.putBit( ( (num >>> (length - i - 1) ) & 1) == 1);
  836. }
  837. };
  838. _this.getLengthInBits = function() {
  839. return _length;
  840. };
  841. _this.putBit = function(bit) {
  842. var bufIndex = Math.floor(_length / 8);
  843. if (_buffer.length <= bufIndex) {
  844. _buffer.push(0);
  845. }
  846. if (bit) {
  847. _buffer[bufIndex] |= (0x80 >>> (_length % 8) );
  848. }
  849. _length += 1;
  850. };
  851. return _this;
  852. };
  853. //---------------------------------------------------------------------
  854. // qr8BitByte
  855. //---------------------------------------------------------------------
  856. var qr8BitByte = function(data) {
  857. var _mode = QRMode.MODE_8BIT_BYTE;
  858. var _data = data;
  859. var _parsedData = [];
  860. var _this = {};
  861. // Added to support UTF-8 Characters
  862. for (var i = 0, l = _data.length; i < l; i++) {
  863. var byteArray = [];
  864. var code = _data.charCodeAt(i);
  865. if (code > 0x10000) {
  866. byteArray[0] = 0xF0 | ((code & 0x1C0000) >>> 18);
  867. byteArray[1] = 0x80 | ((code & 0x3F000) >>> 12);
  868. byteArray[2] = 0x80 | ((code & 0xFC0) >>> 6);
  869. byteArray[3] = 0x80 | (code & 0x3F);
  870. } else if (code > 0x800) {
  871. byteArray[0] = 0xE0 | ((code & 0xF000) >>> 12);
  872. byteArray[1] = 0x80 | ((code & 0xFC0) >>> 6);
  873. byteArray[2] = 0x80 | (code & 0x3F);
  874. } else if (code > 0x80) {
  875. byteArray[0] = 0xC0 | ((code & 0x7C0) >>> 6);
  876. byteArray[1] = 0x80 | (code & 0x3F);
  877. } else {
  878. byteArray[0] = code;
  879. }
  880. // Fix Unicode corruption bug
  881. _parsedData.push(byteArray);
  882. }
  883. _parsedData = Array.prototype.concat.apply([], _parsedData);
  884. if (_parsedData.length != _data.length) {
  885. _parsedData.unshift(191);
  886. _parsedData.unshift(187);
  887. _parsedData.unshift(239);
  888. }
  889. var _bytes = _parsedData;
  890. _this.getMode = function() {
  891. return _mode;
  892. };
  893. _this.getLength = function(buffer) {
  894. return _bytes.length;
  895. };
  896. _this.write = function(buffer) {
  897. for (var i = 0; i < _bytes.length; i += 1) {
  898. buffer.put(_bytes[i], 8);
  899. }
  900. };
  901. return _this;
  902. };
  903. //=====================================================================
  904. // GIF Support etc.
  905. //
  906. //---------------------------------------------------------------------
  907. // byteArrayOutputStream
  908. //---------------------------------------------------------------------
  909. var byteArrayOutputStream = function() {
  910. var _bytes = new Array();
  911. var _this = {};
  912. _this.writeByte = function(b) {
  913. _bytes.push(b & 0xff);
  914. };
  915. _this.writeShort = function(i) {
  916. _this.writeByte(i);
  917. _this.writeByte(i >>> 8);
  918. };
  919. _this.writeBytes = function(b, off, len) {
  920. off = off || 0;
  921. len = len || b.length;
  922. for (var i = 0; i < len; i += 1) {
  923. _this.writeByte(b[i + off]);
  924. }
  925. };
  926. _this.writeString = function(s) {
  927. for (var i = 0; i < s.length; i += 1) {
  928. _this.writeByte(s.charCodeAt(i) );
  929. }
  930. };
  931. _this.toByteArray = function() {
  932. return _bytes;
  933. };
  934. _this.toString = function() {
  935. var s = '';
  936. s += '[';
  937. for (var i = 0; i < _bytes.length; i += 1) {
  938. if (i > 0) {
  939. s += ',';
  940. }
  941. s += _bytes[i];
  942. }
  943. s += ']';
  944. return s;
  945. };
  946. return _this;
  947. };
  948. //---------------------------------------------------------------------
  949. // base64EncodeOutputStream
  950. //---------------------------------------------------------------------
  951. var base64EncodeOutputStream = function() {
  952. var _buffer = 0;
  953. var _buflen = 0;
  954. var _length = 0;
  955. var _base64 = '';
  956. var _this = {};
  957. var writeEncoded = function(b) {
  958. _base64 += String.fromCharCode(encode(b & 0x3f) );
  959. };
  960. var encode = function(n) {
  961. if (n < 0) {
  962. // error.
  963. } else if (n < 26) {
  964. return 0x41 + n;
  965. } else if (n < 52) {
  966. return 0x61 + (n - 26);
  967. } else if (n < 62) {
  968. return 0x30 + (n - 52);
  969. } else if (n == 62) {
  970. return 0x2b;
  971. } else if (n == 63) {
  972. return 0x2f;
  973. }
  974. throw new Error('n:' + n);
  975. };
  976. _this.writeByte = function(n) {
  977. _buffer = (_buffer << 8) | (n & 0xff);
  978. _buflen += 8;
  979. _length += 1;
  980. while (_buflen >= 6) {
  981. writeEncoded(_buffer >>> (_buflen - 6) );
  982. _buflen -= 6;
  983. }
  984. };
  985. _this.flush = function() {
  986. if (_buflen > 0) {
  987. writeEncoded(_buffer << (6 - _buflen) );
  988. _buffer = 0;
  989. _buflen = 0;
  990. }
  991. if (_length % 3 != 0) {
  992. // padding
  993. var padlen = 3 - _length % 3;
  994. for (var i = 0; i < padlen; i += 1) {
  995. _base64 += '=';
  996. }
  997. }
  998. };
  999. _this.toString = function() {
  1000. return _base64;
  1001. };
  1002. return _this;
  1003. };
  1004. //---------------------------------------------------------------------
  1005. // base64DecodeInputStream
  1006. //---------------------------------------------------------------------
  1007. var base64DecodeInputStream = function(str) {
  1008. var _str = str;
  1009. var _pos = 0;
  1010. var _buffer = 0;
  1011. var _buflen = 0;
  1012. var _this = {};
  1013. _this.read = function() {
  1014. while (_buflen < 8) {
  1015. if (_pos >= _str.length) {
  1016. if (_buflen == 0) {
  1017. return -1;
  1018. }
  1019. throw new Error('unexpected end of file./' + _buflen);
  1020. }
  1021. var c = _str.charAt(_pos);
  1022. _pos += 1;
  1023. if (c == '=') {
  1024. _buflen = 0;
  1025. return -1;
  1026. } else if (c.match(/^\s$/) ) {
  1027. // ignore if whitespace.
  1028. continue;
  1029. }
  1030. _buffer = (_buffer << 6) | decode(c.charCodeAt(0) );
  1031. _buflen += 6;
  1032. }
  1033. var n = (_buffer >>> (_buflen - 8) ) & 0xff;
  1034. _buflen -= 8;
  1035. return n;
  1036. };
  1037. var decode = function(c) {
  1038. if (0x41 <= c && c <= 0x5a) {
  1039. return c - 0x41;
  1040. } else if (0x61 <= c && c <= 0x7a) {
  1041. return c - 0x61 + 26;
  1042. } else if (0x30 <= c && c <= 0x39) {
  1043. return c - 0x30 + 52;
  1044. } else if (c == 0x2b) {
  1045. return 62;
  1046. } else if (c == 0x2f) {
  1047. return 63;
  1048. } else {
  1049. throw new Error('c:' + c);
  1050. }
  1051. };
  1052. return _this;
  1053. };
  1054. //---------------------------------------------------------------------
  1055. // gifImage (B/W)
  1056. //---------------------------------------------------------------------
  1057. var gifImage = function(width, height) {
  1058. var _width = width;
  1059. var _height = height;
  1060. var _data = new Array(width * height);
  1061. var _this = {};
  1062. _this.setPixel = function(x, y, pixel) {
  1063. _data[y * _width + x] = pixel;
  1064. };
  1065. _this.write = function(out) {
  1066. //---------------------------------
  1067. // GIF Signature
  1068. out.writeString('GIF87a');
  1069. //---------------------------------
  1070. // Screen Descriptor
  1071. out.writeShort(_width);
  1072. out.writeShort(_height);
  1073. out.writeByte(0x80); // 2bit
  1074. out.writeByte(0);
  1075. out.writeByte(0);
  1076. //---------------------------------
  1077. // Global Color Map
  1078. // black
  1079. out.writeByte(0x00);
  1080. out.writeByte(0x00);
  1081. out.writeByte(0x00);
  1082. // white
  1083. out.writeByte(0xff);
  1084. out.writeByte(0xff);
  1085. out.writeByte(0xff);
  1086. //---------------------------------
  1087. // Image Descriptor
  1088. out.writeString(',');
  1089. out.writeShort(0);
  1090. out.writeShort(0);
  1091. out.writeShort(_width);
  1092. out.writeShort(_height);
  1093. out.writeByte(0);
  1094. //---------------------------------
  1095. // Local Color Map
  1096. //---------------------------------
  1097. // Raster Data
  1098. var lzwMinCodeSize = 2;
  1099. var raster = getLZWRaster(lzwMinCodeSize);
  1100. out.writeByte(lzwMinCodeSize);
  1101. var offset = 0;
  1102. while (raster.length - offset > 255) {
  1103. out.writeByte(255);
  1104. out.writeBytes(raster, offset, 255);
  1105. offset += 255;
  1106. }
  1107. out.writeByte(raster.length - offset);
  1108. out.writeBytes(raster, offset, raster.length - offset);
  1109. out.writeByte(0x00);
  1110. //---------------------------------
  1111. // GIF Terminator
  1112. out.writeString(';');
  1113. };
  1114. var bitOutputStream = function(out) {
  1115. var _out = out;
  1116. var _bitLength = 0;
  1117. var _bitBuffer = 0;
  1118. var _this = {};
  1119. _this.write = function(data, length) {
  1120. if ( (data >>> length) != 0) {
  1121. throw new Error('length over');
  1122. }
  1123. while (_bitLength + length >= 8) {
  1124. _out.writeByte(0xff & ( (data << _bitLength) | _bitBuffer) );
  1125. length -= (8 - _bitLength);
  1126. data >>>= (8 - _bitLength);
  1127. _bitBuffer = 0;
  1128. _bitLength = 0;
  1129. }
  1130. _bitBuffer = (data << _bitLength) | _bitBuffer;
  1131. _bitLength = _bitLength + length;
  1132. };
  1133. _this.flush = function() {
  1134. if (_bitLength > 0) {
  1135. _out.writeByte(_bitBuffer);
  1136. }
  1137. };
  1138. return _this;
  1139. };
  1140. var getLZWRaster = function(lzwMinCodeSize) {
  1141. var clearCode = 1 << lzwMinCodeSize;
  1142. var endCode = (1 << lzwMinCodeSize) + 1;
  1143. var bitLength = lzwMinCodeSize + 1;
  1144. // Setup LZWTable
  1145. var table = lzwTable();
  1146. for (var i = 0; i < clearCode; i += 1) {
  1147. table.add(String.fromCharCode(i) );
  1148. }
  1149. table.add(String.fromCharCode(clearCode) );
  1150. table.add(String.fromCharCode(endCode) );
  1151. var byteOut = byteArrayOutputStream();
  1152. var bitOut = bitOutputStream(byteOut);
  1153. // clear code
  1154. bitOut.write(clearCode, bitLength);
  1155. var dataIndex = 0;
  1156. var s = String.fromCharCode(_data[dataIndex]);
  1157. dataIndex += 1;
  1158. while (dataIndex < _data.length) {
  1159. var c = String.fromCharCode(_data[dataIndex]);
  1160. dataIndex += 1;
  1161. if (table.contains(s + c) ) {
  1162. s = s + c;
  1163. } else {
  1164. bitOut.write(table.indexOf(s), bitLength);
  1165. if (table.size() < 0xfff) {
  1166. if (table.size() == (1 << bitLength) ) {
  1167. bitLength += 1;
  1168. }
  1169. table.add(s + c);
  1170. }
  1171. s = c;
  1172. }
  1173. }
  1174. bitOut.write(table.indexOf(s), bitLength);
  1175. // end code
  1176. bitOut.write(endCode, bitLength);
  1177. bitOut.flush();
  1178. return byteOut.toByteArray();
  1179. };
  1180. var lzwTable = function() {
  1181. var _map = {};
  1182. var _size = 0;
  1183. var _this = {};
  1184. _this.add = function(key) {
  1185. if (_this.contains(key) ) {
  1186. throw new Error('dup key:' + key);
  1187. }
  1188. _map[key] = _size;
  1189. _size += 1;
  1190. };
  1191. _this.size = function() {
  1192. return _size;
  1193. };
  1194. _this.indexOf = function(key) {
  1195. return _map[key];
  1196. };
  1197. _this.contains = function(key) {
  1198. return typeof _map[key] != 'undefined';
  1199. };
  1200. return _this;
  1201. };
  1202. return _this;
  1203. };
  1204. var createImgTag = function(width, height, getPixel, alt) {
  1205. var gif = gifImage(width, height);
  1206. for (var y = 0; y < height; y += 1) {
  1207. for (var x = 0; x < width; x += 1) {
  1208. gif.setPixel(x, y, getPixel(x, y) );
  1209. }
  1210. }
  1211. var b = byteArrayOutputStream();
  1212. gif.write(b);
  1213. var base64 = base64EncodeOutputStream();
  1214. var bytes = b.toByteArray();
  1215. for (var i = 0; i < bytes.length; i += 1) {
  1216. base64.writeByte(bytes[i]);
  1217. }
  1218. base64.flush();
  1219. var img = '';
  1220. img += 'data:image/gif;base64,';
  1221. img += base64;
  1222. return img;
  1223. };
  1224. //---------------------------------------------------------------------
  1225. // returns qrcode function.
  1226. var createQrCodeImg = function(text, options) {
  1227. options = options || {};
  1228. var typeNumber = options.typeNumber || 4;
  1229. var errorCorrectLevel = options.errorCorrectLevel || 'M';
  1230. var size = options.size || 500;
  1231. var qr;
  1232. try {
  1233. qr = qrcode(typeNumber, errorCorrectLevel || 'M');
  1234. qr.addData(text);
  1235. qr.make();
  1236. } catch (e) {
  1237. if(typeNumber >= 40) {
  1238. throw new Error('Text too long to encode');
  1239. } else {
  1240. return gen(text, {
  1241. size: size,
  1242. errorCorrectLevel: errorCorrectLevel,
  1243. typeNumber: typeNumber + 1
  1244. });
  1245. }
  1246. }
  1247. // calc cellsize and margin
  1248. var cellsize = parseInt(size / qr.getModuleCount());
  1249. var margin = parseInt((size - qr.getModuleCount() * cellsize) / 2);
  1250. return qr.createImgTag(cellsize, margin, size);
  1251. };
  1252. // var module = {}; 需要注释这一行,否则微信小程序无法使用
  1253. export default {
  1254. createQrCodeImg
  1255. }
tki-qrcode.vue
复制代码
  1. <template xlang="wxml" minapp="mpvue">
  2. <view class="_qrCode">
  3. <canvas class="_qrCodeCanvas" id="_myQrCodeCanvas" canvas-id="_myQrCodeCanvas" :style="{width:cpSize+'px',height:cpSize+'px'}" />
  4. <image v-show="show" :src="result" :style="{width:cpSize+'px',height:cpSize+'px'}" />
  5. </view>
  6. </template>
  7. <script>
  8. import QRCode from "./qrcode.js"
  9. let qrcode
  10. export default {
  11. name: "tki-qrcode",
  12. props: {
  13. size: {
  14. type: Number,
  15. default: 200
  16. },
  17. unit: {
  18. type: String,
  19. default: 'upx'
  20. },
  21. show: {
  22. type: Boolean,
  23. default: true
  24. },
  25. val: {
  26. type: String,
  27. default: ''
  28. },
  29. background: {
  30. type: String,
  31. default: '#ffffff'
  32. },
  33. foreground: {
  34. type: String,
  35. default: '#000000'
  36. },
  37. pdground: {
  38. type: String,
  39. default: '#000000'
  40. },
  41. icon: {
  42. type: String,
  43. default: ''
  44. },
  45. iconSize: {
  46. type: Number,
  47. default: 40
  48. },
  49. lv: {
  50. type: Number,
  51. default: 3
  52. },
  53. onval: {
  54. type: Boolean,
  55. default: false
  56. },
  57. loadMake: {
  58. type: Boolean,
  59. default: false
  60. },
  61. },
  62. data() {
  63. return {
  64. result: '',
  65. }
  66. },
  67. methods: {
  68. _makeCode() {
  69. let that = this
  70. if (!this._empty(this.val)) {
  71. qrcode = new QRCode({
  72. context: that,
  73. text: that.val, // 生成内容
  74. size: that.cpSize, // 二维码大小
  75. background: that.background, // 背景色
  76. foreground: that.foreground, // 前景色
  77. pdground: that.pdground, // 定位角点颜色
  78. correctLevel: that.lv, // 容错级别
  79. image: that.icon, // 二维码图标
  80. imageSize: that.iconSize,// 二维码图标大小
  81. cbResult: function (res) { // 生成二维码的回调
  82. that._result(res)
  83. },
  84. });
  85. } else {
  86. uni.showToast({
  87. title: '二维码内容不能为空',
  88. icon: 'none',
  89. duration: 1000,
  90. complete: function () {
  91. setTimeout(function() {
  92. uni.hideToast();
  93. },1000);
  94. }
  95. });
  96. }
  97. },
  98. _clearCode() {
  99. this._result('')
  100. qrcode.clear()
  101. },
  102. _saveCode() {
  103. let that = this;
  104. if (this.result != "") {
  105. uni.saveImageToPhotosAlbum({
  106. filePath: that.result,
  107. success: function () {
  108. uni.showToast({
  109. title: '二维码保存成功',
  110. icon: 'success',
  111. duration: 1000,
  112. complete: function () {
  113. setTimeout(function() {
  114. uni.hideToast();
  115. },1000);
  116. }
  117. });
  118. }
  119. });
  120. }
  121. },
  122. _result(res) {
  123. this.result = res;
  124. this.$emit('result', res)
  125. },
  126. _empty(v) {
  127. let tp = typeof v,
  128. rt = false;
  129. if (tp == "number" && String(v) == "") {
  130. rt = true
  131. } else if (tp == "undefined") {
  132. rt = true
  133. } else if (tp == "object") {
  134. if (JSON.stringify(v) == "{}" || JSON.stringify(v) == "[]" || v == null) rt = true
  135. } else if (tp == "string") {
  136. if (v == "" || v == "undefined" || v == "null" || v == "{}" || v == "[]") rt = true
  137. } else if (tp == "function") {
  138. rt = false
  139. }
  140. return rt
  141. }
  142. },
  143. watch: {
  144. size: function (n, o) {
  145. if (n != o && !this._empty(n)) {
  146. this.cSize = n
  147. if (!this._empty(this.val)) {
  148. setTimeout(() => {
  149. this._makeCode()
  150. }, 100);
  151. }
  152. }
  153. },
  154. val: function (n, o) {
  155. if (this.onval) {
  156. if (n != o && !this._empty(n)) {
  157. setTimeout(() => {
  158. this._makeCode()
  159. }, 0);
  160. }
  161. }
  162. }
  163. },
  164. computed: {
  165. cpSize() {
  166. if(this.unit == "upx"){
  167. return uni.upx2px(this.size)
  168. }else{
  169. return this.size
  170. }
  171. }
  172. },
  173. mounted: function () {
  174. if (this.loadMake) {
  175. if (!this._empty(this.val)) {
  176. setTimeout(() => {
  177. this._makeCode()
  178. }, 0);
  179. }
  180. }
  181. },
  182. }
  183. </script>
  184. <style>
  185. ._qrCode {
  186. position: relative;
  187. }
  188. ._qrCodeCanvas {
  189. position: fixed;
  190. top: -99999upx;
  191. left: -99999upx;
  192. z-index: -99999;
  193. }
  194. </style>

u-charts

component.vue
复制代码
  1. <template>
  2. <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'}"
  3. @touchstart="touchStart" @touchmove="touchMove" @touchend="touchEnd" @error="error">
  4. </canvas>
  5. </template>
  6. <script>
  7. import uCharts from './u-charts.js';
  8. var canvases = {};
  9. export default {
  10. props: {
  11. chartType: {
  12. required: true,
  13. type: String,
  14. default: 'column'
  15. },
  16. opts: {
  17. required: true,
  18. type: Object,
  19. default () {
  20. return null;
  21. },
  22. },
  23. canvasId: {
  24. type: String,
  25. default: 'u-canvas',
  26. },
  27. cWidth: {
  28. default: 375,
  29. },
  30. cHeight: {
  31. default: 250,
  32. },
  33. pixelRatio: {
  34. type: Number,
  35. default: 1,
  36. },
  37. },
  38. mounted() {
  39. this.init();
  40. },
  41. methods: {
  42. init() {
  43. switch (this.chartType) {
  44. case 'column':
  45. this.initColumnChart();
  46. break;
  47. case 'line':
  48. this.initLineChart();
  49. break;
  50. default:
  51. break;
  52. }
  53. },
  54. initColumnChart() {
  55. canvases[this.canvasId] = new uCharts({
  56. $this: this,
  57. canvasId: this.canvasId,
  58. type: 'column',
  59. legend: true,
  60. fontSize: 11,
  61. background: '#FFFFFF',
  62. pixelRatio: this.pixelRatio,
  63. animation: true,
  64. categories: this.opts.categories,
  65. series: this.opts.series,
  66. enableScroll: true,
  67. xAxis: {
  68. disableGrid: true,
  69. itemCount: 4,
  70. scrollShow: true
  71. },
  72. yAxis: {
  73. //disabled:true
  74. },
  75. dataLabel: true,
  76. width: this.cWidth * this.pixelRatio,
  77. height: this.cHeight * this.pixelRatio,
  78. extra: {
  79. column: {
  80. type: 'group',
  81. }
  82. }
  83. });
  84. },
  85. initLineChart() {
  86. canvases[this.canvasId] = new uCharts({
  87. $this: this,
  88. canvasId: this.canvasId,
  89. type: 'line',
  90. fontSize: 11,
  91. legend: true,
  92. dataLabel: false,
  93. dataPointShape: true,
  94. background: '#FFFFFF',
  95. pixelRatio: this.pixelRatio,
  96. categories: this.opts.categories,
  97. series: this.opts.series,
  98. animation: true,
  99. enableScroll: true,
  100. xAxis: {
  101. type: 'grid',
  102. gridColor: '#CCCCCC',
  103. gridType: 'dash',
  104. dashLength: 8,
  105. itemCount: 4,
  106. scrollShow: true
  107. },
  108. yAxis: {
  109. gridType: 'dash',
  110. gridColor: '#CCCCCC',
  111. dashLength: 8,
  112. splitNumber: 5,
  113. min: 10,
  114. max: 180,
  115. format: (val) => {
  116. return val.toFixed(0) + '元'
  117. }
  118. },
  119. width: this.cWidth * this.pixelRatio,
  120. height: this.cHeight * this.pixelRatio,
  121. extra: {
  122. line: {
  123. type: 'straight'
  124. }
  125. }
  126. });
  127. },
  128. // 这里仅作为示例传入两个参数,cid为canvas-id,newdata为更新的数据,需要更多参数请自行修改
  129. changeData(cid,newdata) {
  130. canvases[cid].updateData({
  131. series: newdata.series,
  132. categories: newdata.categories
  133. });
  134. },
  135. touchStart(e) {
  136. canvases[this.canvasId].showToolTip(e, {
  137. format: function(item, category) {
  138. return category + ' ' + item.name + ':' + item.data
  139. }
  140. });
  141. canvases[this.canvasId].scrollStart(e);
  142. },
  143. touchMove(e) {
  144. canvases[this.canvasId].scroll(e);
  145. },
  146. touchEnd(e) {
  147. canvases[this.canvasId].scrollEnd(e);
  148. },
  149. error(e) {
  150. // console.log(e)
  151. }
  152. },
  153. };
  154. </script>
  155. <style scoped>
  156. .charts {
  157. width: 100%;
  158. height: 100%;
  159. flex: 1;
  160. background-color: #FFFFFF;
  161. }
  162. </style>
u-charts.js
复制代码
  1. /*
  2. * uCharts v1.7.0.20190713
  3. * uni-app平台高性能跨全端图表,支持H5、APP、小程序(微信/支付宝/百度/头条)
  4. * Copyright (c) 2019 QIUN秋云 https://www.ucharts.cn All rights reserved.
  5. * Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  6. *
  7. * uCharts官方网站
  8. * https://www.uCharts.cn
  9. *
  10. * 开源地址:
  11. * https://gitee.com/uCharts/uCharts
  12. *
  13. * uni-app插件市场地址:
  14. * http://ext.dcloud.net.cn/plugin?id=271
  15. *
  16. *
  17. */
  18. 'use strict';
  19. var config = {
  20. yAxisWidth: 15,
  21. yAxisSplit: 5,
  22. xAxisHeight: 15,
  23. xAxisLineHeight: 15,
  24. legendHeight: 15,
  25. yAxisTitleWidth: 15,
  26. padding: 12,
  27. pixelRatio: 1, //适配H5高分屏
  28. rotate: false, //横屏模式
  29. columePadding: 3,
  30. fontSize: 13,
  31. //dataPointShape: ['diamond', 'circle', 'triangle', 'rect'],
  32. dataPointShape: ['circle', 'circle', 'circle', 'circle'], //仿F2图例样式改为圆点
  33. colors: ['#1890ff', '#2fc25b', '#facc14', '#f04864', '#8543e0', '#90ed7d'],
  34. pieChartLinePadding: 15,
  35. pieChartTextPadding: 5,
  36. xAxisTextPadding: 3,
  37. titleColor: '#333333',
  38. titleFontSize: 20,
  39. subtitleColor: '#999999',
  40. subtitleFontSize: 15,
  41. toolTipPadding: 3,
  42. toolTipBackground: '#000000',
  43. toolTipOpacity: 0.7,
  44. toolTipLineHeight: 20,
  45. radarGridCount: 3,
  46. radarLabelTextMargin: 15,
  47. gaugeLabelTextMargin: 15
  48. };
  49. // Object.assign polyfill
  50. // https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
  51. function assign(target, varArgs) {
  52. if (target == null) {
  53. // TypeError if undefined or null
  54. throw new TypeError('Cannot convert undefined or null to object');
  55. }
  56. var to = Object(target);
  57. for (var index = 1; index < arguments.length; index++) {
  58. var nextSource = arguments[index];
  59. if (nextSource != null) {
  60. // Skip over if undefined or null
  61. for (var nextKey in nextSource) {
  62. // Avoid bugs when hasOwnProperty is shadowed
  63. if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
  64. to[nextKey] = nextSource[nextKey];
  65. }
  66. }
  67. }
  68. }
  69. return to;
  70. }
  71. var util = {
  72. toFixed: function toFixed(num, limit) {
  73. limit = limit || 2;
  74. if (this.isFloat(num)) {
  75. num = num.toFixed(limit);
  76. }
  77. return num;
  78. },
  79. isFloat: function isFloat(num) {
  80. return num % 1 !== 0;
  81. },
  82. approximatelyEqual: function approximatelyEqual(num1, num2) {
  83. return Math.abs(num1 - num2) < 1e-10;
  84. },
  85. isSameSign: function isSameSign(num1, num2) {
  86. return Math.abs(num1) === num1 && Math.abs(num2) === num2 || Math.abs(num1) !== num1 && Math.abs(num2) !== num2;
  87. },
  88. isSameXCoordinateArea: function isSameXCoordinateArea(p1, p2) {
  89. return this.isSameSign(p1.x, p2.x);
  90. },
  91. isCollision: function isCollision(obj1, obj2) {
  92. obj1.end = {};
  93. obj1.end.x = obj1.start.x + obj1.width;
  94. obj1.end.y = obj1.start.y - obj1.height;
  95. obj2.end = {};
  96. obj2.end.x = obj2.start.x + obj2.width;
  97. obj2.end.y = obj2.start.y - obj2.height;
  98. var flag = obj2.start.x > obj1.end.x || obj2.end.x < obj1.start.x || obj2.end.y > obj1.start.y || obj2.start.y <
  99. obj1.end.y;
  100. return !flag;
  101. }
  102. };
  103. //兼容H5点击事件
  104. function getH5Offset(e) {
  105. e.mp={changedTouches:[]};
  106. e.mp.changedTouches.push({x:e.offsetX,y:e.offsetY});
  107. return e;
  108. }
  109. // hex 转 rgba
  110. function hexToRgb(hexValue, opc) {
  111. var rgx = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
  112. var hex = hexValue.replace(rgx, function(m, r, g, b) {
  113. return r + r + g + g + b + b;
  114. });
  115. var rgb = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
  116. var r = parseInt(rgb[1], 16);
  117. var g = parseInt(rgb[2], 16);
  118. var b = parseInt(rgb[3], 16);
  119. return 'rgba(' + r + ',' + g + ',' + b + ',' + opc + ')';
  120. }
  121. function findRange(num, type, limit) {
  122. if (isNaN(num)) {
  123. throw new Error('[wxCharts] unvalid series data!');
  124. }
  125. limit = limit || 10;
  126. type = type ? type : 'upper';
  127. var multiple = 1;
  128. while (limit < 1) {
  129. limit *= 10;
  130. multiple *= 10;
  131. }
  132. if (type === 'upper') {
  133. num = Math.ceil(num * multiple);
  134. } else {
  135. num = Math.floor(num * multiple);
  136. }
  137. while (num % limit !== 0) {
  138. if (type === 'upper') {
  139. num++;
  140. } else {
  141. num--;
  142. }
  143. }
  144. return num / multiple;
  145. }
  146. function calCandleMA(dayArr, nameArr, colorArr, kdata) {
  147. let seriesTemp = [];
  148. for (let k = 0; k < dayArr.length; k++) {
  149. let seriesItem = {
  150. data: [],
  151. name: nameArr[k],
  152. color: colorArr[k]
  153. };
  154. for (let i = 0, len = kdata.length; i < len; i++) {
  155. if (i < dayArr[k]) {
  156. seriesItem.data.push(null);
  157. continue;
  158. }
  159. let sum = 0;
  160. for (let j = 0; j < dayArr[k]; j++) {
  161. sum += kdata[i - j][1];
  162. }
  163. seriesItem.data.push(+(sum / dayArr[k]).toFixed(3));
  164. }
  165. seriesTemp.push(seriesItem);
  166. }
  167. return seriesTemp;
  168. }
  169. function calValidDistance(distance, chartData, config, opts) {
  170. var dataChartAreaWidth = opts.width - config.padding - chartData.xAxisPoints[0];
  171. var dataChartWidth = chartData.eachSpacing * opts.categories.length;
  172. var validDistance = distance;
  173. if (distance >= 0) {
  174. validDistance = 0;
  175. } else if (Math.abs(distance) >= dataChartWidth - dataChartAreaWidth) {
  176. validDistance = dataChartAreaWidth - dataChartWidth;
  177. }
  178. return validDistance;
  179. }
  180. function isInAngleRange(angle, startAngle, endAngle) {
  181. function adjust(angle) {
  182. while (angle < 0) {
  183. angle += 2 * Math.PI;
  184. }
  185. while (angle > 2 * Math.PI) {
  186. angle -= 2 * Math.PI;
  187. }
  188. return angle;
  189. }
  190. angle = adjust(angle);
  191. startAngle = adjust(startAngle);
  192. endAngle = adjust(endAngle);
  193. if (startAngle > endAngle) {
  194. endAngle += 2 * Math.PI;
  195. if (angle < startAngle) {
  196. angle += 2 * Math.PI;
  197. }
  198. }
  199. return angle >= startAngle && angle <= endAngle;
  200. }
  201. function calRotateTranslate(x, y, h) {
  202. var xv = x;
  203. var yv = h - y;
  204. var transX = xv + (h - yv - xv) / Math.sqrt(2);
  205. transX *= -1;
  206. var transY = (h - yv) * (Math.sqrt(2) - 1) - (h - yv - xv) / Math.sqrt(2);
  207. return {
  208. transX: transX,
  209. transY: transY
  210. };
  211. }
  212. function createCurveControlPoints(points, i) {
  213. function isNotMiddlePoint(points, i) {
  214. if (points[i - 1] && points[i + 1]) {
  215. return points[i].y >= Math.max(points[i - 1].y, points[i + 1].y) || points[i].y <= Math.min(points[i - 1].y, points[
  216. i + 1].y);
  217. } else {
  218. return false;
  219. }
  220. }
  221. var a = 0.2;
  222. var b = 0.2;
  223. var pAx = null;
  224. var pAy = null;
  225. var pBx = null;
  226. var pBy = null;
  227. if (i < 1) {
  228. pAx = points[0].x + (points[1].x - points[0].x) * a;
  229. pAy = points[0].y + (points[1].y - points[0].y) * a;
  230. } else {
  231. pAx = points[i].x + (points[i + 1].x - points[i - 1].x) * a;
  232. pAy = points[i].y + (points[i + 1].y - points[i - 1].y) * a;
  233. }
  234. if (i > points.length - 3) {
  235. var last = points.length - 1;
  236. pBx = points[last].x - (points[last].x - points[last - 1].x) * b;
  237. pBy = points[last].y - (points[last].y - points[last - 1].y) * b;
  238. } else {
  239. pBx = points[i + 1].x - (points[i + 2].x - points[i].x) * b;
  240. pBy = points[i + 1].y - (points[i + 2].y - points[i].y) * b;
  241. }
  242. // fix issue https://github.com/xiaolin3303/wx-charts/issues/79
  243. if (isNotMiddlePoint(points, i + 1)) {
  244. pBy = points[i + 1].y;
  245. }
  246. if (isNotMiddlePoint(points, i)) {
  247. pAy = points[i].y;
  248. }
  249. return {
  250. ctrA: {
  251. x: pAx,
  252. y: pAy
  253. },
  254. ctrB: {
  255. x: pBx,
  256. y: pBy
  257. }
  258. };
  259. }
  260. function convertCoordinateOrigin(x, y, center) {
  261. return {
  262. x: center.x + x,
  263. y: center.y - y
  264. };
  265. }
  266. function avoidCollision(obj, target) {
  267. if (target) {
  268. // is collision test
  269. while (util.isCollision(obj, target)) {
  270. if (obj.start.x > 0) {
  271. obj.start.y--;
  272. } else if (obj.start.x < 0) {
  273. obj.start.y++;
  274. } else {
  275. if (obj.start.y > 0) {
  276. obj.start.y++;
  277. } else {
  278. obj.start.y--;
  279. }
  280. }
  281. }
  282. }
  283. return obj;
  284. }
  285. function fillSeriesColor(series, config) {
  286. var index = 0;
  287. return series.map(function(item) {
  288. if (!item.color) {
  289. item.color = config.colors[index];
  290. index = (index + 1) % config.colors.length;
  291. }
  292. return item;
  293. });
  294. }
  295. function fillSeriesType(series, opts) {
  296. return series.map(function(item) {
  297. if (!item.type) {
  298. item.type = opts.type;
  299. }
  300. return item;
  301. });
  302. }
  303. function getDataRange(minData, maxData) {
  304. var limit = 0;
  305. var range = maxData - minData;
  306. if (range >= 10000) {
  307. limit = 1000;
  308. } else if (range >= 1000) {
  309. limit = 100;
  310. } else if (range >= 100) {
  311. limit = 10;
  312. } else if (range >= 10) {
  313. limit = 5;
  314. } else if (range >= 1) {
  315. limit = 1;
  316. } else if (range >= 0.1) {
  317. limit = 0.1;
  318. } else {
  319. limit = 0.01;
  320. }
  321. return {
  322. minRange: findRange(minData, 'lower', limit),
  323. maxRange: findRange(maxData, 'upper', limit)
  324. };
  325. }
  326. function measureText(text) {
  327. var fontSize = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : config.fontSize;
  328. // wx canvas 未实现measureText方法, 此处自行实现
  329. // 适配修改初始字体10px为其他大小的方法
  330. text = String(text);
  331. var text = text.split('');
  332. var width = 0;
  333. for (let i = 0; i < text.length; i++) {
  334. let item = text[i];
  335. if (/[a-zA-Z]/.test(item)) {
  336. width += 7;
  337. } else if (/[0-9]/.test(item)) {
  338. width += 5.5;
  339. } else if (/\./.test(item)) {
  340. width += 2.7;
  341. } else if (/-/.test(item)) {
  342. width += 3.25;
  343. } else if (/[\u4e00-\u9fa5]/.test(item)) {
  344. width += 10;
  345. } else if (/\(|\)/.test(item)) {
  346. width += 3.73;
  347. } else if (/\s/.test(item)) {
  348. width += 2.5;
  349. } else if (/%/.test(item)) {
  350. width += 8;
  351. } else {
  352. width += 10;
  353. }
  354. }
  355. return width * fontSize / 10;
  356. }
  357. function dataCombine(series) {
  358. return series.reduce(function(a, b) {
  359. return (a.data ? a.data : a).concat(b.data);
  360. }, []);
  361. }
  362. function dataCombineStack(series) {
  363. var sum = new Array(series[0].data.length);
  364. for (var j = 0; j < sum.length; j++) {
  365. sum[j] = 0;
  366. }
  367. for (var i = 0; i < series.length; i++) {
  368. for (var j = 0; j < sum.length; j++) {
  369. sum[j] += series[i].data[j];
  370. }
  371. }
  372. return series.reduce(function(a, b) {
  373. return (a.data ? a.data : a).concat(b.data).concat(sum);
  374. }, []);
  375. }
  376. function getTouches(touches, opts, e) {
  377. let x, y;
  378. if (touches.clientX) {
  379. if (opts.rotate) { //适配横屏
  380. y = opts.height - touches.clientX * opts.pixelRatio;
  381. x = (touches.pageY - e.currentTarget.offsetTop - (opts.height / opts.pixelRatio / 2) * (opts.pixelRatio - 1)) *
  382. opts.pixelRatio;
  383. } else {
  384. x = touches.clientX * opts.pixelRatio;
  385. y = (touches.pageY - e.currentTarget.offsetTop - (opts.height / opts.pixelRatio / 2) * (opts.pixelRatio - 1)) *
  386. opts.pixelRatio;
  387. }
  388. } else {
  389. if (opts.rotate) { //适配横屏
  390. y = opts.height - touches.x * opts.pixelRatio;
  391. x = touches.y * opts.pixelRatio;
  392. } else {
  393. x = touches.x * opts.pixelRatio;
  394. y = touches.y * opts.pixelRatio;
  395. }
  396. }
  397. return {
  398. x: x,
  399. y: y
  400. }
  401. }
  402. function getSeriesDataItem(series, index) {
  403. var data = [];
  404. for (let i = 0; i < series.length; i++) {
  405. let item = series[i];
  406. if (item.data[index] !== null && typeof item.data[index] !== 'undefined') {
  407. let seriesItem = {};
  408. seriesItem.color = item.color;
  409. seriesItem.type = item.type;
  410. seriesItem.style = item.style;
  411. seriesItem.shape = item.shape;
  412. seriesItem.disableLegend = item.disableLegend;
  413. seriesItem.name = item.name;
  414. seriesItem.data = item.format ? item.format(item.data[index]) : item.data[index];
  415. data.push(seriesItem);
  416. }
  417. }
  418. return data;
  419. }
  420. function getMaxTextListLength(list) {
  421. var lengthList = list.map(function(item) {
  422. return measureText(item);
  423. });
  424. return Math.max.apply(null, lengthList);
  425. }
  426. function getRadarCoordinateSeries(length) {
  427. var eachAngle = 2 * Math.PI / length;
  428. var CoordinateSeries = [];
  429. for (var i = 0; i < length; i++) {
  430. CoordinateSeries.push(eachAngle * i);
  431. }
  432. return CoordinateSeries.map(function(item) {
  433. return -1 * item + Math.PI / 2;
  434. });
  435. }
  436. function getToolTipData(seriesData, calPoints, index, categories) {
  437. var option = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
  438. var textList = seriesData.map(function(item) {
  439. return {
  440. text: option.format ? option.format(item, categories[index]) : item.name + ': ' + item.data,
  441. color: item.color
  442. };
  443. });
  444. var validCalPoints = [];
  445. var offset = {
  446. x: 0,
  447. y: 0
  448. };
  449. for (let i = 0; i < calPoints.length; i++) {
  450. let points = calPoints[i];
  451. if (typeof points[index] !== 'undefined' && points[index] !== null) {
  452. validCalPoints.push(points[index]);
  453. }
  454. }
  455. for (let i = 0; i < validCalPoints.length; i++) {
  456. let item = validCalPoints[i];
  457. offset.x = Math.round(item.x);
  458. offset.y += item.y;
  459. }
  460. offset.y /= validCalPoints.length;
  461. return {
  462. textList: textList,
  463. offset: offset
  464. };
  465. }
  466. function getMixToolTipData(seriesData, calPoints, index, categories) {
  467. var option = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
  468. var textList = seriesData.map(function(item) {
  469. return {
  470. text: option.format ? option.format(item, categories[index]) : item.name + ': ' + item.data,
  471. color: item.color,
  472. disableLegend: item.disableLegend ? true : false
  473. };
  474. });
  475. textList = textList.filter(function(item) {
  476. if (item.disableLegend !== true) {
  477. return item;
  478. }
  479. });
  480. var validCalPoints = [];
  481. var offset = {
  482. x: 0,
  483. y: 0
  484. };
  485. for (let i = 0; i < calPoints.length; i++) {
  486. let points = calPoints[i];
  487. if (typeof points[index] !== 'undefined' && points[index] !== null) {
  488. validCalPoints.push(points[index]);
  489. }
  490. }
  491. for (let i = 0; i < validCalPoints.length; i++) {
  492. let item = validCalPoints[i];
  493. offset.x = Math.round(item.x);
  494. offset.y += item.y;
  495. }
  496. offset.y /= validCalPoints.length;
  497. return {
  498. textList: textList,
  499. offset: offset
  500. };
  501. }
  502. function getCandleToolTipData(series, seriesData, calPoints, index, categories, extra) {
  503. var option = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : {};
  504. let upColor = extra.color.upFill;
  505. let downColor = extra.color.downFill;
  506. //颜色顺序为开盘,收盘,最低,最高
  507. let color = [upColor, upColor, downColor, upColor];
  508. var textList = [];
  509. let text0 = {
  510. text: categories[index],
  511. color: null
  512. };
  513. textList.push(text0);
  514. seriesData.map(function(item) {
  515. //console.log(color)
  516. if (index == 0 && item.data[1] - item.data[0] < 0) {
  517. color[1] = downColor;
  518. } else {
  519. if (item.data[0] < series[index - 1][1]) {
  520. color[0] = downColor;
  521. }
  522. if (item.data[1] < item.data[0]) {
  523. color[1] = downColor;
  524. }
  525. if (item.data[2] > series[index - 1][1]) {
  526. color[2] = upColor;
  527. }
  528. if (item.data[3] < series[index - 1][1]) {
  529. color[3] = downColor;
  530. }
  531. }
  532. let text1 = {
  533. text: '开盘:' + item.data[0],
  534. color: color[0]
  535. };
  536. let text2 = {
  537. text: '收盘:' + item.data[1],
  538. color: color[1]
  539. };
  540. let text3 = {
  541. text: '最低:' + item.data[2],
  542. color: color[2]
  543. };
  544. let text4 = {
  545. text: '最高:' + item.data[3],
  546. color: color[3]
  547. };
  548. textList.push(text1, text2, text3, text4);
  549. });
  550. var validCalPoints = [];
  551. var offset = {
  552. x: 0,
  553. y: 0
  554. };
  555. for (let i = 0; i < calPoints.length; i++) {
  556. let points = calPoints[i];
  557. if (typeof points[index] !== 'undefined' && points[index] !== null) {
  558. validCalPoints.push(points[index]);
  559. }
  560. }
  561. offset.x = Math.round(validCalPoints[0][0].x);
  562. return {
  563. textList: textList,
  564. offset: offset
  565. };
  566. }
  567. function findCurrentIndex(currentPoints, xAxisPoints, opts, config) {
  568. var offset = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0;
  569. var currentIndex = -1;
  570. if (isInExactChartArea(currentPoints, opts, config)) {
  571. xAxisPoints.forEach(function(item, index) {
  572. if (currentPoints.x + offset > item) {
  573. currentIndex = index;
  574. }
  575. });
  576. }
  577. return currentIndex;
  578. }
  579. function isInExactChartArea(currentPoints, opts, config) {
  580. return currentPoints.x < opts.width - config.padding && currentPoints.x > config.padding + config.yAxisWidth + config.yAxisTitleWidth &&
  581. currentPoints.y > config.padding && currentPoints.y < opts.height - config.legendHeight - config.xAxisHeight - config
  582. .padding;
  583. }
  584. function findRadarChartCurrentIndex(currentPoints, radarData, count) {
  585. var eachAngleArea = 2 * Math.PI / count;
  586. var currentIndex = -1;
  587. if (isInExactPieChartArea(currentPoints, radarData.center, radarData.radius)) {
  588. var fixAngle = function fixAngle(angle) {
  589. if (angle < 0) {
  590. angle += 2 * Math.PI;
  591. }
  592. if (angle > 2 * Math.PI) {
  593. angle -= 2 * Math.PI;
  594. }
  595. return angle;
  596. };
  597. var angle = Math.atan2(radarData.center.y - currentPoints.y, currentPoints.x - radarData.center.x);
  598. angle = -1 * angle;
  599. if (angle < 0) {
  600. angle += 2 * Math.PI;
  601. }
  602. var angleList = radarData.angleList.map(function(item) {
  603. item = fixAngle(-1 * item);
  604. return item;
  605. });
  606. angleList.forEach(function(item, index) {
  607. var rangeStart = fixAngle(item - eachAngleArea / 2);
  608. var rangeEnd = fixAngle(item + eachAngleArea / 2);
  609. if (rangeEnd < rangeStart) {
  610. rangeEnd += 2 * Math.PI;
  611. }
  612. if (angle >= rangeStart && angle <= rangeEnd || angle + 2 * Math.PI >= rangeStart && angle + 2 * Math.PI <=
  613. rangeEnd) {
  614. currentIndex = index;
  615. }
  616. });
  617. }
  618. return currentIndex;
  619. }
  620. function findPieChartCurrentIndex(currentPoints, pieData) {
  621. var currentIndex = -1;
  622. if (isInExactPieChartArea(currentPoints, pieData.center, pieData.radius)) {
  623. var angle = Math.atan2(pieData.center.y - currentPoints.y, currentPoints.x - pieData.center.x);
  624. angle = -angle;
  625. for (var i = 0, len = pieData.series.length; i < len; i++) {
  626. var item = pieData.series[i];
  627. if (isInAngleRange(angle, item._start_, item._start_ + item._proportion_ * 2 * Math.PI)) {
  628. currentIndex = i;
  629. break;
  630. }
  631. }
  632. }
  633. return currentIndex;
  634. }
  635. function isInExactPieChartArea(currentPoints, center, radius) {
  636. return Math.pow(currentPoints.x - center.x, 2) + Math.pow(currentPoints.y - center.y, 2) <= Math.pow(radius, 2);
  637. }
  638. function splitPoints(points) {
  639. var newPoints = [];
  640. var items = [];
  641. points.forEach(function(item, index) {
  642. if (item !== null) {
  643. items.push(item);
  644. } else {
  645. if (items.length) {
  646. newPoints.push(items);
  647. }
  648. items = [];
  649. }
  650. });
  651. if (items.length) {
  652. newPoints.push(items);
  653. }
  654. return newPoints;
  655. }
  656. function calLegendData(series, opts, config) {
  657. if (opts.legend === false) {
  658. return {
  659. legendList: [],
  660. legendHeight: 0
  661. };
  662. }
  663. //适配H5高分屏
  664. var padding = 5 * opts.pixelRatio;
  665. var marginTop = 8 * opts.pixelRatio;
  666. var shapeWidth = 15 * opts.pixelRatio;
  667. var legendList = [];
  668. var widthCount = 0;
  669. var currentRow = [];
  670. for (let i = 0; i < series.length; i++) {
  671. let item = series[i];
  672. let itemWidth = 3 * padding + shapeWidth + measureText(item.name || 'undefined');
  673. if (widthCount + itemWidth > opts.width) {
  674. legendList.push(currentRow);
  675. widthCount = itemWidth;
  676. currentRow = [item];
  677. } else {
  678. widthCount += itemWidth;
  679. currentRow.push(item);
  680. }
  681. }
  682. if (currentRow.length) {
  683. legendList.push(currentRow);
  684. }
  685. return {
  686. legendList: legendList,
  687. legendHeight: legendList.length * (config.fontSize + marginTop) + padding
  688. };
  689. }
  690. function calCategoriesData(categories, opts, config) {
  691. var result = {
  692. angle: 0,
  693. xAxisHeight: config.xAxisHeight
  694. };
  695. var _getXAxisPoints = getXAxisPoints(categories, opts, config),
  696. eachSpacing = _getXAxisPoints.eachSpacing;
  697. // get max length of categories text
  698. var categoriesTextLenth = categories.map(function(item) {
  699. return measureText(item);
  700. });
  701. var maxTextLength = Math.max.apply(this, categoriesTextLenth);
  702. if (opts.xAxis.rotateLabel == true && maxTextLength + 2 * config.xAxisTextPadding > eachSpacing) {
  703. result.angle = 45 * Math.PI / 180;
  704. result.xAxisHeight = 2 * config.xAxisTextPadding + maxTextLength * Math.sin(result.angle);
  705. }
  706. return result;
  707. }
  708. function getRadarDataPoints(angleList, center, radius, series, opts) {
  709. var process = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 1;
  710. var radarOption = opts.extra.radar || {};
  711. radarOption.max = radarOption.max || 0;
  712. var maxData = Math.max(radarOption.max, Math.max.apply(null, dataCombine(series)));
  713. var data = [];
  714. for (let i = 0; i < series.length; i++) {
  715. let each = series[i];
  716. let listItem = {};
  717. listItem.color = each.color;
  718. listItem.data = [];
  719. each.data.forEach(function(item, index) {
  720. let tmp = {};
  721. tmp.angle = angleList[index];
  722. tmp.proportion = item / maxData;
  723. tmp.position = convertCoordinateOrigin(radius * tmp.proportion * process * Math.cos(tmp.angle), radius * tmp.proportion *
  724. process * Math.sin(tmp.angle), center);
  725. listItem.data.push(tmp);
  726. });
  727. data.push(listItem);
  728. }
  729. return data;
  730. }
  731. function getPieDataPoints(series, radius) {
  732. var process = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
  733. var count = 0;
  734. var _start_ = 0;
  735. for (let i = 0; i < series.length; i++) {
  736. let item = series[i];
  737. item.data = item.data === null ? 0 : item.data;
  738. count += item.data;
  739. }
  740. for (let i = 0; i < series.length; i++) {
  741. let item = series[i];
  742. item.data = item.data === null ? 0 : item.data;
  743. if (count === 0) {
  744. item._proportion_ = 1 / series.length * process;
  745. } else {
  746. item._proportion_ = item.data / count * process;
  747. }
  748. item._radius_=radius;
  749. }
  750. for (let i = 0; i < series.length; i++) {
  751. let item = series[i];
  752. item._start_ = _start_;
  753. _start_ += 2 * item._proportion_ * Math.PI;
  754. }
  755. return series;
  756. }
  757. function getRoseDataPoints(series, type, minRadius, radius) {
  758. var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
  759. var count = 0;
  760. var _start_ = 0;
  761. var dataArr=[];
  762. for (let i = 0; i < series.length; i++) {
  763. let item = series[i];
  764. item.data = item.data === null ? 0 : item.data;
  765. count += item.data;
  766. dataArr.push(item.data);
  767. }
  768. var minData = dataArr.pop();
  769. var maxData = dataArr.shift();
  770. var radiusLength = radius - minRadius;
  771. for (let i = 0; i < series.length; i++) {
  772. let item = series[i];
  773. item.data = item.data === null ? 0 : item.data;
  774. if (count === 0 || type == 'area') {
  775. item._proportion_ = 1 / series.length * process;
  776. } else {
  777. item._proportion_ = item.data / count * process;
  778. }
  779. item._radius_ = minRadius + radiusLength * ( (item.data - minData)/(maxData-minData) );
  780. }
  781. for (let i = 0; i < series.length; i++) {
  782. let item = series[i];
  783. item._start_ = _start_;
  784. _start_ += 2 * item._proportion_ * Math.PI;
  785. }
  786. return series;
  787. }
  788. function getArcbarDataPoints(series, arcbarOption) {
  789. var process = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
  790. if (process == 1) {
  791. process = 0.999999;
  792. }
  793. for (let i = 0; i < series.length; i++) {
  794. let item = series[i];
  795. item.data = item.data === null ? 0 : item.data;
  796. let totalAngle;
  797. if (arcbarOption.type == 'default') {
  798. totalAngle = arcbarOption.startAngle - arcbarOption.endAngle + 1;
  799. } else {
  800. totalAngle = 2;
  801. }
  802. item._proportion_ = totalAngle * item.data * process + arcbarOption.startAngle;
  803. if (item._proportion_ >= 2) {
  804. item._proportion_ = item._proportion_ % 2;
  805. }
  806. }
  807. return series;
  808. }
  809. function getGaugeAxisPoints(categories, startAngle, endAngle) {
  810. let totalAngle = startAngle - endAngle + 1;
  811. let tempStartAngle = startAngle;
  812. for (let i = 0; i < categories.length; i++) {
  813. categories[i].value = categories[i].value === null ? 0 : categories[i].value;
  814. categories[i]._startAngle_ = tempStartAngle;
  815. categories[i]._endAngle_ = totalAngle * categories[i].value + startAngle;
  816. if (categories[i]._endAngle_ >= 2) {
  817. categories[i]._endAngle_ = categories[i]._endAngle_ % 2;
  818. }
  819. tempStartAngle = categories[i]._endAngle_;
  820. }
  821. return categories;
  822. }
  823. function getGaugeDataPoints(series, categories, gaugeOption) {
  824. let process = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 1;
  825. for (let i = 0; i < series.length; i++) {
  826. let item = series[i];
  827. item.data = item.data === null ? 0 : item.data;
  828. if (gaugeOption.pointer.color == 'auto') {
  829. for (let i = 0; i < categories.length; i++) {
  830. if (item.data <= categories[i].value) {
  831. item.color = categories[i].color;
  832. break;
  833. }
  834. }
  835. } else {
  836. item.color = gaugeOption.pointer.color;
  837. }
  838. let totalAngle = gaugeOption.startAngle - gaugeOption.endAngle + 1;
  839. item._endAngle_ = totalAngle * item.data + gaugeOption.startAngle;
  840. item._oldAngle_ = gaugeOption.oldAngle;
  841. if (gaugeOption.oldAngle < gaugeOption.endAngle) {
  842. item._oldAngle_ += 2;
  843. }
  844. if (item.data >= gaugeOption.oldData) {
  845. item._proportion_ = (item._endAngle_ - item._oldAngle_) * process + gaugeOption.oldAngle;
  846. } else {
  847. item._proportion_ = item._oldAngle_ - (item._oldAngle_ - item._endAngle_) * process;
  848. }
  849. if (item._proportion_ >= 2) {
  850. item._proportion_ = item._proportion_ % 2;
  851. }
  852. }
  853. return series;
  854. }
  855. function getPieTextMaxLength(series) {
  856. series = getPieDataPoints(series);
  857. let maxLength = 0;
  858. for (let i = 0; i < series.length; i++) {
  859. let item = series[i];
  860. let text = item.format ? item.format(+item._proportion_.toFixed(2)) : util.toFixed(item._proportion_ * 100) + '%';
  861. maxLength = Math.max(maxLength, measureText(text));
  862. }
  863. return maxLength;
  864. }
  865. function fixColumeData(points, eachSpacing, columnLen, index, config, opts) {
  866. return points.map(function(item) {
  867. if (item === null) {
  868. return null;
  869. }
  870. item.width = Math.ceil((eachSpacing - 2 * config.columePadding) / columnLen);
  871. if (opts.extra.column && opts.extra.column.width && +opts.extra.column.width > 0) {
  872. item.width = Math.min(item.width, +opts.extra.column.width);
  873. }
  874. item.x += (index + 0.5 - columnLen / 2) * item.width;
  875. return item;
  876. });
  877. }
  878. function fixColumeMeterData(points, eachSpacing, columnLen, index, config, opts, border) {
  879. return points.map(function(item) {
  880. if (item === null) {
  881. return null;
  882. }
  883. item.width = eachSpacing - 2 * config.columePadding;
  884. if (opts.extra.column && opts.extra.column.width && +opts.extra.column.width > 0) {
  885. item.width = Math.min(item.width, +opts.extra.column.width);
  886. } else {
  887. item.width = Math.min(item.width, 25);
  888. }
  889. if (index > 0) {
  890. item.width -= 2 * border;
  891. }
  892. return item;
  893. });
  894. }
  895. function fixColumeStackData(points, eachSpacing, columnLen, index, config, opts, series) {
  896. return points.map(function(item, indexn) {
  897. if (item === null) {
  898. return null;
  899. }
  900. item.width = eachSpacing - 2 * config.columePadding;
  901. if (opts.extra.column && opts.extra.column.width && +opts.extra.column.width > 0) {
  902. item.width = Math.min(item.width, +opts.extra.column.width);
  903. } else {
  904. item.width = Math.min(item.width, 25);
  905. }
  906. return item;
  907. });
  908. }
  909. function getXAxisPoints(categories, opts, config) {
  910. var yAxisTotalWidth = config.yAxisWidth + config.yAxisTitleWidth;
  911. var spacingValid = opts.width - 2 * config.padding - yAxisTotalWidth;
  912. var dataCount = opts.enableScroll ? Math.min(opts.xAxis.itemCount, categories.length) : categories.length;
  913. var eachSpacing = spacingValid / dataCount;
  914. var xAxisPoints = [];
  915. var startX = config.padding + yAxisTotalWidth;
  916. var endX = opts.width - config.padding;
  917. categories.forEach(function(item, index) {
  918. xAxisPoints.push(startX + index * eachSpacing);
  919. });
  920. if (opts.enableScroll === true) {
  921. xAxisPoints.push(startX + categories.length * eachSpacing);
  922. } else {
  923. xAxisPoints.push(endX);
  924. }
  925. return {
  926. xAxisPoints: xAxisPoints,
  927. startX: startX,
  928. endX: endX,
  929. eachSpacing: eachSpacing
  930. };
  931. }
  932. function getCandleDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config) {
  933. var process = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : 1;
  934. var points = [];
  935. var validHeight = opts.height - 2 * config.padding - config.xAxisHeight - config.legendHeight;
  936. data.forEach(function(item, index) {
  937. if (item === null) {
  938. points.push(null);
  939. } else {
  940. var cPoints = [];
  941. item.forEach(function(items, indexs) {
  942. var point = {};
  943. point.x = xAxisPoints[index] + Math.round(eachSpacing / 2);
  944. var value = items.value || items;
  945. var height = validHeight * (value - minRange) / (maxRange - minRange);
  946. height *= process;
  947. point.y = opts.height - config.xAxisHeight - config.legendHeight - Math.round(height) - config.padding;
  948. cPoints.push(point);
  949. });
  950. points.push(cPoints);
  951. }
  952. });
  953. return points;
  954. }
  955. function getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config) {
  956. var process = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : 1;
  957. var points = [];
  958. var validHeight = opts.height - 2 * config.padding - config.xAxisHeight - config.legendHeight;
  959. data.forEach(function(item, index) {
  960. if (item === null) {
  961. points.push(null);
  962. } else {
  963. var point = {};
  964. point.color = item.color;
  965. point.x = xAxisPoints[index] + Math.round(eachSpacing / 2);
  966. var value = item;
  967. if (typeof item === 'object' && item !== null) {
  968. value = item.value
  969. }
  970. var height = validHeight * (value - minRange) / (maxRange - minRange);
  971. height *= process;
  972. point.y = opts.height - config.xAxisHeight - config.legendHeight - Math.round(height) - config.padding;
  973. points.push(point);
  974. }
  975. });
  976. return points;
  977. }
  978. function getStackDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, seriesIndex, stackSeries) {
  979. var process = arguments.length > 9 && arguments[9] !== undefined ? arguments[9] : 1;
  980. var points = [];
  981. var validHeight = opts.height - 2 * config.padding - config.xAxisHeight - config.legendHeight;
  982. data.forEach(function(item, index) {
  983. if (item === null) {
  984. points.push(null);
  985. } else {
  986. var point = {};
  987. point.color = item.color;
  988. point.x = xAxisPoints[index] + Math.round(eachSpacing / 2);
  989. if (seriesIndex > 0) {
  990. var value = 0;
  991. for (let i = 0; i <= seriesIndex; i++) {
  992. value += stackSeries[i].data[index];
  993. }
  994. var value0 = value - item;
  995. var height = validHeight * (value - minRange) / (maxRange - minRange);
  996. var height0 = validHeight * (value0 - minRange) / (maxRange - minRange);
  997. } else {
  998. var value = item;
  999. var height = validHeight * (value - minRange) / (maxRange - minRange);
  1000. var height0 = 0;
  1001. }
  1002. var heightc = height0;
  1003. height *= process;
  1004. heightc *= process;
  1005. point.y = opts.height - config.xAxisHeight - config.legendHeight - Math.round(height) - config.padding;
  1006. point.y0 = opts.height - config.xAxisHeight - config.legendHeight - Math.round(heightc) - config.padding;
  1007. points.push(point);
  1008. }
  1009. });
  1010. return points;
  1011. }
  1012. function getYAxisTextList(series, opts, config, stack) {
  1013. var data;
  1014. if (stack == 'stack') {
  1015. //data = dataCombine(series);
  1016. data = dataCombineStack(series);
  1017. } else {
  1018. data = dataCombine(series);
  1019. }
  1020. var sorted = [];
  1021. // remove null from data
  1022. data = data.filter(function(item) {
  1023. //return item !== null;
  1024. if (typeof item === 'object' && item !== null) {
  1025. //判断是否为数组
  1026. if (item.constructor == Array) {
  1027. return item !== null;
  1028. } else {
  1029. return item.value !== null;
  1030. }
  1031. } else {
  1032. return item !== null;
  1033. }
  1034. });
  1035. //var minData = Math.min.apply(this, data);
  1036. //var maxData = Math.max.apply(this, data);
  1037. data.map(function(item) {
  1038. if (typeof item === 'object') {
  1039. if (item.constructor == Array) {
  1040. item.map(function(subitem) {
  1041. sorted.push(subitem);
  1042. })
  1043. } else {
  1044. sorted.push(item.value);
  1045. }
  1046. } else {
  1047. sorted.push(item);
  1048. }
  1049. //typeof item === 'object' ? sorted.push(item.value) : sorted.push(item)
  1050. })
  1051. var minData = 0;
  1052. var maxData = 0;
  1053. if (sorted.length > 0) {
  1054. minData = Math.min.apply(this, sorted);
  1055. maxData = Math.max.apply(this, sorted);
  1056. }
  1057. if (typeof opts.yAxis.min === 'number') {
  1058. minData = Math.min(opts.yAxis.min, minData);
  1059. }
  1060. if (typeof opts.yAxis.max === 'number') {
  1061. maxData = Math.max(opts.yAxis.max, maxData);
  1062. }
  1063. // fix issue https://github.com/xiaolin3303/wx-charts/issues/9
  1064. if (minData === maxData) {
  1065. var rangeSpan = maxData || 10;
  1066. //minData -= rangeSpan;
  1067. maxData += rangeSpan;
  1068. }
  1069. var dataRange = getDataRange(minData, maxData);
  1070. var minRange = dataRange.minRange;
  1071. var maxRange = dataRange.maxRange;
  1072. var range = [];
  1073. var eachRange = (maxRange - minRange) / config.yAxisSplit;
  1074. for (var i = 0; i <= config.yAxisSplit; i++) {
  1075. range.push(minRange + eachRange * i);
  1076. }
  1077. return range.reverse();
  1078. }
  1079. function calYAxisData(series, opts, config) {
  1080. //堆叠图重算Y轴
  1081. var columnstyle = assign({}, opts.extra.column || {
  1082. "type": ""
  1083. });
  1084. var ranges = getYAxisTextList(series, opts, config, columnstyle.type);
  1085. var yAxisWidth = config.yAxisWidth;
  1086. var rangesFormat = ranges.map(function(item) {
  1087. item = util.toFixed(item, 2);
  1088. item = opts.yAxis.format ? opts.yAxis.format(Number(item)) : item;
  1089. yAxisWidth = Math.max(yAxisWidth, measureText(item) + 5);
  1090. return item;
  1091. });
  1092. if (opts.yAxis.disabled === true) {
  1093. yAxisWidth = 0;
  1094. }
  1095. return {
  1096. rangesFormat: rangesFormat,
  1097. ranges: ranges,
  1098. yAxisWidth: yAxisWidth
  1099. };
  1100. }
  1101. function calTooltipYAxisData(point, series, opts, config, eachSpacing) {
  1102. var ranges = getYAxisTextList(series, opts, config);
  1103. var spacingValid = opts.height - 2 * config.padding - config.xAxisHeight - config.legendHeight;
  1104. let maxVal = ranges[0];
  1105. let minVal = ranges[ranges.length - 1];
  1106. let minAxis = config.padding;
  1107. let maxAxis = config.padding + spacingValid;
  1108. let item = maxVal - (maxVal - minVal) * (point - minAxis) / (maxAxis - minAxis);
  1109. item = opts.yAxis.format ? opts.yAxis.format(Number(item)) : item;
  1110. return item;
  1111. }
  1112. function contextRotate(context, opts) {
  1113. if (opts.rotateLock !== true) {
  1114. context.translate(opts.height, 0);
  1115. context.rotate(90 * Math.PI / 180);
  1116. } else if (opts._rotate_ !== true) {
  1117. context.translate(opts.height, 0);
  1118. context.rotate(90 * Math.PI / 180);
  1119. opts._rotate_ = true;
  1120. }
  1121. }
  1122. function drawPointShape(points, color, shape, context, opts) {
  1123. context.beginPath();
  1124. context.setStrokeStyle("#ffffff");
  1125. context.setLineWidth(1 * opts.pixelRatio);
  1126. context.setFillStyle(color);
  1127. if (shape === 'diamond') {
  1128. points.forEach(function(item, index) {
  1129. if (item !== null) {
  1130. context.moveTo(item.x, item.y - 4.5);
  1131. context.lineTo(item.x - 4.5, item.y);
  1132. context.lineTo(item.x, item.y + 4.5);
  1133. context.lineTo(item.x + 4.5, item.y);
  1134. context.lineTo(item.x, item.y - 4.5);
  1135. }
  1136. });
  1137. } else if (shape === 'circle') {
  1138. points.forEach(function(item, index) {
  1139. if (item !== null) {
  1140. context.moveTo(item.x + 3.5 * opts.pixelRatio, item.y);
  1141. context.arc(item.x, item.y, 4 * opts.pixelRatio, 0, 2 * Math.PI, false);
  1142. }
  1143. });
  1144. } else if (shape === 'rect') {
  1145. points.forEach(function(item, index) {
  1146. if (item !== null) {
  1147. context.moveTo(item.x - 3.5, item.y - 3.5);
  1148. context.rect(item.x - 3.5, item.y - 3.5, 7, 7);
  1149. }
  1150. });
  1151. } else if (shape === 'triangle') {
  1152. points.forEach(function(item, index) {
  1153. if (item !== null) {
  1154. context.moveTo(item.x, item.y - 4.5);
  1155. context.lineTo(item.x - 4.5, item.y + 4.5);
  1156. context.lineTo(item.x + 4.5, item.y + 4.5);
  1157. context.lineTo(item.x, item.y - 4.5);
  1158. }
  1159. });
  1160. }
  1161. context.closePath();
  1162. context.fill();
  1163. context.stroke();
  1164. }
  1165. function drawRingTitle(opts, config, context) {
  1166. var titlefontSize = opts.title.fontSize || config.titleFontSize;
  1167. var subtitlefontSize = opts.subtitle.fontSize || config.subtitleFontSize;
  1168. var title = opts.title.name || '';
  1169. var subtitle = opts.subtitle.name || '';
  1170. var titleFontColor = opts.title.color || config.titleColor;
  1171. var subtitleFontColor = opts.subtitle.color || config.subtitleColor;
  1172. var titleHeight = title ? titlefontSize : 0;
  1173. var subtitleHeight = subtitle ? subtitlefontSize : 0;
  1174. var margin = 5;
  1175. if (subtitle) {
  1176. var textWidth = measureText(subtitle, subtitlefontSize);
  1177. var startX = (opts.width - textWidth) / 2 + (opts.subtitle.offsetX || 0);
  1178. var startY = ((opts.height - config.legendHeight + subtitlefontSize) / 2) + (opts.subtitle.offsetY || 0);
  1179. if (title) {
  1180. startY -= (titleHeight + margin) / 2;
  1181. }
  1182. context.beginPath();
  1183. context.setFontSize(subtitlefontSize);
  1184. context.setFillStyle(subtitleFontColor);
  1185. context.fillText(subtitle, startX, startY);
  1186. context.closePath();
  1187. context.stroke();
  1188. }
  1189. if (title) {
  1190. var _textWidth = measureText(title, titlefontSize);
  1191. var _startX = (opts.width - _textWidth) / 2 + (opts.title.offsetX || 0);
  1192. var _startY = ((opts.height - config.legendHeight + titlefontSize) / 2) + (opts.title.offsetY || 0);
  1193. if (subtitle) {
  1194. _startY += (subtitleHeight + margin) / 2;
  1195. }
  1196. context.beginPath();
  1197. context.setFontSize(titlefontSize);
  1198. context.setFillStyle(titleFontColor);
  1199. context.fillText(title, _startX, _startY);
  1200. context.closePath();
  1201. context.stroke();
  1202. }
  1203. }
  1204. function drawPointText(points, series, config, context) {
  1205. // 绘制数据文案
  1206. var data = series.data;
  1207. points.forEach(function(item, index) {
  1208. if (item !== null) {
  1209. //var formatVal = series.format ? series.format(data[index]) : data[index];
  1210. context.beginPath();
  1211. context.setFontSize(series.textSize || config.fontSize);
  1212. context.setFillStyle(series.textColor || '#666666');
  1213. var value = data[index]
  1214. if (typeof data[index] === 'object' && data[index] !== null) {
  1215. value = data[index].value
  1216. }
  1217. var formatVal = series.format ? series.format(value) : value;
  1218. context.fillText(formatVal, item.x - measureText(formatVal,series.textSize || config.fontSize) / 2, item.y - 2);
  1219. context.closePath();
  1220. context.stroke();
  1221. }
  1222. });
  1223. }
  1224. function drawGaugeLabel(gaugeOption, radius, centerPosition, opts, config, context) {
  1225. radius -= gaugeOption.width / 2 + config.gaugeLabelTextMargin;
  1226. let totalAngle = gaugeOption.startAngle - gaugeOption.endAngle + 1;
  1227. let splitAngle = totalAngle / gaugeOption.splitLine.splitNumber;
  1228. let totalNumber = gaugeOption.endNumber - gaugeOption.startNumber;
  1229. let splitNumber = totalNumber / gaugeOption.splitLine.splitNumber;
  1230. let nowAngle = gaugeOption.startAngle;
  1231. let nowNumber = gaugeOption.startNumber;
  1232. for (let i = 0; i < gaugeOption.splitLine.splitNumber + 1; i++) {
  1233. var pos = {
  1234. x: radius * Math.cos(nowAngle * Math.PI),
  1235. y: radius * Math.sin(nowAngle * Math.PI)
  1236. };
  1237. var labelText = gaugeOption.labelFormat ? gaugeOption.labelFormat(nowNumber) : nowNumber;
  1238. pos.x += centerPosition.x - measureText(labelText) / 2;
  1239. pos.y += centerPosition.y;
  1240. var startX = pos.x;
  1241. var startY = pos.y;
  1242. context.beginPath();
  1243. context.setFontSize(config.fontSize);
  1244. context.setFillStyle(gaugeOption.labelColor || '#666666');
  1245. context.fillText(labelText, startX, startY + config.fontSize / 2);
  1246. context.closePath();
  1247. context.stroke();
  1248. nowAngle += splitAngle;
  1249. if (nowAngle >= 2) {
  1250. nowAngle = nowAngle % 2;
  1251. }
  1252. nowNumber += splitNumber;
  1253. }
  1254. }
  1255. function drawRadarLabel(angleList, radius, centerPosition, opts, config, context) {
  1256. var radarOption = opts.extra.radar || {};
  1257. radius += config.radarLabelTextMargin;
  1258. angleList.forEach(function(angle, index) {
  1259. var pos = {
  1260. x: radius * Math.cos(angle),
  1261. y: radius * Math.sin(angle)
  1262. };
  1263. var posRelativeCanvas = convertCoordinateOrigin(pos.x, pos.y, centerPosition);
  1264. var startX = posRelativeCanvas.x;
  1265. var startY = posRelativeCanvas.y;
  1266. if (util.approximatelyEqual(pos.x, 0)) {
  1267. startX -= measureText(opts.categories[index] || '') / 2;
  1268. } else if (pos.x < 0) {
  1269. startX -= measureText(opts.categories[index] || '');
  1270. }
  1271. context.beginPath();
  1272. context.setFontSize(config.fontSize);
  1273. context.setFillStyle(radarOption.labelColor || '#666666');
  1274. context.fillText(opts.categories[index] || '', startX, startY + config.fontSize / 2);
  1275. context.closePath();
  1276. context.stroke();
  1277. });
  1278. }
  1279. function drawPieText(series, opts, config, context, radius, center) {
  1280. var lineRadius = config.pieChartLinePadding;
  1281. var textObjectCollection = [];
  1282. var lastTextObject = null;
  1283. var seriesConvert = series.map(function(item) {
  1284. var arc = 2 * Math.PI - (item._start_ + 2 * Math.PI * item._proportion_ / 2);
  1285. var text = item.format ? item.format(+item._proportion_.toFixed(2)) : util.toFixed(item._proportion_ * 100) + '%';
  1286. var color = item.color;
  1287. var radius = item._radius_;
  1288. return {
  1289. arc: arc,
  1290. text: text,
  1291. color: color,
  1292. radius: radius,
  1293. textColor: item.textColor,
  1294. textSize: item.textSize,
  1295. };
  1296. });
  1297. for (let i = 0; i < seriesConvert.length; i++) {
  1298. let item = seriesConvert[i];
  1299. // line end
  1300. let orginX1 = Math.cos(item.arc) * (item.radius+lineRadius);
  1301. let orginY1 = Math.sin(item.arc) * (item.radius+lineRadius);
  1302. // line start
  1303. let orginX2 = Math.cos(item.arc) * item.radius;
  1304. let orginY2 = Math.sin(item.arc) * item.radius;
  1305. // text start
  1306. let orginX3 = orginX1 >= 0 ? orginX1 + config.pieChartTextPadding : orginX1 - config.pieChartTextPadding;
  1307. let orginY3 = orginY1;
  1308. let textWidth = measureText(item.text);
  1309. let startY = orginY3;
  1310. if (lastTextObject && util.isSameXCoordinateArea(lastTextObject.start, {
  1311. x: orginX3
  1312. })) {
  1313. if (orginX3 > 0) {
  1314. startY = Math.min(orginY3, lastTextObject.start.y);
  1315. } else if (orginX1 < 0) {
  1316. startY = Math.max(orginY3, lastTextObject.start.y);
  1317. } else {
  1318. if (orginY3 > 0) {
  1319. startY = Math.max(orginY3, lastTextObject.start.y);
  1320. } else {
  1321. startY = Math.min(orginY3, lastTextObject.start.y);
  1322. }
  1323. }
  1324. }
  1325. if (orginX3 < 0) {
  1326. orginX3 -= textWidth;
  1327. }
  1328. let textObject = {
  1329. lineStart: {
  1330. x: orginX2,
  1331. y: orginY2
  1332. },
  1333. lineEnd: {
  1334. x: orginX1,
  1335. y: orginY1
  1336. },
  1337. start: {
  1338. x: orginX3,
  1339. y: startY
  1340. },
  1341. width: textWidth,
  1342. height: config.fontSize,
  1343. text: item.text,
  1344. color: item.color,
  1345. textColor: item.textColor,
  1346. textSize: item.textSize
  1347. };
  1348. lastTextObject = avoidCollision(textObject, lastTextObject);
  1349. textObjectCollection.push(lastTextObject);
  1350. }
  1351. for (let i = 0; i < textObjectCollection.length; i++) {
  1352. let item = textObjectCollection[i];
  1353. let lineStartPoistion = convertCoordinateOrigin(item.lineStart.x, item.lineStart.y, center);
  1354. let lineEndPoistion = convertCoordinateOrigin(item.lineEnd.x, item.lineEnd.y, center);
  1355. let textPosition = convertCoordinateOrigin(item.start.x, item.start.y, center);
  1356. context.setLineWidth(1 * opts.pixelRatio);
  1357. context.setFontSize(config.fontSize);
  1358. context.beginPath();
  1359. context.setStrokeStyle(item.color);
  1360. context.setFillStyle(item.color);
  1361. context.moveTo(lineStartPoistion.x, lineStartPoistion.y);
  1362. let curveStartX = item.start.x < 0 ? textPosition.x + item.width : textPosition.x;
  1363. let textStartX = item.start.x < 0 ? textPosition.x - 5 : textPosition.x + 5;
  1364. context.quadraticCurveTo(lineEndPoistion.x, lineEndPoistion.y, curveStartX, textPosition.y);
  1365. context.moveTo(lineStartPoistion.x, lineStartPoistion.y);
  1366. context.stroke();
  1367. context.closePath();
  1368. context.beginPath();
  1369. context.moveTo(textPosition.x + item.width, textPosition.y);
  1370. context.arc(curveStartX, textPosition.y, 2, 0, 2 * Math.PI);
  1371. context.closePath();
  1372. context.fill();
  1373. context.beginPath();
  1374. context.setFontSize(item.textSize||config.fontSize);
  1375. context.setFillStyle(item.textColor||'#666666');
  1376. context.fillText(item.text, textStartX, textPosition.y + 3);
  1377. context.closePath();
  1378. context.stroke();
  1379. context.closePath();
  1380. }
  1381. }
  1382. function drawToolTipSplitLine(offsetX, opts, config, context) {
  1383. var toolTipOption = opts.extra.tooltip || {};
  1384. toolTipOption.gridType = toolTipOption.gridType == undefined ? 'solid' : toolTipOption.gridType;
  1385. toolTipOption.dashLength = toolTipOption.dashLength == undefined ? 4 : toolTipOption.dashLength;
  1386. var startY = config.padding;
  1387. var endY = opts.height - config.padding - config.xAxisHeight - config.legendHeight;
  1388. if (toolTipOption.gridType == 'dash') {
  1389. context.setLineDash([toolTipOption.dashLength, toolTipOption.dashLength]);
  1390. }
  1391. context.beginPath();
  1392. context.setStrokeStyle(toolTipOption.gridColor || '#cccccc');
  1393. context.setLineWidth(1 * opts.pixelRatio);
  1394. context.moveTo(offsetX, startY);
  1395. context.lineTo(offsetX, endY);
  1396. context.closePath();
  1397. context.stroke();
  1398. context.setLineDash([]);
  1399. if (toolTipOption.xAxisLabel) {
  1400. let labelText = opts.categories[opts.tooltip.index];
  1401. context.setFontSize(config.fontSize);
  1402. let textWidth = context.measureText(labelText).width;
  1403. let textX = offsetX - config.toolTipPadding - 0.5 * textWidth;
  1404. let textY = endY;
  1405. context.beginPath();
  1406. context.setFillStyle(hexToRgb(toolTipOption.labelBgColor || config.toolTipBackground, toolTipOption.labelBgOpacity ||
  1407. config.toolTipOpacity));
  1408. context.setStrokeStyle(toolTipOption.labelBgColor || config.toolTipBackground);
  1409. context.setLineWidth(1 * opts.pixelRatio);
  1410. context.rect(textX, textY, textWidth + 2 * config.toolTipPadding, config.fontSize + 2 * config.toolTipPadding);
  1411. context.closePath();
  1412. context.stroke();
  1413. context.fill();
  1414. context.beginPath();
  1415. context.setFontSize(config.fontSize);
  1416. context.setFillStyle(toolTipOption.labelFontColor || config.fontColor);
  1417. context.fillText(labelText, textX + 2 * config.toolTipPadding, textY + config.toolTipPadding + config.fontSize);
  1418. context.closePath();
  1419. context.stroke();
  1420. }
  1421. }
  1422. function drawToolTipHorizentalLine(opts, config, context, eachSpacing, xAxisPoints) {
  1423. var toolTipOption = opts.extra.tooltip || {};
  1424. toolTipOption.gridType = toolTipOption.gridType == undefined ? 'solid' : toolTipOption.gridType;
  1425. toolTipOption.dashLength = toolTipOption.dashLength == undefined ? 4 : toolTipOption.dashLength;
  1426. var startX = config.padding + config.yAxisWidth + config.yAxisTitleWidth;
  1427. var endX = opts.width - config.padding;
  1428. if (toolTipOption.gridType == 'dash') {
  1429. context.setLineDash([toolTipOption.dashLength, toolTipOption.dashLength]);
  1430. }
  1431. context.beginPath();
  1432. context.setStrokeStyle(toolTipOption.gridColor || '#cccccc');
  1433. context.setLineWidth(1 * opts.pixelRatio);
  1434. context.moveTo(startX, opts.tooltip.offset.y);
  1435. context.lineTo(endX, opts.tooltip.offset.y);
  1436. context.closePath();
  1437. context.stroke();
  1438. context.setLineDash([]);
  1439. if (toolTipOption.yAxisLabel) {
  1440. let labelText = calTooltipYAxisData(opts.tooltip.offset.y, opts.series, opts, config, eachSpacing);
  1441. context.setFontSize(config.fontSize);
  1442. let textWidth = context.measureText(labelText).width;
  1443. let textX = startX - 2 * config.toolTipPadding - textWidth;
  1444. let textY = opts.tooltip.offset.y;
  1445. context.beginPath();
  1446. context.setFillStyle(hexToRgb(toolTipOption.labelBgColor || config.toolTipBackground, toolTipOption.labelBgOpacity ||
  1447. config.toolTipOpacity));
  1448. context.setStrokeStyle(toolTipOption.labelBgColor || config.toolTipBackground);
  1449. context.setLineWidth(1 * opts.pixelRatio);
  1450. context.rect(textX, textY - 0.5 * config.fontSize - config.toolTipPadding, textWidth + 2 * config.toolTipPadding,
  1451. config.fontSize + 2 * config.toolTipPadding);
  1452. context.closePath();
  1453. context.stroke();
  1454. context.fill();
  1455. context.beginPath();
  1456. context.setFontSize(config.fontSize);
  1457. context.setFillStyle(toolTipOption.labelFontColor || config.fontColor);
  1458. context.fillText(labelText, textX + config.toolTipPadding, textY + 0.5 * config.fontSize);
  1459. context.closePath();
  1460. context.stroke();
  1461. }
  1462. }
  1463. function drawToolTipSplitArea(offsetX, opts, config, context, eachSpacing) {
  1464. var toolTipOption = opts.extra.tooltip || {
  1465. activeBgColor: '#000000',
  1466. activeBgOpacity: 0.08
  1467. };
  1468. toolTipOption.activeBgColor = toolTipOption.activeBgColor ? toolTipOption.activeBgColor : '#000000';
  1469. toolTipOption.activeBgOpacity = toolTipOption.activeBgOpacity ? toolTipOption.activeBgOpacity : 0.08;
  1470. var startY = config.padding;
  1471. var endY = opts.height - config.padding - config.xAxisHeight - config.legendHeight;
  1472. context.beginPath();
  1473. context.setFillStyle(hexToRgb(toolTipOption.activeBgColor, toolTipOption.activeBgOpacity));
  1474. context.rect(offsetX - eachSpacing / 2, startY, eachSpacing, endY - startY);
  1475. context.closePath();
  1476. context.fill();
  1477. }
  1478. function drawToolTip(textList, offset, opts, config, context, eachSpacing, xAxisPoints) {
  1479. var toolTipOption = opts.extra.tooltip || {
  1480. bgColor: '#000000',
  1481. bgOpacity: 0.7,
  1482. fontColor: '#FFFFFF'
  1483. };
  1484. toolTipOption.bgColor = toolTipOption.bgColor ? toolTipOption.bgColor : '#000000';
  1485. toolTipOption.bgOpacity = toolTipOption.bgOpacity ? toolTipOption.bgOpacity : 0.7;
  1486. toolTipOption.fontColor = toolTipOption.fontColor ? toolTipOption.fontColor : '#FFFFFF';
  1487. var legendWidth = 4 * opts.pixelRatio;
  1488. var legendMarginRight = 5 * opts.pixelRatio;
  1489. var arrowWidth = 8 * opts.pixelRatio;
  1490. var isOverRightBorder = false;
  1491. if (opts.type == 'line' || opts.type == 'area' || opts.type == 'candle' || opts.type == 'mix') {
  1492. drawToolTipSplitLine(opts.tooltip.offset.x, opts, config, context);
  1493. }
  1494. offset = assign({
  1495. x: 0,
  1496. y: 0
  1497. }, offset);
  1498. offset.y -= 8 * opts.pixelRatio;
  1499. var textWidth = textList.map(function(item) {
  1500. return measureText(item.text);
  1501. });
  1502. var toolTipWidth = legendWidth + legendMarginRight + 4 * config.toolTipPadding + Math.max.apply(null, textWidth);
  1503. var toolTipHeight = 2 * config.toolTipPadding + textList.length * config.toolTipLineHeight;
  1504. // if beyond the right border
  1505. if (offset.x - Math.abs(opts._scrollDistance_) + arrowWidth + toolTipWidth > opts.width) {
  1506. isOverRightBorder = true;
  1507. }
  1508. // draw background rect
  1509. context.beginPath();
  1510. context.setFillStyle(hexToRgb(toolTipOption.bgColor || config.toolTipBackground, toolTipOption.bgOpacity || config.toolTipOpacity));
  1511. if (isOverRightBorder) {
  1512. context.moveTo(offset.x, offset.y + 10 * opts.pixelRatio);
  1513. context.lineTo(offset.x - arrowWidth, offset.y + 10 * opts.pixelRatio - 5 * opts.pixelRatio);
  1514. context.lineTo(offset.x - arrowWidth, offset.y);
  1515. context.lineTo(offset.x - arrowWidth - Math.round(toolTipWidth), offset.y);
  1516. context.lineTo(offset.x - arrowWidth - Math.round(toolTipWidth), offset.y + toolTipHeight);
  1517. context.lineTo(offset.x - arrowWidth, offset.y + toolTipHeight);
  1518. context.lineTo(offset.x - arrowWidth, offset.y + 10 * opts.pixelRatio + 5 * opts.pixelRatio);
  1519. context.lineTo(offset.x, offset.y + 10 * opts.pixelRatio);
  1520. } else {
  1521. context.moveTo(offset.x, offset.y + 10 * opts.pixelRatio);
  1522. context.lineTo(offset.x + arrowWidth, offset.y + 10 * opts.pixelRatio - 5 * opts.pixelRatio);
  1523. context.lineTo(offset.x + arrowWidth, offset.y);
  1524. context.lineTo(offset.x + arrowWidth + Math.round(toolTipWidth), offset.y);
  1525. context.lineTo(offset.x + arrowWidth + Math.round(toolTipWidth), offset.y + toolTipHeight);
  1526. context.lineTo(offset.x + arrowWidth, offset.y + toolTipHeight);
  1527. context.lineTo(offset.x + arrowWidth, offset.y + 10 * opts.pixelRatio + 5 * opts.pixelRatio);
  1528. context.lineTo(offset.x, offset.y + 10 * opts.pixelRatio);
  1529. }
  1530. context.closePath();
  1531. context.fill();
  1532. // draw legend
  1533. textList.forEach(function(item, index) {
  1534. if (item.color !== null) {
  1535. context.beginPath();
  1536. context.setFillStyle(item.color);
  1537. var startX = offset.x + arrowWidth + 2 * config.toolTipPadding;
  1538. var startY = offset.y + (config.toolTipLineHeight - config.fontSize) / 2 + config.toolTipLineHeight * index +
  1539. config.toolTipPadding + 1;
  1540. if (isOverRightBorder) {
  1541. startX = offset.x - toolTipWidth - arrowWidth + 2 * config.toolTipPadding;
  1542. }
  1543. context.fillRect(startX, startY, legendWidth, config.fontSize);
  1544. context.closePath();
  1545. }
  1546. });
  1547. // draw text list
  1548. textList.forEach(function(item, index) {
  1549. var startX = offset.x + arrowWidth + 2 * config.toolTipPadding + legendWidth + legendMarginRight;
  1550. if (isOverRightBorder) {
  1551. startX = offset.x - toolTipWidth - arrowWidth + 2 * config.toolTipPadding + +legendWidth + legendMarginRight;
  1552. }
  1553. var startY = offset.y + (config.toolTipLineHeight - config.fontSize) / 2 + config.toolTipLineHeight * index +
  1554. config.toolTipPadding;
  1555. context.beginPath();
  1556. context.setFontSize(config.fontSize);
  1557. context.setFillStyle(toolTipOption.fontColor);
  1558. context.fillText(item.text, startX, startY + config.fontSize);
  1559. context.closePath();
  1560. context.stroke();
  1561. });
  1562. }
  1563. function drawYAxisTitle(title, opts, config, context) {
  1564. var startX = config.xAxisHeight + (opts.height - config.xAxisHeight - measureText(title)) / 2;
  1565. context.save();
  1566. context.beginPath();
  1567. context.setFontSize(config.fontSize);
  1568. context.setFillStyle(opts.yAxis.titleFontColor || '#333333');
  1569. context.translate(0, opts.height);
  1570. context.rotate(-90 * Math.PI / 180);
  1571. context.fillText(title, startX, config.padding + 0.5 * config.fontSize);
  1572. context.closePath();
  1573. context.stroke();
  1574. context.restore();
  1575. }
  1576. function drawColumnDataPoints(series, opts, config, context) {
  1577. var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
  1578. var columnOption = opts.extra.column || {
  1579. type: {},
  1580. meter: {}
  1581. };
  1582. columnOption.type = columnOption.type == undefined ? 'group' : columnOption.type;
  1583. columnOption.meter = columnOption.meter || {}
  1584. columnOption.meter.border = columnOption.meter.border == undefined ? 4 : columnOption.meter.border;
  1585. columnOption.meter.fillColor = columnOption.meter.fillColor == undefined ? '#FFFFFF' : columnOption.meter.fillColor;
  1586. var _calYAxisData = calYAxisData(series, opts, config),
  1587. ranges = _calYAxisData.ranges;
  1588. var _getXAxisPoints = getXAxisPoints(opts.categories, opts, config),
  1589. xAxisPoints = _getXAxisPoints.xAxisPoints,
  1590. eachSpacing = _getXAxisPoints.eachSpacing;
  1591. var minRange = ranges.pop();
  1592. var maxRange = ranges.shift();
  1593. var calPoints = [];
  1594. context.save();
  1595. if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) {
  1596. context.translate(opts._scrollDistance_, 0);
  1597. }
  1598. if (opts.tooltip && opts.tooltip.textList && opts.tooltip.textList.length && process === 1) {
  1599. drawToolTipSplitArea(opts.tooltip.offset.x, opts, config, context, eachSpacing);
  1600. }
  1601. series.forEach(function(eachSeries, seriesIndex) {
  1602. var data = eachSeries.data;
  1603. switch (columnOption.type) {
  1604. case 'group':
  1605. var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
  1606. var tooltipPoints = getStackDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config,
  1607. seriesIndex, series, process);
  1608. calPoints.push(tooltipPoints);
  1609. points = fixColumeData(points, eachSpacing, series.length, seriesIndex, config, opts);
  1610. points.forEach(function(item, index) {
  1611. if (item !== null) {
  1612. context.beginPath();
  1613. context.setFillStyle(item.color || eachSeries.color);
  1614. var startX = item.x - item.width / 2 + 1;
  1615. var height = opts.height - item.y - config.padding - config.xAxisHeight - config.legendHeight;
  1616. context.moveTo(startX, item.y);
  1617. context.fillRect(startX, item.y, item.width - 2, height);
  1618. context.closePath();
  1619. context.fill();
  1620. }
  1621. });
  1622. break;
  1623. case 'stack':
  1624. // 绘制堆叠数据图
  1625. var points = getStackDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, seriesIndex,
  1626. series, process);
  1627. calPoints.push(points);
  1628. points = fixColumeStackData(points, eachSpacing, series.length, seriesIndex, config, opts, series);
  1629. points.forEach(function(item, index) {
  1630. if (item !== null) {
  1631. context.beginPath();
  1632. context.setFillStyle(item.color || eachSeries.color);
  1633. var startX = item.x - item.width / 2 + 1;
  1634. var height = opts.height - item.y - config.padding - config.xAxisHeight - config.legendHeight;
  1635. var height0 = opts.height - item.y0 - config.padding - config.xAxisHeight - config.legendHeight;
  1636. if (seriesIndex > 0) {
  1637. height -= height0;
  1638. }
  1639. context.moveTo(startX, item.y);
  1640. context.fillRect(startX, item.y, item.width - 2, height);
  1641. context.closePath();
  1642. context.fill();
  1643. }
  1644. });
  1645. break;
  1646. case 'meter':
  1647. // 绘制温度计数据图
  1648. var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
  1649. calPoints.push(points);
  1650. points = fixColumeMeterData(points, eachSpacing, series.length, seriesIndex, config, opts, columnOption.meter.border);
  1651. if (seriesIndex == 0) {
  1652. points.forEach(function(item, index) {
  1653. if (item !== null) {
  1654. //画背景颜色
  1655. context.beginPath();
  1656. context.setFillStyle(columnOption.meter.fillColor);
  1657. var startX = item.x - item.width / 2 ;
  1658. var height = opts.height - item.y - config.padding - config.xAxisHeight - config.legendHeight;
  1659. context.moveTo(startX, item.y);
  1660. context.fillRect(startX, item.y, item.width, height);
  1661. context.closePath();
  1662. context.fill();
  1663. //画边框线
  1664. if(columnOption.meter.border>0){
  1665. context.beginPath();
  1666. context.setStrokeStyle(eachSeries.color);
  1667. context.setLineWidth(columnOption.meter.border * opts.pixelRatio);
  1668. context.moveTo(startX + columnOption.meter.border*0.5, item.y + height);
  1669. context.lineTo(startX + columnOption.meter.border*0.5, item.y + columnOption.meter.border*0.5);
  1670. context.lineTo(startX + item.width - columnOption.meter.border*0.5, item.y + columnOption.meter.border*0.5);
  1671. context.lineTo(startX + item.width - columnOption.meter.border*0.5, item.y + height);
  1672. context.stroke();
  1673. }
  1674. }
  1675. });
  1676. } else {
  1677. points.forEach(function(item, index) {
  1678. if (item !== null) {
  1679. context.beginPath();
  1680. context.setFillStyle(item.color || eachSeries.color);
  1681. var startX = item.x - item.width / 2;
  1682. var height = opts.height - item.y - config.padding - config.xAxisHeight - config.legendHeight;
  1683. context.moveTo(startX, item.y);
  1684. context.fillRect(startX, item.y, item.width, height);
  1685. context.closePath();
  1686. context.fill();
  1687. }
  1688. });
  1689. }
  1690. break;
  1691. }
  1692. });
  1693. if (opts.dataLabel !== false && process === 1) {
  1694. series.forEach(function(eachSeries, seriesIndex) {
  1695. var data = eachSeries.data;
  1696. switch (columnOption.type) {
  1697. case 'group':
  1698. var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
  1699. points = fixColumeData(points, eachSpacing, series.length, seriesIndex, config, opts);
  1700. drawPointText(points, eachSeries, config, context);
  1701. break;
  1702. case 'stack':
  1703. var points = getStackDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, seriesIndex,
  1704. series, process);
  1705. drawPointText(points, eachSeries, config, context);
  1706. break;
  1707. case 'meter':
  1708. var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
  1709. drawPointText(points, eachSeries, config, context);
  1710. break;
  1711. }
  1712. });
  1713. }
  1714. context.restore();
  1715. return {
  1716. xAxisPoints: xAxisPoints,
  1717. calPoints: calPoints,
  1718. eachSpacing: eachSpacing
  1719. };
  1720. }
  1721. function drawCandleDataPoints(series, seriesMA, opts, config, context) {
  1722. var process = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 1;
  1723. var candleOption = opts.extra.candle || {
  1724. color: {},
  1725. average: {}
  1726. };
  1727. candleOption.color.upLine = candleOption.color.upLine ? candleOption.color.upLine : '#f04864';
  1728. candleOption.color.upFill = candleOption.color.upFill ? candleOption.color.upFill : '#f04864';
  1729. candleOption.color.downLine = candleOption.color.downLine ? candleOption.color.downLine : '#2fc25b';
  1730. candleOption.color.downFill = candleOption.color.downFill ? candleOption.color.downFill : '#2fc25b';
  1731. candleOption.average.show = candleOption.average.show === true ? true : false;
  1732. candleOption.average.name = candleOption.average.name ? candleOption.average.name : [];
  1733. candleOption.average.day = candleOption.average.day ? candleOption.average.day : [];
  1734. candleOption.average.color = candleOption.average.color ? candleOption.average.color : ['#1890ff', '#2fc25b',
  1735. '#facc14', '#f04864', '#8543e0', '#90ed7d'
  1736. ];
  1737. opts.extra.candle = candleOption;
  1738. var _calYAxisData5 = calYAxisData(series, opts, config),
  1739. ranges = _calYAxisData5.ranges;
  1740. var _getXAxisPoints5 = getXAxisPoints(opts.categories, opts, config),
  1741. xAxisPoints = _getXAxisPoints5.xAxisPoints,
  1742. eachSpacing = _getXAxisPoints5.eachSpacing;
  1743. var minRange = ranges.pop();
  1744. var maxRange = ranges.shift();
  1745. var calPoints = [];
  1746. context.save();
  1747. if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) {
  1748. context.translate(opts._scrollDistance_, 0);
  1749. }
  1750. //画均线
  1751. if (candleOption.average.show) {
  1752. seriesMA.forEach(function(eachSeries, seriesIndex) {
  1753. var data = eachSeries.data;
  1754. var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
  1755. //calPoints.push(points);
  1756. var splitPointList = splitPoints(points);
  1757. splitPointList.forEach(function(points, index) {
  1758. context.beginPath();
  1759. context.setStrokeStyle(eachSeries.color);
  1760. context.setLineWidth(1);
  1761. if (points.length === 1) {
  1762. context.moveTo(points[0].x, points[0].y);
  1763. context.arc(points[0].x, points[0].y, 1, 0, 2 * Math.PI);
  1764. } else {
  1765. context.moveTo(points[0].x, points[0].y);
  1766. points.forEach(function(item, index) {
  1767. if (index > 0) {
  1768. var ctrlPoint = createCurveControlPoints(points, index - 1);
  1769. context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y, item.x, item
  1770. .y);
  1771. }
  1772. });
  1773. context.moveTo(points[0].x, points[0].y);
  1774. }
  1775. context.closePath();
  1776. context.stroke();
  1777. });
  1778. });
  1779. }
  1780. //画K线
  1781. series.forEach(function(eachSeries, seriesIndex) {
  1782. var data = eachSeries.data;
  1783. var points = getCandleDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
  1784. calPoints.push(points);
  1785. var splitPointList = splitPoints(points);
  1786. splitPointList = splitPointList[0];
  1787. splitPointList.forEach(function(points, index) {
  1788. context.beginPath();
  1789. //如果上涨
  1790. if (data[index][1] - data[index][0] > 0) {
  1791. context.setStrokeStyle(candleOption.color.upLine);
  1792. context.setFillStyle(candleOption.color.upFill);
  1793. context.setLineWidth(1 * opts.pixelRatio);
  1794. context.moveTo(points[3].x, points[3].y); //顶点
  1795. context.lineTo(points[1].x, points[1].y); //收盘中间点
  1796. context.lineTo(points[1].x - eachSpacing / 4, points[1].y); //收盘左侧点
  1797. context.lineTo(points[0].x - eachSpacing / 4, points[0].y); //开盘左侧点
  1798. context.lineTo(points[0].x, points[0].y); //开盘中间点
  1799. context.lineTo(points[2].x, points[2].y); //底点
  1800. context.lineTo(points[0].x, points[0].y); //开盘中间点
  1801. context.lineTo(points[0].x + eachSpacing / 4, points[0].y); //开盘右侧点
  1802. context.lineTo(points[1].x + eachSpacing / 4, points[1].y); //收盘右侧点
  1803. context.lineTo(points[1].x, points[1].y); //收盘中间点
  1804. context.moveTo(points[3].x, points[3].y); //顶点
  1805. } else {
  1806. context.setStrokeStyle(candleOption.color.downLine);
  1807. context.setFillStyle(candleOption.color.downFill);
  1808. context.setLineWidth(1 * opts.pixelRatio);
  1809. context.moveTo(points[3].x, points[3].y); //顶点
  1810. context.lineTo(points[0].x, points[0].y); //开盘中间点
  1811. context.lineTo(points[0].x - eachSpacing / 4, points[0].y); //开盘左侧点
  1812. context.lineTo(points[1].x - eachSpacing / 4, points[1].y); //收盘左侧点
  1813. context.lineTo(points[1].x, points[1].y); //收盘中间点
  1814. context.lineTo(points[2].x, points[2].y); //底点
  1815. context.lineTo(points[1].x, points[1].y); //收盘中间点
  1816. context.lineTo(points[1].x + eachSpacing / 4, points[1].y); //收盘右侧点
  1817. context.lineTo(points[0].x + eachSpacing / 4, points[0].y); //开盘右侧点
  1818. context.lineTo(points[0].x, points[0].y); //开盘中间点
  1819. context.moveTo(points[3].x, points[3].y); //顶点
  1820. }
  1821. context.closePath();
  1822. context.fill();
  1823. context.stroke();
  1824. });
  1825. });
  1826. context.restore();
  1827. return {
  1828. xAxisPoints: xAxisPoints,
  1829. calPoints: calPoints,
  1830. eachSpacing: eachSpacing
  1831. };
  1832. }
  1833. function drawAreaDataPoints(series, opts, config, context) {
  1834. var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
  1835. var areaOption = opts.extra.area || {
  1836. type: 'straight',
  1837. opacity: 0.5,
  1838. addLine: false,
  1839. width: 2
  1840. };
  1841. areaOption.type = areaOption.type ? areaOption.type : 'straight';
  1842. areaOption.opacity = areaOption.opacity ? areaOption.opacity : 0.2;
  1843. areaOption.addLine = areaOption.addLine == true ? true : false;
  1844. areaOption.width = areaOption.width ? areaOption.width : 2;
  1845. var _calYAxisData2 = calYAxisData(series, opts, config),
  1846. ranges = _calYAxisData2.ranges;
  1847. var _getXAxisPoints2 = getXAxisPoints(opts.categories, opts, config),
  1848. xAxisPoints = _getXAxisPoints2.xAxisPoints,
  1849. eachSpacing = _getXAxisPoints2.eachSpacing;
  1850. var minRange = ranges.pop();
  1851. var maxRange = ranges.shift();
  1852. var endY = opts.height - config.padding - config.xAxisHeight - config.legendHeight;
  1853. var calPoints = [];
  1854. context.save();
  1855. if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) {
  1856. context.translate(opts._scrollDistance_, 0);
  1857. }
  1858. if (opts.tooltip && opts.tooltip.textList && opts.tooltip.textList.length && process === 1) {
  1859. drawToolTipSplitLine(opts.tooltip.offset.x, opts, config, context);
  1860. }
  1861. series.forEach(function(eachSeries, seriesIndex) {
  1862. let data = eachSeries.data;
  1863. let points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
  1864. calPoints.push(points);
  1865. let splitPointList = splitPoints(points);
  1866. for (let i = 0; i < splitPointList.length; i++) {
  1867. let points = splitPointList[i];
  1868. // 绘制区域数
  1869. context.beginPath();
  1870. context.setStrokeStyle(hexToRgb(eachSeries.color, areaOption.opacity));
  1871. context.setFillStyle(hexToRgb(eachSeries.color, areaOption.opacity));
  1872. context.setLineWidth(areaOption.width * opts.pixelRatio);
  1873. if (points.length > 1) {
  1874. let firstPoint = points[0];
  1875. let lastPoint = points[points.length - 1];
  1876. context.moveTo(firstPoint.x, firstPoint.y);
  1877. if (areaOption.type === 'curve') {
  1878. points.forEach(function(item, index) {
  1879. if (index > 0) {
  1880. let ctrlPoint = createCurveControlPoints(points, index - 1);
  1881. context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y, item.x, item
  1882. .y);
  1883. }
  1884. });
  1885. } else {
  1886. points.forEach(function(item, index) {
  1887. if (index > 0) {
  1888. context.lineTo(item.x, item.y);
  1889. }
  1890. });
  1891. }
  1892. context.lineTo(lastPoint.x, endY);
  1893. context.lineTo(firstPoint.x, endY);
  1894. context.lineTo(firstPoint.x, firstPoint.y);
  1895. } else {
  1896. let item = points[0];
  1897. context.moveTo(item.x - eachSpacing / 2, item.y);
  1898. context.lineTo(item.x + eachSpacing / 2, item.y);
  1899. context.lineTo(item.x + eachSpacing / 2, endY);
  1900. context.lineTo(item.x - eachSpacing / 2, endY);
  1901. context.moveTo(item.x - eachSpacing / 2, item.y);
  1902. }
  1903. context.closePath();
  1904. context.fill();
  1905. //画连线
  1906. if (areaOption.addLine) {
  1907. context.beginPath();
  1908. context.setStrokeStyle(eachSeries.color);
  1909. context.setLineWidth(areaOption.width * opts.pixelRatio);
  1910. if (points.length === 1) {
  1911. context.moveTo(points[0].x, points[0].y);
  1912. context.arc(points[0].x, points[0].y, 1, 0, 2 * Math.PI);
  1913. } else {
  1914. context.moveTo(points[0].x, points[0].y);
  1915. if (areaOption.type === 'curve') {
  1916. points.forEach(function(item, index) {
  1917. if (index > 0) {
  1918. let ctrlPoint = createCurveControlPoints(points, index - 1);
  1919. context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y, item.x,
  1920. item.y);
  1921. }
  1922. });
  1923. } else {
  1924. points.forEach(function(item, index) {
  1925. if (index > 0) {
  1926. context.lineTo(item.x, item.y);
  1927. }
  1928. });
  1929. }
  1930. context.moveTo(points[0].x, points[0].y);
  1931. }
  1932. context.closePath();
  1933. context.stroke();
  1934. }
  1935. }
  1936. //画点
  1937. if (opts.dataPointShape !== false) {
  1938. var shape = config.dataPointShape[seriesIndex % config.dataPointShape.length];
  1939. drawPointShape(points, eachSeries.color, shape, context, opts);
  1940. }
  1941. });
  1942. if (opts.dataLabel !== false && process === 1) {
  1943. series.forEach(function(eachSeries, seriesIndex) {
  1944. var data = eachSeries.data;
  1945. var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
  1946. drawPointText(points, eachSeries, config, context);
  1947. });
  1948. }
  1949. context.restore();
  1950. return {
  1951. xAxisPoints: xAxisPoints,
  1952. calPoints: calPoints,
  1953. eachSpacing: eachSpacing
  1954. };
  1955. }
  1956. function drawLineDataPoints(series, opts, config, context) {
  1957. var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
  1958. var lineOption = opts.extra.line || {
  1959. type: 'straight',
  1960. width: 2
  1961. };
  1962. lineOption.type = lineOption.type ? lineOption.type : 'straight';
  1963. lineOption.width = lineOption.width ? lineOption.width : 2;
  1964. var _calYAxisData3 = calYAxisData(series, opts, config),
  1965. ranges = _calYAxisData3.ranges;
  1966. var _getXAxisPoints3 = getXAxisPoints(opts.categories, opts, config),
  1967. xAxisPoints = _getXAxisPoints3.xAxisPoints,
  1968. eachSpacing = _getXAxisPoints3.eachSpacing;
  1969. var minRange = ranges.pop();
  1970. var maxRange = ranges.shift();
  1971. var calPoints = [];
  1972. context.save();
  1973. if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) {
  1974. context.translate(opts._scrollDistance_, 0);
  1975. }
  1976. if (opts.tooltip && opts.tooltip.textList && opts.tooltip.textList.length && process === 1) {
  1977. drawToolTipSplitLine(opts.tooltip.offset.x, opts, config, context);
  1978. }
  1979. series.forEach(function(eachSeries, seriesIndex) {
  1980. var data = eachSeries.data;
  1981. var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
  1982. calPoints.push(points);
  1983. var splitPointList = splitPoints(points);
  1984. splitPointList.forEach(function(points, index) {
  1985. context.beginPath();
  1986. context.setStrokeStyle(eachSeries.color);
  1987. context.setLineWidth(lineOption.width * opts.pixelRatio);
  1988. if (points.length === 1) {
  1989. context.moveTo(points[0].x, points[0].y);
  1990. context.arc(points[0].x, points[0].y, 1, 0, 2 * Math.PI);
  1991. } else {
  1992. context.moveTo(points[0].x, points[0].y);
  1993. if (lineOption.type === 'curve') {
  1994. points.forEach(function(item, index) {
  1995. if (index > 0) {
  1996. var ctrlPoint = createCurveControlPoints(points, index - 1);
  1997. context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y, item.x, item
  1998. .y);
  1999. }
  2000. });
  2001. } else {
  2002. points.forEach(function(item, index) {
  2003. if (index > 0) {
  2004. context.lineTo(item.x, item.y);
  2005. }
  2006. });
  2007. }
  2008. context.moveTo(points[0].x, points[0].y);
  2009. }
  2010. context.closePath();
  2011. context.stroke();
  2012. });
  2013. if (opts.dataPointShape !== false) {
  2014. var shape = config.dataPointShape[seriesIndex % config.dataPointShape.length];
  2015. drawPointShape(points, eachSeries.color, shape, context, opts);
  2016. }
  2017. });
  2018. if (opts.dataLabel !== false && process === 1) {
  2019. series.forEach(function(eachSeries, seriesIndex) {
  2020. var data = eachSeries.data;
  2021. var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
  2022. drawPointText(points, eachSeries, config, context);
  2023. });
  2024. }
  2025. context.restore();
  2026. return {
  2027. xAxisPoints: xAxisPoints,
  2028. calPoints: calPoints,
  2029. eachSpacing: eachSpacing
  2030. };
  2031. }
  2032. function drawMixDataPoints(series, opts, config, context) {
  2033. var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
  2034. var _calYAxisData6 = calYAxisData(series, opts, config),
  2035. ranges = _calYAxisData6.ranges;
  2036. var _getXAxisPoints6 = getXAxisPoints(opts.categories, opts, config),
  2037. xAxisPoints = _getXAxisPoints6.xAxisPoints,
  2038. eachSpacing = _getXAxisPoints6.eachSpacing;
  2039. var minRange = ranges.pop();
  2040. var maxRange = ranges.shift();
  2041. var endY = opts.height - config.padding - config.xAxisHeight - config.legendHeight;
  2042. var calPoints = [];
  2043. var columnIndex = 0;
  2044. var columnLength = 0;
  2045. series.forEach(function(eachSeries, seriesIndex) {
  2046. if (eachSeries.type == 'column') {
  2047. columnLength += 1;
  2048. }
  2049. });
  2050. context.save();
  2051. if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) {
  2052. context.translate(opts._scrollDistance_, 0);
  2053. }
  2054. if (opts.tooltip && opts.tooltip.textList && opts.tooltip.textList.length && process === 1) {
  2055. drawToolTipSplitLine(opts.tooltip.offset.x, opts, config, context);
  2056. }
  2057. series.forEach(function(eachSeries, seriesIndex) {
  2058. var data = eachSeries.data;
  2059. var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
  2060. calPoints.push(points);
  2061. // 绘制柱状数据图
  2062. if (eachSeries.type == 'column') {
  2063. points = fixColumeData(points, eachSpacing, columnLength, columnIndex, config, opts);
  2064. points.forEach(function(item, index) {
  2065. if (item !== null) {
  2066. context.beginPath();
  2067. context.setFillStyle(item.color || eachSeries.color);
  2068. var startX = item.x - item.width / 2 + 1;
  2069. var height = opts.height - item.y - config.padding - config.xAxisHeight - config.legendHeight;
  2070. context.moveTo(startX, item.y);
  2071. context.rect(startX, item.y, item.width - 2, height);
  2072. context.closePath();
  2073. context.fill();
  2074. }
  2075. });
  2076. columnIndex += 1;
  2077. }
  2078. //绘制区域图数据
  2079. if (eachSeries.type == 'area') {
  2080. let splitPointList = splitPoints(points);
  2081. for (let i = 0; i < splitPointList.length; i++) {
  2082. let points = splitPointList[i];
  2083. // 绘制区域数据
  2084. context.beginPath();
  2085. context.setStrokeStyle(eachSeries.color);
  2086. context.setFillStyle(eachSeries.color);
  2087. context.setGlobalAlpha(0.2);
  2088. context.setLineWidth(2 * opts.pixelRatio);
  2089. if (points.length > 1) {
  2090. var firstPoint = points[0];
  2091. let lastPoint = points[points.length - 1];
  2092. context.moveTo(firstPoint.x, firstPoint.y);
  2093. if (eachSeries.style === 'curve') {
  2094. points.forEach(function(item, index) {
  2095. if (index > 0) {
  2096. var ctrlPoint = createCurveControlPoints(points, index - 1);
  2097. context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y, item.x,
  2098. item.y);
  2099. }
  2100. });
  2101. } else {
  2102. points.forEach(function(item, index) {
  2103. if (index > 0) {
  2104. context.lineTo(item.x, item.y);
  2105. }
  2106. });
  2107. }
  2108. context.lineTo(lastPoint.x, endY);
  2109. context.lineTo(firstPoint.x, endY);
  2110. context.lineTo(firstPoint.x, firstPoint.y);
  2111. } else {
  2112. let item = points[0];
  2113. context.moveTo(item.x - eachSpacing / 2, item.y);
  2114. context.lineTo(item.x + eachSpacing / 2, item.y);
  2115. context.lineTo(item.x + eachSpacing / 2, endY);
  2116. context.lineTo(item.x - eachSpacing / 2, endY);
  2117. context.moveTo(item.x - eachSpacing / 2, item.y);
  2118. }
  2119. context.closePath();
  2120. context.fill();
  2121. context.setGlobalAlpha(1);
  2122. }
  2123. }
  2124. // 绘制折线数据图
  2125. if (eachSeries.type == 'line') {
  2126. var splitPointList = splitPoints(points);
  2127. splitPointList.forEach(function(points, index) {
  2128. context.beginPath();
  2129. context.setStrokeStyle(eachSeries.color);
  2130. context.setLineWidth(2 * opts.pixelRatio);
  2131. if (points.length === 1) {
  2132. context.moveTo(points[0].x, points[0].y);
  2133. context.arc(points[0].x, points[0].y, 1, 0, 2 * Math.PI);
  2134. } else {
  2135. context.moveTo(points[0].x, points[0].y);
  2136. if (eachSeries.style == 'curve') {
  2137. points.forEach(function(item, index) {
  2138. if (index > 0) {
  2139. var ctrlPoint = createCurveControlPoints(points, index - 1);
  2140. context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y, item.x,
  2141. item.y);
  2142. }
  2143. });
  2144. } else {
  2145. points.forEach(function(item, index) {
  2146. if (index > 0) {
  2147. context.lineTo(item.x, item.y);
  2148. }
  2149. });
  2150. }
  2151. context.moveTo(points[0].x, points[0].y);
  2152. }
  2153. context.closePath();
  2154. context.stroke();
  2155. });
  2156. }
  2157. // 绘制点数据图
  2158. if (eachSeries.type == 'point') {
  2159. points.forEach(function(pointsa, index) {
  2160. if(pointsa){
  2161. context.beginPath();
  2162. context.setFillStyle(eachSeries.color);
  2163. context.setStrokeStyle('#FFFFFF');
  2164. context.setLineWidth(1 * opts.pixelRatio);
  2165. context.moveTo(pointsa.x + 3.5 * opts.pixelRatio, pointsa.y);
  2166. context.arc(pointsa.x, pointsa.y, 4* opts.pixelRatio, 0, 2 * Math.PI);
  2167. context.closePath();
  2168. context.fill();
  2169. context.stroke();
  2170. }
  2171. });
  2172. }
  2173. if (eachSeries.addPoint == true && eachSeries.type !== 'column') {
  2174. var shape = config.dataPointShape[seriesIndex % config.dataPointShape.length];
  2175. drawPointShape(points, eachSeries.color, shape, context, opts);
  2176. }
  2177. });
  2178. if (opts.dataLabel !== false && process === 1) {
  2179. var columnIndex = 0;
  2180. series.forEach(function(eachSeries, seriesIndex) {
  2181. var data = eachSeries.data;
  2182. var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
  2183. if (eachSeries.type !== 'column') {
  2184. drawPointText(points, eachSeries, config, context);
  2185. } else {
  2186. points = fixColumeData(points, eachSpacing, columnLength, columnIndex, config, opts);
  2187. drawPointText(points, eachSeries, config, context);
  2188. columnIndex += 1;
  2189. }
  2190. });
  2191. }
  2192. context.restore();
  2193. return {
  2194. xAxisPoints: xAxisPoints,
  2195. calPoints: calPoints,
  2196. eachSpacing: eachSpacing
  2197. };
  2198. }
  2199. function drawToolTipBridge(opts, config, context, process, eachSpacing, xAxisPoints) {
  2200. var toolTipOption = opts.extra.tooltip || {};
  2201. if (toolTipOption.horizentalLine && opts.tooltip && process === 1 && (opts.type == 'line' || opts.type == 'area' ||
  2202. opts.type == 'column' || opts.type == 'candle' || opts.type == 'mix')) {
  2203. drawToolTipHorizentalLine(opts, config, context, eachSpacing, xAxisPoints)
  2204. }
  2205. context.save();
  2206. if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) {
  2207. context.translate(opts._scrollDistance_, 0);
  2208. }
  2209. if (opts.tooltip && opts.tooltip.textList && opts.tooltip.textList.length && process === 1) {
  2210. drawToolTip(opts.tooltip.textList, opts.tooltip.offset, opts, config, context, eachSpacing, xAxisPoints);
  2211. }
  2212. context.restore();
  2213. }
  2214. function drawXAxis(categories, opts, config, context) {
  2215. var _getXAxisPoints4 = getXAxisPoints(categories, opts, config),
  2216. xAxisPoints = _getXAxisPoints4.xAxisPoints,
  2217. startX = _getXAxisPoints4.startX,
  2218. endX = _getXAxisPoints4.endX,
  2219. eachSpacing = _getXAxisPoints4.eachSpacing;
  2220. var startY = opts.height - config.padding - config.xAxisHeight - config.legendHeight;
  2221. var endY = config.padding;
  2222. //绘制滚动条
  2223. if (opts.enableScroll && opts.xAxis.scrollShow) {
  2224. var scrollY = opts.height - config.padding - config.legendHeight + 6 * opts.pixelRatio;
  2225. var scrollScreenWidth = endX - startX;
  2226. var scrollTotalWidth = eachSpacing * (xAxisPoints.length - 1);
  2227. var scrollWidth = scrollScreenWidth * scrollScreenWidth / scrollTotalWidth;
  2228. var scrollLeft = 0;
  2229. if (opts._scrollDistance_) {
  2230. scrollLeft = -opts._scrollDistance_ * (scrollScreenWidth) / scrollTotalWidth;
  2231. }
  2232. context.beginPath();
  2233. context.setLineCap('round');
  2234. context.setLineWidth(6 * opts.pixelRatio);
  2235. context.setStrokeStyle(opts.xAxis.scrollBackgroundColor || "#EFEBEF");
  2236. context.moveTo(startX, scrollY);
  2237. context.lineTo(endX, scrollY);
  2238. context.stroke();
  2239. context.closePath();
  2240. context.beginPath();
  2241. context.setLineCap('round');
  2242. context.setLineWidth(6 * opts.pixelRatio);
  2243. context.setStrokeStyle(opts.xAxis.scrollColor || "#A6A6A6");
  2244. context.moveTo(startX + scrollLeft, scrollY);
  2245. context.lineTo(startX + scrollLeft + scrollWidth, scrollY);
  2246. context.stroke();
  2247. context.setLineCap('butt');
  2248. context.closePath();
  2249. }
  2250. context.save();
  2251. if (opts._scrollDistance_ && opts._scrollDistance_ !== 0) {
  2252. context.translate(opts._scrollDistance_, 0);
  2253. }
  2254. context.beginPath();
  2255. context.setStrokeStyle(opts.xAxis.gridColor || "#cccccc");
  2256. context.setLineCap('butt');
  2257. context.setLineWidth(1 * opts.pixelRatio);
  2258. if (opts.xAxis.gridType == 'dash') {
  2259. context.setLineDash([opts.xAxis.dashLength, opts.xAxis.dashLength]);
  2260. }
  2261. if (opts.xAxis.disableGrid !== true) {
  2262. if (opts.xAxis.type === 'calibration') {
  2263. xAxisPoints.forEach(function(item, index) {
  2264. if (index > 0) {
  2265. context.moveTo(item - eachSpacing / 2, startY);
  2266. context.lineTo(item - eachSpacing / 2, startY + 4 * opts.pixelRatio);
  2267. }
  2268. });
  2269. } else {
  2270. opts.xAxis.gridEval = opts.xAxis.gridEval || 1;
  2271. xAxisPoints.forEach(function(item, index) {
  2272. if(index % opts.xAxis.gridEval == 0){
  2273. context.moveTo(item, startY);
  2274. context.lineTo(item, endY);
  2275. }
  2276. });
  2277. }
  2278. }
  2279. context.closePath();
  2280. context.stroke();
  2281. context.setLineDash([]);
  2282. //不绘制X轴
  2283. if (opts.xAxis.disabled !== true) {
  2284. // 对X轴列表做抽稀处理
  2285. let validWidth = opts.width - 2 * config.padding - config.yAxisWidth - config.yAxisTitleWidth;
  2286. //默认全部显示X轴标签
  2287. let maxXAxisListLength = categories.length;
  2288. //如果设置了X轴单屏数量
  2289. if (opts.xAxis.labelCount) {
  2290. //如果设置X轴密度
  2291. if (opts.xAxis.itemCount) {
  2292. maxXAxisListLength = Math.ceil(categories.length / opts.xAxis.itemCount * opts.xAxis.labelCount);
  2293. } else {
  2294. maxXAxisListLength = opts.xAxis.labelCount;
  2295. }
  2296. maxXAxisListLength -= 1;
  2297. }
  2298. let ratio = Math.ceil(categories.length / maxXAxisListLength);
  2299. let newCategories = [];
  2300. let cgLength = categories.length;
  2301. for (let i = 0; i < cgLength; i++) {
  2302. if (i % ratio !== 0) {
  2303. newCategories.push("");
  2304. } else {
  2305. newCategories.push(categories[i]);
  2306. }
  2307. }
  2308. newCategories[cgLength - 1] = categories[cgLength - 1];
  2309. /*
  2310. categories = categories.map(function (item, index) {
  2311. return index % ratio !== 0 ? '' : item;
  2312. });*/
  2313. var xAxisFontSize = opts.xAxis.fontSize || config.fontSize;
  2314. if (config._xAxisTextAngle_ === 0) {
  2315. newCategories.forEach(function(item, index) {
  2316. var offset = eachSpacing / 2 - measureText(item,xAxisFontSize) / 2;
  2317. context.beginPath();
  2318. context.setFontSize(xAxisFontSize);
  2319. context.setFillStyle(opts.xAxis.fontColor || '#666666');
  2320. context.fillText(item, xAxisPoints[index] + offset, startY + xAxisFontSize + 5);
  2321. context.closePath();
  2322. context.stroke();
  2323. });
  2324. } else {
  2325. newCategories.forEach(function(item, index) {
  2326. context.save();
  2327. context.beginPath();
  2328. context.setFontSize(xAxisFontSize);
  2329. context.setFillStyle(opts.xAxis.fontColor || '#666666');
  2330. var textWidth = measureText(item);
  2331. var offset = eachSpacing / 2 - textWidth;
  2332. var _calRotateTranslate = calRotateTranslate(xAxisPoints[index] + eachSpacing / 2, startY + xAxisFontSize / 2 + 5, opts.height),
  2333. transX = _calRotateTranslate.transX,
  2334. transY = _calRotateTranslate.transY;
  2335. context.rotate(-1 * config._xAxisTextAngle_);
  2336. context.translate(transX, transY);
  2337. context.fillText(item, xAxisPoints[index] + offset, startY + xAxisFontSize + 5);
  2338. context.closePath();
  2339. context.stroke();
  2340. context.restore();
  2341. });
  2342. }
  2343. }
  2344. context.restore();
  2345. }
  2346. function drawYAxisGrid(categories, opts, config, context) {
  2347. if (opts.yAxis.disableGrid === true) {
  2348. return;
  2349. }
  2350. var spacingValid = opts.height - 2 * config.padding - config.xAxisHeight - config.legendHeight;
  2351. var eachSpacing = Math.floor(spacingValid / config.yAxisSplit);
  2352. var yAxisTotalWidth = config.yAxisWidth + config.yAxisTitleWidth;
  2353. var startX = config.padding + yAxisTotalWidth;
  2354. var _getXAxisPoints4 = getXAxisPoints(categories, opts, config),
  2355. xAxisPoints = _getXAxisPoints4.xAxisPoints,
  2356. xAxiseachSpacing = _getXAxisPoints4.eachSpacing;
  2357. var TotalWidth = xAxiseachSpacing * (xAxisPoints.length - 1);
  2358. var endX = startX + TotalWidth;
  2359. var points = [];
  2360. for (var i = 0; i < config.yAxisSplit; i++) {
  2361. points.push(config.padding + eachSpacing * i);
  2362. }
  2363. points.push(config.padding + eachSpacing * config.yAxisSplit + 2);
  2364. context.save();
  2365. if (opts._scrollDistance_ && opts._scrollDistance_ !== 0) {
  2366. context.translate(opts._scrollDistance_, 0);
  2367. }
  2368. if (opts.yAxis.gridType == 'dash') {
  2369. context.setLineDash([opts.yAxis.dashLength, opts.yAxis.dashLength]);
  2370. }
  2371. context.beginPath();
  2372. context.setStrokeStyle(opts.yAxis.gridColor || "#cccccc");
  2373. context.setLineWidth(1 * opts.pixelRatio);
  2374. points.forEach(function(item, index) {
  2375. context.moveTo(startX, item);
  2376. context.lineTo(endX, item);
  2377. });
  2378. context.closePath();
  2379. context.stroke();
  2380. context.setLineDash([]);
  2381. context.restore();
  2382. }
  2383. function drawYAxis(series, opts, config, context) {
  2384. if (opts.yAxis.disabled === true) {
  2385. return;
  2386. }
  2387. var _calYAxisData4 = calYAxisData(series, opts, config),
  2388. rangesFormat = _calYAxisData4.rangesFormat;
  2389. var yAxisTotalWidth = config.yAxisWidth + config.yAxisTitleWidth;
  2390. var spacingValid = opts.height - 2 * config.padding - config.xAxisHeight - config.legendHeight;
  2391. var eachSpacing = Math.floor(spacingValid / config.yAxisSplit);
  2392. var startX = config.padding + yAxisTotalWidth;
  2393. var endX = opts.width - config.padding;
  2394. var endY = opts.height - config.padding - config.xAxisHeight - config.legendHeight + config.xAxisTextPadding;
  2395. // set YAxis background
  2396. context.beginPath();
  2397. context.setFillStyle(opts.background || '#ffffff');
  2398. if (opts._scrollDistance_ < 0) {
  2399. context.fillRect(0, 0, startX, endY + config.xAxisHeight);
  2400. }
  2401. context.fillRect(endX, 0, opts.width, endY + config.xAxisHeight);
  2402. context.closePath();
  2403. context.stroke();
  2404. var points = [];
  2405. for (var i = 0; i <= config.yAxisSplit; i++) {
  2406. points.push(config.padding + eachSpacing * i);
  2407. }
  2408. var yAxisFontSize = opts.yAxis.fontSize || config.fontSize;
  2409. rangesFormat.forEach(function(item, index) {
  2410. var pos = points[index] ? points[index] : endY;
  2411. context.beginPath();
  2412. context.setFontSize(yAxisFontSize);
  2413. context.setFillStyle(opts.yAxis.fontColor || '#666666');
  2414. context.fillText(item, config.padding + config.yAxisTitleWidth, pos + yAxisFontSize / 2);
  2415. context.closePath();
  2416. context.stroke();
  2417. });
  2418. if (opts.yAxis.title) {
  2419. drawYAxisTitle(opts.yAxis.title, opts, config, context);
  2420. }
  2421. }
  2422. function drawLegend(series, opts, config, context) {
  2423. if (opts.legend === false) {
  2424. return;
  2425. }
  2426. // each legend shape width 15px
  2427. // the spacing between shape and text in each legend is the `padding`
  2428. // each legend spacing is the `padding`
  2429. // legend margin top `config.padding`
  2430. var _calLegendData = calLegendData(series, opts, config),
  2431. legendList = _calLegendData.legendList;
  2432. var padding = 5 * opts.pixelRatio;
  2433. var marginTop = 10 * opts.pixelRatio;
  2434. var shapeWidth = 15 * opts.pixelRatio;
  2435. legendList.forEach(function(itemList, listIndex) {
  2436. var width = 0;
  2437. for (let i = 0; i < itemList.length; i++) {
  2438. let item = itemList[i];
  2439. item.name = item.name || 'undefined';
  2440. width += 3 * padding + measureText(item.name) + shapeWidth;
  2441. }
  2442. var startX = (opts.width - width) / 2 + padding;
  2443. var startY = opts.height - config.padding - config.legendHeight + listIndex * (config.fontSize + marginTop) +
  2444. padding + marginTop;
  2445. context.setFontSize(config.fontSize);
  2446. for (let i = 0; i < itemList.length; i++) {
  2447. let item = itemList[i];
  2448. switch (opts.type) {
  2449. case 'line':
  2450. context.beginPath();
  2451. context.setLineWidth(1 * opts.pixelRatio);
  2452. context.setStrokeStyle(item.color);
  2453. context.setFillStyle(item.color);
  2454. context.moveTo(startX + 7.5 * opts.pixelRatio, startY + 5 * opts.pixelRatio);
  2455. context.arc(startX + 7.5 * opts.pixelRatio, startY + 5 * opts.pixelRatio, 6 * opts.pixelRatio, 0, 2 * Math.PI);
  2456. context.closePath();
  2457. context.fill();
  2458. context.stroke();
  2459. break;
  2460. case 'pie':
  2461. context.beginPath();
  2462. context.setLineWidth(1 * opts.pixelRatio);
  2463. context.setStrokeStyle(item.color);
  2464. context.setFillStyle(item.color);
  2465. context.moveTo(startX + 7.5 * opts.pixelRatio, startY + 5 * opts.pixelRatio);
  2466. context.arc(startX + 7.5 * opts.pixelRatio, startY + 5 * opts.pixelRatio, 6 * opts.pixelRatio, 0, 2 * Math.PI);
  2467. context.closePath();
  2468. context.fill();
  2469. context.stroke();
  2470. break;
  2471. case 'ring':
  2472. case 'rose':
  2473. context.beginPath();
  2474. context.setLineWidth(1 * opts.pixelRatio);
  2475. context.setStrokeStyle(item.color);
  2476. context.setFillStyle(item.color);
  2477. context.moveTo(startX + 7.5 * opts.pixelRatio, startY + 5 * opts.pixelRatio);
  2478. context.arc(startX + 7.5 * opts.pixelRatio, startY + 5 * opts.pixelRatio, 6 * opts.pixelRatio, 0, 2 * Math.PI);
  2479. context.closePath();
  2480. context.fill();
  2481. context.stroke();
  2482. break;
  2483. //圆弧进度图不显示图例
  2484. case 'gauge':
  2485. break;
  2486. case 'arcbar':
  2487. break;
  2488. default:
  2489. context.beginPath();
  2490. context.setLineWidth(1 * opts.pixelRatio);
  2491. context.setStrokeStyle(item.color);
  2492. context.setFillStyle(item.color);
  2493. context.moveTo(startX, startY);
  2494. context.fillRect(startX, startY, 15 * opts.pixelRatio, 10 * opts.pixelRatio);
  2495. context.closePath();
  2496. context.fill();
  2497. context.stroke();
  2498. }
  2499. startX += padding + shapeWidth;
  2500. context.beginPath();
  2501. context.setFontSize(config.fontSize);
  2502. context.setFillStyle(opts.extra.legendTextColor || '#333333');
  2503. context.fillText(item.name, startX, startY + 6 * opts.pixelRatio + 3 * opts.pixelRatio);
  2504. context.closePath();
  2505. context.stroke();
  2506. startX += measureText(item.name) + 2 * padding;
  2507. }
  2508. });
  2509. }
  2510. function drawPieDataPoints(series, opts, config, context) {
  2511. var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
  2512. var pieOption = opts.extra.pie || {};
  2513. var centerPosition = {
  2514. x: opts.width / 2,
  2515. y: (opts.height - config.legendHeight) / 2
  2516. };
  2517. var radius = Math.min(centerPosition.x - config.pieChartLinePadding - config.pieChartTextPadding - config._pieTextMaxLength_,
  2518. centerPosition.y - config.pieChartLinePadding - config.pieChartTextPadding);
  2519. if (opts.dataLabel) {
  2520. radius -= 10;
  2521. } else {
  2522. radius -= 2 * config.padding;
  2523. }
  2524. series = getPieDataPoints(series, radius, process);
  2525. var activeRadius = config.pieChartLinePadding / 2;
  2526. series = series.map(function(eachSeries) {
  2527. eachSeries._start_ += (pieOption.offsetAngle || 0) * Math.PI / 180;
  2528. return eachSeries;
  2529. });
  2530. series.forEach(function(eachSeries, seriesIndex) {
  2531. if (opts.tooltip) {
  2532. if (opts.tooltip.index == seriesIndex) {
  2533. context.beginPath();
  2534. context.setFillStyle(hexToRgb(eachSeries.color, opts.extra.pie.activeOpacity || 0.5));
  2535. context.moveTo(centerPosition.x, centerPosition.y);
  2536. context.arc(centerPosition.x, centerPosition.y, eachSeries._radius_+activeRadius, eachSeries._start_, eachSeries._start_ + 2 *
  2537. eachSeries._proportion_ * Math.PI);
  2538. context.closePath();
  2539. context.fill();
  2540. }
  2541. }
  2542. context.beginPath();
  2543. context.setLineWidth(2 * opts.pixelRatio);
  2544. context.lineJoin = "round";
  2545. context.setStrokeStyle('#ffffff');
  2546. context.setFillStyle(eachSeries.color);
  2547. context.moveTo(centerPosition.x, centerPosition.y);
  2548. context.arc(centerPosition.x, centerPosition.y, eachSeries._radius_, eachSeries._start_, eachSeries._start_ + 2 * eachSeries._proportion_ *
  2549. Math.PI);
  2550. context.closePath();
  2551. context.fill();
  2552. if (opts.disablePieStroke !== true) {
  2553. context.stroke();
  2554. }
  2555. });
  2556. if (opts.type === 'ring') {
  2557. var innerPieWidth = radius * 0.6;
  2558. if (typeof opts.extra.pie.ringWidth === 'number' && opts.extra.pie.ringWidth > 0) {
  2559. innerPieWidth = Math.max(0, radius - opts.extra.pie.ringWidth);
  2560. }
  2561. context.beginPath();
  2562. context.setFillStyle(opts.background || '#ffffff');
  2563. context.moveTo(centerPosition.x, centerPosition.y);
  2564. context.arc(centerPosition.x, centerPosition.y, innerPieWidth, 0, 2 * Math.PI);
  2565. context.closePath();
  2566. context.fill();
  2567. }
  2568. if (opts.dataLabel !== false && process === 1) {
  2569. var valid = false;
  2570. for (var i = 0, len = series.length; i < len; i++) {
  2571. if (series[i].data > 0) {
  2572. valid = true;
  2573. break;
  2574. }
  2575. }
  2576. if (valid) {
  2577. drawPieText(series, opts, config, context, radius, centerPosition);
  2578. }
  2579. }
  2580. if (process === 1 && opts.type === 'ring') {
  2581. drawRingTitle(opts, config, context);
  2582. }
  2583. return {
  2584. center: centerPosition,
  2585. radius: radius,
  2586. series: series
  2587. };
  2588. }
  2589. function drawRoseDataPoints(series, opts, config, context) {
  2590. var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
  2591. var roseOption = opts.extra.rose || {};
  2592. roseOption.type = roseOption.type || 'area';
  2593. var centerPosition = {
  2594. x: opts.width / 2,
  2595. y: (opts.height - config.legendHeight) / 2
  2596. };
  2597. var radius = Math.min(centerPosition.x - config.pieChartLinePadding - config.pieChartTextPadding - config._pieTextMaxLength_,
  2598. centerPosition.y - config.pieChartLinePadding - config.pieChartTextPadding);
  2599. if (opts.dataLabel) {
  2600. radius -= 10;
  2601. } else {
  2602. radius -= 2 * config.padding;
  2603. }
  2604. var minRadius = roseOption.minRadius || radius*0.5;
  2605. series = getRoseDataPoints(series, roseOption.type, minRadius, radius, process);
  2606. var activeRadius = config.pieChartLinePadding / 2;
  2607. series = series.map(function(eachSeries) {
  2608. eachSeries._start_ += (roseOption.offsetAngle || 0) * Math.PI / 180;
  2609. return eachSeries;
  2610. });
  2611. series.forEach(function(eachSeries, seriesIndex) {
  2612. if (opts.tooltip) {
  2613. if (opts.tooltip.index == seriesIndex) {
  2614. context.beginPath();
  2615. context.setFillStyle(hexToRgb(eachSeries.color, roseOption.activeOpacity || 0.5));
  2616. context.moveTo(centerPosition.x, centerPosition.y);
  2617. context.arc(centerPosition.x, centerPosition.y, activeRadius+eachSeries._radius_, eachSeries._start_, eachSeries._start_ + 2 * eachSeries._proportion_ * Math.PI);
  2618. context.closePath();
  2619. context.fill();
  2620. }
  2621. }
  2622. context.beginPath();
  2623. context.setLineWidth(2 * opts.pixelRatio);
  2624. context.lineJoin = "round";
  2625. context.setStrokeStyle('#ffffff');
  2626. context.setFillStyle(eachSeries.color);
  2627. context.moveTo(centerPosition.x, centerPosition.y);
  2628. context.arc(centerPosition.x, centerPosition.y, eachSeries._radius_ , eachSeries._start_, eachSeries._start_ + 2 * eachSeries._proportion_ *Math.PI);
  2629. context.closePath();
  2630. context.fill();
  2631. if (opts.disablePieStroke !== true) {
  2632. context.stroke();
  2633. }
  2634. });
  2635. if (opts.dataLabel !== false && process === 1) {
  2636. // fix https://github.com/xiaolin3303/wx-charts/issues/132
  2637. var valid = false;
  2638. for (var i = 0, len = series.length; i < len; i++) {
  2639. if (series[i].data > 0) {
  2640. valid = true;
  2641. break;
  2642. }
  2643. }
  2644. if (valid) {
  2645. drawPieText(series, opts, config, context, radius, centerPosition);
  2646. }
  2647. }
  2648. return {
  2649. center: centerPosition,
  2650. radius: radius,
  2651. series: series
  2652. };
  2653. }
  2654. function drawArcbarDataPoints(series, opts, config, context) {
  2655. var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
  2656. var arcbarOption = opts.extra.arcbar || {};
  2657. arcbarOption.startAngle = arcbarOption.startAngle ? arcbarOption.startAngle : 0.75;
  2658. arcbarOption.endAngle = arcbarOption.endAngle ? arcbarOption.endAngle : 0.25;
  2659. arcbarOption.type = arcbarOption.type ? arcbarOption.type : 'default';
  2660. series = getArcbarDataPoints(series, arcbarOption, process);
  2661. var centerPosition = {
  2662. x: opts.width / 2,
  2663. y: (opts.height) / 2
  2664. };
  2665. var radius = Math.min(centerPosition.x, centerPosition.y);
  2666. if (typeof arcbarOption.width === 'number' && arcbarOption.width > 0) {
  2667. arcbarOption.width = arcbarOption.width;
  2668. } else {
  2669. arcbarOption.width = 12 * opts.pixelRatio;
  2670. }
  2671. radius -= config.padding + arcbarOption.width / 2;
  2672. //背景颜色
  2673. context.setLineWidth(arcbarOption.width); // 设置圆环的宽度
  2674. context.setStrokeStyle(arcbarOption.backgroundColor || '#E9E9E9'); // 设置圆环的颜色
  2675. context.setLineCap('round'); // 设置圆环端点的形状
  2676. context.beginPath(); //开始一个新的路径
  2677. if (arcbarOption.type == 'default') {
  2678. context.arc(centerPosition.x, centerPosition.y, radius, arcbarOption.startAngle * Math.PI, arcbarOption.endAngle *
  2679. Math.PI, false);
  2680. } else {
  2681. context.arc(centerPosition.x, centerPosition.y, radius, 0, 2 * Math.PI, false);
  2682. }
  2683. context.stroke(); //对当前路径进行描边
  2684. for (let i = 0; i < series.length; i++) {
  2685. let eachSeries = series[i];
  2686. context.setLineWidth(arcbarOption.width);
  2687. context.setStrokeStyle(eachSeries.color);
  2688. context.setLineCap('round');
  2689. context.beginPath();
  2690. context.arc(centerPosition.x, centerPosition.y, radius, arcbarOption.startAngle * Math.PI, eachSeries._proportion_ *
  2691. Math.PI, false);
  2692. context.stroke();
  2693. }
  2694. drawRingTitle(opts, config, context);
  2695. return {
  2696. center: centerPosition,
  2697. radius: radius,
  2698. series: series
  2699. };
  2700. }
  2701. function drawGaugeDataPoints(categories, series, opts, config, context) {
  2702. var process = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 1;
  2703. var gaugeOption = opts.extra.gauge || {};
  2704. gaugeOption.startAngle = gaugeOption.startAngle ? gaugeOption.startAngle : 0.75;
  2705. if (gaugeOption.oldAngle == undefined) {
  2706. gaugeOption.oldAngle = gaugeOption.startAngle;
  2707. }
  2708. if (gaugeOption.oldData == undefined) {
  2709. gaugeOption.oldData = 0;
  2710. }
  2711. gaugeOption.endAngle = gaugeOption.endAngle ? gaugeOption.endAngle : 0.25;
  2712. categories = getGaugeAxisPoints(categories, gaugeOption.startAngle, gaugeOption.endAngle);
  2713. var centerPosition = {
  2714. x: opts.width / 2,
  2715. y: (opts.height) / 2
  2716. };
  2717. var radius = Math.min(centerPosition.x, centerPosition.y);
  2718. if (typeof gaugeOption.width === 'number' && gaugeOption.width > 0) {
  2719. gaugeOption.width = gaugeOption.width;
  2720. } else {
  2721. gaugeOption.width = 15 * opts.pixelRatio;
  2722. }
  2723. radius -= config.padding + gaugeOption.width / 2;
  2724. var innerRadius = radius - gaugeOption.width;
  2725. //画背景
  2726. context.setLineWidth(gaugeOption.width);
  2727. context.setLineCap('butt');
  2728. for (let i = 0; i < categories.length; i++) {
  2729. let eachCategories = categories[i];
  2730. context.beginPath();
  2731. context.setStrokeStyle(eachCategories.color);
  2732. context.arc(centerPosition.x, centerPosition.y, radius, eachCategories._startAngle_ * Math.PI, eachCategories._endAngle_ *
  2733. Math.PI, false);
  2734. context.stroke();
  2735. }
  2736. context.save();
  2737. //画刻度线
  2738. let totalAngle = gaugeOption.startAngle - gaugeOption.endAngle + 1;
  2739. gaugeOption.splitLine.fixRadius = gaugeOption.splitLine.fixRadius ? gaugeOption.splitLine.fixRadius : 0;
  2740. gaugeOption.splitLine.splitNumber = gaugeOption.splitLine.splitNumber ? gaugeOption.splitLine.splitNumber : 10;
  2741. gaugeOption.splitLine.width = gaugeOption.splitLine.width ? gaugeOption.splitLine.width : 15 * opts.pixelRatio;
  2742. gaugeOption.splitLine.color = gaugeOption.splitLine.color ? gaugeOption.splitLine.color : '#FFFFFF';
  2743. gaugeOption.splitLine.childNumber = gaugeOption.splitLine.childNumber ? gaugeOption.splitLine.childNumber : 5;
  2744. gaugeOption.splitLine.childWidth = gaugeOption.splitLine.childWidth ? gaugeOption.splitLine.childWidth : 5 * opts.pixelRatio;
  2745. let splitAngle = totalAngle / gaugeOption.splitLine.splitNumber;
  2746. let childAngle = totalAngle / gaugeOption.splitLine.splitNumber / gaugeOption.splitLine.childNumber;
  2747. let startX = -radius - gaugeOption.width * 0.5 - gaugeOption.splitLine.fixRadius;
  2748. let endX = -radius - gaugeOption.width * 0.5 - gaugeOption.splitLine.fixRadius + gaugeOption.splitLine.width;
  2749. let childendX = -radius - gaugeOption.width * 0.5 - gaugeOption.splitLine.fixRadius + gaugeOption.splitLine.childWidth;
  2750. context.translate(centerPosition.x, centerPosition.y);
  2751. context.rotate((gaugeOption.startAngle - 1) * Math.PI);
  2752. for (let i = 0; i < gaugeOption.splitLine.splitNumber + 1; i++) {
  2753. context.beginPath();
  2754. context.setStrokeStyle(gaugeOption.splitLine.color);
  2755. context.setLineWidth(2 * opts.pixelRatio);
  2756. context.moveTo(startX, 0);
  2757. context.lineTo(endX, 0);
  2758. context.stroke();
  2759. context.rotate(splitAngle * Math.PI);
  2760. }
  2761. context.restore();
  2762. context.save();
  2763. context.translate(centerPosition.x, centerPosition.y);
  2764. context.rotate((gaugeOption.startAngle - 1) * Math.PI);
  2765. for (let i = 0; i < gaugeOption.splitLine.splitNumber * gaugeOption.splitLine.childNumber + 1; i++) {
  2766. context.beginPath();
  2767. context.setStrokeStyle(gaugeOption.splitLine.color);
  2768. context.setLineWidth(1 * opts.pixelRatio);
  2769. context.moveTo(startX, 0);
  2770. context.lineTo(childendX, 0);
  2771. context.stroke();
  2772. context.rotate(childAngle * Math.PI);
  2773. }
  2774. context.restore();
  2775. //画指针
  2776. gaugeOption.pointer.width = gaugeOption.pointer.width ? gaugeOption.pointer.width : 15 * opts.pixelRatio;
  2777. if (gaugeOption.pointer.color == undefined || gaugeOption.pointer.color == 'auto') {
  2778. gaugeOption.pointer.color == 'auto';
  2779. } else {
  2780. gaugeOption.pointer.color == gaugeOption.pointer.color;
  2781. }
  2782. series = getGaugeDataPoints(series, categories, gaugeOption, process);
  2783. for (let i = 0; i < series.length; i++) {
  2784. let eachSeries = series[i];
  2785. context.save();
  2786. context.translate(centerPosition.x, centerPosition.y);
  2787. context.rotate((eachSeries._proportion_ - 1) * Math.PI);
  2788. context.beginPath();
  2789. context.setFillStyle(eachSeries.color);
  2790. context.moveTo(gaugeOption.pointer.width, 0);
  2791. context.lineTo(0, -gaugeOption.pointer.width / 2);
  2792. context.lineTo(-innerRadius, 0);
  2793. context.lineTo(0, gaugeOption.pointer.width / 2);
  2794. context.lineTo(gaugeOption.pointer.width, 0);
  2795. context.closePath();
  2796. context.fill();
  2797. context.beginPath();
  2798. context.setFillStyle('#FFFFFF');
  2799. context.arc(0, 0, gaugeOption.pointer.width / 6, 0, 2 * Math.PI, false);
  2800. context.fill();
  2801. context.restore();
  2802. }
  2803. if (opts.dataLabel !== false) {
  2804. drawGaugeLabel(gaugeOption, radius, centerPosition, opts, config, context);
  2805. }
  2806. drawRingTitle(opts, config, context);
  2807. if (process === 1 && opts.type === 'gauge') {
  2808. gaugeOption.oldAngle = series[0]._proportion_;
  2809. gaugeOption.oldData = series[0].data;
  2810. }
  2811. return {
  2812. center: centerPosition,
  2813. radius: radius,
  2814. innerRadius: innerRadius,
  2815. categories: categories,
  2816. totalAngle: totalAngle
  2817. };
  2818. }
  2819. function drawRadarDataPoints(series, opts, config, context) {
  2820. var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
  2821. var radarOption = opts.extra.radar || {};
  2822. var coordinateAngle = getRadarCoordinateSeries(opts.categories.length);
  2823. var centerPosition = {
  2824. x: opts.width / 2,
  2825. y: (opts.height - config.legendHeight) / 2
  2826. };
  2827. var radius = Math.min(centerPosition.x - (getMaxTextListLength(opts.categories) + config.radarLabelTextMargin),
  2828. centerPosition.y - config.radarLabelTextMargin);
  2829. radius -= config.padding;
  2830. // draw grid
  2831. context.beginPath();
  2832. context.setLineWidth(1 * opts.pixelRatio);
  2833. context.setStrokeStyle(radarOption.gridColor || "#cccccc");
  2834. coordinateAngle.forEach(function (angle) {
  2835. var pos = convertCoordinateOrigin(radius * Math.cos(angle), radius * Math.sin(angle), centerPosition);
  2836. context.moveTo(centerPosition.x, centerPosition.y);
  2837. context.lineTo(pos.x, pos.y);
  2838. });
  2839. context.stroke();
  2840. context.closePath();
  2841. // draw split line grid
  2842. var _loop = function _loop(i) {
  2843. var startPos = {};
  2844. context.beginPath();
  2845. context.setLineWidth(1 * opts.pixelRatio);
  2846. context.setStrokeStyle(radarOption.gridColor || "#cccccc");
  2847. coordinateAngle.forEach(function (angle, index) {
  2848. var pos = convertCoordinateOrigin(radius / config.radarGridCount * i * Math.cos(angle), radius / config.radarGridCount * i * Math.sin(angle), centerPosition);
  2849. if (index === 0) {
  2850. startPos = pos;
  2851. context.moveTo(pos.x, pos.y);
  2852. } else {
  2853. context.lineTo(pos.x, pos.y);
  2854. }
  2855. });
  2856. context.lineTo(startPos.x, startPos.y);
  2857. context.stroke();
  2858. context.closePath();
  2859. };
  2860. for (var i = 1; i <= config.radarGridCount; i++) {
  2861. _loop(i);
  2862. }
  2863. var radarDataPoints = getRadarDataPoints(coordinateAngle, centerPosition, radius, series, opts, process);
  2864. radarDataPoints.forEach(function(eachSeries, seriesIndex) {
  2865. // 绘制区域数据
  2866. context.beginPath();
  2867. context.setFillStyle(eachSeries.color);
  2868. context.setGlobalAlpha(0.3);
  2869. eachSeries.data.forEach(function(item, index) {
  2870. if (index === 0) {
  2871. context.moveTo(item.position.x, item.position.y);
  2872. } else {
  2873. context.lineTo(item.position.x, item.position.y);
  2874. }
  2875. });
  2876. context.closePath();
  2877. context.fill();
  2878. context.setGlobalAlpha(1);
  2879. if (opts.dataPointShape !== false) {
  2880. var shape = config.dataPointShape[seriesIndex % config.dataPointShape.length];
  2881. var points = eachSeries.data.map(function(item) {
  2882. return item.position;
  2883. });
  2884. drawPointShape(points, eachSeries.color, shape, context, opts);
  2885. }
  2886. });
  2887. // draw label text
  2888. drawRadarLabel(coordinateAngle, radius, centerPosition, opts, config, context);
  2889. return {
  2890. center: centerPosition,
  2891. radius: radius,
  2892. angleList: coordinateAngle
  2893. };
  2894. }
  2895. function drawCanvas(opts, context) {
  2896. context.draw();
  2897. }
  2898. var Timing = {
  2899. easeIn: function easeIn(pos) {
  2900. return Math.pow(pos, 3);
  2901. },
  2902. easeOut: function easeOut(pos) {
  2903. return Math.pow(pos - 1, 3) + 1;
  2904. },
  2905. easeInOut: function easeInOut(pos) {
  2906. if ((pos /= 0.5) < 1) {
  2907. return 0.5 * Math.pow(pos, 3);
  2908. } else {
  2909. return 0.5 * (Math.pow(pos - 2, 3) + 2);
  2910. }
  2911. },
  2912. linear: function linear(pos) {
  2913. return pos;
  2914. }
  2915. };
  2916. function Animation(opts) {
  2917. this.isStop = false;
  2918. opts.duration = typeof opts.duration === 'undefined' ? 1000 : opts.duration;
  2919. opts.timing = opts.timing || 'linear';
  2920. var delay = 17;
  2921. var createAnimationFrame = function createAnimationFrame() {
  2922. if (typeof requestAnimationFrame !== 'undefined') {
  2923. return requestAnimationFrame;
  2924. } else if (typeof setTimeout !== 'undefined') {
  2925. return function(step, delay) {
  2926. setTimeout(function() {
  2927. var timeStamp = +new Date();
  2928. step(timeStamp);
  2929. }, delay);
  2930. };
  2931. } else {
  2932. return function(step) {
  2933. step(null);
  2934. };
  2935. }
  2936. };
  2937. var animationFrame = createAnimationFrame();
  2938. var startTimeStamp = null;
  2939. var _step = function step(timestamp) {
  2940. if (timestamp === null || this.isStop === true) {
  2941. opts.onProcess && opts.onProcess(1);
  2942. opts.onAnimationFinish && opts.onAnimationFinish();
  2943. return;
  2944. }
  2945. if (startTimeStamp === null) {
  2946. startTimeStamp = timestamp;
  2947. }
  2948. if (timestamp - startTimeStamp < opts.duration) {
  2949. var process = (timestamp - startTimeStamp) / opts.duration;
  2950. var timingFunction = Timing[opts.timing];
  2951. process = timingFunction(process);
  2952. opts.onProcess && opts.onProcess(process);
  2953. animationFrame(_step, delay);
  2954. } else {
  2955. opts.onProcess && opts.onProcess(1);
  2956. opts.onAnimationFinish && opts.onAnimationFinish();
  2957. }
  2958. };
  2959. _step = _step.bind(this);
  2960. animationFrame(_step, delay);
  2961. }
  2962. // stop animation immediately
  2963. // and tigger onAnimationFinish
  2964. Animation.prototype.stop = function() {
  2965. this.isStop = true;
  2966. };
  2967. function drawCharts(type, opts, config, context) {
  2968. var _this = this;
  2969. var series = opts.series;
  2970. var categories = opts.categories;
  2971. series = fillSeriesColor(series, config);
  2972. series = fillSeriesType(series, opts);
  2973. let seriesMA = null;
  2974. if (type == 'candle') {
  2975. let average = assign({}, opts.extra.candle.average);
  2976. if (average.show) {
  2977. seriesMA = calCandleMA(average.day, average.name, average.color, series[0].data);
  2978. opts.seriesMA = seriesMA;
  2979. }
  2980. }
  2981. var _calLegendData = calLegendData(series, opts, config),
  2982. legendHeight = _calLegendData.legendHeight;
  2983. config.legendHeight = legendHeight;
  2984. var _calYAxisData = calYAxisData(series, opts, config),
  2985. yAxisWidth = _calYAxisData.yAxisWidth;
  2986. config.yAxisWidth = yAxisWidth;
  2987. if (categories && categories.length) {
  2988. var _calCategoriesData = calCategoriesData(categories, opts, config),
  2989. xAxisHeight = _calCategoriesData.xAxisHeight,
  2990. angle = _calCategoriesData.angle;
  2991. config.xAxisHeight = xAxisHeight;
  2992. config._xAxisTextAngle_ = angle;
  2993. }
  2994. if (type === 'pie' || type === 'ring' || type === 'rose') {
  2995. config._pieTextMaxLength_ = opts.dataLabel === false ? 0 : getPieTextMaxLength(series);
  2996. }
  2997. var duration = opts.animation ? opts.duration : 0;
  2998. this.animationInstance && this.animationInstance.stop();
  2999. switch (type) {
  3000. case 'line':
  3001. this.animationInstance = new Animation({
  3002. timing: 'easeIn',
  3003. duration: duration,
  3004. onProcess: function onProcess(process) {
  3005. context.clearRect(0, 0, opts.width, opts.height);
  3006. if (opts.rotate) {
  3007. contextRotate(context, opts);
  3008. }
  3009. drawYAxisGrid(categories, opts, config, context);
  3010. drawXAxis(categories, opts, config, context);
  3011. var _drawLineDataPoints = drawLineDataPoints(series, opts, config, context, process),
  3012. xAxisPoints = _drawLineDataPoints.xAxisPoints,
  3013. calPoints = _drawLineDataPoints.calPoints,
  3014. eachSpacing = _drawLineDataPoints.eachSpacing;
  3015. _this.chartData.xAxisPoints = xAxisPoints;
  3016. _this.chartData.calPoints = calPoints;
  3017. _this.chartData.eachSpacing = eachSpacing;
  3018. drawLegend(opts.series, opts, config, context);
  3019. drawYAxis(series, opts, config, context);
  3020. drawToolTipBridge(opts, config, context, process, eachSpacing, xAxisPoints);
  3021. drawCanvas(opts, context);
  3022. },
  3023. onAnimationFinish: function onAnimationFinish() {
  3024. _this.event.trigger('renderComplete');
  3025. }
  3026. });
  3027. break;
  3028. case 'mix':
  3029. this.animationInstance = new Animation({
  3030. timing: 'easeIn',
  3031. duration: duration,
  3032. onProcess: function onProcess(process) {
  3033. context.clearRect(0, 0, opts.width, opts.height);
  3034. if (opts.rotate) {
  3035. contextRotate(context, opts);
  3036. }
  3037. drawYAxisGrid(categories, opts, config, context);
  3038. drawXAxis(categories, opts, config, context);
  3039. var _drawMixDataPoints = drawMixDataPoints(series, opts, config, context, process),
  3040. xAxisPoints = _drawMixDataPoints.xAxisPoints,
  3041. calPoints = _drawMixDataPoints.calPoints,
  3042. eachSpacing = _drawMixDataPoints.eachSpacing;
  3043. _this.chartData.xAxisPoints = xAxisPoints;
  3044. _this.chartData.calPoints = calPoints;
  3045. _this.chartData.eachSpacing = eachSpacing;
  3046. drawLegend(opts.series, opts, config, context);
  3047. drawYAxis(series, opts, config, context);
  3048. drawToolTipBridge(opts, config, context, process, eachSpacing, xAxisPoints);
  3049. drawCanvas(opts, context);
  3050. },
  3051. onAnimationFinish: function onAnimationFinish() {
  3052. _this.event.trigger('renderComplete');
  3053. }
  3054. });
  3055. break;
  3056. case 'column':
  3057. this.animationInstance = new Animation({
  3058. timing: 'easeIn',
  3059. duration: duration,
  3060. onProcess: function onProcess(process) {
  3061. context.clearRect(0, 0, opts.width, opts.height);
  3062. if (opts.rotate) {
  3063. contextRotate(context, opts);
  3064. }
  3065. drawYAxisGrid(categories, opts, config, context);
  3066. drawXAxis(categories, opts, config, context);
  3067. var _drawColumnDataPoints = drawColumnDataPoints(series, opts, config, context, process),
  3068. xAxisPoints = _drawColumnDataPoints.xAxisPoints,
  3069. calPoints = _drawColumnDataPoints.calPoints,
  3070. eachSpacing = _drawColumnDataPoints.eachSpacing;
  3071. _this.chartData.xAxisPoints = xAxisPoints;
  3072. _this.chartData.calPoints = calPoints;
  3073. _this.chartData.eachSpacing = eachSpacing;
  3074. drawLegend(opts.series, opts, config, context);
  3075. drawYAxis(series, opts, config, context);
  3076. drawToolTipBridge(opts, config, context, process, eachSpacing, xAxisPoints);
  3077. drawCanvas(opts, context);
  3078. },
  3079. onAnimationFinish: function onAnimationFinish() {
  3080. _this.event.trigger('renderComplete');
  3081. }
  3082. });
  3083. break;
  3084. case 'area':
  3085. this.animationInstance = new Animation({
  3086. timing: 'easeIn',
  3087. duration: duration,
  3088. onProcess: function onProcess(process) {
  3089. context.clearRect(0, 0, opts.width, opts.height);
  3090. if (opts.rotate) {
  3091. contextRotate(context, opts);
  3092. }
  3093. drawYAxisGrid(categories, opts, config, context);
  3094. drawXAxis(categories, opts, config, context);
  3095. var _drawAreaDataPoints = drawAreaDataPoints(series, opts, config, context, process),
  3096. xAxisPoints = _drawAreaDataPoints.xAxisPoints,
  3097. calPoints = _drawAreaDataPoints.calPoints,
  3098. eachSpacing = _drawAreaDataPoints.eachSpacing;
  3099. _this.chartData.xAxisPoints = xAxisPoints;
  3100. _this.chartData.calPoints = calPoints;
  3101. _this.chartData.eachSpacing = eachSpacing;
  3102. drawLegend(opts.series, opts, config, context);
  3103. drawYAxis(series, opts, config, context);
  3104. drawToolTipBridge(opts, config, context, process, eachSpacing, xAxisPoints);
  3105. drawCanvas(opts, context);
  3106. },
  3107. onAnimationFinish: function onAnimationFinish() {
  3108. _this.event.trigger('renderComplete');
  3109. }
  3110. });
  3111. break;
  3112. case 'ring':
  3113. case 'pie':
  3114. this.animationInstance = new Animation({
  3115. timing: 'easeInOut',
  3116. duration: duration,
  3117. onProcess: function onProcess(process) {
  3118. context.clearRect(0, 0, opts.width, opts.height);
  3119. if (opts.rotate) {
  3120. contextRotate(context, opts);
  3121. }
  3122. _this.chartData.pieData = drawPieDataPoints(series, opts, config, context, process);
  3123. drawLegend(opts.series, opts, config, context);
  3124. drawToolTipBridge(opts, config, context, process);
  3125. drawCanvas(opts, context);
  3126. },
  3127. onAnimationFinish: function onAnimationFinish() {
  3128. _this.event.trigger('renderComplete');
  3129. }
  3130. });
  3131. break;
  3132. case 'rose':
  3133. this.animationInstance = new Animation({
  3134. timing: 'easeInOut',
  3135. duration: duration,
  3136. onProcess: function onProcess(process) {
  3137. context.clearRect(0, 0, opts.width, opts.height);
  3138. if (opts.rotate) {
  3139. contextRotate(context, opts);
  3140. }
  3141. _this.chartData.pieData = drawRoseDataPoints(series, opts, config, context, process);
  3142. drawLegend(opts.series, opts, config, context);
  3143. drawToolTipBridge(opts, config, context, process);
  3144. drawCanvas(opts, context);
  3145. },
  3146. onAnimationFinish: function onAnimationFinish() {
  3147. _this.event.trigger('renderComplete');
  3148. }
  3149. });
  3150. break;
  3151. case 'radar':
  3152. this.animationInstance = new Animation({
  3153. timing: 'easeInOut',
  3154. duration: duration,
  3155. onProcess: function onProcess(process) {
  3156. context.clearRect(0, 0, opts.width, opts.height);
  3157. if (opts.rotate) {
  3158. contextRotate(context, opts);
  3159. }
  3160. _this.chartData.radarData = drawRadarDataPoints(series, opts, config, context, process);
  3161. drawLegend(opts.series, opts, config, context);
  3162. drawToolTipBridge(opts, config, context, process);
  3163. drawCanvas(opts, context);
  3164. },
  3165. onAnimationFinish: function onAnimationFinish() {
  3166. _this.event.trigger('renderComplete');
  3167. }
  3168. });
  3169. break;
  3170. case 'arcbar':
  3171. this.animationInstance = new Animation({
  3172. timing: 'easeInOut',
  3173. duration: duration,
  3174. onProcess: function onProcess(process) {
  3175. context.clearRect(0, 0, opts.width, opts.height);
  3176. if (opts.rotate) {
  3177. contextRotate(context, opts);
  3178. }
  3179. _this.chartData.arcbarData = drawArcbarDataPoints(series, opts, config, context, process);
  3180. drawCanvas(opts, context);
  3181. },
  3182. onAnimationFinish: function onAnimationFinish() {
  3183. _this.event.trigger('renderComplete');
  3184. }
  3185. });
  3186. break;
  3187. case 'gauge':
  3188. this.animationInstance = new Animation({
  3189. timing: 'easeInOut',
  3190. duration: duration,
  3191. onProcess: function onProcess(process) {
  3192. context.clearRect(0, 0, opts.width, opts.height);
  3193. if (opts.rotate) {
  3194. contextRotate(context, opts);
  3195. }
  3196. _this.chartData.gaugeData = drawGaugeDataPoints(categories, series, opts, config, context, process);
  3197. drawCanvas(opts, context);
  3198. },
  3199. onAnimationFinish: function onAnimationFinish() {
  3200. _this.event.trigger('renderComplete');
  3201. }
  3202. });
  3203. break;
  3204. case 'candle':
  3205. this.animationInstance = new Animation({
  3206. timing: 'easeIn',
  3207. duration: duration,
  3208. onProcess: function onProcess(process) {
  3209. context.clearRect(0, 0, opts.width, opts.height);
  3210. if (opts.rotate) {
  3211. contextRotate(context, opts);
  3212. }
  3213. drawYAxisGrid(categories, opts, config, context);
  3214. drawXAxis(categories, opts, config, context);
  3215. var _drawCandleDataPoints = drawCandleDataPoints(series, seriesMA, opts, config, context, process),
  3216. xAxisPoints = _drawCandleDataPoints.xAxisPoints,
  3217. calPoints = _drawCandleDataPoints.calPoints,
  3218. eachSpacing = _drawCandleDataPoints.eachSpacing;
  3219. _this.chartData.xAxisPoints = xAxisPoints;
  3220. _this.chartData.calPoints = calPoints;
  3221. _this.chartData.eachSpacing = eachSpacing;
  3222. if (seriesMA) {
  3223. drawLegend(seriesMA, opts, config, context);
  3224. } else {
  3225. drawLegend(opts.series, opts, config, context);
  3226. }
  3227. drawYAxis(series, opts, config, context);
  3228. drawToolTipBridge(opts, config, context, process, eachSpacing, xAxisPoints);
  3229. drawCanvas(opts, context);
  3230. },
  3231. onAnimationFinish: function onAnimationFinish() {
  3232. _this.event.trigger('renderComplete');
  3233. }
  3234. });
  3235. break;
  3236. }
  3237. }
  3238. // simple event implement
  3239. function Event() {
  3240. this.events = {};
  3241. }
  3242. Event.prototype.addEventListener = function(type, listener) {
  3243. this.events[type] = this.events[type] || [];
  3244. this.events[type].push(listener);
  3245. };
  3246. Event.prototype.trigger = function() {
  3247. for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
  3248. args[_key] = arguments[_key];
  3249. }
  3250. var type = args[0];
  3251. var params = args.slice(1);
  3252. if (!!this.events[type]) {
  3253. this.events[type].forEach(function(listener) {
  3254. try {
  3255. listener.apply(null, params);
  3256. } catch (e) {
  3257. // console.error(e);
  3258. }
  3259. });
  3260. }
  3261. };
  3262. var Charts = function Charts(opts) {
  3263. opts.pixelRatio = opts.pixelRatio ? opts.pixelRatio : 1;
  3264. opts.fontSize = opts.fontSize ? opts.fontSize * opts.pixelRatio : 13 * opts.pixelRatio;
  3265. opts.title = assign({}, opts.title);
  3266. opts.subtitle = assign({}, opts.subtitle);
  3267. opts.yAxis = assign({}, {
  3268. gridType:'solid',
  3269. dashLength:4 * opts.pixelRatio
  3270. },opts.yAxis);
  3271. opts.xAxis = assign({}, {
  3272. rotateLabel:false,
  3273. type:'calibration',
  3274. gridType:'solid',
  3275. dashLength:4 * opts.pixelRatio,
  3276. scrollAlign:'left'
  3277. },opts.xAxis);
  3278. opts.extra = assign({}, opts.extra);
  3279. opts.rotate = opts.rotate ? true : false;
  3280. opts.animation = opts.animation ? true : false;
  3281. var config$$1 = assign({}, config);
  3282. config$$1.yAxisTitleWidth = opts.yAxis.disabled !== true && opts.yAxis.title ? config$$1.yAxisTitleWidth : 0;
  3283. if (opts.type == 'pie' || opts.type == 'ring' ) {
  3284. config$$1.pieChartLinePadding = opts.dataLabel === false ? 0 : opts.extra.pie.labelWidth*opts.pixelRatio || config$$1.pieChartLinePadding *opts.pixelRatio;
  3285. }
  3286. if (opts.type == 'rose' ) {
  3287. config$$1.pieChartLinePadding = opts.dataLabel === false ? 0 : opts.extra.rose.labelWidth*opts.pixelRatio || config$$1.pieChartLinePadding *opts.pixelRatio;
  3288. }
  3289. config$$1.pieChartTextPadding = opts.dataLabel === false ? 0 : config$$1.pieChartTextPadding * opts.pixelRatio;
  3290. config$$1.yAxisSplit = opts.yAxis.splitNumber ? opts.yAxis.splitNumber : config.yAxisSplit;
  3291. //屏幕旋转
  3292. config$$1.rotate = opts.rotate;
  3293. if (opts.rotate) {
  3294. let tempWidth = opts.width;
  3295. let tempHeight = opts.height;
  3296. opts.width = tempHeight;
  3297. opts.height = tempWidth;
  3298. }
  3299. //适配高分屏
  3300. config$$1.yAxisWidth = config.yAxisWidth * opts.pixelRatio;
  3301. config$$1.xAxisHeight = config.xAxisHeight * opts.pixelRatio;
  3302. if (opts.enableScroll && opts.xAxis.scrollShow) {
  3303. config$$1.xAxisHeight += 6 * opts.pixelRatio;
  3304. }
  3305. config$$1.xAxisLineHeight = config.xAxisLineHeight * opts.pixelRatio;
  3306. config$$1.legendHeight = config.legendHeight * opts.pixelRatio;
  3307. config$$1.padding = config.padding * opts.pixelRatio;
  3308. config$$1.fontSize = opts.fontSize;
  3309. config$$1.titleFontSize = config.titleFontSize * opts.pixelRatio;
  3310. config$$1.subtitleFontSize = config.subtitleFontSize * opts.pixelRatio;
  3311. config$$1.toolTipPadding = config.toolTipPadding * opts.pixelRatio;
  3312. config$$1.toolTipLineHeight = config.toolTipLineHeight * opts.pixelRatio;
  3313. config$$1.columePadding = config.columePadding * opts.pixelRatio;
  3314. this.opts = opts;
  3315. this.config = config$$1;
  3316. opts.$this = opts.$this ? opts.$this : this;
  3317. this.context = uni.createCanvasContext(opts.canvasId, opts.$this);
  3318. /* 兼容原生H5
  3319. this.context = document.getElementById(opts.canvasId).getContext("2d");
  3320. this.context.setStrokeStyle = function(e){ return this.strokeStyle=e; }
  3321. this.context.setLineWidth = function(e){ return this.lineWidth=e; }
  3322. this.context.setLineCap = function(e){ return this.lineCap=e; }
  3323. this.context.setFontSize = function(e){ return this.font=e+"px sans-serif"; }
  3324. this.context.setFillStyle = function(e){ return this.fillStyle=e; }
  3325. this.context.draw = function(){ }
  3326. */
  3327. this.chartData = {};
  3328. this.event = new Event();
  3329. this.scrollOption = {
  3330. currentOffset: 0,
  3331. startTouchX: 0,
  3332. distance: 0,
  3333. lastMoveTime: 0
  3334. };
  3335. //计算右对齐偏移距离
  3336. if (opts.enableScroll && opts.xAxis.scrollAlign == 'right') {
  3337. let _calYAxisData = calYAxisData(opts.series, opts, config$$1),
  3338. yAxisWidth = _calYAxisData.yAxisWidth;
  3339. config$$1.yAxisWidth = yAxisWidth;
  3340. let offsetLeft = 0;
  3341. let _getXAxisPoints0 = getXAxisPoints(opts.categories, opts, config$$1),
  3342. xAxisPoints = _getXAxisPoints0.xAxisPoints,
  3343. startX = _getXAxisPoints0.startX,
  3344. endX = _getXAxisPoints0.endX,
  3345. eachSpacing = _getXAxisPoints0.eachSpacing;
  3346. let totalWidth = eachSpacing * (xAxisPoints.length - 1);
  3347. let screenWidth = endX - startX;
  3348. offsetLeft = screenWidth - totalWidth;
  3349. this.scrollOption = {
  3350. currentOffset: offsetLeft,
  3351. startTouchX: offsetLeft,
  3352. distance: 0,
  3353. lastMoveTime: 0
  3354. };
  3355. opts._scrollDistance_ = offsetLeft;
  3356. }
  3357. drawCharts.call(this, opts.type, opts, config$$1, this.context);
  3358. };
  3359. Charts.prototype.updateData = function() {
  3360. let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  3361. this.opts = assign({}, this.opts, data);
  3362. let scrollPosition = data.scrollPosition || 'current';
  3363. switch (scrollPosition) {
  3364. case 'current':
  3365. this.opts._scrollDistance_ = this.scrollOption.currentOffset;
  3366. break;
  3367. case 'left':
  3368. this.opts._scrollDistance_ = 0;
  3369. this.scrollOption = {
  3370. currentOffset: 0,
  3371. startTouchX: 0,
  3372. distance: 0,
  3373. lastMoveTime: 0
  3374. };
  3375. break;
  3376. case 'right':
  3377. let _calYAxisData = calYAxisData(this.opts.series, this.opts, this.config),
  3378. yAxisWidth = _calYAxisData.yAxisWidth;
  3379. this.config.yAxisWidth = yAxisWidth;
  3380. let offsetLeft = 0;
  3381. let _getXAxisPoints0 = getXAxisPoints(this.opts.categories, this.opts, this.config),
  3382. xAxisPoints = _getXAxisPoints0.xAxisPoints,
  3383. startX = _getXAxisPoints0.startX,
  3384. endX = _getXAxisPoints0.endX,
  3385. eachSpacing = _getXAxisPoints0.eachSpacing;
  3386. let totalWidth = eachSpacing * (xAxisPoints.length - 1);
  3387. let screenWidth = endX - startX;
  3388. offsetLeft = screenWidth - totalWidth;
  3389. this.scrollOption = {
  3390. currentOffset: offsetLeft,
  3391. startTouchX: offsetLeft,
  3392. distance: 0,
  3393. lastMoveTime: 0
  3394. };
  3395. this.opts._scrollDistance_ = offsetLeft;
  3396. break;
  3397. }
  3398. drawCharts.call(this, this.opts.type, this.opts, this.config, this.context);
  3399. };
  3400. Charts.prototype.zoom = function() {
  3401. var val = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.opts.xAxis.itemCount;
  3402. if (this.opts.enableScroll !== true) {
  3403. // console.log('请启用滚动条后使用!')
  3404. return;
  3405. }
  3406. //当前屏幕中间点
  3407. let centerPoint = Math.round(Math.abs(this.scrollOption.currentOffset) / this.chartData.eachSpacing) + Math.round(
  3408. this.opts.xAxis.itemCount / 2);
  3409. this.opts.animation = false;
  3410. this.opts.xAxis.itemCount = val.itemCount;
  3411. //重新计算x轴偏移距离
  3412. let _calYAxisData = calYAxisData(this.opts.series, this.opts, this.config),
  3413. yAxisWidth = _calYAxisData.yAxisWidth;
  3414. this.config.yAxisWidth = yAxisWidth;
  3415. let offsetLeft = 0;
  3416. let _getXAxisPoints0 = getXAxisPoints(this.opts.categories, this.opts, this.config),
  3417. xAxisPoints = _getXAxisPoints0.xAxisPoints,
  3418. startX = _getXAxisPoints0.startX,
  3419. endX = _getXAxisPoints0.endX,
  3420. eachSpacing = _getXAxisPoints0.eachSpacing;
  3421. let centerLeft = eachSpacing * centerPoint;
  3422. let screenWidth = endX - startX;
  3423. let MaxLeft = screenWidth - eachSpacing * (xAxisPoints.length - 1);
  3424. offsetLeft = screenWidth / 2 - centerLeft;
  3425. if (offsetLeft > 0) {
  3426. offsetLeft = 0;
  3427. }
  3428. if (offsetLeft < MaxLeft) {
  3429. offsetLeft = MaxLeft;
  3430. }
  3431. this.scrollOption = {
  3432. currentOffset: offsetLeft,
  3433. startTouchX: offsetLeft,
  3434. distance: 0,
  3435. lastMoveTime: 0
  3436. };
  3437. this.opts._scrollDistance_ = offsetLeft;
  3438. drawCharts.call(this, this.opts.type, this.opts, this.config, this.context);
  3439. };
  3440. Charts.prototype.stopAnimation = function() {
  3441. this.animationInstance && this.animationInstance.stop();
  3442. };
  3443. Charts.prototype.addEventListener = function(type, listener) {
  3444. this.event.addEventListener(type, listener);
  3445. };
  3446. Charts.prototype.getCurrentDataIndex = function(e) {
  3447. var touches = null;
  3448. if(e.changedTouches){
  3449. touches = e.changedTouches[0];
  3450. }else{
  3451. touches = e.mp.changedTouches[0];
  3452. }
  3453. if (touches) {
  3454. var _touches$ = getTouches(touches, this.opts, e);
  3455. if (this.opts.type === 'pie' || this.opts.type === 'ring' || this.opts.type === 'rose') {
  3456. return findPieChartCurrentIndex({
  3457. x: _touches$.x,
  3458. y: _touches$.y
  3459. }, this.chartData.pieData);
  3460. } else if (this.opts.type === 'radar') {
  3461. return findRadarChartCurrentIndex({
  3462. x: _touches$.x,
  3463. y: _touches$.y
  3464. }, this.chartData.radarData, this.opts.categories.length);
  3465. } else {
  3466. return findCurrentIndex({
  3467. x: _touches$.x,
  3468. y: _touches$.y
  3469. }, this.chartData.xAxisPoints, this.opts, this.config, Math.abs(this.scrollOption.currentOffset));
  3470. }
  3471. }
  3472. return -1;
  3473. };
  3474. Charts.prototype.showToolTip = function(e) {
  3475. var option = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  3476. var touches = null;
  3477. if(e.changedTouches){
  3478. touches = e.changedTouches[0];
  3479. }else{
  3480. touches = e.mp.changedTouches[0];
  3481. }
  3482. if(!touches){
  3483. // console.log("touchError");
  3484. return;
  3485. }
  3486. var _touches$ = getTouches(touches, this.opts, e);
  3487. if (this.opts.type === 'line' || this.opts.type === 'area' || this.opts.type === 'column') {
  3488. var index = this.getCurrentDataIndex(e);
  3489. var currentOffset = this.scrollOption.currentOffset;
  3490. var opts = assign({}, this.opts, {
  3491. _scrollDistance_: currentOffset,
  3492. animation: false
  3493. });
  3494. if (index > -1) {
  3495. var seriesData = getSeriesDataItem(this.opts.series, index);
  3496. if (seriesData.length !== 0) {
  3497. var _getToolTipData = getToolTipData(seriesData, this.chartData.calPoints, index, this.opts.categories, option),
  3498. textList = _getToolTipData.textList,
  3499. offset = _getToolTipData.offset;
  3500. offset.y = _touches$.y;
  3501. opts.tooltip = {
  3502. textList: textList,
  3503. offset: offset,
  3504. option: option,
  3505. index: index
  3506. };
  3507. }
  3508. }
  3509. drawCharts.call(this, opts.type, opts, this.config, this.context);
  3510. }
  3511. if (this.opts.type === 'mix') {
  3512. var index = this.getCurrentDataIndex(e);
  3513. var currentOffset = this.scrollOption.currentOffset;
  3514. var opts = assign({}, this.opts, {
  3515. _scrollDistance_: currentOffset,
  3516. animation: false
  3517. });
  3518. if (index > -1) {
  3519. var seriesData = getSeriesDataItem(this.opts.series, index);
  3520. if (seriesData.length !== 0) {
  3521. var _getMixToolTipData = getMixToolTipData(seriesData, this.chartData.calPoints, index, this.opts.categories,option),
  3522. textList = _getMixToolTipData.textList,
  3523. offset = _getMixToolTipData.offset;
  3524. offset.y = _touches$.y;
  3525. opts.tooltip = {
  3526. textList: textList,
  3527. offset: offset,
  3528. option: option,
  3529. index: index
  3530. };
  3531. }
  3532. }
  3533. drawCharts.call(this, opts.type, opts, this.config, this.context);
  3534. }
  3535. if (this.opts.type === 'candle') {
  3536. var index = this.getCurrentDataIndex(e);
  3537. var currentOffset = this.scrollOption.currentOffset;
  3538. var opts = assign({}, this.opts, {
  3539. _scrollDistance_: currentOffset,
  3540. animation: false
  3541. });
  3542. if (index > -1) {
  3543. var seriesData = getSeriesDataItem(this.opts.series, index);
  3544. if (seriesData.length !== 0) {
  3545. var _getToolTipData = getCandleToolTipData(this.opts.series[0].data, seriesData, this.chartData.calPoints, index,this.opts.categories, this.opts.extra.candle, option),
  3546. textList = _getToolTipData.textList,
  3547. offset = _getToolTipData.offset;
  3548. offset.y = _touches$.y;
  3549. opts.tooltip = {
  3550. textList: textList,
  3551. offset: offset,
  3552. option: option,
  3553. index: index
  3554. };
  3555. }
  3556. }
  3557. drawCharts.call(this, opts.type, opts, this.config, this.context);
  3558. }
  3559. if (this.opts.type === 'pie' || this.opts.type === 'ring' || this.opts.type === 'rose') {
  3560. var index = this.getCurrentDataIndex(e);
  3561. var currentOffset = this.scrollOption.currentOffset;
  3562. var opts = assign({}, this.opts, {
  3563. _scrollDistance_: currentOffset,
  3564. animation: false
  3565. });
  3566. if (index > -1) {
  3567. var seriesData = this.opts.series[index];
  3568. var textList = [{
  3569. text: option.format ? option.format(seriesData) : seriesData.name + ': ' + seriesData.data,
  3570. color: seriesData.color
  3571. }];
  3572. var offset = {
  3573. x: _touches$.x,
  3574. y: _touches$.y
  3575. };
  3576. opts.tooltip = {
  3577. textList: textList,
  3578. offset: offset,
  3579. option: option,
  3580. index: index
  3581. };
  3582. }
  3583. drawCharts.call(this, opts.type, opts, this.config, this.context);
  3584. }
  3585. if (this.opts.type === 'radar') {
  3586. var index = this.getCurrentDataIndex(e);
  3587. var currentOffset = this.scrollOption.currentOffset;
  3588. var opts = assign({}, this.opts, {
  3589. _scrollDistance_: currentOffset,
  3590. animation: false
  3591. });
  3592. if (index > -1) {
  3593. var seriesData = getSeriesDataItem(this.opts.series, index);
  3594. if (seriesData.length !== 0) {
  3595. var textList = seriesData.map(function(item) {
  3596. return {
  3597. text: option.format ? option.format(item) : item.name + ': ' + item.data,
  3598. color: item.color
  3599. };
  3600. });
  3601. var offset = {
  3602. x: _touches$.x,
  3603. y: _touches$.y
  3604. };
  3605. opts.tooltip = {
  3606. textList: textList,
  3607. offset: offset,
  3608. option: option,
  3609. index: index
  3610. };
  3611. }
  3612. }
  3613. drawCharts.call(this, opts.type, opts, this.config, this.context);
  3614. }
  3615. };
  3616. Charts.prototype.translate = function(distance) {
  3617. this.scrollOption = {
  3618. currentOffset: distance,
  3619. startTouchX: distance,
  3620. distance: 0,
  3621. lastMoveTime: 0
  3622. };
  3623. let opts = assign({}, this.opts, {
  3624. _scrollDistance_: distance,
  3625. animation: false
  3626. });
  3627. drawCharts.call(this, this.opts.type, opts, this.config, this.context);
  3628. };
  3629. Charts.prototype.scrollStart = function(e) {
  3630. var touches = null;
  3631. if(e.changedTouches){
  3632. touches = e.changedTouches[0];
  3633. }else{
  3634. touches = e.mp.changedTouches[0];
  3635. }
  3636. var _touches$ = getTouches(touches, this.opts, e);
  3637. if (touches && this.opts.enableScroll === true) {
  3638. this.scrollOption.startTouchX = _touches$.x;
  3639. }
  3640. };
  3641. Charts.prototype.scroll = function(e) {
  3642. if (this.scrollOption.lastMoveTime === 0) {
  3643. this.scrollOption.lastMoveTime = Date.now();
  3644. }
  3645. let Limit = this.opts.extra.touchMoveLimit || 20;
  3646. let currMoveTime = Date.now();
  3647. let duration = currMoveTime - this.scrollOption.lastMoveTime;
  3648. if (duration < Math.floor(1000 / Limit)) return;
  3649. this.scrollOption.lastMoveTime = currMoveTime;
  3650. var touches = null;
  3651. if(e.changedTouches){
  3652. touches = e.changedTouches[0];
  3653. }else{
  3654. touches = e.mp.changedTouches[0];
  3655. }
  3656. var _touches$ = getTouches(touches, this.opts, e);
  3657. if (touches && this.opts.enableScroll === true) {
  3658. var _distance;
  3659. _distance = _touches$.x - this.scrollOption.startTouchX;
  3660. var currentOffset = this.scrollOption.currentOffset;
  3661. var validDistance = calValidDistance(currentOffset + _distance, this.chartData, this.config, this.opts);
  3662. this.scrollOption.distance = _distance = validDistance - currentOffset;
  3663. var opts = assign({}, this.opts, {
  3664. _scrollDistance_: currentOffset + _distance,
  3665. animation: false
  3666. });
  3667. drawCharts.call(this, opts.type, opts, this.config, this.context);
  3668. return currentOffset + _distance;
  3669. }
  3670. };
  3671. Charts.prototype.scrollEnd = function(e) {
  3672. if (this.opts.enableScroll === true) {
  3673. var _scrollOption = this.scrollOption,
  3674. currentOffset = _scrollOption.currentOffset,
  3675. distance = _scrollOption.distance;
  3676. this.scrollOption.currentOffset = currentOffset + distance;
  3677. this.scrollOption.distance = 0;
  3678. }
  3679. };
  3680. if ( typeof module === "object" && typeof module.exports === "object" ) {
  3681. module.exports = Charts;
  3682. //export default Charts;//建议使用nodejs的module导出方式,如报错请使用export方式导出
  3683. }
u-charts.min.js
复制代码
  1. '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
复制代码
  1. <template>
  2. <!--增加audio标签支持-->
  3. <audio
  4. :id="node.attr.id"
  5. :class="node.classStr"
  6. :style="node.styleStr"
  7. :src="node.attr.src"
  8. :loop="node.attr.loop"
  9. :poster="node.attr.poster"
  10. :name="node.attr.name"
  11. :author="node.attr.author"
  12. controls></audio>
  13. </template>
  14. <script>
  15. export default {
  16. name: 'wxParseAudio',
  17. props: {
  18. node: {
  19. type: Object,
  20. default() {
  21. return {};
  22. },
  23. },
  24. },
  25. };
  26. </script>
wxParseImg.vue
复制代码
  1. <template>
  2. <image
  3. :mode="node.attr.mode"
  4. :lazy-load="node.attr.lazyLoad"
  5. :class="node.classStr"
  6. :style="newStyleStr || node.styleStr"
  7. :data-src="node.attr.src"
  8. :src="node.attr.src"
  9. @tap="wxParseImgTap"
  10. @load="wxParseImgLoad"
  11. />
  12. </template>
  13. <script>
  14. export default {
  15. name: 'wxParseImg',
  16. data() {
  17. return {
  18. newStyleStr: '',
  19. preview: true,
  20. };
  21. },
  22. props: {
  23. node: {
  24. type: Object,
  25. default() {
  26. return {};
  27. },
  28. },
  29. },
  30. methods: {
  31. wxParseImgTap(e) {
  32. if (!this.preview) return;
  33. const { src } = e.currentTarget.dataset;
  34. if (!src) return;
  35. let parent = this.$parent;
  36. while(!parent.preview || typeof parent.preview !== 'function') {// TODO 遍历获取父节点执行方法
  37. parent = parent.$parent;
  38. }
  39. parent.preview(src, e);
  40. },
  41. // 图片视觉宽高计算函数区
  42. wxParseImgLoad(e) {
  43. const { src } = e.currentTarget.dataset;
  44. if (!src) return;
  45. const { width, height } = e.mp.detail;
  46. const recal = this.wxAutoImageCal(width, height);
  47. const { imageheight, imageWidth } = recal;
  48. const { padding, mode } = this.node.attr;
  49. const { styleStr } = this.node;
  50. const imageHeightStyle = mode === 'widthFix' ? '' : `height: ${imageheight}px;`;
  51. this.newStyleStr = `${styleStr}; ${imageHeightStyle}; width: ${imageWidth}px; padding: 0 ${+padding}px;`;
  52. },
  53. // 计算视觉优先的图片宽高
  54. wxAutoImageCal(originalWidth, originalHeight) {
  55. // 获取图片的原始长宽
  56. const { padding } = this.node.attr;
  57. const windowWidth = this.node.$screen.width - (2 * padding);
  58. const results = {};
  59. if (originalWidth < 60 || originalHeight < 60) {
  60. const { src } = this.node.attr;
  61. let parent = this.$parent;
  62. while(!parent.preview || typeof parent.preview !== 'function') {
  63. parent = parent.$parent;
  64. }
  65. parent.removeImageUrl(src);
  66. this.preview = false;
  67. }
  68. // 判断按照那种方式进行缩放
  69. if (originalWidth > windowWidth) {
  70. // 在图片width大于手机屏幕width时候
  71. results.imageWidth = windowWidth;
  72. results.imageheight = windowWidth * (originalHeight / originalWidth);
  73. } else {
  74. // 否则展示原来的数据
  75. results.imageWidth = originalWidth;
  76. results.imageheight = originalHeight;
  77. }
  78. return results;
  79. },
  80. },
  81. };
  82. </script>
wxParseTemplate0.vue
复制代码
  1. <template>
  2. <view>
  3. <!--判断是否是标签节点-->
  4. <block v-if="node.node == 'element'">
  5. <block v-if="node.tag == 'button'">
  6. <button type="default" size="mini">
  7. <block v-for="(node, index) of node.nodes" :key="index">
  8. <wx-parse-template :node="node" />
  9. </block>
  10. </button>
  11. </block>
  12. <!--li类型-->
  13. <block v-else-if="node.tag == 'li'">
  14. <view :class="node.classStr" :style="node.styleStr">
  15. <block v-for="(node, index) of node.nodes" :key="index">
  16. <wx-parse-template :node="node" />
  17. </block>
  18. </view>
  19. </block>
  20. <!--video类型-->
  21. <block v-else-if="node.tag == 'video'">
  22. <wx-parse-video :node="node" />
  23. </block>
  24. <!--audio类型-->
  25. <block v-else-if="node.tag == 'audio'">
  26. <wx-parse-audio :node="node" />
  27. </block>
  28. <!--img类型-->
  29. <block v-else-if="node.tag == 'img'">
  30. <wx-parse-img :node="node" />
  31. </block>
  32. <!--a类型-->
  33. <block v-else-if="node.tag == 'a'">
  34. <view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  35. <block v-for="(node, index) of node.nodes" :key="index">
  36. <wx-parse-template :node="node" />
  37. </block>
  38. </view>
  39. </block>
  40. <!--table类型-->
  41. <block v-else-if="node.tag == 'table'">
  42. <view :class="node.classStr" class="table" :style="node.styleStr">
  43. <block v-for="(node, index) of node.nodes" :key="index">
  44. <wx-parse-template :node="node" />
  45. </block>
  46. </view>
  47. </block>
  48. <!--br类型-->
  49. <block v-else-if="node.tag == 'br'">
  50. <text>\n</text>
  51. </block>
  52. <!--其他标签-->
  53. <block v-else>
  54. <view :class="node.classStr" :style="node.styleStr">
  55. <block v-for="(node, index) of node.nodes" :key="index">
  56. <wx-parse-template :node="node" />
  57. </block>
  58. </view>
  59. </block>
  60. </block>
  61. <!--判断是否是文本节点-->
  62. <block v-else-if="node.node == 'text'">{{node.text}}</block>
  63. </view>
  64. </template>
  65. <script>
  66. import wxParseTemplate from './wxParseTemplate1';
  67. import wxParseImg from './wxParseImg';
  68. import wxParseVideo from './wxParseVideo';
  69. import wxParseAudio from './wxParseAudio';
  70. export default {
  71. name: 'wxParseTemplate0',
  72. props: {
  73. node: {},
  74. },
  75. components: {
  76. wxParseTemplate,
  77. wxParseImg,
  78. wxParseVideo,
  79. wxParseAudio,
  80. },
  81. methods: {
  82. wxParseATap(e) {
  83. const {
  84. href
  85. } = e.currentTarget.dataset;// TODO currentTarget才有dataset
  86. if (!href) return;
  87. let parent = this.$parent;
  88. while(!parent.preview || typeof parent.preview !== 'function') {// TODO 遍历获取父节点执行方法
  89. parent = parent.$parent;
  90. }
  91. parent.navigate(href, e);
  92. },
  93. },
  94. };
  95. </script>
wxParseTemplate1.vue
复制代码
  1. <template>
  2. <view :class="(node.tag == 'li' ? node.classStr : (node.node==='text'?'text':''))">
  3. <!--判断是否是标签节点-->
  4. <block v-if="node.node == 'element'">
  5. <block v-if="node.tag == 'button'">
  6. <button type="default" size="mini">
  7. <block v-for="(node, index) of node.nodes" :key="index">
  8. <wx-parse-template :node="node" />
  9. </block>
  10. </button>
  11. </block>
  12. <!--li类型-->
  13. <block v-else-if="node.tag == 'li'">
  14. <!-- <view :class="node.classStr" :style="node.styleStr"> -->
  15. <view :style="node.styleStr">
  16. <block v-for="(node, index) of node.nodes" :key="index">
  17. <wx-parse-template :node="node" />
  18. </block>
  19. </view>
  20. </block>
  21. <!--video类型-->
  22. <block v-else-if="node.tag == 'video'">
  23. <wx-parse-video :node="node" />
  24. </block>
  25. <!--audio类型-->
  26. <block v-else-if="node.tag == 'audio'">
  27. <wx-parse-audio :node="node" />
  28. </block>
  29. <!--img类型-->
  30. <block v-else-if="node.tag == 'img'">
  31. <wx-parse-img :node="node" />
  32. </block>
  33. <!--a类型-->
  34. <block v-else-if="node.tag == 'a'">
  35. <view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  36. <block v-for="(node, index) of node.nodes" :key="index">
  37. <wx-parse-template :node="node" />
  38. </block>
  39. </view>
  40. </block>
  41. <!--br类型-->
  42. <block v-else-if="node.tag == 'br'">
  43. <text>\n</text>
  44. </block>
  45. <!--其他标签-->
  46. <block v-else>
  47. <view :class="node.classStr" :style="node.styleStr">
  48. <block v-for="(node, index) of node.nodes" :key="index">
  49. <wx-parse-template :node="node" />
  50. </block>
  51. </view>
  52. </block>
  53. </block>
  54. <!--判断是否是文本节点-->
  55. <block v-else-if="node.node == 'text'">{{node.text}}</block>
  56. </view>
  57. </template>
  58. <script>
  59. import wxParseTemplate from './wxParseTemplate2';
  60. import wxParseImg from './wxParseImg';
  61. import wxParseVideo from './wxParseVideo';
  62. import wxParseAudio from './wxParseAudio';
  63. export default {
  64. name: 'wxParseTemplate1',
  65. props: {
  66. node: {},
  67. },
  68. components: {
  69. wxParseTemplate,
  70. wxParseImg,
  71. wxParseVideo,
  72. wxParseAudio,
  73. },
  74. methods: {
  75. wxParseATap(e) {
  76. const {
  77. href
  78. } = e.currentTarget.dataset;
  79. if (!href) return;
  80. let parent = this.$parent;
  81. while(!parent.preview || typeof parent.preview !== 'function') {
  82. parent = parent.$parent;
  83. }
  84. parent.navigate(href, e);
  85. },
  86. },
  87. };
  88. </script>
wxParseTemplate10.vue
复制代码
  1. <template>
  2. <view>
  3. <!--判断是否是标签节点-->
  4. <block v-if="node.node == 'element'">
  5. <block v-if="node.tag == 'button'">
  6. <button type="default" size="mini">
  7. <block v-for="(node, index) of node.nodes" :key="index">
  8. <wx-parse-template :node="node" />
  9. </block>
  10. </button>
  11. </block>
  12. <!--li类型-->
  13. <block v-else-if="node.tag == 'li'">
  14. <view :class="node.classStr" :style="node.styleStr">
  15. <block v-for="(node, index) of node.nodes" :key="index">
  16. <wx-parse-template :node="node" />
  17. </block>
  18. </view>
  19. </block>
  20. <!--video类型-->
  21. <block v-else-if="node.tag == 'video'">
  22. <wx-parse-video :node="node" />
  23. </block>
  24. <!--audio类型-->
  25. <block v-else-if="node.tag == 'audio'">
  26. <wx-parse-audio :node="node" />
  27. </block>
  28. <!--img类型-->
  29. <block v-else-if="node.tag == 'img'">
  30. <wx-parse-img :node="node" />
  31. </block>
  32. <!--a类型-->
  33. <block v-else-if="node.tag == 'a'">
  34. <view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  35. <block v-for="(node, index) of node.nodes" :key="index">
  36. <wx-parse-template :node="node" />
  37. </block>
  38. </view>
  39. </block>
  40. <!--br类型-->
  41. <block v-else-if="node.tag == 'br'">
  42. <text>\n</text>
  43. </block>
  44. <!--其他标签-->
  45. <block v-else>
  46. <view :class="node.classStr" :style="node.styleStr">
  47. <block v-for="(node, index) of node.nodes" :key="index">
  48. <wx-parse-template :node="node" />
  49. </block>
  50. </view>
  51. </block>
  52. </block>
  53. <!--判断是否是文本节点-->
  54. <block v-else-if="node.node == 'text'">{{node.text}}</block>
  55. </view>
  56. </template>
  57. <script>
  58. import wxParseTemplate from './wxParseTemplate11';
  59. import wxParseImg from './wxParseImg';
  60. import wxParseVideo from './wxParseVideo';
  61. import wxParseAudio from './wxParseAudio';
  62. export default {
  63. name: 'wxParseTemplate10',
  64. props: {
  65. node: {},
  66. },
  67. components: {
  68. wxParseTemplate,
  69. wxParseImg,
  70. wxParseVideo,
  71. wxParseAudio,
  72. },
  73. methods: {
  74. wxParseATap(e) {
  75. const {
  76. href
  77. } = e.currentTarget.dataset;
  78. if (!href) return;
  79. let parent = this.$parent;
  80. while(!parent.preview || typeof parent.preview !== 'function') {
  81. parent = parent.$parent;
  82. }
  83. parent.navigate(href, e);
  84. },
  85. },
  86. };
  87. </script>
wxParseTemplate11.vue
复制代码
  1. <template>
  2. <view>
  3. <!--判断是否是标签节点-->
  4. <block v-if="node.node == 'element'">
  5. <!--button类型-->
  6. <block v-if="node.tag == 'button'">
  7. <button type="default" size="mini">
  8. </button>
  9. </block>
  10. <!--li类型-->
  11. <block v-else-if="node.tag == 'li'">
  12. <view :class="node.classStr" :style="node.styleStr">
  13. {{node.text}}
  14. </view>
  15. </block>
  16. <!--video类型-->
  17. <block v-else-if="node.tag == 'video'">
  18. <wx-parse-video :node="node" />
  19. </block>
  20. <!--audio类型-->
  21. <block v-else-if="node.tag == 'audio'">
  22. <wx-parse-audio :node="node" />
  23. </block>
  24. <!--img类型-->
  25. <block v-else-if="node.tag == 'img'">
  26. <wx-parse-img :node="node" />
  27. </block>
  28. <!--a类型-->
  29. <block v-else-if="node.tag == 'a'">
  30. <view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  31. {{node.text}}
  32. </view>
  33. </block>
  34. <!--br类型-->
  35. <block v-else-if="node.tag == 'br'">
  36. <text>\n</text>
  37. </block>
  38. <!--其他标签-->
  39. <block v-else>
  40. <view :class="node.classStr" :style="node.styleStr">
  41. {{node.text}}
  42. </view>
  43. </block>
  44. </block>
  45. <!--判断是否是文本节点-->
  46. <block v-else-if="node.node == 'text'">{{node.text}}</block>
  47. </view>
  48. </template>
  49. <script>
  50. import wxParseImg from './wxParseImg';
  51. import wxParseVideo from './wxParseVideo';
  52. import wxParseAudio from './wxParseAudio';
  53. export default {
  54. name: 'wxParseTemplate11',
  55. props: {
  56. node: {},
  57. },
  58. components: {
  59. wxParseImg,
  60. wxParseVideo,
  61. wxParseAudio,
  62. },
  63. methods: {
  64. wxParseATap(e) {
  65. const {
  66. href
  67. } = e.currentTarget.dataset;
  68. if (!href) return;
  69. let parent = this.$parent;
  70. while(!parent.preview || typeof parent.preview !== 'function') {
  71. parent = parent.$parent;
  72. }
  73. parent.navigate(href, e);
  74. },
  75. },
  76. };
  77. </script>
wxParseTemplate2.vue
复制代码
  1. <template>
  2. <view>
  3. <!--判断是否是标签节点-->
  4. <block v-if="node.node == 'element'">
  5. <block v-if="node.tag == 'button'">
  6. <button type="default" size="mini">
  7. <block v-for="(node, index) of node.nodes" :key="index">
  8. <wx-parse-template :node="node" />
  9. </block>
  10. </button>
  11. </block>
  12. <!--li类型-->
  13. <block v-else-if="node.tag == 'li'">
  14. <view :class="node.classStr" :style="node.styleStr">
  15. <block v-for="(node, index) of node.nodes" :key="index">
  16. <wx-parse-template :node="node" />
  17. </block>
  18. </view>
  19. </block>
  20. <!--video类型-->
  21. <block v-else-if="node.tag == 'video'">
  22. <wx-parse-video :node="node" />
  23. </block>
  24. <!--audio类型-->
  25. <block v-else-if="node.tag == 'audio'">
  26. <wx-parse-audio :node="node" />
  27. </block>
  28. <!--img类型-->
  29. <block v-else-if="node.tag == 'img'">
  30. <wx-parse-img :node="node" />
  31. </block>
  32. <!--a类型-->
  33. <block v-else-if="node.tag == 'a'">
  34. <view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  35. <block v-for="(node, index) of node.nodes" :key="index">
  36. <wx-parse-template :node="node" />
  37. </block>
  38. </view>
  39. </block>
  40. <!--br类型-->
  41. <block v-else-if="node.tag == 'br'">
  42. <text>\n</text>
  43. </block>
  44. <!--其他标签-->
  45. <block v-else>
  46. <view :class="node.classStr" :style="node.styleStr">
  47. <block v-for="(node, index) of node.nodes" :key="index">
  48. <wx-parse-template :node="node" />
  49. </block>
  50. </view>
  51. </block>
  52. </block>
  53. <!--判断是否是文本节点-->
  54. <block v-else-if="node.node == 'text'">{{node.text}}</block>
  55. </view>
  56. </template>
  57. <script>
  58. import wxParseTemplate from './wxParseTemplate3';
  59. import wxParseImg from './wxParseImg';
  60. import wxParseVideo from './wxParseVideo';
  61. import wxParseAudio from './wxParseAudio';
  62. export default {
  63. name: 'wxParseTemplate2',
  64. props: {
  65. node: {},
  66. },
  67. components: {
  68. wxParseTemplate,
  69. wxParseImg,
  70. wxParseVideo,
  71. wxParseAudio,
  72. },
  73. methods: {
  74. wxParseATap(e) {
  75. const {
  76. href
  77. } = e.currentTarget.dataset;
  78. if (!href) return;
  79. let parent = this.$parent;
  80. while(!parent.preview || typeof parent.preview !== 'function') {
  81. parent = parent.$parent;
  82. }
  83. parent.navigate(href, e);
  84. },
  85. },
  86. };
  87. </script>
wxParseTemplate3.vue
复制代码
  1. <template>
  2. <view>
  3. <!--判断是否是标签节点-->
  4. <block v-if="node.node == 'element'">
  5. <block v-if="node.tag == 'button'">
  6. <button type="default" size="mini">
  7. <block v-for="(node, index) of node.nodes" :key="index">
  8. <wx-parse-template :node="node" />
  9. </block>
  10. </button>
  11. </block>
  12. <!--li类型-->
  13. <block v-else-if="node.tag == 'li'">
  14. <view :class="node.classStr" :style="node.styleStr">
  15. <block v-for="(node, index) of node.nodes" :key="index">
  16. <wx-parse-template :node="node" />
  17. </block>
  18. </view>
  19. </block>
  20. <!--video类型-->
  21. <block v-else-if="node.tag == 'video'">
  22. <wx-parse-video :node="node" />
  23. </block>
  24. <!--audio类型-->
  25. <block v-else-if="node.tag == 'audio'">
  26. <wx-parse-audio :node="node" />
  27. </block>
  28. <!--img类型-->
  29. <block v-else-if="node.tag == 'img'">
  30. <wx-parse-img :node="node" />
  31. </block>
  32. <!--a类型-->
  33. <block v-else-if="node.tag == 'a'">
  34. <view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  35. <block v-for="(node, index) of node.nodes" :key="index">
  36. <wx-parse-template :node="node" />
  37. </block>
  38. </view>
  39. </block>
  40. <!--br类型-->
  41. <block v-else-if="node.tag == 'br'">
  42. <text>\n</text>
  43. </block>
  44. <!--其他标签-->
  45. <block v-else>
  46. <view :class="node.classStr" :style="node.styleStr">
  47. <block v-for="(node, index) of node.nodes" :key="index">
  48. <wx-parse-template :node="node" />
  49. </block>
  50. </view>
  51. </block>
  52. </block>
  53. <!--判断是否是文本节点-->
  54. <block v-else-if="node.node == 'text'">{{node.text}}</block>
  55. </view>
  56. </template>
  57. <script>
  58. import wxParseTemplate from './wxParseTemplate4';
  59. import wxParseImg from './wxParseImg';
  60. import wxParseVideo from './wxParseVideo';
  61. import wxParseAudio from './wxParseAudio';
  62. export default {
  63. name: 'wxParseTemplate3',
  64. props: {
  65. node: {},
  66. },
  67. components: {
  68. wxParseTemplate,
  69. wxParseImg,
  70. wxParseVideo,
  71. wxParseAudio,
  72. },
  73. methods: {
  74. wxParseATap(e) {
  75. const {
  76. href
  77. } = e.currentTarget.dataset;
  78. if (!href) return;
  79. let parent = this.$parent;
  80. while(!parent.preview || typeof parent.preview !== 'function') {
  81. parent = parent.$parent;
  82. }
  83. parent.navigate(href, e);
  84. },
  85. },
  86. };
  87. </script>
wxParseTemplate4.vue
复制代码
  1. <template>
  2. <view>
  3. <!--判断是否是标签节点-->
  4. <block v-if="node.node == 'element'">
  5. <block v-if="node.tag == 'button'">
  6. <button type="default" size="mini">
  7. <block v-for="(node, index) of node.nodes" :key="index">
  8. <wx-parse-template :node="node" />
  9. </block>
  10. </button>
  11. </block>
  12. <!--li类型-->
  13. <block v-else-if="node.tag == 'li'">
  14. <view :class="node.classStr" :style="node.styleStr">
  15. <block v-for="(node, index) of node.nodes" :key="index">
  16. <wx-parse-template :node="node" />
  17. </block>
  18. </view>
  19. </block>
  20. <!--video类型-->
  21. <block v-else-if="node.tag == 'video'">
  22. <wx-parse-video :node="node" />
  23. </block>
  24. <!--audio类型-->
  25. <block v-else-if="node.tag == 'audio'">
  26. <wx-parse-audio :node="node" />
  27. </block>
  28. <!--img类型-->
  29. <block v-else-if="node.tag == 'img'">
  30. <wx-parse-img :node="node" />
  31. </block>
  32. <!--a类型-->
  33. <block v-else-if="node.tag == 'a'">
  34. <view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  35. <block v-for="(node, index) of node.nodes" :key="index">
  36. <wx-parse-template :node="node" />
  37. </block>
  38. </view>
  39. </block>
  40. <!--br类型-->
  41. <block v-else-if="node.tag == 'br'">
  42. <text>\n</text>
  43. </block>
  44. <!--其他标签-->
  45. <block v-else>
  46. <view :class="node.classStr" :style="node.styleStr">
  47. <block v-for="(node, index) of node.nodes" :key="index">
  48. <wx-parse-template :node="node" />
  49. </block>
  50. </view>
  51. </block>
  52. </block>
  53. <!--判断是否是文本节点-->
  54. <block v-else-if="node.node == 'text'">{{node.text}}</block>
  55. </view>
  56. </template>
  57. <script>
  58. import wxParseTemplate from './wxParseTemplate5';
  59. import wxParseImg from './wxParseImg';
  60. import wxParseVideo from './wxParseVideo';
  61. import wxParseAudio from './wxParseAudio';
  62. export default {
  63. name: 'wxParseTemplate4',
  64. props: {
  65. node: {},
  66. },
  67. components: {
  68. wxParseTemplate,
  69. wxParseImg,
  70. wxParseVideo,
  71. wxParseAudio,
  72. },
  73. methods: {
  74. wxParseATap(e) {
  75. const {
  76. href
  77. } = e.currentTarget.dataset;
  78. if (!href) return;
  79. let parent = this.$parent;
  80. while(!parent.preview || typeof parent.preview !== 'function') {
  81. parent = parent.$parent;
  82. }
  83. parent.navigate(href, e);
  84. },
  85. },
  86. };
  87. </script>
wxParseTemplate5.vue
复制代码
  1. <template>
  2. <view>
  3. <!--判断是否是标签节点-->
  4. <block v-if="node.node == 'element'">
  5. <block v-if="node.tag == 'button'">
  6. <button type="default" size="mini">
  7. <block v-for="(node, index) of node.nodes" :key="index">
  8. <wx-parse-template :node="node" />
  9. </block>
  10. </button>
  11. </block>
  12. <!--li类型-->
  13. <block v-else-if="node.tag == 'li'">
  14. <view :class="node.classStr" :style="node.styleStr">
  15. <block v-for="(node, index) of node.nodes" :key="index">
  16. <wx-parse-template :node="node" />
  17. </block>
  18. </view>
  19. </block>
  20. <!--video类型-->
  21. <block v-else-if="node.tag == 'video'">
  22. <wx-parse-video :node="node" />
  23. </block>
  24. <!--audio类型-->
  25. <block v-else-if="node.tag == 'audio'">
  26. <wx-parse-audio :node="node" />
  27. </block>
  28. <!--img类型-->
  29. <block v-else-if="node.tag == 'img'">
  30. <wx-parse-img :node="node" />
  31. </block>
  32. <!--a类型-->
  33. <block v-else-if="node.tag == 'a'">
  34. <view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  35. <block v-for="(node, index) of node.nodes" :key="index">
  36. <wx-parse-template :node="node" />
  37. </block>
  38. </view>
  39. </block>
  40. <!--br类型-->
  41. <block v-else-if="node.tag == 'br'">
  42. <text>\n</text>
  43. </block>
  44. <!--其他标签-->
  45. <block v-else>
  46. <view :class="node.classStr" :style="node.styleStr">
  47. <block v-for="(node, index) of node.nodes" :key="index">
  48. <wx-parse-template :node="node" />
  49. </block>
  50. </view>
  51. </block>
  52. </block>
  53. <!--判断是否是文本节点-->
  54. <block v-else-if="node.node == 'text'">{{node.text}}</block>
  55. </view>
  56. </template>
  57. <script>
  58. import wxParseTemplate from './wxParseTemplate6';
  59. import wxParseImg from './wxParseImg';
  60. import wxParseVideo from './wxParseVideo';
  61. import wxParseAudio from './wxParseAudio';
  62. export default {
  63. name: 'wxParseTemplate5',
  64. props: {
  65. node: {},
  66. },
  67. components: {
  68. wxParseTemplate,
  69. wxParseImg,
  70. wxParseVideo,
  71. wxParseAudio,
  72. },
  73. methods: {
  74. wxParseATap(e) {
  75. const {
  76. href
  77. } = e.currentTarget.dataset;
  78. if (!href) return;
  79. let parent = this.$parent;
  80. while(!parent.preview || typeof parent.preview !== 'function') {
  81. parent = parent.$parent;
  82. }
  83. parent.navigate(href, e);
  84. },
  85. },
  86. };
  87. </script>
wxParseTemplate6.vue
复制代码
  1. <template>
  2. <view>
  3. <!--判断是否是标签节点-->
  4. <block v-if="node.node == 'element'">
  5. <block v-if="node.tag == 'button'">
  6. <button type="default" size="mini">
  7. <block v-for="(node, index) of node.nodes" :key="index">
  8. <wx-parse-template :node="node" />
  9. </block>
  10. </button>
  11. </block>
  12. <!--li类型-->
  13. <block v-else-if="node.tag == 'li'">
  14. <view :class="node.classStr" :style="node.styleStr">
  15. <block v-for="(node, index) of node.nodes" :key="index">
  16. <wx-parse-template :node="node" />
  17. </block>
  18. </view>
  19. </block>
  20. <!--video类型-->
  21. <block v-else-if="node.tag == 'video'">
  22. <wx-parse-video :node="node" />
  23. </block>
  24. <!--audio类型-->
  25. <block v-else-if="node.tag == 'audio'">
  26. <wx-parse-audio :node="node" />
  27. </block>
  28. <!--img类型-->
  29. <block v-else-if="node.tag == 'img'">
  30. <wx-parse-img :node="node" />
  31. </block>
  32. <!--a类型-->
  33. <block v-else-if="node.tag == 'a'">
  34. <view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  35. <block v-for="(node, index) of node.nodes" :key="index">
  36. <wx-parse-template :node="node" />
  37. </block>
  38. </view>
  39. </block>
  40. <!--br类型-->
  41. <block v-else-if="node.tag == 'br'">
  42. <text>\n</text>
  43. </block>
  44. <!--其他标签-->
  45. <block v-else>
  46. <view :class="node.classStr" :style="node.styleStr">
  47. <block v-for="(node, index) of node.nodes" :key="index">
  48. <wx-parse-template :node="node" />
  49. </block>
  50. </view>
  51. </block>
  52. </block>
  53. <!--判断是否是文本节点-->
  54. <block v-else-if="node.node == 'text'">{{node.text}}</block>
  55. </view>
  56. </template>
  57. <script>
  58. import wxParseTemplate from './wxParseTemplate7';
  59. import wxParseImg from './wxParseImg';
  60. import wxParseVideo from './wxParseVideo';
  61. import wxParseAudio from './wxParseAudio';
  62. export default {
  63. name: 'wxParseTemplate6',
  64. props: {
  65. node: {},
  66. },
  67. components: {
  68. wxParseTemplate,
  69. wxParseImg,
  70. wxParseVideo,
  71. wxParseAudio,
  72. },
  73. methods: {
  74. wxParseATap(e) {
  75. const {
  76. href
  77. } = e.currentTarget.dataset;
  78. if (!href) return;
  79. let parent = this.$parent;
  80. while(!parent.preview || typeof parent.preview !== 'function') {
  81. parent = parent.$parent;
  82. }
  83. parent.navigate(href, e);
  84. },
  85. },
  86. };
  87. </script>
wxParseTemplate7.vue
复制代码
  1. <template>
  2. <view>
  3. <!--判断是否是标签节点-->
  4. <block v-if="node.node == 'element'">
  5. <block v-if="node.tag == 'button'">
  6. <button type="default" size="mini">
  7. <block v-for="(node, index) of node.nodes" :key="index">
  8. <wx-parse-template :node="node" />
  9. </block>
  10. </button>
  11. </block>
  12. <!--li类型-->
  13. <block v-else-if="node.tag == 'li'">
  14. <view :class="node.classStr" :style="node.styleStr">
  15. <block v-for="(node, index) of node.nodes" :key="index">
  16. <wx-parse-template :node="node" />
  17. </block>
  18. </view>
  19. </block>
  20. <!--video类型-->
  21. <block v-else-if="node.tag == 'video'">
  22. <wx-parse-video :node="node" />
  23. </block>
  24. <!--audio类型-->
  25. <block v-else-if="node.tag == 'audio'">
  26. <wx-parse-audio :node="node" />
  27. </block>
  28. <!--img类型-->
  29. <block v-else-if="node.tag == 'img'">
  30. <wx-parse-img :node="node" />
  31. </block>
  32. <!--a类型-->
  33. <block v-else-if="node.tag == 'a'">
  34. <view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  35. <block v-for="(node, index) of node.nodes" :key="index">
  36. <wx-parse-template :node="node" />
  37. </block>
  38. </view>
  39. </block>
  40. <!--br类型-->
  41. <block v-else-if="node.tag == 'br'">
  42. <text>\n</text>
  43. </block>
  44. <!--其他标签-->
  45. <block v-else>
  46. <view :class="node.classStr" :style="node.styleStr">
  47. <block v-for="(node, index) of node.nodes" :key="index">
  48. <wx-parse-template :node="node" />
  49. </block>
  50. </view>
  51. </block>
  52. </block>
  53. <!--判断是否是文本节点-->
  54. <block v-else-if="node.node == 'text'">{{node.text}}</block>
  55. </view>
  56. </template>
  57. <script>
  58. import wxParseTemplate from './wxParseTemplate8';
  59. import wxParseImg from './wxParseImg';
  60. import wxParseVideo from './wxParseVideo';
  61. import wxParseAudio from './wxParseAudio';
  62. export default {
  63. name: 'wxParseTemplate7',
  64. props: {
  65. node: {},
  66. },
  67. components: {
  68. wxParseTemplate,
  69. wxParseImg,
  70. wxParseVideo,
  71. wxParseAudio,
  72. },
  73. methods: {
  74. wxParseATap(e) {
  75. const {
  76. href
  77. } = e.currentTarget.dataset;
  78. if (!href) return;
  79. let parent = this.$parent;
  80. while(!parent.preview || typeof parent.preview !== 'function') {
  81. parent = parent.$parent;
  82. }
  83. parent.navigate(href, e);
  84. },
  85. },
  86. };
  87. </script>
wxParseTemplate8.vue
复制代码
  1. <template>
  2. <view>
  3. <!--判断是否是标签节点-->
  4. <block v-if="node.node == 'element'">
  5. <block v-if="node.tag == 'button'">
  6. <button type="default" size="mini">
  7. <block v-for="(node, index) of node.nodes" :key="index">
  8. <wx-parse-template :node="node" />
  9. </block>
  10. </button>
  11. </block>
  12. <!--li类型-->
  13. <block v-else-if="node.tag == 'li'">
  14. <view :class="node.classStr" :style="node.styleStr">
  15. <block v-for="(node, index) of node.nodes" :key="index">
  16. <wx-parse-template :node="node" />
  17. </block>
  18. </view>
  19. </block>
  20. <!--video类型-->
  21. <block v-else-if="node.tag == 'video'">
  22. <wx-parse-video :node="node" />
  23. </block>
  24. <!--audio类型-->
  25. <block v-else-if="node.tag == 'audio'">
  26. <wx-parse-audio :node="node" />
  27. </block>
  28. <!--img类型-->
  29. <block v-else-if="node.tag == 'img'">
  30. <wx-parse-img :node="node" />
  31. </block>
  32. <!--a类型-->
  33. <block v-else-if="node.tag == 'a'">
  34. <view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  35. <block v-for="(node, index) of node.nodes" :key="index">
  36. <wx-parse-template :node="node" />
  37. </block>
  38. </view>
  39. </block>
  40. <!--br类型-->
  41. <block v-else-if="node.tag == 'br'">
  42. <text>\n</text>
  43. </block>
  44. <!--其他标签-->
  45. <block v-else>
  46. <view :class="node.classStr" :style="node.styleStr">
  47. <block v-for="(node, index) of node.nodes" :key="index">
  48. <wx-parse-template :node="node" />
  49. </block>
  50. </view>
  51. </block>
  52. </block>
  53. <!--判断是否是文本节点-->
  54. <block v-else-if="node.node == 'text'">{{node.text}}</block>
  55. </view>
  56. </template>
  57. <script>
  58. import wxParseTemplate from './wxParseTemplate9';
  59. import wxParseImg from './wxParseImg';
  60. import wxParseVideo from './wxParseVideo';
  61. import wxParseAudio from './wxParseAudio';
  62. export default {
  63. name: 'wxParseTemplate8',
  64. props: {
  65. node: {},
  66. },
  67. components: {
  68. wxParseTemplate,
  69. wxParseImg,
  70. wxParseVideo,
  71. wxParseAudio,
  72. },
  73. methods: {
  74. wxParseATap(e) {
  75. const {
  76. href
  77. } = e.currentTarget.dataset;
  78. if (!href) return;
  79. let parent = this.$parent;
  80. while(!parent.preview || typeof parent.preview !== 'function') {
  81. parent = parent.$parent;
  82. }
  83. parent.navigate(href, e);
  84. },
  85. },
  86. };
  87. </script>
wxParseTemplate9.vue
复制代码
  1. <template>
  2. <view>
  3. <!--判断是否是标签节点-->
  4. <block v-if="node.node == 'element'">
  5. <block v-if="node.tag == 'button'">
  6. <button type="default" size="mini">
  7. <block v-for="(node, index) of node.nodes" :key="index">
  8. <wx-parse-template :node="node" />
  9. </block>
  10. </button>
  11. </block>
  12. <!--li类型-->
  13. <block v-else-if="node.tag == 'li'">
  14. <view :class="node.classStr" :style="node.styleStr">
  15. <block v-for="(node, index) of node.nodes" :key="index">
  16. <wx-parse-template :node="node" />
  17. </block>
  18. </view>
  19. </block>
  20. <!--video类型-->
  21. <block v-else-if="node.tag == 'video'">
  22. <wx-parse-video :node="node" />
  23. </block>
  24. <!--audio类型-->
  25. <block v-else-if="node.tag == 'audio'">
  26. <wx-parse-audio :node="node" />
  27. </block>
  28. <!--img类型-->
  29. <block v-else-if="node.tag == 'img'">
  30. <wx-parse-img :node="node" />
  31. </block>
  32. <!--a类型-->
  33. <block v-else-if="node.tag == 'a'">
  34. <view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
  35. <block v-for="(node, index) of node.nodes" :key="index">
  36. <wx-parse-template :node="node" />
  37. </block>
  38. </view>
  39. </block>
  40. <!--br类型-->
  41. <block v-else-if="node.tag == 'br'">
  42. <text>\n</text>
  43. </block>
  44. <!--其他标签-->
  45. <block v-else>
  46. <view :class="node.classStr" :style="node.styleStr">
  47. <block v-for="(node, index) of node.nodes" :key="index">
  48. <wx-parse-template :node="node" />
  49. </block>
  50. </view>
  51. </block>
  52. </block>
  53. <!--判断是否是文本节点-->
  54. <block v-else-if="node.node == 'text'">{{node.text}}</block>
  55. </view>
  56. </template>
  57. <script>
  58. import wxParseTemplate from './wxParseTemplate10';
  59. import wxParseImg from './wxParseImg';
  60. import wxParseVideo from './wxParseVideo';
  61. import wxParseAudio from './wxParseAudio';
  62. export default {
  63. name: 'wxParseTemplate9',
  64. props: {
  65. node: {},
  66. },
  67. components: {
  68. wxParseTemplate,
  69. wxParseImg,
  70. wxParseVideo,
  71. wxParseAudio,
  72. },
  73. methods: {
  74. wxParseATap(e) {
  75. const {
  76. href
  77. } = e.currentTarget.dataset;
  78. if (!href) return;
  79. let parent = this.$parent;
  80. while(!parent.preview || typeof parent.preview !== 'function') {
  81. parent = parent.$parent;
  82. }
  83. parent.navigate(href, e);
  84. },
  85. },
  86. };
  87. </script>
wxParseVideo.vue
复制代码
  1. <template>
  2. <!--增加video标签支持,并循环添加-->
  3. <view :class="node.classStr" :style="node.styleStr">
  4. <video :class="node.classStr" class="video-video" :src="node.attr.src"></video>
  5. </view>
  6. </template>
  7. <script>
  8. export default {
  9. name: 'wxParseVideo',
  10. props: {
  11. node: {},
  12. },
  13. };
  14. </script>
libs
html2json.js
复制代码
  1. /**
  2. * html2Json 改造来自: https://github.com/Jxck/html2json
  3. *
  4. *
  5. * author: Di (微信小程序开发工程师)
  6. * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
  7. * 垂直微信小程序开发交流社区
  8. *
  9. * github地址: https://github.com/icindy/wxParse
  10. *
  11. * for: 微信小程序富文本解析
  12. * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
  13. */
  14. import wxDiscode from './wxDiscode';
  15. import HTMLParser from './htmlparser';
  16. function makeMap(str) {
  17. const obj = {};
  18. const items = str.split(',');
  19. for (let i = 0; i < items.length; i += 1) obj[items[i]] = true;
  20. return obj;
  21. }
  22. // Block Elements - HTML 5
  23. 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');
  24. // Inline Elements - HTML 5
  25. 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');
  26. // Elements that you can, intentionally, leave open
  27. // (and which close themselves)
  28. const closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr');
  29. function removeDOCTYPE(html) {
  30. const isDocument = /<body.*>([^]*)<\/body>/.test(html);
  31. return isDocument ? RegExp.$1 : html;
  32. }
  33. function trimHtml(html) {
  34. return html
  35. .replace(/<!--.*?-->/gi, '')
  36. .replace(/\/\*.*?\*\//gi, '')
  37. .replace(/[ ]+</gi, '<')
  38. .replace(/<script[^]*<\/script>/gi, '')
  39. .replace(/<style[^]*<\/style>/gi, '');
  40. }
  41. function getScreenInfo() {
  42. const screen = {};
  43. wx.getSystemInfo({
  44. success: (res) => {
  45. screen.width = res.windowWidth;
  46. screen.height = res.windowHeight;
  47. },
  48. });
  49. return screen;
  50. }
  51. function html2json(html, customHandler, imageProp, host) {
  52. // 处理字符串
  53. html = removeDOCTYPE(html);
  54. html = trimHtml(html);
  55. html = wxDiscode.strDiscode(html);
  56. // 生成node节点
  57. const bufArray = [];
  58. const results = {
  59. nodes: [],
  60. imageUrls: [],
  61. };
  62. const screen = getScreenInfo();
  63. function Node(tag) {
  64. this.node = 'element';
  65. this.tag = tag;
  66. this.$screen = screen;
  67. }
  68. HTMLParser(html, {
  69. start(tag, attrs, unary) {
  70. // node for this element
  71. const node = new Node(tag);
  72. if (bufArray.length !== 0) {
  73. const parent = bufArray[0];
  74. if (parent.nodes === undefined) {
  75. parent.nodes = [];
  76. }
  77. }
  78. if (block[tag]) {
  79. node.tagType = 'block';
  80. } else if (inline[tag]) {
  81. node.tagType = 'inline';
  82. } else if (closeSelf[tag]) {
  83. node.tagType = 'closeSelf';
  84. }
  85. node.attr = attrs.reduce((pre, attr) => {
  86. const { name } = attr;
  87. let { value } = attr;
  88. if (name === 'class') {
  89. node.classStr = value;
  90. }
  91. // has multi attibutes
  92. // make it array of attribute
  93. if (name === 'style') {
  94. node.styleStr = value;
  95. }
  96. if (value.match(/ /)) {
  97. value = value.split(' ');
  98. }
  99. // if attr already exists
  100. // merge it
  101. if (pre[name]) {
  102. if (Array.isArray(pre[name])) {
  103. // already array, push to last
  104. pre[name].push(value);
  105. } else {
  106. // single value, make it array
  107. pre[name] = [pre[name], value];
  108. }
  109. } else {
  110. // not exist, put it
  111. pre[name] = value;
  112. }
  113. return pre;
  114. }, {});
  115. // 优化样式相关属性
  116. if (node.classStr) {
  117. node.classStr += ` ${node.tag}`;
  118. } else {
  119. node.classStr = node.tag;
  120. }
  121. if (node.tagType === 'inline') {
  122. node.classStr += ' inline';
  123. }
  124. // 对img添加额外数据
  125. if (node.tag === 'img') {
  126. let imgUrl = node.attr.src;
  127. imgUrl = wxDiscode.urlToHttpUrl(imgUrl, imageProp.domain);
  128. Object.assign(node.attr, imageProp, {
  129. src: imgUrl || '',
  130. });
  131. if (imgUrl) {
  132. results.imageUrls.push(imgUrl);
  133. }
  134. }
  135. // 处理a标签属性
  136. if (node.tag === 'a') {
  137. node.attr.href = node.attr.href || '';
  138. }
  139. // 处理font标签样式属性
  140. if (node.tag === 'font') {
  141. const fontSize = [
  142. 'x-small',
  143. 'small',
  144. 'medium',
  145. 'large',
  146. 'x-large',
  147. 'xx-large',
  148. '-webkit-xxx-large',
  149. ];
  150. const styleAttrs = {
  151. color: 'color',
  152. face: 'font-family',
  153. size: 'font-size',
  154. };
  155. if (!node.styleStr) node.styleStr = '';
  156. Object.keys(styleAttrs).forEach((key) => {
  157. if (node.attr[key]) {
  158. const value = key === 'size' ? fontSize[node.attr[key] - 1] : node.attr[key];
  159. node.styleStr += `${styleAttrs[key]}: ${value};`;
  160. }
  161. });
  162. }
  163. // 临时记录source资源
  164. if (node.tag === 'source') {
  165. results.source = node.attr.src;
  166. }
  167. if (customHandler.start) {
  168. customHandler.start(node, results);
  169. }
  170. if (unary) {
  171. // if this tag doesn't have end tag
  172. // like <img src="hoge.png"/>
  173. // add to parents
  174. const parent = bufArray[0] || results;
  175. if (parent.nodes === undefined) {
  176. parent.nodes = [];
  177. }
  178. parent.nodes.push(node);
  179. } else {
  180. bufArray.unshift(node);
  181. }
  182. },
  183. end(tag) {
  184. // merge into parent tag
  185. const node = bufArray.shift();
  186. if (node.tag !== tag) {
  187. // console.error('invalid state: mismatch end tag');
  188. }
  189. // 当有缓存source资源时于于video补上src资源
  190. if (node.tag === 'video' && results.source) {
  191. node.attr.src = results.source;
  192. delete results.source;
  193. }
  194. if (customHandler.end) {
  195. customHandler.end(node, results);
  196. }
  197. if (bufArray.length === 0) {
  198. results.nodes.push(node);
  199. } else {
  200. const parent = bufArray[0];
  201. if (!parent.nodes) {
  202. parent.nodes = [];
  203. }
  204. parent.nodes.push(node);
  205. }
  206. },
  207. chars(text) {
  208. if (!text.trim()) return;
  209. const node = {
  210. node: 'text',
  211. text,
  212. };
  213. if (customHandler.chars) {
  214. customHandler.chars(node, results);
  215. }
  216. if (bufArray.length === 0) {
  217. results.nodes.push(node);
  218. } else {
  219. const parent = bufArray[0];
  220. if (parent.nodes === undefined) {
  221. parent.nodes = [];
  222. }
  223. parent.nodes.push(node);
  224. }
  225. },
  226. });
  227. return results;
  228. }
  229. export default html2json;
htmlparser.js
复制代码
  1. /**
  2. *
  3. * htmlParser改造自: https://github.com/blowsie/Pure-JavaScript-HTML5-Parser
  4. *
  5. * author: Di (微信小程序开发工程师)
  6. * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
  7. * 垂直微信小程序开发交流社区
  8. *
  9. * github地址: https://github.com/icindy/wxParse
  10. *
  11. * for: 微信小程序富文本解析
  12. * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
  13. */
  14. // Regular Expressions for parsing tags and attributes
  15. const startTag = /^<([-A-Za-z0-9_]+)((?:\s+[a-zA-Z0-9_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/;
  16. const endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/;
  17. const attr = /([a-zA-Z0-9_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g;
  18. function makeMap(str) {
  19. const obj = {};
  20. const items = str.split(',');
  21. for (let i = 0; i < items.length; i += 1) obj[items[i]] = true;
  22. return obj;
  23. }
  24. // Empty Elements - HTML 5
  25. const empty = makeMap('area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr');
  26. // Block Elements - HTML 5
  27. 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');
  28. // Inline Elements - HTML 5
  29. 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');
  30. // Elements that you can, intentionally, leave open
  31. // (and which close themselves)
  32. const closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr');
  33. // Attributes that have their values filled in disabled="disabled"
  34. const fillAttrs = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected');
  35. function HTMLParser(html, handler) {
  36. let index;
  37. let chars;
  38. let match;
  39. let last = html;
  40. const stack = [];
  41. stack.last = () => stack[stack.length - 1];
  42. function parseEndTag(tag, tagName) {
  43. // If no tag name is provided, clean shop
  44. let pos;
  45. if (!tagName) {
  46. pos = 0;
  47. } else {
  48. // Find the closest opened tag of the same type
  49. tagName = tagName.toLowerCase();
  50. for (pos = stack.length - 1; pos >= 0; pos -= 1) {
  51. if (stack[pos] === tagName) break;
  52. }
  53. }
  54. if (pos >= 0) {
  55. // Close all the open elements, up the stack
  56. for (let i = stack.length - 1; i >= pos; i -= 1) {
  57. if (handler.end) handler.end(stack[i]);
  58. }
  59. // Remove the open elements from the stack
  60. stack.length = pos;
  61. }
  62. }
  63. function parseStartTag(tag, tagName, rest, unary) {
  64. tagName = tagName.toLowerCase();
  65. if (block[tagName]) {
  66. while (stack.last() && inline[stack.last()]) {
  67. parseEndTag('', stack.last());
  68. }
  69. }
  70. if (closeSelf[tagName] && stack.last() === tagName) {
  71. parseEndTag('', tagName);
  72. }
  73. unary = empty[tagName] || !!unary;
  74. if (!unary) stack.push(tagName);
  75. if (handler.start) {
  76. const attrs = [];
  77. rest.replace(attr, function genAttr(matches, name) {
  78. const value = arguments[2] || arguments[3] || arguments[4] || (fillAttrs[name] ? name : '');
  79. attrs.push({
  80. name,
  81. value,
  82. escaped: value.replace(/(^|[^\\])"/g, '$1\\"'), // "
  83. });
  84. });
  85. if (handler.start) {
  86. handler.start(tagName, attrs, unary);
  87. }
  88. }
  89. }
  90. while (html) {
  91. chars = true;
  92. if (html.indexOf('</') === 0) {
  93. match = html.match(endTag);
  94. if (match) {
  95. html = html.substring(match[0].length);
  96. match[0].replace(endTag, parseEndTag);
  97. chars = false;
  98. }
  99. // start tag
  100. } else if (html.indexOf('<') === 0) {
  101. match = html.match(startTag);
  102. if (match) {
  103. html = html.substring(match[0].length);
  104. match[0].replace(startTag, parseStartTag);
  105. chars = false;
  106. }
  107. }
  108. if (chars) {
  109. index = html.indexOf('<');
  110. let text = '';
  111. while (index === 0) {
  112. text += '<';
  113. html = html.substring(1);
  114. index = html.indexOf('<');
  115. }
  116. text += index < 0 ? html : html.substring(0, index);
  117. html = index < 0 ? '' : html.substring(index);
  118. if (handler.chars) handler.chars(text);
  119. }
  120. if (html === last) throw new Error(`Parse Error: ${html}`);
  121. last = html;
  122. }
  123. // Clean up any remaining tags
  124. parseEndTag();
  125. }
  126. export default HTMLParser;
wxDiscode.js
复制代码
  1. // HTML 支持的数学符号
  2. function strNumDiscode(str) {
  3. str = str.replace(/&forall;/g, '∀');
  4. str = str.replace(/&part;/g, '∂');
  5. str = str.replace(/&exist;/g, '∃');
  6. str = str.replace(/&empty;/g, '∅');
  7. str = str.replace(/&nabla;/g, '∇');
  8. str = str.replace(/&isin;/g, '∈');
  9. str = str.replace(/&notin;/g, '∉');
  10. str = str.replace(/&ni;/g, '∋');
  11. str = str.replace(/&prod;/g, '∏');
  12. str = str.replace(/&sum;/g, '∑');
  13. str = str.replace(/&minus;/g, '−');
  14. str = str.replace(/&lowast;/g, '∗');
  15. str = str.replace(/&radic;/g, '√');
  16. str = str.replace(/&prop;/g, '∝');
  17. str = str.replace(/&infin;/g, '∞');
  18. str = str.replace(/&ang;/g, '∠');
  19. str = str.replace(/&and;/g, '∧');
  20. str = str.replace(/&or;/g, '∨');
  21. str = str.replace(/&cap;/g, '∩');
  22. str = str.replace(/&cup;/g, '∪');
  23. str = str.replace(/&int;/g, '∫');
  24. str = str.replace(/&there4;/g, '∴');
  25. str = str.replace(/&sim;/g, '∼');
  26. str = str.replace(/&cong;/g, '≅');
  27. str = str.replace(/&asymp;/g, '≈');
  28. str = str.replace(/&ne;/g, '≠');
  29. str = str.replace(/&le;/g, '≤');
  30. str = str.replace(/&ge;/g, '≥');
  31. str = str.replace(/&sub;/g, '⊂');
  32. str = str.replace(/&sup;/g, '⊃');
  33. str = str.replace(/&nsub;/g, '⊄');
  34. str = str.replace(/&sube;/g, '⊆');
  35. str = str.replace(/&supe;/g, '⊇');
  36. str = str.replace(/&oplus;/g, '⊕');
  37. str = str.replace(/&otimes;/g, '⊗');
  38. str = str.replace(/&perp;/g, '⊥');
  39. str = str.replace(/&sdot;/g, '⋅');
  40. return str;
  41. }
  42. // HTML 支持的希腊字母
  43. function strGreeceDiscode(str) {
  44. str = str.replace(/&Alpha;/g, 'Α');
  45. str = str.replace(/&Beta;/g, 'Β');
  46. str = str.replace(/&Gamma;/g, 'Γ');
  47. str = str.replace(/&Delta;/g, 'Δ');
  48. str = str.replace(/&Epsilon;/g, 'Ε');
  49. str = str.replace(/&Zeta;/g, 'Ζ');
  50. str = str.replace(/&Eta;/g, 'Η');
  51. str = str.replace(/&Theta;/g, 'Θ');
  52. str = str.replace(/&Iota;/g, 'Ι');
  53. str = str.replace(/&Kappa;/g, 'Κ');
  54. str = str.replace(/&Lambda;/g, 'Λ');
  55. str = str.replace(/&Mu;/g, 'Μ');
  56. str = str.replace(/&Nu;/g, 'Ν');
  57. str = str.replace(/&Xi;/g, 'Ν');
  58. str = str.replace(/&Omicron;/g, 'Ο');
  59. str = str.replace(/&Pi;/g, 'Π');
  60. str = str.replace(/&Rho;/g, 'Ρ');
  61. str = str.replace(/&Sigma;/g, 'Σ');
  62. str = str.replace(/&Tau;/g, 'Τ');
  63. str = str.replace(/&Upsilon;/g, 'Υ');
  64. str = str.replace(/&Phi;/g, 'Φ');
  65. str = str.replace(/&Chi;/g, 'Χ');
  66. str = str.replace(/&Psi;/g, 'Ψ');
  67. str = str.replace(/&Omega;/g, 'Ω');
  68. str = str.replace(/&alpha;/g, 'α');
  69. str = str.replace(/&beta;/g, 'β');
  70. str = str.replace(/&gamma;/g, 'γ');
  71. str = str.replace(/&delta;/g, 'δ');
  72. str = str.replace(/&epsilon;/g, 'ε');
  73. str = str.replace(/&zeta;/g, 'ζ');
  74. str = str.replace(/&eta;/g, 'η');
  75. str = str.replace(/&theta;/g, 'θ');
  76. str = str.replace(/&iota;/g, 'ι');
  77. str = str.replace(/&kappa;/g, 'κ');
  78. str = str.replace(/&lambda;/g, 'λ');
  79. str = str.replace(/&mu;/g, 'μ');
  80. str = str.replace(/&nu;/g, 'ν');
  81. str = str.replace(/&xi;/g, 'ξ');
  82. str = str.replace(/&omicron;/g, 'ο');
  83. str = str.replace(/&pi;/g, 'π');
  84. str = str.replace(/&rho;/g, 'ρ');
  85. str = str.replace(/&sigmaf;/g, 'ς');
  86. str = str.replace(/&sigma;/g, 'σ');
  87. str = str.replace(/&tau;/g, 'τ');
  88. str = str.replace(/&upsilon;/g, 'υ');
  89. str = str.replace(/&phi;/g, 'φ');
  90. str = str.replace(/&chi;/g, 'χ');
  91. str = str.replace(/&psi;/g, 'ψ');
  92. str = str.replace(/&omega;/g, 'ω');
  93. str = str.replace(/&thetasym;/g, 'ϑ');
  94. str = str.replace(/&upsih;/g, 'ϒ');
  95. str = str.replace(/&piv;/g, 'ϖ');
  96. str = str.replace(/&middot;/g, '·');
  97. return str;
  98. }
  99. function strcharacterDiscode(str) {
  100. // 加入常用解析
  101. str = str.replace(/&nbsp;/g, ' ');
  102. str = str.replace(/&ensp;/g, ' ');
  103. str = str.replace(/&emsp;/g, ' ');
  104. str = str.replace(/&quot;/g, "'");
  105. str = str.replace(/&amp;/g, '&');
  106. str = str.replace(/&lt;/g, '<');
  107. str = str.replace(/&gt;/g, '>');
  108. str = str.replace(/&#8226;/g, '•');
  109. return str;
  110. }
  111. // HTML 支持的其他实体
  112. function strOtherDiscode(str) {
  113. str = str.replace(/&OElig;/g, 'Œ');
  114. str = str.replace(/&oelig;/g, 'œ');
  115. str = str.replace(/&Scaron;/g, 'Š');
  116. str = str.replace(/&scaron;/g, 'š');
  117. str = str.replace(/&Yuml;/g, 'Ÿ');
  118. str = str.replace(/&fnof;/g, 'ƒ');
  119. str = str.replace(/&circ;/g, 'ˆ');
  120. str = str.replace(/&tilde;/g, '˜');
  121. str = str.replace(/&ensp;/g, '');
  122. str = str.replace(/&emsp;/g, '');
  123. str = str.replace(/&thinsp;/g, '');
  124. str = str.replace(/&zwnj;/g, '');
  125. str = str.replace(/&zwj;/g, '');
  126. str = str.replace(/&lrm;/g, '');
  127. str = str.replace(/&rlm;/g, '');
  128. str = str.replace(/&ndash;/g, '–');
  129. str = str.replace(/&mdash;/g, '—');
  130. str = str.replace(/&lsquo;/g, '‘');
  131. str = str.replace(/&rsquo;/g, '’');
  132. str = str.replace(/&sbquo;/g, '‚');
  133. str = str.replace(/&ldquo;/g, '“');
  134. str = str.replace(/&rdquo;/g, '”');
  135. str = str.replace(/&bdquo;/g, '„');
  136. str = str.replace(/&dagger;/g, '†');
  137. str = str.replace(/&Dagger;/g, '‡');
  138. str = str.replace(/&bull;/g, '•');
  139. str = str.replace(/&hellip;/g, '…');
  140. str = str.replace(/&permil;/g, '‰');
  141. str = str.replace(/&prime;/g, '′');
  142. str = str.replace(/&Prime;/g, '″');
  143. str = str.replace(/&lsaquo;/g, '‹');
  144. str = str.replace(/&rsaquo;/g, '›');
  145. str = str.replace(/&oline;/g, '‾');
  146. str = str.replace(/&euro;/g, '€');
  147. str = str.replace(/&trade;/g, '™');
  148. str = str.replace(/&larr;/g, '←');
  149. str = str.replace(/&uarr;/g, '↑');
  150. str = str.replace(/&rarr;/g, '→');
  151. str = str.replace(/&darr;/g, '↓');
  152. str = str.replace(/&harr;/g, '↔');
  153. str = str.replace(/&crarr;/g, '↵');
  154. str = str.replace(/&lceil;/g, '⌈');
  155. str = str.replace(/&rceil;/g, '⌉');
  156. str = str.replace(/&lfloor;/g, '⌊');
  157. str = str.replace(/&rfloor;/g, '⌋');
  158. str = str.replace(/&loz;/g, '◊');
  159. str = str.replace(/&spades;/g, '♠');
  160. str = str.replace(/&clubs;/g, '♣');
  161. str = str.replace(/&hearts;/g, '♥');
  162. str = str.replace(/&diams;/g, '♦');
  163. str = str.replace(/&#39;/g, "'");
  164. return str;
  165. }
  166. function strDiscode(str) {
  167. str = strNumDiscode(str);
  168. str = strGreeceDiscode(str);
  169. str = strcharacterDiscode(str);
  170. str = strOtherDiscode(str);
  171. return str;
  172. }
  173. function urlToHttpUrl(url, domain) {
  174. if (/^\/\//.test(url)) {
  175. return `https:${url}`;
  176. } else if (/^\//.test(url)) {
  177. return `https://${domain}${url}`;
  178. }
  179. return url;
  180. }
  181. export default {
  182. strDiscode,
  183. urlToHttpUrl,
  184. };
readme.md
复制代码
  1. ## uParse 适用于 uni-app/mpvue 的富文本解析组件
  2. > 支持 Html、Markdown 解析,Fork自: [mpvue-wxParse](https://github.com/F-loat/mpvue-wxParse)
  3. ## 属性
  4. | 名称 | 类型 | 默认值 | 描述 |
  5. | -----------------|--------------- | ------------- | ---------------- |
  6. | loading | Boolean | false | 数据加载状态 |
  7. | className | String | — | 自定义 class 名称 |
  8. | content | String | — | 渲染内容 |
  9. | noData | String | 数据不能为空 | 空数据时的渲染展示 |
  10. | startHandler | Function | 见源码 | 自定义 parser 函数 |
  11. | endHandler | Function | null | 自定义 parser 函数 |
  12. | charsHandler | Function | null | 自定义 parser 函数 |
  13. | imageProp | Object | 见下文 | 图片相关参数 |
  14. ### 自定义 parser 函数具体介绍
  15. * 传入的参数为当前节点 `node` 对象及解析结果 `results` 对象,例如 `startHandler(node, results)`
  16. * 无需返回值,通过对传入的参数直接操作来完成需要的改动
  17. * 自定义函数会在原解析函数处理之后执行
  18. ### imageProp 对象具体属性
  19. | 名称 | 类型 | 默认值 | 描述 |
  20. | -----------------|--------------- | ------------- | ------------------ |
  21. | mode | String | 'aspectFit' | 图片裁剪、缩放的模式 |
  22. | padding | Number | 0 | 图片内边距 |
  23. | lazyLoad | Boolean | false | 图片懒加载 |
  24. | domain | String | '' | 图片服务域名 |
  25. ## 事件
  26. | 名称 | 参数 | 描述 |
  27. | -----------------|----------------- | ---------------- |
  28. | preview | 图片地址,原始事件 | 预览图片时触发 |
  29. | navigate | 链接地址,原始事件 | 点击链接时触发 |
  30. ## 基本使用方法

<template>
<div>

复制代码
  1. <u-parse :content="article" @preview="preview" @navigate="navigate" />

</div>
</template>

<script>
import uParse from '@/components/u-parse/u-parse.vue'

export default {
components: {

复制代码
  1. uParse

},
data () {

复制代码
  1. return {
  2. article: '<div>我是HTML代码</div>'
  3. }

},
methods: {

复制代码
  1. preview(src, e) {
  2. // do something
  3. },
  4. navigate(href, e) {
  5. // do something
  6. }

}
}
</script>

<style>
@import url("@/components/u-parse/u-parse.css");
</style>

复制代码
  1. ## 渲染 Markdown
  2. > 先将 markdown 转换为 html 即可

npm install marked

import marked from 'marked'
import uParse from '@/components/u-parse/u-parse.vue'

export default {
components: {

复制代码
  1. uParse

},
data () {

复制代码
  1. return {
  2. article: marked(`#hello, markdown!`)
  3. }

}
}

u-parse.css
复制代码
  1. /**
  2. * author: Di (微信小程序开发工程师)
  3. * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
  4. * 垂直微信小程序开发交流社区
  5. *
  6. * github地址: https://github.com/icindy/wxParse
  7. *
  8. * for: 微信小程序富文本解析
  9. * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
  10. */
  11. .wxParse {
  12. width: 100%;
  13. font-family: Helvetica, sans-serif;
  14. font-size: 30upx;
  15. color: #666;
  16. line-height: 1.8;
  17. }
  18. .wxParse view {
  19. word-break: hyphenate;
  20. }
  21. .wxParse .inline {
  22. display: inline;
  23. margin: 0;
  24. padding: 0;
  25. }
  26. .wxParse .div {
  27. margin: 0;
  28. padding: 0;
  29. }
  30. .wxParse .h1 .text {
  31. font-size: 2em;
  32. margin: 0.67em 0;
  33. }
  34. .wxParse .h2 .text {
  35. font-size: 1.5em;
  36. margin: 0.83em 0;
  37. }
  38. .wxParse .h3 .text {
  39. font-size: 1.17em;
  40. margin: 1em 0;
  41. }
  42. .wxParse .h4 .text {
  43. margin: 1.33em 0;
  44. }
  45. .wxParse .h5 .text {
  46. font-size: 0.83em;
  47. margin: 1.67em 0;
  48. }
  49. .wxParse .h6 .text {
  50. font-size: 0.67em;
  51. margin: 2.33em 0;
  52. }
  53. .wxParse .h1 .text,
  54. .wxParse .h2 .text,
  55. .wxParse .h3 .text,
  56. .wxParse .h4 .text,
  57. .wxParse .h5 .text,
  58. .wxParse .h6 .text,
  59. .wxParse .b,
  60. .wxParse .strong {
  61. font-weight: bolder;
  62. }
  63. .wxParse .p {
  64. margin: 1em 0;
  65. }
  66. .wxParse .i,
  67. .wxParse .cite,
  68. .wxParse .em,
  69. .wxParse .var,
  70. .wxParse .address {
  71. font-style: italic;
  72. }
  73. .wxParse .pre,
  74. .wxParse .tt,
  75. .wxParse .code,
  76. .wxParse .kbd,
  77. .wxParse .samp {
  78. font-family: monospace;
  79. }
  80. .wxParse .pre {
  81. overflow: auto;
  82. background: #f5f5f5;
  83. padding: 16upx;
  84. white-space: pre;
  85. margin: 1em 0upx;
  86. }
  87. .wxParse .code {
  88. display: inline;
  89. background: #f5f5f5;
  90. }
  91. .wxParse .big {
  92. font-size: 1.17em;
  93. }
  94. .wxParse .small,
  95. .wxParse .sub,
  96. .wxParse .sup {
  97. font-size: 0.83em;
  98. }
  99. .wxParse .sub {
  100. vertical-align: sub;
  101. }
  102. .wxParse .sup {
  103. vertical-align: super;
  104. }
  105. .wxParse .s,
  106. .wxParse .strike,
  107. .wxParse .del {
  108. text-decoration: line-through;
  109. }
  110. .wxParse .strong,
  111. .wxParse .s {
  112. display: inline;
  113. }
  114. .wxParse .a {
  115. color: deepskyblue;
  116. }
  117. .wxParse .video {
  118. text-align: center;
  119. margin: 22upx 0;
  120. }
  121. .wxParse .video-video {
  122. width: 100%;
  123. }
  124. .wxParse .img {
  125. display: inline-block;
  126. width: 0;
  127. height: 0;
  128. max-width: 100%;
  129. overflow: hidden;
  130. }
  131. .wxParse .blockquote {
  132. margin: 10upx 0;
  133. padding: 22upx 0 22upx 22upx;
  134. font-family: Courier, Calibri, "宋体";
  135. background: #f5f5f5;
  136. border-left: 6upx solid #dbdbdb;
  137. }
  138. .wxParse .blockquote .p {
  139. margin: 0;
  140. }
  141. .wxParse .ul, .wxParse .ol {
  142. display: block;
  143. margin: 1em 0;
  144. padding-left: 33upx;
  145. }
  146. .wxParse .ol {
  147. list-style-type: disc;
  148. }
  149. .wxParse .ol {
  150. list-style-type: decimal;
  151. }
  152. .wxParse .ol>weixin-parse-template,.wxParse .ul>weixin-parse-template {
  153. display: list-item;
  154. align-items: baseline;
  155. text-align: match-parent;
  156. }
  157. .wxParse .ol>.li,.wxParse .ul>.li {
  158. display: list-item;
  159. align-items: baseline;
  160. text-align: match-parent;
  161. }
  162. .wxParse .ul .ul, .wxParse .ol .ul {
  163. list-style-type: circle;
  164. }
  165. .wxParse .ol .ol .ul, .wxParse .ol .ul .ul, .wxParse .ul .ol .ul, .wxParse .ul .ul .ul {
  166. list-style-type: square;
  167. }
  168. .wxParse .u {
  169. text-decoration: underline;
  170. }
  171. .wxParse .hide {
  172. display: none;
  173. }
  174. .wxParse .del {
  175. display: inline;
  176. }
  177. .wxParse .figure {
  178. overflow: hidden;
  179. }
  180. .wxParse .table {
  181. width: 100%;
  182. }
  183. .wxParse .thead, .wxParse .tfoot, .wxParse .tr {
  184. display: flex;
  185. flex-direction: row;
  186. }
  187. .wxParse .tr {
  188. width:100%;
  189. display: flex;
  190. border-right: 2upx solid #e0e0e0;
  191. border-bottom: 2upx solid #e0e0e0;
  192. }
  193. .wxParse .th,
  194. .wxParse .td {
  195. display: flex;
  196. width: 1276upx;
  197. overflow: auto;
  198. flex: 1;
  199. padding: 11upx;
  200. border-left: 2upx solid #e0e0e0;
  201. }
  202. .wxParse .td:last {
  203. border-top: 2upx solid #e0e0e0;
  204. }
  205. .wxParse .th {
  206. background: #f0f0f0;
  207. border-top: 2upx solid #e0e0e0;
  208. }
u-parse.vue
复制代码
  1. <!--**
  2. * forked from:https://github.com/F-loat/mpvue-wxParse
  3. *
  4. * github地址: https://github.com/dcloudio/uParse
  5. *
  6. * for: uni-app框架下 富文本解析
  7. */-->
  8. <template>
  9. <!--基础元素-->
  10. <div class="wxParse" :class="className" v-if="!loading">
  11. <block v-for="(node,index) of nodes" :key="index">
  12. <wxParseTemplate :node="node" />
  13. </block>
  14. </div>
  15. </template>
  16. <script>
  17. import HtmlToJson from './libs/html2json';
  18. import wxParseTemplate from './components/wxParseTemplate0';
  19. export default {
  20. name: 'wxParse',
  21. props: {
  22. loading: {
  23. type: Boolean,
  24. default: false,
  25. },
  26. className: {
  27. type: String,
  28. default: '',
  29. },
  30. content: {
  31. type: String,
  32. default: '',
  33. },
  34. noData: {
  35. type: String,
  36. default: '<div style="color: #999;text-align: center;">加载中...</div>',
  37. },
  38. startHandler: {
  39. type: Function,
  40. default() {
  41. return (node) => {
  42. node.attr.class = null;
  43. node.attr.style = null;
  44. };
  45. },
  46. },
  47. endHandler: {
  48. type: Function,
  49. default: null,
  50. },
  51. charsHandler: {
  52. type: Function,
  53. default: null,
  54. },
  55. imageProp: {
  56. type: Object,
  57. default() {
  58. return {
  59. mode: 'aspectFit',
  60. padding: 0,
  61. lazyLoad: false,
  62. domain: '',
  63. };
  64. },
  65. },
  66. },
  67. components: {
  68. wxParseTemplate,
  69. },
  70. data() {
  71. return {
  72. imageUrls: [],
  73. };
  74. },
  75. computed: {
  76. nodes() {
  77. const {
  78. content,
  79. noData,
  80. imageProp,
  81. startHandler,
  82. endHandler,
  83. charsHandler,
  84. } = this;
  85. const parseData = content || noData;
  86. const customHandler = {
  87. start: startHandler,
  88. end: endHandler,
  89. chars: charsHandler,
  90. };
  91. const results = HtmlToJson(parseData, customHandler, imageProp, this);
  92. this.imageUrls = results.imageUrls;
  93. return results.nodes;
  94. },
  95. },
  96. methods: {
  97. navigate(href, $event) {
  98. this.$emit('navigate', href, $event);
  99. },
  100. preview(src, $event) {
  101. if (!this.imageUrls.length) return;
  102. uni.previewImage({
  103. current: src,
  104. urls: this.imageUrls,
  105. });
  106. this.$emit('preview', src, $event);
  107. },
  108. removeImageUrl(src) {
  109. const { imageUrls } = this;
  110. imageUrls.splice(imageUrls.indexOf(src), 1);
  111. },
  112. },
  113. };
  114. </script>

uni-countdown

readme.md
复制代码
  1. ### CountDown 倒计时
  2. 倒计时组件,组件名:``uni-countdown``,代码块: uCountDown。
  3. **使用方式:**
  4. ``script`` 中引用组件

import uniCountdown from "@/components/uni-countdown/uni-countdown.vue"
export default {

复制代码
  1. components: {uniCountdown}

}

复制代码
  1. 一般用法

<uni-countdown

复制代码
  1. :day="1"
  2. :hour="1"
  3. :minute="12"
  4. :second="40">

</uni-countdown>

复制代码
  1. 不显示天数

<uni-countdown

复制代码
  1. :show-day="false"
  2. :hour="12"
  3. :minute="12"
  4. :second="12">

</uni-countdown>

复制代码
  1. 修改颜色

<uni-countdown

复制代码
  1. color="#FFFFFF"
  2. background-color="#00B26A"
  3. border-color="#00B26A"
  4. :day="1"
  5. :hour="2"
  6. :minute="30"
  7. :second="0">

</uni-countdown>

复制代码
  1. 实际效果参考:[https://github.com/dcloudio/uni-ui](https://github.com/dcloudio/uni-ui)
  2. **uniCountDown 属性说明:**
  3. |属性名|类型|默认值 |说明|
  4. |---|----|---|---|
  5. |background-color|String|#FFFFFF|背景色|
  6. |border-color|String|#000000|边框颜色|
  7. |color |String |#000000|文字颜色|
  8. |splitor-color|String|#000000|割符号颜色|
  9. |day|Number|0|天数|
  10. |hour|Number|0|小时|
  11. |minute|Number|0|分钟|
  12. |second|Number|0|秒|
  13. |show-day|Boolean|true|是否显示天数|
  14. |show-colon|Boolean|true|是否以冒号为分隔符|
  15. **uniCountDown 事件说明:**
  16. |事件称名|说明|返回参数|
  17. |---|----|---|
  18. |timeup|倒计时时间到触发事件|-|
uni-countdown.vue
复制代码
  1. <template>
  2. <view class="uni-countdown">
  3. <view v-if="showDay && d!=0" class="uni-countdown__number" :style="{borderColor:borderColor, color:color, background:backgroundColor}">{{d}}</view>
  4. <view v-if="showDay && d!=0" class="uni-countdown__splitor" :style="{color:textColor}"></view>
  5. <view class="uni-countdown__number" :style="{borderColor:borderColor, color:color, background:backgroundColor}">{{h}}</view>
  6. <view class="uni-countdown__splitor" :style="{color:textColor}">{{showColon ? ':' : '时'}}</view>
  7. <view class="uni-countdown__number" :style="{borderColor:borderColor, color:color, background:backgroundColor}">{{i}}</view>
  8. <view class="uni-countdown__splitor" :style="{color:textColor}">{{showColon ? ':' : '分'}}</view>
  9. <view class="uni-countdown__number" :style="{borderColor:borderColor, color:color, background:backgroundColor}">{{s}}</view>
  10. <view v-if="!showColon" class="uni-countdown__splitor" :style="{color:textColor}"></view>
  11. </view>
  12. </template>
  13. <script>
  14. export default {
  15. name: "uni-countdown",
  16. props: {
  17. showDay: {
  18. type: Boolean,
  19. default: true
  20. },
  21. showColon: {
  22. type: Boolean,
  23. default: true
  24. },
  25. backgroundColor: {
  26. type: String,
  27. default: "#FFFFFF"
  28. },
  29. borderColor: {
  30. type: String,
  31. default: "#000000"
  32. },
  33. color: {
  34. type: String,
  35. // value: "#000000"
  36. },
  37. textColor: {
  38. type: String,
  39. default: "#000000"
  40. },
  41. splitorColor: {
  42. type: String,
  43. default: "#000"
  44. },
  45. day: {
  46. type: Number,
  47. default: 0
  48. },
  49. hour: {
  50. type: Number,
  51. default: 0
  52. },
  53. minute: {
  54. type: Number,
  55. default: 0
  56. },
  57. second: {
  58. type: Number,
  59. default: 0
  60. }
  61. },
  62. data() {
  63. return {
  64. timer: null,
  65. d: '00',
  66. h: '00',
  67. i: '00',
  68. s: '00',
  69. leftTime: 0,
  70. seconds: 0
  71. }
  72. },
  73. created: function(e) {
  74. this.seconds = this.toSeconds(this.day, this.hour, this.minute, this.second)
  75. this.countDown()
  76. this.timer = setInterval(() => {
  77. this.seconds--
  78. if (this.seconds < 0) {
  79. this.timeUp()
  80. return
  81. }
  82. this.countDown()
  83. }, 1000)
  84. },
  85. beforeDestroy() {
  86. clearInterval(this.timer)
  87. },
  88. methods: {
  89. toSeconds(day, hours, minutes, seconds) {
  90. return (day * 60 * 60 * 24) + (hours * 60 * 60) + (minutes * 60) + seconds
  91. },
  92. timeUp() {
  93. clearInterval(this.timer)
  94. this.$emit('timeup')
  95. },
  96. countDown() {
  97. let seconds = this.seconds
  98. let [day, hour, minute, second] = [0, 0, 0, 0]
  99. if (seconds > 0) {
  100. day = Math.floor(seconds / (60 * 60 * 24))
  101. hour = Math.floor(seconds / (60 * 60)) - (day * 24)
  102. minute = Math.floor(seconds / 60) - (day * 24 * 60) - (hour * 60)
  103. second = Math.floor(seconds) - (day * 24 * 60 * 60) - (hour * 60 * 60) - (minute * 60)
  104. } else {
  105. this.timeUp()
  106. }
  107. if (day < 10) {
  108. day = '0' + day
  109. }
  110. if (hour < 10) {
  111. hour = '0' + hour
  112. }
  113. if (minute < 10) {
  114. minute = '0' + minute
  115. }
  116. if (second < 10) {
  117. second = '0' + second
  118. }
  119. this.d = day
  120. this.h = hour
  121. this.i = minute
  122. this.s = second
  123. }
  124. }
  125. }
  126. </script>
  127. <style lang="scss">
  128. $countdown-height:44upx;
  129. .uni-countdown {
  130. padding: 2upx 0;
  131. display: inline-flex;
  132. flex-wrap: nowrap;
  133. justify-content: center;
  134. &__splitor {
  135. justify-content: center;
  136. line-height: $countdown-height;
  137. padding: 0 5upx;
  138. font-size: 24upx;
  139. // color: #d0d0d0;
  140. }
  141. &__number {
  142. line-height: $countdown-height;
  143. justify-content: center;
  144. height: $countdown-height;
  145. border-radius: $uni-border-radius-base;
  146. // margin: 0 5upx;
  147. font-size: 24upx;
  148. // border: 1px solid #000000;
  149. font-size: $uni-font-size-sm;
  150. // padding: 0 10upx;
  151. }
  152. }
  153. </style>

uni-fab

uni-fab.vue
复制代码
  1. <template>
  2. <view>
  3. <view
  4. class="fab-box fab"
  5. :class="{
  6. leftBottom: leftBottom,
  7. rightBottom: rightBottom,
  8. leftTop: leftTop,
  9. rightTop: rightTop
  10. }"
  11. >
  12. <view
  13. class="fab-circle"
  14. :class="{
  15. left: horizontal === 'left' && direction === 'horizontal',
  16. top: vertical === 'top' && direction === 'vertical',
  17. bottom: vertical === 'bottom' && direction === 'vertical',
  18. right: horizontal === 'right' && direction === 'horizontal'
  19. }"
  20. :style="{ 'background-color': styles.buttonColor }"
  21. @click="open"
  22. >
  23. <image class="icon icon-jia" src="../../../static/image/menu.png" mode="" :class="{ active: showContent }"></image>
  24. <!-- <text class="icon icon-jia" :class="{ active: showContent }"></text> -->
  25. </view>
  26. <view
  27. class="fab-content"
  28. :class="{
  29. left: horizontal === 'left',
  30. right: horizontal === 'right',
  31. flexDirection: direction === 'vertical',
  32. flexDirectionStart: flexDirectionStart,
  33. flexDirectionEnd: flexDirectionEnd
  34. }"
  35. :style="{ width: boxWidth, height: boxHeight, background: styles.backgroundColor }"
  36. >
  37. <view v-if="flexDirectionStart || horizontalLeft" class="fab-item first"></view>
  38. <view
  39. class="fab-item"
  40. v-for="(item, index) in content"
  41. :key="index"
  42. :class="{ active: showContent }"
  43. :style="{
  44. color: item.active ? styles.selectedColor : styles.color
  45. }"
  46. @click="taps(index, item)"
  47. >
  48. <image
  49. class="content-image icon"
  50. :src="item.active ? item.selectedIconPath : item.iconPath"
  51. mode=""
  52. ></image>
  53. <text class="text">{{ item.text }}</text>
  54. </view>
  55. <view v-if="flexDirectionEnd || horizontalRight" class="fab-item first"></view>
  56. </view>
  57. </view>
  58. </view>
  59. </template>
  60. <script>
  61. export default {
  62. props: {
  63. pattern: {
  64. type: Object,
  65. default: () => {
  66. return {};
  67. }
  68. },
  69. horizontal: {
  70. type: String,
  71. default: 'left'
  72. },
  73. vertical: {
  74. type: String,
  75. default: 'bottom'
  76. },
  77. direction: {
  78. type: String,
  79. default: 'horizontal'
  80. },
  81. content: {
  82. type: Array,
  83. default: () => {
  84. return [];
  85. }
  86. }
  87. },
  88. data() {
  89. return {
  90. fabShow: false,
  91. flug: true,
  92. showContent: false,
  93. styles: {
  94. color: '#3c3e49',
  95. selectedColor: '#007AFF',
  96. backgroundColor: '#fff',
  97. buttonColor: '#3c3e49'
  98. }
  99. };
  100. },
  101. created() {
  102. if (this.top === 0) {
  103. this.fabShow = true;
  104. }
  105. // 初始化样式
  106. this.styles = Object.assign({}, this.styles, this.pattern);
  107. },
  108. methods: {
  109. open() {
  110. this.showContent = !this.showContent;
  111. },
  112. /**
  113. * 按钮点击事件
  114. */
  115. taps(index, item) {
  116. this.$emit('trigger', {
  117. index,
  118. item
  119. });
  120. },
  121. /**
  122. * 获取 位置信息
  123. */
  124. getPosition(types, paramA, paramB) {
  125. if (types === 0) {
  126. return this.horizontal === paramA && this.vertical === paramB;
  127. } else if (types === 1) {
  128. return this.direction === paramA && this.vertical === paramB;
  129. } else if (types === 2) {
  130. return this.direction === paramA && this.horizontal === paramB;
  131. } else {
  132. return this.showContent && this.direction === paramA
  133. ? this.contentWidth
  134. : this.contentWidthMin;
  135. }
  136. }
  137. },
  138. watch: {
  139. pattern(newValue, oldValue) {
  140. // console.log(JSON.stringify(newValue));
  141. this.styles = Object.assign({}, this.styles, newValue);
  142. }
  143. },
  144. computed: {
  145. contentWidth(e) {
  146. return uni.upx2px((this.content.length + 1) * 90 + 20) + 'px';
  147. },
  148. contentWidthMin() {
  149. return uni.upx2px(90) + 'px';
  150. },
  151. // 动态计算宽度
  152. boxWidth() {
  153. return this.getPosition(3, 'horizontal');
  154. },
  155. // 动态计算高度
  156. boxHeight() {
  157. return this.getPosition(3, 'vertical');
  158. },
  159. // 计算左下位置
  160. leftBottom() {
  161. return this.getPosition(0, 'left', 'bottom');
  162. },
  163. // 计算右下位置
  164. rightBottom() {
  165. return this.getPosition(0, 'right', 'bottom');
  166. },
  167. // 计算左上位置
  168. leftTop() {
  169. return this.getPosition(0, 'left', 'top');
  170. },
  171. rightTop() {
  172. return this.getPosition(0, 'right', 'top');
  173. },
  174. flexDirectionStart() {
  175. return this.getPosition(1, 'vertical', 'top');
  176. },
  177. flexDirectionEnd() {
  178. return this.getPosition(1, 'vertical', 'bottom');
  179. },
  180. horizontalLeft() {
  181. return this.getPosition(2, 'horizontal', 'left');
  182. },
  183. horizontalRight() {
  184. return this.getPosition(2, 'horizontal', 'right');
  185. }
  186. }
  187. };
  188. </script>
  189. <style scoped>
  190. .fab-box {
  191. position: fixed;
  192. display: flex;
  193. justify-content: center;
  194. align-items: center;
  195. z-index: 2;
  196. }
  197. .fab-box.top {
  198. width: 60upx;
  199. height: 60upx;
  200. right: 30upx;
  201. bottom: 60upx;
  202. border: 1px #5989b9 solid;
  203. background: #6699cc;
  204. border-radius: 10upx;
  205. color: #fff;
  206. transition: all 0.3;
  207. opacity: 0;
  208. }
  209. .fab-box.active {
  210. opacity: 1;
  211. }
  212. .fab-box.fab {
  213. z-index: 10;
  214. }
  215. .fab-box.fab.leftBottom {
  216. left: 30upx;
  217. bottom: 130upx;
  218. }
  219. .fab-box.fab.leftTop {
  220. left: 30upx;
  221. top: 80upx;
  222. /* #ifdef H5 */
  223. top: calc(80upx + var(--window-top));
  224. /* #endif */
  225. }
  226. .fab-box.fab.rightBottom {
  227. right: 30upx;
  228. bottom: 130upx;
  229. }
  230. .fab-box.fab.rightTop {
  231. right: 30upx;
  232. top: 80upx;
  233. /* #ifdef H5 */
  234. top: calc(80upx + var(--window-top));
  235. /* #endif */
  236. }
  237. .fab-circle {
  238. display: flex;
  239. justify-content: center;
  240. align-items: center;
  241. position: absolute;
  242. width: 90upx;
  243. height: 90upx;
  244. background: #3c3e49;
  245. /* background: #5989b9; */
  246. border-radius: 50%;
  247. box-shadow: 0 0 5px 2px rgba(0, 0, 0, 0.2);
  248. z-index: 11;
  249. }
  250. .fab-circle.left {
  251. left: 0;
  252. }
  253. .fab-circle.right {
  254. right: 0;
  255. }
  256. .fab-circle.top {
  257. top: 0;
  258. }
  259. .fab-circle.bottom {
  260. bottom: 0;
  261. }
  262. .fab-circle .icon-jia {
  263. color: #ffffff;
  264. font-size: 50upx;
  265. transition: all 0.3s;
  266. }
  267. .fab-circle .icon-jia.active {
  268. transform: rotate(90deg);
  269. }
  270. .fab-content {
  271. background: #6699cc;
  272. box-sizing: border-box;
  273. display: flex;
  274. border-radius: 100upx;
  275. overflow: hidden;
  276. box-shadow: 0 0 5px 2px rgba(0, 0, 0, 0.1);
  277. transition: all 0.2s;
  278. width: 110upx;
  279. }
  280. .fab-content.left {
  281. justify-content: flex-start;
  282. }
  283. .fab-content.right {
  284. justify-content: flex-end;
  285. }
  286. .fab-content.flexDirection {
  287. flex-direction: column;
  288. justify-content: flex-end;
  289. }
  290. .fab-content.flexDirectionStart {
  291. flex-direction: column;
  292. justify-content: flex-start;
  293. }
  294. .fab-content.flexDirectionEnd {
  295. flex-direction: column;
  296. justify-content: flex-end;
  297. }
  298. .fab-content .fab-item {
  299. display: flex;
  300. flex-direction: column;
  301. justify-content: center;
  302. align-items: center;
  303. width: 90upx;
  304. height: 90upx;
  305. font-size: 24upx;
  306. color: #fff;
  307. opacity: 0;
  308. transition: opacity 0.2s;
  309. }
  310. .fab-content .fab-item.active {
  311. opacity: 1;
  312. }
  313. .fab-content .fab-item .content-image {
  314. width: 60upx;
  315. height: 60upx;
  316. margin-bottom: 10upx;
  317. }
  318. .fab-content .fab-item.first {
  319. width: 110upx;
  320. }
  321. /* @font-face {
  322. font-family: 'iconfont';
  323. src: url('https://at.alicdn.com/t/font_1028200_xhbo4rn58rp.ttf?t=1548214263520')
  324. format('truetype');
  325. }
  326. .icon {
  327. font-family: 'iconfont' !important;
  328. font-size: 16px;
  329. font-style: normal;
  330. -webkit-font-smoothing: antialiased;
  331. -moz-osx-font-smoothing: grayscale;
  332. }
  333. .icon-jia:before {
  334. content: '\e630';
  335. }
  336. .icon-arrow-up:before {
  337. content: '\e603';
  338. } */
  339. </style>

uni-icon

readme.md
复制代码
  1. ### Icon 图标
  2. 用于展示 icon,组件名:``uni-icon``,代码块: uIcon。
  3. **使用方式:**
  4. ``script`` 中引用组件

import uniIcon from "@/components/uni-icon/uni-icon.vue"
export default {

复制代码
  1. components: {uniIcon}

}

复制代码
  1. 在 ``template`` 中使用组件

<uni-icon type="contact" size="30"></uni-icon>

复制代码
  1. 实际效果参考:[https://github.com/dcloudio/uni-ui](https://github.com/dcloudio/uni-ui)
  2. **Icon 属性说明:**
  3. |属性名 |类型|默认值 |说明|
  4. |---|----|---|---|
  5. |type |String |-|图标图案,参考下表|
  6. |color |String |-|图标颜色 |
  7. |size |Number |24|图标大小|
  8. |@click |EventHandle|-|点击 Icon 触发事件|
  9. **type 类型:**
  10. <div>
  11. <link rel="stylesheet" type="text/css" href="https://img-cdn-qiniu.dcloud.net.cn/uniapp/doc/icon1.1.css"/>
  12. <ul class="icon-group">
  13. <li class="icon-item"><span class="uni-icon uni-icon-contact"></span><span>contact</span></li>
  14. <li class="icon-item"><span class="uni-icon uni-icon-person"></span><span>person</span></li>
  15. <li class="icon-item"><span class="uni-icon uni-icon-personadd"></span><span>personadd</span></li>
  16. <li class="icon-item"><span class="uni-icon uni-icon-contact-filled"></span><span>contact-filled</span></li>
  17. <li class="icon-item"><span class="uni-icon uni-icon-person-filled"></span><span>person-filled</span></li>
  18. <li class="icon-item"><span class="uni-icon uni-icon-personadd-filled"></span><span>personadd-filled</span></li>
  19. <li class="icon-item"><span class="uni-icon uni-icon-phone"></span><span>phone</span></li>
  20. <li class="icon-item"><span class="uni-icon uni-icon-email"></span><span>email</span></li>
  21. <li class="icon-item"><span class="uni-icon uni-icon-chatbubble"></span><span>chatbubble</span></li>
  22. <li class="icon-item"><span class="uni-icon uni-icon-chatboxes"></span><span>chatboxes</span></li>
  23. <li class="icon-item"><span class="uni-icon uni-icon-phone-filled"></span><span>phone-filled</span></li>
  24. <li class="icon-item"><span class="uni-icon uni-icon-email-filled"></span><span>email-filled</span></li>
  25. <li class="icon-item"><span class="uni-icon uni-icon-chatbubble-filled"></span><span>chatbubble-filled</span></li>
  26. <li class="icon-item"><span class="uni-icon uni-icon-chatboxes-filled"></span><span>chatboxes-filled</span></li>
  27. <li class="icon-item"><span class="uni-icon uni-icon-weibo"></span><span>weibo</span></li>
  28. <li class="icon-item"><span class="uni-icon uni-icon-weixin"></span><span>weixin</span></li>
  29. <li class="icon-item"><span class="uni-icon uni-icon-pengyouquan"></span><span>pengyouquan</span></li>
  30. <li class="icon-item"><span class="uni-icon uni-icon-chat"></span><span>chat</span></li>
  31. <li class="icon-item"><span class="uni-icon uni-icon-qq"></span><span>qq</span></li>
  32. <li class="icon-item"><span class="uni-icon uni-icon-videocam"></span><span>videocam</span></li>
  33. <li class="icon-item"><span class="uni-icon uni-icon-camera"></span><span>camera</span></li>
  34. <li class="icon-item"><span class="uni-icon uni-icon-mic"></span><span>mic</span></li>
  35. <li class="icon-item"><span class="uni-icon uni-icon-location"></span><span>location</span></li>
  36. <li class="icon-item"><span class="uni-icon uni-icon-mic-filled"></span><span>mic-filled</span></li>
  37. <li class="icon-item"><span class="uni-icon uni-icon-location-filled"></span><span>location-filled</span></li>
  38. <li class="icon-item"><span class="uni-icon uni-icon-micoff"></span><span>micoff</span></li>
  39. <li class="icon-item"><span class="uni-icon uni-icon-image"></span><span>image</span></li>
  40. <li class="icon-item"><span class="uni-icon uni-icon-map"></span><span>map</span></li>
  41. <li class="icon-item"><span class="uni-icon uni-icon-compose"></span><span>compose</span></li>
  42. <li class="icon-item"><span class="uni-icon uni-icon-trash"></span><span>trash</span></li>
  43. <li class="icon-item"><span class="uni-icon uni-icon-upload"></span><span>upload</span></li>
  44. <li class="icon-item"><span class="uni-icon uni-icon-download"></span><span>download</span></li>
  45. <li class="icon-item"><span class="uni-icon uni-icon-close"></span><span>close</span></li>
  46. <li class="icon-item"><span class="uni-icon uni-icon-redo"></span><span>redo</span></li>
  47. <li class="icon-item"><span class="uni-icon uni-icon-undo"></span><span>undo</span></li>
  48. <li class="icon-item"><span class="uni-icon uni-icon-refresh"></span><span>refresh</span></li>
  49. <li class="icon-item"><span class="uni-icon uni-icon-star"></span><span>star</span></li>
  50. <li class="icon-item"><span class="uni-icon uni-icon-plus"></span><span>plus</span></li>
  51. <li class="icon-item"><span class="uni-icon uni-icon-minus"></span><span>minus</span></li>
  52. <li class="icon-item"><span class="uni-icon uni-icon-circle"></span><span>circle</span></li>
  53. <li class="icon-item"><span class="uni-icon uni-icon-clear"></span><span>clear</span></li>
  54. <li class="icon-item"><span class="uni-icon uni-icon-refresh-filled"></span><span>refresh-filled</span></li>
  55. <li class="icon-item"><span class="uni-icon uni-icon-star-filled"></span><span>star-filled</span></li>
  56. <li class="icon-item"><span class="uni-icon uni-icon-plus-filled"></span><span>plus-filled</span></li>
  57. <li class="icon-item"><span class="uni-icon uni-icon-minus-filled"></span><span>minus-filled</span></li>
  58. <li class="icon-item"><span class="uni-icon uni-icon-circle-filled"></span><span>circle-filled</span></li>
  59. <li class="icon-item"><span class="uni-icon uni-icon-checkbox-filled"></span><span>checkbox-filled</span></li>
  60. <li class="icon-item"><span class="uni-icon uni-icon-closeempty"></span><span>closeempty</span></li>
  61. <li class="icon-item"><span class="uni-icon uni-icon-refreshempty"></span><span>refreshempty</span></li>
  62. <li class="icon-item"><span class="uni-icon uni-icon-reload"></span><span>reload</span></li>
  63. <li class="icon-item"><span class="uni-icon uni-icon-starhalf"></span><span>starhalf</span></li>
  64. <li class="icon-item"><span class="uni-icon uni-icon-spinner"></span><span>spinner</span></li>
  65. <li class="icon-item"><span class="uni-icon uni-icon-spinner-cycle"></span><span>spinner-cycle</span></li>
  66. <li class="icon-item"><span class="uni-icon uni-icon-search"></span><span>search</span></li>
  67. <li class="icon-item"><span class="uni-icon uni-icon-plusempty"></span><span>plusempty</span></li>
  68. <li class="icon-item"><span class="uni-icon uni-icon-forward"></span><span>forward</span></li>
  69. <li class="icon-item"><span class="uni-icon uni-icon-back"></span><span>back</span></li>
  70. <li class="icon-item"><span class="uni-icon uni-icon-checkmarkempty"></span><span>checkmarkempty</span></li>
  71. <li class="icon-item"><span class="uni-icon uni-icon-home"></span><span>home</span></li>
  72. <li class="icon-item"><span class="uni-icon uni-icon-navigate"></span><span>navigate</span></li>
  73. <li class="icon-item"><span class="uni-icon uni-icon-gear"></span><span>gear</span></li>
  74. <li class="icon-item"><span class="uni-icon uni-icon-paperplane"></span><span>paperplane</span></li>
  75. <li class="icon-item"><span class="uni-icon uni-icon-info"></span><span>info</span></li>
  76. <li class="icon-item"><span class="uni-icon uni-icon-help"></span><span>help</span></li>
  77. <li class="icon-item"><span class="uni-icon uni-icon-locked"></span><span>locked</span></li>
  78. <li class="icon-item"><span class="uni-icon uni-icon-more"></span><span>more</span></li>
  79. <li class="icon-item"><span class="uni-icon uni-icon-flag"></span><span>flag</span></li>
  80. <li class="icon-item"><span class="uni-icon uni-icon-home-filled"></span><span>home-filled</span></li>
  81. <li class="icon-item"><span class="uni-icon uni-icon-gear-filled"></span><span>gear-filled</span></li>
  82. <li class="icon-item"><span class="uni-icon uni-icon-info-filled"></span><span>info-filled</span></li>
  83. <li class="icon-item"><span class="uni-icon uni-icon-help-filled"></span><span>help-filled</span></li>
  84. <li class="icon-item"><span class="uni-icon uni-icon-more-filled"></span><span>more-filled</span></li>
  85. <li class="icon-item"><span class="uni-icon uni-icon-settings"></span><span>settings</span></li>
  86. <li class="icon-item"><span class="uni-icon uni-icon-list"></span><span>list</span></li>
  87. <li class="icon-item"><span class="uni-icon uni-icon-bars"></span><span>bars</span></li>
  88. <li class="icon-item"><span class="uni-icon uni-icon-loop"></span><span>loop</span></li>
  89. <li class="icon-item"><span class="uni-icon uni-icon-paperclip"></span><span>paperclip</span></li>
  90. <li class="icon-item"><span class="uni-icon uni-icon-eye"></span><span>eye</span></li>
  91. <li class="icon-item"><span class="uni-icon uni-icon-arrowup"></span><span>arrowup</span></li>
  92. <li class="icon-item"><span class="uni-icon uni-icon-arrowdown"></span><span>arrowdown</span></li>
  93. <li class="icon-item"><span class="uni-icon uni-icon-arrowleft"></span><span>arrowleft</span></li>
  94. <li class="icon-item"><span class="uni-icon uni-icon-arrowright"></span><span>arrowright</span></li>
  95. <li class="icon-item"><span class="uni-icon uni-icon-arrowthinup"></span><span>arrowthinup</span></li>
  96. <li class="icon-item"><span class="uni-icon uni-icon-arrowthindown"></span><span>arrowthindown</span></li>
  97. <li class="icon-item"><span class="uni-icon uni-icon-arrowthinleft"></span><span>arrowthinleft</span></li>
  98. <li class="icon-item"><span class="uni-icon uni-icon-arrowthinright"></span><span>arrowthinright</span></li>
  99. <li class="icon-item"><span class="uni-icon uni-icon-pulldown"></span><span>pulldown</span></li>
  100. <li class="icon-item"><span class="uni-icon uni-icon-scan"></span><span>scan</span></li>
  101. </ul>
  102. </div>
uni-icon.vue
复制代码
  1. <template>
  2. <view class="uni-icon" :class="['uni-icon-'+type]" :style="{color:color,'font-size':fontSize}" @click="onClick()"></view>
  3. </template>
  4. <script>
  5. export default {
  6. name: 'uni-icon',
  7. props: {
  8. /**
  9. * 图标类型
  10. */
  11. type: String,
  12. /**
  13. * 图标颜色
  14. */
  15. color: String,
  16. /**
  17. * 图标大小
  18. */
  19. size: [Number, String]
  20. },
  21. computed: {
  22. fontSize() {
  23. return `${this.size}px`
  24. }
  25. },
  26. methods: {
  27. onClick() {
  28. this.$emit('click')
  29. }
  30. }
  31. }
  32. </script>
  33. <style>
  34. @font-face {
  35. font-family: uniicons;
  36. font-weight: normal;
  37. font-style: normal;
  38. 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');
  39. }
  40. .uni-icon {
  41. font-family: uniicons;
  42. font-size: 24px;
  43. font-weight: normal;
  44. font-style: normal;
  45. line-height: 1;
  46. display: inline-block;
  47. text-decoration: none;
  48. -webkit-font-smoothing: antialiased;
  49. }
  50. .uni-icon.uni-active {
  51. color: #007aff;
  52. }
  53. .uni-icon-contact:before {
  54. content: '\e100';
  55. }
  56. .uni-icon-person:before {
  57. content: '\e101';
  58. }
  59. .uni-icon-personadd:before {
  60. content: '\e102';
  61. }
  62. .uni-icon-contact-filled:before {
  63. content: '\e130';
  64. }
  65. .uni-icon-person-filled:before {
  66. content: '\e131';
  67. }
  68. .uni-icon-personadd-filled:before {
  69. content: '\e132';
  70. }
  71. .uni-icon-phone:before {
  72. content: '\e200';
  73. }
  74. .uni-icon-email:before {
  75. content: '\e201';
  76. }
  77. .uni-icon-chatbubble:before {
  78. content: '\e202';
  79. }
  80. .uni-icon-chatboxes:before {
  81. content: '\e203';
  82. }
  83. .uni-icon-phone-filled:before {
  84. content: '\e230';
  85. }
  86. .uni-icon-email-filled:before {
  87. content: '\e231';
  88. }
  89. .uni-icon-chatbubble-filled:before {
  90. content: '\e232';
  91. }
  92. .uni-icon-chatboxes-filled:before {
  93. content: '\e233';
  94. }
  95. .uni-icon-weibo:before {
  96. content: '\e260';
  97. }
  98. .uni-icon-weixin:before {
  99. content: '\e261';
  100. }
  101. .uni-icon-pengyouquan:before {
  102. content: '\e262';
  103. }
  104. .uni-icon-chat:before {
  105. content: '\e263';
  106. }
  107. .uni-icon-qq:before {
  108. content: '\e264';
  109. }
  110. .uni-icon-videocam:before {
  111. content: '\e300';
  112. }
  113. .uni-icon-camera:before {
  114. content: '\e301';
  115. }
  116. .uni-icon-mic:before {
  117. content: '\e302';
  118. }
  119. .uni-icon-location:before {
  120. content: '\e303';
  121. }
  122. .uni-icon-mic-filled:before,
  123. .uni-icon-speech:before {
  124. content: '\e332';
  125. }
  126. .uni-icon-location-filled:before {
  127. content: '\e333';
  128. }
  129. .uni-icon-micoff:before {
  130. content: '\e360';
  131. }
  132. .uni-icon-image:before {
  133. content: '\e363';
  134. }
  135. .uni-icon-map:before {
  136. content: '\e364';
  137. }
  138. .uni-icon-compose:before {
  139. content: '\e400';
  140. }
  141. .uni-icon-trash:before {
  142. content: '\e401';
  143. }
  144. .uni-icon-upload:before {
  145. content: '\e402';
  146. }
  147. .uni-icon-download:before {
  148. content: '\e403';
  149. }
  150. .uni-icon-close:before {
  151. content: '\e404';
  152. }
  153. .uni-icon-redo:before {
  154. content: '\e405';
  155. }
  156. .uni-icon-undo:before {
  157. content: '\e406';
  158. }
  159. .uni-icon-refresh:before {
  160. content: '\e407';
  161. }
  162. .uni-icon-star:before {
  163. content: '\e408';
  164. }
  165. .uni-icon-plus:before {
  166. content: '\e409';
  167. }
  168. .uni-icon-minus:before {
  169. content: '\e410';
  170. }
  171. .uni-icon-circle:before,
  172. .uni-icon-checkbox:before {
  173. content: '\e411';
  174. }
  175. .uni-icon-close-filled:before,
  176. .uni-icon-clear:before {
  177. content: '\e434';
  178. }
  179. .uni-icon-refresh-filled:before {
  180. content: '\e437';
  181. }
  182. .uni-icon-star-filled:before {
  183. content: '\e438';
  184. }
  185. .uni-icon-plus-filled:before {
  186. content: '\e439';
  187. }
  188. .uni-icon-minus-filled:before {
  189. content: '\e440';
  190. }
  191. .uni-icon-circle-filled:before {
  192. content: '\e441';
  193. }
  194. .uni-icon-checkbox-filled:before {
  195. content: '\e442';
  196. }
  197. .uni-icon-closeempty:before {
  198. content: '\e460';
  199. }
  200. .uni-icon-refreshempty:before {
  201. content: '\e461';
  202. }
  203. .uni-icon-reload:before {
  204. content: '\e462';
  205. }
  206. .uni-icon-starhalf:before {
  207. content: '\e463';
  208. }
  209. .uni-icon-spinner:before {
  210. content: '\e464';
  211. }
  212. .uni-icon-spinner-cycle:before {
  213. content: '\e465';
  214. }
  215. .uni-icon-search:before {
  216. content: '\e466';
  217. }
  218. .uni-icon-plusempty:before {
  219. content: '\e468';
  220. }
  221. .uni-icon-forward:before {
  222. content: '\e470';
  223. }
  224. .uni-icon-back:before,
  225. .uni-icon-left-nav:before {
  226. content: '\e471';
  227. }
  228. .uni-icon-checkmarkempty:before {
  229. content: '\e472';
  230. }
  231. .uni-icon-home:before {
  232. content: '\e500';
  233. }
  234. .uni-icon-navigate:before {
  235. content: '\e501';
  236. }
  237. .uni-icon-gear:before {
  238. content: '\e502';
  239. }
  240. .uni-icon-paperplane:before {
  241. content: '\e503';
  242. }
  243. .uni-icon-info:before {
  244. content: '\e504';
  245. }
  246. .uni-icon-help:before {
  247. content: '\e505';
  248. }
  249. .uni-icon-locked:before {
  250. content: '\e506';
  251. }
  252. .uni-icon-more:before {
  253. content: '\e507';
  254. }
  255. .uni-icon-flag:before {
  256. content: '\e508';
  257. }
  258. .uni-icon-home-filled:before {
  259. content: '\e530';
  260. }
  261. .uni-icon-gear-filled:before {
  262. content: '\e532';
  263. }
  264. .uni-icon-info-filled:before {
  265. content: '\e534';
  266. }
  267. .uni-icon-help-filled:before {
  268. content: '\e535';
  269. }
  270. .uni-icon-more-filled:before {
  271. content: '\e537';
  272. }
  273. .uni-icon-settings:before {
  274. content: '\e560';
  275. }
  276. .uni-icon-list:before {
  277. content: '\e562';
  278. }
  279. .uni-icon-bars:before {
  280. content: '\e563';
  281. }
  282. .uni-icon-loop:before {
  283. content: '\e565';
  284. }
  285. .uni-icon-paperclip:before {
  286. content: '\e567';
  287. }
  288. .uni-icon-eye:before {
  289. content: '\e568';
  290. }
  291. .uni-icon-arrowup:before {
  292. content: '\e580';
  293. }
  294. .uni-icon-arrowdown:before {
  295. content: '\e581';
  296. }
  297. .uni-icon-arrowleft:before {
  298. content: '\e582';
  299. }
  300. .uni-icon-arrowright:before {
  301. content: '\e583';
  302. }
  303. .uni-icon-arrowthinup:before {
  304. content: '\e584';
  305. }
  306. .uni-icon-arrowthindown:before {
  307. content: '\e585';
  308. }
  309. .uni-icon-arrowthinleft:before {
  310. content: '\e586';
  311. }
  312. .uni-icon-arrowthinright:before {
  313. content: '\e587';
  314. }
  315. .uni-icon-pulldown:before {
  316. content: '\e588';
  317. }
  318. .uni-icon-closefill:before {
  319. content: '\e589';
  320. }
  321. .uni-icon-sound:before {
  322. content: "\e590";
  323. }
  324. .uni-icon-scan:before {
  325. content: "\e612";
  326. }
  327. </style>

uni-load-more

readme.md
复制代码
  1. ### LoadMore 加载更多
  2. 用于列表中,做滚动加载使用,展示 loading 的各种状态,组件名:``uni-load-more``,代码块: uLoadMore。
  3. **使用方式:**
  4. ``script`` 中引用组件

import uniLoadMore from "@/components/uni-load-more/uni-load-more.vue"
export default {

复制代码
  1. components: {uniLoadMore}

}

复制代码
  1. 在 ``template`` 中使用组件

<uni-load-more status="loading"></uni-load-more>

复制代码
  1. 实际效果参考:[https://github.com/dcloudio/uni-ui](https://github.com/dcloudio/uni-ui)
  2. **属性说明:**
  3. |属性名 |类型|默认值 |说明|
  4. |---|----|---|---|
  5. |status |String |more|loading 的状态,可选值:more(loading前)、loading(loading中)、noMore(没有更多了)|
  6. |show-icon |Boolean |true|是否显示 loading 图标|
  7. |color |String |#777777|图标和文字颜色 |
  8. |content-text |Object |```{contentdown: "上拉显示更多",contentrefresh: "正在加载...",contentnomore: "没有更多数据了"}```|各状态文字说明|
uni-load-more.vue
复制代码
  1. <template>
  2. <view class="uni-load-more">
  3. <view class="uni-load-more__img" v-show="status === 'loading' && showIcon">
  4. <view class="load1">
  5. <view :style="{background:color}"></view>
  6. <view :style="{background:color}"></view>
  7. <view :style="{background:color}"></view>
  8. <view :style="{background:color}"></view>
  9. </view>
  10. <view class="load2">
  11. <view :style="{background:color}"></view>
  12. <view :style="{background:color}"></view>
  13. <view :style="{background:color}"></view>
  14. <view :style="{background:color}"></view>
  15. </view>
  16. <view class="load3">
  17. <view :style="{background:color}"></view>
  18. <view :style="{background:color}"></view>
  19. <view :style="{background:color}"></view>
  20. <view :style="{background:color}"></view>
  21. </view>
  22. </view>
  23. <text class="uni-load-more__text" :style="{color:color}">{{status === 'more' ? contentText.contentdown : (status === 'loading' ? contentText.contentrefresh : contentText.contentnomore)}}</text>
  24. </view>
  25. </template>
  26. <script>
  27. export default {
  28. name: "uni-load-more",
  29. props: {
  30. status: {
  31. //上拉的状态:more-loading前;loading-loading中;noMore-没有更多了
  32. type: String,
  33. default: 'more'
  34. },
  35. showIcon: {
  36. type: Boolean,
  37. default: true
  38. },
  39. color: {
  40. type: String,
  41. default: "#999"
  42. },
  43. contentText: {
  44. type: Object,
  45. default () {
  46. return {
  47. contentdown: "上拉显示更多",
  48. contentrefresh: "正在加载...",
  49. contentnomore: "没有更多数据了"
  50. };
  51. }
  52. }
  53. },
  54. data() {
  55. return {}
  56. }
  57. }
  58. </script>
  59. <style lang="scss">
  60. .uni-load-more {
  61. display: flex;
  62. flex-direction: row;
  63. height: 80upx;
  64. align-items: center;
  65. justify-content: center;
  66. &__text {
  67. font-size: 26upx;
  68. color: $uni-text-color-grey;
  69. }
  70. &__img {
  71. height: 24px;
  72. width: 24px;
  73. margin-right: 10px;
  74. &>view {
  75. position: absolute;
  76. view {
  77. width: 6px;
  78. height: 2px;
  79. border-top-left-radius: 1px;
  80. border-bottom-left-radius: 1px;
  81. background: $uni-text-color-grey;
  82. position: absolute;
  83. opacity: 0.2;
  84. transform-origin: 50%;
  85. animation: load 1.56s ease infinite;
  86. &:nth-child(1) {
  87. transform: rotate(90deg);
  88. top: 2px;
  89. left: 9px;
  90. }
  91. &:nth-child(2) {
  92. transform: rotate(180deg);
  93. top: 11px;
  94. right: 0px;
  95. }
  96. &:nth-child(3) {
  97. transform: rotate(270deg);
  98. bottom: 2px;
  99. left: 9px;
  100. }
  101. &:nth-child(4) {
  102. top: 11px;
  103. left: 0px;
  104. }
  105. }
  106. }
  107. }
  108. }
  109. .load1,
  110. .load2,
  111. .load3 {
  112. height: 24px;
  113. width: 24px;
  114. }
  115. .load2 {
  116. transform: rotate(30deg);
  117. }
  118. .load3 {
  119. transform: rotate(60deg);
  120. }
  121. .load1 view:nth-child(1) {
  122. animation-delay: 0s;
  123. }
  124. .load2 view:nth-child(1) {
  125. animation-delay: 0.13s;
  126. }
  127. .load3 view:nth-child(1) {
  128. animation-delay: 0.26s;
  129. }
  130. .load1 view:nth-child(2) {
  131. animation-delay: 0.39s;
  132. }
  133. .load2 view:nth-child(2) {
  134. animation-delay: 0.52s;
  135. }
  136. .load3 view:nth-child(2) {
  137. animation-delay: 0.65s;
  138. }
  139. .load1 view:nth-child(3) {
  140. animation-delay: 0.78s;
  141. }
  142. .load2 view:nth-child(3) {
  143. animation-delay: 0.91s;
  144. }
  145. .load3 view:nth-child(3) {
  146. animation-delay: 1.04s;
  147. }
  148. .load1 view:nth-child(4) {
  149. animation-delay: 1.17s;
  150. }
  151. .load2 view:nth-child(4) {
  152. animation-delay: 1.30s;
  153. }
  154. .load3 view:nth-child(4) {
  155. animation-delay: 1.43s;
  156. }
  157. @-webkit-keyframes load {
  158. 0% {
  159. opacity: 1;
  160. }
  161. 100% {
  162. opacity: 0.2;
  163. }
  164. }
  165. </style>

uni-number-box

readme.md
复制代码
  1. ### NumberBox 数字输入框
  2. 带加减按钮的数字输入框,组件名:``uni-number-box``,代码块: uNumberBox。
  3. **使用方式:**
  4. ``script`` 中引用组件

import uniNumberBox from "@/components/uni-number-box/uni-number-box.vue"
export default {

复制代码
  1. components: {uniNumberBox}

}

复制代码
  1. 在 ``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>

复制代码
  1. 实际效果参考:[https://github.com/dcloudio/uni-ui](https://github.com/dcloudio/uni-ui)
  2. **NumberBox 属性说明:**
  3. |属性名 |类型 |默认值 |说明 |
  4. |--- |---- |--- |--- |
  5. |value |Number |0 |输入框当前值 |
  6. |min |Number |0 |最小值 |
  7. |max |Number |100 |最大值 |
  8. |step |Number |1 |每次点击改变的间隔大小 |
  9. |disabled |Boolean|false |是否为禁用状态 |
  10. **事件说明:**
  11. |事件名称 |说明 |
  12. |---|---|
  13. |change |输入框值改变时触发的事件,参数为输入框当前的 value|
uni-number-box.vue
复制代码
  1. <template>
  2. <view class="uni-numbox">
  3. <view class="uni-numbox__minus" :class="{'uni-numbox--disabled': disableSubtract||disabled}" @click="_calcValue('subtract')">-</view>
  4. <input class="uni-numbox__value" type="number" :disabled="disabled" :value="inputValue" @blur="_onBlur">
  5. <view class="uni-numbox__plus" :class="{'uni-numbox--disabled': disableAdd||disabled}" @click="_calcValue('add')">+</view>
  6. </view>
  7. </template>
  8. <script>
  9. export default {
  10. name: 'uni-number-box',
  11. props: {
  12. value: {
  13. type: Number,
  14. default: 1
  15. },
  16. min: {
  17. type: Number,
  18. default: 0
  19. },
  20. max: {
  21. type: Number,
  22. default: 9999
  23. },
  24. step: {
  25. type: Number,
  26. default: 1
  27. },
  28. disabled: {
  29. type: Boolean,
  30. default: false
  31. }
  32. },
  33. data() {
  34. return {
  35. inputValue: this.value
  36. }
  37. },
  38. computed: {
  39. disableSubtract() {
  40. return this.inputValue <= this.min
  41. },
  42. disableAdd() {
  43. return this.inputValue >= this.max
  44. }
  45. },
  46. watch: {
  47. value(val) {
  48. this.inputValue = val;
  49. },
  50. inputValue(val) {
  51. this.$emit('change', val);
  52. }
  53. },
  54. methods: {
  55. _calcValue(type) {
  56. if (this.disabled) {
  57. return
  58. }
  59. const scale = this._getDecimalScale()
  60. let value = this.inputValue * scale
  61. let step = this.step * scale
  62. if (type === 'subtract') {
  63. value -= step
  64. } else if (type === 'add') {
  65. value += step
  66. }
  67. if (value < this.min || value > this.max) {
  68. return
  69. }
  70. this.inputValue = value / scale;
  71. },
  72. _getDecimalScale() {
  73. let scale = 1
  74. // 浮点型
  75. if (~~this.step !== this.step) {
  76. scale = Math.pow(10, (this.step + '').split('.')[1].length)
  77. }
  78. return scale
  79. },
  80. _onBlur(event) {
  81. let value = event.detail.value
  82. if (!value) {
  83. this.inputValue = 0
  84. return
  85. }
  86. value = +value;
  87. if (value > this.max) {
  88. value = this.max
  89. } else if (value < this.min) {
  90. value = this.min
  91. }
  92. this.inputValue = value
  93. }
  94. }
  95. }
  96. </script>
  97. <style lang="scss">
  98. $numbox-btn-width:44upx;
  99. $numbox-input-width:44upx;
  100. $numbox-height:52upx;
  101. $uni-font-size-xxl:32upx;
  102. .uni-numbox {
  103. display: inline-flex;
  104. flex-direction: row;
  105. justify-content: flex-start;
  106. height: $numbox-height;
  107. position: relative;
  108. &:after {
  109. content: '';
  110. position: absolute;
  111. transform-origin: center;
  112. box-sizing: border-box;
  113. pointer-events: none;
  114. top: -50%;
  115. left: -50%;
  116. right: -50%;
  117. bottom: -50%;
  118. // border: 1px solid $uni-border-color;
  119. border-radius: $uni-border-radius-lg;
  120. transform: scale(.5);
  121. }
  122. &__minus,
  123. &__plus {
  124. margin: 0;
  125. // background-color: $uni-bg-color-grey;
  126. width: $numbox-btn-width;
  127. font-size: $uni-font-size-xxl;
  128. height: 100%;
  129. line-height: $numbox-height;
  130. text-align: center;
  131. color: $uni-text-color;
  132. position: relative;
  133. }
  134. &__value {
  135. position: relative;
  136. background-color: $uni-bg-color;
  137. width: $numbox-input-width;
  138. height: 100%;
  139. text-align: center;
  140. min-height: 40upx;
  141. font-size: 26upx;
  142. &:after {
  143. content: '';
  144. position: absolute;
  145. transform-origin: center;
  146. box-sizing: border-box;
  147. pointer-events: none;
  148. top: -50%;
  149. left: -50%;
  150. right: -50%;
  151. bottom: -50%;
  152. border-style: solid;
  153. border-color: $uni-border-color;
  154. border-left-width: 0px;
  155. border-right-width: 0px;
  156. border-top-width: 0;
  157. border-bottom-width: 0;
  158. transform: scale(.5);
  159. }
  160. }
  161. &--disabled {
  162. color: $uni-text-color-disable;
  163. }
  164. }
  165. </style>

uni-rate

readme.md
复制代码
  1. ### Rate 评分
  2. 评分组件,组件名:``uni-rate``,代码块: uRate。
  3. **使用方式:**
  4. ``script`` 中引用组件

import uniRate from "@/components/uni-rate/uni-rate.vue"
export default {

复制代码
  1. components: {uniRate}

}

复制代码
  1. 基本用法

<uni-rate value="2"></uni-rate>

复制代码
  1. 自定义星星大小

<uni-rate size="18" value="5"></uni-rate>

复制代码
  1. 设置评分数

<uni-rate max="10" value="5"></uni-rate>

复制代码
  1. 不可点击状态

<uni-rate disabled="true" value="3.5"></uni-rate>

复制代码
  1. 实际效果参考:[https://github.com/dcloudio/uni-ui](https://github.com/dcloudio/uni-ui)
  2. **属性说明:**
  3. |属性名|类型|默认值 |说明|
  4. |---|----|---|---|
  5. |value|Number|0|当前评分|
  6. |max|Number|5|最大的评分|
  7. |size|Number|24|星星的大小|
  8. |margin|Number|0|星星的间距|
  9. |color|String|#ececec|星星的颜色|
  10. |active-color|String|#ffca3e|选中状态的星星的颜色|
  11. |is-fill|Boolean|true|星星的类型,是否为实心类型|
  12. |disabled|Boolean|false|是否为不可点击状态|
  13. **事件说明:**
  14. |事件称名|说明|返回参数|
  15. |---|----|---|
  16. |change|Rate 的 value 改变时触发事件,返回参数为Rate的value|{value:Number}|
uni-rate.vue
复制代码
  1. <template>
  2. <view class="uni-rate">
  3. <view class="uni-rate-icon" v-for="(star,index) in stars" :key="index" :style="{marginLeft:margin+'px'}" @click="onClick(index)">
  4. <uni-icon :size="size" :color="color" :type="isFill === false || isFill === 'false' ? 'star' : 'star-filled'"></uni-icon>
  5. <view class="uni-rate-icon-on" :style="{width:star.activeWitch}">
  6. <uni-icon :size="size" :color="activeColor" type="star-filled"></uni-icon>
  7. </view>
  8. </view>
  9. </view>
  10. </template>
  11. <script>
  12. import uniIcon from '../uni-icon/uni-icon.vue'
  13. export default {
  14. name: "uni-rate",
  15. components: {
  16. uniIcon
  17. },
  18. props: {
  19. isFill: { //星星的类型,是否镂空
  20. type: [Boolean, String],
  21. default: true
  22. },
  23. color: { //星星的颜色
  24. type: String,
  25. default: '#ececec'
  26. },
  27. activeColor: { //星星选中状态颜色
  28. type: String,
  29. default: '#ffca3e'
  30. },
  31. size: { //星星的大小
  32. type: [Number, String],
  33. default: 24
  34. },
  35. value: { //当前评分
  36. type: [Number, String],
  37. default: 0
  38. },
  39. max: { //最大评分
  40. type: [Number, String],
  41. default: 5
  42. },
  43. margin: { //星星的间距
  44. type: [Number, String],
  45. default: 0
  46. },
  47. disabled: { //是否可点击
  48. type: [Boolean, String],
  49. default: false
  50. },
  51. id: {
  52. type: [Number, String],
  53. default: 1
  54. }
  55. },
  56. data() {
  57. // console.log('data')
  58. return {
  59. maxSync: this.max,
  60. valueSync: this.value
  61. }
  62. },
  63. computed: {
  64. stars() {
  65. const max = Number(this.maxSync) ? Number(this.maxSync) : 5
  66. const value = Number(this.valueSync) ? Number(this.valueSync) : 0
  67. const starList = []
  68. const floorValue = Math.floor(value)
  69. const ceilValue = Math.ceil(value)
  70. for (let i = 0; i < max; i++) {
  71. if (floorValue > i) {
  72. starList.push({
  73. activeWitch: '100%'
  74. })
  75. } else if (ceilValue - 1 === i) {
  76. starList.push({
  77. activeWitch: (value - floorValue) * 100 + '%'
  78. })
  79. } else {
  80. starList.push({
  81. activeWitch: '0'
  82. })
  83. }
  84. }
  85. return starList
  86. }
  87. },
  88. methods: {
  89. onClick(index) {
  90. if (this.disabled === true || this.disabled === 'true') {
  91. return
  92. }
  93. this.valueSync = index + 1
  94. this.$emit('change', {
  95. id: this.id,
  96. value: this.valueSync
  97. })
  98. }
  99. }
  100. }
  101. </script>
  102. <style lang="scss">
  103. .uni-rate {
  104. line-height: 0;
  105. font-size: 0;
  106. display: flex;
  107. flex-direction: row;
  108. &-icon {
  109. position: relative;
  110. line-height: 0;
  111. font-size: 0;
  112. display: inline-block;
  113. &-on {
  114. position: absolute;
  115. top: 0;
  116. left: 0;
  117. overflow: hidden;
  118. }
  119. }
  120. }
  121. </style>

uni-segmented-control

uni-segmented-control.vue
复制代码
  1. <template>
  2. <view class="segmented-control" :class="styleType" :style="wrapStyle">
  3. <view v-for="(item, index) in values" class="segmented-control-item" :class="styleType" :key="index" :style="index === currentIndex ? activeStyle : itemStyle" @click="onClick(index)">
  4. {{item}}
  5. </view>
  6. </view>
  7. </template>
  8. <script>
  9. export default {
  10. name: 'uni-segmented-control',
  11. props: {
  12. current: {
  13. type: Number,
  14. default: 0
  15. },
  16. values: {
  17. type: Array,
  18. default () {
  19. return [];
  20. }
  21. },
  22. activeColor: {
  23. type: String,
  24. default: '#007aff'
  25. },
  26. styleType: {
  27. type: String,
  28. default: 'button'
  29. }
  30. },
  31. data() {
  32. return {
  33. currentIndex: this.current
  34. }
  35. },
  36. watch: {
  37. current(val) {
  38. if (val !== this.currentIndex) {
  39. this.currentIndex = val;
  40. }
  41. }
  42. },
  43. computed: {
  44. wrapStyle() {
  45. let styleString = '';
  46. switch (this.styleType) {
  47. case 'text':
  48. styleString = `border:0;`;
  49. break;
  50. default:
  51. styleString = `border-color: ${this.activeColor}`;
  52. break;
  53. }
  54. return styleString;
  55. },
  56. itemStyle() {
  57. let styleString = '';
  58. switch (this.styleType) {
  59. case 'text':
  60. styleString = `color:#999;border-left:0;`;
  61. break;
  62. default:
  63. styleString = `color:${this.activeColor};border-color:${this.activeColor};`;
  64. break;
  65. }
  66. return styleString;
  67. },
  68. activeStyle() {
  69. let styleString = '';
  70. switch (this.styleType) {
  71. case 'text':
  72. styleString = `color:${this.activeColor};border-left:0;border-bottom-style:solid;border-bottom-width:4upx`;
  73. break;
  74. default:
  75. styleString = `color:#fff;border-color:${this.activeColor};background-color:${this.activeColor}`;
  76. break;
  77. }
  78. return styleString;
  79. }
  80. },
  81. methods: {
  82. onClick(index) {
  83. if (this.currentIndex !== index) {
  84. this.currentIndex = index;
  85. this.$emit('clickItem', index);
  86. }
  87. }
  88. },
  89. }
  90. </script>
  91. <style>
  92. .segmented-control {
  93. display: flex;
  94. flex-direction: row;
  95. justify-content: center;
  96. width: 75%;
  97. font-size: 28upx;
  98. border-radius: 10upx;
  99. box-sizing: border-box;
  100. margin: 0 auto;
  101. overflow: hidden;
  102. }
  103. .segmented-control.button {
  104. border: 2upx solid;
  105. }
  106. .segmented-control.text {
  107. border: 0;
  108. border-radius: 0upx;
  109. }
  110. .segmented-control-item {
  111. flex: 1;
  112. text-align: center;
  113. line-height: 60upx;
  114. box-sizing: border-box;
  115. }
  116. .segmented-control-item.button {
  117. border-left: 1upx solid;
  118. }
  119. .segmented-control-item.text {
  120. border-left: 0;
  121. }
  122. .segmented-control-item:first-child {
  123. border-left-width: 0;
  124. }
  125. </style>

uni-swipe-action

readme.md
复制代码
  1. ### SwipeAction 滑动操作
  2. 通过滑动触发选项的容器,组件名:``uni-swipe-action``
  3. **使用方式:**
  4. ``script`` 中引用组件

import uniSwipeAction from "@/components/uni-swipe-action"
export default {

复制代码
  1. components: {uniSwipeAction}

}

复制代码
  1. 一般用法

<uni-swipe-action :options="[

复制代码
  1. {
  2. text: '取消',
  3. style: {
  4. backgroundColor: '#007aff'
  5. }
  6. }, {
  7. text: '确认',
  8. style: {
  9. backgroundColor: '#dd524d'
  10. }
  11. }

]">

复制代码
  1. <view class='cont'>SwipeAction 基础使用场景</view>

</uni-swipe-action>

复制代码
  1. 禁止滑动

<uni-swipe-action :disabled="true" :options="[

复制代码
  1. {
  2. text: '取消',
  3. style: {
  4. backgroundColor: '#007aff'
  5. }
  6. }, {
  7. text: '确认',
  8. style: {
  9. backgroundColor: '#dd524d'
  10. }
  11. }

]">

复制代码
  1. <view class='cont'>点击按钮自动关闭</view>

</uni-swipe-action>

复制代码
  1. 传递点击事件

<uni-swipe-action @click="bindClick" :options="[

复制代码
  1. {
  2. text: '取消',
  3. style: {
  4. backgroundColor: '#007aff'
  5. }
  6. }, {
  7. text: '确认',
  8. style: {
  9. backgroundColor: '#dd524d'
  10. }
  11. }

]">

复制代码
  1. <view class='cont'>点击选项时触发事件</view>

</uni-swipe-action>

复制代码
  1. List 组件使用

<uni-list>

复制代码
  1. <uni-swipe-action :options="options1">
  2. <uni-list-item title="item1" show-arrow="false"></uni-list-item>
  3. </uni-swipe-action>
  4. <uni-swipe-action :options="options2">
  5. <uni-list-item title="item2" show-arrow="false"></uni-list-item>
  6. </uni-swipe-action>
  7. <uni-swipe-action :options="options3">
  8. <uni-list-item title="item3" show-arrow="false"></uni-list-item>
  9. </uni-swipe-action>

</uni-list>

复制代码
  1. **SwipeAction 属性说明:**
  2. |属性名|类型|默认值|是否必填 |说明|
  3. |:--|:--|:--|:--|:--|
  4. |is-opened|Boolean|false||是否为开启状态|
  5. |disabled|Boolean|false||是否禁止滑动|
  6. |auto-close|Boolean|true||在组件开启状态时点击组件,是否自动关闭|
  7. |options|Array<Object>|-||组件选项内容及样式|
  8. options 参数说明
  9. |参数|类型|是否必填|说明|
  10. |:--|:--|:--|:--|
  11. |text|String|是|按钮的文字|
  12. |style|Object||按钮样式{backgroundColor,color,fontSize},backgroundColor默认为:#C7C6CD,color默认为:#FFFFFF,fontSize默认为:28upx|
  13. **SwipeAction 事件说明:**
  14. |事件称名|说明|返回参数|
  15. |:--|:---|:--|
  16. |click|点击选项按钮时触发事件|{text,style,index} ,text(按钮文字)、style(按钮的样式)、index(下标)|
  17. |opened|完全打开时触发|-|
  18. |closed|完全关闭时触发|-|
uni-swipe-action.vue
复制代码
  1. <template>
  2. <view class="uni-swipe-action">
  3. <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}">
  4. <view class="uni-swipe-action__content">
  5. <slot></slot>
  6. </view>
  7. <view class="uni-swipe-action__btn-group" :id="elId">
  8. <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)">
  9. {{item.text}}
  10. </div>
  11. </view>
  12. </view>
  13. </view>
  14. </template>
  15. <script>
  16. export default {
  17. name: 'uni-swipe-action',
  18. props: {
  19. isOpened: {
  20. type: Boolean,
  21. default: false
  22. },
  23. disabled: {
  24. type: Boolean,
  25. default: false
  26. },
  27. autoClose: {
  28. type: Boolean,
  29. default: true
  30. },
  31. options: Array
  32. },
  33. watch: {
  34. isOpened(newValue, oldValue) {
  35. this.isShowBtn = newValue ? true : false;
  36. this.endMove();
  37. }
  38. },
  39. data() {
  40. const elId = `Uni_${Math.ceil(Math.random() * 10e5).toString(36)}`
  41. return {
  42. elId: elId,
  43. moveLength: 0,
  44. isMoving: false,
  45. direction: '',
  46. startX: 0,
  47. startY: 0,
  48. isShowBtn: false,
  49. btnGroupWidth: 0
  50. }
  51. },
  52. // #ifdef H5
  53. mounted() {
  54. let view = uni.createSelectorQuery().select(`#${this.elId}`);
  55. view.fields({
  56. size: true
  57. }, data => {
  58. this.btnGroupWidth = data.width;
  59. }).exec();
  60. if (this.isOpened === true) {
  61. this.isShowBtn = true;
  62. this.endMove();
  63. }
  64. },
  65. // #endif
  66. // #ifndef H5
  67. onReady() {
  68. let view = uni.createSelectorQuery().select(`#${this.elId}`);
  69. view.fields({
  70. size: true
  71. }, data => {
  72. this.btnGroupWidth = data.width;
  73. }).exec();
  74. if (this.isOpened === true) {
  75. this.isShowBtn = true;
  76. this.endMove();
  77. }
  78. },
  79. // #endif
  80. computed: {
  81. transformX() {
  82. return `translateX(${this.moveLength}px)`
  83. }
  84. },
  85. methods: {
  86. bindClickBtn(item, index) {
  87. this.$emit('click', {
  88. text: item.text,
  89. style: item.style,
  90. index: index,
  91. key: item.key
  92. })
  93. },
  94. bindClickCont(e) {
  95. if (this.isShowBtn && this.autoClose === true) {
  96. this.isShowBtn = false;
  97. this.endMove();
  98. }
  99. },
  100. touchStart(event) {
  101. this.startX = event.touches[0].pageX;
  102. this.startY = event.touches[0].pageY;
  103. },
  104. touchMove(event) {
  105. if (this.direction === 'Y' || this.disabled === true) {
  106. return;
  107. }
  108. var moveY = event.touches[0].pageY - this.startY,
  109. moveX = event.touches[0].pageX - this.startX;
  110. if (!this.isMoving && Math.abs(moveY) > Math.abs(moveX)) { //纵向滑动
  111. this.direction = 'Y';
  112. return;
  113. }
  114. this.direction = moveX > 0 ? 'right' : 'left';
  115. this.isMoving = true;
  116. },
  117. touchEnd(event) {
  118. this.isMoving = false;
  119. if (this.direction !== 'right' && this.direction !== 'left') {
  120. this.direction = '';
  121. return;
  122. }
  123. if (this.direction == 'right') {
  124. this.isShowBtn = false
  125. } else {
  126. this.isShowBtn = true
  127. }
  128. this.endMove()
  129. },
  130. endMove() {
  131. if (this.direction === 'Y' || this.disabled === true) {
  132. this.direction = '';
  133. return;
  134. }
  135. if (this.isShowBtn) {
  136. this.moveLength = -this.btnGroupWidth;
  137. this.$emit('opened');
  138. } else {
  139. this.moveLength = 0;
  140. this.$emit('closed');
  141. }
  142. this.direction = '';
  143. }
  144. }
  145. }
  146. </script>
  147. <style>
  148. @charset "UTF-8";
  149. .uni-swipe-action {
  150. width: 100%;
  151. overflow: hidden
  152. }
  153. .uni-swipe-action__container {
  154. background-color: #fff;
  155. width: 200%;
  156. display: flex;
  157. flex-direction: row;
  158. flex-wrap: wrap
  159. }
  160. .uni-swipe-action__container.animtion {
  161. transition: transform 350ms cubic-bezier(.165, .84, .44, 1)
  162. }
  163. .uni-swipe-action__content {
  164. width: 50%
  165. }
  166. .uni-swipe-action__btn-group {
  167. display: flex;
  168. flex-direction: row
  169. }
  170. .uni-swipe-action--btn {
  171. padding: 0 32upx;
  172. color: #fff;
  173. background-color: #c7c6cd;
  174. font-size: 28upx;
  175. display: inline-flex;
  176. text-align: center;
  177. flex-direction: row;
  178. align-items: center
  179. }
  180. </style>

config

api.js

复制代码
  1. import {
  2. apiBaseUrl
  3. } from './config.js';
  4. import * as common from './common.js' //引入common
  5. import * as db from './db.js' //引入common
  6. // 需要登陆的,都写到这里,否则就是不需要登陆的接口
  7. const methodsToken = [
  8. 'user.info',
  9. 'user.editinfo',
  10. 'user.changeavatar',
  11. 'user.logout',
  12. 'user.addgoodsbrowsing',
  13. 'user.delgoodsbrowsing',
  14. 'user.goodsbrowsing',
  15. 'user.goodscollection',
  16. 'user.goodscollectionlist',
  17. 'user.vuesaveusership',
  18. 'user.saveusership',
  19. 'user.getshipdetail',
  20. 'user.setdefship',
  21. 'user.editship',
  22. 'user.removeship',
  23. 'user.getusership',
  24. 'user.pay',
  25. 'user.orderevaluate',
  26. 'user.getuserdefaultship',
  27. 'user.issign',
  28. 'user.sign',
  29. 'user.mypoint',
  30. 'user.userpointlog',
  31. 'user.getbankcardlist',
  32. 'user.getdefaultbankcard',
  33. 'user.addbankcard',
  34. 'user.removebankcard',
  35. 'user.setdefaultbankcard',
  36. 'user.getbankcardinfo',
  37. 'user.editpwd',
  38. 'user.forgotpwd',
  39. 'user.recommend',
  40. 'user.balancelist',
  41. 'user.sharecode',
  42. 'user.cash',
  43. 'user.cashlist',
  44. 'user.myinvite',
  45. 'user.activationinvite',
  46. 'coupon.getcoupon',
  47. 'coupon.usercoupon',
  48. 'cart.add',
  49. 'cart.del',
  50. 'cart.getlist',
  51. 'cart.setnums',
  52. 'cart.getnumber',
  53. 'order.cancel',
  54. 'order.del',
  55. 'order.details',
  56. 'order.confirm',
  57. 'order.getlist',
  58. 'order.create',
  59. 'order.getship',
  60. 'order.getorderlist',
  61. 'order.getorderstatusnum',
  62. 'order.aftersaleslist',
  63. 'order.aftersalesinfo',
  64. 'order.aftersalesstatus',
  65. 'order.addaftersales',
  66. 'order.sendreship',
  67. 'order.iscomment',
  68. 'payments.getinfo',
  69. 'user.getuserpoint',
  70. 'coupon.getcouponkey',
  71. 'store.isclerk',
  72. 'store.storeladinglist',
  73. 'store.ladinginfo',
  74. 'store.lading',
  75. 'store.ladingdel',
  76. 'distribution_center-api-info',
  77. 'distribution_center-api-applydistribution',
  78. 'distribution_center-api-setstore',
  79. 'distribution_center-api-myorder',
  80. 'pintuan.pintuanteam',
  81. 'lottery-api-getLotteryConfig',
  82. 'lottery-api-lottery',
  83. 'lottery-api-lotteryLog'
  84. ];
  85. const post = (method, data, callback) => {
  86. uni.showLoading({
  87. title: '加载中'
  88. });
  89. // 判断token是否存在
  90. if (methodsToken.indexOf(method) >= 0) {
  91. // 获取用户token
  92. let userToken = db.get("userToken");
  93. if (!userToken) {
  94. common.jumpToLogin();
  95. return false;
  96. } else {
  97. data.token = userToken;
  98. }
  99. }
  100. data.method = method;
  101. uni.request({
  102. url: apiBaseUrl + 'api.html',
  103. data: data,
  104. header: {
  105. 'Accept': 'application/json',
  106. 'Content-Type': 'application/json',
  107. // 'Content-Type': 'application/x-www-form-urlencoded', //自定义请求头信息
  108. },
  109. method: 'POST',
  110. success: (response) => {
  111. uni.hideLoading();
  112. const result = response.data
  113. if (!result.status) {
  114. // 登录信息过期或者未登录
  115. if (result.data === 14007 || result.data === 14006) {
  116. db.del("userToken");
  117. uni.showToast({
  118. title: result.msg,
  119. icon: 'none',
  120. duration: 1000,
  121. complete: function() {
  122. setTimeout(function() {
  123. uni.hideToast();
  124. // #ifdef H5 || APP-PLUS
  125. uni.navigateTo({
  126. url: '/pages/login/login/index1'
  127. })
  128. // #endif
  129. // #ifdef MP-WEIXIN || MP-ALIPAY
  130. uni.navigateTo({
  131. url: '/pages/login/choose/index',
  132. animationType: 'pop-in',
  133. animationDuration: 200
  134. });
  135. // #endif
  136. }, 1000)
  137. }
  138. });
  139. }
  140. }
  141. callback(result);
  142. },
  143. complete: () => {
  144. uni.hideLoading();
  145. },
  146. fail: (error) => {
  147. uni.hideLoading();
  148. if (error && error.response) {
  149. showError(error.response);
  150. }
  151. },
  152. });
  153. }
  154. //插件post
  155. const pluginsPost = (method, data, callback) => {
  156. uni.showLoading({
  157. title: '加载中'
  158. });
  159. // 判断token是否存在
  160. if (methodsToken.indexOf(method) >= 0) {
  161. // 获取用户token
  162. let userToken = db.get("userToken");
  163. if (!userToken) {
  164. common.jumpToLogin();
  165. return false;
  166. } else {
  167. data.token = userToken;
  168. }
  169. }
  170. uni.request({
  171. url: apiBaseUrl + 'plugins/' + method + '.html',
  172. data: data,
  173. header: {
  174. 'Accept': 'application/json',
  175. 'Content-Type': 'application/json',
  176. // 'Content-Type': 'application/x-www-form-urlencoded', //自定义请求头信息
  177. },
  178. method: 'POST',
  179. success: (response) => {
  180. uni.hideLoading();
  181. const result = response.data
  182. if (!result.status) {
  183. // 登录信息过期或者未登录
  184. if (result.data === 14007 || result.data === 14006) {
  185. db.del("userToken");
  186. uni.showToast({
  187. title: result.msg,
  188. icon: 'none',
  189. duration: 1000,
  190. complete: function() {
  191. setTimeout(function() {
  192. uni.hideToast();
  193. // #ifdef H5 || APP-PLUS
  194. uni.navigateTo({
  195. url: '/pages/login/login/index1'
  196. })
  197. // #endif
  198. // #ifdef MP-WEIXIN || MP-ALIPAY
  199. uni.navigateTo({
  200. url: '/pages/login/choose/index',
  201. animationType: 'pop-in',
  202. animationDuration: 200
  203. });
  204. // #endif
  205. }, 1000);
  206. }
  207. });
  208. }
  209. }
  210. callback(result);
  211. },
  212. fail: (error) => {
  213. uni.hideLoading();
  214. if (error && error.response) {
  215. showError(error.response);
  216. }
  217. },
  218. complete: () => {
  219. setTimeout(function() {
  220. uni.hideLoading();
  221. }, 250);
  222. }
  223. });
  224. }
  225. const get = (url, callback) => {
  226. uni.showLoading({
  227. title: '加载中'
  228. });
  229. uni.request({
  230. url: url,
  231. header: {
  232. 'Accept': 'application/json',
  233. 'Content-Type': 'application/x-www-form-urlencoded', //自定义请求头信息
  234. },
  235. method: 'GET',
  236. success: (response) => {
  237. uni.hideLoading();
  238. callback(response.data);
  239. },
  240. fail: (error) => {
  241. uni.hideLoading();
  242. if (error && error.response) {
  243. showError(error.response);
  244. }
  245. },
  246. complete: () => {
  247. setTimeout(function() {
  248. uni.hideLoading();
  249. }, 250);
  250. }
  251. });
  252. }
  253. const showError = error => {
  254. let errorMsg = ''
  255. switch (error.status) {
  256. case 400:
  257. errorMsg = '请求参数错误'
  258. break
  259. case 401:
  260. errorMsg = '未授权,请登录'
  261. break
  262. case 403:
  263. errorMsg = '跨域拒绝访问'
  264. break
  265. case 404:
  266. errorMsg = `请求地址出错: ${error.config.url}`
  267. break
  268. case 408:
  269. errorMsg = '请求超时'
  270. break
  271. case 500:
  272. errorMsg = '服务器内部错误'
  273. break
  274. case 501:
  275. errorMsg = '服务未实现'
  276. break
  277. case 502:
  278. errorMsg = '网关错误'
  279. break
  280. case 503:
  281. errorMsg = '服务不可用'
  282. break
  283. case 504:
  284. errorMsg = '网关超时'
  285. break
  286. case 505:
  287. errorMsg = 'HTTP版本不受支持'
  288. break
  289. default:
  290. errorMsg = error.msg
  291. break
  292. }
  293. uni.showToast({
  294. title: errorMsg,
  295. icon: 'none',
  296. duration: 1000,
  297. complete: function() {
  298. setTimeout(function() {
  299. uni.hideToast();
  300. }, 1000);
  301. }
  302. });
  303. }
  304. // 文件上传
  305. export const uploadFiles = (callback) => {
  306. uni.chooseImage({
  307. success: (chooseImageRes) => {
  308. uni.showLoading({
  309. title: '上传中...'
  310. });
  311. const tempFilePaths = chooseImageRes.tempFilePaths;
  312. const uploadTask = uni.uploadFile({
  313. url: apiBaseUrl + 'api.html', //仅为示例,非真实的接口地址
  314. filePath: tempFilePaths[0],
  315. fileType: 'image',
  316. name: 'file',
  317. headers: {
  318. 'Accept': 'application/json',
  319. 'Content-Type': 'multipart/form-data',
  320. },
  321. formData: {
  322. 'method': 'images.upload',
  323. 'upfile': tempFilePaths[0]
  324. },
  325. success: (uploadFileRes) => {
  326. callback(JSON.parse(uploadFileRes.data));
  327. },
  328. fail: (error) => {
  329. if (error && error.response) {
  330. showError(error.response);
  331. }
  332. },
  333. complete: () => {
  334. setTimeout(function() {
  335. uni.hideLoading();
  336. }, 250);
  337. }
  338. });
  339. // uploadTask.onProgressUpdate((res) => {
  340. // console.log('上传进度' + res.progress);
  341. // console.log('已经上传的数据长度' + res.totalBytesSent);
  342. // console.log('预期需要上传的数据总长度' + res.totalBytesExpectedToSend);
  343. //
  344. // // 测试条件,取消上传任务。
  345. // if (res.progress > 50) {
  346. // uploadTask.abort();
  347. // }
  348. // });
  349. }
  350. });
  351. }
  352. // 上传图片
  353. export const uploadImage = (num, callback) => {
  354. uni.chooseImage({
  355. count: num,
  356. success: (res) => {
  357. uni.showLoading({
  358. title: '上传中...'
  359. });
  360. let tempFilePaths = res.tempFilePaths
  361. for (var i = 0; i < tempFilePaths.length; i++) {
  362. uni.uploadFile({
  363. url: apiBaseUrl + 'api.html',
  364. filePath: tempFilePaths[i],
  365. fileType: 'image',
  366. name: 'file',
  367. headers: {
  368. 'Accept': 'application/json',
  369. 'Content-Type': 'multipart/form-data',
  370. },
  371. formData: {
  372. 'method': 'images.upload',
  373. 'upfile': tempFilePaths[i]
  374. },
  375. success: (uploadFileRes) => {
  376. callback(JSON.parse(uploadFileRes.data));
  377. },
  378. fail: (error) => {
  379. if (error && error.response) {
  380. showError(error.response);
  381. }
  382. },
  383. complete: () => {
  384. setTimeout(function() {
  385. uni.hideLoading();
  386. }, 250);
  387. },
  388. });
  389. }
  390. }
  391. });
  392. }
  393. // 获取店铺配置
  394. export const shopConfig = (callback) => get(apiBaseUrl + 'api/common/jshopconf', callback);
  395. // 用户注册
  396. export const reg = (data, callback) => post('user.reg', data, callback);
  397. // 用户登录
  398. export const login = (data, callback) => post('user.login', data, callback);
  399. // 用户信息
  400. export const userInfo = (data, callback) => post('user.info', data, callback);
  401. // 上传头像
  402. export const changeAvatar = (data, callback) => post('user.changeavatar', data, callback);
  403. // 编辑用户信息
  404. export const editInfo = (data, callback) => post('user.editinfo', data, callback);
  405. // 发送短信验证码
  406. export const sms = (data, callback) => post('user.sms', data, callback);
  407. // 短信验证码登录
  408. export const smsLogin = (data, callback) => post('user.smslogin', data, callback);
  409. // 退出登录
  410. export const logout = (data, callback) => post('user.logout', data, callback);
  411. // 获取首页幻灯片
  412. export const slider = (data, callback) => post('advert.getAdvertList', data, callback);
  413. // 获取广告
  414. export const advert = (data, callback) => post('advert.getcarousellists', data, callback);
  415. // 获取公告列表
  416. export const notice = (data, callback) => post('notice.noticeList', data, callback);
  417. // 获取公告详情
  418. export const noticeInfo = (data, callback) => post('notice.noticeInfo', data, callback);
  419. // 获取文章详情
  420. export const articleInfo = (data, callback) => post('articles.getArticleDetail', data, callback);
  421. // 获取文章列表
  422. export const articleList = (data, callback) => post('articles.getArticleList', data, callback);
  423. // 获取商品分类
  424. export const categories = (data, callback) => post('categories.getallcat', data, callback);
  425. // 获取商品列表
  426. export const goodsList = (data, callback) => post('goods.getlist', data, callback);
  427. // 获取商品详情
  428. export const goodsDetail = (data, callback) => post('goods.getdetial', data, callback);
  429. // 获取商品参数信息
  430. export const goodsParams = (data, callback) => post('goods.getgoodsparams', data, callback);
  431. // 获取设置默认货品
  432. export const getProductInfo = (data, callback) => post('goods.getproductinfo', data, callback);
  433. // 获取商品评论信息
  434. export const goodsComment = (data, callback) => post('goods.getgoodscomment', data, callback);
  435. // 添加购物车
  436. export const addCart = (data, callback) => post('cart.add', data, callback);
  437. // 移除购物车
  438. export const removeCart = (data, callback) => post('cart.del', data, callback);
  439. // 获取购物车列表
  440. export const cartList = (data, callback) => post('cart.getlist', data, callback);
  441. // 设置购物车商品数量
  442. export const setCartNum = (data, callback) => post('cart.setnums', data, callback);
  443. // 获取购物车数量
  444. export const getCartNum = (data, callback) => post('cart.getnumber', data, callback);
  445. // 获取用户的收货地址列表
  446. export const userShip = (data, callback) => post('user.getusership', data, callback);
  447. // 获取用户默认收货地址
  448. export const userDefaultShip = (data, callback) => post('user.getuserdefaultship', data, callback);
  449. // 存储用户收货地址
  450. export const saveUserShip = (data, callback) => post('user.vuesaveusership', data, callback);
  451. // 微信存储收货地址
  452. export const saveUserShipWx = (data, callback) => post('user.saveusership', data, callback);
  453. //获取区域ID
  454. export const getAreaId = (data, callback) => post('user.getareaid', data, callback);
  455. // 获取收货地址详情
  456. export const shipDetail = (data, callback) => post('user.getshipdetail', data, callback);
  457. // 收货地址编辑
  458. export const editShip = (data, callback) => post('user.editship', data, callback);
  459. // 收货地址删除
  460. export const removeShip = (data, callback) => post('user.removeship', data, callback);
  461. // 设置默认收货地址
  462. export const setDefShip = (data, callback) => post('user.setdefship', data, callback);
  463. // 生成订单
  464. export const createOrder = (data, callback) => post('order.create', data, callback);
  465. // 获取状态订单列表
  466. export const getOrderList = (data, callback) => post('order.getlist', data, callback);
  467. // 取消订单
  468. export const cancelOrder = (data, callback) => post('order.cancel', data, callback);
  469. // 删除订单
  470. export const delOrder = (data, callback) => post('order.del', data, callback);
  471. // 获取订单详情
  472. export const orderDetail = (data, callback) => post('order.details', data, callback);
  473. // 确认收货
  474. export const confirmOrder = (data, callback) => post('order.confirm', data, callback);
  475. // 获取配送方式
  476. export const orderShip = (data, callback) => post('order.getship', data, callback);
  477. // 获取全部订单列表
  478. export const orderList = (data, callback) => post('order.getorderlist', data, callback);
  479. // 获取订单不同状态的数量
  480. export const getOrderStatusSum = (data, callback) => post('order.getorderstatusnum', data, callback);
  481. // 售后单列表
  482. export const afterSalesList = (data, callback) => post('order.aftersaleslist', data, callback);
  483. // 售后单详情
  484. export const afterSalesInfo = (data, callback) => post('order.aftersalesinfo', data, callback);
  485. // 订单售后状态
  486. export const afterSalesStatus = (data, callback) => post('order.aftersalesstatus', data, callback);
  487. // 添加售后单
  488. export const addAfterSales = (data, callback) => post('order.addaftersales', data, callback);
  489. // 用户发送退货包裹
  490. export const sendShip = (data, callback) => post('order.sendreship', data, callback);
  491. // 添加商品浏览足迹
  492. export const addGoodsBrowsing = (data, callback) => post('user.addgoodsbrowsing', data, callback);
  493. // 删除商品浏览足迹
  494. export const delGoodsBrowsing = (data, callback) => post('user.delgoodsbrowsing', data, callback);
  495. // 获取商品浏览足迹
  496. export const goodsBrowsing = (data, callback) => post('user.goodsbrowsing', data, callback);
  497. // 商品收藏 关注/取消
  498. export const goodsCollection = (data, callback) => post('user.goodscollection', data, callback);
  499. // 获取商品收藏关注列表
  500. export const goodsCollectionList = (data, callback) => post('user.goodscollectionlist', data, callback);
  501. // 获取店铺支付方式列表
  502. export const paymentList = (data, callback) => post('payments.getlist', data, callback);
  503. // 获取支付单详情
  504. export const paymentInfo = (data, callback) => post('payments.getinfo', data, callback);
  505. // 支付接口
  506. export const pay = (data, callback) => post('user.pay', data, callback);
  507. // 订单评价接口
  508. export const orderEvaluate = (data, callback) => post('user.orderevaluate', data, callback);
  509. // 判断是否签到
  510. export const isSign = (data, callback) => post('user.issign', data, callback);
  511. // 签到接口
  512. export const sign = (data, callback) => post('user.sign', data, callback);
  513. // 我的积分
  514. export const myPoint = (data, callback) => post('user.mypoint', data, callback);
  515. // 积分记录
  516. export const pointLog = (data, callback) => post('user.userpointlog', data, callback);
  517. // 物流信息接口
  518. export const logistics = (data, callback) => post('order.logisticbyapi', data, callback);
  519. // 优惠券列表
  520. export const couponList = (data, callback) => post('coupon.couponlist', data, callback);
  521. // 优惠券详情
  522. export const couponDetail = (data, callback) => post('coupon.coupondetail', data, callback);
  523. // 用户领取优惠券
  524. export const getCoupon = (data, callback) => post('coupon.getcoupon', data, callback);
  525. // 用户已领取的优惠券列表
  526. export const userCoupon = (data, callback) => post('coupon.usercoupon', data, callback);
  527. // 获取店铺设置
  528. export const getSetting = (data, callback) => post('user.getsetting', data, callback);
  529. // 获取商户配置信息
  530. export const getSellerSetting = (data, callback) => post('user.getsellersetting', data, callback);
  531. // 获取我的银行卡列表
  532. export const getBankCardList = (data, callback) => post('user.getbankcardlist', data, callback);
  533. // 获取默认的银行卡
  534. export const getDefaultBankCard = (data, callback) => post('user.getdefaultbankcard', data, callback);
  535. // 添加银行卡
  536. export const addBankCard = (data, callback) => post('user.addbankcard', data, callback);
  537. // 删除银行卡
  538. export const removeBankCard = (data, callback) => post('user.removebankcard', data, callback);
  539. // 设置默认银行卡
  540. export const setDefaultBankCard = (data, callback) => post('user.setdefaultbankcard', data, callback);
  541. // 获取银行卡信息
  542. export const getBankCardInfo = (data, callback) => post('user.getbankcardinfo', data, callback);
  543. // 获取银行卡组织信息
  544. export const getBankCardOrganization = (data, callback) => post('user.getbankcardorganization', data, callback);
  545. // 用户修改密码
  546. export const editPwd = (data, callback) => post('user.editpwd', data, callback);
  547. // 用户找回密码
  548. export const forgotPwd = (data, callback) => post('user.forgotpwd', data, callback);
  549. // 获取用户余额明细
  550. export const getBalanceList = (data, callback) => post('user.balancelist', data, callback);
  551. // 用户推荐列表
  552. export const recommendList = (data, callback) => post('user.recommend', data, callback);
  553. // 邀请码
  554. export const shareCode = (data, callback) => post('user.sharecode', data, callback);
  555. // 用户提现
  556. export const userToCash = (data, callback) => post('user.cash', data, callback);
  557. // 用户提现列表
  558. export const cashList = (data, callback) => post('user.cashlist', data, callback);
  559. // 绑定授权登录
  560. export const trustBind = (data, callback) => post('user.trustbind', data, callback);
  561. // 获取用户信息
  562. // export const trustLogin = (data, callback) => post('user.trustcallback', data, callback);
  563. // 判断用户下单可以使用多少积分
  564. export const usablePoint = (data, callback) => post('user.getuserpoint', data, callback);
  565. // 门店列表
  566. export const storeList = (data, callback) => post('store.getstorelist', data, callback);
  567. // 判断是否开启门店自提
  568. export const switchStore = (data, callback) => post('store.getstoreswitch', data, callback);
  569. // 获取默认的门店
  570. export const defaultStore = (data, callback) => post('store.getdefaultstore', data, callback);
  571. // 判断是否开启积分
  572. export const isPoint = (data, callback) => post('user.ispoint', data, callback);
  573. // 用户输入code领取优惠券
  574. export const couponKey = (data, callback) => post('coupon.getcouponkey', data, callback);
  575. // 判断是否是店员
  576. export const isStoreUser = (data, callback) => post('store.isclerk', data, callback);
  577. // 获取店铺提货单列表
  578. export const storeLadingList = (data, callback) => post('store.storeladinglist', data, callback);
  579. // 获取提货单详情
  580. export const ladingInfo = (data, callback) => post('store.ladinginfo', data, callback);
  581. // 店铺提单操作
  582. export const ladingExec = (data, callback) => post('store.lading', data, callback);
  583. // 提货单删除
  584. export const ladingDel = (data, callback) => post('store.ladingdel', data, callback);
  585. // 获取活动列表
  586. export const activityList = (data, callback) => post('group.getlist', data, callback);
  587. // 获取活动详情
  588. export const activityDetail = (data, callback) => post('group.getgoodsdetial', data, callback);
  589. //小程序解析code
  590. export const login1 = (data, callback) => post('user.wxapplogin1', data, callback);
  591. //小程序登录第二步
  592. export const login2 = (data, callback) => post('user.wxapplogin2', data, callback);
  593. //支付宝小程序解析code
  594. export const alilogin1 = (data, callback) => post('user.alipayapplogin1', data, callback);
  595. //取下级地址列表
  596. export const getAreaList = (data, callback) => post('user.getarealist', data, callback);
  597. //取搜索页推荐关键字
  598. export const getRecommendKeys = (callback) => post('store.getrecommendkeys', {}, callback);
  599. // 获取我的邀请信息
  600. export const myInvite = (callback) => post('user.myinvite', {}, callback);
  601. // 设置我的上级邀请人
  602. export const setMyInvite = (data, callback) => post('user.activationinvite', data, callback);
  603. // 获取小程序二维码
  604. export const getInviteQRCode = (data, callback) => post('store.getinviteqrcode', data, callback);
  605. // 生成海报
  606. export const createPoster = (data, callback) => post('user.getposter', data, callback);
  607. // 获取秒杀团购
  608. export const getGroup = (data, callback) => post('group.getlist', data, callback);
  609. // 获取秒杀团购详情
  610. export const groupInfo = (data, callback) => post('group.getgoodsdetial', data, callback);
  611. // 自定义页面
  612. export const getPageConfig = (data, callback) => post('pages.getpageconfig', data, callback);
  613. //万能表单
  614. export const getFormDetial = (data, callback) => post('form.getformdetial', data, callback);
  615. //提交表单
  616. export const addSubmitForm = (data, callback) => post('form.addsubmit', data, callback);
  617. //公众号授权获取openid
  618. export const getOpenId = (data, callback) => post('user.officiallogin', data, callback);
  619. // 获取授权登录方式
  620. export const getTrustLogin = (data, callback) => post('user.gettrustlogin', data, callback);
  621. // APP信任登录
  622. export const appTrustLogin = (data, callback) => post('user.uniapplogin', data, callback);
  623. // 获取分销商进度状态
  624. export const getDistributioninfo = (data, callback) => pluginsPost('distribution_center-api-info', data, callback);
  625. // 申请分销商
  626. export const applyDistribution = (data, callback) => pluginsPost('distribution_center-api-applydistribution', data,
  627. callback);
  628. // 店铺设置
  629. export const setStore = (data, callback) => pluginsPost('distribution_center-api-setstore', data, callback);
  630. //我的分销订单
  631. export const getStoreInfo = (data, callback) => pluginsPost('distribution_center-api-getstoreinfo', data, callback);
  632. //我的分销订单
  633. export const getDistributionOrder = (data, callback) => pluginsPost('distribution_center-api-myorder', data, callback);
  634. // 拼团列表
  635. export const pintuanList = (data, callback) => post('pintuan.list', data, callback);
  636. // 拼团商品详情
  637. export const pintuanGoodsInfo = (data, callback) => post('pintuan.goodsinfo', data, callback);
  638. // 拼团货品详情
  639. export const pintuanProductInfo = (data, callback) => post('pintuan.productinfo', data, callback);
  640. //微信图文消息
  641. export const messageDetail = (data, callback) => post('articles.getweixinmessage', data, callback);
  642. //获取APP版本
  643. export const getAppVersion = (data, callback) => pluginsPost('app-api-checkVersion', data, callback);
  644. //获取APP版本
  645. export const getOrderPintuanTeamInfo = (data, callback) => post('pintuan.pintuanteam', data, callback);
  646. //抽奖规则
  647. export const lotteryConfig = (callback) => pluginsPost('lottery-api-getLotteryConfig', {}, callback);
  648. //抽奖操作
  649. export const lottery = (callback) => pluginsPost('lottery-api-lottery', {}, callback);
  650. //获取我的抽奖记录
  651. export const myLottery = (data, callback) => pluginsPost('lottery-api-lotteryLog', data, callback);
  652. //生成分享URL
  653. export const createShareUrl = (data, callback) => post('user.shareurl', data, callback);

common.js

复制代码
  1. import * as db from './db.js' //引入common
  2. import store from './../store'
  3. //把obj对象里的值覆盖到newobj里面
  4. function deepCopy(newobj, obj) {
  5. if (typeof obj != 'object') {
  6. return obj
  7. }
  8. for (var attr in obj) {
  9. var a = {}
  10. if (newobj[attr]) {
  11. a = newobj[attr]
  12. }
  13. newobj[attr] = deepCopy(a, obj[attr])
  14. }
  15. return newobj
  16. }
  17. //跳转到登陆页面
  18. function jumpToLogin(method) {
  19. var now_time = Date.parse(new Date())
  20. var value = db.get('jump_to_login')
  21. if (!value) {
  22. value = 0
  23. }
  24. if (now_time - value > 3000) {
  25. //db.set('jump_to_login',now_time); //暂时屏蔽登录时间查询
  26. // 将当前页面route存vuex中 登录注册后跳转
  27. let pages = getCurrentPages()
  28. let page = pages[pages.length - 1]
  29. // 获取页面参数信息
  30. let pagePath = ''
  31. // #ifdef H5 || MP-WEIXIN || APP-PLUS || APP-PLUS-NVUE
  32. if (page.route.indexOf('pages/goods/index/index') !== -1) {
  33. //商品详情页
  34. if (page.goodsId) {
  35. pagePath = '/' + page.route + '?id=' + page.goodsId;
  36. } else {
  37. pagePath = '/pages/index/index';
  38. }
  39. }
  40. if (page.route.indexOf('pages/goods/index/group') !== -1) {
  41. //团购秒杀详情页
  42. if (page.goodsId && page.groupId) {
  43. pagePath = '/' + page.route + '?id=' + page.goodsId + '&group_id' + page.groupId;
  44. } else {
  45. pagePath = '/pages/index/index';
  46. }
  47. }
  48. // #endif
  49. // #ifdef MP-ALIPAY
  50. if (page.__proto__.route.indexOf('pages/goods/index/index') !== -1) {
  51. //商品详情页
  52. if (page.rootVM.goodsId) {
  53. pagePath = '/' + page.__proto__.route + '?id=' + page.rootVM.goodsId;
  54. } else {
  55. pagePath = '/pages/index/index';
  56. }
  57. }
  58. if (page.__proto__.route.indexOf('pages/goods/index/group') !== -1) {
  59. //团购秒杀详情页
  60. if (page.rootVM.goodsId && page.rootVM.groupId) {
  61. pagePath = '/' + page.__proto__.route + '?id=' + page.rootVM.goodsId + '&group_id' + page.rootVM.groupId;
  62. } else {
  63. pagePath = '/pages/index/index';
  64. }
  65. }
  66. // #endif
  67. if (pagePath) {
  68. store.commit({
  69. type: 'redirect',
  70. page: pagePath
  71. })
  72. }
  73. uni.showToast({
  74. title: '请先登录!',
  75. icon: 'none',
  76. duration: 1000,
  77. success: function(res) {
  78. // #ifdef H5 || APP-PLUS
  79. setTimeout(() => {
  80. uni.hideToast();
  81. uni.navigateTo({
  82. url: '/pages/login/login/index1'
  83. })
  84. }, 1000)
  85. // #endif
  86. // #ifdef MP-WEIXIN || MP-ALIPAY
  87. setTimeout(() => {
  88. uni.hideToast();
  89. uni.navigateTo({
  90. url: '/pages/login/choose/index',
  91. animationType: 'pop-in',
  92. animationDuration: 200
  93. })
  94. }, 500)
  95. // #endif
  96. }
  97. })
  98. }
  99. }
  100. //当出错的时候,显示错误信息,并且跳转 弃用
  101. /* function errorToBack(msg = '出错了,请重试',delta=1){
  102. uni.showToast({
  103. title: msg,
  104. icon: 'none',
  105. duration: 2000,
  106. });
  107. if(delta > 0){
  108. setTimeout(function () {
  109. uni.navigateBack({
  110. delta: delta
  111. })
  112. }, 1000);
  113. }
  114. } */
  115. //操作成功后,的提示信息
  116. function successToShow(msg = '保存成功', callback = function() {}) {
  117. setTimeout(function() {
  118. uni.showToast({
  119. title: msg,
  120. icon: 'success',
  121. duration: 1000,
  122. success() {
  123. setTimeout(function() {
  124. callback()
  125. }, 500)
  126. }
  127. })
  128. }, 100)
  129. /* uni.showToast({
  130. title: msg,
  131. icon: 'success',
  132. duration: 1000
  133. }) */
  134. }
  135. //操作失败的提示信息
  136. function errorToShow(msg = '操作失败', callback = function() {}) {
  137. setTimeout(function() {
  138. uni.showToast({
  139. title: msg,
  140. icon: 'none',
  141. duration: 1500,
  142. success() {
  143. setTimeout(function() {
  144. callback()
  145. }, 1500)
  146. }
  147. })
  148. },100)
  149. }
  150. //加载显示
  151. function loadToShow(msg = '加载中') {
  152. uni.showToast({
  153. title: msg,
  154. icon: 'loading'
  155. })
  156. }
  157. //加载隐藏
  158. function loadToHide() {
  159. uni.hideToast()
  160. }
  161. // 提示框
  162. function modelShow(
  163. title = '提示',
  164. content = '确认执行此操作吗?',
  165. callback = () => {},
  166. showCancel = true,
  167. cancelText = '取消',
  168. confirmText = '确定'
  169. ) {
  170. uni.showModal({
  171. title: title,
  172. content: content,
  173. showCancel: showCancel,
  174. cancelText: cancelText,
  175. confirmText: confirmText,
  176. cancelText: cancelText,
  177. success: function(res) {
  178. if (res.confirm) {
  179. // 用户点击确定操作
  180. setTimeout(() => {
  181. callback()
  182. }, 500)
  183. } else if (res.cancel) {
  184. // 用户取消操作
  185. }
  186. }
  187. })
  188. }
  189. //时间戳转时间格式
  190. function timeToDate(date, flag = false) {
  191. var date = new Date(date * 1000) //如果date为13位不需要乘1000
  192. var Y = date.getFullYear() + '-'
  193. var M =
  194. (date.getMonth() + 1 < 10 ?
  195. '0' + (date.getMonth() + 1) :
  196. date.getMonth() + 1) + '-'
  197. var D = (date.getDate() < 10 ? '0' + date.getDate() : date.getDate()) + ' '
  198. var h = (date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + ':'
  199. var m =
  200. (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()) + ':'
  201. var s = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
  202. if (flag) {
  203. return Y + M + D
  204. } else {
  205. return Y + M + D + h + m + s
  206. }
  207. }
  208. function time2date(micro_second) {
  209. var time = {}
  210. // 总秒数
  211. var second = Math.floor(micro_second)
  212. // 天数
  213. time.day = PrefixInteger(Math.floor(second / 3600 / 24), 2)
  214. // 小时
  215. time.hour = PrefixInteger(Math.floor((second / 3600) % 24), 2)
  216. // 分钟
  217. time.minute = PrefixInteger(Math.floor((second / 60) % 60), 2)
  218. // 秒
  219. time.second = PrefixInteger(Math.floor(second % 60), 2)
  220. var newtime = ''
  221. if (time.day > 0) {
  222. newtime =
  223. time.day +
  224. '天' +
  225. time.hour +
  226. '小时' +
  227. time.minute +
  228. '分' +
  229. time.second +
  230. '秒'
  231. } else {
  232. if (time.hour != 0) {
  233. newtime = time.hour + '小时' + time.minute + '分' + time.second + '秒'
  234. } else {
  235. newtime = time.minute + '分' + time.second + '秒'
  236. }
  237. }
  238. return newtime
  239. }
  240. function timeToDateObj(micro_second) {
  241. var time = {}
  242. // 总秒数
  243. var second = Math.floor(micro_second)
  244. // 天数
  245. time.day = Math.floor(second / 3600 / 24)
  246. // 小时
  247. time.hour = Math.floor((second / 3600) % 24)
  248. // 分钟
  249. time.minute = Math.floor((second / 60) % 60)
  250. // 秒
  251. time.second = Math.floor(second % 60)
  252. return time
  253. }
  254. //货币格式化
  255. function formatMoney(number, places, symbol, thousand, decimal) {
  256. number = number || 0
  257. places = !isNaN((places = Math.abs(places))) ? places : 2
  258. symbol = symbol !== undefined ? symbol : '¥'
  259. thousand = thousand || ','
  260. decimal = decimal || '.'
  261. var negative = number < 0 ? '-' : '',
  262. i = parseInt((number = Math.abs(+number || 0).toFixed(places)), 10) + '',
  263. j = (j = i.length) > 3 ? j % 3 : 0
  264. return (
  265. symbol +
  266. negative +
  267. (j ? i.substr(0, j) + thousand : '') +
  268. i.substr(j).replace(/(\d{3})(?=\d)/g, '$1' + thousand) +
  269. (places ?
  270. decimal +
  271. Math.abs(number - i)
  272. .toFixed(places)
  273. .slice(2) :
  274. '')
  275. )
  276. }
  277. function throttle(fn, context, delay) {
  278. clearTimeout(fn.timeoutId)
  279. fn.timeoutId = setTimeout(function() {
  280. fn.call(context)
  281. }, delay)
  282. }
  283. // 时间格式化输出,如11:03 25:19 每1s都会调用一次
  284. function dateformat(micro_second) {
  285. var time = {}
  286. // 总秒数
  287. var second = Math.floor(micro_second / 1000) // 天数
  288. time.day = PrefixInteger(Math.floor(second / 3600 / 24), 2) // 小时
  289. time.hour = PrefixInteger(Math.floor((second / 3600) % 24), 2) // 分钟
  290. time.minute = PrefixInteger(Math.floor((second / 60) % 60), 2) // 秒
  291. time.second = PrefixInteger(Math.floor(second % 60), 2)
  292. return time
  293. }
  294. //不足位数前面补0
  295. function PrefixInteger(num, length) {
  296. return (Array(length).join('0') + num).slice(-length)
  297. }
  298. //验证是否是手机号
  299. function isPhoneNumber(str) {
  300. var myreg = /^[1][3,4,5,6,7,8,9][0-9]{9}$/
  301. if (!myreg.test(str)) {
  302. return false
  303. } else {
  304. return true
  305. }
  306. }
  307. /**
  308. *
  309. * 对象参数转为url参数
  310. *
  311. */
  312. function builderUrlParams(url, data) {
  313. if (typeof url == 'undefined' || url == null || url == '') {
  314. return ''
  315. }
  316. if (typeof data == 'undefined' || data == null || typeof data != 'object') {
  317. return ''
  318. }
  319. url += url.indexOf('?') != -1 ? '' : '?'
  320. for (var k in data) {
  321. url += (url.indexOf('=') != -1 ? '&' : '') + k + '=' + encodeURI(data[k])
  322. }
  323. return url
  324. }
  325. /**
  326. * 使用循环的方式判断一个元素是否存在于一个数组中
  327. * @param {Object} arr 数组
  328. * @param {Object} value 元素值
  329. */
  330. function isInArray(arr, value) {
  331. for (var i = 0; i < arr.length; i++) {
  332. if (value === arr[i]) {
  333. return true
  334. }
  335. }
  336. return false
  337. }
  338. /**
  339. * 统一跳转
  340. */
  341. function navigateTo(url) {
  342. uni.navigateTo({
  343. url: url,
  344. animationType: 'pop-in',
  345. animationDuration: 300
  346. })
  347. }
  348. /**
  349. * 关闭当前页面并跳转
  350. */
  351. function redirectTo(url) {
  352. uni.redirectTo({
  353. url: url,
  354. animationType: 'pop-in',
  355. animationDuration: 300
  356. })
  357. }
  358. /**
  359. * 获取url参数
  360. *
  361. * @param {*} name
  362. * @param {*} [url=window.location.serach]
  363. * @returns
  364. */
  365. function getQueryString(name, url) {
  366. var url = url || window.location.href
  367. var reg = new RegExp('(^|&|/?)' + name + '=([^&|/?]*)(&|/?|$)', 'i')
  368. var r = url.substr(1).match(reg)
  369. if (r != null) {
  370. return r[2]
  371. }
  372. return null
  373. }
  374. /**
  375. *
  376. * 判断是否在微信浏览器 true是
  377. */
  378. function isWeiXinBrowser() {
  379. // #ifdef H5
  380. // window.navigator.userAgent属性包含了浏览器类型、版本、操作系统类型、浏览器引擎类型等信息,这个属性可以用来判断浏览器类型
  381. let ua = window.navigator.userAgent.toLowerCase()
  382. // 通过正则表达式匹配ua中是否含有MicroMessenger字符串
  383. if (ua.match(/MicroMessenger/i) == 'micromessenger') {
  384. return true
  385. } else {
  386. return false
  387. }
  388. // #endif
  389. return false
  390. }
  391. /**
  392. * 金额相加
  393. * @param {Object} value1
  394. * @param {Object} value2
  395. */
  396. function moneySum(value1, value2) {
  397. return (parseFloat(value1) + parseFloat(value2)).toFixed(2);
  398. }
  399. /**
  400. * 金额相减
  401. * @param {Object} value1
  402. * @param {Object} value2
  403. */
  404. function moneySub(value1, value2) {
  405. let res = (parseFloat(value1) - parseFloat(value2)).toFixed(2);
  406. return res > 0 ? res : 0;
  407. }
  408. /**
  409. * 分享URL解压缩
  410. * @param {Object} url
  411. */
  412. function shareParameterEncode(url) {
  413. let urlArray = url.split('-');
  414. let newUrl = 'type=' + urlArray[0] + '&invite=' + urlArray[1] + '&id=' + urlArray[2] + '&team_id=' + urlArray[3] +
  415. '&id_type=' + urlArray[4] + '&page_code=' + urlArray[5] + '&group_id=' + urlArray[6];
  416. return newUrl;
  417. }
  418. /**
  419. * 分享URL压缩
  420. * @param {Object} url
  421. */
  422. function shareParameterDecode(url) {
  423. var urlArray = url.split('&');
  424. var allParameter = {
  425. 'type': '',
  426. 'invite': '',
  427. 'id': '',
  428. 'team_id': '',
  429. 'id_type': '',
  430. 'page_code': '',
  431. 'group_id': '',
  432. };
  433. for (var i = 0; i < urlArray.length; i++) {
  434. var parameter = urlArray[i].split('=');
  435. allParameter[parameter[0]] = parameter[1];
  436. }
  437. var newUrl = allParameter.type + '-' + allParameter.invite + '-' + allParameter.id + '-' + allParameter.team_id + '-' +
  438. allParameter.id_type + '-' + allParameter.page_code + '-' + allParameter.group_id;
  439. return newUrl;
  440. }
  441. export {
  442. deepCopy,
  443. jumpToLogin,
  444. timeToDate,
  445. formatMoney,
  446. /* errorToBack, */
  447. successToShow,
  448. throttle,
  449. errorToShow,
  450. time2date,
  451. isPhoneNumber,
  452. isInArray,
  453. loadToShow,
  454. loadToHide,
  455. navigateTo,
  456. redirectTo,
  457. modelShow,
  458. builderUrlParams,
  459. isWeiXinBrowser,
  460. dateformat,
  461. getQueryString,
  462. timeToDateObj,
  463. moneySum,
  464. moneySub,
  465. shareParameterEncode,
  466. shareParameterDecode
  467. }

config.js

复制代码
  1. export const apiBaseUrl = 'http://www.b2c.com/'
  2. // #ifdef H5
  3. export const baseUrl=process.env.NODE_ENV === 'development'?window.location.origin+'/':apiBaseUrl
  4. // #endif
  5. export const paymentType = {
  6. //支付单类型
  7. order: 1, //订单
  8. recharge: 2, //充值
  9. form_order: 5, //表单付款码
  10. form_pay: 6 //表单订单
  11. }

db.js

复制代码
  1. import * as common from './common.js' //引入common
  2. //取值
  3. function get(key,sync = true) {
  4. try {
  5. if(sync){
  6. return uni.getStorageSync(key);
  7. }else{
  8. let data = '';
  9. uni.getStorage({
  10. key:key,
  11. success: function (res) {
  12. data = res.data;
  13. }
  14. });
  15. return data;
  16. }
  17. } catch (e) {
  18. return false;
  19. }
  20. }
  21. //赋值
  22. function set(key, value, sync = true) {
  23. try {
  24. if (sync) {
  25. return uni.setStorageSync(key, value);
  26. } else {
  27. uni.setStorage({
  28. key: key,
  29. data: value
  30. });
  31. }
  32. } catch (e) {
  33. }
  34. }
  35. //移除
  36. function del(key, sync = true){
  37. try {
  38. if (sync) {
  39. return uni.removeStorageSync(key);
  40. } else {
  41. uni.removeStorage({
  42. key: key
  43. });
  44. }
  45. } catch (e) {
  46. return false;
  47. }
  48. }
  49. //清空
  50. function clear(sync = true){
  51. try {
  52. if (sync) {
  53. return uni.clearStorageSync();
  54. } else {
  55. uni.clearStorage();
  56. }
  57. } catch (e) {
  58. return false;
  59. }
  60. }
  61. //获取用户token,如果缓存有,直接返回,如果没有,就先微信登陆,然后服务器登陆,最后返回token
  62. function userToken(callback) {
  63. var token = get('userToken');
  64. if (token){
  65. callback(token);
  66. }else{
  67. //如果没有登陆,就去登陆
  68. common.jumpToLogin();
  69. }
  70. }
  71. export {
  72. get,
  73. set,
  74. del,
  75. clear,
  76. userToken
  77. }

mixins.js

复制代码
  1. export const orders = {
  2. mounted() {},
  3. methods: {
  4. // 查看订单详情
  5. orderDetail(orderId) {
  6. this.$common.navigateTo(
  7. '/pages/member/order/orderdetail?order_id=' + orderId
  8. )
  9. },
  10. // 取消订单
  11. // 去支付
  12. toPay(orderId) {
  13. this.$common.navigateTo(
  14. '/pages/goods/payment/index?order_id=' + orderId + '&type=1'
  15. )
  16. },
  17. // 确认收货
  18. // 去评价
  19. toEvaluate(orderId) {
  20. this.$common.navigateTo(
  21. '/pages/member/order/evaluate?order_id=' + orderId
  22. )
  23. },
  24. // 申请售后
  25. // 查看物流信息
  26. showExpress(code, no, address = '') {
  27. let params = encodeURIComponent(
  28. 'code=' + code + '&no=' + no + '&add=' + address
  29. )
  30. this.$common.navigateTo(
  31. '/pages/member/order/express_delivery?params=' + params
  32. )
  33. }
  34. }
  35. }
  36. /**
  37. * 商品接口信息
  38. *
  39. */
  40. export const goods = {
  41. mounted() {},
  42. methods: {
  43. // 查看商品详情
  44. goodsDetail(goodsId) {
  45. this.$common.navigateTo('/pages/goods/index/index?id=' + goodsId)
  46. },
  47. // 跳转商品列表页
  48. goodsList(obj = {}) {
  49. let url = '/pages/classify/index'
  50. if (Object.keys(obj).length) {
  51. url = this.$common.builderUrlParams(url, obj)
  52. }
  53. this.$common.navigateTo(url)
  54. },
  55. // 团购秒杀详情
  56. groupDetail(id, group_id) {
  57. this.$common.navigateTo(
  58. '/pages/goods/index/group?id=' + id + '&group_id=' + group_id
  59. )
  60. },
  61. //拼团详情页
  62. pintuanDetail(id, team_id) {
  63. if (team_id) {
  64. this.$common.navigateTo(
  65. '/pages/goods/index/pintuan?id=' + id + '&team_id=' + team_id
  66. )
  67. } else {
  68. this.$common.navigateTo('/pages/goods/index/pintuan?id=' + id)
  69. }
  70. }
  71. }
  72. }
  73. /**
  74. *
  75. * 返回操作处理
  76. *
  77. */
  78. export const goBack = {
  79. onBackPress(options) {
  80. if (options.from === 'navigateBack') {
  81. return false
  82. }
  83. let loginPages = ['/pages/cart/index/index', '/pages/member/index/index']
  84. let backPage = this.$store.state.redirectPage
  85. if (loginPages.indexOf(backPage) > -1) {
  86. this.$store.commit({
  87. type: 'redirect',
  88. page: ''
  89. })
  90. uni.switchTab({
  91. url: '/pages/index/index'
  92. })
  93. return true
  94. }
  95. }
  96. }
  97. /* Function Info
  98. * Author: zhf
  99. * CreateTime: 2019/7/12 下午12:10:00
  100. * LastEditor: zhf
  101. * ModifyTime: 2019/7/12 下午12:10:00
  102. * Description: 登录成功统一跳转处理
  103. */
  104. export const jumpBackPage = {
  105. methods: {
  106. handleBack() {
  107. let redirect = this.$store.state.redirectPage
  108. this.$store.commit({
  109. type: 'redirect',
  110. page: ''
  111. })
  112. let switchTabs = ['/pages/index/index', '/pages/member/index/index']
  113. if (switchTabs.indexOf(redirect) > -1) {
  114. uni.switchTab({
  115. url: redirect
  116. })
  117. } else if (redirect) {
  118. uni.redirectTo({
  119. url: redirect
  120. })
  121. } else {
  122. uni.switchTab({
  123. url: '/pages/index/index'
  124. })
  125. }
  126. }
  127. }
  128. }
  129. /* Function Info
  130. * Author: zhf
  131. * CreateTime: 2019/7/12 下午12:10:28
  132. * LastEditor: zhf
  133. * ModifyTime: 2019/7/12 下午12:10:28
  134. * Description: 操作判断登录处理
  135. */
  136. export const checkLogin = {
  137. methods: {
  138. checkIsLogin() {
  139. uni.showToast({
  140. title: '请先登录!',
  141. icon: 'none',
  142. duration: 800,
  143. success: function(res) {
  144. // #ifdef H5 || APP-PLUS
  145. setTimeout(() => {
  146. uni.hideToast()
  147. uni.navigateTo({
  148. url: '/pages/login/login/index1'
  149. })
  150. }, 800)
  151. // #endif
  152. // #ifdef MP-WEIXIN || MP-ALIPAY
  153. setTimeout(() => {
  154. uni.hideToast()
  155. uni.navigateTo({
  156. url: '/pages/login/choose/index',
  157. animationType: 'pop-in',
  158. animationDuration: 200
  159. })
  160. }, 500)
  161. // #endif
  162. }
  163. })
  164. }
  165. }
  166. }
  167. /**
  168. * 工具函数
  169. */
  170. export const tools = {
  171. methods: {
  172. copyData(data) {
  173. var _this = this;
  174. uni.setClipboardData({
  175. data: data,
  176. success: function() {
  177. _this.$common.errorToShow('复制成功')
  178. }
  179. });
  180. }
  181. }
  182. }

index.html

复制代码
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="author" content="novice@jihainet.com" />
  7. <meta name="viewport"
  8. content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  9. <title>
  10. <%= htmlWebpackPlugin.options.title %>
  11. </title>
  12. <!-- <script type="text/javascript">
  13. let url = window.location.origin;
  14. if(!/Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent)) {
  15. window.location.href= url + '/web/';
  16. }
  17. </script> -->
  18. <script>
  19. document.addEventListener('DOMContentLoaded', function () {
  20. document.documentElement.style.fontSize = document.documentElement.clientWidth / 20 + 'px'
  21. })
  22. </script>
  23. <!-- <script src="https://cdn.bootcss.com/vConsole/3.3.2/vconsole.min.js"></script>
  24. <script>
  25. var vConsole = new VConsole();
  26. </script> -->
  27. <link rel="stylesheet" href="<%= BASE_URL %>static/index.css" />
  28. </head>
  29. <body>
  30. <div id="app"></div>
  31. </body>
  32. <script>
  33. (function (w, d, s, n, a, e) {
  34. w[n] = w[n] || function () {
  35. (w[n].z = w[n].z || []).push(arguments)
  36. };
  37. a = d.createElement(s), e = d.getElementsByTagName(s)[0];
  38. a.async = 1;
  39. a.charset = "UTF-8";
  40. a.src = "https://pubres.aihecong.com/hecong.js";
  41. e.parentNode.insertBefore(a, e)
  42. })(window, document, "script", "_AIHECONG");
  43. </script>
  44. </html>

main.js

复制代码
  1. import Vue from 'vue'
  2. import App from './App'
  3. import * as Api from './config/api.js'
  4. import * as Common from './config/common.js'
  5. import * as Db from './config/db.js'
  6. import * as Config from './config/config.js'
  7. import store from './store'
  8. import './common/uni-H5Api'
  9. Vue.config.productionTip = false
  10. Vue.prototype.$api = Api;
  11. Vue.prototype.$common = Common;
  12. Vue.prototype.$db = Db;
  13. Vue.prototype.$config = Config;
  14. Vue.prototype.$store = store;
  15. App.mpType = 'app'
  16. const app = new Vue({
  17. ...App
  18. })
  19. app.$mount()

manifest.json

复制代码
  1. {
  2. "name" : "Jshop云商",
  3. "appid" : "__UNI__60F611E",
  4. "description" : "Jshop云商",
  5. "versionName" : "2.0",
  6. "versionCode" : 15,
  7. "transformPx" : false,
  8. "app-plus" : {
  9. /* 5+App特有相关 */
  10. "modules" : {
  11. "Payment" : {}
  12. },
  13. /* 模块配置 */
  14. "distribute" : {
  15. /* 应用发布信息 */
  16. "android" : {
  17. /* android打包配置 */
  18. "permissions" : [
  19. "<uses-feature android:name=\"android.hardware.camera\"/>",
  20. "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
  21. "<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
  22. "<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
  23. "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
  24. "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
  25. "<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
  26. "<uses-permission android:name=\"android.permission.CAMERA\"/>",
  27. "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
  28. "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
  29. "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
  30. "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
  31. "<uses-permission android:name=\"android.permission.INTERNET\"/>",
  32. "<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
  33. "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
  34. "<uses-permission android:name=\"android.permission.READ_CONTACTS\"/>",
  35. "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
  36. "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
  37. "<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
  38. "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
  39. "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
  40. "<uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>",
  41. "<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>",
  42. "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
  43. ]
  44. },
  45. "ios" : {},
  46. /* ios打包配置 */
  47. "sdkConfigs" : {
  48. "payment" : {
  49. "weixin" : {
  50. "appid" : "wxf62e2f29f15741af"
  51. },
  52. "alipay" : {
  53. "scheme" : ""
  54. }
  55. }
  56. }
  57. },
  58. "splashscreen" : {
  59. "waiting" : true
  60. }
  61. },
  62. /* SDK配置 */
  63. "quickapp" : {},
  64. /* 快应用特有相关 */
  65. "mp-weixin" : {
  66. "appid" : "wxaec38ca2e5cdc46a",
  67. "setting" : {
  68. "urlCheck" : true,
  69. "postcss" : true,
  70. "minified" : true,
  71. "es6" : true
  72. },
  73. "permission" : {
  74. "scope.userLocation" : {
  75. "desc" : "用于获取您附近的门店列表"
  76. }
  77. },
  78. "usingComponents" : false
  79. },
  80. "h5" : {
  81. "title" : "Jshop云商",
  82. "domain" : "https://wmp.uneedabox.com",
  83. "router" : {
  84. "base" : "/wap/",
  85. "mode" : "history"
  86. },
  87. "template" : "index.html",
  88. "devServer" : {
  89. "port" : 8080,
  90. "disableHostCheck" : true,
  91. "https" : false
  92. },
  93. "sdkConfigs" : {
  94. "maps" : {
  95. "qqmap" : {
  96. "key" : "AEIBZ-H5TRI-A6VGA-5KRNA-QKKK6-JGB33"
  97. }
  98. }
  99. }
  100. }
  101. }

pages

activity

index.vue
复制代码
  1. <template>
  2. <view class="conbox">
  3. <view class="container">
  4. <image src="../../static/img/bg.png" class="cont" mode=""></image>
  5. <image src="../../static/img/caidai.png" class="caidai" mode=""></image>
  6. <view class="header">
  7. <view class="header-title">
  8. <view class="left">
  9. 免费次数:<text style="color: #E4431A;">{{chishu}}</text>
  10. </view>
  11. <view class="left">
  12. 账户积分:<text style="color: #E4431A;">{{jifen}}</text>
  13. </view>
  14. <view class="right" @click="getmyPrize">
  15. 抽奖记录 >
  16. </view>
  17. </view>
  18. </view>
  19. <view class="main">
  20. <view class="canvas-container">
  21. <view :animation="animationData" class="canvas-content" id="zhuanpano" style="">
  22. <!-- <view :animation="animationData" class="canvas-content" id="zhuanpano" :style="[{transform:'rotate('+runDeg+')'}]"> -->
  23. <!-- <canvas class="canvas" canvas-id="canvas"></canvas> -->
  24. <view class="canvas-line">
  25. <view class="canvas-litem" v-for="(item,index1) in awardsList" :key="index1" :style="[{transform:'rotate('+item.lineTurn+')'}]"></view>
  26. </view>
  27. <view class="canvas-list">
  28. <view class="canvas-item" :style="[{zIndex:index2}]" v-for="(iteml,index2) in awardsList" :key="index2">
  29. <view class="canvas-item-text" :style="[{transform:'rotate('+iteml.turn+')'}]">
  30. <text>{{iteml.award}}</text>
  31. <image class="canvas-item-text-img" src="../../static/img/kongjiang.png" v-if="iteml.type == 0"></image>
  32. <image class="canvas-item-text-img" src="../../static/img/jifen.png" v-if="iteml.type == 1"></image>
  33. <image class="canvas-item-text-img" src="../../static/img/youhuiquan.png" v-if="iteml.type == 2"></image>
  34. <image class="canvas-item-text-img" src="../../static/img/yue.png" v-if="iteml.type == 3"></image>
  35. <image class="canvas-item-text-img" src="../../static/img/shangpin.png" v-if="iteml.type == 4"></image>
  36. </view>
  37. </view>
  38. </view>
  39. </view>
  40. <view @tap="playReward" class="canvas-btn" v-bind:class="btnDisabled">开始 </view>
  41. </view>
  42. </view>
  43. <view class="typecheckbox"></view>
  44. <!-- 规则 -->
  45. <view class="guize">
  46. <view class="title">
  47. 规则说明
  48. </view>
  49. <view class="g_item" v-for="(v, k) in awardsConfig.rule" :key="k">
  50. {{v}}
  51. </view>
  52. </view>
  53. <view class="typecheckbox2"></view>
  54. <!-- 抽奖记录 -->
  55. <view class="shadowbox" v-if="r_flg" @click="closeshadow">
  56. <view class="myrewards" @click.stop="openshadow">
  57. <view class="title">
  58. 抽奖记录
  59. </view>
  60. <view class="itembox">
  61. <view class="item" v-for="(items,i) in myPrizelist" :key="i">
  62. <div class="t">
  63. <text class="left">{{items.name}}</text>
  64. <text class="right">{{items.ctime_name}}</text>
  65. </div>
  66. <div class="b">
  67. {{items.prize_content}}
  68. </div>
  69. </view>
  70. </view>
  71. </view>
  72. </view>
  73. </view>
  74. </view>
  75. </template>
  76. <script>
  77. export default {
  78. data() {
  79. return {
  80. awardsConfig: {
  81. chance: true, //是否有抽奖机会
  82. prize: [], //奖品列表
  83. },
  84. awardsList: {},
  85. animationData: {},
  86. btnDisabled: '',
  87. thanksarr: [], //存储谢谢参与的索引
  88. chishu: 0,
  89. mold: 1,
  90. r_flg: 0,
  91. myPrizelist:[],
  92. jifen: 0
  93. }
  94. },
  95. onLoad: function() {
  96. // 获取奖品列表
  97. this.initdata(this)
  98. },
  99. onReady: function(e) {
  100. },
  101. methods: {
  102. // 查看奖品
  103. getmyPrize(){
  104. this.$api.myLottery({page: 1, limit: 1000}, res => {
  105. this.myPrizelist = res.data
  106. this.r_flg=1
  107. })
  108. },
  109. openshadow(){
  110. this.r_flg=1
  111. },
  112. closeshadow(){
  113. this.r_flg=0
  114. },
  115. // 初始化抽奖数据
  116. initdata:function(that){
  117. this.$api.lotteryConfig(res => {
  118. if(res.status){
  119. this.awardsConfig = res.data
  120. this.chishu = res.data.user.day_remaining;
  121. this.jifen = res.data.user.jifen;
  122. // 获取奖品的个数
  123. let awarrlength = this.awardsConfig.prize.length
  124. // 为每一项追加index属性
  125. this.awardsConfig.prize.forEach(function(element, index) {
  126. element.index = index
  127. });
  128. // 画转盘
  129. this.drawAwardRoundel();
  130. }else{
  131. this.$common.errorToShow(res.msg, () => {
  132. uni.navigateBack({
  133. delta: 1
  134. });
  135. });
  136. }
  137. });
  138. },
  139. //画抽奖圆盘
  140. drawAwardRoundel: function() {
  141. // 拿到奖品列表
  142. var awards = this.awardsConfig.prize;
  143. var awardsList = [];
  144. // 每份奖品所占角度
  145. var turnNum = 1 / awards.length * 360; // 文字旋转 turn 值
  146. // 奖项列表
  147. for (var i = 0; i < awards.length; i++) {
  148. awardsList.push({
  149. turn: i * turnNum + 'deg', //每个奖品块旋转的角度
  150. lineTurn: i * turnNum + turnNum / 2 + 'deg', //奖品分割线的旋转角度
  151. award: awards[i].title, //奖品的名字,
  152. type: awards[i].type,
  153. id: awards[i].id,
  154. });
  155. }
  156. if(this.chishu < 1 && this.jifen < this.awardsConfig.integral_exchange) {
  157. this.btnDisabled = 'disabled';
  158. }else{
  159. if(!this.awardsConfig.user.lottery){
  160. this.btnDisabled = 'disabled';
  161. }else{
  162. this.btnDisabled = '';
  163. }
  164. }
  165. this.awardsList = awardsList;
  166. },
  167. //发起抽奖
  168. playReward: function() {
  169. if(this.chishu < 1) {
  170. if(this.jifen < this.awardsConfig.integral_exchange) {
  171. this.$common.errorToShow('抽奖次数已经用完');
  172. return false;
  173. } else if (this.jifen >= this.awardsConfig.integral_exchange) {
  174. this.$common.modelShow('提示', '本次抽奖将消耗'+this.awardsConfig.integral_exchange+'积分,确认吗?', res => {
  175. this.lottery();
  176. });
  177. }
  178. }else{
  179. this.lottery();
  180. }
  181. },
  182. lottery: function () {
  183. // 抽奖
  184. this.$api.lottery(res => {
  185. if(res.status) {
  186. let awardIndex = 0;
  187. let awardInfo = res.data.result;
  188. //获取抽奖结果
  189. this.awardsList.forEach(function(element, index) {
  190. if (element.id == awardInfo.id) {
  191. awardIndex = index;
  192. }
  193. })
  194. //中奖index
  195. let awardsNum = this.awardsConfig.prize;
  196. let runNum = 4; //旋转8周
  197. let duration = 3686; //时长
  198. // 旋转角度
  199. this.runDeg = this.runDeg || 0;
  200. let preDeg = this.runDeg;
  201. this.runDeg = this.runDeg + (360 - this.runDeg % 360) + (360 * runNum - awardIndex * (360 / awardsNum.length)) + 1;
  202. //创建动画
  203. if(process.env.VUE_APP_PLATFORM == 'h5'){
  204. // document.styleSheets[0]
  205. document.getElementById('zhuanpano').style='animation:rotate_before 4s 0ms ease forwards;'
  206. if(document.styleSheets[0].cssRules.length>0){
  207. Array.from(document.styleSheets[0].cssRules).forEach(function(element,index){
  208. if(element.name == 'rotate_before'){
  209. // 删除上次插入的动画
  210. document.styleSheets[0].deleteRule(index)
  211. }
  212. })
  213. }
  214. // console.log(document.styleSheets[0].cssRules)
  215. // console.log("@keyframes rotate_before{from{ transform: rotate("+preDeg+"deg); }to{ transform: rotate("+this.runDeg+"deg);}}")
  216. // 插入定义的动画
  217. document.styleSheets[0].insertRule("@keyframes rotate_before{from{ transform: rotate("+preDeg+"deg); }to{ transform: rotate("+this.runDeg+"deg);}}",8);
  218. }else{
  219. var animationRun = uni.createAnimation({
  220. duration: duration,
  221. timingFunction: 'ease'
  222. })
  223. animationRun.rotate(this.runDeg).step();
  224. this.animationData = animationRun.export();
  225. }
  226. // // #ifndef H5
  227. // console.log(document.styleSheets)
  228. // document.getElementById('zhuanpano')
  229. // // #endif
  230. this.btnDisabled = 'disabled';
  231. // 中奖提示
  232. var awardsConfig = this.awardsConfig;
  233. var awardType = awardsConfig.prize[awardIndex].type;
  234. this.jifen = this.chishu <= 0 ? (this.jifen - awardsConfig.integral_exchange >= 0 ? this.jifen - awardsConfig.integral_exchange : 0) : this.jifen;
  235. this.chishu = this.chishu > 1 ? this.chishu - 1 : 0;
  236. if (awardType != 0) {
  237. let msg = this.getPrizeMsg(awardsConfig.prize[awardIndex].type, awardsConfig.prize[awardIndex].val);
  238. setTimeout(function() {
  239. this.$common.modelShow('恭喜', '获得' + (awardsConfig.prize[awardIndex].title) + ',' + msg, res => {
  240. setTimeout(function(){
  241. document.getElementById('zhuanpano').style=''
  242. },1000)
  243. }, false);
  244. if(!res.data.is_lottery.lottery){
  245. this.btnDisabled = 'disabled';
  246. }else{
  247. this.btnDisabled = '';
  248. }
  249. }.bind(this), duration);
  250. } else {
  251. setTimeout(function() {
  252. this.$common.modelShow('很遗憾', '没中奖,再接再厉!', res => {
  253. setTimeout(function(){
  254. document.getElementById('zhuanpano').style=''
  255. },1000)
  256. }, false);
  257. if(!res.data.is_lottery.lottery){
  258. this.btnDisabled = 'disabled';
  259. }else{
  260. this.btnDisabled = '';
  261. }
  262. }.bind(this), duration);
  263. }
  264. } else {
  265. this.$common.modelShow('提示', res.msg);
  266. }
  267. });
  268. },
  269. //获取显示的奖品信息
  270. getPrizeMsg: function(type, val){
  271. let msg = '';
  272. switch(type){
  273. case 1: //积分
  274. msg = '积分:' + val + '个';
  275. break;
  276. case 2: //优惠券
  277. msg = '优惠券:“' + val + '” 一张';
  278. break;
  279. case 3: //余额
  280. msg = '余额:' + val + '元';
  281. break;
  282. case 4: //商品
  283. msg = '商品:“' + val + '”';
  284. break;
  285. default: //默认
  286. break;
  287. }
  288. return msg;
  289. }
  290. }
  291. }
  292. </script>
  293. <style scoped>
  294. .conbox {
  295. width: 750upx;
  296. height: 100vh;
  297. overflow-x: hidden;
  298. overflow-y: scroll;
  299. }
  300. .container,
  301. image.cont {
  302. width: 750upx;
  303. min-height: 100vh;
  304. height: auto;
  305. position: relative;
  306. }
  307. image.cont {
  308. height: 100%;
  309. position: absolute;
  310. z-index: 0;
  311. }
  312. image.caidai {
  313. position: absolute;
  314. top: 0;
  315. left: 0;
  316. width: 750upx;
  317. height: 1024upx;
  318. }
  319. .header {
  320. display: flex;
  321. flex-direction: column;
  322. align-items: center;
  323. justify-content: center;
  324. /* height: 246upx; */
  325. padding-top: 48upx;
  326. padding-bottom: 40upx;
  327. box-sizing: border-box;
  328. position: relative;
  329. z-index: 3;
  330. }
  331. .header-title {
  332. width: 100%;
  333. height: 60upx;
  334. display: flex;
  335. align-items: center;
  336. padding: 0 48upx;
  337. box-sizing: border-box;
  338. justify-content: space-between;
  339. }
  340. .header-title>view {
  341. padding: 8upx 16upx;
  342. border: 1px solid #d89720;
  343. color: #d89720;
  344. font-size: 28upx;
  345. border-radius: 26upx;
  346. }
  347. /* 转盘 */
  348. .canvas-container {
  349. margin: 0 auto;
  350. position: relative;
  351. width: 600upx;
  352. height: 600upx;
  353. background: url(../../static/img/circle.png) no-repeat;
  354. background-size: cover;
  355. border-radius: 50%;
  356. }
  357. .canvas {
  358. width: 100%;
  359. height: 100%;
  360. display: block !important;
  361. border-radius: 50%;
  362. }
  363. .canvas-content {
  364. position: absolute;
  365. left: 0;
  366. top: 0;
  367. z-index: 1;
  368. display: block;
  369. width: 600upx;
  370. height: 600upx;
  371. border-radius: inherit;
  372. /* background-clip: padding-box; */
  373. /* background-color: #ffcb3f; */
  374. }
  375. .canvas-element {
  376. position: relative;
  377. z-index: 1;
  378. width: inherit;
  379. height: inherit;
  380. border-radius: 50%;
  381. }
  382. .canvas-list {
  383. position: absolute;
  384. left: 0;
  385. top: 0;
  386. width: inherit;
  387. height: inherit;
  388. z-index: 9999;
  389. }
  390. .canvas-item {
  391. position: absolute;
  392. left: 0;
  393. top: 0;
  394. width: 100%;
  395. height: 100%;
  396. color: #e4370e;
  397. /* text-shadow: 0 1upx 1upx rgba(255, 255, 255, 0.6); */
  398. }
  399. .canvas-item-text {
  400. position: relative;
  401. display: block;
  402. padding-top: 46upx;
  403. margin: 0 auto;
  404. text-align: center;
  405. -webkit-transform-origin: 50% 300upx;
  406. transform-origin: 50% 300upx;
  407. display: flex;
  408. flex-direction: column;
  409. align-items: center;
  410. color: #FB778B;
  411. }
  412. .canvas-item-text text {
  413. font-size: 30upx;
  414. }
  415. .canvas-item-text-img {
  416. width: 50upx;
  417. height: 50upx;
  418. padding-top: 30upx;
  419. }
  420. /* 分隔线 */
  421. .canvas-line {
  422. position: absolute;
  423. left: 0;
  424. top: 0;
  425. width: inherit;
  426. height: inherit;
  427. z-index: 99;
  428. }
  429. .canvas-litem {
  430. position: absolute;
  431. left: 300upx;
  432. top: 0;
  433. width: 3upx;
  434. height: 300upx;
  435. background-color: rgba(228, 55, 14, 0.4);
  436. overflow: hidden;
  437. -webkit-transform-origin: 50% 300upx;
  438. transform-origin: 50% 300upx;
  439. }
  440. /**
  441. * 抽奖按钮
  442. */
  443. .canvas-btn {
  444. position: absolute;
  445. left: 260upx;
  446. top: 260upx;
  447. z-index: 400;
  448. width: 80upx;
  449. height: 80upx;
  450. border-radius: 50%;
  451. color: #f4e9cc;
  452. background-color: #e44025;
  453. line-height: 80upx;
  454. text-align: center;
  455. font-size: 26upx;
  456. text-shadow: 0 -1px 1px rgba(0, 0, 0, 0.6);
  457. box-shadow: 0 3px 5px rgba(0, 0, 0, 0.6);
  458. text-decoration: none;
  459. }
  460. .canvas-btn::after {
  461. position: absolute;
  462. display: block;
  463. content: ' ';
  464. left: 12upx;
  465. top: -44upx;
  466. width: 0;
  467. height: 0;
  468. overflow: hidden;
  469. border-width: 30upx;
  470. border-style: solid;
  471. border-color: transparent;
  472. border-bottom-color: #e44025;
  473. }
  474. .canvas-btn.disabled {
  475. pointer-events: none;
  476. background: #b07a7b;
  477. color: #ccc;
  478. }
  479. .canvas-btn.disabled::after {
  480. border-bottom-color: #b07a7b;
  481. }
  482. .canvas-btn-table {
  483. color: #A83FDB;
  484. width: 120upx;
  485. text-align: center;
  486. position: absolute;
  487. left: 240upx;
  488. top: 360upx;
  489. font-size: 26upx;
  490. background-color: #FFFFFF;
  491. opacity: 0.9;
  492. }
  493. .typecheckbox {
  494. width: 100%;
  495. position: relative;
  496. z-index: 3;
  497. display: flex;
  498. justify-content: space-between;
  499. padding: 20upx;
  500. box-sizing: border-box;
  501. color: #fff;
  502. font-size: 28upx;
  503. top: -120upx;
  504. flex-direction: column;
  505. height: 180upx;
  506. align-items: flex-end;
  507. /* padding-top: 46upx; */
  508. }
  509. .typecheckbox2{
  510. width: 100%;
  511. position: relative;
  512. z-index: 3;
  513. display: flex;
  514. justify-content: space-between;
  515. padding: 20upx;
  516. box-sizing: border-box;
  517. color: #fff;
  518. font-size: 28upx;
  519. top: -120upx;
  520. flex-direction: column;
  521. height: 120upx;
  522. align-items: flex-end;
  523. /* padding-top: 46upx; */
  524. }
  525. .typecheckbox view {
  526. border: 1px solid #FF3637;
  527. background: transparent;
  528. color: #FF3637;
  529. display: flex;
  530. height: 60upx;
  531. width: 140upx;
  532. border-radius: 50upx;
  533. align-items: center;
  534. justify-content: center;
  535. display: flex;
  536. margin-left: 20upx;
  537. }
  538. .typecheckbox view.active {
  539. background: #FF3637;
  540. color: #fff;
  541. }
  542. .guize {
  543. width: 502upx;
  544. min-height: 300upx;
  545. display: flex;
  546. flex-direction: column;
  547. position: relative;
  548. z-index: 3;
  549. background-image: linear-gradient(-180deg, #F48549 0%, #F2642E 100%);
  550. border: 18upx solid #E4431A;
  551. border-radius: 16px;
  552. margin: 0 auto;
  553. margin-top: -104upx;
  554. padding: 48upx;
  555. /* box-sizing: border-box; */
  556. color: #fff;
  557. }
  558. .guize .title {
  559. text-align: center;
  560. margin-bottom: 28upx;
  561. }
  562. .guize .g_item {
  563. font-family: PingFang-SC-Medium;
  564. font-size: 24upx;
  565. color: #FFFFFF;
  566. letter-spacing: 0.5px;
  567. text-align: justify;
  568. line-height: 20px;
  569. }
  570. .shadowbox {
  571. width: 750upx;
  572. height: 100vh;
  573. position: fixed;
  574. top: 0;
  575. left: 0;
  576. z-index: 999;
  577. background: rgba(0, 0, 0, .6);
  578. display: flex;
  579. justify-content: center;
  580. align-items: center;
  581. }
  582. .myrewards {
  583. width: 600upx;
  584. min-height: 80upx;
  585. background: #FFEEDF;
  586. border: 10upx solid #F2692F;
  587. color: #333;
  588. font-size: 24upx;
  589. font-family: PingFang-SC-Medium;
  590. border-radius: 40upx;
  591. padding:0 24upx 20upx;
  592. }
  593. .myrewards .title {
  594. font-family: PingFang-SC-Bold;
  595. font-size: 16px;
  596. color: #E4431A;
  597. letter-spacing: 0.57px;
  598. display: flex;
  599. padding-top: 36upx;
  600. justify-content: center;
  601. }
  602. .myrewards .itembox {
  603. max-height: 320upx;
  604. overflow-y: auto;
  605. }
  606. .myrewards .item {
  607. width: 100%;
  608. padding: 12upx 0;
  609. box-sizing: border-box;
  610. border-bottom: 1upx dashed #CCCCCC;
  611. }
  612. .myrewards .item .t{
  613. display: flex;
  614. justify-content: space-between;
  615. align-items: center;
  616. margin-bottom:10upx;
  617. }
  618. .myrewards .item .b{
  619. font-size: 12px;
  620. color:#999999;
  621. text-align: left;
  622. }
  623. </style>

article

index.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="article">
  4. <view class="article-title" v-if="shopLogo && shopName">
  5. <img :src="shopLogo" alt="" class='shop-logo'>
  6. <text class='shop-name'>{{ shopName }}</text>
  7. <text class="fsz24 color-9 article-time">{{ info.ctime }}</text>
  8. </view>
  9. <!-- <view class="article-time">
  10. </view> -->
  11. <view class="article-content">
  12. <jshopContent :content="info.content" v-if="info.content"></jshopContent>
  13. </view>
  14. </view>
  15. </view>
  16. </template>
  17. <script>
  18. import jshopContent from '@/components/jshop/jshop-content.vue'
  19. export default {
  20. components: {
  21. jshopContent
  22. },
  23. data() {
  24. return {
  25. myShareCode: '', //分享Code
  26. idType: 1, //1文章 2公告 3微信图文消息
  27. id: 0,
  28. info: {}
  29. }
  30. },
  31. onLoad(e) {
  32. this.idType = e.id_type;
  33. this.id = e.id;
  34. if (!this.idType && !this.id) {
  35. this.$common.errorToShow('请求出错', res => {
  36. uni.switchTab({
  37. url: '/pages/index/index'
  38. });
  39. });
  40. } else if (this.idType == 1) {
  41. this.articleDetail();
  42. } else if (this.idType == 2) {
  43. uni.setNavigationBarTitle({
  44. title: '公告详情'
  45. });
  46. this.noticeDetail();
  47. } else if (this.idType == 3) {
  48. uni.setNavigationBarTitle({
  49. title: '图文消息'
  50. });
  51. this.messageDetail();
  52. }
  53. this.getMyShareCode();
  54. },
  55. computed: {
  56. shopName() {
  57. return this.$store.state.config.shop_name
  58. },
  59. shopLogo() {
  60. return this.$store.state.config.shop_logo
  61. }
  62. },
  63. methods: {
  64. articleDetail() {
  65. let data = {
  66. article_id: this.id
  67. }
  68. this.$api.articleInfo(data, res => {
  69. if (res.status) {
  70. this.info = res.data
  71. uni.setNavigationBarTitle({
  72. title: this.info.title
  73. });
  74. } else {
  75. this.$common.errorToShow(res.msg, res => {
  76. uni.navigateBack({
  77. delta: 1
  78. });
  79. });
  80. }
  81. })
  82. },
  83. noticeDetail() {
  84. let data = {
  85. id: this.id
  86. }
  87. this.$api.noticeInfo(data, res => {
  88. if (res.status) {
  89. this.info = res.data
  90. uni.setNavigationBarTitle({
  91. title: this.info.title
  92. });
  93. } else {
  94. this.$common.errorToShow(res.msg)
  95. }
  96. })
  97. },
  98. //微信图文消息
  99. messageDetail() {
  100. let data = {
  101. id: this.id
  102. }
  103. this.$api.messageDetail(data, res => {
  104. if (res.status) {
  105. this.info = res.data
  106. uni.setNavigationBarTitle({
  107. title: this.info.title
  108. });
  109. } else {
  110. this.$common.errorToShow(res.msg)
  111. }
  112. })
  113. },
  114. getMyShareCode() {
  115. let userToken = this.$db.get("userToken");
  116. if (userToken && userToken != '') {
  117. // 获取我的分享码
  118. this.$api.shareCode({}, res => {
  119. if (res.status) {
  120. this.myShareCode = res.data ? res.data : '';
  121. }
  122. });
  123. }
  124. }
  125. },
  126. //分享
  127. onShareAppMessage() {
  128. let myInviteCode = this.myShareCode ? this.myShareCode : '';
  129. let ins = this.$common.shareParameterDecode('type=4&id=' + this.id + '&id_type=' + this.idType + '&invite=' +
  130. myInviteCode);
  131. let path = '/pages/share/jump?scene=' + ins;
  132. return {
  133. title: this.info.title,
  134. // #ifdef MP-ALIPAY
  135. //desc: this.goodsInfo.brief,
  136. // #endif
  137. //imageUrl: this.goodsInfo.album[0],
  138. path: path
  139. }
  140. }
  141. }
  142. </script>
  143. <style>
  144. .content {
  145. /* #ifdef H5 */
  146. height: calc(100vh - 90upx);
  147. /* #endif */
  148. /* #ifndef H5 */
  149. height: 100vh;
  150. /* #endif */
  151. background-color: #fff;
  152. }
  153. .article {
  154. padding: 20upx;
  155. }
  156. .article-title {
  157. font-size: 32upx;
  158. color: #333;
  159. margin-bottom: 20upx;
  160. /* text-align: center; */
  161. position: relative;
  162. height: 100upx;
  163. }
  164. .article-time {
  165. /* text-align: right; */
  166. margin-left: 20upx;
  167. }
  168. .article-content {
  169. font-size: 28upx !important;
  170. color: #666;
  171. line-height: 1.6;
  172. margin-top: 20upx;
  173. }
  174. .article-content p img {
  175. width: 100% !important;
  176. }
  177. .shop-logo {
  178. width: 60upx;
  179. height: 60upx;
  180. border-radius: 50%;
  181. position: absolute;
  182. top: 50%;
  183. transform: translateY(-50%);
  184. }
  185. .shop-name {
  186. line-height: 100upx;
  187. margin-left: 80upx;
  188. }
  189. </style>
list.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class='cell-group margin-cell-group'>
  4. <view class='cell-item'
  5. v-for="item in list"
  6. :key="item.id"
  7. @click="articleDetail(item.id)"
  8. >
  9. <view class="cell-title-img">
  10. <image :src="item.cover" mode="aspectFill"></image>
  11. </view>
  12. <view class="cell-item-bd">
  13. <view class="article-title ">
  14. {{ item.title }}
  15. </view>
  16. <view class="article-time">
  17. {{ item.ctime }}
  18. </view>
  19. </view>
  20. </view>
  21. </view>
  22. <uni-load-more
  23. :status="loadStatus"
  24. ></uni-load-more>
  25. </view>
  26. </template>
  27. <script>
  28. import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue'
  29. export default {
  30. components: { uniLoadMore },
  31. data () {
  32. return {
  33. cid: 0, // 文章分类id
  34. page: 1,
  35. limit: 10,
  36. list: [],
  37. loadStatus: 'more'
  38. }
  39. },
  40. onLoad (options) {
  41. this.cid = options.cid
  42. if (!this.cid) {
  43. this.$common.errorToShow('未指定文章分类', () => {
  44. uni.navigateBack({
  45. delta: 1
  46. })
  47. })
  48. } else {
  49. this.articleList()
  50. }
  51. },
  52. onReachBottom () {
  53. if (this.loadStatus === 'more') {
  54. this.articleList()
  55. }
  56. },
  57. methods: {
  58. articleList () {
  59. let data = {
  60. page: this.page,
  61. limit: this.limit,
  62. type_id:this.cid
  63. }
  64. this.loadStatus = 'loading'
  65. this.$api.articleList(data, res => {
  66. if (res.status) {
  67. const _list = res.data.list
  68. this.list = [...this.list, ..._list]
  69. if (res.data.count > this.list.length) {
  70. this.loadStatus = 'more'
  71. this.page ++
  72. } else {
  73. // 数据已加载完毕
  74. this.loadStatus = 'noMore'
  75. }
  76. } else {
  77. // 接口请求出错了
  78. this.$common.errorToShow(res.msg)
  79. }
  80. })
  81. },
  82. // 查看文章详情
  83. articleDetail (articleId) {
  84. this.$common.navigateTo('/pages/article/index?id=' + articleId +'&id_type=1')
  85. }
  86. }
  87. }
  88. </script>
  89. <style>
  90. .cell-title-img{
  91. width: 160upx;
  92. height: 160upx;
  93. }
  94. .cell-title-img image{
  95. width: 100%;
  96. height: 100%;
  97. }
  98. .cell-item-bd{
  99. padding-right: 0;
  100. vertical-align: top;
  101. position: relative;
  102. }
  103. .article-title{
  104. font-size: 28upx;
  105. color: #333;
  106. width: 100%;
  107. min-height: 80upx;
  108. display: -webkit-box;
  109. -webkit-box-orient: vertical;
  110. -webkit-line-clamp: 2;
  111. overflow: hidden;
  112. }
  113. .article-time{
  114. font-size: 24upx;
  115. color: #999;
  116. display: inline-block;
  117. min-width: 220upx;
  118. min-height: 32upx;
  119. position: absolute;
  120. bottom: 0;
  121. }
  122. </style>

author.vue

复制代码
  1. <template>
  2. <view class="content">
  3. <view class="content-c">
  4. <image class="load-img" src="/static/image/loading.gif" mode=""></image>
  5. <view class="load-text color-9">信息加载中.....</view>
  6. </view>
  7. </view>
  8. </template>
  9. <script>
  10. export default {
  11. data() {
  12. return {
  13. code: '',
  14. type: '',
  15. state: ''
  16. }
  17. },
  18. onLoad(options) {
  19. // 获取url上的参数
  20. this.code = this.getUrlParam('code')
  21. this.state = this.getUrlParam('state')
  22. this.type = options.type
  23. var _this = this
  24. setTimeout(function() {
  25. _this.userTrustLogin()
  26. }, 100)
  27. },
  28. methods: {
  29. // 获取url地址参数
  30. getUrlParam(paraName) {
  31. let url = window.location.toString()
  32. let arrObj = url.split('?')
  33. if (arrObj.length > 1) {
  34. let arrPara = arrObj[1].split('&')
  35. let arr
  36. for (let i = 0; i < arrPara.length; i++) {
  37. arr = arrPara[i].split('=')
  38. if (arr != null && arr[0] == paraName) {
  39. if (arr[1].indexOf('#')) {
  40. let str
  41. str = arr[1].split('#')
  42. return str[0]
  43. }
  44. return arr[1]
  45. }
  46. }
  47. return ''
  48. } else {
  49. return ''
  50. }
  51. },
  52. // 第三方登录
  53. userTrustLogin() {
  54. let data = {
  55. scope: 1,
  56. code: this.code,
  57. state: this.state,
  58. invitecode: this.$db.get('invitecode') || ''
  59. }
  60. this.$api.getOpenId(data, res => {
  61. if (res.status) {
  62. if (res.data.token) {
  63. this.$db.set('userToken', res.data.token)
  64. this.redirectHandler()
  65. } else if (res.data.user_wx_id) {
  66. uni.redirectTo({
  67. url: '/pages/login/login/index?user_wx_id=' + res.data.user_wx_id
  68. })
  69. }
  70. } else {
  71. this.$common.errorToShow(res.msg)
  72. }
  73. })
  74. },
  75. redirectHandler() {
  76. this.$db.del('invitecode')
  77. let redirectPage = this.$db.get('redirectPage')
  78. if (redirectPage) {
  79. this.$db.del('redirectPage')
  80. this.$common.redirectTo(redirectPage)
  81. } else {
  82. uni.reLaunch({
  83. url: '/pages/index/index'
  84. })
  85. }
  86. }
  87. }
  88. }
  89. </script>
  90. <style>
  91. .content {
  92. position: relative;
  93. height: 80vh;
  94. }
  95. .content-c {
  96. position: absolute;
  97. top: 50%;
  98. left: 50%;
  99. transform: translate(-50%, -50%);
  100. text-align: center;
  101. }
  102. .load-img {
  103. width: 100upx;
  104. height: 100upx;
  105. }
  106. .load-text {
  107. font-size: 26upx;
  108. }
  109. </style>

cart

index
index.vue
复制代码
  1. <template>
  2. <view class="content" v-if="cartData.list && cartData.list.length > 0">
  3. <view class="content-top">
  4. <view class="cell-group margin-cell-group">
  5. <view class="cell-item">
  6. <view class="cell-item-hd">
  7. <image class="cell-hd-icon" src="/static/image/homepage.png" style="width: 32upx;height: 32upx;"></image>
  8. </view>
  9. <view class="cell-item-bd">
  10. <text class="cell-bd-text">{{ shopName }}</text>
  11. </view>
  12. <view class="cell-item-ft">
  13. <text class="cell-bd-text" @click="editBtn" v-if="!editStatus">编辑</text>
  14. <text class="cell-bd-text" @click="editNoBtn" v-else>完成</text>
  15. <!-- <image class='cell-ft-next icon' src='/static/image/right.png'></image> -->
  16. </view>
  17. </view>
  18. </view>
  19. <view class="img-list cart-list">
  20. <checkbox-group class="cart-checkbox" v-for="(item, index) in cartData.list" :key="index" :val="item.id" @change="checkboxChange(item.id)">
  21. <view class="">
  22. <label class="uni-list-cell uni-list-cell-pd">
  23. <view class="cart-checkbox-c">
  24. <checkbox color="#FF7159" :checked="item.is_select" :value="item.id" :disabled="item.stockNo" v-if="item.stockNo" class="checkboxNo" />
  25. <checkbox color="#FF7159" :checked="item.is_select" :value="item.id" v-else/>
  26. </view>
  27. </label>
  28. <view class="img-list-item">
  29. <image class="img-list-item-l little-img have-none" :src="item.products.image_path" mode="aspectFill"></image>
  30. <view class="img-list-item-r little-right">
  31. <view class="little-right-t">
  32. <view class="goods-name list-goods-name" @click="goodsDetail(item.products.goods_id)">
  33. {{ item.products.name }}
  34. </view>
  35. <view class="goods-price red-price">
  36. ¥{{ item.products.price }}
  37. </view>
  38. </view>
  39. <view class="romotion-tip" v-if="item.products.promotion_list">
  40. <view class="romotion-tip-item" v-for="(v, k) in item.products.promotion_list" :key="k" :class="v.type !== 2 ? 'bg-gray' : ''">
  41. {{v.name}}
  42. </view>
  43. </view>
  44. <view class="goods-item-c">
  45. <view class="goods-buy">
  46. <!-- 商品规格 -->
  47. <view class="goods-salesvolume" v-if="item.products.spes_desc">
  48. {{ item.products.spes_desc }}
  49. </view>
  50. <view class="goods-salesvolume" v-else></view>
  51. <view class="goods-numbox">
  52. <text v-if="item.stockNo && !editStatus" class="stockError">库存不足</text>
  53. <text v-else-if="item.stockTension && !editStatus" class="stockError stockTension">库存紧张</text>
  54. <uni-number-box v-on:change="bindChange($event, item)" :min="1" :max="item.maxStock" :value="item.nums" v-if="!editStatus"></uni-number-box>
  55. <view v-else="" @click="del(index,item.id)" class='click-del'>
  56. <image class="icon" src="/static/image/delete.png" mode=""></image>
  57. </view>
  58. </view>
  59. </view>
  60. </view>
  61. </view>
  62. </view>
  63. </view>
  64. </checkbox-group>
  65. </view>
  66. </view>
  67. <view class="cart-bottom">
  68. <checkbox-group class="cart-checkbox" @change="checkboxAllButton">
  69. <label class="uni-list-cell uni-list-cell-pd">
  70. <view class="cart-checkbox-c">
  71. <checkbox :checked="checkboxAll" color="#FF7159" /> 全选
  72. </view>
  73. </label>
  74. <view class="cart-bottom-right">
  75. <view class="cart-bottom-right-t" v-if="!editStatus">
  76. 合计:
  77. <view class="goods-price red-price">¥{{ cartData.amount }}</view>
  78. </view>
  79. <button class="btn btn-square btn-b" v-if="!editStatus" @click="settlement" hover-class="btn-hover2">去结算</button>
  80. <view v-else>
  81. <button class="btn btn-square btn-b" @click="delList">删除</button>
  82. <!-- <button class="btn btn-square" @click="collection">收藏</button> -->
  83. </view>
  84. </view>
  85. </checkbox-group>
  86. </view>
  87. </view>
  88. <!-- 购物车为空 -->
  89. <!-- <view class='cart-none' v-else-if="cartData.list && cartData.list.length < 1 && isLoad == true">
  90. <image class="cart-none-img" src="/static/image/car.png" mode=""></image>
  91. <view class='cart-none-t'>购物车快饿瘪了 T.T</view>
  92. <view class='cart-none-m'>快给我挑点宝贝吧</view>
  93. <navigator class="cart-none-b" url='../../index/index' hover-class="btn-hover" open-type="switchTab">去逛逛</navigator>
  94. </view> -->
  95. <view class='cart-none' v-else>
  96. <image class="cart-none-img" src="/static/image/car.png" mode=""></image>
  97. <view class='cart-none-t'>购物车快饿瘪了 T.T</view>
  98. <view class='cart-none-m'>快给我挑点宝贝吧</view>
  99. <navigator class="cart-none-b" url='../../index/index' hover-class="btn-hover" open-type="switchTab">去逛逛</navigator>
  100. </view>
  101. </template>
  102. <script>
  103. import uniNumberBox from '@/components/uni-number-box/uni-number-box.vue'
  104. import { goods } from '@/config/mixins.js'
  105. export default {
  106. mixins: [goods],
  107. data() {
  108. return {
  109. startX: 0, //开始坐标
  110. startY: 0,
  111. cartData: {}, //购物车数据
  112. cartIds: [], //选中ids
  113. checkboxAll: false, //全选按钮
  114. total: 0.0, //总价
  115. goSettlement: false, //去结算按钮
  116. cartId: '',
  117. cartNum: '',
  118. isLoad: false,
  119. cartNums: 0,
  120. editStatus: false
  121. }
  122. },
  123. components: { uniNumberBox },
  124. //页面加载
  125. onShow: function() {
  126. let userToken = this.$db.get('userToken')
  127. if (userToken) {
  128. this.getCartData(); //获取购物车数据
  129. }
  130. },
  131. computed: {
  132. // 从vuex中获取店铺名称
  133. shopName() {
  134. return this.$store.state.config.shop_name
  135. },
  136. goods_stocks_warn() {
  137. return this.$store.state.config.goods_stocks_warn
  138. }
  139. },
  140. methods: {
  141. checkboxChange: function(e) {
  142. let _this = this
  143. let id = e
  144. let cartData = _this.cartData
  145. for (let key in cartData.list) {
  146. if (cartData.list[key].id == id) {
  147. if (cartData.list[key].is_select == true) {
  148. cartData.list[key].is_select = false
  149. } else {
  150. cartData.list[key].is_select = true
  151. }
  152. }
  153. }
  154. _this.cartData = cartData
  155. _this.setNumsData()
  156. _this.isAllCheckbox()
  157. },
  158. //数组转字符串
  159. arrayToStr: function(array) {
  160. return array.toString()
  161. },
  162. //获取购物车数据
  163. getCartData: function() {
  164. let _this = this
  165. let cartIds = _this.arrayToStr(_this.cartIds)
  166. let data = {
  167. ids: cartIds,
  168. display: 'all'
  169. }
  170. this.$api.cartList(data, function(res) {
  171. if (res.status) {
  172. let data = res.data
  173. _this.showHandle(data) //数量设置
  174. }
  175. })
  176. },
  177. //渲染前配置数据
  178. showHandle: function(data, flag = true) {
  179. let _this = this
  180. let goSettlement = false
  181. for (let i in data.list) {
  182. //不可能购买0件
  183. if (data.list[i].nums < 1) {
  184. data.list[i].nums = 1
  185. }
  186. //不能买大于库存的数量(库存不足)
  187. let stockNo = false
  188. let maxStock = data.list[i].products.stock
  189. if (data.list[i].nums > data.list[i].products.stock) {
  190. //data.list[i].nums = data.list[i].products.stock;
  191. stockNo = true
  192. maxStock = data.list[i].nums
  193. }
  194. data.list[i].maxStock = maxStock
  195. data.list[i].stockNo = stockNo
  196. //库存紧张
  197. let stockTension = false
  198. if (_this.goods_stocks_warn >= data.list[i].products.stock) {
  199. stockTension = true
  200. }
  201. data.list[i].stockTension = stockTension
  202. //设置样式
  203. data.list[i].minStatus = 'normal'
  204. data.list[i].maxStatus = 'normal'
  205. if (data.list[i].nums == 1) {
  206. data.list[i].minStatus = 'disabled'
  207. }
  208. if (data.list[i].nums == data.list[i].products.stock) {
  209. data.list[i].maxStatus = 'disabled'
  210. }
  211. //设置规格参数
  212. data.list[i].spes = []
  213. if (data.list[i].products.spes_desc != null) {
  214. let spesArray = data.list[i].products.spes_desc.split(',')
  215. for (let key in spesArray) {
  216. let spesOne = spesArray[key].split(':')
  217. data.list[i].spes.push(spesOne[1])
  218. }
  219. }
  220. //添加左滑效果
  221. data.list[i].isTouchMove = false
  222. //是否可以去支付
  223. if (data.list[i].is_select) {
  224. goSettlement = true
  225. }
  226. //id转换为字符串
  227. data.list[i].id = _this.arrayToStr(data.list[i].id)
  228. //选中状态
  229. if (flag) {
  230. if (data.list[i].is_select) {
  231. if (_this.cartIds.indexOf(data.list[i].id) < 0) {
  232. _this.cartIds.push(data.list[i].id)
  233. }
  234. }
  235. }
  236. }
  237. data.goods_pmt = _this.$common.formatMoney(data.goods_pmt, 2, '')
  238. data.order_pmt = _this.$common.formatMoney(data.order_pmt, 2, '')
  239. data.amount = _this.$common.formatMoney(data.amount, 2, '')
  240. let isLoad = false
  241. if (data.list.length < 1) {
  242. isLoad = true
  243. }
  244. let n = 0
  245. for (let i in data.promotion_list) {
  246. n++
  247. }
  248. _this.goSettlement = goSettlement
  249. _this.isLoad = isLoad
  250. _this.cartNums = n
  251. if (flag) {
  252. _this.cartData = data
  253. } else {
  254. _this.getCartData()
  255. }
  256. _this.isAllCheckbox()
  257. },
  258. //是否全选
  259. isAllCheckbox: function() {
  260. let _this = this
  261. let cartData = _this.cartData.list
  262. let goSettlement = false
  263. let flag = true
  264. for (let key in cartData) {
  265. if (
  266. cartData[key].is_select == false &&
  267. cartData[key].stockNo == false
  268. ) {
  269. flag = false
  270. }
  271. if (cartData[key].is_select == true) {
  272. goSettlement = true
  273. }
  274. }
  275. if (cartData.length <= 0) {
  276. flag = false
  277. }
  278. _this.checkboxAll = flag
  279. _this.goSettlement = goSettlement
  280. },
  281. //全选操作
  282. checkboxAllButton: function(e) {
  283. if (this.checkboxAll == true) {
  284. this.checkboxAll = false
  285. this.setAllCheckbox(false)
  286. } else {
  287. this.checkboxAll = true
  288. this.setAllCheckbox(true)
  289. }
  290. },
  291. //全选设置
  292. setAllCheckbox: function(e) {
  293. let _this = this
  294. let cartData = _this.cartData
  295. if (e) {
  296. //全选
  297. for (let key in cartData.list) {
  298. if (cartData.list[key].stockNo == false) {
  299. cartData.list[key].is_select = true
  300. }
  301. }
  302. } else {
  303. //全不选
  304. for (let key in cartData.list) {
  305. cartData.list[key].is_select = false
  306. }
  307. }
  308. _this.cartData = cartData
  309. _this.setNumsData()
  310. _this.isAllCheckbox()
  311. },
  312. //设置刷新数据
  313. setNumsData: function() {
  314. let _this = this
  315. let cartData = _this.cartData
  316. let cartIds = []
  317. for (let key in cartData.list) {
  318. if (cartData.list[key].is_select) {
  319. cartIds.push(cartData.list[key].id)
  320. } else {
  321. // if (cartData.list[key].products.promotion_list) {
  322. // for (let k in cartData.list[key].products.promotion_list) {
  323. // cartData.list[key].products.promotion_list[k].type = 1;
  324. // }
  325. // }
  326. }
  327. }
  328. _this.cartIds = cartIds
  329. _this.cartData = cartData
  330. if (cartIds.length == 0) {
  331. let cartData = _this.cartData
  332. for (let k in cartData.promotion_list) {
  333. cartData.promotion_list[k].type = 1
  334. }
  335. cartData.goods_pmt = '0.00'
  336. cartData.order_pmt = '0.00'
  337. cartData.amount = '0.00'
  338. _this.cartData = cartData
  339. } else {
  340. _this.getCartData()
  341. }
  342. },
  343. //购物车数量调整
  344. bindChange(value, e) {
  345. let _this = this
  346. let id = e.id
  347. let num = value
  348. let cartData = _this.cartData
  349. let changeSelected = false
  350. for (let key in cartData.list) {
  351. if (cartData.list[key].id == id) {
  352. if (num <= cartData.list[key].products.stock) {
  353. cartData.list[key].nums = num
  354. changeSelected = true
  355. }
  356. }
  357. }
  358. if (changeSelected) {
  359. _this.cartData = cartData
  360. _this.cartId = id
  361. _this.cartNum = num
  362. _this.$common.throttle(_this.bindCartNumberOperation, _this, 350)
  363. } else {
  364. //_this.$common.errorToShow('数量错误1');
  365. }
  366. return false
  367. },
  368. //数量减一操作
  369. bindCartNumberOperation: function() {
  370. let _this = this
  371. _this.setCartNum(_this.cartId, _this.cartNum)
  372. },
  373. //设置购物车数量
  374. setCartNum: function(id, nums) {
  375. let _this = this
  376. let data = {
  377. id: id,
  378. nums: nums
  379. }
  380. _this.$api.setCartNum(data, function(res) {
  381. if (_this.cartIds.indexOf(id) > -1) {
  382. //_this.getCartData();
  383. if (res.status) {
  384. _this.$nextTick(function() {
  385. _this.showHandle(res.data, false)
  386. })
  387. } else {
  388. _this.$common.errorToShow(res.msg)
  389. }
  390. } else {
  391. _this.$nextTick(function() {
  392. _this.showHandle(res.data, false)
  393. })
  394. }
  395. })
  396. },
  397. //删除事件
  398. del: function(index, id) {
  399. let _this = this
  400. let cartid = id //cart_id
  401. //移除渲染
  402. _this.cartData.list.splice(index, 1)
  403. _this.cartData = _this.cartData
  404. _this.isLoad = true
  405. //移除数据库
  406. let data = {
  407. ids: cartid
  408. }
  409. _this.$api.removeCart(data, function(res) {
  410. if (res.status) {
  411. _this.$common.successToShow(res.msg)
  412. }
  413. _this.setNumsData()
  414. _this.isAllCheckbox()
  415. })
  416. },
  417. //收藏
  418. collection: function(e) {
  419. let _this = this
  420. app.db.userToken(function(token) {
  421. let data = {
  422. goods_id: e.currentTarget.dataset.goodsid
  423. }
  424. app.api.goodsCollection(data, function(res) {
  425. for (let k in _this.cartData.list) {
  426. if (
  427. _this.cartData.list[k].products.goods_id ==
  428. e.currentTarget.dataset.goodsid
  429. ) {
  430. if (res.msg == '收藏成功') {
  431. _this.cartData.list[k].isCollection = true
  432. } else {
  433. _this.cartData.list[k].isCollection = false
  434. }
  435. }
  436. }
  437. wx.showToast({
  438. title: res.msg,
  439. complete: function () {
  440. setTimeout(function() {
  441. uni.hideToast();
  442. },1000);
  443. }
  444. })
  445. })
  446. })
  447. },
  448. //去结算
  449. settlement: function(e) {
  450. let _this = this
  451. if (_this.goSettlement) {
  452. let cartData = _this.cartData.list
  453. let newData = ''
  454. for (let key in cartData) {
  455. if (cartData[key].is_select == true) {
  456. newData += ',' + cartData[key].id
  457. }
  458. }
  459. if (newData.substr(0, 1) == ',') {
  460. newData = newData.substr(1)
  461. }
  462. if (newData.length > 0) {
  463. _this.$common.navigateTo(
  464. '/pages/goods/place-order/index?cart_ids=' + JSON.stringify(newData)
  465. )
  466. return true
  467. } else {
  468. //没有选择不跳转
  469. }
  470. }
  471. },
  472. //手指触摸动作开始 记录起点X坐标
  473. touchstart: function(e) {
  474. //开始触摸时 重置所有删除
  475. let _this = this
  476. _this.cartData.list.forEach(function(v, i) {
  477. if (v.isTouchMove)
  478. //只操作为true的
  479. v.isTouchMove = false
  480. })
  481. _this.setData({
  482. startX: e.changedTouches[0].clientX,
  483. startY: e.changedTouches[0].clientY,
  484. cartData: _this.cartData
  485. })
  486. },
  487. //滑动事件处理
  488. touchmove: function(e) {
  489. let _this = this
  490. let index = e.currentTarget.dataset.index //当前索引
  491. let startX = _this.startX //开始X坐标
  492. let startY = _this.startY //开始Y坐标
  493. let touchMoveX = e.changedTouches[0].clientX //滑动变化坐标
  494. let touchMoveY = e.changedTouches[0].clientY //滑动变化坐标
  495. let angle = _this.angle(
  496. { X: startX, Y: startY },
  497. { X: touchMoveX, Y: touchMoveY }
  498. ) //获取滑动角度
  499. _this.cartData.list.forEach(function(v, i) {
  500. v.isTouchMove = false
  501. //滑动超过30度角 return
  502. if (Math.abs(angle) > 30) return
  503. if (i == index) {
  504. if (touchMoveX > startX)
  505. //右滑
  506. v.isTouchMove = false
  507. else
  508. //左滑
  509. v.isTouchMove = true
  510. }
  511. })
  512. //更新数据
  513. _this.setData({
  514. cartData: _this.cartData
  515. })
  516. },
  517. //计算滑动角度
  518. angle: function(start, end) {
  519. let _X = end.X - start.X,
  520. _Y = end.Y - start.Y
  521. //返回角度 /Math.atan()返回数字的反正切值
  522. return 360 * Math.atan(_Y / _X) / (2 * Math.PI)
  523. },
  524. //点击编辑
  525. editBtn: function() {
  526. this.editStatus = true
  527. },
  528. //点击完成
  529. editNoBtn: function() {
  530. let _this = this
  531. this.editStatus = false
  532. let is_select = false
  533. for (let i in _this.cartData.list) {
  534. if (_this.cartData.list[i].is_select) {
  535. is_select = true
  536. break
  537. }
  538. }
  539. if (is_select) {
  540. _this.getCartData()
  541. }
  542. },
  543. delList: function() {
  544. let _this = this
  545. let ids = []
  546. for (let k in _this.cartData.list) {
  547. if (_this.cartData.list[k].is_select) {
  548. ids += _this.cartData.list[k].id + ','
  549. }
  550. }
  551. let data = {
  552. ids: ids
  553. }
  554. _this.$api.removeCart(data, function(res) {
  555. if (res.status) {
  556. _this.$common.successToShow(res.msg)
  557. }
  558. _this.setNumsData()
  559. _this.isAllCheckbox()
  560. })
  561. }
  562. }
  563. }
  564. </script>
  565. <style>
  566. .cell-item-hd {
  567. max-width: 40upx;
  568. min-width: 40upx;
  569. }
  570. .margin-cell-group {
  571. margin: 0 0 2upx 0;
  572. }
  573. .little-right .goods-salesvolume {
  574. float: none;
  575. }
  576. .cart-bottom {
  577. /* #ifdef H5 */
  578. bottom: 50px;
  579. /* #endif */
  580. /* #ifndef H5 */
  581. bottom: 0;
  582. /* #endif */
  583. z-index: 99;
  584. height: 90upx;
  585. width: 100%;
  586. background-color: #fff;
  587. position: fixed;
  588. overflow: hidden;
  589. box-shadow: 0 0 20upx #ccc;
  590. }
  591. .cart-bottom-right {
  592. height: 90upx;
  593. float: right;
  594. overflow: hidden;
  595. }
  596. .cart-bottom-right-t {
  597. display: inline-block;
  598. height: 100%;
  599. line-height: 90upx;
  600. margin-right: 20upx;
  601. font-size: 28upx;
  602. color: #666;
  603. }
  604. .cart-bottom-right-t .red-price {
  605. float: none;
  606. }
  607. .btn-square {
  608. float: right;
  609. }
  610. .cart-bottom .cart-checkbox-c {
  611. color: #333;
  612. font-size: 30upx;
  613. }
  614. .cart-none {
  615. text-align: center;
  616. padding: 200upx 0;
  617. }
  618. .cart-none-img {
  619. width: 252upx;
  620. height: 228upx;
  621. margin-bottom: 40upx;
  622. }
  623. .cart-none-t {
  624. color: #666;
  625. font-size: 28upx;
  626. }
  627. .cart-none-m {
  628. color: #666;
  629. font-size: 28upx;
  630. margin-bottom: 40upx;
  631. }
  632. .cart-none-b {
  633. /* border: 2upx solid #ccc; */
  634. display: inline-block;
  635. padding: 16upx 40upx;
  636. font-size: 30upx;
  637. color: #666;
  638. background-color: #e3e3e3;
  639. }
  640. .stockError {
  641. font-size: 12px;
  642. color: #ffffff;
  643. background-color: #ff7159;
  644. padding: 1px 3px;
  645. border-radius: 3px;
  646. }
  647. .stockTension {
  648. background-color: #ffc107;
  649. }
  650. /* #ifdef MP-ALIPAY */
  651. label {
  652. display: block;
  653. }
  654. /* #endif */
  655. .click-del{
  656. overflow: hidden;
  657. height: 52upx;
  658. }
  659. .click-del .icon{
  660. float: right;
  661. }
  662. </style>

classify

classify.vue
复制代码
  1. <template>
  2. <view class="classify">
  3. <!-- 二级小图 -->
  4. <view class="goods-box" v-if="cate_style == 3">
  5. <view class="goods-list">
  6. <scroll-view scroll-y="true">
  7. <view class="goods-li" :class="{active:index==ins}" @click="active(index)" v-for="(tab,index) in beans" :key="index">
  8. <view class="shelectedZhu"></view>
  9. {{tab.name}}
  10. </view>
  11. </scroll-view>
  12. </view>
  13. <view class="goods-grid">
  14. <scroll-view class="goods-content" scroll-y="true">
  15. <view class="goods-banner" v-if="advert.tpl1_class_banner1">
  16. <image mode="widthFix" v-for="item in advert.tpl1_class_banner1" :key="item.id" :src="item.img" @click="showSliderInfo(item.type, item.val)"/>
  17. </view>
  18. <view class="goods-item">
  19. <view class="goods-item-box" v-if="isChild">
  20. <view class="goods-items" v-for="(item, index) in beans[ins].child" :key="index" @click="goClass(item.id)">
  21. <image class="goods-item-img" :src="item.image_url" alt="" mode="aspectFill"/>
  22. <view class="goods-item-name">{{item.name}}</view>
  23. </view>
  24. </view>
  25. </view>
  26. </scroll-view>
  27. </view>
  28. </view>
  29. <!-- 一级小图 -->
  30. <view class="goods-box level1-s" v-if="cate_style == 2">
  31. <view class="goods-grid">
  32. <scroll-view class="goods-content" scroll-y="true">
  33. <view class="goods-item">
  34. <view class="goods-item-box">
  35. <view class="goods-items" v-for="(item, index) in beans" :key="index" @click="goClass(item.id)">
  36. <image class="goods-item-img" :src="item.image_url" alt="" mode="aspectFill"/>
  37. <view class="goods-item-name">{{item.name}}</view>
  38. </view>
  39. </view>
  40. </view>
  41. </scroll-view>
  42. </view>
  43. </view>
  44. <!-- 一级大图 -->
  45. <view class="goods-box level1-b" v-if="cate_style == 1">
  46. <view class="goods-grid">
  47. <scroll-view class="goods-content" scroll-y="true">
  48. <view class="goods-item">
  49. <view class="goods-item-box">
  50. <view class="goods-items" v-for="(item, index) in beans" :key="index" @click="goClass(item.id)">
  51. <image class="goods-item-img" :src="item.image_url" alt="" mode="aspectFill"/>
  52. <view class="goods-item-name">{{item.name}}</view>
  53. </view>
  54. </view>
  55. </view>
  56. </scroll-view>
  57. </view>
  58. </view>
  59. </view>
  60. </template>
  61. <script>
  62. var _this;
  63. import { mapGetters } from 'vuex'
  64. import { goods } from '@/config/mixins.js'
  65. export default {
  66. mixins: [goods],
  67. data() {
  68. return {
  69. dataList: null,
  70. ins: 0,
  71. beans:[],
  72. advert: {},
  73. isChild: false
  74. };
  75. },
  76. computed: {
  77. cate_style () {
  78. return this.$store.state.config.cate_style ? this.$store.state.config.cate_style : 3;
  79. }
  80. },
  81. methods: {
  82. //切换样式 请求分类数据
  83. active (index) {
  84. this.ins = index;
  85. this.isChild = this.beans[index].hasOwnProperty('child');
  86. },
  87. categories () {
  88. this.$api.categories({}, res => {
  89. if(res.status){
  90. for(var i = 0; i < res.data.length; i++){
  91. if (i == 0) {
  92. res.data[i].active = true;
  93. }
  94. }
  95. this.beans = res.data;
  96. this.isChild = this.beans[0].hasOwnProperty('child');
  97. }
  98. });
  99. },
  100. goClass (cat_id) {
  101. uni.navigateTo({
  102. url: '/pages/classify/index?id=' + cat_id
  103. });
  104. },
  105. getBanner() {
  106. this.$api.advert({
  107. codes: 'tpl1_class_banner1'
  108. }, res => {
  109. this.advert = res.data.list;
  110. });
  111. },
  112. // 广告点击查看详情
  113. showSliderInfo(type, val) {
  114. if (type == 1) {
  115. // URL
  116. // #ifdef H5
  117. window.location.href = val
  118. // #endif
  119. } else if (type == 2) {
  120. // 商品详情
  121. this.goodsDetail(val)
  122. } else if (type == 3) {
  123. // 文章详情
  124. this.$common.navigateTo('/pages/article/index?id=' + val +'&id_type=1')
  125. } else if (type == 4) {
  126. // 文章列表
  127. this.$common.navigateTo('/pages/article/list?cid=' + val)
  128. }
  129. },
  130. },
  131. onLoad () {
  132. this.categories();
  133. this.getBanner();
  134. },
  135. };
  136. </script>
  137. <style>
  138. .classify {
  139. /* #ifdef H5 */
  140. height: calc(100vh - 188upx);
  141. /* #endif */
  142. /* #ifndef H5 */
  143. height: 100vh;
  144. /* #endif */
  145. }
  146. .goods-box {
  147. height: 100%;
  148. overflow: hidden;
  149. }
  150. .goods-list {
  151. overflow: auto;
  152. height: 100%;
  153. width: 160upx;
  154. float: left;
  155. display: inline-block;
  156. background-color: #f8f8f8;
  157. }
  158. .goods-li{
  159. font-size: 24upx;
  160. color: #666;
  161. height: 100upx;
  162. line-height: 100upx;
  163. text-align: center;
  164. position: relative;
  165. overflow: hidden;
  166. text-overflow: ellipsis;
  167. white-space: nowrap;
  168. }
  169. .goods-li.active{
  170. background-color: #fff;
  171. }
  172. .shelectedZhu {
  173. height: 56upx;
  174. width: 8upx;
  175. position: absolute;
  176. top: 50%;
  177. transform: translateY(-50%);
  178. }
  179. .goods-li.active .shelectedZhu{
  180. background-color: #333;
  181. }
  182. .goods-content{
  183. width: 590upx;
  184. display: inline-block;
  185. float: left;
  186. padding: 20upx;
  187. box-sizing: border-box;
  188. }
  189. .goods-grid{
  190. height: 100%;
  191. overflow: auto;
  192. background-color: #fff;
  193. }
  194. .goods-banner{
  195. width: 100%;
  196. /* height: 200upx; */
  197. margin-bottom: 20upx;
  198. }
  199. .goods-banner image{
  200. width: 100%;
  201. height: 100%;
  202. }
  203. .goods-item{
  204. }
  205. .goods-item-box{
  206. overflow: hidden;
  207. }
  208. .goods-items{
  209. width: 170upx;
  210. margin-right: 20upx;
  211. margin-bottom: 20upx;
  212. display: inline-block;
  213. }
  214. .goods-items:nth-child(3n){
  215. margin-right: 0;
  216. }
  217. .goods-item-img{
  218. width: 170upx;
  219. height: 170upx;
  220. }
  221. .goods-item-name{
  222. text-align: center;
  223. color: #666;
  224. font-size: 26upx;
  225. }
  226. .level1-s .goods-content,.level1-b .goods-content{
  227. width: 100%;
  228. }
  229. .level1-s .goods-items{
  230. width: 222upx;
  231. }
  232. .level1-s .goods-item-img{
  233. width: 222upx;
  234. height: 222upx;
  235. }
  236. .level1-b .goods-items{
  237. width: 100%;
  238. }
  239. .level1-b .goods-item-img{
  240. width: 100%;
  241. height: 222upx;
  242. }
  243. </style>
index.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <!-- 搜索框 -->
  4. <view class="search">
  5. <view class="search-c" @click="goSearch">
  6. <view class="search-input search-input-p" v-bind:class="$store.state.searchStyle">
  7. <view class="search-input-p-c">
  8. {{ searchKey }}
  9. </view>
  10. </view>
  11. <image class="icon search-icon" src="/static/image/zoom.png"></image>
  12. </view>
  13. </view>
  14. <!-- 条件筛选 -->
  15. <view class="screen">
  16. <view class="screen-item" @click="comprehensive">
  17. <text class="screen-item-text">综合</text>
  18. <view class='screen-item-icon'>
  19. <image v-if="searchData.order.key == 'sort' && searchData.order.sort == 'asc'" class="screen-item-icon-img" src="/static/image/bottom-black.png"></image>
  20. <image v-else class="screen-item-icon-img" src="/static/image/bottom-gray.png" ></image>
  21. </view>
  22. </view>
  23. <view class="screen-item" @click="priceSort">
  24. <text class="screen-item-text">价格</text>
  25. <view class="screen-item-icon">
  26. <image v-if="searchData.order.key == 'price' && searchData.order.sort == 'asc'" class="screen-item-icon-img" src="/static/image/top-black.png"></image>
  27. <image v-else-if="!(searchData.order.key == 'price' && searchData.order.sort == 'asc')" class="screen-item-icon-img" src="/static/image/top-gray.png"></image>
  28. <image v-if="searchData.order.key == 'price' && searchData.order.sort == 'desc'" class="screen-item-icon-img" src="/static/image/bottom-black.png"></image>
  29. <image v-if="!(searchData.order.key == 'price' && searchData.order.sort == 'desc')" class="screen-item-icon-img" src="/static/image/bottom-gray.png" ></image>
  30. </view>
  31. </view>
  32. <view class="screen-item" @click="salesVolume">
  33. <text class="screen-item-text">销量</text>
  34. <view class="screen-item-icon">
  35. <image v-if="searchData.order.key == 'buy_count' && searchData.order.sort == 'asc'" class="screen-item-icon-img" src="/static/image/top-black.png"></image>
  36. <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>
  37. <image v-if="searchData.order.key == 'buy_count' && searchData.order.sort == 'desc'" class="screen-item-icon-img" src="/static/image/bottom-black.png"></image>
  38. <image v-if="!(searchData.order.key == 'buy_count' && searchData.order.sort == 'desc')" class="screen-item-icon-img" src="/static/image/bottom-gray.png"></image>
  39. </view>
  40. </view>
  41. <view class="screen-item">
  42. <view class="screen-item-icon" style-type="button" :current="current" @click="listGrid">
  43. <image class="list-grid" src="/static/image/switch-ic-side-2.png" v-if="current == 0"></image>
  44. <image class="list-grid" src="/static/image/switch-ic-list.png" v-else-if="current == 1"></image>
  45. </view>
  46. </view>
  47. <view class="screen-item screents" v-if="screents" @click="toshow()">
  48. <text class="screen-item-text">筛选</text>
  49. <image class="filter-img" src="/static/image/top.png"></image>
  50. </view>
  51. <view class="screen-item screents" v-else-if="screentc" @click="toclose()">
  52. <text class="screen-item-text">筛选</text>
  53. <image class="filter-img" src="/static/image/bottom.png"></image>
  54. </view>
  55. </view>
  56. <!-- 高级赛选 -->
  57. <lvv-popup position="top" ref="lvvpopref" style="background: none;">
  58. <view class="fliter-c">
  59. <scroll-view scroll-y="true" style="height: 100%;">
  60. <view class="fliter-item">
  61. <view class='cell-item right-img'>
  62. <view class='cell-item-hd'>
  63. <view class='cell-hd-title'>价格区间</view>
  64. </view>
  65. </view>
  66. <view class="fliter-i-c">
  67. <view class="fic-item">
  68. <input class="fic-item-input" type="number" v-model="sPrice" />
  69. </view>
  70. <view class="fic-item-line"></view>
  71. <view class="fic-item">
  72. <input class="fic-item-input" type="number" v-model="ePrice" />
  73. </view>
  74. </view>
  75. </view>
  76. <view class="fliter-item" v-if="cat_list.length > 0">
  77. <view class='cell-item right-img'>
  78. <view class='cell-item-hd'>
  79. <view class='cell-hd-title'>分类</view>
  80. </view>
  81. </view>
  82. <view class="fliter-i-c">
  83. <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)">
  84. <view class="fic-item" v-if="!item.isSelect">
  85. <view class="fic-item-text two-line" >
  86. {{item.name}}
  87. </view>
  88. </view>
  89. <view class="fic-item fic-item-active" v-else-if="item.isSelect">
  90. <view class="fic-item-text two-line">
  91. {{item.name}}
  92. </view>
  93. </view>
  94. </view>
  95. </view>
  96. </view>
  97. <view class="fliter-item" v-if="brand_list.length > 0">
  98. <view class='cell-item right-img'>
  99. <view class='cell-item-hd'>
  100. <view class='cell-hd-title'>品牌</view>
  101. </view>
  102. </view>
  103. <view class="fliter-i-c">
  104. <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)">
  105. <view class="fic-item" v-if="!item.isSelect">
  106. <view class="fic-item-text two-line">
  107. {{item.name}}
  108. </view>
  109. </view>
  110. <view class="fic-item fic-item-active" v-else-if="item.isSelect">
  111. <view class="fic-item-text two-line">
  112. {{item.name}}
  113. </view>
  114. </view>
  115. </view>
  116. </view>
  117. </view>
  118. <view class="fliter-item" v-if="label_list.length > 0">
  119. <view class='cell-item right-img'>
  120. <view class='cell-item-hd'>
  121. <view class='cell-hd-title'>标签</view>
  122. </view>
  123. </view>
  124. <view class="fliter-i-c">
  125. <view v-for="item in label_list" :key="item.id" v-if="item.id && item.name" @click="selectKey('label_list', item.id)">
  126. <view class="fic-item" v-if="!item.isSelect">
  127. <view class="fic-item-text two-line">
  128. {{item.name}}
  129. </view>
  130. </view>
  131. <view class="fic-item fic-item-active" v-else-if="item.isSelect">
  132. <view class="fic-item-text two-line">
  133. {{item.name}}
  134. </view>
  135. </view>
  136. </view>
  137. </view>
  138. </view>
  139. </scroll-view>
  140. <view class="button-bottom">
  141. <!-- <button class="btn btn-square" @click="filterNo()">重置</button> -->
  142. <button class="btn btn-square" @click="toclose()">关闭</button>
  143. <button class="btn btn-b btn-square" @click="filterOk()">确定</button>
  144. </view>
  145. </view>
  146. </lvv-popup>
  147. <!-- 商品列表 -->
  148. <scroll-view scroll-y="true" :scroll-into-view="toView" class="scroll-Y" @scrolltolower="lower" enable-back-to-top="true" lower-threshold="45">
  149. <!-- 表格图片 -->
  150. <view class="img-grids" v-show="current === 0">
  151. <view v-if="goodsList.length>0">
  152. <view class="img-grids-item" v-for="(item, index) in goodsList" :key="index" @click="goodsDetail(item.id)">
  153. <image class="img-grids-item-t have-none" :src="item.image_url" mode='aspectFill'></image>
  154. <view class="img-grids-item-b">
  155. <view class="goods-name grids-goods-name">
  156. {{item.name}}
  157. </view>
  158. <view class="goods-item-c">
  159. <view class="goods-price red-price">¥{{item.price}}</view>
  160. <image class="goods-cart" src="/static/image/ic-car.png"></image>
  161. </view>
  162. </view>
  163. </view>
  164. </view>
  165. <!-- 无数据时默认显示 -->
  166. <view class="order-none" v-else>
  167. <image class="order-none-img" src="/static/image/order.png" mode=""></image>
  168. </view>
  169. </view>
  170. <!-- 列表图片 -->
  171. <view class="img-list" v-show="current === 1">
  172. <view v-if="goodsList.length>0">
  173. <view class="img-list-item" v-for="(item, index) in goodsList" :key="index" @click="goodsDetail(item.id)">
  174. <image class="img-list-item-l" :src="item.image_url" mode='aspectFill'></image>
  175. <view class="img-list-item-r">
  176. <view class="goods-name list-goods-name">
  177. {{item.name}}
  178. </view>
  179. <view class="goods-item-c">
  180. <view class="goods-price red-price">¥{{item.price}}</view>
  181. <view class="goods-buy">
  182. <view class="goods-salesvolume" v-if="item.comments_count > 0">{{item.comments_count}}条评论</view>
  183. <view class="goods-salesvolume" v-else-if="item.comments_count <= 0">暂无评论</view>
  184. <image class="goods-cart" src="/static/image/ic-car.png"></image>
  185. </view>
  186. </view>
  187. </view>
  188. </view>
  189. </view>
  190. <view class="order-none" v-else>
  191. <image class="order-none-img" src="/static/image/order.png" mode=""></image>
  192. </view>
  193. </view>
  194. </scroll-view>
  195. </view>
  196. </template>
  197. <script>
  198. import lvvPopup from '@/components/lvv-popup/lvv-popup.vue'
  199. export default {
  200. data() {
  201. return {
  202. current: 0,
  203. id: '',
  204. showView: false,
  205. goodsList: [],
  206. minPrice: '',
  207. maxPrice: '',
  208. ajaxStatus: false,
  209. loading: true,
  210. loadingComplete: false,
  211. nodata: false,
  212. toView: '',
  213. searchData: {
  214. where: {},
  215. limit: 10,
  216. page: 1,
  217. order: {
  218. key: 'sort',
  219. sort: 'asc'
  220. }
  221. },
  222. searchKey: '请输入关键字搜索', //关键词
  223. alllist: true,
  224. allgrid: false,
  225. screents: true,
  226. screentc: false,
  227. sPrice: '',
  228. ePrice: '',
  229. brand_list: [],
  230. cat_list: [],
  231. label_list: []
  232. };
  233. },
  234. //加载执行
  235. onLoad: function(options) {
  236. var where = {};
  237. if (options.id) {
  238. where = {
  239. cat_id: options.id
  240. };
  241. //this.getGoodsClass(options.id);
  242. }
  243. if (options.key) {
  244. where = {
  245. search_name: options.key
  246. };
  247. this.searchKey = options.key;
  248. }
  249. if (options.type) {
  250. if (options.type == 'hot') {
  251. where = {
  252. hot: true
  253. };
  254. }
  255. if (options.type == 'recommend') {
  256. where = {
  257. recommend: true
  258. }
  259. }
  260. }
  261. if(options.cat_id){
  262. where.cat_id = options.cat_id
  263. }
  264. if(options.brand_id){
  265. where.brand_id =options.brand_id
  266. }
  267. if(options.hot){
  268. where.hot =options.hot
  269. }
  270. if(options.recommend){
  271. where.recommend =options.recommend
  272. }
  273. if(options.label_id){
  274. where.label_id =options.label_id
  275. }
  276. this.setSearchData({
  277. where: where
  278. });
  279. this.getGoods();
  280. },
  281. components: {lvvPopup},
  282. methods: {
  283. listGrid() {
  284. if (this.current == 0) {
  285. this.current = 1;
  286. } else {
  287. this.current = 0;
  288. }
  289. },
  290. //设置查询条件
  291. setSearchData: function(searchData, clear = false) {
  292. var sd = this.searchData;
  293. this.searchData = this.$common.deepCopy(sd, searchData)
  294. if (clear) {
  295. this.goodsList = [];
  296. }
  297. },
  298. //获取分类名称
  299. // getGoodsClass: function(id) {
  300. // let data = {
  301. // id: id
  302. // };
  303. // this.$api.getGoodsClass(data, function(res) {
  304. // wx.setNavigationBarTitle({
  305. // title: res.data
  306. // });
  307. // });
  308. // },
  309. onChangeShowState: function() {
  310. var _this = this;
  311. _this.showView = !_this.showView;
  312. },
  313. //点击综合排序
  314. comprehensive: function() {
  315. this.setSearchData(
  316. {
  317. order: {
  318. key: 'sort',
  319. sort: 'asc'
  320. },
  321. page: 1
  322. },
  323. true
  324. );
  325. this.getGoods();
  326. },
  327. //销量
  328. salesVolume: function() {
  329. if (this.searchData.order.key == 'buy_count') {
  330. if (this.searchData.order.sort == 'desc') {
  331. this.searchData.order.sort = 'asc';
  332. } else {
  333. this.searchData.order.sort = 'desc';
  334. }
  335. } else {
  336. this.searchData.order = {
  337. key: 'buy_count',
  338. sort: 'desc'
  339. };
  340. }
  341. this.searchData.page = 1; //从第一页重新显示
  342. this.setSearchData(this.searchData, true);
  343. this.getGoods();
  344. },
  345. //价格排序
  346. priceSort: function() {
  347. if (this.searchData.order.key == 'price') {
  348. if (this.searchData.order.sort == 'desc') {
  349. this.searchData.order.sort = 'asc';
  350. } else {
  351. this.searchData.order.sort = 'desc';
  352. }
  353. } else {
  354. this.searchData.order = {
  355. key: 'price',
  356. sort: 'asc'
  357. };
  358. }
  359. this.searchData.page = 1; //从第一页重新显示
  360. this.setSearchData(this.searchData, true);
  361. this.getGoods();
  362. },
  363. //设置查询价格区间
  364. // orderPrice: function(e) {
  365. // var reg = /^[0-9]+(.[0-9]{2})?$/;
  366. // if (!reg.test(e.detail.value)) {
  367. // this.$common.errorToShow('请输入正确金额');
  368. // this.maxPrice = '';
  369. // } else {
  370. // this.maxPrice = e.detail.value;
  371. // }
  372. // },
  373. //查询价格区间
  374. // searchPrice: function(event) {
  375. // if (
  376. // this.minPrice > 0 &&
  377. // this.maxPrice > 0 &&
  378. // this.minPrice > this.maxPrice
  379. // ) {
  380. // app.common.errorToShow('价格区间有误');
  381. // return false;
  382. // }
  383. //
  384. // this.setSearchData(
  385. // {
  386. // page: 1,
  387. // where: {
  388. // price_f: this.minPrice,
  389. // price_t: this.maxPrice
  390. // }
  391. // },
  392. // true
  393. // );
  394. // this.getGoods();
  395. // },
  396. //页面相关事件处理函数--监听用户下拉动作
  397. onPullDownRefresh: function() {},
  398. //跳转到商品详情页面
  399. goodsDetail: function(id) {
  400. let url = '/pages/goods/index/index?id=' + id;
  401. this.$common.navigateTo(url);
  402. },
  403. //取得商品数据
  404. getGoods: function() {
  405. var _this = this;
  406. if (_this.ajaxStatus) {
  407. return false;
  408. }
  409. _this.ajaxStatus = true;
  410. _this.loading = true;
  411. _this.loadingComplete = false;
  412. _this.nodata = true;
  413. //如果已经没有数据了,就不取数据了,直接提示已经没有数据
  414. if (_this.loadingComplete) {
  415. _this.$common.errorToShow("暂时没有数据了")
  416. return false;
  417. }
  418. _this.$api.goodsList(_this.conditions(), function(res) {
  419. if (res.status) {
  420. //判是否没有数据了,只要返回的记录条数小于总记录条数,那就说明到底了,因为后面没有数据了
  421. var isEnd = false;
  422. if (res.data.list.length < _this.searchData.limit) {
  423. isEnd = true;
  424. }
  425. //判断是否为空
  426. var isEmpty = false;
  427. if (_this.searchData.page == 1 && res.data.list.length == 0) {
  428. isEmpty = true;
  429. }
  430. if(res.data.class_name != ''){
  431. uni.setNavigationBarTitle({
  432. title: res.data.class_name
  433. });
  434. }else{
  435. if(res.data.where && res.data.where.search_name && res.data.where.search_name != ''){
  436. uni.setNavigationBarTitle({
  437. title: '商品搜索'
  438. });
  439. }
  440. }
  441. _this.goodsList = _this.goodsList.concat(res.data.list);
  442. _this.ajaxStatus = false;
  443. _this.loading = !isEnd && !isEmpty;
  444. _this.toView = '';
  445. _this.loadingComplete = isEnd && !isEmpty;
  446. _this.nodata = isEmpty;
  447. if(res.data.filter){
  448. let filter = res.data.filter;
  449. if(filter.brand_ids){
  450. for(let i = 0; i < filter.brand_ids.length; i++){
  451. filter.brand_ids[i].isSelect = false;
  452. }
  453. _this.brand_list = filter.brand_ids;
  454. }
  455. if(filter.goods_cat){
  456. for(let i = 0; i < filter.goods_cat.length; i++){
  457. filter.goods_cat[i].isSelect = false;
  458. }
  459. _this.cat_list = filter.goods_cat;
  460. }
  461. if(filter.label_ids){
  462. for(let i = 0; i < filter.label_ids.length; i++){
  463. filter.label_ids[i].isSelect = false;
  464. }
  465. _this.label_list = filter.label_ids;
  466. }
  467. }
  468. }
  469. });
  470. },
  471. //上拉加载
  472. lower: function() {
  473. var _this = this;
  474. _this.toView = 'loading';
  475. if (!_this.loadingComplete) {
  476. _this.setSearchData({
  477. page: _this.searchData.page + 1
  478. });
  479. _this.getGoods();
  480. }
  481. },
  482. listgrid: function() {
  483. let _this = this;
  484. if (_this.alllist) {
  485. _this.allgrid = true;
  486. _this.listgrid = true;
  487. _this.alllist = false;
  488. } else {
  489. _this.allgrid = false;
  490. _this.listgrid = false;
  491. _this.alllist = true;
  492. }
  493. },
  494. // 统一返回筛选条件 查询条件 分页
  495. conditions () {
  496. let data = this.searchData;
  497. var newData = {};
  498. newData = this.$common.deepCopy(newData,data);
  499. //把data里的where换成json
  500. if(data.where){
  501. newData.where = JSON.stringify(data.where);
  502. }
  503. //把排序换成字符串
  504. if(data.order){
  505. var sort = data.order.key + ' ' + data.order.sort;
  506. if(data.order.key != 'sort'){
  507. sort = sort + ',sort asc' //如果不是综合排序,增加上第二个排序优先级排序
  508. }
  509. newData.order = sort;
  510. }else{
  511. newData.order = 'sort asc';
  512. }
  513. return newData;
  514. },
  515. //老搜索
  516. search(){
  517. this.setSearchData(
  518. {
  519. page: 1,
  520. where: {
  521. search_name: this.keyword
  522. }
  523. },
  524. true
  525. );
  526. this.getGoods();
  527. },
  528. //去搜索
  529. goSearch() {
  530. let pages = getCurrentPages();
  531. let prevPage = pages[pages.length - 2];
  532. // #ifdef H5 || MP-WEIXIN
  533. if(prevPage && prevPage.route){
  534. let search_flag = prevPage.route;
  535. if (search_flag == 'pages/index/search') {
  536. uni.navigateBack({
  537. delta: 1
  538. });
  539. }else{
  540. this.$common.navigateTo('/pages/index/search');
  541. }
  542. }else{
  543. this.$common.navigateTo('/pages/index/search');
  544. }
  545. // #endif
  546. // #ifdef MP-ALIPAY
  547. if(prevPage && prevPage.__proto__.route){
  548. let search_flag = prevPage.__proto__.route;
  549. if (search_flag == 'pages/index/search') {
  550. uni.navigateBack({
  551. delta: 1
  552. });
  553. }else{
  554. this.$common.navigateTo('/pages/index/search');
  555. }
  556. }else{
  557. this.$common.navigateTo('/pages/index/search');
  558. }
  559. // #endif
  560. },
  561. //筛选条件弹出窗口
  562. toshow(){
  563. this.$refs.lvvpopref.show();
  564. this.screents = false;
  565. this.screentc = true;
  566. },
  567. //关闭筛选
  568. toclose(){
  569. this.$refs.lvvpopref.close();
  570. this.screentc = false;
  571. this.screents = true;
  572. },
  573. //取消筛选
  574. filterNo(){
  575. this.ePrice = '';
  576. this.sPrice = '';
  577. for(let i = 0; i < this.cat_list.length; i++){
  578. this.cat_list[i].isSelect = false;
  579. }
  580. for(let i = 0; i < this.brand_list.length; i++){
  581. this.brand_list[i].isSelect = false;
  582. }
  583. for(let i = 0; i < this.label_list.length; i++){
  584. this.label_list[i].isSelect = false;
  585. }
  586. this.filterOk();
  587. this.toclose();
  588. },
  589. //确认筛选
  590. filterOk(){
  591. let data = this.searchData;
  592. //获取分类
  593. // data.where.cat_id = '';
  594. for(let i = 0; i < this.cat_list.length; i++){
  595. if(this.cat_list[i].isSelect){
  596. data.where.cat_id = this.cat_list[i].goods_cat_id;
  597. }
  598. }
  599. //获取多个品牌
  600. let brand_ids = '';
  601. for(let i = 0; i < this.brand_list.length; i++){
  602. if(this.brand_list[i].isSelect){
  603. brand_ids += this.brand_list[i].brand_id+',';
  604. }
  605. }
  606. if(brand_ids){
  607. brand_ids = brand_ids.substr(0, brand_ids.length-1);
  608. }
  609. data.where.brand_id = brand_ids;
  610. //获取标签
  611. data.where.label_id = '';
  612. for(let i = 0; i < this.label_list.length; i++){
  613. if(this.label_list[i].isSelect){
  614. data.where.label_id = this.label_list[i].id;
  615. }
  616. }
  617. //价格区间
  618. data.where.price_f = '';
  619. data.where.price_t = '';
  620. if(this.sPrice*1 < 0 || (this.ePrice != '' && this.ePrice <= 0) || this.ePrice*1 < 0 || (this.sPrice*1 > this.ePrice*1 && this.sPrice != '' && this.ePrice != '')){
  621. this.$common.errorToShow('价格区间有误');
  622. return false;
  623. }else{
  624. data.where.price_f = this.sPrice;
  625. data.where.price_t = this.ePrice;
  626. }
  627. this.setSearchData(data, true);
  628. this.getGoods();
  629. this.toclose();
  630. },
  631. //选择
  632. selectKey(type, id){
  633. //分类一次只能选择一个
  634. if(type == 'cat_list'){
  635. for(let i = 0; i < this.cat_list.length; i++){
  636. if(this.cat_list[i].goods_cat_id == id){
  637. this.cat_list[i].isSelect = this.cat_list[i].isSelect?false:true;
  638. }else{
  639. this.cat_list[i].isSelect = false;
  640. }
  641. }
  642. }
  643. if(type == 'brand_list'){
  644. for(let i = 0; i < this.brand_list.length; i++){
  645. if(this.brand_list[i].brand_id == id){
  646. this.brand_list[i].isSelect = this.brand_list[i].isSelect?false:true;
  647. }
  648. }
  649. }
  650. if(type == 'label_list'){
  651. for(let i = 0; i < this.label_list.length; i++){
  652. if(this.label_list[i].id == id){
  653. this.label_list[i].isSelect = this.label_list[i].isSelect?false:true;
  654. }else{
  655. this.label_list[i].isSelect = false;
  656. }
  657. }
  658. }
  659. }
  660. },
  661. // #ifdef MP-ALIPAY
  662. onChangeShowState_show: function () {
  663. var that = this;
  664. that.setData({
  665. showView: that.showView =true
  666. })
  667. },
  668. onChangeShowState_hid: function () {
  669. var that = this;
  670. that.setData({
  671. showView: that.showView =false
  672. })
  673. },
  674. // #endif
  675. };
  676. </script>
  677. <style>
  678. page{
  679. background-color: #fff;
  680. }
  681. .search{
  682. position: fixed;
  683. z-index: 997;
  684. /* #ifdef H5 */
  685. top: 44px;
  686. /* #endif */
  687. }
  688. .screen {
  689. width: 100%;
  690. padding: 10upx 26upx 20upx;
  691. overflow: hidden;
  692. margin-bottom: 2upx;
  693. background-color: #fff;
  694. position: fixed;
  695. /* #ifdef H5 */
  696. top: calc(44px + 104upx);
  697. /* #endif */
  698. /* #ifndef H5 */
  699. top: 104upx;
  700. /* #endif */
  701. z-index: 997;
  702. }
  703. .screen-item {
  704. width: 20%;
  705. height: 50upx;
  706. line-height: 42upx;
  707. float: left;
  708. text-align: center;
  709. position: relative;
  710. }
  711. .screents {
  712. border-left: 2upx solid #eee;
  713. }
  714. .screen-item-text {
  715. font-size: 24upx;
  716. color: #333;
  717. margin-right: 8upx;
  718. }
  719. .screen-item-icon {
  720. display: inline-block;
  721. position: absolute;
  722. top: 50%;
  723. transform: translateY(-50%);
  724. overflow: hidden;
  725. }
  726. .screen-item-icon-img {
  727. width: 16upx;
  728. height: 8upx;
  729. display: block;
  730. }
  731. .screen-item-icon .screen-item-icon-img:first-child {
  732. margin-bottom: 4upx;
  733. }
  734. .list-grid {
  735. width: 44upx;
  736. height: 44upx;
  737. float: left;
  738. }
  739. .filter-img {
  740. width: 18upx;
  741. height: 8upx;
  742. position: absolute;
  743. top: 50%;
  744. transform: translateY(-50%);
  745. }
  746. .img-grids{
  747. padding-bottom: 26upx;
  748. }
  749. .img-grids-item {
  750. margin-bottom: 0;
  751. }
  752. .img-grids>view,.img-list>view{
  753. overflow: hidden;
  754. }
  755. .scroll-Y{
  756. /* #ifdef H5 */
  757. height:calc(100vh - 44px - 186upx);
  758. /* #endif */
  759. /* #ifndef H5 */
  760. height:calc(100vh - 186upx);
  761. /* #endif */
  762. position: fixed;
  763. bottom: 0;
  764. }
  765. .search-input-p{
  766. color: #888;
  767. }
  768. .order-none{
  769. text-align: center;
  770. padding: 200upx 0;
  771. }
  772. .order-none-img{
  773. width: 274upx;
  774. height: 274upx;
  775. }
  776. .fliter-c{
  777. width: 100%;
  778. /* #ifdef H5 */
  779. height: calc(100% - 44px - 184upx);
  780. top: calc(44px + 182upx);
  781. /* #endif */
  782. /* #ifndef H5 */
  783. height: calc(100% - 184upx);
  784. top: 182upx;
  785. /* #endif */
  786. background: #FFFFFF;
  787. position: absolute;
  788. left:0;
  789. padding-bottom: 90upx;
  790. }
  791. .fliter-item{}
  792. .fliter-item .cell-item{
  793. border-bottom: none;
  794. }
  795. .fliter-i-c{
  796. padding: 0 26upx;
  797. overflow: hidden;
  798. }
  799. .fic-item{
  800. display: inline-block;
  801. float: left;
  802. width: 160upx;
  803. margin-right: 14upx;
  804. height: 70upx;
  805. background-color: #f1f1f1;
  806. text-align: center;
  807. font-size: 24upx;
  808. margin-bottom: 14upx;
  809. color: #333;
  810. padding: 0 10upx;
  811. }
  812. .fic-item-active{
  813. background-color: #FF7159;
  814. color: #fff;
  815. }
  816. .fic-item-text{
  817. position: relative;
  818. top:50%;
  819. transform: translateY(-50%);
  820. }
  821. .fic-item:nth-child(4n){
  822. margin-right: 0;
  823. }
  824. .fic-item-line{
  825. float: left;
  826. margin: 34upx 18upx 0 0;
  827. width: 50upx;
  828. height: 2upx;
  829. border-bottom: 2upx solid #ccc;
  830. }
  831. .fic-item-input{
  832. position: relative;
  833. top: 50%;
  834. transform: translateY(-50%);
  835. }
  836. /* #ifdef MP-ALIPAY */
  837. .hide{
  838. display: none;
  839. }
  840. .show{
  841. display: block;
  842. }
  843. /* #endif */
  844. .square{
  845. border-radius: 0;
  846. }
  847. .radius{
  848. border-radius: 12upx;
  849. }
  850. </style>
pintuan_list.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <!-- 列表图片 -->
  4. <view class="img-list" >
  5. <view v-if="goodsList.length>0">
  6. <view class="img-list-item" v-for="(item, index) in goodsList" :key="index" @click="goodsDetail(item.id)">
  7. <image class="img-list-item-l" :src="item.image_url" mode='aspectFill'></image>
  8. <view class="img-list-item-r">
  9. <view class="goods-name list-goods-name">
  10. {{item.name}}
  11. </view>
  12. <view class="goods-item-c">
  13. <view class="pintuan_time">
  14. <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>
  15. </view>
  16. <view class="goods-price red-price">
  17. ¥{{item.pintuanPrice}} <text class="people-num color-9 fsz24">{{item.pintuan_rule.people_number}}人成团</text>
  18. <!-- <image class="goods-cart" src="/static/image/more.png"></image> -->
  19. </view>
  20. <view class="goods-buy">
  21. <view class="goods-salesvolume" v-if="item.comments_count > 0">{{item.comments_count}}条评论</view>
  22. <view class="goods-salesvolume" v-else-if="item.comments_count <= 0">暂无评论</view>
  23. <image class="goods-cart" src="/static/image/more.png"></image>
  24. </view>
  25. </view>
  26. </view>
  27. </view>
  28. </view>
  29. <view class="order-none" v-else>
  30. <image class="order-none-img" src="/static/image/order.png" mode=""></image>
  31. </view>
  32. </view>
  33. </view>
  34. </template>
  35. <script>
  36. import uniCountdown from "@/components/uni-countdown/uni-countdown.vue"
  37. export default {
  38. components:{uniCountdown},
  39. data() {
  40. return {
  41. goodsList: {},
  42. pintuanPrice: 0,
  43. lasttime: {
  44. day: 0,
  45. hour: false,
  46. minute: 0,
  47. second: 0
  48. }, //购买倒计时
  49. };
  50. },
  51. //加载执行
  52. onLoad: function() {
  53. this.getGoods();
  54. },
  55. methods: {
  56. //跳转到商品详情页面
  57. goodsDetail: function(id) {
  58. let url = '/pages/goods/index/pintuan?id=' + id;
  59. this.$common.navigateTo(url);
  60. },
  61. //取得商品数据
  62. getGoods: function() {
  63. var _this = this;
  64. let data = {}
  65. _this.$api.pintuanList(data, res => {
  66. if (res.status) {
  67. _this.goodsList = res.data;
  68. _this.goodsList.forEach(item=>{
  69. if (item.pintuan_price<=0) {
  70. item.pintuan_price = '0.00'
  71. } else {
  72. item.pintuanPrice = this.$common.moneySub(item.price,item.pintuan_rule.discount_amount);
  73. }
  74. let timestamp = Date.parse(new Date())/1000;
  75. let lasttime = item.pintuan_rule.etime - timestamp;
  76. item.lasttime = _this.$common.timeToDateObj(lasttime);
  77. })
  78. }
  79. });
  80. },
  81. },
  82. };
  83. </script>
  84. <style>
  85. .list-grid {
  86. width: 44upx;
  87. height: 44upx;
  88. float: left;
  89. }
  90. .img-grids{
  91. padding-bottom: 26upx;
  92. }
  93. .img-grids-item {
  94. margin-bottom: 0;
  95. }
  96. .img-grids>view,.img-list>view{
  97. overflow: hidden;
  98. }
  99. .order-none{
  100. text-align: center;
  101. padding: 200upx 0;
  102. }
  103. .order-none-img{
  104. width: 274upx;
  105. height: 274upx;
  106. }
  107. .goods-price{
  108. margin-bottom: 10upx;
  109. width: 100%;
  110. overflow: hidden;
  111. }
  112. .people-num{
  113. margin-left: 16upx;
  114. }
  115. .img-list-item .goods-item-c{
  116. bottom: 0;
  117. }
  118. </style>

form

detail
form.vue
复制代码
  1. <template>
  2. <view v-show="showPage">
  3. <form @submit="formSubmit" bindreset="formReset">
  4. <view class="content">
  5. <view v-if="form.head_type==1">
  6. <view class="banner">
  7. <image :src='form.head_type_value_url[0]' mode='widthFix'></image>
  8. </view>
  9. </view>
  10. <!-- 轮播图 -->
  11. <view v-else-if="form.head_type == 2">
  12. <view>
  13. <view class='sw'>
  14. <swiper>
  15. <swiper-item v-for="(item,item_index) in form.head_type_value_url" :key="item_index">
  16. <image :src="item" class="slide-image" mode='widthFix' />
  17. </swiper-item>
  18. </swiper>
  19. </view>
  20. </view>
  21. </view>
  22. <view v-else-if="form.head_type==3">
  23. <view class='video'>
  24. <video :src='form.head_type_video_url[0]' :poster="form.head_type_value_url[0]"></video>
  25. </view>
  26. </view>
  27. <!-- 纯文字 -->
  28. <view v-if="form.desc !=''">
  29. <view class='plaintext'>
  30. <text>{{form.desc}}</text>
  31. </view>
  32. </view>
  33. <view class="input-box">
  34. <view v-for="(item,index) in form.items" :key="index">
  35. <view class='goods-box-item' v-if="item.type=='goods'">
  36. <image class='goods-img' :src='item.goods.image_url' mode='aspectFit'></image>
  37. <view class='goods-right'>
  38. <view class='goods-name'>{{item.name}}</view>
  39. <view class='goods-mid'>
  40. <text>已售{{item.goods.buy_count}}</text>
  41. </view>
  42. <view class='goods-buttom'>
  43. <view class="goods-price">¥{{item.goods.price}}</view>
  44. <view class='choose-specs' @click="specifications($event,item)" data-type='1' :data-goods="item.goods.id"
  45. :data-id="item.id" data-statu="openspecs">
  46. 选规格
  47. </view>
  48. <text class='order-num' v-if="item.cart_count> 0">{{item.cart_count}}</text>
  49. </view>
  50. </view>
  51. </view>
  52. <view class='form-input-box-item' v-if="item.type=='text'">
  53. <view class='ib-item-left'>
  54. <text>{{item.name}}:</text>
  55. </view>
  56. <view class='ib-item-right'>
  57. <input class='ib-item-input' type="text" :name="''+item.id" :data-id="item.id" v-model="item.default_value"
  58. placeholder-class='ib-item-input-c' :placeholder="'请输入'+item.name"></input>
  59. </view>
  60. </view>
  61. <!-- 日期 -->
  62. <view class='form-input-box-item' v-if="item.type=='date'">
  63. <view class='ib-item-left'>
  64. <text>{{item.name}}:</text>
  65. </view>
  66. <view class='ib-item-right'>
  67. <view class="ib-item-mid">
  68. <picker mode="date" :name="''+item.id" :value="item.default_value" start="1949-10-01" end="2019-10-01" @change="bindDateChange($event,item)"
  69. :data-id='item.id'>
  70. <view>{{item.default_value}}</view>
  71. </picker>
  72. <image class='icon-img-right' src='/static/image/ic-unfold.png'></image>
  73. </view>
  74. </view>
  75. </view>
  76. <!-- 时间 -->
  77. <view class='form-input-box-item' v-if="item.type=='time'">
  78. <view class='ib-item-left'>
  79. <text>{{item.name}}:</text>
  80. </view>
  81. <view class='ib-item-right'>
  82. <view class="ib-item-mid">
  83. <picker class="weui-btn" :name="''+item.id" mode="time" :value="item.default_value" start="09:01" end="21:01"
  84. @change="bindTimeChange($event,item)" :data-id='item.id'>
  85. <view>{{item.default_value}}</view>
  86. </picker>
  87. <image class='icon-img-right' src='/static/image/ic-unfold.png'></image>
  88. </view>
  89. </view>
  90. </view>
  91. <!-- 范围选择 -->
  92. <!-- 多选 -->
  93. <view class='form-input-box-item' v-if="item.type=='checbox'">
  94. <view class='ib-item-left'>
  95. <text>{{item.name}}:</text>
  96. </view>
  97. <view class='ib-item-right'>
  98. <view class='checkout-list'>
  99. <checkbox-group @change="checkboxChange($event,item)" :data-value="item.id" :name="''+item.id">
  100. <label class="checkout-item" v-for="(checkbox_item,item_index) in item.checbox_value" :key="item_index">
  101. <view class="checkout-item-c" :class="checkbox_item.checked?'black':''">
  102. <checkbox class="" :value="checkbox_item.value" :checked="checkbox_item.checked" /> {{checkbox_item.value}}
  103. </view>
  104. </label>
  105. </checkbox-group>
  106. </view>
  107. </view>
  108. </view>
  109. <!-- radio时处理 -->
  110. <view class='form-input-box-item' v-if="item.type=='radio'">
  111. <view class='ib-item-left'>
  112. <text>{{item.name}}:</text>
  113. </view>
  114. <view class='ib-item-right'>
  115. <radio-group class="uni-list" @change="radioChange($event,item)" :data-value="item.id" :name="''+item.id">
  116. <label class=" uni-list-cell uni-list-cell-pd " v-for="(radio_item, item_index) in item.radio_value" :key="item_index">
  117. <view class="invoice-type-icon">
  118. <radio class="a-radio" :id="radio_item" :value="radio_item" checked=true v-if="radio_item==item.default_value"></radio>
  119. <radio class="a-radio" :id="radio_item" :value="radio_item" v-if="radio_item!=item.default_value"></radio>
  120. </view>
  121. <view class="invoice-type-c">
  122. <label class="label-2-text" :for="radio_item">
  123. <text>{{radio_item}}</text>
  124. </label>
  125. </view>
  126. </label>
  127. </radio-group>
  128. </view>
  129. </view>
  130. <!-- 省市区选择 -->
  131. <view class='form-input-box-item' v-if="item.type=='area'">
  132. <view class='ib-item-left'>
  133. <text>{{item.name}}:</text>
  134. </view>
  135. <view class='ib-item-right'>
  136. <view class="ib-item-mid">
  137. <input class="fsz26" :value="pickerValue" @focus="showThreePicker" :name="''+item.id" />
  138. <area-picker class="fsz26" ref="areaPicker" :areaId="areaId" :defaultIndex="defaultIndex" @onConfirm="onConfirm"></area-picker>
  139. </view>
  140. </view>
  141. </view>
  142. <!-- 金额 -->
  143. <view class='form-input-box-item' v-if="item.type=='money'">
  144. <view class='ib-item-left'>
  145. <text>{{item.name}}:</text>
  146. </view>
  147. <view class='ib-item-right'>
  148. <view class="ib-item-mid">
  149. <input class='ib-item-input' type="digit" :name="''+item.id" v-model="item.default_value" placeholder-class='ib-item-input-c'
  150. :placeholder="'请输入'+item.name"></input>
  151. </view>
  152. </view>
  153. </view>
  154. <!-- 密码 -->
  155. <view class='form-input-box-item' v-if="item.type=='password'">
  156. <view class='ib-item-left'>
  157. <text>{{item.name}}:</text>
  158. </view>
  159. <view class='ib-item-right'>
  160. <view class="ib-item-mid">
  161. <input class='ib-item-input' type='password' :name="''+item.id" v-model="item.default_value" placeholder-class='ib-item-input-c'
  162. :placeholder="'请输入'+item.name"></input>
  163. </view>
  164. </view>
  165. </view>
  166. <!-- 图片 -->
  167. <view class='form-input-box-item' v-if="item.type=='image'">
  168. <view class='form-input-box-title'>上传{{item.name}}</view>
  169. <view class='form-multiple-rows'>
  170. <view class='f-m-r-item'>
  171. <view class='upload-img-list'>
  172. <view class='upload-img-bd'>
  173. <view class='upload-img' v-for="(pic_item, i) in item.pics" :key="i">
  174. <image @click='pic_del(item,index,i)' :data-index="i" class='del-img' src='/static/image/del.png'></image>
  175. <image class='upload-camera' :src="pic_item.src" mode='aspectFit'></image>
  176. <input type='text' hidden='hidden' :name="item.id+'_'+i" v-model="pic_item.image_id"></input>
  177. </view>
  178. </view>
  179. <view class='upload-img-hd'>
  180. <image class='upload-camera' src="/static/image/camera.png" @click="pic_choose($event,item,index)"
  181. :data-id="item.id"></image>
  182. </view>
  183. </view>
  184. </view>
  185. </view>
  186. </view>
  187. <!-- 文本域 -->
  188. <view class='form-input-box-item' v-if="item.type=='textarea'">
  189. <view class='form-input-box-title'>{{item.name}}</view>
  190. <view class='form-multiple-rows'>
  191. <view class='f-m-r-item form-input-box-item'>
  192. <textarea :name="''+item.id" class='ib-item-textarea' :placeholder="'请输入'+item.name" placeholder-class="ib-item-input-c"></textarea>
  193. </view>
  194. </view>
  195. </view>
  196. <!-- 定位 -->
  197. <view class='form-input-box-item' v-if="item.type=='coordinate'">
  198. <view class='ib-item-left'>
  199. <text>{{item.name}}:</text>
  200. </view>
  201. <view class='ib-item-right'>
  202. <view class="ib-item-mid">
  203. <image class='icon-img' src='/static/image/ic-location.png'></image>
  204. <input class='ib-item-input margin-r' placeholder-class='ib-item-input-c' :name="''+item.id" :value="item.default_value"
  205. disabled='disabled' placeholder="点击获取位置信息" @click="chooseLocation($event,item)" :data-id='item.id' />
  206. </view>
  207. </view>
  208. </view>
  209. </view>
  210. </view>
  211. <view class='goods-bottom' v-if="form.type==1">
  212. <text class='goods-total'>合计
  213. <text class='goods-total-r'>¥{{goodsTotalMoney}}</text>
  214. </text>
  215. </view>
  216. </view>
  217. <!-- 底部按钮 -->
  218. <view class='bottom-btn'>
  219. <button :style='{backgroundColor:form.button_color}' data-statu="open" form-type="submit" :disabled='submitStatus'
  220. :loading='submitStatus'>{{form.button_name}}</button>
  221. </view>
  222. </form>
  223. <lvv-popup position="bottom" ref="lvvpopref" class="lvvpopref">
  224. <!-- 多规格商品弹出 -->
  225. <block v-if="showSpecs">
  226. <view class="modal-body" data-statu="closespecs" catchtouchmove="move">
  227. <view class='specs-goods-t'>
  228. <view class='specs-goods-information'>
  229. <text class='specs-goods-name'>{{goodsInfoName}}</text>
  230. <text class='specs-goods-price'>¥{{goodsInfoPrint}}</text>
  231. </view>
  232. <view class='close-btn' @click="closeModal" :data-goods="select_goods_id" :data-id="select_id" data-type="100"
  233. data-statu="closespecs">
  234. <image src='/static/image/close.png'></image>
  235. </view>
  236. </view>
  237. <scroll-view class='specs-goods-c' scroll-y="true">
  238. <view class="color" v-for="(value,key) in goodsSpesDesc" :key="key">
  239. <text class='salespromotion-service-name'>{{key}}</text>
  240. <view class='salespromotion-service-b'>
  241. <block v-for="(i,item_index) in value" :key="item_index">
  242. <view v-if="i.is_default" class='pitch-on'>{{i.name}}</view>
  243. <view v-else-if="i.product_id != 0" :class='i.is_default ? "pitch-on" : ""' :data-key="i.product_id" :data-id="i.name"
  244. @click="selectSku">{{i.name}}</view>
  245. <view v-else class='nothing'>{{i.name}}</view>
  246. </block>
  247. </view>
  248. </view>
  249. <!-- 库存 -->
  250. <view class='number'>
  251. <text class='salespromotion-service-name'>数量</text>
  252. <view class="stepper">
  253. <text :class="goodsNums==0?'disabled':'normal'" @click="bindMinus">-</text>
  254. <input type="number" @change="bindManual" v-model="goodsNums" />
  255. <text :class="goodsNums==goodsInfoNumber?'disabled':'normal'" @click="bindPlus">+</text>
  256. </view>
  257. </view>
  258. </scroll-view>
  259. <view class='detail-footer'>
  260. <!-- 点击加购物车/购买 -->
  261. <view class='detail-footer-right determine-next' v-if="status">
  262. <!-- <view @click='goodsAddCart' class='determine'>确定</view> -->
  263. <view @click='goodsAddCart' class='next'>下一步</view>
  264. </view>
  265. <view class='detail-footer-right' v-else>
  266. <view class='stockno'>该商品已售罄</view>
  267. </view>
  268. </view>
  269. </view>
  270. </block>
  271. </lvv-popup>
  272. </view>
  273. </template>
  274. <script>
  275. import areaPicker from '@/components/area-picker/areaPicker.vue'
  276. import lvvPopup from '@/components/lvv-popup/lvv-popup.vue'
  277. export default {
  278. name: '',
  279. components: {
  280. areaPicker,
  281. lvvPopup
  282. },
  283. props: {},
  284. data() {
  285. return {
  286. formId: '',
  287. form: {
  288. head_type: 1,
  289. head_type_value_url: '',
  290. },
  291. showPage: true,
  292. hiddenForm: true,
  293. indicatorDots: true, //商品轮播图底部圆点
  294. autoplay: true, //商品轮播图自动播放
  295. interval: 3000, //商品轮播图切换间隔
  296. duration: 500, //商品轮播图切换动画时间
  297. slideImg: [], //幻灯片广告数据
  298. minusStatus: 'disabled', // 使用data数据对象设置样式名
  299. animationData: {},
  300. opacityData: {},
  301. hide: 'animathide',
  302. formMoney: 0.0, //表单金额
  303. region: ['河南省', '郑州市', '中原区'],
  304. areaId: 410102,
  305. pickerValue: '',
  306. defaultIndex: [0, 0, 0],
  307. pics: [], //图片
  308. goodsNums: 0,
  309. cart: [],
  310. currentKey: 0, //当前下单的商品的Key
  311. currentGoodsId: 0, //当前选中的商品ID
  312. goodsTotalMoney: '0.00', //商品总额
  313. originForm: [], //原始表单
  314. paymentType: '', //支付类型
  315. payment_type: '', //表单付款码||表单订单
  316. /** 商品信息*/
  317. goodsSpesDesc: '',
  318. productId: '',
  319. status: '',
  320. goodsInfoName: '',
  321. goodsInfoPrint: '',
  322. goodsInfoNumber: '',
  323. select_goods_id: '',
  324. select_id: '',
  325. showSpecs: false,
  326. submitStatus: false, //按钮状态
  327. }
  328. },
  329. onLoad(options) {
  330. var id = options.id
  331. if (!id) {
  332. this.$common.errorToShow('路径错误')
  333. return false
  334. }
  335. this.formId = id
  336. this.$db.set('formId', id)
  337. },
  338. onShow() {
  339. this.getFormDetail()
  340. },
  341. methods: {
  342. // 省市区联动初始化
  343. showThreePicker() {
  344. this.pickerValue =
  345. this.region[0] + ' ' + this.region[1] + ' ' + this.region[2]
  346. this.$refs.areaPicker[0].showPicker()
  347. },
  348. onConfirm(e) {
  349. let province_name = e[0].name
  350. let city_name = e[1].name
  351. let county_name = e[2].name
  352. this.pickerValue = e[0].name + ' ' + e[1].name + ' ' + e[2].name
  353. let data = {
  354. province_name: province_name,
  355. city_name: city_name,
  356. county_name: county_name
  357. }
  358. let regionName = [province_name, city_name, county_name]
  359. this.$api.getAreaId(data, res => {
  360. if (res.status) {
  361. this.areaId = res.data
  362. } else {
  363. uni.showModal({
  364. title: '提示',
  365. content: '地区选择出现问题,请重新选择地区',
  366. showCancel: false
  367. })
  368. }
  369. })
  370. },
  371. getFormDetail() {
  372. var data = {
  373. id: this.formId,
  374. token: this.$db.get('userToken')
  375. }
  376. var that = this
  377. this.$api.getFormDetial(data, res => {
  378. if (res.status) {
  379. this.form = res.data
  380. this.originForm = res.data
  381. if (res.data.type == '1' || res.data.type == '2') {
  382. if (res.data.type == '1') {
  383. //订单
  384. that.payment_type = this.$config.paymentType.form_order
  385. } else if (res.data.type == '2') {
  386. //付款码
  387. that.payment_type = this.$config.paymentType.form_pay
  388. }
  389. }
  390. //设置title名称
  391. uni.setNavigationBarTitle({
  392. title: res.data.name
  393. })
  394. } else {
  395. this.showPage = false;
  396. if (typeof res.data.need_login == 'undefined') {
  397. uni.showModal({
  398. title: '提示',
  399. content: '表单已过期,请扫描新的二维码',
  400. showCancel: false,
  401. success: function(res) {
  402. if (res.confirm) {
  403. uni.switchTab({
  404. url: '../../index/index'
  405. })
  406. }
  407. }
  408. })
  409. } else {
  410. //去登录
  411. this.$store.commit({
  412. type: 'redirect',
  413. page: '/pages/form/detail/form?id=' + this.formId
  414. })
  415. this.$common.jumpToLogin();
  416. }
  417. }
  418. })
  419. },
  420. // 选择日期
  421. bindDateChange(e, item) {
  422. item.default_value = e.target.value
  423. },
  424. // 选择时间
  425. bindTimeChange(e, item) {
  426. item.default_value = e.target.value
  427. },
  428. // 单选
  429. radioChange(e, item) {
  430. item.default_value = e.detail.value
  431. },
  432. // 多选
  433. checkboxChange(e, item) {
  434. var values = e.detail.value
  435. for (var i = 0; i < item.checbox_value.length; ++i) {
  436. const checkbox_item = item.checbox_value[i]
  437. if (values.includes(checkbox_item.value)) {
  438. this.$set(checkbox_item, 'checked', true)
  439. } else {
  440. this.$set(checkbox_item, 'checked', false)
  441. }
  442. }
  443. },
  444. //商品减一
  445. bindMinus() {
  446. if (this.goodsNums > 1) {
  447. this.goodsNums--
  448. } else {
  449. this.goodsNums = 0
  450. }
  451. },
  452. //商品加一
  453. bindPlus() {
  454. if (this.goodsNums >= this.goodsInfoNumber) {
  455. this.goodsNums = this.goodsInfoNumber
  456. } else {
  457. this.goodsNums++
  458. }
  459. },
  460. /* 输入框事件 */
  461. bindManual(e) {
  462. this.num = e.detail.value
  463. },
  464. //选择位置
  465. chooseLocation(e, item) {
  466. wx.chooseLocation({
  467. success(e) {
  468. item.default_value = e.latitude + ',' + e.longitude
  469. },
  470. fail(e) {
  471. wx.getSetting({
  472. success(res) {
  473. if (!res.authSetting['scope.userLocation']) {
  474. wx.openSetting()
  475. }
  476. }
  477. })
  478. }
  479. })
  480. },
  481. pic_choose(e, item, index) {
  482. var that = this
  483. this.$api.uploadImage(5, res => {
  484. if (res.status) {
  485. if (!item.pics) {
  486. item.pics = []
  487. }
  488. item.pics.push({
  489. src: res.data.url.replace(/\\/g, '/'),
  490. image_id: res.data.image_id
  491. })
  492. this.$set(this.form.items, index, item)
  493. that.$common.successToShow(res.msg)
  494. } else {
  495. that.$common.errorToShow(res.msg)
  496. }
  497. })
  498. },
  499. //删除图片
  500. pic_del(item, index, i) {
  501. item.pics.splice(i, 1)
  502. this.$set(this.form.items, index, item)
  503. },
  504. //表单提交
  505. formSubmit(e) {
  506. var that = this
  507. var data = e.detail.value
  508. //订单时需要合并购物车信息
  509. if (this.form.type == 1) {
  510. if (this.cart.length < 1) {
  511. this.$common.errorToShow('请先选择商品')
  512. return true
  513. }
  514. var tempArray = []
  515. this.cart.forEach(function(item, index, input) {
  516. tempArray[item.key + '_' + index] = item
  517. })
  518. data = Object.assign(data, tempArray)
  519. }
  520. let userToken = this.$db.get('userToken')
  521. let obj = {
  522. data,
  523. id: this.form.id,
  524. token: userToken
  525. }
  526. this.submitStatus = true;
  527. this.$api.addSubmitForm(obj, res => {
  528. this.submitStatus = false;
  529. if (res.status) {
  530. //表单类型判断是否需要支付,支付金额多少
  531. if (that.form.type == '1' || that.form.type == '2') {
  532. that.$common.successToShow(res.msg);
  533. //跳转首页
  534. setTimeout(function() {
  535. //出来支付按钮
  536. that.$common.redirectTo('/pages/goods/payment/index?form_id=' + res.data.id + '&type=' + that.payment_type +
  537. '&recharge=' + res.data.money)
  538. }, 1000)
  539. } else {
  540. that.formReset()
  541. that.$common.successToShow(res.msg)
  542. //跳转首页
  543. setTimeout(function() {
  544. wx.switchTab({
  545. url: '../../index/index'
  546. })
  547. }, 1500)
  548. }
  549. } else {
  550. this.$common.errorToShow(res.msg);
  551. }
  552. })
  553. },
  554. //表单清空
  555. formReset(e) {
  556. this.$db.set('formId', '')
  557. this.cart = [] //初始化,刷新当前页面
  558. this.form = this.originForm
  559. },
  560. closeModal() {
  561. this.$refs.lvvpopref.close()
  562. },
  563. //选择规格弹出
  564. specifications(e, item) {
  565. this.$refs.lvvpopref.show()
  566. this.showSpecs = true
  567. this.select_id = e.target.dataset.id
  568. this.select_goods_id = e.target.dataset.goods
  569. this.currentKey = e.target.dataset.id //当前选中的key
  570. this.currentGoodsId = e.target.dataset.goods //当前选中的商品ID
  571. this.getGoodsInfo(item)
  572. },
  573. //获取商品详情
  574. getGoodsInfo(item) {
  575. let goods = item.goods
  576. this.goodsSpesDesc = this.getSpes(goods.product)
  577. this.productId = goods.product.id
  578. this.goodsInfoName = goods.product.name
  579. this.goodsInfoPrint = goods.product.price
  580. this.goodsInfoNumber = goods.product.stock
  581. this.goodsNums = this.getNumsByKey(this.currentKey, goods.product.id)
  582. this.status = goods.product.stock < 1 ? false : true
  583. },
  584. /*获取key的数量 */
  585. getNumsByKey(key, productId) {
  586. var that = this
  587. if (that.cart.length < 1) {
  588. return 0
  589. } else {
  590. for (var i = 0; i < that.cart.length; i++) {
  591. if (that.cart[i].key == key && that.cart[i].productId == productId) {
  592. return that.cart[i].nums
  593. }
  594. }
  595. return 0
  596. }
  597. },
  598. //加入购物车
  599. goodsAddCart: function() {
  600. var productId = this.productId
  601. var currentKey = this.currentKey
  602. if (this.cart.length < 1) {
  603. this.cart.push({
  604. key: currentKey,
  605. productId: productId,
  606. goodsId: this.select_goods_id,
  607. nums: this.goodsNums,
  608. price: this.goodsInfoPrint
  609. })
  610. } else {
  611. var isIn = false
  612. for (var i = 0; i < this.cart.length; i++) {
  613. if (
  614. this.cart[i].key == currentKey &&
  615. this.cart[i].productId == productId
  616. ) {
  617. this.cart[i] = {
  618. key: currentKey,
  619. productId: productId,
  620. goodsId: this.select_goods_id,
  621. nums: this.goodsNums,
  622. price: this.goodsInfoPrint
  623. }
  624. isIn = true
  625. }
  626. }
  627. if (!isIn) {
  628. this.cart.push({
  629. key: currentKey,
  630. productId: productId,
  631. goodsId: this.select_goods_id,
  632. nums: this.goodsNums,
  633. price: this.goodsInfoPrint
  634. })
  635. }
  636. }
  637. this.showSpecs = false
  638. this.$refs.lvvpopref.close()
  639. this.getCartNums()
  640. },
  641. getCartNums() {
  642. var items = this.form.items
  643. var itemKey = ''
  644. for (var i = 0, len = items.length; i < len; ++i) {
  645. if (items[i].id == this.currentKey) {
  646. itemKey = i
  647. }
  648. }
  649. var that = this
  650. if (this.form.items[itemKey].goods.id == this.currentGoodsId) {
  651. if (this.form.items[itemKey].cart_count > 0) {
  652. var cart_count = 0
  653. var currentKey = this.currentKey
  654. this.cart.forEach(function(item, index, input) {
  655. if (item.key == currentKey) {
  656. cart_count += item.nums
  657. }
  658. that.form.items[itemKey].cart_count = cart_count
  659. })
  660. } else {
  661. this.form.items[itemKey].cart_count = this.goodsNums
  662. }
  663. } else {
  664. this.form.items[itemKey].cart_count = this.goodsNums
  665. }
  666. this.getGoodsTotalMoney()
  667. },
  668. //获取商品总额
  669. getGoodsTotalMoney() {
  670. var that = this
  671. var goodsTotalMoney = 0
  672. this.cart.forEach(function(item, index, input) {
  673. goodsTotalMoney += item.price * item.nums
  674. })
  675. this.goodsTotalMoney = this.$common.formatMoney(goodsTotalMoney, 2, '')
  676. },
  677. getSpes: function(product) {
  678. if (!product.default_spes_desc) {
  679. return []
  680. }
  681. return product.default_spes_desc
  682. },
  683. //获取规格信息
  684. selectSku(e) {
  685. var id = e.target.dataset.key
  686. this.$api.getProductInfo({
  687. id
  688. }, res => {
  689. if (res.status) {
  690. this.goodsSpesDesc = this.getSpes(res.data)
  691. this.productId = res.data.id
  692. this.goodsInfoName = res.data.name
  693. this.goodsInfoPrint = res.data.price
  694. this.goodsInfoNumber = res.data.stock
  695. this.goodsNums = this.getNumsByKey(this.currentKey, res.data.id)
  696. this.status = res.data.stock < 1 ? false : true
  697. }
  698. })
  699. }
  700. },
  701. //分享
  702. onShareAppMessage() {
  703. let myInviteCode = this.$db.get("userToken");
  704. let ins = this.$common.shareParameterDecode('type=10&id=' + this.formId + '&invite=' + myInviteCode);
  705. let path = '/pages/share/jump?scene=' + ins;
  706. return {
  707. title: this.form.name,
  708. path: path
  709. }
  710. }
  711. }
  712. </script>
  713. <style>
  714. .content {
  715. margin-bottom: 200rpx;
  716. background-color: #eeeeee;
  717. }
  718. .sw,
  719. .video {
  720. height: 350rpx;
  721. }
  722. .banner,
  723. .sw,
  724. .video {
  725. width: 100%;
  726. /* height: 350rpx; */
  727. background-color: #fff;
  728. }
  729. .banner image,
  730. .sw swiper,
  731. .sw swiper image,
  732. .video video {
  733. width: 100%;
  734. height: 100%;
  735. }
  736. .plaintext {
  737. padding: 20rpx 30rpx;
  738. font-size: 30rpx;
  739. color: #333;
  740. background-color: #fff;
  741. }
  742. .goods {
  743. /* margin: 20rpx 0; */
  744. background-color: #fff;
  745. }
  746. .form-input-box-title {
  747. /* padding: 20rpx 30rpx 0; */
  748. font-size: 28rpx;
  749. }
  750. .goods-box-item {
  751. overflow: hidden;
  752. padding: 20rpx 30rpx 20rpx 0;
  753. margin-left: 30rpx;
  754. border-bottom: 2rpx solid #eeeeee;
  755. }
  756. .goods-box-item:nth-last-child(2) {
  757. border: none;
  758. }
  759. .goods-img {
  760. width: 150rpx;
  761. height: 150rpx;
  762. display: inline-block;
  763. float: left;
  764. }
  765. .goods-right {
  766. width: 520rpx;
  767. display: inline-block;
  768. float: left;
  769. margin-left: 20rpx;
  770. }
  771. .goods-name {
  772. font-size: 30rpx;
  773. color: #333;
  774. overflow: hidden;
  775. display: -webkit-box;
  776. -webkit-line-clamp: 2;
  777. -webkit-box-orient: vertical;
  778. }
  779. .goods-mid {
  780. font-size: 24rpx;
  781. color: #999;
  782. }
  783. .goods-buttom {
  784. overflow: hidden;
  785. position: relative;
  786. height: 60rpx;
  787. }
  788. .goods-price {
  789. font-size: 28rpx;
  790. color: #eb0000;
  791. display: inline-block;
  792. }
  793. .stepper {
  794. width: 156rpx;
  795. height: 48rpx;
  796. border-radius: 6rpx;
  797. margin: 0 auto;
  798. display: inline-block;
  799. overflow: hidden;
  800. box-sizing: border-box;
  801. float: right;
  802. }
  803. .stepper text {
  804. width: 44rpx;
  805. line-height: 42rpx;
  806. text-align: center;
  807. float: left;
  808. box-sizing: border-box;
  809. border: 2rpx solid #ccc;
  810. }
  811. .stepper input {
  812. width: 64rpx;
  813. height: 38rpx;
  814. float: left;
  815. text-align: center;
  816. font-size: 28rpx;
  817. display: inline-block;
  818. box-sizing: border-box;
  819. }
  820. .stepper .normal {
  821. color: black;
  822. }
  823. .stepper .disabled {
  824. color: #ccc;
  825. }
  826. .choose-specs {
  827. width: 136rpx;
  828. height: 48rpx;
  829. line-height: 46rpx;
  830. border-radius: 50rpx;
  831. margin: 0 auto;
  832. text-align: center;
  833. display: inline-block;
  834. overflow: hidden;
  835. box-sizing: border-box;
  836. float: right;
  837. font-size: 24rpx;
  838. border: 2rpx solid #ccc;
  839. position: relative;
  840. top: 12rpx;
  841. }
  842. .goods-bottom {
  843. border-top: 2rpx solid #eeeeee;
  844. overflow: hidden;
  845. padding: 20rpx 30rpx;
  846. background-color: #fff;
  847. }
  848. .goods-total {
  849. float: right;
  850. color: #999;
  851. font-size: 28rpx;
  852. }
  853. .goods-total-r {
  854. color: #eb0000;
  855. font-size: 30rpx;
  856. }
  857. .input-box {
  858. margin: 20rpx 0;
  859. background-color: #fff;
  860. }
  861. .form-input-box-item {
  862. overflow: hidden;
  863. padding: 20rpx 30rpx 20rpx 0;
  864. margin-left: 30rpx;
  865. border-bottom: 2rpx solid #eeeeee;
  866. }
  867. .ib-item-left {
  868. display: inline-block;
  869. min-width: 150rpx;
  870. max-width: 600rpx;
  871. font-size: 28rpx;
  872. color: #333;
  873. float: left;
  874. padding: 10rpx 0;
  875. }
  876. .ib-item-right {
  877. min-width: 600rpx;
  878. max-width: 690rpx;
  879. display: inline-block;
  880. color: #666;
  881. font-size: 28rpx;
  882. float: left;
  883. padding: 6rpx 0;
  884. }
  885. .ib-item-input {
  886. color: #666;
  887. font-size: 28rpx;
  888. }
  889. .margin-r {
  890. margin-left: 40rpx;
  891. }
  892. .ib-item-input-c {
  893. color: #999;
  894. font-size: 28rpx;
  895. }
  896. .ib-item-label {
  897. display: inline-block;
  898. position: relative;
  899. min-width: 150rpx;
  900. margin-right: 20rpx;
  901. }
  902. .ib-item-label radio {
  903. position: absolute;
  904. opacity: 0;
  905. width: 40rpx;
  906. height: 40rpx;
  907. }
  908. .ib-item-label-text {
  909. display: inline-block;
  910. margin-left: 60rpx;
  911. position: relative;
  912. top: 2rpx;
  913. }
  914. .label-icon {
  915. position: absolute;
  916. top: 0;
  917. }
  918. .label-icon icon {
  919. margin: 0;
  920. }
  921. .ib-item-mid {
  922. padding-top: 4rpx;
  923. margin: 0;
  924. position: relative;
  925. }
  926. .ib-item-mid picker {
  927. height: 40rpx;
  928. }
  929. .ib-item-mid .weui-select {
  930. border: none;
  931. height: 100%;
  932. line-height: 48rpx;
  933. min-height: 40rpx;
  934. }
  935. .ib-item-mid-text {
  936. margin-left: 40rpx;
  937. color: #999;
  938. }
  939. .icon-img {
  940. position: absolute;
  941. top: 50%;
  942. transform: translateY(-50%);
  943. width: 32rpx;
  944. height: 32rpx;
  945. }
  946. .icon-img-right {
  947. position: absolute;
  948. top: 50%;
  949. transform: translateY(-50%);
  950. width: 32rpx;
  951. height: 32rpx;
  952. right: 0;
  953. }
  954. .form-multiple-rows .form-input-box-item {
  955. border: none;
  956. }
  957. .f-m-r-item {
  958. color: #666;
  959. font-size: 28rpx;
  960. margin-top: 16upx;
  961. }
  962. .f-m-r-item .ib-item-label {
  963. display: block;
  964. margin-bottom: 20rpx;
  965. }
  966. .f-m-r-item .ib-item-label:last-child {
  967. margin-bottom: 0;
  968. }
  969. .various-spec-list {
  970. overflow: hidden;
  971. }
  972. .various-spec-item {
  973. padding: 10rpx 20rpx;
  974. display: inline-block;
  975. border: 2rpx solid #e2e2e2;
  976. margin-right: 20rpx;
  977. margin-bottom: 20rpx;
  978. border-radius: 6rpx;
  979. color: #666;
  980. background-color: #f7f7f7;
  981. min-width: 130rpx;
  982. text-align: center;
  983. }
  984. .vAactive {
  985. border: 2rpx solid #333;
  986. color: #333;
  987. }
  988. .various-spec-list:last-child .various-spec-item {
  989. margin-bottom: 0rpx;
  990. }
  991. .upload-img-list {
  992. overflow: hidden;
  993. }
  994. .upload-img-hd {
  995. position: relative;
  996. width: 150rpx;
  997. height: 150rpx;
  998. border: 2rpx solid #e2e2e2;
  999. background-color: #f7f7f7;
  1000. border-radius: 6rpx;
  1001. box-sizing: border-box;
  1002. float: left;
  1003. margin-left: 30rpx;
  1004. }
  1005. .upload-img-hd input {
  1006. position: absolute;
  1007. width: 100%;
  1008. height: 100%;
  1009. opacity: 0;
  1010. }
  1011. .upload-img-hd image {
  1012. width: 48rpx;
  1013. height: 48rpx;
  1014. position: relative;
  1015. top: 50%;
  1016. left: 50%;
  1017. transform: translate(-50%, -50%);
  1018. }
  1019. .upload-img-bd {
  1020. /* width: 150rpx; */
  1021. /* height: 150rpx; */
  1022. float: left;
  1023. overflow: hidden;
  1024. }
  1025. .upload-img .upload-camera {
  1026. width: 100%;
  1027. height: 100%;
  1028. }
  1029. .upload-img {
  1030. width: 150rpx;
  1031. height: 150rpx;
  1032. position: relative;
  1033. float: left;
  1034. margin-right: 30rpx;
  1035. }
  1036. .upload-img:last-child {
  1037. margin-right: 0;
  1038. }
  1039. .del-img {
  1040. width: 36rpx !important;
  1041. height: 36rpx !important;
  1042. position: absolute;
  1043. right: 0;
  1044. top: 0;
  1045. z-index: 99;
  1046. }
  1047. .ib-item-textarea {
  1048. width: 100%;
  1049. height: 200rpx;
  1050. box-sizing: border-box;
  1051. border: 2rpx solid #e2e2e2;
  1052. background-color: #f7f7f7;
  1053. border-radius: 6rpx;
  1054. padding: 20rpx 30rpx;
  1055. }
  1056. .bottom-btn {
  1057. position: fixed;
  1058. bottom: 0;
  1059. width: 100%;
  1060. z-index: 95;
  1061. }
  1062. .bottom-btn button {
  1063. width: 100%;
  1064. height: 90rpx;
  1065. line-height: 90rpx;
  1066. margin: 0 auto;
  1067. background-color: #333;
  1068. color: #fff;
  1069. font-size: 32rpx;
  1070. border-radius: 0;
  1071. }
  1072. .bottom-btn button::after {
  1073. border-radius: 0;
  1074. }
  1075. .hidden {
  1076. display: none;
  1077. }
  1078. .checkout-list {
  1079. overflow: hidden;
  1080. }
  1081. .checkout-item {
  1082. display: inline-block;
  1083. float: left;
  1084. }
  1085. .checkout-item-c {
  1086. padding: 4rpx 14rpx;
  1087. border: 2rpx solid #ccc;
  1088. margin-right: 10rpx;
  1089. border-radius: 6rpx;
  1090. color: #888;
  1091. }
  1092. .checkout-item-c checkbox {
  1093. display: none;
  1094. }
  1095. .black {
  1096. background-color: rgb(55, 55, 55);
  1097. color: #fff;
  1098. border: 2rpx solid rgb(55, 55, 55);
  1099. }
  1100. /*支付按钮样式*/
  1101. .content-bot {
  1102. margin-top: 18rpx;
  1103. }
  1104. .content-bot>view {
  1105. padding: 16rpx 0;
  1106. margin-bottom: 2rpx;
  1107. position: relative;
  1108. background-color: #fff;
  1109. height: 75rpx;
  1110. }
  1111. .content-bot>view button {
  1112. background-color: #fff;
  1113. width: 100%;
  1114. height: 100%;
  1115. padding: 0;
  1116. position: static;
  1117. text-align: left;
  1118. }
  1119. .content-bot>view button::after {
  1120. border: none;
  1121. }
  1122. .content-bot .left-img {
  1123. display: inline-block;
  1124. height: 82rpx;
  1125. width: 94rpx;
  1126. border-right: 2rpx solid #f4f4f4;
  1127. position: absolute;
  1128. left: 30rpx;
  1129. top: 50%;
  1130. transform: translateY(-50%);
  1131. }
  1132. .content-bot .left-img image {
  1133. width: 64rpx;
  1134. height: 64rpx;
  1135. position: relative;
  1136. top: 8rpx;
  1137. }
  1138. .content-bot-right {
  1139. display: inline-block;
  1140. margin-left: 150rpx;
  1141. position: relative;
  1142. top: 16rpx;
  1143. }
  1144. .modal-box {
  1145. position: fixed;
  1146. width: 100%;
  1147. height: 100%;
  1148. top: 0px;
  1149. background: rgba(0, 0, 0, 0.4);
  1150. overflow: hidden;
  1151. z-index: 1000;
  1152. }
  1153. .modal-body {
  1154. position: fixed;
  1155. bottom: 0;
  1156. background-color: #fff;
  1157. width: 100%;
  1158. z-index: 1001;
  1159. font-size: 28rpx;
  1160. }
  1161. .modal-payment .item {
  1162. height: 80rpx;
  1163. width: 100%;
  1164. line-height: 80rpx;
  1165. text-align: center;
  1166. }
  1167. .modal-payment .immediate-pay {
  1168. height: 80rpx;
  1169. line-height: 80rpx;
  1170. width: 100%;
  1171. text-align: center;
  1172. border: none;
  1173. border-radius: 0;
  1174. border-bottom: 2rpx solid #eee;
  1175. box-sizing: border-box;
  1176. background-color: #fff;
  1177. }
  1178. .modal-payment .immediate-pay::after {
  1179. border: none;
  1180. }
  1181. .specs-goods-t {
  1182. position: relative;
  1183. padding: 30rpx;
  1184. border-bottom: 2rpx solid #f3f3f3;
  1185. }
  1186. .specs-goods-information {
  1187. width: 520rpx;
  1188. display: inline-block;
  1189. }
  1190. .specs-goods-information .specs-goods-name {
  1191. width: 100%;
  1192. overflow: hidden;
  1193. white-space: nowrap;
  1194. text-overflow: ellipsis;
  1195. display: block;
  1196. font-size: 24rpx;
  1197. margin-bottom: 20rpx;
  1198. }
  1199. .specs-goods-information .specs-goods-price {
  1200. display: block;
  1201. color: #ff3b44;
  1202. font-size: 30rpx;
  1203. }
  1204. .close-btn {
  1205. width: 40rpx;
  1206. height: 40rpx;
  1207. border-radius: 50%;
  1208. display: inline-block;
  1209. position: absolute;
  1210. right: 30rpx;
  1211. }
  1212. .close-btn image {
  1213. width: 100%;
  1214. height: 100%;
  1215. }
  1216. .modal-body .detail-footer-right {
  1217. width: 100%;
  1218. }
  1219. .gray-text {
  1220. color: #a5a5a5;
  1221. font-size: 28rpx;
  1222. }
  1223. .salespromotion-service-name {
  1224. color: #a5a5a5;
  1225. margin-right: 26rpx;
  1226. }
  1227. .color .salespromotion-service-name {
  1228. float: left;
  1229. }
  1230. .salespromotion-service-body,
  1231. .salespromotion-service-body view {
  1232. display: inline-block;
  1233. }
  1234. .sales-promotion .salespromotion-service-body {
  1235. margin: auto;
  1236. }
  1237. .sales-promotion text.salespromotion-service-body {
  1238. background-color: #ff3b44;
  1239. color: #fff;
  1240. font-size: 18rpx;
  1241. margin-left: 0rpx;
  1242. border-radius: 10rpx;
  1243. height: 28rpx;
  1244. line-height: 28rpx;
  1245. padding: 0 10rpx;
  1246. }
  1247. .salespromotion-service-body view {
  1248. width: 170rpx;
  1249. height: 40rpx;
  1250. overflow: hidden;
  1251. white-space: nowrap;
  1252. text-overflow: ellipsis;
  1253. position: relative;
  1254. left: -6rpx;
  1255. }
  1256. .salespromotion-service-body view:first-child {
  1257. margin-right: 8rpx;
  1258. }
  1259. .color-number {
  1260. font-size: 28rpx;
  1261. border-bottom: 14rpx solid #f3f3f3;
  1262. }
  1263. .color,
  1264. .specifications,
  1265. .number {
  1266. padding: 22rpx 25rpx;
  1267. border-bottom: 2rpx solid #f3f3f3;
  1268. overflow: hidden;
  1269. }
  1270. .color {
  1271. padding-bottom: 8rpx;
  1272. }
  1273. .color .salespromotion-service-b,
  1274. .specifications .salespromotion-service-b {
  1275. width: 600rpx;
  1276. display: inline-block;
  1277. float: left;
  1278. }
  1279. .color .salespromotion-service-b>view,
  1280. .specifications .salespromotion-service-b>view {
  1281. padding: 2rpx 20rpx;
  1282. display: inline-block;
  1283. text-align: center;
  1284. border: 2rpx solid #e0e0e0;
  1285. border-radius: 8rpx;
  1286. color: #666;
  1287. margin-right: 22rpx;
  1288. margin-bottom: 12rpx;
  1289. }
  1290. .pitch-on {
  1291. border: 2rpx solid #ff3b44;
  1292. background-color: #ff3b44;
  1293. color: #fff !important;
  1294. }
  1295. .nothing {
  1296. border: 2rpx dashed #e0e0e0 !important;
  1297. color: #c9c9c9 !important;
  1298. }
  1299. .specs-goods-c {
  1300. margin-bottom: 100rpx;
  1301. max-height: 432rpx;
  1302. }
  1303. .number {
  1304. padding: 22rpx 25rpx;
  1305. }
  1306. .number>text {
  1307. color: #999;
  1308. position: relative;
  1309. font-size: 28rpx;
  1310. }
  1311. .detail-footer {
  1312. overflow: hidden;
  1313. height: 100rpx;
  1314. position: fixed;
  1315. bottom: 0;
  1316. width: 750rpx;
  1317. text-align: center;
  1318. z-index: 1000;
  1319. }
  1320. .detail-footer-left {
  1321. width: 30%;
  1322. height: 100rpx;
  1323. font-size: 24rpx;
  1324. color: #666;
  1325. background-color: #f7f7f7;
  1326. padding-top: 10rpx;
  1327. box-sizing: border-box;
  1328. display: inline-block;
  1329. }
  1330. .detail-footer-left>view {
  1331. width: 50%;
  1332. box-sizing: border-box;
  1333. float: left;
  1334. display: inline-block;
  1335. }
  1336. .detail-footer-left>view image {
  1337. height: 36rpx;
  1338. width: 36rpx;
  1339. }
  1340. .detail-footer-left>view text {
  1341. display: block;
  1342. }
  1343. .detail-footer-right {
  1344. width: 70%;
  1345. display: inline-block;
  1346. height: 100rpx;
  1347. line-height: 100rpx;
  1348. float: right;
  1349. font-size: 28rpx;
  1350. color: #fff;
  1351. box-sizing: border-box;
  1352. }
  1353. .detail-footer-right>view {
  1354. width: 100%;
  1355. display: inline-block;
  1356. }
  1357. .modal-body .detail-footer-right {
  1358. width: 100%;
  1359. }
  1360. .detail-footer-right>view {
  1361. background-color: #333;
  1362. }
  1363. .order-num {
  1364. display: block;
  1365. min-width: 16rpx;
  1366. height: 28rpx;
  1367. line-height: 28rpx;
  1368. background-color: #ff3b44;
  1369. color: #fff;
  1370. font-size: 16rpx;
  1371. border-radius: 50rpx;
  1372. position: absolute;
  1373. right: 0rpx;
  1374. top: 0rpx;
  1375. padding: 0 6rpx;
  1376. text-align: center;
  1377. }
  1378. .uni-list-cell-pd {
  1379. /* width: 200upx; */
  1380. margin-right: 40upx;
  1381. }
  1382. .invoice-type-icon,
  1383. .invoice-type-c {
  1384. display: inline-block;
  1385. }
  1386. .lvvpopref {
  1387. z-index: 100;
  1388. }
  1389. </style>

goods

index
group.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="nav-back">
  4. <view class="back-btn" @click="backBtn()">
  5. <image class="icon" src="/static/image/back-black.png" mode=""></image>
  6. </view>
  7. </view>
  8. <view class="content-top">
  9. <!-- 轮播图 -->
  10. <view class='swiper'>
  11. <swiper class="swiper-c" :indicator-dots="swiper.indicatorDots" :autoplay="swiper.autoplay" :interval="swiper.interval"
  12. :duration="swiper.duration">
  13. <swiper-item class="have-none" v-for="(item, index) in goodsInfo.album" :key="index" @click="clickImg(item)">
  14. <image class='' :src='item' mode="aspectFill"></image>
  15. </swiper-item>
  16. </swiper>
  17. </view>
  18. <!-- 轮播图end -->
  19. <view class='cell-group'>
  20. <!-- 倒计时 -->
  21. <view class='price-salesvolume' v-if="lasttime.hour!==false">
  22. <view class='commodity-price'>
  23. <text class='current-price'>¥{{product.price}}</text>
  24. <text class='cost-price' v-if="parseFloat(product.mktprice)>0">¥{{product.mktprice}}</text>
  25. </view>
  26. <view class='commodity-salesvolume'>
  27. <text>已售{{goodsInfo.buy_count}}件/剩余{{product.stock}}件</text>
  28. <text>累计销售{{goodsInfo.buy_count}}件</text>
  29. </view>
  30. <view class='commodity-time-img'></view>
  31. <view class='commodity-time'>
  32. <text>距结束仅剩</text>
  33. <view class='commodity-day'>
  34. <uni-countdown :show-day="false" :hour="lasttime.hour" :minute="lasttime.minute" :second="lasttime.second"></uni-countdown>
  35. </view>
  36. </view>
  37. <!-- <view class='commodity-time'>
  38. 已结束
  39. </view> -->
  40. </view>
  41. <!-- 倒计时end -->
  42. <!-- 分享 -->
  43. <view class='cell-item goods-details'>
  44. <view class='cell-item-hd'>
  45. <view class='cell-hd-title'>
  46. <view class="color-3 fsz28 cell-hd-title-view">
  47. {{ product.name }}
  48. </view>
  49. <view v-if="goodsInfo.brief" class="color-9 fsz24 cell-hd-title-view">
  50. {{ goodsInfo.brief }}
  51. </view>
  52. </view>
  53. </view>
  54. <view class='cell-item-ft'>
  55. <image class='cell-ft-next icon' @click="goShare()" src='/static/image/share.png'></image>
  56. </view>
  57. </view>
  58. <!-- 分享end -->
  59. <!-- 促销 -->
  60. <view class='cell-item goods-title-item' v-if="promotion.length">
  61. <view class='cell-item-hd'>
  62. <view class='cell-hd-title'>促销</view>
  63. </view>
  64. <view class='cell-item-bd'>
  65. <view class="romotion-tip">
  66. <view class="romotion-tip-item" :class="item.type !== 2 ? 'bg-gray' : ''" v-for="(item, index) in promotion"
  67. :key="index">
  68. {{ item.name }}
  69. </view>
  70. </view>
  71. </view>
  72. </view>
  73. <!-- 促销end -->
  74. <!-- 规格 -->
  75. <view class='cell-item goods-title-item' v-if="isSpes">
  76. <view class='cell-item-hd'>
  77. <view class='cell-hd-title'>规格</view>
  78. </view>
  79. <view class='cell-item-bd' @click="toshow()">
  80. <text class='cell-bd-text'>{{ product.spes_desc }}</text>
  81. </view>
  82. </view>
  83. <!-- 规格end -->
  84. <!-- 说明 -->
  85. <view class='cell-item goods-title-item'>
  86. <view class='cell-item-hd'>
  87. <view class='cell-hd-title'>说明</view>
  88. </view>
  89. <view class='cell-item-bd'>
  90. <view class="cell-bd-view">
  91. <image class="goods-title-item-ic" src="/static/image/ic-dui.png" mode=""></image>
  92. <text class="cell-bd-text">24小时内发货</text>
  93. </view>
  94. <view class="cell-bd-view">
  95. <image class="goods-title-item-ic" src="/static/image/ic-dui.png" mode=""></image>
  96. <text class="cell-bd-text">7天拆封无条件退货</text>
  97. </view>
  98. </view>
  99. </view>
  100. <!-- 说明end -->
  101. </view>
  102. <view class="goods-content">
  103. <uni-segmented-control :current="current" :values="items" @clickItem="onClickItem" style-type="text" active-color="#333"></uni-segmented-control>
  104. <view class="goods-content-c">
  105. <view class="goods-detail" v-if="current === 0">
  106. <jshopContent :content="goodsInfo.intro" v-if="goodsInfo.intro"></jshopContent>
  107. </view>
  108. <view class="goods-parameter" v-else-if="current === 1">
  109. <view class='cell-group' v-if="goodsParams.length">
  110. <view class='cell-item' v-for="(item, index) in goodsParams" :key="index">
  111. <view class='cell-item-hd'>
  112. <view class='cell-hd-title'>{{ item.name }}</view>
  113. </view>
  114. <view class='cell-item-bd'>
  115. <text class='cell-bd-text'>{{ item.value }}</text>
  116. </view>
  117. </view>
  118. <!-- <view class='cell-item'>
  119. <view class='cell-item-hd'>
  120. <view class='cell-hd-title'>保修政策</view>
  121. </view>
  122. <view class='cell-item-bd'>
  123. <view class="cell-bd-view">
  124. <text class="cell-bd-text">二十日内包修理或换货</text>
  125. </view>
  126. <view class="cell-bd-view">
  127. <text class="cell-bd-text">一年内包修理</text>
  128. </view>
  129. </view>
  130. </view> -->
  131. </view>
  132. </view>
  133. <view class="goods-assess" v-else-if="current === 2">
  134. <view v-if="goodsComments.list.length">
  135. <view class="goods-assess-item" v-for="(item, index) in goodsComments.list" :key="index">
  136. <view class='cell-group'>
  137. <view class='cell-item goods-title-item'>
  138. <view class='cell-item-hd'>
  139. <image class='user-head-img' :src='item.user.avatar' mode="aspectFill"></image>
  140. </view>
  141. <view class='cell-item-bd'>
  142. <view class="cell-bd-view">
  143. <text class="cell-bd-text">{{ item.user.nickname }}</text>
  144. <view class="cell-bd-text-right">
  145. <uni-rate size="16" disabled="true" :value="item.score"></uni-rate>
  146. </view>
  147. </view>
  148. <view class="cell-bd-view">
  149. <text class="cell-bd-text color-9" style="margin-right: 16upx;">{{ item.ctime }}</text>
  150. <text class="cell-bd-text color-9">{{ item.addon }}</text>
  151. </view>
  152. </view>
  153. </view>
  154. </view>
  155. <view class="gai-body">
  156. <view class="gai-body-text">
  157. {{ item.content }}
  158. </view>
  159. <view class="gai-body-img" v-if="item.images_url.length">
  160. <image :src="img" mode="aspectFill" v-for="(img, key) in item.images_url" :key="key" @click="clickImg(img)"></image>
  161. </view>
  162. </view>
  163. </view>
  164. <uni-load-more :status="goodsComments.loadStatus"></uni-load-more>
  165. </view>
  166. <view class="comment-none" v-else>
  167. <image class="comment-none-img" src="/static/image/order.png" mode=""></image>
  168. </view>
  169. </view>
  170. </view>
  171. </view>
  172. </view>
  173. <lvv-popup position="bottom" ref="share">
  174. <!-- #ifdef H5 -->
  175. <shareByH5 :goodsId="goodsInfo.id" :shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief"
  176. :shareHref="shareHref" @close="closeShare()"></shareByH5>
  177. <!-- #endif -->
  178. <!-- #ifdef MP-WEIXIN -->
  179. <shareByWx :goodsId="goodsInfo.id" :shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief"
  180. :shareHref="shareHref" @close="closeShare()"></shareByWx>
  181. <!-- #endif -->
  182. <!-- #ifdef MP-ALIPAY -->
  183. <shareByAli :goodsId="goodsInfo.id" :shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief"
  184. :shareHref="shareHref" @close="closeShare()"></shareByAli>
  185. <!-- #endif -->
  186. <!-- #ifdef APP-PLUS -->
  187. <shareByApp :goodsId="goodsInfo.id" :shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief"
  188. :shareHref="shareHref" @close="closeShare()"></shareByApp>
  189. <!-- #endif -->
  190. </lvv-popup>
  191. <!-- 弹出层 -->
  192. <lvv-popup position="bottom" ref="lvvpopref">
  193. <view style="width: 100%;max-height: 804upx;background: #FFFFFF;position: absolute;left:0;bottom: 0;">
  194. <view class="pop-c">
  195. <view class="pop-t">
  196. <view class='goods-img'>
  197. <image :src='product.image_path' mode='aspectFill'></image>
  198. </view>
  199. <view class='goods-information'>
  200. <view class='pop-goods-name'>{{ product.name }}</view>
  201. <view class='pop-goods-price red-price'>¥ {{ product.price }}</view>
  202. </view>
  203. <view class='close-btn' @click="toclose()">
  204. <image src='/static/image/close.png'></image>
  205. </view>
  206. </view>
  207. <scroll-view class="pop-m" scroll-y="true" style="max-height: 560upx;">
  208. <spec :spesData="product.default_spes_desc" ref="spec" @changeSpes="changeSpes"></spec>
  209. <view class="goods-number">
  210. <text class="pop-m-title">数量</text>
  211. <view class="pop-m-bd-in">
  212. <uni-number-box :min="minNums" :max="product.stock" :value="buyNum" @change="bindChange"></uni-number-box>
  213. </view>
  214. </view>
  215. </scroll-view>
  216. <view class="pop-b">
  217. <!-- <button class='btn btn-square btn-g btn-half' @click="addToCart">加入购物车</button>
  218. <button class='btn btn-square btn-b btn-half' @click="buyNow">立即购买</button> -->
  219. <button class='btn btn-square btn-b btn-all' hover-class="btn-hover2" @click="buyNow()" v-if="product.stock">确定</button>
  220. <button class='btn btn-square btn-g btn-all' v-else>已售罄</button>
  221. </view>
  222. </view>
  223. </view>
  224. </lvv-popup>
  225. <!-- 弹出层end -->
  226. <div id="qrCode" ref="qrCodeDiv"></div>
  227. <!-- 底部按钮 -->
  228. <view class="goods-bottom">
  229. <view class="goods-bottom-ic" @click="collection">
  230. <image class="icon" :src="isfav ? favLogo[1] : favLogo[0]" mode=""></image>
  231. <view v-if="!isfav">收藏</view>
  232. <view v-if="isfav">已收藏</view>
  233. </view>
  234. <view class="goods-bottom-ic" @click="redirectCart">
  235. <view class="badge color-f" v-if="cartNums">{{ cartNums }}</view>
  236. <image class="icon" src="/static/image/ic-me-car.png" mode=""></image>
  237. <view>购物车</view>
  238. </view>
  239. <button class='btn btn-square btn-b tl' @click="toshow(2)" hover-class="btn-hover2">立即{{typeName}}</button>
  240. </view>
  241. <!-- 底部按钮end -->
  242. <!-- 右边浮动球 -->
  243. <!-- <view class="right-ball">
  244. <view class="" @click="goIndex()">
  245. <image class="icon" src="/static/image/tab-ic-hom-selected.png" mode=""></image>
  246. </view>
  247. </view> -->
  248. <uni-fab :pattern="pattern" :content="content" :horizontal="horizontal" :vertical="vertical" :direction="direction"
  249. @trigger="trigger"></uni-fab>
  250. </view>
  251. </template>
  252. <script>
  253. import uniSegmentedControl from "@/components/uni-segmented-control/uni-segmented-control.vue";
  254. import lvvPopup from '@/components/lvv-popup/lvv-popup.vue';
  255. import uniNumberBox from "@/components/uni-number-box/uni-number-box.vue";
  256. import uniRate from "@/components/uni-rate/uni-rate.vue";
  257. import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue';
  258. import uniFab from '@/components/uni-fab/uni-fab.vue';
  259. import {
  260. get
  261. } from '@/config/db.js';
  262. import {
  263. apiBaseUrl
  264. } from '@/config/config.js'
  265. import uniCountdown from "@/components/uni-countdown/uni-countdown.vue"
  266. import spec from '@/components/spec/spec.vue'
  267. // #ifdef H5
  268. import shareByH5 from '@/components/share/shareByh5.vue'
  269. // #endif
  270. // #ifdef MP-WEIXIN
  271. import shareByWx from '@/components/share/shareByWx.vue'
  272. // #endif
  273. // #ifdef MP-ALIPAY
  274. import shareByAli from '@/components/share/shareByAli.vue'
  275. // #endif
  276. // #ifdef APP-PLUS
  277. import shareByApp from '@/components/share/shareByApp.vue'
  278. // #endif
  279. import jshopContent from '@/components/jshop/jshop-content.vue'//视频和文本解析组件
  280. export default {
  281. components: {
  282. uniSegmentedControl,
  283. lvvPopup,
  284. uniNumberBox,
  285. uniRate,
  286. uniLoadMore,
  287. uniFab,
  288. uniCountdown,
  289. spec,
  290. jshopContent,
  291. // #ifdef H5
  292. shareByH5,
  293. // #endif
  294. // #ifdef MP-WEIXIN
  295. shareByWx,
  296. // #endif
  297. // #ifdef MP-ALIPAY
  298. shareByAli,
  299. // #endif
  300. // #ifdef APP-PLUS
  301. shareByApp,
  302. // #endif
  303. },
  304. data() {
  305. return {
  306. myShareCode: '', //分享Code
  307. swiper: {
  308. indicatorDots: true,
  309. autoplay: true,
  310. interval: 3000,
  311. duration: 800,
  312. }, // 轮播图属性设置
  313. items: ['图文详情', '商品参数', '买家评论'],
  314. current: 0, // init tab位
  315. goodsId: 0, // 商品id
  316. groupId: 0, // 团购ID
  317. goodsInfo: {}, // 商品详情
  318. cartNums: 0, // 购物车数量
  319. product: {}, // 规格详情
  320. goodsParams: [], // 商品参数信息
  321. goodsComments: {
  322. loadStatus: 'more',
  323. page: 1,
  324. limit: 5,
  325. list: []
  326. }, // 商品评论信息
  327. buyNum: 1, // 选定的购买数量
  328. minBuyNum: 1, // 最小可购买数量
  329. type: 1,
  330. isfav: false, // 商品是否收藏
  331. favLogo: [
  332. '/static/image/ic-me-collect.png',
  333. '/static/image/ic-me-collect2.png'
  334. ],
  335. horizontal: 'right', //右下角弹出按钮
  336. vertical: 'bottom',
  337. direction: 'vertical',
  338. pattern: {
  339. color: '#7A7E83',
  340. backgroundColor: '#fff',
  341. selectedColor: '#007AFF',
  342. buttonColor: "#FF7159"
  343. },
  344. content: [{
  345. iconPath: '/static/image/tab-ic-hom-selected.png',
  346. selectedIconPath: '/static/image/tab-ic-hom-unselected.png',
  347. // text: '首页',
  348. active: false,
  349. url: '/pages/index/index'
  350. },
  351. {
  352. iconPath: '/static/image/tab-ic-me-selected.png',
  353. selectedIconPath: '/static/image/tab-ic-me-unselected.png',
  354. // text: '个人中心',
  355. active: false,
  356. url: '/pages/member/index/index'
  357. },
  358. ],
  359. indicatorDots: false,
  360. autoplay: false,
  361. interval: 2000,
  362. duration: 500,
  363. lasttime: {
  364. hour: false,
  365. minute: 0,
  366. second: 0
  367. },
  368. }
  369. },
  370. onLoad(e) {
  371. this.goodsId = e.id;
  372. this.groupId = e.group_id;
  373. if (this.goodsId && this.groupId) {
  374. this.getGoodsInfo();
  375. this.getGoodsParams();
  376. this.getGoodsComments();
  377. } else {
  378. this.$common.errorToShow('获取失败', () => {
  379. uni.navigateBack({
  380. delta: 1
  381. });
  382. });
  383. }
  384. // 获取购物车数量
  385. this.getCartNums();
  386. this.getMyShareCode();
  387. },
  388. computed: {
  389. // 规格切换计算规格商品的 可购买数量
  390. minNums() {
  391. return this.product.stock > this.minBuyNum ? this.minBuyNum : this.product.stock;
  392. },
  393. // 判断商品是否是多规格商品 (为了兼容小程序 只能写在计算属性里面了)
  394. isSpes() {
  395. if (this.product.hasOwnProperty('default_spes_desc') && Object.keys(this.product.default_spes_desc).length) {
  396. return true;
  397. } else {
  398. return false;
  399. }
  400. },
  401. // 优惠信息重新组装
  402. promotion() {
  403. let arr = [];
  404. if (this.product.promotion_list) {
  405. for (let k in this.product.promotion_list) {
  406. arr.push(this.product.promotion_list[k]);
  407. }
  408. }
  409. return arr;
  410. },
  411. typeName() {
  412. return this.goodsInfo.group_type == 3 ? '团购' : '秒杀';
  413. },
  414. shareHref() {
  415. let pages = getCurrentPages()
  416. let page = pages[pages.length - 1]
  417. // #ifdef H5 || MP-WEIXIN || APP-PLUS || APP-PLUS-NVUE
  418. return apiBaseUrl + 'wap/' + page.route + '?id=' + this.goodsId + '&group_id=' + this.groupId;
  419. // #endif
  420. // #ifdef MP-ALIPAY
  421. return apiBaseUrl + 'wap/' + page.__proto__.route + '?id=' + this.goodsId + '&group_id=' + this.groupId;
  422. // #endif
  423. }
  424. },
  425. onReachBottom() {
  426. if (this.current === 2 && this.goodsComments.loadStatus === 'more') {
  427. this.getGoodsComments();
  428. }
  429. },
  430. methods: {
  431. // 返回上一页
  432. backBtn() {
  433. uni.navigateBack({
  434. delta: 1
  435. });
  436. },
  437. getGoodsInfo() {
  438. let data = {
  439. id: this.goodsId,
  440. group_id: this.groupId,
  441. }
  442. // 如果用户已经登录 要传用户token
  443. let userToken = get('userToken');
  444. if (userToken) {
  445. data['token'] = userToken;
  446. }
  447. let _this = this;
  448. this.$api.groupInfo(data, res => {
  449. if (res.status) {
  450. if (res.data.length < 1) {
  451. this.$common.errorToShow('该商品不存在,请返回重新选择商品。', () => {
  452. uni.navigateBack({
  453. delta: 1
  454. });
  455. });
  456. } else if (res.data.marketable != 1) {
  457. this.$common.errorToShow('该商品已下架,请返回重新选择商品。', () => {
  458. uni.navigateBack({
  459. delta: 1
  460. });
  461. });
  462. } else {
  463. let info = res.data;
  464. let products = res.data.product;
  465. this.goodsInfo = info;
  466. this.isfav = this.goodsInfo.isfav === 'true' ? true : false;
  467. this.product = this.spesClassHandle(products);
  468. let lasttime = res.data.lasttime;
  469. _this.lasttime = lasttime;
  470. // 判断如果登录用户添加商品浏览足迹
  471. if (userToken) {
  472. this.goodsBrowsing();
  473. }
  474. }
  475. }
  476. });
  477. },
  478. // 获取购物车数量
  479. getCartNums() {
  480. let userToken = this.$db.get("userToken");
  481. if (userToken && userToken != '') {
  482. // 获取购物车数量
  483. this.$api.getCartNum({}, res => {
  484. if (res.status) {
  485. this.cartNums = res.data;
  486. }
  487. });
  488. }
  489. },
  490. // 显示modal弹出框
  491. toshow(type) {
  492. this.type = type;
  493. this.$refs.lvvpopref.show();
  494. },
  495. // 关闭modal弹出框
  496. toclose() {
  497. this.$refs.lvvpopref.close();
  498. },
  499. // 切换商品规格
  500. changeSpes(obj) {
  501. let index = obj.v;
  502. let key = obj.k;
  503. if (this.product.default_spes_desc[index][key].hasOwnProperty('product_id') && this.product.default_spes_desc[index]
  504. [key].product_id) {
  505. let data = {
  506. 'id': this.product.default_spes_desc[index][key].product_id
  507. };
  508. let userToken = this.$db.get("userToken");
  509. if (userToken) {
  510. data['token'] = userToken;
  511. }
  512. this.$api.getProductInfo(data, res => {
  513. if (res.status == true) {
  514. // 切换规格判断可购买数量
  515. this.buyNum = res.data.stock > this.minBuyNum ? this.minBuyNum : res.data.stock;
  516. this.product = this.spesClassHandle(res.data);
  517. }
  518. });
  519. uni.showLoading({
  520. title: '加载中'
  521. });
  522. setTimeout(function() {
  523. uni.hideLoading();
  524. }, 1000);
  525. }
  526. },
  527. // 多规格样式统一处理
  528. spesClassHandle(products) {
  529. // 判断是否是多规格 (是否有默认规格)
  530. if (products.hasOwnProperty('default_spes_desc')) {
  531. let spes = products.default_spes_desc;
  532. for (let key in spes) {
  533. for (let i in spes[key]) {
  534. if (spes[key][i].hasOwnProperty('is_default') && spes[key][i].is_default === true) {
  535. this.$set(spes[key][i], 'cla', 'pop-m-item selected');
  536. } else if (spes[key][i].hasOwnProperty('product_id') && spes[key][i].product_id) {
  537. this.$set(spes[key][i], 'cla', 'pop-m-item not-selected');
  538. } else {
  539. this.$set(spes[key][i], 'cla', 'pop-m-item none');
  540. }
  541. }
  542. }
  543. products.default_spes_desc = spes;
  544. }
  545. return products;
  546. },
  547. // 购买数量加减操作
  548. bindChange(val) {
  549. this.buyNum = val;
  550. },
  551. // 商品收藏/取消
  552. collection() {
  553. let data = {
  554. goods_id: this.goodsInfo.id
  555. }
  556. this.$api.goodsCollection(data, res => {
  557. if (res.status) {
  558. this.isfav = !this.isfav;
  559. this.$common.successToShow(res.msg);
  560. } else {
  561. this.$common.errorToShow(res.msg);
  562. }
  563. })
  564. },
  565. // tab点击切换
  566. onClickItem(index) {
  567. if (this.current !== index) {
  568. this.current = index;
  569. }
  570. },
  571. // 获取商品参数信息
  572. getGoodsParams() {
  573. this.$api.goodsParams({
  574. id: this.goodsId
  575. }, res => {
  576. if (res.status == true) {
  577. this.goodsParams = res.data;
  578. }
  579. })
  580. },
  581. // 获取商品评论信息
  582. getGoodsComments() {
  583. let data = {
  584. page: this.goodsComments.page,
  585. limit: this.goodsComments.limit,
  586. goods_id: this.goodsId
  587. }
  588. this.goodsComments.loadStatus = 'loading';
  589. this.$api.goodsComment(data, res => {
  590. if (res.status == true) {
  591. let _list = res.data.list;
  592. // 如果评论没有图片 在这块作处理否则控制台报错
  593. _list.forEach(item => {
  594. item.ctime = this.$common.timeToDate(item.ctime)
  595. if (!item.hasOwnProperty('images_url')) {
  596. this.$set(item, 'images_url', [])
  597. }
  598. });
  599. this.goodsComments.list = [...this.goodsComments.list, ..._list];
  600. // 根据count数量判断是否还有数据
  601. if (res.data.count > this.goodsComments.list.length) {
  602. this.goodsComments.loadStatus = 'more';
  603. this.goodsComments.page++;
  604. } else {
  605. this.goodsComments.loadStatus = 'noMore';
  606. }
  607. } else {
  608. this.$common.errorToShow(res.msg);
  609. }
  610. })
  611. },
  612. // 添加商品浏览足迹
  613. goodsBrowsing() {
  614. let data = {
  615. goods_id: this.goodsInfo.id
  616. }
  617. this.$api.addGoodsBrowsing(data, res => {});
  618. },
  619. // 立即购买
  620. buyNow() {
  621. if (this.buyNum > 0) {
  622. let data = {
  623. product_id: this.product.id,
  624. nums: this.buyNum,
  625. order_type: 1,
  626. }
  627. this.$api.addCart(data, res => {
  628. if (res.status) {
  629. this.toclose();
  630. let cartIds = res.data;
  631. this.$common.navigateTo('/pages/goods/place-order/index?cart_ids=' + JSON.stringify(cartIds));
  632. } else {
  633. this.$common.errorToShow(res.msg);
  634. }
  635. })
  636. }
  637. },
  638. // 拼团
  639. Group() {
  640. if (this.buyNum > 0) {
  641. let data = {
  642. product_id: this.product.id,
  643. nums: this.buyNum,
  644. order_type: this.type, // 区分购买和拼团
  645. }
  646. this.$api.addCart(data, res => {
  647. if (res.status) {
  648. this.toclose();
  649. let cartIds = res.data;
  650. this.$common.navigateTo('/pages/goods/place-order/index?cart_ids=' + JSON.stringify(cartIds));
  651. }
  652. })
  653. }
  654. },
  655. // 购物车页面跳转
  656. redirectCart() {
  657. uni.switchTab({
  658. url: '/pages/cart/index/index'
  659. });
  660. },
  661. trigger(e) {
  662. this.content[e.index].active = !e.item.active;
  663. uni.switchTab({
  664. url: e.item.url
  665. })
  666. },
  667. // 跳转到h5分享页面
  668. goShare() {
  669. this.$refs.share.show();
  670. },
  671. closeShare() {
  672. this.$refs.share.close();
  673. },
  674. // 图片点击放大
  675. clickImg(imgs) {
  676. // 预览图片
  677. uni.previewImage({
  678. urls: imgs.split()
  679. });
  680. },
  681. getMyShareCode() {
  682. let userToken = this.$db.get("userToken");
  683. if (userToken && userToken != '') {
  684. // 获取我的分享码
  685. this.$api.shareCode({}, res => {
  686. if (res.status) {
  687. this.myShareCode = res.data ? res.data : '';
  688. }
  689. });
  690. }
  691. }
  692. },
  693. //分享
  694. onShareAppMessage() {
  695. let myInviteCode = this.myShareCode ? this.myShareCode : '';
  696. let ins = this.$common.shareParameterDecode('type=6&id=' + this.goodsId + '&group_id=' + this.groupId + '&invite=' +
  697. myInviteCode);
  698. let path = '/pages/share/jump?scene=' + ins;
  699. return {
  700. title: this.goodsInfo.name,
  701. // #ifdef MP-ALIPAY
  702. desc: this.goodsInfo.brief,
  703. // #endif
  704. imageUrl: this.goodsInfo.album[0],
  705. path: path
  706. }
  707. }
  708. }
  709. </script>
  710. <style>
  711. .swiper {
  712. height: 750upx;
  713. }
  714. .goods-top {
  715. border-bottom: 0;
  716. }
  717. .goods-top .goods-price {
  718. font-size: 38upx;
  719. }
  720. .cost-price {
  721. font-size: 28upx !important;
  722. bottom: -10upx;
  723. color: #999;
  724. text-decoration: line-through;
  725. }
  726. .goods-top .cell-item-ft {
  727. font-size: 20upx;
  728. color: #666;
  729. }
  730. .goods-details {
  731. padding-top: 16upx;
  732. }
  733. .goods-details .cell-hd-title {
  734. width: 620upx;
  735. }
  736. .goods-details .cell-hd-title .cell-hd-title-view {
  737. width: 100%;
  738. display: -webkit-box;
  739. -webkit-box-orient: vertical;
  740. -webkit-line-clamp: 2;
  741. overflow: hidden;
  742. }
  743. .goods-details .cell-hd-title .cell-hd-title-view:last-child {
  744. margin-top: 10upx;
  745. }
  746. .goods-details .cell-item-ft {
  747. top: 24upx;
  748. }
  749. .goods-title-item .cell-item-hd {
  750. min-width: 60upx;
  751. color: #666;
  752. font-size: 24upx;
  753. }
  754. .goods-title-item .cell-item-bd {
  755. color: #333;
  756. font-size: 24upx;
  757. }
  758. .goods-title-item .cell-bd-text {
  759. bottom: 0;
  760. }
  761. .cell-bd-view {
  762. position: relative;
  763. overflow: hidden;
  764. }
  765. .cell-bd-view:first-child {
  766. margin-bottom: 8upx;
  767. }
  768. .goods-title-item-ic {
  769. width: 22upx;
  770. height: 22upx;
  771. position: absolute;
  772. top: 50%;
  773. transform: translateY(-50%);
  774. /* #ifdef MP-ALIPAY */
  775. background-size: 100% 100%;
  776. /* #endif */
  777. }
  778. .cell-bd-view .cell-bd-text {
  779. margin-left: 30upx;
  780. }
  781. .goods-content {
  782. margin-top: 26upx;
  783. background-color: #fff;
  784. padding: 26upx 0;
  785. }
  786. .goods-content-c {}
  787. .goods-parameter {
  788. padding: 10upx 26upx;
  789. }
  790. .goods-bottom,
  791. .pop-b {
  792. background-color: #fff;
  793. position: fixed;
  794. bottom: 0;
  795. height: 90upx;
  796. width: 100%;
  797. overflow: hidden;
  798. box-shadow: 0 0 20upx #ccc;
  799. }
  800. .goods-bottom button {
  801. height: 100%;
  802. width: 35%;
  803. }
  804. .goods-bottom-ic {
  805. display: inline-block;
  806. position: relative;
  807. text-align: center;
  808. height: 100%;
  809. width: 15%;
  810. float: left;
  811. font-size: 22upx;
  812. color: #666;
  813. }
  814. .goods-bottom-ic .icon {
  815. position: relative;
  816. top: 6upx;
  817. /* left: -6upx; */
  818. /* #ifdef MP-ALIPAY */
  819. background-size: 100% 100%;
  820. /* #endif */
  821. }
  822. .goods-bottom .btn-g {
  823. color: #333;
  824. background-color: #D9D9D9;
  825. }
  826. .goods-parameter .cell-item {
  827. border-bottom: none;
  828. margin-left: 0;
  829. }
  830. .goods-parameter .cell-item-hd {
  831. color: #333;
  832. font-size: 24upx;
  833. }
  834. .goods-parameter .cell-item-bd {
  835. color: #999;
  836. }
  837. .goods-parameter .cell-item-bd .cell-bd-text {
  838. bottom: 0;
  839. }
  840. .goods-parameter .cell-bd-text {
  841. margin-left: 0;
  842. }
  843. .pop-t {
  844. position: relative;
  845. padding: 30upx 26upx;
  846. border-bottom: 2upx solid #f3f3f3;
  847. /* box-shadow: 0 0 20upx #ccc; */
  848. }
  849. .goods-img {
  850. width: 160upx;
  851. height: 160upx;
  852. position: absolute;
  853. top: -20upx;
  854. background-color: #fff;
  855. border-radius: 6upx;
  856. border: 2upx solid #fff;
  857. }
  858. .goods-img image {
  859. height: 100%;
  860. width: 100%;
  861. }
  862. .goods-information {
  863. width: 420upx;
  864. display: inline-block;
  865. margin-left: 180upx;
  866. }
  867. .pop-goods-name {
  868. width: 100%;
  869. overflow: hidden;
  870. white-space: nowrap;
  871. text-overflow: ellipsis;
  872. display: block;
  873. font-size: 24upx;
  874. margin-bottom: 20upx;
  875. }
  876. .pop-goods-price {
  877. font-size: 30upx;
  878. }
  879. .close-btn {
  880. width: 40upx;
  881. height: 40upx;
  882. border-radius: 50%;
  883. display: inline-block;
  884. position: absolute;
  885. right: 30upx;
  886. }
  887. .close-btn image {
  888. width: 100%;
  889. height: 100%;
  890. }
  891. .pop-m {
  892. font-size: 28upx;
  893. margin-bottom: 90upx;
  894. }
  895. .goods-specs,
  896. .goods-number {
  897. padding: 26upx;
  898. border-top: 1px solid #f3f3f3;
  899. }
  900. .goods-specs:first-child {
  901. border: none;
  902. }
  903. .pop-m-title {
  904. margin-right: 10upx;
  905. color: #666;
  906. }
  907. .pop-m-bd {
  908. overflow: hidden;
  909. margin-top: 10upx;
  910. }
  911. .pop-m-item {
  912. display: inline-block;
  913. float: left;
  914. padding: 6upx 16upx;
  915. background-color: #fff;
  916. color: #333;
  917. margin-right: 16upx;
  918. margin-bottom: 10upx;
  919. }
  920. .selected {
  921. border: 2upx solid #333;
  922. background-color: #333;
  923. color: #fff;
  924. }
  925. .not-selected {
  926. border: 2upx solid #ccc;
  927. }
  928. .none {
  929. border: 2upx dashed #ccc;
  930. color: #888;
  931. }
  932. .pop-m-bd-in {
  933. display: inline-block;
  934. }
  935. .badge {
  936. top: 2upx;
  937. left: 62upx;
  938. }
  939. .goods-assess .user-head-img {
  940. width: 80upx;
  941. height: 80upx;
  942. border-radius: 50%;
  943. }
  944. .goods-assess .cell-item-bd {
  945. padding-right: 0;
  946. }
  947. .goods-assess .cell-bd-text {
  948. margin: 0;
  949. }
  950. .goods-assess .cell-bd-text.color-9 {
  951. overflow: hidden;
  952. text-overflow: ellipsis;
  953. white-space: nowrap;
  954. max-width: 440upx;
  955. }
  956. .gai-body {}
  957. .gai-body-text {
  958. font-size: 26upx;
  959. color: #333;
  960. padding: 0 26upx;
  961. word-wrap: break-word;
  962. }
  963. .gai-body-img {
  964. overflow: hidden;
  965. padding: 20upx 26upx;
  966. }
  967. .gai-body-img image {
  968. width: 220upx;
  969. height: 220upx;
  970. float: left;
  971. margin-right: 19upx;
  972. margin-bottom: 18upx;
  973. }
  974. .gai-body-img image:nth-child(3n) {
  975. margin-right: 0;
  976. }
  977. .redstar {
  978. width: 24rpx;
  979. height: 24rpx;
  980. padding: 2rpx;
  981. }
  982. .mask-share-wechat {
  983. display: inline-block;
  984. background-color: #fff;
  985. padding: 0;
  986. }
  987. .mask-share-wechat:after {
  988. border: none;
  989. }
  990. .right-ball {
  991. position: fixed;
  992. right: 30upx;
  993. bottom: 300upx;
  994. z-index: 999;
  995. text-align: center;
  996. padding: 14upx 0;
  997. /* line-height: 80upx; */
  998. width: 80upx;
  999. height: 80upx;
  1000. font-size: 24upx;
  1001. color: #fff;
  1002. background-color: rgba(0, 0, 0, .5);
  1003. border-radius: 50%;
  1004. }
  1005. .share-pop {
  1006. height: 300upx;
  1007. width: 100%;
  1008. display: flex;
  1009. }
  1010. .share-item {
  1011. flex: 1;
  1012. text-align: center;
  1013. font-size: 26upx;
  1014. color: #333;
  1015. padding: 20upx 0;
  1016. }
  1017. /* .share-item image{
  1018. width: 120upx;
  1019. height: 120upx;
  1020. } */
  1021. .comment-none {
  1022. text-align: center;
  1023. padding: 200upx 0;
  1024. }
  1025. .comment-none-img {
  1026. width: 274upx;
  1027. height: 274upx;
  1028. }
  1029. .price-salesvolume {
  1030. width: 100%;
  1031. padding: 0 0 0 26upx;
  1032. overflow: hidden;
  1033. color: #A5A5A5;
  1034. background-color: rgb(252, 226, 80);
  1035. position: relative;
  1036. }
  1037. .commodity-price {
  1038. width: 224upx;
  1039. display: inline-block;
  1040. float: left;
  1041. }
  1042. .current-price {
  1043. font-size: 40upx;
  1044. color: #FF7159;
  1045. display: block;
  1046. line-height: 1.5;
  1047. }
  1048. .cost-price {
  1049. font-size: 26upx;
  1050. text-decoration: line-through;
  1051. /* margin-left: 8rpx; */
  1052. display: block;
  1053. }
  1054. .commodity-salesvolume {
  1055. width: 240upx;
  1056. display: inline-block;
  1057. font-size: 22upx;
  1058. float: left;
  1059. padding: 16upx 0;
  1060. }
  1061. .commodity-salesvolume>text {
  1062. display: block;
  1063. }
  1064. .commodity-time-img {
  1065. display: block;
  1066. width: 0;
  1067. height: 0;
  1068. border-width: 56upx 28upx 56upx 0;
  1069. border-style: solid;
  1070. border-color: transparent #FF7159 transparent transparent;
  1071. /*透明 黄 透明 透明 */
  1072. position: absolute;
  1073. top: 0px;
  1074. left: 462upx;
  1075. }
  1076. .commodity-time {
  1077. display: inline-block;
  1078. width: 260upx;
  1079. text-align: center;
  1080. font-size: 24upx;
  1081. background-color: #FF7159;
  1082. padding: 16upx 0 18upx;
  1083. color: #FF7159;
  1084. }
  1085. .commodity-time>text {
  1086. color: rgb(252, 226, 80);
  1087. }
  1088. .nav-back {
  1089. width: 100%;
  1090. height: 44px;
  1091. /* #ifndef MP-WEIXIN */
  1092. padding: 12px 12px 0;
  1093. /* #endif */
  1094. /* #ifdef MP-WEIXIN */
  1095. padding: 26px 12px 0;
  1096. /* #endif */
  1097. position: fixed;
  1098. top: 0;
  1099. background-color: rgba(255, 255, 255, 0);
  1100. z-index: 98;
  1101. }
  1102. .back-btn {
  1103. height: 32px;
  1104. width: 32px;
  1105. border-radius: 50%;
  1106. background-color: rgba(255, 255, 255, 0.8);
  1107. }
  1108. .back-btn .icon {
  1109. height: 20px;
  1110. width: 20px;
  1111. position: relative;
  1112. top: 50%;
  1113. left: 46%;
  1114. transform: translate(-50%, -50%);
  1115. }
  1116. .commodity-day>text {
  1117. display: inline-block;
  1118. background-color: rgb(255, 212, 176);
  1119. color: rgb(255, 115, 0);
  1120. padding: 0 6upx;
  1121. border-radius: 6upx;
  1122. }
  1123. .tl {
  1124. width: 70% !important;
  1125. }
  1126. .group-swiper {
  1127. /* padding: 20upx 26upx; */
  1128. }
  1129. .group-swiper-c {
  1130. height: 242upx;
  1131. }
  1132. .group-swiper-c .swiper-item .cell-item {
  1133. height: 50%;
  1134. }
  1135. .group-swiper-c .swiper-item .cell-item .user-head-img {
  1136. width: 80upx;
  1137. height: 80upx;
  1138. border-radius: 50%;
  1139. }
  1140. .group-swiper-c .swiper-item .cell-item .cell-hd-title {
  1141. position: absolute;
  1142. top: 50%;
  1143. left: 100upx;
  1144. transform: translateY(-50%);
  1145. max-width: 260upx;
  1146. width: 100%;
  1147. overflow: hidden;
  1148. text-overflow: ellipsis;
  1149. white-space: nowrap;
  1150. }
  1151. .group-swiper-c .swiper-item .cell-item .cell-item-bd {
  1152. min-width: 150upx;
  1153. max-width: 150upx
  1154. }
  1155. .group-swiper-c .swiper-item .cell-item .cell-item-ft .btn {
  1156. font-size: 26upx;
  1157. color: #fff;
  1158. background-color: #FF7159;
  1159. /* padding: 0; */
  1160. text-align: center;
  1161. }
  1162. </style>
index.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="nav-back">
  4. <view class="back-btn" @click="backBtn()">
  5. <image class="icon" src="/static/image/back-black.png" mode=""></image>
  6. </view>
  7. </view>
  8. <view class="content-top">
  9. <!-- 轮播图 -->
  10. <view class='swiper'>
  11. <swiper class="swiper-c" :indicator-dots="swiper.indicatorDots" :autoplay="swiper.autoplay" :interval="swiper.interval"
  12. :duration="swiper.duration">
  13. <swiper-item class="have-none" v-for="(item, index) in goodsInfo.album" :key="index" @click="clickImg(item)">
  14. <image class='' :src='item' mode="aspectFill"></image>
  15. </swiper-item>
  16. </swiper>
  17. </view>
  18. <!-- 轮播图end -->
  19. <view class='cell-group'>
  20. <view class='cell-item goods-top'>
  21. <view class='cell-item-hd'>
  22. <view class='cell-hd-title goods-price red-price'>¥{{ product.price }}</view>
  23. <view class='cell-hd-title goods-price cost-price' v-if="parseFloat(product.mktprice)>0">¥{{ product.mktprice }}</view>
  24. </view>
  25. <view class='cell-item-ft'>
  26. <text>{{ goodsInfo.buy_count }} 人已购买</text>
  27. </view>
  28. </view>
  29. <view class='cell-item goods-details'>
  30. <view class='cell-item-hd'>
  31. <view class='cell-hd-title'>
  32. <view class="color-3 fsz28 cell-hd-title-view">
  33. {{ product.name }}
  34. </view>
  35. <text v-if="goodsInfo.brief" class="color-9 fsz24 ">
  36. {{ goodsInfo.brief }}
  37. </text>
  38. </view>
  39. </view>
  40. <view class='cell-item-ft'>
  41. <image class='cell-ft-next icon' @click="goShare()" src='/static/image/share.png'></image>
  42. </view>
  43. </view>
  44. <!-- 促销 -->
  45. <view class='cell-item goods-title-item' v-if="promotion.length">
  46. <view class='cell-item-hd'>
  47. <view class='cell-hd-title'>促销</view>
  48. </view>
  49. <view class='cell-item-bd'>
  50. <view class="romotion-tip">
  51. <view class="romotion-tip-item" :class="item.type !== 2 ? 'bg-gray' : ''" v-for="(item, index) in promotion"
  52. :key="index">
  53. {{ item.name }}
  54. </view>
  55. </view>
  56. </view>
  57. </view>
  58. <!-- 促销end -->
  59. <!-- 规格 -->
  60. <view class='cell-item goods-title-item' v-if="isSpes">
  61. <view class='cell-item-hd'>
  62. <view class='cell-hd-title'>规格</view>
  63. </view>
  64. <view class='cell-item-bd' @click="toshow()">
  65. <text class='cell-bd-text'>{{ product.spes_desc }}</text>
  66. </view>
  67. </view>
  68. <!-- 规格end -->
  69. <view class='cell-item goods-title-item'>
  70. <view class='cell-item-hd'>
  71. <view class='cell-hd-title'>说明</view>
  72. </view>
  73. <view class='cell-item-bd'>
  74. <view class="cell-bd-view">
  75. <image class="goods-title-item-ic" src="/static/image/ic-dui.png" mode=""></image>
  76. <text class="cell-bd-text">24小时内发货</text>
  77. </view>
  78. <view class="cell-bd-view">
  79. <image class="goods-title-item-ic" src="/static/image/ic-dui.png" mode=""></image>
  80. <text class="cell-bd-text">7天拆封无条件退货</text>
  81. </view>
  82. </view>
  83. </view>
  84. </view>
  85. <view class="goods-content">
  86. <uni-segmented-control :current="current" :values="items" @clickItem="onClickItem" style-type="text" active-color="#333"></uni-segmented-control>
  87. <view class="goods-content-c">
  88. <view class="goods-detail" v-show="current === 0">
  89. <jshopContent :content="goodsInfo.intro" v-if="goodsInfo.intro"></jshopContent>
  90. </view>
  91. <view class="goods-parameter" v-show="current === 1">
  92. <view class='cell-group' v-if="goodsParams.length">
  93. <view class='cell-item' v-for="(item, index) in goodsParams" :key="index">
  94. <view class='cell-item-hd'>
  95. <view class='cell-hd-title'>{{ item.name }}</view>
  96. </view>
  97. <view class='cell-item-bd'>
  98. <text class='cell-bd-text'>{{ item.value }}</text>
  99. </view>
  100. </view>
  101. <!-- <view class='cell-item'>
  102. <view class='cell-item-hd'>
  103. <view class='cell-hd-title'>保修政策</view>
  104. </view>
  105. <view class='cell-item-bd'>
  106. <view class="cell-bd-view">
  107. <text class="cell-bd-text">二十日内包修理或换货</text>
  108. </view>
  109. <view class="cell-bd-view">
  110. <text class="cell-bd-text">一年内包修理</text>
  111. </view>
  112. </view>
  113. </view> -->
  114. </view>
  115. </view>
  116. <view class="goods-assess" v-show="current === 2">
  117. <view v-if="goodsComments.list.length">
  118. <view class="goods-assess-item" v-for="(item, index) in goodsComments.list" :key="index">
  119. <view class='cell-group'>
  120. <view class='cell-item goods-title-item'>
  121. <view class='cell-item-hd'>
  122. <image class='user-head-img' :src='item.user.avatar' mode="aspectFill"></image>
  123. </view>
  124. <view class='cell-item-bd'>
  125. <view class="cell-bd-view">
  126. <text class="cell-bd-text">{{ (item.user.nickname && item.user.nickname != '')?item.user.nickname:item.user.mobile }}</text>
  127. <view class="cell-bd-text-right">
  128. <uni-rate size="16" disabled="true" :value="item.score"></uni-rate>
  129. </view>
  130. </view>
  131. <view class="cell-bd-view">
  132. <text class="cell-bd-text color-9" style="margin-right: 16upx;">{{ item.ctime }}</text>
  133. <text class="cell-bd-text color-9">{{ item.addon }}</text>
  134. </view>
  135. </view>
  136. </view>
  137. </view>
  138. <view class="gai-body">
  139. <view class="gai-body-text">
  140. {{ item.content }}
  141. </view>
  142. <view class="gai-body-img" v-if="item.images_url.length">
  143. <image :src="img" mode="aspectFill" v-for="(img, key) in item.images_url" :key="key" @click="clickImg(img)"></image>
  144. </view>
  145. <view class="seller-content" v-if="item.seller_content">
  146. <view class="seller-content-top">
  147. <image class="seller-content-img" src="/static/image/seller-content.png"></image>掌柜回复
  148. </view>
  149. {{item.seller_content}}
  150. </view>
  151. </view>
  152. </view>
  153. <uni-load-more :status="goodsComments.loadStatus"></uni-load-more>
  154. </view>
  155. <view class="comment-none" v-else>
  156. <image class="comment-none-img" src="/static/image/order.png" mode=""></image>
  157. </view>
  158. </view>
  159. </view>
  160. </view>
  161. </view>
  162. <lvv-popup position="bottom" ref="share">
  163. <!-- #ifdef H5 -->
  164. <shareByH5 :goodsId="goodsInfo.id" :shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief"
  165. :shareHref="shareHref" @close="closeShare()"></shareByH5>
  166. <!-- #endif -->
  167. <!-- #ifdef MP-WEIXIN -->
  168. <shareByWx :goodsId="goodsInfo.id" :shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief"
  169. :shareHref="shareHref" @close="closeShare()"></shareByWx>
  170. <!-- #endif -->
  171. <!-- #ifdef MP-ALIPAY -->
  172. <shareByAli :goodsId="goodsInfo.id" :shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief"
  173. :shareHref="shareHref" @close="closeShare()"></shareByAli>
  174. <!-- #endif -->
  175. <!-- #ifdef APP-PLUS -->
  176. <shareByApp :goodsId="goodsInfo.id" :shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief"
  177. :shareHref="shareHref" @close="closeShare()"></shareByApp>
  178. <!-- #endif -->
  179. </lvv-popup>
  180. <!-- 弹出层 -->
  181. <lvv-popup position="bottom" ref="lvvpopref">
  182. <view style="width: 100%;max-height: 804upx;background: #FFFFFF;position: absolute;left:0;bottom: 0;">
  183. <view class="pop-c">
  184. <view class="pop-t">
  185. <view class='goods-img'>
  186. <image :src='product.image_path' mode='aspectFill'></image>
  187. </view>
  188. <view class='goods-information'>
  189. <view class='pop-goods-name'>{{ product.name }}</view>
  190. <view class='pop-goods-price red-price'>¥ {{ product.price }}</view>
  191. </view>
  192. <view class='close-btn' @click="toclose()">
  193. <image src='/static/image/close.png'></image>
  194. </view>
  195. </view>
  196. <scroll-view class="pop-m" scroll-y="true" style="max-height: 560upx;">
  197. <spec :spesData="product.default_spes_desc" ref="spec" @changeSpes="changeSpes"></spec>
  198. <view class="goods-number">
  199. <text class="pop-m-title">数量</text>
  200. <view class="pop-m-bd-in">
  201. <uni-number-box :min="minNums" :max="product.stock" :value="buyNum" @change="bindChange"></uni-number-box>
  202. </view>
  203. </view>
  204. </scroll-view>
  205. <view class="pop-b">
  206. <!-- <button class='btn btn-square btn-g btn-half' @click="addToCart">加入购物车</button>
  207. <button class='btn btn-square btn-b btn-half' @click="buyNow">立即购买</button> -->
  208. <button class='btn btn-square btn-b btn-all' hover-class="btn-hover2" @click="clickHandle()" :disabled='submitStatus'
  209. :loading='submitStatus' v-if="product.stock">确定</button>
  210. <button class='btn btn-square btn-g btn-all' v-else>已售罄</button>
  211. </view>
  212. </view>
  213. </view>
  214. </lvv-popup>
  215. <!-- 弹出层end -->
  216. <div id="qrCode" ref="qrCodeDiv"></div>
  217. <!-- 底部按钮 -->
  218. <view class="goods-bottom">
  219. <view class="goods-bottom-ic" @click="collection">
  220. <image class="icon" :src="isfav ? favLogo[1] : favLogo[0]" mode=""></image>
  221. <view v-if="!isfav">收藏</view>
  222. <view v-if="isfav">已收藏</view>
  223. </view>
  224. <view class="goods-bottom-ic" @click="redirectCart">
  225. <view class="badge color-f" v-if="cartNums">{{ cartNums }}</view>
  226. <image class="icon" src="/static/image/ic-me-car.png" mode=""></image>
  227. <view>购物车</view>
  228. </view>
  229. <button class='btn btn-square btn-g' @click="toshow(1)" hover-class="btn-hover2">加入购物车</button>
  230. <button class='btn btn-square btn-b' @click="toshow(2)" hover-class="btn-hover2">立即购买</button>
  231. </view>
  232. <!-- 底部按钮end -->
  233. <!-- 右边浮动球 -->
  234. <!-- <view class="right-ball">
  235. <view class="" @click="goIndex()">
  236. <image class="icon" src="/static/image/tab-ic-hom-selected.png" mode=""></image>
  237. </view>
  238. </view> -->
  239. <uni-fab :pattern="pattern" :content="content" :horizontal="horizontal" :vertical="vertical" :direction="direction"
  240. @trigger="trigger"></uni-fab>
  241. </view>
  242. </template>
  243. <script>
  244. import uniSegmentedControl from "@/components/uni-segmented-control/uni-segmented-control.vue";
  245. import lvvPopup from '@/components/lvv-popup/lvv-popup.vue';
  246. import uniNumberBox from "@/components/uni-number-box/uni-number-box.vue";
  247. import uniRate from "@/components/uni-rate/uni-rate.vue";
  248. import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue';
  249. import uniFab from '@/components/uni-fab/uni-fab.vue';
  250. import {
  251. get
  252. } from '@/config/db.js';
  253. import {
  254. apiBaseUrl
  255. } from '@/config/config.js'
  256. import spec from '@/components/spec/spec.vue'
  257. // #ifdef H5
  258. import shareByH5 from '@/components/share/shareByh5.vue'
  259. // #endif
  260. // #ifdef MP-WEIXIN
  261. import shareByWx from '@/components/share/shareByWx.vue'
  262. // #endif
  263. // #ifdef MP-ALIPAY
  264. import shareByAli from '@/components/share/shareByAli.vue'
  265. // #endif
  266. // #ifdef APP-PLUS
  267. import shareByApp from '@/components/share/shareByApp.vue'
  268. // #endif
  269. import jshopContent from '@/components/jshop/jshop-content.vue'//视频和文本解析组件
  270. export default {
  271. components: {
  272. uniSegmentedControl,
  273. lvvPopup,
  274. uniNumberBox,
  275. uniRate,
  276. uniLoadMore,
  277. uniFab,
  278. spec,
  279. jshopContent,
  280. // #ifdef H5
  281. shareByH5,
  282. // #endif
  283. // #ifdef MP-WEIXIN
  284. shareByWx,
  285. // #endif
  286. // #ifdef MP-ALIPAY
  287. shareByAli,
  288. // #endif
  289. // #ifdef APP-PLUS
  290. shareByApp,
  291. // #endif
  292. },
  293. data() {
  294. return {
  295. myShareCode: '', //分享Code
  296. swiper: {
  297. indicatorDots: true,
  298. autoplay: true,
  299. interval: 3000,
  300. duration: 800,
  301. }, // 轮播图属性设置
  302. items: ['图文详情', '商品参数', '买家评论'],
  303. current: 0, // init tab位
  304. goodsId: 0, // 商品id
  305. goodsInfo: {}, // 商品详情
  306. cartNums: 0, // 购物车数量
  307. product: {}, // 规格详情
  308. goodsParams: [], // 商品参数信息
  309. goodsComments: {
  310. loadStatus: 'more',
  311. page: 1,
  312. limit: 5,
  313. list: []
  314. }, // 商品评论信息
  315. buyNum: 1, // 选定的购买数量
  316. minBuyNum: 1, // 最小可购买数量
  317. type: 2, // 1加入购物车 2购买
  318. isfav: false, // 商品是否收藏
  319. favLogo: [
  320. '/static/image/ic-me-collect.png',
  321. '/static/image/ic-me-collect2.png'
  322. ],
  323. horizontal: 'right', //右下角弹出按钮
  324. vertical: 'bottom',
  325. direction: 'vertical',
  326. pattern: {
  327. color: '#7A7E83',
  328. backgroundColor: '#fff',
  329. selectedColor: '#007AFF',
  330. buttonColor: "#FF7159"
  331. },
  332. content: [{
  333. iconPath: '/static/image/tab-ic-hom-selected.png',
  334. selectedIconPath: '/static/image/tab-ic-hom-unselected.png',
  335. // text: '首页',
  336. active: false,
  337. url: '/pages/index/index'
  338. },
  339. {
  340. iconPath: '/static/image/tab-ic-me-selected.png',
  341. selectedIconPath: '/static/image/tab-ic-me-unselected.png',
  342. // text: '个人中心',
  343. active: false,
  344. url: '/pages/member/index/index'
  345. }
  346. ],
  347. submitStatus: false
  348. }
  349. },
  350. onLoad(options) {
  351. //获取商品ID
  352. if (options.id != '') {
  353. this.goodsId = options.id;
  354. }
  355. if (this.goodsId) {
  356. this.getGoodsDetail();
  357. this.getGoodsParams();
  358. this.getGoodsComments();
  359. } else {
  360. this.$common.errorToShow('获取失败', () => {
  361. uni.navigateBack({
  362. delta: 1
  363. });
  364. });
  365. }
  366. // 获取购物车数量
  367. this.getCartNums();
  368. this.getMyShareCode();
  369. },
  370. onShow(){
  371. this.submitStatus = false;
  372. },
  373. computed: {
  374. // 规格切换计算规格商品的 可购买数量
  375. minNums() {
  376. return this.product.stock > this.minBuyNum ? this.minBuyNum : this.product.stock;
  377. },
  378. // 判断商品是否是多规格商品 (为了兼容小程序 只能写在计算属性里面了)
  379. isSpes() {
  380. if (this.product.hasOwnProperty('default_spes_desc') && Object.keys(this.product.default_spes_desc).length) {
  381. return true;
  382. } else {
  383. return false;
  384. }
  385. },
  386. // 优惠信息重新组装
  387. promotion() {
  388. let arr = [];
  389. if (this.product.promotion_list) {
  390. for (let k in this.product.promotion_list) {
  391. arr.push(this.product.promotion_list[k]);
  392. }
  393. }
  394. return arr;
  395. },
  396. shareHref() {
  397. let pages = getCurrentPages()
  398. let page = pages[pages.length - 1]
  399. // #ifdef H5 || MP-WEIXIN || APP-PLUS || APP-PLUS-NVUE
  400. return apiBaseUrl + 'wap/' + page.route + '?id=' + this.goodsId;
  401. // #endif
  402. // #ifdef MP-ALIPAY
  403. return apiBaseUrl + 'wap/' + page.__proto__.route + '?id=' + this.goodsId;
  404. // #endif
  405. }
  406. },
  407. onReachBottom() {
  408. if (this.current === 2 && this.goodsComments.loadStatus === 'more') {
  409. this.getGoodsComments();
  410. }
  411. },
  412. methods: {
  413. // 返回上一页
  414. backBtn() {
  415. uni.navigateBack({
  416. delta: 1
  417. });
  418. },
  419. // 获取商品详情
  420. getGoodsDetail() {
  421. let data = {
  422. id: this.goodsId
  423. }
  424. // 如果用户已经登录 要传用户token
  425. let userToken = this.$db.get("userToken");
  426. if (userToken) {
  427. data['token'] = userToken;
  428. }
  429. this.$api.goodsDetail(data, res => {
  430. if (res.status == true) {
  431. let info = res.data;
  432. let products = res.data.product;
  433. //var htmlString = info.intro; //replace(/\\/g, "").replace(/<img/g, "<img style=\"display:none;\"")
  434. //info.intro = htmlParser(htmlString);
  435. this.goodsInfo = info;
  436. this.isfav = this.goodsInfo.isfav === 'true' ? true : false;
  437. this.product = this.spesClassHandle(products);
  438. // 判断如果登录用户添加商品浏览足迹
  439. if (userToken) {
  440. this.goodsBrowsing();
  441. }
  442. } else {
  443. this.$common.errorToShow(res.msg, () => {
  444. uni.navigateBack({
  445. delta: 1
  446. });
  447. })
  448. }
  449. })
  450. },
  451. // 获取购物车数量
  452. getCartNums() {
  453. let userToken = this.$db.get("userToken");
  454. if (userToken && userToken != '') {
  455. // 获取购物车数量
  456. this.$api.getCartNum({}, res => {
  457. if (res.status) {
  458. this.cartNums = res.data;
  459. }
  460. })
  461. }
  462. },
  463. // 显示modal弹出框
  464. toshow(type) {
  465. this.type = type;
  466. this.$refs.lvvpopref.show();
  467. },
  468. // 关闭modal弹出框
  469. toclose() {
  470. this.$refs.lvvpopref.close();
  471. },
  472. // 切换商品规格
  473. changeSpes(obj) {
  474. let index = obj.v;
  475. let key = obj.k;
  476. if (this.product.default_spes_desc[index][key].hasOwnProperty('product_id') && this.product.default_spes_desc[index]
  477. [key].product_id) {
  478. let data = {
  479. 'id': this.product.default_spes_desc[index][key].product_id
  480. };
  481. let userToken = this.$db.get("userToken");
  482. if (userToken) {
  483. data['token'] = userToken;
  484. }
  485. this.$api.getProductInfo(data, res => {
  486. if (res.status == true) {
  487. // 切换规格判断可购买数量
  488. this.buyNum = res.data.stock > this.minBuyNum ? this.minBuyNum : res.data.stock;
  489. this.product = this.spesClassHandle(res.data);
  490. }
  491. });
  492. uni.showLoading({
  493. title: '加载中'
  494. });
  495. setTimeout(function() {
  496. uni.hideLoading();
  497. }, 1000);
  498. }
  499. },
  500. // 多规格样式统一处理
  501. spesClassHandle(products) {
  502. // 判断是否是多规格 (是否有默认规格)
  503. if (products.hasOwnProperty('default_spes_desc')) {
  504. let spes = products.default_spes_desc;
  505. for (let key in spes) {
  506. for (let i in spes[key]) {
  507. if (spes[key][i].hasOwnProperty('is_default') && spes[key][i].is_default === true) {
  508. this.$set(spes[key][i], 'cla', 'pop-m-item selected');
  509. } else if (spes[key][i].hasOwnProperty('product_id') && spes[key][i].product_id) {
  510. this.$set(spes[key][i], 'cla', 'pop-m-item not-selected');
  511. } else {
  512. this.$set(spes[key][i], 'cla', 'pop-m-item none');
  513. }
  514. }
  515. }
  516. products.default_spes_desc = spes;
  517. }
  518. return products;
  519. },
  520. // 购买数量加减操作
  521. bindChange(val) {
  522. this.buyNum = val;
  523. },
  524. // 商品收藏/取消
  525. collection() {
  526. let data = {
  527. goods_id: this.goodsInfo.id
  528. }
  529. this.$api.goodsCollection(data, res => {
  530. if (res.status) {
  531. this.isfav = !this.isfav;
  532. this.$common.successToShow(res.msg);
  533. } else {
  534. this.$common.errorToShow(res.msg);
  535. }
  536. })
  537. },
  538. // tab点击切换
  539. onClickItem(index) {
  540. if (this.current !== index) {
  541. this.current = index;
  542. }
  543. },
  544. // 获取商品参数信息
  545. getGoodsParams() {
  546. this.$api.goodsParams({
  547. id: this.goodsId
  548. }, res => {
  549. if (res.status == true) {
  550. this.goodsParams = res.data;
  551. }
  552. })
  553. },
  554. // 获取商品评论信息
  555. getGoodsComments() {
  556. let data = {
  557. page: this.goodsComments.page,
  558. limit: this.goodsComments.limit,
  559. goods_id: this.goodsId
  560. }
  561. this.goodsComments.loadStatus = 'loading';
  562. this.$api.goodsComment(data, res => {
  563. if (res.status == true) {
  564. let _list = res.data.list;
  565. let count = res.data.count;
  566. this.items = ['图文详情', '商品参数', '买家评论(' + count + ')']
  567. // 如果评论没有图片 在这块作处理否则控制台报错
  568. _list.forEach(item => {
  569. item.ctime = this.$common.timeToDate(item.ctime, true);
  570. if (!item.hasOwnProperty('images_url')) {
  571. this.$set(item, 'images_url', [])
  572. }
  573. });
  574. this.goodsComments.list = [...this.goodsComments.list, ..._list];
  575. // 根据count数量判断是否还有数据
  576. if (res.data.count > this.goodsComments.list.length) {
  577. this.goodsComments.loadStatus = 'more';
  578. this.goodsComments.page++;
  579. } else {
  580. this.goodsComments.loadStatus = 'noMore';
  581. }
  582. } else {
  583. this.$common.errorToShow(res.msg);
  584. }
  585. })
  586. },
  587. // 添加商品浏览足迹
  588. goodsBrowsing() {
  589. let data = {
  590. goods_id: this.goodsInfo.id
  591. }
  592. this.$api.addGoodsBrowsing(data, res => {});
  593. },
  594. // 加入购物车
  595. addToCart() {
  596. if (this.buyNum > 0) {
  597. let data = {
  598. product_id: this.product.id,
  599. nums: this.buyNum
  600. }
  601. this.$api.addCart(data, res => {
  602. if (res.status) {
  603. this.toclose(); // 关闭弹出层
  604. this.getCartNums(); // 获取购物车数量
  605. this.$common.successToShow(res.msg);
  606. } else {
  607. this.$common.errorToShow(res.msg);
  608. }
  609. this.submitStatus = false;
  610. })
  611. } else {
  612. this.submitStatus = false;
  613. }
  614. },
  615. // 立即购买
  616. buyNow() {
  617. if (this.buyNum > 0) {
  618. let data = {
  619. product_id: this.product.id,
  620. nums: this.buyNum,
  621. type: 2 // 区分加入购物车和购买
  622. }
  623. this.$api.addCart(data, res => {
  624. if (res.status) {
  625. this.toclose();
  626. let cartIds = res.data;
  627. this.$common.navigateTo('/pages/goods/place-order/index?cart_ids=' + JSON.stringify(cartIds));
  628. }
  629. this.submitStatus = false;
  630. })
  631. } else {
  632. this.submitStatus = false;
  633. }
  634. },
  635. // 购物车页面跳转
  636. redirectCart() {
  637. uni.switchTab({
  638. url: '/pages/cart/index/index'
  639. });
  640. },
  641. // 点击弹出框确定按钮事件处理
  642. clickHandle() {
  643. this.submitStatus = true;
  644. this.type === 1 ? this.addToCart() : this.buyNow();
  645. },
  646. // 右下角按钮
  647. // goIndex(){
  648. // uni.switchTab({
  649. // url:'../../index/index'
  650. // });
  651. // },
  652. trigger(e) {
  653. // console.log(e);
  654. this.content[e.index].active = !e.item.active;
  655. // uni.showModal({
  656. // title: '提示',
  657. // content: `您${this.content[e.index].active?'选中了':'取消了'}${e.item.text}`,
  658. // success: function(res) {
  659. // if (res.confirm) {
  660. // console.log('用户点击确定');
  661. // } else if (res.cancel) {
  662. // console.log('用户点击取消');
  663. // }
  664. // }
  665. // });
  666. uni.switchTab({
  667. url: e.item.url
  668. })
  669. },
  670. // 跳转到h5分享页面
  671. goShare() {
  672. this.$refs.share.show();
  673. },
  674. closeShare() {
  675. this.$refs.share.close();
  676. },
  677. // 图片点击放大
  678. clickImg(imgs) {
  679. // 预览图片
  680. uni.previewImage({
  681. urls: imgs.split()
  682. });
  683. },
  684. getMyShareCode() {
  685. let userToken = this.$db.get("userToken");
  686. if (userToken && userToken != '') {
  687. // 获取我的分享码
  688. this.$api.shareCode({}, res => {
  689. if (res.status) {
  690. this.myShareCode = res.data ? res.data : '';
  691. }
  692. });
  693. }
  694. }
  695. },
  696. //分享
  697. onShareAppMessage() {
  698. let myInviteCode = this.myShareCode ? this.myShareCode : '';
  699. let ins = this.$common.shareParameterDecode('type=2&id=' + this.goodsInfo.id + '&invite=' + myInviteCode);
  700. let path = '/pages/share/jump?scene=' + ins;
  701. return {
  702. title: this.goodsInfo.name,
  703. // #ifdef MP-ALIPAY
  704. desc: this.goodsInfo.brief,
  705. // #endif
  706. imageUrl: this.goodsInfo.album[0],
  707. path: path
  708. }
  709. }
  710. }
  711. </script>
  712. <style>
  713. .swiper {
  714. height: 750upx;
  715. }
  716. .goods-top {
  717. border-bottom: 0;
  718. }
  719. .goods-top .goods-price {
  720. font-size: 38upx;
  721. }
  722. .cost-price {
  723. font-size: 28upx !important;
  724. bottom: -10upx;
  725. color: #999;
  726. text-decoration: line-through;
  727. }
  728. .goods-top .cell-item-ft {
  729. font-size: 20upx;
  730. color: #666;
  731. }
  732. .goods-details {
  733. padding-top: 0;
  734. }
  735. .goods-details .cell-hd-title {
  736. width: 620upx;
  737. }
  738. .goods-details .cell-hd-title .cell-hd-title-view {
  739. width: 100%;
  740. display: -webkit-box;
  741. -webkit-box-orient: vertical;
  742. -webkit-line-clamp: 2;
  743. overflow: hidden;
  744. }
  745. .goods-details .cell-hd-title .cell-hd-title-view:last-child {
  746. margin-top: 10upx;
  747. }
  748. .goods-details .cell-item-ft {
  749. top: 24upx;
  750. }
  751. .goods-title-item .cell-item-hd {
  752. min-width: 60upx;
  753. color: #666;
  754. font-size: 24upx;
  755. }
  756. .goods-title-item .cell-item-bd {
  757. color: #333;
  758. font-size: 24upx;
  759. }
  760. .goods-title-item .cell-bd-text {
  761. bottom: 0;
  762. }
  763. .cell-bd-view {
  764. position: relative;
  765. overflow: hidden;
  766. }
  767. .cell-bd-view:first-child {
  768. margin-bottom: 8upx;
  769. }
  770. .goods-title-item-ic {
  771. width: 22upx;
  772. height: 22upx;
  773. position: absolute;
  774. top: 50%;
  775. transform: translateY(-50%);
  776. /* #ifdef MP-ALIPAY */
  777. background-size: 100% 100%;
  778. /* #endif */
  779. }
  780. .cell-bd-view .cell-bd-text {
  781. margin-left: 30upx;
  782. }
  783. .goods-content {
  784. margin-top: 26upx;
  785. background-color: #fff;
  786. padding: 26upx 0;
  787. }
  788. .goods-content-c {
  789. margin-top: 20upx;
  790. }
  791. .goods-parameter {
  792. padding: 10upx 26upx;
  793. }
  794. .goods-bottom,
  795. .pop-b {
  796. background-color: #fff;
  797. position: fixed;
  798. bottom: 0;
  799. height: 90upx;
  800. width: 100%;
  801. overflow: hidden;
  802. box-shadow: 0 0 20upx #ccc;
  803. }
  804. .goods-bottom button {
  805. height: 100%;
  806. width: 35%;
  807. }
  808. .goods-bottom-ic {
  809. display: inline-block;
  810. position: relative;
  811. text-align: center;
  812. height: 100%;
  813. width: 15%;
  814. float: left;
  815. font-size: 22upx;
  816. color: #666;
  817. }
  818. .goods-bottom-ic .icon {
  819. position: relative;
  820. top: 6upx;
  821. /* left: -6upx; */
  822. /* #ifdef MP-ALIPAY */
  823. background-size: 100% 100%;
  824. /* #endif */
  825. }
  826. .goods-bottom .btn-g {
  827. color: #333;
  828. background-color: #D9D9D9;
  829. }
  830. .goods-parameter .cell-item {
  831. border-bottom: none;
  832. margin-left: 0;
  833. }
  834. .goods-parameter .cell-item-hd {
  835. color: #333;
  836. font-size: 24upx;
  837. }
  838. .goods-parameter .cell-item-bd {
  839. color: #999;
  840. }
  841. .goods-parameter .cell-item-bd .cell-bd-text {
  842. bottom: 0;
  843. }
  844. .goods-parameter .cell-bd-text {
  845. margin-left: 0;
  846. }
  847. .pop-t {
  848. position: relative;
  849. padding: 30upx 26upx;
  850. border-bottom: 2upx solid #f3f3f3;
  851. /* box-shadow: 0 0 20upx #ccc; */
  852. }
  853. .goods-img {
  854. width: 160upx;
  855. height: 160upx;
  856. position: absolute;
  857. top: -20upx;
  858. background-color: #fff;
  859. border-radius: 6upx;
  860. border: 2upx solid #fff;
  861. }
  862. .goods-img image {
  863. height: 100%;
  864. width: 100%;
  865. }
  866. .goods-information {
  867. width: 420upx;
  868. display: inline-block;
  869. margin-left: 180upx;
  870. }
  871. .pop-goods-name {
  872. width: 100%;
  873. overflow: hidden;
  874. white-space: nowrap;
  875. text-overflow: ellipsis;
  876. display: block;
  877. font-size: 24upx;
  878. margin-bottom: 20upx;
  879. }
  880. .pop-goods-price {
  881. font-size: 30upx;
  882. }
  883. .close-btn {
  884. width: 40upx;
  885. height: 40upx;
  886. border-radius: 50%;
  887. display: inline-block;
  888. position: absolute;
  889. right: 30upx;
  890. }
  891. .close-btn image {
  892. width: 100%;
  893. height: 100%;
  894. }
  895. .pop-m {
  896. font-size: 28upx;
  897. margin-bottom: 90upx;
  898. }
  899. .goods-specs,
  900. .goods-number {
  901. padding: 26upx;
  902. border-top: 1px solid #f3f3f3;
  903. }
  904. .goods-specs:first-child {
  905. border: none;
  906. }
  907. .pop-m-title {
  908. margin-right: 10upx;
  909. color: #666;
  910. }
  911. .pop-m-bd {
  912. overflow: hidden;
  913. margin-top: 10upx;
  914. }
  915. .pop-m-item {
  916. display: inline-block;
  917. float: left;
  918. padding: 6upx 16upx;
  919. background-color: #fff;
  920. color: #333;
  921. margin-right: 16upx;
  922. margin-bottom: 10upx;
  923. }
  924. .selected {
  925. border: 2upx solid #333;
  926. background-color: #333;
  927. color: #fff;
  928. }
  929. .not-selected {
  930. border: 2upx solid #ccc;
  931. }
  932. .none {
  933. border: 2upx dashed #ccc;
  934. color: #888;
  935. }
  936. .pop-m-bd-in {
  937. display: inline-block;
  938. }
  939. .badge {
  940. top: 2upx;
  941. left: 62upx;
  942. }
  943. .goods-assess .user-head-img {
  944. width: 80upx;
  945. height: 80upx;
  946. border-radius: 50%;
  947. }
  948. .goods-assess .cell-item-bd {
  949. padding-right: 0;
  950. }
  951. .goods-assess .cell-bd-text {
  952. margin: 0;
  953. }
  954. .goods-assess .cell-bd-text.color-9 {
  955. overflow: hidden;
  956. text-overflow: ellipsis;
  957. white-space: nowrap;
  958. max-width: 440upx;
  959. }
  960. .gai-body {}
  961. .gai-body-text {
  962. font-size: 26upx;
  963. color: #333;
  964. padding: 0 26upx;
  965. word-wrap: break-word;
  966. }
  967. .gai-body-img {
  968. overflow: hidden;
  969. padding: 20upx 26upx;
  970. }
  971. .gai-body-img image {
  972. width: 220upx;
  973. height: 220upx;
  974. float: left;
  975. margin-right: 19upx;
  976. margin-bottom: 18upx;
  977. }
  978. .gai-body-img image:nth-child(3n) {
  979. margin-right: 0;
  980. }
  981. .redstar {
  982. width: 24rpx;
  983. height: 24rpx;
  984. padding: 2rpx;
  985. }
  986. .mask-share-wechat {
  987. display: inline-block;
  988. background-color: #fff;
  989. padding: 0;
  990. }
  991. .mask-share-wechat:after {
  992. border: none;
  993. }
  994. .right-ball {
  995. position: fixed;
  996. right: 30upx;
  997. bottom: 300upx;
  998. z-index: 999;
  999. text-align: center;
  1000. padding: 14upx 0;
  1001. /* line-height: 80upx; */
  1002. width: 80upx;
  1003. height: 80upx;
  1004. font-size: 24upx;
  1005. color: #fff;
  1006. background-color: rgba(0, 0, 0, .5);
  1007. border-radius: 50%;
  1008. }
  1009. .comment-none {
  1010. text-align: center;
  1011. padding: 200upx 0;
  1012. }
  1013. .comment-none-img {
  1014. width: 274upx;
  1015. height: 274upx;
  1016. }
  1017. .price-salesvolume {
  1018. width: 100%;
  1019. padding: 0 0 0 26upx;
  1020. overflow: hidden;
  1021. color: #A5A5A5;
  1022. background-color: rgb(252, 226, 80);
  1023. position: relative;
  1024. }
  1025. .commodity-price {
  1026. width: 224upx;
  1027. display: inline-block;
  1028. float: left;
  1029. }
  1030. .current-price {
  1031. font-size: 40upx;
  1032. color: #FF7159;
  1033. display: block;
  1034. line-height: 1.5;
  1035. }
  1036. .cost-price {
  1037. font-size: 26upx;
  1038. text-decoration: line-through;
  1039. /* margin-left: 8rpx; */
  1040. display: block;
  1041. }
  1042. .commodity-salesvolume {
  1043. width: 240upx;
  1044. display: inline-block;
  1045. font-size: 22upx;
  1046. float: left;
  1047. padding: 16upx 0;
  1048. }
  1049. .commodity-salesvolume>text {
  1050. display: block;
  1051. }
  1052. .commodity-time-img {
  1053. display: block;
  1054. width: 0;
  1055. height: 0;
  1056. border-width: 48upx 28upx 50upx 0;
  1057. border-style: solid;
  1058. border-color: transparent #FF7159 transparent transparent;
  1059. /*透明 黄 透明 透明 */
  1060. position: absolute;
  1061. top: 0px;
  1062. left: 462upx;
  1063. }
  1064. .commodity-time {
  1065. display: inline-block;
  1066. width: 260upx;
  1067. text-align: center;
  1068. font-size: 24upx;
  1069. background-color: #FF7159;
  1070. padding: 16upx 0 18upx;
  1071. color: rgb(250, 233, 0);
  1072. }
  1073. .commodity-time>text {
  1074. display: block;
  1075. }
  1076. .commodity-day {
  1077. font-size: 22upx;
  1078. }
  1079. .commodity-day>text {
  1080. display: inline-block;
  1081. background-color: rgb(255, 212, 176);
  1082. color: rgb(255, 115, 0);
  1083. padding: 0 6upx;
  1084. border-radius: 6upx;
  1085. }
  1086. .nav-back {
  1087. width: 100%;
  1088. height: 44px;
  1089. /* #ifndef MP-WEIXIN */
  1090. padding: 12px 12px 0;
  1091. /* #endif */
  1092. /* #ifdef MP-WEIXIN */
  1093. padding: 26px 12px 0;
  1094. /* #endif */
  1095. position: fixed;
  1096. top: 0;
  1097. background-color: rgba(255, 255, 255, 0);
  1098. z-index: 98;
  1099. }
  1100. .back-btn {
  1101. height: 32px;
  1102. width: 32px;
  1103. border-radius: 50%;
  1104. background-color: rgba(255, 255, 255, 0.8);
  1105. }
  1106. .back-btn .icon {
  1107. height: 20px;
  1108. width: 20px;
  1109. position: relative;
  1110. top: 50%;
  1111. left: 46%;
  1112. transform: translate(-50%, -50%);
  1113. }
  1114. .seller-content {
  1115. background-color: #f8f8f8;
  1116. margin: 0 13px 15px;
  1117. padding: 10px;
  1118. color: #6e6e6e;
  1119. border-radius: 4px;
  1120. }
  1121. .seller-content-top {
  1122. font-weight: bold;
  1123. margin-bottom: 6px;
  1124. }
  1125. .seller-content-img {
  1126. width: 20px;
  1127. height: 20px;
  1128. vertical-align: middle;
  1129. margin-right: 4px;
  1130. }
  1131. </style>
pintuan.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="nav-back">
  4. <view class="back-btn" @click="backBtn()">
  5. <image class="icon" src="/static/image/back-black.png" mode=""></image>
  6. </view>
  7. </view>
  8. <view class="content-top">
  9. <!-- 轮播图 -->
  10. <view class='swiper'>
  11. <swiper class="swiper-c" :indicator-dots="swiper.indicatorDots" :autoplay="swiper.autoplay" :interval="swiper.interval"
  12. :duration="swiper.duration">
  13. <swiper-item class="have-none" v-for="(item, index) in goodsInfo.album" :key="index" @click="clickImg(item)">
  14. <!-- {{goodsInfo.album}} -->
  15. <image class='' :src='item' mode="aspectFill"></image>
  16. </swiper-item>
  17. </swiper>
  18. </view>
  19. <!-- 轮播图end -->
  20. <view class='cell-group'>
  21. <!-- 倒计时 -->
  22. <view class='price-salesvolume' v-if="lasttime.hour!==false">
  23. <view class='commodity-price'>
  24. <text class='current-price'>¥{{pintuanPrice}}</text>
  25. <text class='cost-price' v-if="parseFloat(product.mktprice)>0">¥{{product.mktprice}}</text>
  26. </view>
  27. <view class='commodity-salesvolume'>
  28. <text>已售{{goodsInfo.buy_count}}件/剩余{{product.stock}}件</text>
  29. <text>累计销售{{goodsInfo.buy_count}}件</text>
  30. </view>
  31. <view class='commodity-time' v-if="goodsInfo.pintuan_rule.pintuan_start_status == 1">
  32. <text>距结束仅剩</text>
  33. <view class='commodity-day'>
  34. <uni-countdown textColor="#fce250" :day="lasttime.day" :hour="lasttime.hour" :minute="lasttime.minute" :second="lasttime.second"></uni-countdown>
  35. </view>
  36. </view>
  37. <view class='commodity-time' v-if="goodsInfo.pintuan_rule.pintuan_start_status == 2">
  38. <text>即将开团</text>
  39. <view class='commodity-day'>
  40. <uni-countdown textColor="#fce250" :day="goodsInfo.pintuan_rule.lasttime.day" :hour="goodsInfo.pintuan_rule.lasttime.hour"
  41. :minute="goodsInfo.pintuan_rule.lasttime.minute" :second="goodsInfo.pintuan_rule.lasttime.second"></uni-countdown>
  42. </view>
  43. </view>
  44. <view class='commodity-time-img'></view>
  45. <!-- <view class='commodity-time'>
  46. 已结束
  47. </view> -->
  48. </view>
  49. <!-- 倒计时end -->
  50. <!-- 分享 -->
  51. <view class='cell-item goods-details'>
  52. <view class='cell-item-hd'>
  53. <view class='cell-hd-title'>
  54. <view class="color-3 fsz28 cell-hd-title-view">
  55. {{ product.name }}
  56. </view>
  57. <view v-if="goodsInfo.brief" class="color-9 fsz24 cell-hd-title-view">
  58. {{ goodsInfo.brief }}
  59. </view>
  60. </view>
  61. </view>
  62. <view class='cell-item-ft'>
  63. <image class='cell-ft-next icon' @click="goShare()" src='/static/image/share.png'></image>
  64. </view>
  65. </view>
  66. <!-- 分享end -->
  67. <!-- 促销 -->
  68. <view class='cell-item goods-title-item' v-if="promotion.length">
  69. <view class='cell-item-hd'>
  70. <view class='cell-hd-title'>促销</view>
  71. </view>
  72. <view class='cell-item-bd'>
  73. <view class="romotion-tip">
  74. <view class="romotion-tip-item" :class="item.type !== 2 ? 'bg-gray' : ''" v-for="(item, index) in promotion"
  75. :key="index">
  76. {{ item.name }}
  77. </view>
  78. </view>
  79. </view>
  80. </view>
  81. <!-- 促销end -->
  82. <!-- 规格 -->
  83. <view class='cell-item goods-title-item' v-if="isSpes">
  84. <view class='cell-item-hd'>
  85. <view class='cell-hd-title'>规格</view>
  86. </view>
  87. <view class='cell-item-bd' @click="toshow()">
  88. <text class='cell-bd-text'>{{ product.spes_desc }}</text>
  89. </view>
  90. </view>
  91. <!-- 规格end -->
  92. <!-- 说明 -->
  93. <view class='cell-item goods-title-item'>
  94. <view class='cell-item-hd'>
  95. <view class='cell-hd-title'>说明</view>
  96. </view>
  97. <view class='cell-item-bd'>
  98. <view class="cell-bd-view">
  99. <image class="goods-title-item-ic" src="/static/image/ic-dui.png" mode=""></image>
  100. <text class="cell-bd-text">24小时内发货</text>
  101. </view>
  102. <view class="cell-bd-view">
  103. <image class="goods-title-item-ic" src="/static/image/ic-dui.png" mode=""></image>
  104. <text class="cell-bd-text">7天拆封无条件退货</text>
  105. </view>
  106. </view>
  107. </view>
  108. <!-- 说明end -->
  109. </view>
  110. <!-- 团购拼单 -->
  111. <view class="cell-group margin-cell-group" v-if="pintuanRecord.length>0">
  112. <view class='cell-item right-img'>
  113. <view class='cell-item-hd'>
  114. <view class='cell-hd-title'>{{teamCount}}人在拼单,可直接参与</view>
  115. </view>
  116. <!-- <view class='cell-item-ft' >
  117. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  118. <text class='cell-ft-text'>查看更多</text>
  119. </view> -->
  120. </view>
  121. <view class="group-swiper">
  122. <swiper class="group-swiper-c" :class="groupHeight" :indicator-dots="indicatorDots" :autoplay="autoplay" vertical="true"
  123. circular="true" :interval="interval" :duration="duration">
  124. <swiper-item v-for="(item, index) in pintuanRecord" :key="index">
  125. <view class="swiper-item">
  126. <view class='cell-item'>
  127. <view class='cell-item-hd'>
  128. <image class="user-head-img cell-hd-icon have-none" :src='item[0].user_avatar' mode=""></image>
  129. <view class="cell-hd-title">
  130. {{item[0].nickname}}
  131. </view>
  132. </view>
  133. <view class='cell-item-bd'>
  134. <view class="cell-bd-view">
  135. <text class="cell-bd-text">还差<text class="red-price">{{item[0].team_nums}}人</text>拼成</text>
  136. </view>
  137. <view class="cell-bd-view">
  138. <view class='commodity-day'>
  139. <text class="fsz24 color-6">剩余:</text>
  140. <uni-countdown color="#666" :day="item[0].remainder_time.day" :hour="item[0].remainder_time.hour" :minute="item[0].remainder_time.minute"
  141. :second="item[0].remainder_time.second"></uni-countdown>
  142. </view>
  143. </view>
  144. </view>
  145. <view class="cell-item-ft">
  146. <button class="btn" @click="toshow(2,item[0].team_id)">去拼单</button>
  147. </view>
  148. <!-- <view class="cell-item-ft" v-else>
  149. <button class="btn btn-b">拼团中</button>
  150. </view> -->
  151. </view>
  152. <view class='cell-item' v-if="item[1]">
  153. <view class='cell-item-hd'>
  154. <image class="user-head-img cell-hd-icon have-none" :src='item[1].user_avatar' mode=""></image>
  155. <view class="cell-hd-title">
  156. {{item[1].nickname}}
  157. </view>
  158. </view>
  159. <view class='cell-item-bd'>
  160. <view class="cell-bd-view">
  161. <text class="cell-bd-text">还差<text class="red-price">{{item[1].team_nums}}人</text>拼成</text>
  162. </view>
  163. <view class="cell-bd-view">
  164. <view class='commodity-day'>
  165. <text class="fsz24 color-6">剩余:</text>
  166. <uni-countdown color="#666" :day="item[1].remainder_time.day" :hour="item[1].remainder_time.hour" :minute="item[1].remainder_time.minute"
  167. :second="item[1].remainder_time.second"></uni-countdown>
  168. </view>
  169. </view>
  170. </view>
  171. <view class="cell-item-ft">
  172. <button class="btn" @click="toshow(2,item[1].id)">去拼单</button>
  173. </view>
  174. </view>
  175. </view>
  176. </swiper-item>
  177. </swiper>
  178. </view>
  179. </view>
  180. <view class="cell-group margin-cell-group" v-else="">
  181. <view class='cell-item right-img'>
  182. <view class='cell-item-hd'>
  183. <view class='cell-hd-title'>暂无开团信息</view>
  184. </view>
  185. </view>
  186. </view>
  187. <view class="goods-content">
  188. <uni-segmented-control :current="current" :values="items" @clickItem="onClickItem" style-type="text" active-color="#333"></uni-segmented-control>
  189. <view class="goods-content-c">
  190. <view class="goods-detail" v-if="current === 0">
  191. <jshopContent :content="goodsInfo.intro" v-if="goodsInfo.intro"></jshopContent>
  192. </view>
  193. <view class="goods-parameter" v-else-if="current === 1">
  194. <view class='cell-group' v-if="goodsParams.length">
  195. <view class='cell-item' v-for="(item, index) in goodsParams" :key="index">
  196. <view class='cell-item-hd'>
  197. <view class='cell-hd-title'>{{ item.name }}</view>
  198. </view>
  199. <view class='cell-item-bd'>
  200. <text class='cell-bd-text'>{{ item.value }}</text>
  201. </view>
  202. </view>
  203. </view>
  204. </view>
  205. <view class="goods-assess" v-else-if="current === 2">
  206. <view v-if="goodsComments.list.length">
  207. <view class="goods-assess-item" v-for="(item, index) in goodsComments.list" :key="index">
  208. <view class='cell-group'>
  209. <view class='cell-item goods-title-item'>
  210. <view class='cell-item-hd'>
  211. <image class='user-head-img' :src='item.user.avatar' mode="aspectFill"></image>
  212. </view>
  213. <view class='cell-item-bd'>
  214. <view class="cell-bd-view">
  215. <text class="cell-bd-text">{{ item.user.nickname }}</text>
  216. <view class="cell-bd-text-right">
  217. <uni-rate size="16" disabled="true" :value="item.score"></uni-rate>
  218. </view>
  219. </view>
  220. <view class="cell-bd-view">
  221. <text class="cell-bd-text color-9" style="margin-right: 16upx;">{{ item.ctime }}</text>
  222. <text class="cell-bd-text color-9">{{ item.addon }}</text>
  223. </view>
  224. </view>
  225. </view>
  226. </view>
  227. <view class="gai-body">
  228. <view class="gai-body-text">
  229. {{ item.content }}
  230. </view>
  231. <view class="gai-body-img" v-if="item.images_url.length">
  232. <image :src="img" mode="aspectFill" v-for="(img, key) in item.images_url" :key="key" @click="clickImg(img)"></image>
  233. </view>
  234. </view>
  235. </view>
  236. <uni-load-more :status="goodsComments.loadStatus"></uni-load-more>
  237. </view>
  238. <view class="comment-none" v-else>
  239. <image class="comment-none-img" src="/static/image/order.png" mode=""></image>
  240. </view>
  241. </view>
  242. </view>
  243. </view>
  244. </view>
  245. <lvv-popup position="bottom" ref="pintuanpop">
  246. <view class="ig-top" v-if="teamInfo.list.length>0">
  247. <view class="ig-top-t">
  248. <view class="">
  249. 剩余时间:<uni-countdown :day="teamInfo.team_time.day" :hour="teamInfo.team_time.hour" :minute="teamInfo.team_time.minute"
  250. :second="teamInfo.team_time.second"></uni-countdown>
  251. </view>
  252. </view>
  253. <view class="ig-top-m">
  254. <view class="user-head-img-c" v-for="(item, index) in teamInfo.list" :key="index">
  255. <view class="user-head-img-tip" v-if="item.id == item.team_id">拼主</view>
  256. <image class="user-head-img cell-hd-icon have-none" :src='item.user_avatar' mode=""></image>
  257. </view>
  258. <view class="user-head-img-c uhihn" v-if="teamInfo.team_nums" v-for="n in teamInfo.team_nums" :key="n"><text>?</text></view>
  259. </view>
  260. <view class="ig-top-b">
  261. <view class="igtb-top">
  262. 还差<text class="red-price">{{ teamInfo.team_nums }}</text>人,赶快拼单吧
  263. </view>
  264. <view class="igtb-mid">
  265. <button class="btn" @click="toshow(2,teamInfo.id)">参与拼团</button>
  266. </view>
  267. </view>
  268. </view>
  269. </lvv-popup>
  270. <lvv-popup position="bottom" ref="share">
  271. <!-- #ifdef H5 -->
  272. <shareByH5 :shareType='3' :goodsId="goodsInfo.id" :shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name"
  273. :shareContent="goodsInfo.brief" :shareHref="shareHref" @close="closeShare()"></shareByH5>
  274. <!-- #endif -->
  275. <!-- #ifdef MP-WEIXIN -->
  276. <shareByWx :shareType='3' :goodsId="goodsInfo.id" :shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name"
  277. :shareContent="goodsInfo.brief" :shareHref="shareHref" @close="closeShare()"></shareByWx>
  278. <!-- #endif -->
  279. <!-- #ifdef MP-ALIPAY -->
  280. <shareByAli :shareType='3' :goodsId="goodsInfo.id" :shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name"
  281. :shareContent="goodsInfo.brief" :shareHref="shareHref" @close="closeShare()"></shareByAli>
  282. <!-- #endif -->
  283. <!-- #ifdef APP-PLUS -->
  284. <shareByApp :shareType='3' :goodsId="goodsInfo.id" :shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name"
  285. :shareContent="goodsInfo.brief" :shareHref="shareHref" @close="closeShare()"></shareByApp>
  286. <!-- #endif -->
  287. </lvv-popup>
  288. <!-- 弹出层 -->
  289. <lvv-popup position="bottom" ref="lvvpopref">
  290. <view style="width: 100%;max-height: 804upx;background: #FFFFFF;position: absolute;left:0;bottom: 0;">
  291. <view class="pop-c">
  292. <view class="pop-t">
  293. <view class='goods-img'>
  294. <image :src='product.image_path' mode='aspectFill'></image>
  295. </view>
  296. <view class='goods-information'>
  297. <view class='pop-goods-name'>{{ product.name }}</view>
  298. <view class='pop-goods-price red-price'>¥ {{ price }}</view>
  299. </view>
  300. <view class='close-btn' @click="toclose()">
  301. <image src='/static/image/close.png'></image>
  302. </view>
  303. </view>
  304. <scroll-view class="pop-m" scroll-y="true" style="max-height: 560upx;">
  305. <spec :spesData="product.default_spes_desc" ref="spec" @changeSpes="changeSpes"></spec>
  306. <view class="goods-number">
  307. <text class="pop-m-title">数量</text>
  308. <view class="pop-m-bd-in">
  309. <uni-number-box :min="minNums" :max="product.stock" :value="buyNum" @change="bindChange"></uni-number-box>
  310. </view>
  311. </view>
  312. </scroll-view>
  313. <view class="pop-b">
  314. <!-- <button class='btn btn-square btn-g btn-half' @click="addToCart">加入购物车</button>
  315. <button class='btn btn-square btn-b btn-half' @click="buyNow">立即购买</button> -->
  316. <button class='btn btn-square btn-b btn-all' hover-class="btn-hover2" @click="buyNow()" v-if="product.stock">确定</button>
  317. <button class='btn btn-square btn-g btn-all' v-else>已售罄</button>
  318. </view>
  319. </view>
  320. </view>
  321. </lvv-popup>
  322. <!-- 弹出层end -->
  323. <div id="qrCode" ref="qrCodeDiv"></div>
  324. <!-- 底部按钮 -->
  325. <view class="goods-bottom">
  326. <view class="goods-bottom-ic" @click="collection">
  327. <image class="icon" :src="isfav ? favLogo[1] : favLogo[0]" mode=""></image>
  328. <view v-if="!isfav">收藏</view>
  329. <view v-if="isfav">已收藏</view>
  330. </view>
  331. <view class="goods-bottom-ic" @click="redirectCart">
  332. <view class="badge color-f" v-if="cartNums">{{ cartNums }}</view>
  333. <image class="icon" src="/static/image/ic-me-car.png" mode=""></image>
  334. <view>购物车</view>
  335. </view>
  336. <button class='btn btn-square btn-g' @click="toshow(1)" hover-class="btn-hover2">
  337. <view class="btn-content">
  338. <view class="color-6">¥{{product.price}}</view>
  339. <view class="color-6 fsz24">单独购买</view>
  340. </view>
  341. </button>
  342. <button class='btn btn-square btn-b' @click="toshow(2)" hover-class="btn-hover2" v-if="goodsInfo.pintuan_rule.pintuan_start_status == 1 ">
  343. <view class="btn-content">
  344. <view class="">¥{{pintuanPrice}}</view>
  345. <view class="fsz24">发起拼团</view>
  346. </view>
  347. </button>
  348. <button class='btn btn-square btn-b' hover-class="btn-hover2" v-if="goodsInfo.pintuan_rule.pintuan_start_status == 2 ">
  349. <view class="btn-content">
  350. <view class="">¥{{pintuanPrice}}</view>
  351. <view class="fsz24">即将开团</view>
  352. </view>
  353. </button>
  354. <button class='btn btn-square btn-b' hover-class="btn-hover2" v-if="goodsInfo.pintuan_rule.pintuan_start_status == 3 ">
  355. <view class="btn-content">
  356. <view class="">¥{{pintuanPrice}}</view>
  357. <view class="fsz24">拼团已结束</view>
  358. </view>
  359. </button>
  360. </view>
  361. <!-- 底部按钮end -->
  362. <!-- 右边浮动球 -->
  363. <!-- <view class="right-ball">
  364. <view class="" @click="goIndex()">
  365. <image class="icon" src="/static/image/tab-ic-hom-selected.png" mode=""></image>
  366. </view>
  367. </view> -->
  368. <uni-fab :pattern="pattern" :content="content" :horizontal="horizontal" :vertical="vertical" :direction="direction"
  369. @trigger="trigger"></uni-fab>
  370. </view>
  371. </template>
  372. <script>
  373. import uniSegmentedControl from "@/components/uni-segmented-control/uni-segmented-control.vue";
  374. import lvvPopup from '@/components/lvv-popup/lvv-popup.vue';
  375. import uniNumberBox from "@/components/uni-number-box/uni-number-box.vue";
  376. import uniRate from "@/components/uni-rate/uni-rate.vue";
  377. import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue';
  378. import uniFab from '@/components/uni-fab/uni-fab.vue';
  379. import {
  380. get
  381. } from '@/config/db.js';
  382. import {
  383. apiBaseUrl
  384. } from '@/config/config.js'
  385. import uniCountdown from "@/components/uni-countdown/uni-countdown.vue"
  386. import spec from '@/components/spec/spec.vue'
  387. // #ifdef H5
  388. import shareByH5 from '@/components/share/shareByh5.vue'
  389. // #endif
  390. // #ifdef MP-WEIXIN
  391. import shareByWx from '@/components/share/shareByWx.vue'
  392. // #endif
  393. // #ifdef MP-ALIPAY
  394. import shareByAli from '@/components/share/shareByAli.vue'
  395. // #endif
  396. // #ifdef APP-PLUS
  397. import shareByApp from '@/components/share/shareByApp.vue'
  398. // #endif
  399. import jshopContent from '@/components/jshop/jshop-content.vue'//视频和文本解析组件
  400. export default {
  401. components: {
  402. uniSegmentedControl,
  403. lvvPopup,
  404. uniNumberBox,
  405. uniRate,
  406. uniLoadMore,
  407. uniFab,
  408. uniCountdown,
  409. spec,
  410. jshopContent,
  411. // #ifdef H5
  412. shareByH5,
  413. // #endif
  414. // #ifdef MP-WEIXIN
  415. shareByWx,
  416. // #endif
  417. // #ifdef MP-ALIPAY
  418. shareByAli,
  419. // #endif
  420. // #ifdef APP-PLUS
  421. shareByApp,
  422. // #endif
  423. },
  424. data() {
  425. return {
  426. myShareCode: '', //分享Code
  427. swiper: {
  428. indicatorDots: true,
  429. autoplay: true,
  430. interval: 3000,
  431. duration: 800,
  432. }, // 轮播图属性设置
  433. items: ['图文详情', '商品参数', '买家评论'],
  434. current: 0, // init tab位
  435. goodsId: 0, // 商品id
  436. groupId: 0, // 团购ID
  437. goodsInfo: {
  438. pintuan_rule: {
  439. pintuan_start_status: 1
  440. }
  441. }, // 商品详情
  442. cartNums: 0, // 购物车数量
  443. product: {}, // 规格详情
  444. goodsParams: [], // 商品参数信息
  445. goodsComments: {
  446. loadStatus: 'more',
  447. page: 1,
  448. limit: 5,
  449. list: []
  450. }, // 商品评论信息
  451. buyNum: 1, // 选定的购买数量
  452. minBuyNum: 1, // 最小可购买数量
  453. type: 2, // 1单独购买 2拼团
  454. isfav: false, // 商品是否收藏
  455. favLogo: [
  456. '/static/image/ic-me-collect.png',
  457. '/static/image/ic-me-collect2.png'
  458. ],
  459. horizontal: 'right', //右下角弹出按钮
  460. vertical: 'bottom',
  461. direction: 'vertical',
  462. pattern: {
  463. color: '#7A7E83',
  464. backgroundColor: '#fff',
  465. selectedColor: '#007AFF',
  466. buttonColor: "#FF7159"
  467. },
  468. content: [{
  469. iconPath: '/static/image/tab-ic-hom-selected.png',
  470. selectedIconPath: '/static/image/tab-ic-hom-unselected.png',
  471. // text: '首页',
  472. active: false,
  473. url: '/pages/index/index'
  474. },
  475. {
  476. iconPath: '/static/image/tab-ic-me-selected.png',
  477. selectedIconPath: '/static/image/tab-ic-me-unselected.png',
  478. // text: '个人中心',
  479. active: false,
  480. url: '/pages/member/index/index'
  481. },
  482. ],
  483. indicatorDots: false,
  484. autoplay: false,
  485. interval: 2000,
  486. duration: 500,
  487. lasttime: {
  488. day: 0,
  489. hour: false,
  490. minute: 0,
  491. second: 0
  492. }, //购买倒计时
  493. pintuanPrice: 0,
  494. discount_amount: 0, //拼团优惠金额
  495. price: 0,
  496. teamCount: 0, //已经有多少人拼团
  497. pintuanRecord: [], //拼团列表
  498. remainder_time: {
  499. day: 0,
  500. hour: false,
  501. minute: 0,
  502. second: 0
  503. }, //拼团倒计时
  504. groupHeight: 'groupHeight',
  505. teamId: 0, //去参团的teamid
  506. teamInfo: {
  507. list: [],
  508. team_time: {
  509. day: 0,
  510. hour: 0,
  511. minute: 0,
  512. second: 0
  513. }, //被邀请拼团倒计时
  514. },
  515. }
  516. },
  517. onLoad(e) {
  518. this.goodsId = e.id;
  519. if (e.team_id) {
  520. this.teamId = e.team_id;
  521. this.getTeam(this.teamId)
  522. }
  523. if (this.goodsId) {
  524. this.getGoodsInfo();
  525. this.getGoodsParams();
  526. this.getGoodsComments();
  527. } else {
  528. this.$common.errorToShow('获取失败', () => {
  529. uni.navigateBack({
  530. delta: 1
  531. });
  532. });
  533. }
  534. // 获取购物车数量
  535. this.getCartNums();
  536. this.getMyShareCode();
  537. },
  538. onReady() {
  539. },
  540. computed: {
  541. // 规格切换计算规格商品的 可购买数量
  542. minNums() {
  543. return this.product.stock > this.minBuyNum ? this.minBuyNum : this.product.stock;
  544. },
  545. // 判断商品是否是多规格商品 (为了兼容小程序 只能写在计算属性里面了)
  546. isSpes() {
  547. if (this.product.hasOwnProperty('default_spes_desc') && Object.keys(this.product.default_spes_desc).length) {
  548. return true;
  549. } else {
  550. return false;
  551. }
  552. },
  553. // 优惠信息重新组装
  554. promotion() {
  555. let arr = [];
  556. if (this.product.promotion_list) {
  557. for (let k in this.product.promotion_list) {
  558. arr.push(this.product.promotion_list[k]);
  559. }
  560. }
  561. return arr;
  562. },
  563. typeName() {
  564. return this.goodsInfo.group_type == 3 ? '团购' : '秒杀';
  565. },
  566. shareHref() {
  567. let pages = getCurrentPages()
  568. let page = pages[pages.length - 1]
  569. // #ifdef H5 || MP-WEIXIN || APP-PLUS || APP-PLUS-NVUE
  570. return apiBaseUrl + 'wap/' + page.route + '?id=' + this.goodsId + '&group_id=' + this.groupId;
  571. // #endif
  572. // #ifdef MP-ALIPAY
  573. return apiBaseUrl + 'wap/' + page.__proto__.route + '?id=' + this.goodsId + '&group_id=' + this.groupId;
  574. // #endif
  575. }
  576. },
  577. onReachBottom() {
  578. if (this.current === 2 && this.goodsComments.loadStatus === 'more') {
  579. this.getGoodsComments();
  580. }
  581. },
  582. methods: {
  583. // 返回上一页
  584. backBtn() {
  585. uni.navigateBack({
  586. delta: 1
  587. });
  588. },
  589. // 获取商品详情
  590. getGoodsInfo() {
  591. let data = {
  592. id: this.goodsId
  593. }
  594. // 如果用户已经登录 要传用户token
  595. let userToken = get('userToken');
  596. if (userToken) {
  597. data['token'] = userToken;
  598. }
  599. let _this = this;
  600. _this.$api.pintuanGoodsInfo(data, res => {
  601. console.log(res);
  602. if (res.status) {
  603. if (res.data.length < 1) {
  604. _this.$common.errorToShow('该商品不存在,请返回重新选择商品。', () => {
  605. uni.navigateBack({
  606. delta: 1
  607. });
  608. });
  609. } else if (res.data.marketable != 1) {
  610. _this.$common.errorToShow('该商品已下架,请返回重新选择商品。', () => {
  611. uni.navigateBack({
  612. delta: 1
  613. });
  614. });
  615. } else {
  616. let info = res.data;
  617. _this.goodsInfo = info;
  618. let products = res.data.product;
  619. _this.discount_amount = parseFloat(info.pintuan_rule.discount_amount).toFixed(2);
  620. //products.price = _this.$common.moneySub(products.price,_this.discount_amount);
  621. _this.product = _this.spesClassHandle(products);
  622. _this.isfav = _this.goodsInfo.isfav === 'true' ? true : false;
  623. // _this.pintuanPrice = info.pintuan_price.toFixed(2)
  624. _this.pintuanPrice = this.$common.moneySub(this.product.price, this.discount_amount);
  625. let timestamp = Date.parse(new Date()) / 1000;
  626. let lasttime = res.data.pintuan_rule.etime - timestamp;
  627. _this.lasttime = _this.$common.timeToDateObj(lasttime);
  628. // 获取拼团记录
  629. let pintuan_data = info.pintuan_record;
  630. let new_data = new Array();
  631. for (var k = 0; k < pintuan_data.length; k++) {
  632. pintuan_data[k].remainder_time = _this.$common.timeToDateObj(pintuan_data[k].close_time - timestamp)
  633. if (k == 0 || k % 2 == 0) {
  634. if (k + 1 < pintuan_data.length) {
  635. var a = [
  636. pintuan_data[k],
  637. pintuan_data[k + 1]
  638. ];
  639. } else {
  640. var a = [pintuan_data[k]];
  641. }
  642. new_data.push(a);
  643. }
  644. }
  645. pintuan_data.length < 2 ? _this.groupHeight = 'groupHeight' : _this.groupHeight = '';
  646. _this.pintuanRecord = new_data;
  647. // console.log(new_data);
  648. _this.teamCount = info.pintuan_record_nums;
  649. // 判断如果登录用户添加商品浏览足迹
  650. if (userToken) {
  651. _this.goodsBrowsing();
  652. }
  653. }
  654. }
  655. });
  656. },
  657. // 获取通过分享进来的拼团数据
  658. getTeam(id) {
  659. this.$api.getOrderPintuanTeamInfo({
  660. team_id: id
  661. }, res => {
  662. if (res.status) {
  663. this.teamInfo = {
  664. list: res.data.teams,
  665. current_count: res.data.teams.length,
  666. people_number: res.data.people_number,
  667. team_nums: res.data.team_nums, //剩余
  668. close_time: res.data.close_time, //关闭时间
  669. id: res.data.id, //拼团id
  670. team_id: res.data.team_id, //拼团团队id
  671. rule_id: res.data.rule_id,
  672. status: res.data.status
  673. };
  674. let timestamp = Date.parse(new Date()) / 1000;
  675. this.teamInfo.team_time = this.$common.timeToDateObj(res.data.close_time - timestamp);
  676. if (res.data.status == 1) {
  677. this.pintuanShow();
  678. } else {
  679. this.teamId = 0;
  680. }
  681. } else {
  682. this.$common.errorToShow(res.msg)
  683. }
  684. });
  685. },
  686. // 获取购物车数量
  687. getCartNums() {
  688. let userToken = this.$db.get("userToken");
  689. if (userToken && userToken != '') {
  690. // 获取购物车数量
  691. this.$api.getCartNum({}, res => {
  692. if (res.status) {
  693. this.cartNums = res.data;
  694. }
  695. });
  696. }
  697. },
  698. // 显示modal弹出框
  699. toshow(type, team_id) {
  700. this.type = type;
  701. if (team_id) {
  702. this.teamId = team_id
  703. }
  704. if (this.type == 2) {
  705. this.price = this.pintuanPrice;
  706. } else {
  707. this.price = this.product.price;
  708. }
  709. this.$refs.lvvpopref.show();
  710. },
  711. // 关闭modal弹出框
  712. toclose() {
  713. this.$refs.lvvpopref.close();
  714. },
  715. // 切换商品规格
  716. changeSpes(obj) {
  717. let index = obj.v;
  718. let key = obj.k;
  719. //type = 1是立即购买,2是拼团购买
  720. if (this.product.default_spes_desc[index][key].hasOwnProperty('product_id') && this.product.default_spes_desc[index]
  721. [key].product_id) {
  722. let data = {
  723. 'id': this.product.default_spes_desc[index][key].product_id
  724. };
  725. let userToken = this.$db.get("userToken");
  726. if (userToken) {
  727. data['token'] = userToken;
  728. }
  729. this.$api.getProductInfo(data, res => {
  730. if (res.status == true) {
  731. // 切换规格判断可购买数量
  732. this.buyNum = res.data.stock > this.minBuyNum ? this.minBuyNum : res.data.stock;
  733. this.product = this.spesClassHandle(res.data);
  734. //products.price = _this.$common.moneySub(products.price,_this.discount_amount);
  735. if (this.type == 2) { //拼团
  736. this.price = this.$common.moneySub(this.product.price, this.discount_amount);
  737. } else {
  738. this.price = this.product.price;
  739. }
  740. }
  741. });
  742. uni.showLoading({
  743. title: '加载中'
  744. });
  745. setTimeout(function() {
  746. uni.hideLoading();
  747. }, 1000);
  748. }
  749. },
  750. // 多规格样式统一处理
  751. spesClassHandle(products) {
  752. // 判断是否是多规格 (是否有默认规格)
  753. if (products.hasOwnProperty('default_spes_desc')) {
  754. let spes = products.default_spes_desc;
  755. for (let key in spes) {
  756. for (let i in spes[key]) {
  757. if (spes[key][i].hasOwnProperty('is_default') && spes[key][i].is_default === true) {
  758. this.$set(spes[key][i], 'cla', 'pop-m-item selected');
  759. } else if (spes[key][i].hasOwnProperty('product_id') && spes[key][i].product_id) {
  760. this.$set(spes[key][i], 'cla', 'pop-m-item not-selected');
  761. } else {
  762. this.$set(spes[key][i], 'cla', 'pop-m-item none');
  763. }
  764. }
  765. }
  766. products.default_spes_desc = spes;
  767. }
  768. return products;
  769. },
  770. // 购买数量加减操作
  771. bindChange(val) {
  772. this.buyNum = val;
  773. },
  774. // 商品收藏/取消
  775. collection() {
  776. let data = {
  777. goods_id: this.goodsInfo.id
  778. }
  779. this.$api.goodsCollection(data, res => {
  780. if (res.status) {
  781. this.isfav = !this.isfav;
  782. this.$common.successToShow(res.msg);
  783. } else {
  784. this.$common.errorToShow(res.msg);
  785. }
  786. })
  787. },
  788. // tab点击切换
  789. onClickItem(index) {
  790. if (this.current !== index) {
  791. this.current = index;
  792. }
  793. },
  794. // 获取商品参数信息
  795. getGoodsParams() {
  796. this.$api.goodsParams({
  797. id: this.goodsId
  798. }, res => {
  799. if (res.status == true) {
  800. this.goodsParams = res.data;
  801. }
  802. })
  803. },
  804. // 获取商品评论信息
  805. getGoodsComments() {
  806. let data = {
  807. page: this.goodsComments.page,
  808. limit: this.goodsComments.limit,
  809. goods_id: this.goodsId
  810. }
  811. this.goodsComments.loadStatus = 'loading';
  812. this.$api.goodsComment(data, res => {
  813. if (res.status == true) {
  814. let _list = res.data.list;
  815. // 如果评论没有图片 在这块作处理否则控制台报错
  816. _list.forEach(item => {
  817. item.ctime = this.$common.timeToDate(item.ctime)
  818. if (!item.hasOwnProperty('images_url')) {
  819. this.$set(item, 'images_url', [])
  820. }
  821. });
  822. this.goodsComments.list = [...this.goodsComments.list, ..._list];
  823. // 根据count数量判断是否还有数据
  824. if (res.data.count > this.goodsComments.list.length) {
  825. this.goodsComments.loadStatus = 'more';
  826. this.goodsComments.page++;
  827. } else {
  828. this.goodsComments.loadStatus = 'noMore';
  829. }
  830. } else {
  831. this.$common.errorToShow(res.msg);
  832. }
  833. })
  834. },
  835. // 添加商品浏览足迹
  836. goodsBrowsing() {
  837. let data = {
  838. goods_id: this.goodsInfo.id
  839. }
  840. this.$api.addGoodsBrowsing(data, res => {});
  841. },
  842. // 立即购买
  843. buyNow() {
  844. if (this.buyNum > 0) {
  845. let data = {
  846. product_id: this.product.id,
  847. nums: this.buyNum,
  848. order_type: this.type
  849. }
  850. this.$api.addCart(data, res => {
  851. if (res.status) {
  852. this.toclose();
  853. let cartIds = res.data;
  854. if (this.teamId == 0) {
  855. this.$common.navigateTo('/pages/goods/place-order/index?cart_ids=' + JSON.stringify(cartIds) + '&order_type=' +
  856. this.type);
  857. } else {
  858. this.$common.navigateTo('/pages/goods/place-order/index?cart_ids=' + JSON.stringify(cartIds) + '&order_type=' +
  859. this.type + '&team_id=' + this.teamId);
  860. }
  861. } else {
  862. this.toclose();
  863. this.$common.errorToShow(res.msg);
  864. }
  865. })
  866. }
  867. },
  868. // 购物车页面跳转
  869. redirectCart() {
  870. uni.switchTab({
  871. url: '/pages/cart/index/index'
  872. });
  873. },
  874. trigger(e) {
  875. this.content[e.index].active = !e.item.active;
  876. uni.switchTab({
  877. url: e.item.url
  878. })
  879. },
  880. // 跳转到h5分享页面
  881. goShare() {
  882. this.$refs.share.show();
  883. },
  884. closeShare() {
  885. this.$refs.share.close();
  886. },
  887. // 拼团弹出层
  888. pintuanShow() {
  889. this.$refs.pintuanpop.show();
  890. // this.$refs.lvvpopref.close();
  891. },
  892. pintuanClose() {
  893. //this.$refs.pintuanpop.close();
  894. // this.$refs.pintuanpop.close();
  895. // this.$refs.share.close();
  896. //this.$refs.lvvpopref.close();
  897. },
  898. // 图片点击放大
  899. clickImg(imgs) {
  900. // 预览图片
  901. uni.previewImage({
  902. urls: imgs.split()
  903. });
  904. },
  905. getMyShareCode() {
  906. let userToken = this.$db.get("userToken");
  907. if (userToken && userToken != '') {
  908. // 获取我的分享码
  909. this.$api.shareCode({}, res => {
  910. if (res.status) {
  911. this.myShareCode = res.data ? res.data : '';
  912. }
  913. });
  914. }
  915. }
  916. },
  917. //分享
  918. onShareAppMessage() {
  919. let myInviteCode = this.myShareCode ? this.myShareCode : '';
  920. let ins = this.$common.shareParameterDecode('type=5&id=' + this.goodsId + '&invite=' + myInviteCode);
  921. let path = '/pages/share/jump?scene=' + ins;
  922. console.log(path);
  923. return {
  924. title: this.goodsInfo.name,
  925. // #ifdef MP-ALIPAY
  926. desc: this.goodsInfo.brief,
  927. // #endif
  928. imageUrl: this.goodsInfo.album[0],
  929. path: path
  930. }
  931. }
  932. }
  933. </script>
  934. <style>
  935. .swiper {
  936. height: 750upx;
  937. }
  938. .goods-top {
  939. border-bottom: 0;
  940. }
  941. .goods-top .goods-price {
  942. font-size: 38upx;
  943. }
  944. .cost-price {
  945. font-size: 28upx !important;
  946. bottom: -10upx;
  947. color: #999;
  948. text-decoration: line-through;
  949. }
  950. .goods-top .cell-item-ft {
  951. font-size: 20upx;
  952. color: #666;
  953. }
  954. .goods-details {
  955. padding-top: 16upx;
  956. }
  957. .goods-details .cell-hd-title {
  958. width: 620upx;
  959. }
  960. .goods-details .cell-hd-title .cell-hd-title-view {
  961. width: 100%;
  962. display: -webkit-box;
  963. -webkit-box-orient: vertical;
  964. -webkit-line-clamp: 2;
  965. overflow: hidden;
  966. }
  967. .goods-details .cell-hd-title .cell-hd-title-view:last-child {
  968. margin-top: 10upx;
  969. }
  970. .goods-details .cell-item-ft {
  971. top: 42upx;
  972. }
  973. .goods-title-item .cell-item-hd {
  974. min-width: 60upx;
  975. color: #666;
  976. font-size: 24upx;
  977. }
  978. .goods-title-item .cell-item-bd {
  979. color: #333;
  980. font-size: 24upx;
  981. }
  982. .goods-title-item .cell-bd-text {
  983. bottom: 0;
  984. }
  985. .cell-bd-view {
  986. position: relative;
  987. overflow: hidden;
  988. }
  989. .cell-bd-view:first-child {
  990. margin-bottom: 8upx;
  991. }
  992. .goods-title-item-ic {
  993. width: 22upx;
  994. height: 22upx;
  995. position: absolute;
  996. top: 50%;
  997. transform: translateY(-50%);
  998. /* #ifdef MP-ALIPAY */
  999. background-size: 100% 100%;
  1000. /* #endif */
  1001. }
  1002. .cell-bd-view .cell-bd-text {
  1003. margin-left: 30upx;
  1004. }
  1005. .goods-content {
  1006. margin-top: 26upx;
  1007. background-color: #fff;
  1008. padding: 26upx 0;
  1009. }
  1010. .goods-content-c {}
  1011. .goods-parameter {
  1012. padding: 10upx 26upx;
  1013. }
  1014. .goods-bottom,
  1015. .pop-b {
  1016. background-color: #fff;
  1017. position: fixed;
  1018. bottom: 0;
  1019. height: 90upx;
  1020. width: 100%;
  1021. overflow: hidden;
  1022. box-shadow: 0 0 20upx #ccc;
  1023. }
  1024. .goods-bottom button {
  1025. height: 100%;
  1026. width: 35%;
  1027. }
  1028. .goods-bottom-ic {
  1029. display: inline-block;
  1030. position: relative;
  1031. text-align: center;
  1032. height: 100%;
  1033. width: 15%;
  1034. float: left;
  1035. font-size: 22upx;
  1036. color: #666;
  1037. }
  1038. .goods-bottom-ic .icon {
  1039. position: relative;
  1040. top: 6upx;
  1041. /* left: -6upx; */
  1042. /* #ifdef MP-ALIPAY */
  1043. background-size: 100% 100%;
  1044. /* #endif */
  1045. }
  1046. .goods-bottom .btn-g {
  1047. color: #333;
  1048. background-color: #D9D9D9;
  1049. }
  1050. .goods-parameter .cell-item {
  1051. border-bottom: none;
  1052. margin-left: 0;
  1053. }
  1054. .goods-parameter .cell-item-hd {
  1055. color: #333;
  1056. font-size: 24upx;
  1057. }
  1058. .goods-parameter .cell-item-bd {
  1059. color: #999;
  1060. }
  1061. .goods-parameter .cell-item-bd .cell-bd-text {
  1062. bottom: 0;
  1063. }
  1064. .goods-parameter .cell-bd-text {
  1065. margin-left: 0;
  1066. }
  1067. .pop-t {
  1068. position: relative;
  1069. padding: 30upx 26upx;
  1070. border-bottom: 2upx solid #f3f3f3;
  1071. /* box-shadow: 0 0 20upx #ccc; */
  1072. }
  1073. .goods-img {
  1074. width: 160upx;
  1075. height: 160upx;
  1076. position: absolute;
  1077. top: -20upx;
  1078. background-color: #fff;
  1079. border-radius: 6upx;
  1080. border: 2upx solid #fff;
  1081. }
  1082. .goods-img image {
  1083. height: 100%;
  1084. width: 100%;
  1085. }
  1086. .goods-information {
  1087. width: 420upx;
  1088. display: inline-block;
  1089. margin-left: 180upx;
  1090. }
  1091. .pop-goods-name {
  1092. width: 100%;
  1093. overflow: hidden;
  1094. white-space: nowrap;
  1095. text-overflow: ellipsis;
  1096. display: block;
  1097. font-size: 24upx;
  1098. margin-bottom: 20upx;
  1099. }
  1100. .pop-goods-price {
  1101. font-size: 30upx;
  1102. }
  1103. .close-btn {
  1104. width: 40upx;
  1105. height: 40upx;
  1106. border-radius: 50%;
  1107. display: inline-block;
  1108. position: absolute;
  1109. right: 30upx;
  1110. }
  1111. .close-btn image {
  1112. width: 100%;
  1113. height: 100%;
  1114. }
  1115. .pop-m {
  1116. font-size: 28upx;
  1117. margin-bottom: 90upx;
  1118. }
  1119. .goods-specs,
  1120. .goods-number {
  1121. padding: 26upx;
  1122. border-top: 1px solid #f3f3f3;
  1123. }
  1124. .goods-specs:first-child {
  1125. border: none;
  1126. }
  1127. .pop-m-title {
  1128. margin-right: 10upx;
  1129. color: #666;
  1130. }
  1131. .pop-m-bd {
  1132. overflow: hidden;
  1133. margin-top: 10upx;
  1134. }
  1135. .pop-m-item {
  1136. display: inline-block;
  1137. float: left;
  1138. padding: 6upx 16upx;
  1139. background-color: #fff;
  1140. color: #333;
  1141. margin-right: 16upx;
  1142. margin-bottom: 10upx;
  1143. }
  1144. .selected {
  1145. border: 2upx solid #333;
  1146. background-color: #333;
  1147. color: #fff;
  1148. }
  1149. .not-selected {
  1150. border: 2upx solid #ccc;
  1151. }
  1152. .none {
  1153. border: 2upx dashed #ccc;
  1154. color: #888;
  1155. }
  1156. .pop-m-bd-in {
  1157. display: inline-block;
  1158. }
  1159. .badge {
  1160. top: 2upx;
  1161. left: 62upx;
  1162. }
  1163. .goods-assess .user-head-img {
  1164. width: 80upx;
  1165. height: 80upx;
  1166. border-radius: 50%;
  1167. }
  1168. .goods-assess .cell-item-bd {
  1169. padding-right: 0;
  1170. }
  1171. .goods-assess .cell-bd-text {
  1172. margin: 0;
  1173. }
  1174. .goods-assess .cell-bd-text.color-9 {
  1175. overflow: hidden;
  1176. text-overflow: ellipsis;
  1177. white-space: nowrap;
  1178. max-width: 440upx;
  1179. }
  1180. .gai-body {}
  1181. .gai-body-text {
  1182. font-size: 26upx;
  1183. color: #333;
  1184. padding: 0 26upx;
  1185. word-wrap: break-word;
  1186. }
  1187. .gai-body-img {
  1188. overflow: hidden;
  1189. padding: 20upx 26upx;
  1190. }
  1191. .gai-body-img image {
  1192. width: 220upx;
  1193. height: 220upx;
  1194. float: left;
  1195. margin-right: 19upx;
  1196. margin-bottom: 18upx;
  1197. }
  1198. .gai-body-img image:nth-child(3n) {
  1199. margin-right: 0;
  1200. }
  1201. .redstar {
  1202. width: 24rpx;
  1203. height: 24rpx;
  1204. padding: 2rpx;
  1205. }
  1206. .mask-share-wechat {
  1207. display: inline-block;
  1208. background-color: #fff;
  1209. padding: 0;
  1210. }
  1211. .mask-share-wechat:after {
  1212. border: none;
  1213. }
  1214. .right-ball {
  1215. position: fixed;
  1216. right: 30upx;
  1217. bottom: 300upx;
  1218. z-index: 999;
  1219. text-align: center;
  1220. padding: 14upx 0;
  1221. /* line-height: 80upx; */
  1222. width: 80upx;
  1223. height: 80upx;
  1224. font-size: 24upx;
  1225. color: #fff;
  1226. background-color: rgba(0, 0, 0, .5);
  1227. border-radius: 50%;
  1228. }
  1229. .share-pop {
  1230. height: 300upx;
  1231. width: 100%;
  1232. display: flex;
  1233. }
  1234. .share-item {
  1235. flex: 1;
  1236. text-align: center;
  1237. font-size: 26upx;
  1238. color: #333;
  1239. padding: 20upx 0;
  1240. }
  1241. /* .share-item image{
  1242. width: 120upx;
  1243. height: 120upx;
  1244. } */
  1245. .comment-none {
  1246. text-align: center;
  1247. padding: 200upx 0;
  1248. }
  1249. .comment-none-img {
  1250. width: 274upx;
  1251. height: 274upx;
  1252. }
  1253. .price-salesvolume {
  1254. width: 100%;
  1255. height: 112upx;
  1256. padding: 0 0 0 26upx;
  1257. overflow: hidden;
  1258. color: #A5A5A5;
  1259. background-color: rgb(252, 226, 80);
  1260. position: relative;
  1261. }
  1262. .commodity-price {
  1263. width: 224upx;
  1264. display: inline-block;
  1265. float: left;
  1266. }
  1267. .current-price {
  1268. font-size: 40upx;
  1269. color: #FF7159;
  1270. display: block;
  1271. line-height: 1.5;
  1272. }
  1273. .cost-price {
  1274. font-size: 26upx;
  1275. text-decoration: line-through;
  1276. /* margin-left: 8rpx; */
  1277. display: block;
  1278. }
  1279. .commodity-salesvolume {
  1280. width: 240upx;
  1281. display: inline-block;
  1282. font-size: 22upx;
  1283. float: left;
  1284. padding: 16upx 0;
  1285. }
  1286. .commodity-salesvolume>text {
  1287. display: block;
  1288. }
  1289. .commodity-time-img {
  1290. display: block;
  1291. width: 0;
  1292. height: 0;
  1293. border-width: 56upx 28upx 56upx 0;
  1294. border-style: solid;
  1295. border-color: transparent #FF7159 transparent transparent;
  1296. /*透明 黄 透明 透明 */
  1297. /* position: absolute; */
  1298. /* top: 0px; */
  1299. /* right: 260upx; */
  1300. float: right;
  1301. }
  1302. .commodity-time {
  1303. display: inline-block;
  1304. width: 220upx;
  1305. height: 100%;
  1306. text-align: center;
  1307. font-size: 24upx;
  1308. background-color: #FF7159;
  1309. padding: 16upx 0 18upx;
  1310. color: #FF7159;
  1311. float: right;
  1312. }
  1313. .commodity-time>text {
  1314. color: rgb(252, 226, 80);
  1315. }
  1316. .commodity-day>text {
  1317. display: inline-block;
  1318. background-color: rgb(255, 212, 176);
  1319. color: rgb(255, 115, 0);
  1320. padding: 0 6upx;
  1321. border-radius: 6upx;
  1322. }
  1323. .nav-back {
  1324. width: 100%;
  1325. height: 44px;
  1326. /* #ifndef MP-WEIXIN */
  1327. padding: 12px 12px 0;
  1328. /* #endif */
  1329. /* #ifdef MP-WEIXIN */
  1330. padding: 26px 12px 0;
  1331. /* #endif */
  1332. position: fixed;
  1333. top: 0;
  1334. background-color: rgba(255, 255, 255, 0);
  1335. z-index: 98;
  1336. }
  1337. .back-btn {
  1338. height: 32px;
  1339. width: 32px;
  1340. border-radius: 50%;
  1341. background-color: rgba(255, 255, 255, 0.8);
  1342. }
  1343. .back-btn .icon {
  1344. height: 20px;
  1345. width: 20px;
  1346. position: relative;
  1347. top: 50%;
  1348. left: 46%;
  1349. transform: translate(-50%, -50%);
  1350. }
  1351. .tl {
  1352. width: 70% !important;
  1353. }
  1354. .group-swiper {
  1355. /* padding: 20upx 26upx; */
  1356. }
  1357. .groupHeight {
  1358. height: 122upx !important;
  1359. }
  1360. .group-swiper-c {
  1361. height: 242upx;
  1362. }
  1363. .group-swiper-c .swiper-item .cell-item {
  1364. height: 50%;
  1365. }
  1366. .group-swiper-c .swiper-item .cell-item .user-head-img {
  1367. width: 80upx;
  1368. height: 80upx;
  1369. border-radius: 50%;
  1370. }
  1371. .group-swiper-c .swiper-item .cell-item .cell-hd-title {
  1372. position: absolute;
  1373. top: 50%;
  1374. left: 100upx;
  1375. transform: translateY(-50%);
  1376. max-width: 220upx;
  1377. width: 100%;
  1378. overflow: hidden;
  1379. text-overflow: ellipsis;
  1380. white-space: nowrap;
  1381. }
  1382. .group-swiper-c .swiper-item .cell-item .cell-item-bd {
  1383. min-width: 150upx;
  1384. max-width: 200upx;
  1385. padding-right: 134upx;
  1386. text-align: center;
  1387. }
  1388. .group-swiper-c .swiper-item .cell-item .cell-item-bd .cell-bd-view {
  1389. margin-bottom: 0;
  1390. }
  1391. .group-swiper-c .swiper-item .cell-item .cell-item-bd .cell-bd-text {
  1392. float: none;
  1393. }
  1394. .group-swiper-c .commodity-day>text {
  1395. background: none !important;
  1396. padding: 0;
  1397. }
  1398. .group-swiper-c .swiper-item .cell-item .cell-item-ft .btn {
  1399. font-size: 26upx;
  1400. color: #fff;
  1401. background-color: #FF7159;
  1402. /* padding: 0; */
  1403. text-align: center;
  1404. }
  1405. .btn-content {
  1406. line-height: 1.2;
  1407. position: relative;
  1408. top: 49%;
  1409. transform: translateY(-50%);
  1410. }
  1411. .ig-top {
  1412. text-align: center;
  1413. background-color: #fff;
  1414. padding: 20upx 26upx;
  1415. width: 690upx;
  1416. min-height: 90upx;
  1417. position: absolute;
  1418. top: 50%;
  1419. left: 50%;
  1420. transform: translate(-50%, -50%);
  1421. }
  1422. .ig-top-t,
  1423. .ig-top-m {
  1424. margin-bottom: 20upx;
  1425. }
  1426. .ig-top-t>view {
  1427. display: inline-block;
  1428. padding: 0 10upx;
  1429. color: #999;
  1430. }
  1431. .user-head-img-c {
  1432. position: relative;
  1433. width: 80upx;
  1434. height: 80upx;
  1435. border-radius: 50%;
  1436. margin-right: 20upx;
  1437. box-sizing: border-box;
  1438. display: inline-block;
  1439. /* float: left; */
  1440. border: 1px solid #f3f3f3;
  1441. }
  1442. .user-head-img-tip {
  1443. position: absolute;
  1444. top: -6upx;
  1445. left: -10upx;
  1446. display: inline-block;
  1447. background-color: #FF7159;
  1448. color: #fff;
  1449. font-size: 22upx;
  1450. z-index: 98;
  1451. padding: 0 10upx;
  1452. border-radius: 10upx;
  1453. transform: scale(.8);
  1454. }
  1455. .user-head-img-c .user-head-img {
  1456. width: 100%;
  1457. height: 100%;
  1458. border-radius: 50%;
  1459. }
  1460. .user-head-img-c:first-child {
  1461. border: 1px solid #FF7159;
  1462. }
  1463. .uhihn {
  1464. width: 80upx;
  1465. height: 80upx;
  1466. border-radius: 50%;
  1467. display: inline-block;
  1468. border: 2upx dashed #e1e1e1;
  1469. text-align: center;
  1470. color: #d1d1d1;
  1471. font-size: 40upx;
  1472. box-sizing: border-box;
  1473. position: relative;
  1474. }
  1475. .uhihn>text {
  1476. position: absolute;
  1477. left: 50%;
  1478. top: 50%;
  1479. transform: translate(-50%, -50%);
  1480. }
  1481. .igtb-top {
  1482. font-size: 32upx;
  1483. color: #333;
  1484. margin-bottom: 16upx;
  1485. }
  1486. .igtb-mid {
  1487. margin-bottom: 16upx;
  1488. }
  1489. .igtb-mid .btn {
  1490. width: 100%;
  1491. background-color: #FF7159;
  1492. color: #fff;
  1493. }
  1494. .igtb-bot {
  1495. font-size: 24upx;
  1496. color: #666;
  1497. }
  1498. </style>
pintuan2.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="content-top">
  4. <!-- 轮播图 -->
  5. <view class='swiper'>
  6. <swiper class="swiper-c" :indicator-dots="swiper.indicatorDots" :autoplay="swiper.autoplay" :interval="swiper.interval"
  7. :duration="swiper.duration">
  8. <swiper-item class="have-none" v-for="(item, index) in goodsInfo.album" :key="index" @click="clickImg(item)">
  9. <image class='' :src='item' mode="aspectFill"></image>
  10. </swiper-item>
  11. </swiper>
  12. </view>
  13. <!-- 轮播图end -->
  14. <view class='cell-group'>
  15. <!-- 倒计时 -->
  16. <view class='price-salesvolume' v-if="lasttime.hour!==false">
  17. <view class='commodity-price'>
  18. <text class='current-price'>¥{{ product.pintuan_price }}</text>
  19. <text class='cost-price'>¥{{product.mktprice}}</text>
  20. </view>
  21. <view class='commodity-salesvolume'>
  22. <text>已售{{goodsInfo.buy_count}}件/剩余{{product.stock}}件</text>
  23. <text>累计销售{{goodsInfo.buy_count}}件</text>
  24. </view>
  25. <view class='commodity-time-img'></view>
  26. <view class='commodity-time'>
  27. <text>距结束仅剩</text>
  28. <view class='commodity-day'>
  29. <uni-countdown :day="lasttime.day" :hour="lasttime.hour" :minute="lasttime.minute" :second="lasttime.second"></uni-countdown>
  30. </view>
  31. </view>
  32. <!-- <view class='commodity-time'>
  33. 已结束
  34. </view> -->
  35. </view>
  36. <!-- 倒计时end -->
  37. <!-- 分享 -->
  38. <view class='cell-item goods-details'>
  39. <view class='cell-item-hd'>
  40. <view class='cell-hd-title'>{{ product.name }}</view>
  41. </view>
  42. <view class='cell-item-ft'>
  43. <image class='cell-ft-next icon' @click="goShare()" src='../../../static/image/share.png'></image>
  44. </view>
  45. </view>
  46. <!-- 分享end -->
  47. <!-- 规格 -->
  48. <view class='cell-item goods-title-item' v-if="isSpes">
  49. <view class='cell-item-hd'>
  50. <view class='cell-hd-title'>规格</view>
  51. </view>
  52. <view class='cell-item-bd' @click="toshow(2)">
  53. <text class='cell-bd-text'>{{ product.spes_desc }}</text>
  54. </view>
  55. </view>
  56. <!-- 规格end -->
  57. <!-- 说明 -->
  58. <view class='cell-item goods-title-item'>
  59. <view class='cell-item-hd'>
  60. <view class='cell-hd-title'>说明</view>
  61. </view>
  62. <view class='cell-item-bd'>
  63. <view class="cell-bd-view">
  64. <image class="goods-title-item-ic" src="../../../static/image/ic-dui.png" mode=""></image>
  65. <text class="cell-bd-text">24小时内发货</text>
  66. </view>
  67. <view class="cell-bd-view">
  68. <image class="goods-title-item-ic" src="../../../static/image/ic-dui.png" mode=""></image>
  69. <text class="cell-bd-text">7天拆封无条件退货</text>
  70. </view>
  71. </view>
  72. </view>
  73. <!-- 说明end -->
  74. </view>
  75. <!-- 团购拼单 -->
  76. <view class="cell-group margin-cell-group" v-if="teamCount">
  77. <view class='cell-item right-img'>
  78. <view class='cell-item-hd'>
  79. <view class='cell-hd-title'>{{teamCount}}人在拼单,可直接参与</view>
  80. </view>
  81. <!-- <view class='cell-item-ft' >
  82. <image class='cell-ft-next icon' src='../../../static/image/right.png'></image>
  83. <text class='cell-ft-text'>查看更多</text>
  84. </view> -->
  85. </view>
  86. <view class="group-swiper">
  87. <swiper class="group-swiper-c" :indicator-dots="indicatorDots" :autoplay="autoplay" vertical="true" circular="true"
  88. :interval="interval" :duration="duration">
  89. <swiper-item v-for="(item, index) in teamList" :key="index">
  90. <view class="swiper-item">
  91. <view class='cell-item'>
  92. <view class='cell-item-hd'>
  93. <image class="user-head-img cell-hd-icon have-none" :src='item[0].avatar' mode=""></image>
  94. <view class="cell-hd-title">
  95. {{item[0].user_name}}
  96. </view>
  97. </view>
  98. <view class='cell-item-bd'>
  99. <view class="cell-bd-view">
  100. <text class="cell-bd-text">还差<text class="red-price">{{item[0].peopleNums}}人</text>拼成</text>
  101. </view>
  102. <view class="cell-bd-view">
  103. <view class='commodity-day'>
  104. <uni-countdown :day="item[0].remainder_time.day" :hour="item[0].remainder_time.hour" :minute="item[0].remainder_time.minute"
  105. :second="item[0].remainder_time.second"></uni-countdown>
  106. </view>
  107. </view>
  108. </view>
  109. <view class="cell-item-ft" v-if="!item[0].is_own">
  110. <button class="btn" @click="toshow(1,item[0].id)">去拼单</button>
  111. </view>
  112. <view class="cell-item-ft" v-else>
  113. <button class="btn btn-b">拼团中</button>
  114. </view>
  115. </view>
  116. <view class='cell-item' v-if="item[1]">
  117. <view class='cell-item-hd'>
  118. <image class="user-head-img cell-hd-icon have-none" :src='item[1].avatar' mode=""></image>
  119. <view class="cell-hd-title">
  120. {{item[1].user_name}}
  121. </view>
  122. </view>
  123. <view class='cell-item-bd'>
  124. <view class="cell-bd-view">
  125. <text class="cell-bd-text">还差<text class="red-price">{{item[1].peopleNums}}人</text>拼成</text>
  126. </view>
  127. <view class="cell-bd-view">
  128. <view class='commodity-day'>
  129. <uni-countdown :day="item[1].remainder_time.day" :hour="item[1].remainder_time.hour" :minute="item[1].remainder_time.minute"
  130. :second="item[1].remainder_time.second"></uni-countdown>
  131. </view>
  132. </view>
  133. </view>
  134. <view class="cell-item-ft" v-if="!item[1].is_own">
  135. <button class="btn" @click="toshow(1,item[1].id)">去拼单</button>
  136. </view>
  137. <view class="cell-item-ft" v-else>
  138. <button class="btn btn-b">拼团中</button>
  139. </view>
  140. </view>
  141. </view>
  142. </swiper-item>
  143. </swiper>
  144. </view>
  145. </view>
  146. <view class="cell-group margin-cell-group" v-else>
  147. <view class='cell-item right-img'>
  148. <view class='cell-item-hd'>
  149. <view class='cell-hd-title'>暂无开团信息</view>
  150. </view>
  151. </view>
  152. </view>
  153. <view class="goods-content">
  154. <uni-segmented-control :current="current" :values="items" @clickItem="onClickItem" style-type="text" active-color="#333"></uni-segmented-control>
  155. <view class="goods-content-c">
  156. <view class="goods-detail" v-if="current === 0">
  157. <u-parse :content="goodsInfo.intro" />
  158. </view>
  159. <view class="goods-parameter" v-else-if="current === 1">
  160. <view class='cell-group' v-if="goodsParams.length">
  161. <view class='cell-item' v-for="(item, index) in goodsParams" :key="index">
  162. <view class='cell-item-hd'>
  163. <view class='cell-hd-title'>{{ item.name }}</view>
  164. </view>
  165. <view class='cell-item-bd'>
  166. <text class='cell-bd-text'>{{ item.value }}</text>
  167. </view>
  168. </view>
  169. </view>
  170. </view>
  171. <view class="goods-assess" v-else-if="current === 2">
  172. <view v-if="goodsComments.list.length">
  173. <view class="goods-assess-item" v-for="(item, index) in goodsComments.list" :key="index">
  174. <view class='cell-group'>
  175. <view class='cell-item goods-title-item'>
  176. <view class='cell-item-hd'>
  177. <image class='user-head-img' :src='item.user.avatar' mode="aspectFill"></image>
  178. </view>
  179. <view class='cell-item-bd'>
  180. <view class="cell-bd-view">
  181. <text class="cell-bd-text">{{ item.user.nickname }}</text>
  182. <view class="cell-bd-text-right">
  183. <uni-rate size="16" disabled="true" :value="item.score"></uni-rate>
  184. </view>
  185. </view>
  186. <view class="cell-bd-view">
  187. <text class="cell-bd-text color-9" style="margin-right: 16upx;">{{ item.ctime }}</text>
  188. <text class="cell-bd-text color-9">{{ item.addon }}</text>
  189. </view>
  190. </view>
  191. </view>
  192. </view>
  193. <view class="gai-body">
  194. <view class="gai-body-text">
  195. {{ item.content }}
  196. </view>
  197. <view class="gai-body-img" v-if="item.images_url.length">
  198. <image :src="img" mode="aspectFill" v-for="(img, key) in item.images_url" :key="key" @click="clickImg(img)"></image>
  199. </view>
  200. </view>
  201. </view>
  202. <uni-load-more :status="goodsComments.loadStatus"></uni-load-more>
  203. </view>
  204. <view class="comment-none" v-else>
  205. <image class="comment-none-img" src="../../../static/image/order.png" mode=""></image>
  206. </view>
  207. </view>
  208. </view>
  209. </view>
  210. </view>
  211. <!-- 弹出层 -->
  212. <lvv-popup position="bottom" ref="share">
  213. <!-- #ifdef H5 -->
  214. <shareByH5 :shareType='3' :goodsId="goodsInfo.id" :groupId="groupInfo.id" :shareImg="goodsInfo.image_url"
  215. :shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief" :shareHref="shareHref" @close="closeShare()"></shareByH5>
  216. <!-- #endif -->
  217. <!-- #ifdef MP-WEIXIN -->
  218. <shareByWx :shareType='3' :goodsId="goodsInfo.id" :groupId="groupInfo.id" :shareImg="goodsInfo.image_url"
  219. :shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief" :shareHref="shareHref" @close="closeShare()"></shareByWx>
  220. <!-- #endif -->
  221. <!-- #ifdef MP-ALIPAY -->
  222. <shareByAli :shareType='3' :goodsId="goodsInfo.id" :groupId="groupInfo.id" :shareImg="goodsInfo.image_url"
  223. :shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief" :shareHref="shareHref" @close="closeShare()"></shareByAli>
  224. <!-- #endif -->
  225. <!-- #ifdef APP-PLUS -->
  226. <shareByApp :shareType='3' :goodsId="goodsInfo.id" :groupId="groupInfo.id" :shareImg="goodsInfo.image_url"
  227. :shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief" :shareHref="shareHref" @close="closeShare()"></shareByApp>
  228. <!-- #endif -->
  229. </lvv-popup>
  230. <!-- 弹出层 -->
  231. <lvv-popup position="bottom" ref="lvvpopref">
  232. <view style="width: 100%;max-height: 804upx;background: #FFFFFF;position: absolute;left:0;bottom: 0;">
  233. <view class="pop-c">
  234. <view class="pop-t">
  235. <view class='goods-img'>
  236. <image :src='product.image_path' mode='aspectFill'></image>
  237. </view>
  238. <view class='goods-information'>
  239. <view class='pop-goods-name'>{{ product.name }}</view>
  240. <view class='pop-goods-price red-price'>¥ {{ product.price }}</view>
  241. </view>
  242. <view class='close-btn' @click="toclose()">
  243. <image src='../../../static/image/close.png'></image>
  244. </view>
  245. </view>
  246. <scroll-view class="pop-m" scroll-y="true" style="max-height: 560upx;">
  247. <spec :spesData="product.default_spes_desc" ref="spec" @changeSpes="changeSpes"></spec>
  248. <view class="goods-number">
  249. <text class="pop-m-title">数量</text>
  250. <view class="pop-m-bd-in">
  251. <uni-number-box :min="minNums" :max="product.stock" :value="buyNum" @change="bindChange"></uni-number-box>
  252. </view>
  253. </view>
  254. </scroll-view>
  255. <view class="pop-b" v-if="lvvpopref_type == 2">
  256. <button class='btn btn-square btn-g btn-half' @click="buyNow(1)">单独购买¥ {{ product.price }}</button>
  257. <button class='btn btn-square btn-b btn-half' @click="buyNow(2)">立即拼单¥ {{ product.pintuan_price }}</button>
  258. </view>
  259. <view class="pop-b" v-else>
  260. <button class='btn btn-square btn-b' @click="buyNow1(2)">确定¥ {{ product.pintuan_price }}</button>
  261. </view>
  262. </view>
  263. </view>
  264. </lvv-popup>
  265. <!-- 弹出层end -->
  266. <!-- 底部按钮 -->
  267. <view class="goods-bottom">
  268. <view class="goods-bottom-ic" @click="collection">
  269. <image class="icon" :src="isfav ? favLogo[1] : favLogo[0]" mode=""></image>
  270. <view v-if="!isfav">收藏</view>
  271. <view v-if="isfav">已收藏</view>
  272. </view>
  273. <view class="goods-bottom-ic" @click="redirectCart">
  274. <view class="badge color-f" v-if="cartNums">{{ cartNums }}</view>
  275. <image class="icon" src="../../../static/image/ic-me-car.png" mode=""></image>
  276. <view>购物车</view>
  277. </view>
  278. <button class='btn btn-square btn-b tl' @click="toshow(2)" hover-class="btn-hover2">立即拼单</button>
  279. </view>
  280. <!-- 底部按钮end -->
  281. <!-- 右边浮动球 -->
  282. <uni-fab :pattern="pattern" :content="content" :horizontal="horizontal" :vertical="vertical" :direction="direction"
  283. @trigger="trigger"></uni-fab>
  284. </view>
  285. </template>
  286. <script>
  287. import uniSegmentedControl from "@/components/uni-segmented-control/uni-segmented-control.vue";
  288. import lvvPopup from '@/components/lvv-popup/lvv-popup.vue';
  289. import uniNumberBox from "@/components/uni-number-box/uni-number-box.vue";
  290. import uniRate from "@/components/uni-rate/uni-rate.vue";
  291. import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue';
  292. import uniFab from '@/components/uni-fab/uni-fab.vue';
  293. import {
  294. get
  295. } from '@/config/db.js';
  296. import {
  297. apiBaseUrl
  298. } from '@/config/config.js';
  299. import {
  300. pintuanUrl
  301. } from '@/config/config.js';
  302. import uniCountdown from "@/components/uni-countdown/uni-countdown.vue";
  303. import uParse from '@/components/u-parse/u-parse.vue';
  304. import spec from '@/components/spec/spec.vue';
  305. import share from '@/components/share/share.vue';
  306. // #ifdef H5
  307. import shareByH5 from '@/components/share/shareByh5.vue'
  308. // #endif
  309. // #ifdef MP-WEIXIN
  310. import shareByWx from '@/components/share/shareByWx.vue'
  311. // #endif
  312. // #ifdef MP-ALIPAY
  313. import shareByAli from '@/components/share/shareByAli.vue'
  314. // #endif
  315. // #ifdef APP-PLUS
  316. import shareByApp from '@/components/share/shareByApp.vue'
  317. // #endif
  318. import htmlParser from '@/common/html-parser'
  319. export default {
  320. components: {
  321. uniSegmentedControl,
  322. lvvPopup,
  323. uniNumberBox,
  324. uniRate,
  325. uniLoadMore,
  326. uniFab,
  327. uniCountdown,
  328. uParse,
  329. share,
  330. spec,
  331. // #ifdef H5
  332. shareByH5,
  333. // #endif
  334. // #ifdef MP-WEIXIN
  335. shareByWx,
  336. // #endif
  337. // #ifdef MP-ALIPAY
  338. shareByAli,
  339. // #endif
  340. // #ifdef APP-PLUS
  341. shareByApp,
  342. // #endif
  343. },
  344. data() {
  345. return {
  346. myShareCode: '', //分享Code
  347. shareType: 0,
  348. providerList: [], // 分享通道 包含生成海报
  349. swiper: {
  350. indicatorDots: true,
  351. autoplay: true,
  352. interval: 3000,
  353. duration: 800,
  354. }, // 轮播图属性设置
  355. items: ['图文详情', '商品参数', '买家评论'],
  356. current: 0, // init tab位
  357. goodsId: 0, // 商品id
  358. groupId: 0, // 拼团ID
  359. cartNums: 0, // 购物车数量
  360. groupInfo: {}, // 拼团详情
  361. goodsInfo: {}, //商品详情
  362. teamList: [], //团队列表
  363. teamCount: 0, //开团团数
  364. product: {}, // 规格详情
  365. goodsParams: [], // 商品参数信息
  366. goodsComments: {
  367. loadStatus: 'more',
  368. page: 1,
  369. limit: 5,
  370. list: []
  371. }, // 商品评论信息
  372. buyNum: 1, // 选定的购买数量
  373. minBuyNum: 1, // 最小可购买数量
  374. type: 2, // 1加入购物车 2购买
  375. isfav: false, // 商品是否收藏
  376. favLogo: [
  377. '../../../static/image/ic-me-collect.png',
  378. '../../../static/image/ic-me-collect2.png'
  379. ],
  380. horizontal: 'right', //右下角弹出按钮
  381. vertical: 'bottom',
  382. direction: 'vertical',
  383. pattern: {
  384. color: '#7A7E83',
  385. backgroundColor: '#fff',
  386. selectedColor: '#007AFF',
  387. buttonColor: "#FF7159"
  388. },
  389. content: [{
  390. iconPath: '../../../static/image/tab-ic-hom-selected.png',
  391. selectedIconPath: '../../../static/image/tab-ic-hom-unselected.png',
  392. // text: '首页',
  393. active: false,
  394. url: '/pages/index/index'
  395. },
  396. {
  397. iconPath: '../../../static/image/tab-ic-me-selected.png',
  398. selectedIconPath: '../../../static/image/tab-ic-me-unselected.png',
  399. // text: '个人中心',
  400. active: false,
  401. url: '/pages/member/index/index'
  402. },
  403. ],
  404. indicatorDots: false,
  405. autoplay: false,
  406. interval: 2000,
  407. duration: 500,
  408. lasttime: {
  409. hour: false,
  410. minute: 0,
  411. second: 0
  412. },
  413. lvvpopref_type: 2,
  414. team_id: 0, //团id
  415. userToken: 0,
  416. invite: 0 //邀请人的团Id
  417. }
  418. },
  419. onLoad(e) {
  420. this.goodsId = e.id;
  421. this.groupId = e.group_id;
  422. //获取拼团id,商品ID
  423. if (this.goodsId && this.groupId) {
  424. this.getPintuanInfo(groupId);
  425. this.getTeam(groupId);
  426. this.getGoodsParams();
  427. this.getGoodsComments();
  428. } else {
  429. this.$common.errorToShow('获取失败', () => {
  430. uni.navigateBack({
  431. delta: 1
  432. });
  433. });
  434. }
  435. // 获取购物车数量
  436. this.getCartNums();
  437. this.getMyShareCode();
  438. },
  439. computed: {
  440. // 规格切换计算规格商品的 可购买数量
  441. minNums() {
  442. return this.product.stock > this.minBuyNum ? this.minBuyNum : this.product.stock;
  443. },
  444. // 判断商品是否是多规格商品 (为了兼容小程序 只能写在计算属性里面了)
  445. isSpes() {
  446. if (this.product.hasOwnProperty('default_spes_desc') && Object.keys(this.product.default_spes_desc).length) {
  447. return true;
  448. } else {
  449. return false;
  450. }
  451. },
  452. // 优惠信息重新组装
  453. promotion() {
  454. let arr = [];
  455. if (this.product.promotion_list) {
  456. for (let k in this.product.promotion_list) {
  457. arr.push(this.product.promotion_list[k]);
  458. }
  459. }
  460. return arr;
  461. },
  462. shareHref() {
  463. let pages = getCurrentPages()
  464. let page = pages[pages.length - 1]
  465. // #ifdef H5 || MP-WEIXIN || APP-PLUS || APP-PLUS-NVUE
  466. return apiBaseUrl + 'wap/#/' + page.route + '?id=' + this.goodsId + '&group_id=' + this.groupId;
  467. // #endif
  468. // #ifdef MP-ALIPAY
  469. return apiBaseUrl + 'wap/#/' + page.__proto__.route + '?id=' + this.goodsId + '&group_id=' + this.groupId;
  470. // #endif
  471. }
  472. },
  473. onReachBottom() {
  474. if (this.current === 2 && this.goodsComments.loadStatus === 'more') {
  475. this.getGoodsComments();
  476. }
  477. },
  478. methods: {
  479. // 关闭弹出层
  480. close() {
  481. this.$emit('close')
  482. },
  483. // 点击操作
  484. clickHandler(e) {
  485. if (e.cate === 'poster') {
  486. this.createPoster()
  487. } else {
  488. // 去分享
  489. this.share(e)
  490. }
  491. },
  492. // 购物车页面跳转
  493. redirectCart() {
  494. uni.switchTab({
  495. url: '/pages/cart/index/index'
  496. });
  497. },
  498. //开团列表
  499. getTeam(id) {
  500. uni.showLoading({
  501. title: '加载中'
  502. });
  503. let userToken = this.$db.get("userToken");
  504. if (userToken && userToken != '') {
  505. this.userToken = userToken;
  506. }
  507. uni.request({
  508. url: this.$config.pintuanUrl + 'getTeam',
  509. header: {
  510. 'Accept': 'application/json',
  511. 'Content-Type': 'application/json',
  512. },
  513. method: 'POST',
  514. data: {
  515. rule_id: id,
  516. token: this.userToken
  517. },
  518. success: (res) => {
  519. uni.hideLoading();
  520. if (res.data.status) {
  521. let data = res.data.data;
  522. let new_data = new Array();
  523. for (var k = 0; k < data.length; k++) {
  524. if (k == 0 || k % 2 == 0) {
  525. if (k + 1 < data.length) {
  526. var a = [
  527. data[k],
  528. data[k + 1]
  529. ];
  530. } else {
  531. var a = [data[k]];
  532. }
  533. new_data.push(a);
  534. }
  535. }
  536. //console.log(new_data);
  537. this.teamList = new_data;
  538. this.teamCount = res.data.count;
  539. }
  540. },
  541. fail: (error) => {
  542. uni.hideLoading();
  543. if (error && error.response) {
  544. this.$common.showError(error.response);
  545. }
  546. },
  547. });
  548. },
  549. //拼团信息
  550. getPintuanInfo(id) {
  551. uni.showLoading({
  552. title: '加载中'
  553. });
  554. uni.request({
  555. url: this.$config.pintuanUrl + 'getPintuanInfo',
  556. header: {
  557. 'Accept': 'application/json',
  558. 'Content-Type': 'application/json',
  559. },
  560. method: 'POST',
  561. data: {
  562. id: id
  563. },
  564. success: (res) => {
  565. uni.hideLoading();
  566. if (res.data.status) {
  567. if (res.data.data.length < 1) {
  568. this.$common.errorToShow('该拼团活动不存在,请返回重新选择。', () => {
  569. uni.navigateBack({
  570. delta: 1
  571. });
  572. });
  573. }
  574. // else if (res.data.data.goods_info.goodmarketable != 1){
  575. // this.$common.errorToShow('该商品已下架,请返回重新选择商品。', () => {
  576. // uni.navigateBack({
  577. // delta: 1
  578. // });
  579. // });
  580. // }
  581. else {
  582. this.groupInfo = res.data.data;
  583. this.product = res.data.data.goods_info.product;
  584. this.goodsInfo = this.groupInfo.goods_info;
  585. let price = this.product.price;
  586. if (price > 0) {
  587. this.product.price = price;
  588. } else {
  589. this.product.price = 0.00;
  590. }
  591. this.product = this.spesClassHandle(this.product);
  592. this.lasttime = res.data.data.lasttime;
  593. }
  594. }
  595. },
  596. fail: (error) => {
  597. uni.hideLoading();
  598. if (error && error.response) {
  599. this.$common.showError(error.response);
  600. }
  601. },
  602. });
  603. },
  604. // 获取购物车数量
  605. getCartNums() {
  606. let userToken = this.$db.get("userToken");
  607. if (userToken && userToken != '') {
  608. // 获取购物车数量
  609. this.$api.getCartNum({}, res => {
  610. if (res.status) {
  611. this.cartNums = res.data;
  612. }
  613. });
  614. }
  615. },
  616. // 显示modal弹出框
  617. toshow(type, team_id = 0) {
  618. if (type == 1) {
  619. this.lvvpopref_type = 1;
  620. }
  621. if (type == 2) {
  622. this.lvvpopref_type = 2;
  623. }
  624. if (team_id !== 0) {
  625. this.team_id = team_id;
  626. }
  627. this.$refs.lvvpopref.show();
  628. },
  629. // 关闭modal弹出框
  630. toclose() {
  631. this.$refs.lvvpopref.close();
  632. },
  633. // 切换商品规格
  634. changeSpes(obj) {
  635. //console.log(obj);
  636. let index = obj.v;
  637. let key = obj.k;
  638. if (this.product.default_spes_desc[index][key].hasOwnProperty('product_id') && this.product.default_spes_desc[index]
  639. [key].product_id) {
  640. uni.showLoading({
  641. title: '加载中'
  642. });
  643. uni.request({
  644. url: this.$config.pintuanUrl + 'getProductInfo',
  645. header: {
  646. 'Accept': 'application/json',
  647. 'Content-Type': 'application/json',
  648. },
  649. method: 'POST',
  650. data: {
  651. id: this.product.default_spes_desc[index][key].product_id,
  652. discount_amount: this.groupInfo.discount_amount
  653. },
  654. success: (res) => {
  655. uni.hideLoading();
  656. if (res.data.status) {
  657. // 切换规格判断可购买数量
  658. this.buyNum = res.data.data.stock > this.minBuyNum ? this.minBuyNum : res.data.data.stock;
  659. this.product = this.spesClassHandle(res.data.data);
  660. }
  661. },
  662. fail: (error) => {
  663. uni.hideLoading();
  664. if (error && error.response) {
  665. this.$common.showError(error.response);
  666. }
  667. },
  668. });
  669. setTimeout(function() {
  670. uni.hideLoading();
  671. }, 1000);
  672. }
  673. },
  674. // 多规格样式统一处理
  675. spesClassHandle(products) {
  676. // 判断是否是多规格 (是否有默认规格)
  677. if (products.hasOwnProperty('default_spes_desc')) {
  678. let spes = products.default_spes_desc;
  679. for (let key in spes) {
  680. for (let i in spes[key]) {
  681. if (spes[key][i].hasOwnProperty('is_default') && spes[key][i].is_default === true) {
  682. this.$set(spes[key][i], 'cla', 'pop-m-item selected');
  683. } else if (spes[key][i].hasOwnProperty('product_id') && spes[key][i].product_id) {
  684. this.$set(spes[key][i], 'cla', 'pop-m-item not-selected');
  685. } else {
  686. this.$set(spes[key][i], 'cla', 'pop-m-item none');
  687. }
  688. }
  689. }
  690. products.default_spes_desc = spes;
  691. }
  692. return products;
  693. },
  694. // 购买数量加减操作
  695. bindChange(val) {
  696. this.buyNum = val;
  697. },
  698. // 商品收藏/取消
  699. collection() {
  700. let data = {
  701. goods_id: this.goodsId
  702. }
  703. this.$api.goodsCollection(data, res => {
  704. if (res.status) {
  705. this.isfav = !this.isfav;
  706. this.$common.successToShow(res.msg);
  707. } else {
  708. this.$common.errorToShow(res.msg);
  709. }
  710. })
  711. },
  712. // tab点击切换
  713. onClickItem(index) {
  714. if (this.current !== index) {
  715. this.current = index;
  716. }
  717. },
  718. // 获取商品参数信息
  719. getGoodsParams() {
  720. this.$api.goodsParams({
  721. id: this.goodsId
  722. }, res => {
  723. if (res.status == true) {
  724. this.goodsParams = res.data;
  725. }
  726. })
  727. },
  728. // 获取商品评论信息
  729. getGoodsComments() {
  730. let data = {
  731. page: this.goodsComments.page,
  732. limit: this.goodsComments.limit,
  733. goods_id: this.goodsId
  734. }
  735. this.goodsComments.loadStatus = 'loading';
  736. this.$api.goodsComment(data, res => {
  737. if (res.status == true) {
  738. let _list = res.data.list;
  739. // 如果评论没有图片 在这块作处理否则控制台报错
  740. _list.forEach(item => {
  741. item.ctime = this.$common.timeToDate(item.ctime)
  742. if (!item.hasOwnProperty('images_url')) {
  743. this.$set(item, 'images_url', [])
  744. }
  745. });
  746. this.goodsComments.list = [...this.goodsComments.list, ..._list];
  747. // 根据count数量判断是否还有数据
  748. if (res.data.count > this.goodsComments.list.length) {
  749. this.goodsComments.loadStatus = 'more';
  750. this.goodsComments.page++;
  751. } else {
  752. this.goodsComments.loadStatus = 'noMore';
  753. }
  754. } else {
  755. this.$common.errorToShow(res.msg);
  756. }
  757. })
  758. },
  759. // 添加商品浏览足迹
  760. goodsBrowsing() {
  761. let data = {
  762. goods_id: this.goodsInfo.id
  763. }
  764. this.$api.addGoodsBrowsing(data, res => {});
  765. },
  766. // 立即购买
  767. buyNow(card_type) {
  768. if (this.buyNum > 0) {
  769. let data = {
  770. product_id: this.product.id,
  771. nums: this.buyNum,
  772. type: 2, // 区分加入购物车和购买,
  773. }
  774. if (card_type == 2) {
  775. data['cart_type'] = 2;
  776. }
  777. this.$api.addCart(data, res => {
  778. if (res.status) {
  779. this.toclose();
  780. let cartIds = res.data;
  781. if (card_type == 1) {
  782. this.$common.navigateTo('/pages/goods/place-order/index?cart_ids=' + JSON.stringify(cartIds));
  783. } else {
  784. if (this.invite != 0) {
  785. this.$common.navigateTo('/pages/goods/place-order/index?cart_ids=' + JSON.stringify(cartIds) +
  786. '&cart_type=2&team_id=' + this.invite);
  787. } else {
  788. this.$common.navigateTo('/pages/goods/place-order/index?cart_ids=' + JSON.stringify(cartIds) +
  789. '&cart_type=2');
  790. }
  791. }
  792. }
  793. })
  794. }
  795. },
  796. // 立即购买
  797. buyNow1(card_type) {
  798. if (this.buyNum > 0) {
  799. let data = {
  800. product_id: this.product.id,
  801. nums: this.buyNum,
  802. type: 2, // 区分加入购物车和购买,
  803. }
  804. if (card_type == 2) {
  805. data['cart_type'] = 2;
  806. }
  807. this.$api.addCart(data, res => {
  808. if (res.status) {
  809. this.toclose();
  810. let cartIds = res.data;
  811. if (this.team_id != 0) {
  812. this.$common.navigateTo('/pages/goods/place-order/index?cart_ids=' + JSON.stringify(cartIds) +
  813. '&cart_type=2&team_id=' + this.team_id);
  814. } else {
  815. this.$common.navigateTo('/pages/goods/place-order/index?cart_ids=' + JSON.stringify(cartIds) + '&cart_type=2');
  816. }
  817. }
  818. })
  819. }
  820. },
  821. trigger(e) {
  822. this.content[e.index].active = !e.item.active;
  823. uni.switchTab({
  824. url: e.item.url
  825. })
  826. },
  827. // 跳转到h5分享页面
  828. goShare() {
  829. this.$refs.share.show();
  830. },
  831. closeShare() {
  832. this.$refs.share.close();
  833. },
  834. // 图片点击放大
  835. clickImg(imgs) {
  836. // 预览图片
  837. uni.previewImage({
  838. urls: imgs.split()
  839. });
  840. },
  841. getMyShareCode() {
  842. let userToken = this.$db.get("userToken");
  843. if (userToken && userToken != '') {
  844. // 获取我的分享码
  845. this.$api.shareCode({}, res => {
  846. if (res.status) {
  847. this.myShareCode = res.data ? res.data : '';
  848. }
  849. });
  850. }
  851. }
  852. },
  853. //分享
  854. onShareAppMessage() {
  855. let myInviteCode = this.myShareCode ? this.myShareCode : '';
  856. let ins = encodeURIComponent('type=5&id=' + this.goodsId + '&group_id=' + this.groupId + '&invite=' + myInviteCode);
  857. let path = '/pages/share/jump?scene=' + ins;
  858. return {
  859. title: this.goodsInfo.name,
  860. // #ifdef MP-ALIPAY
  861. desc: this.goodsInfo.brief,
  862. // #endif
  863. imageUrl: this.goodsInfo.album[0],
  864. path: path
  865. }
  866. }
  867. }
  868. </script>
  869. <style>
  870. .swiper {
  871. height: 750upx;
  872. }
  873. .goods-top {
  874. border-bottom: 0;
  875. }
  876. .goods-top .goods-price {
  877. font-size: 38upx;
  878. }
  879. .cost-price {
  880. font-size: 28upx !important;
  881. bottom: -10upx;
  882. color: #999;
  883. text-decoration: line-through;
  884. }
  885. .goods-top .cell-item-ft {
  886. font-size: 20upx;
  887. color: #666;
  888. }
  889. .goods-details {
  890. padding-top: 16upx;
  891. }
  892. .goods-details .cell-hd-title {
  893. width: 620upx;
  894. color: #333;
  895. font-size: 26upx;
  896. display: -webkit-box;
  897. -webkit-box-orient: vertical;
  898. -webkit-line-clamp: 2;
  899. overflow: hidden;
  900. }
  901. .goods-details .cell-item-ft {
  902. top: 40%;
  903. }
  904. .goods-title-item .cell-item-hd {
  905. min-width: 60upx;
  906. color: #666;
  907. font-size: 24upx;
  908. }
  909. .goods-title-item .cell-item-bd {
  910. color: #333;
  911. font-size: 24upx;
  912. }
  913. .goods-title-item .cell-bd-text {
  914. bottom: 0;
  915. }
  916. .cell-bd-view {
  917. position: relative;
  918. overflow: hidden;
  919. }
  920. .cell-bd-view:first-child {
  921. margin-bottom: 8upx;
  922. }
  923. .goods-title-item-ic {
  924. width: 22upx;
  925. height: 22upx;
  926. position: absolute;
  927. top: 50%;
  928. transform: translateY(-50%);
  929. /* #ifdef MP-ALIPAY */
  930. background-size: 100% 100%;
  931. /* #endif */
  932. }
  933. .cell-bd-view .cell-bd-text {
  934. margin-left: 30upx;
  935. }
  936. .goods-content {
  937. margin-top: 26upx;
  938. background-color: #fff;
  939. padding: 26upx 0;
  940. }
  941. .goods-content-c {}
  942. .goods-parameter {
  943. padding: 10upx 26upx;
  944. }
  945. .goods-bottom,
  946. .pop-b {
  947. background-color: #fff;
  948. position: fixed;
  949. bottom: 0;
  950. height: 90upx;
  951. width: 100%;
  952. overflow: hidden;
  953. display: flex;
  954. box-shadow: 0 0 20upx #ccc;
  955. }
  956. .pop-b button {
  957. flex: 1;
  958. }
  959. .goods-bottom button {
  960. height: 100%;
  961. width: 35%;
  962. }
  963. .goods-bottom-ic {
  964. display: inline-block;
  965. position: relative;
  966. text-align: center;
  967. height: 100%;
  968. width: 15%;
  969. float: left;
  970. font-size: 22upx;
  971. color: #666;
  972. }
  973. .goods-bottom-ic .icon {
  974. position: relative;
  975. top: 6upx;
  976. /* left: -6upx; */
  977. /* #ifdef MP-ALIPAY */
  978. background-size: 100% 100%;
  979. /* #endif */
  980. }
  981. .goods-bottom .btn-g {
  982. color: #333;
  983. background-color: #D9D9D9;
  984. }
  985. .goods-parameter .cell-item {
  986. border-bottom: none;
  987. margin-left: 0;
  988. }
  989. .goods-parameter .cell-item-hd {
  990. color: #333;
  991. font-size: 24upx;
  992. }
  993. .goods-parameter .cell-item-bd {
  994. color: #999;
  995. }
  996. .goods-parameter .cell-item-bd .cell-bd-text {
  997. bottom: 0;
  998. }
  999. .goods-parameter .cell-bd-text {
  1000. margin-left: 0;
  1001. }
  1002. .pop-t {
  1003. position: relative;
  1004. padding: 30upx 26upx;
  1005. border-bottom: 2upx solid #f3f3f3;
  1006. /* box-shadow: 0 0 20upx #ccc; */
  1007. }
  1008. .goods-img {
  1009. width: 160upx;
  1010. height: 160upx;
  1011. position: absolute;
  1012. top: -20upx;
  1013. background-color: #fff;
  1014. border-radius: 6upx;
  1015. border: 2upx solid #fff;
  1016. }
  1017. .goods-img image {
  1018. height: 100%;
  1019. width: 100%;
  1020. }
  1021. .goods-information {
  1022. width: 420upx;
  1023. display: inline-block;
  1024. margin-left: 180upx;
  1025. }
  1026. .pop-goods-name {
  1027. width: 100%;
  1028. overflow: hidden;
  1029. white-space: nowrap;
  1030. text-overflow: ellipsis;
  1031. display: block;
  1032. font-size: 24upx;
  1033. margin-bottom: 20upx;
  1034. }
  1035. .pop-goods-price {
  1036. font-size: 30upx;
  1037. }
  1038. .close-btn {
  1039. width: 40upx;
  1040. height: 40upx;
  1041. border-radius: 50%;
  1042. display: inline-block;
  1043. position: absolute;
  1044. right: 30upx;
  1045. }
  1046. .close-btn image {
  1047. width: 100%;
  1048. height: 100%;
  1049. }
  1050. .pop-m {
  1051. font-size: 28upx;
  1052. margin-bottom: 90upx;
  1053. }
  1054. .goods-specs,
  1055. .goods-number {
  1056. padding: 26upx;
  1057. border-top: 1px solid #f3f3f3;
  1058. }
  1059. .goods-specs:first-child {
  1060. border: none;
  1061. }
  1062. .pop-m-title {
  1063. margin-right: 10upx;
  1064. color: #666;
  1065. }
  1066. .pop-m-bd {
  1067. overflow: hidden;
  1068. margin-top: 10upx;
  1069. }
  1070. .pop-m-item {
  1071. display: inline-block;
  1072. float: left;
  1073. padding: 6upx 16upx;
  1074. background-color: #fff;
  1075. color: #333;
  1076. margin-right: 16upx;
  1077. margin-bottom: 10upx;
  1078. }
  1079. .selected {
  1080. border: 2upx solid #333;
  1081. background-color: #333;
  1082. color: #fff;
  1083. }
  1084. .not-selected {
  1085. border: 2upx solid #ccc;
  1086. }
  1087. .none {
  1088. border: 2upx dashed #ccc;
  1089. color: #888;
  1090. }
  1091. .pop-m-bd-in {
  1092. display: inline-block;
  1093. }
  1094. .badge {
  1095. top: 2upx;
  1096. left: 62upx;
  1097. }
  1098. .goods-assess .user-head-img {
  1099. width: 80upx;
  1100. height: 80upx;
  1101. border-radius: 50%;
  1102. }
  1103. .goods-assess .cell-item-bd {
  1104. padding-right: 0;
  1105. }
  1106. .goods-assess .cell-bd-text {
  1107. margin: 0;
  1108. }
  1109. .goods-assess .cell-bd-text.color-9 {
  1110. overflow: hidden;
  1111. text-overflow: ellipsis;
  1112. white-space: nowrap;
  1113. max-width: 440upx;
  1114. }
  1115. .gai-body {}
  1116. .gai-body-text {
  1117. font-size: 26upx;
  1118. color: #333;
  1119. padding: 0 26upx;
  1120. }
  1121. .gai-body-img {
  1122. overflow: hidden;
  1123. padding: 20upx 26upx;
  1124. }
  1125. .gai-body-img image {
  1126. width: 220upx;
  1127. height: 220upx;
  1128. float: left;
  1129. margin-right: 19upx;
  1130. margin-bottom: 18upx;
  1131. }
  1132. .gai-body-img image:nth-child(3n) {
  1133. margin-right: 0;
  1134. }
  1135. .redstar {
  1136. width: 24rpx;
  1137. height: 24rpx;
  1138. padding: 2rpx;
  1139. }
  1140. .mask-share-wechat {
  1141. display: inline-block;
  1142. background-color: #fff;
  1143. padding: 0;
  1144. }
  1145. .mask-share-wechat:after {
  1146. border: none;
  1147. }
  1148. .right-ball {
  1149. position: fixed;
  1150. right: 30upx;
  1151. bottom: 300upx;
  1152. z-index: 999;
  1153. text-align: center;
  1154. padding: 14upx 0;
  1155. /* line-height: 80upx; */
  1156. width: 80upx;
  1157. height: 80upx;
  1158. font-size: 24upx;
  1159. color: #fff;
  1160. background-color: rgba(0, 0, 0, .5);
  1161. border-radius: 50%;
  1162. }
  1163. .share-pop {
  1164. height: 300upx;
  1165. width: 100%;
  1166. display: flex;
  1167. }
  1168. .share-item {
  1169. flex: 1;
  1170. text-align: center;
  1171. font-size: 26upx;
  1172. color: #333;
  1173. padding: 20upx 0;
  1174. }
  1175. .share-item image {
  1176. width: 120upx;
  1177. height: 120upx;
  1178. }
  1179. .share-item .btn {
  1180. line-height: 1;
  1181. display: block;
  1182. font-size: 26upx;
  1183. background-color: #fff;
  1184. }
  1185. .comment-none {
  1186. text-align: center;
  1187. padding: 200upx 0;
  1188. }
  1189. .comment-none-img {
  1190. width: 274upx;
  1191. height: 274upx;
  1192. }
  1193. .price-salesvolume {
  1194. width: 100%;
  1195. padding: 0 0 0 26upx;
  1196. overflow: hidden;
  1197. color: #A5A5A5;
  1198. background-color: rgb(252, 226, 80);
  1199. position: relative;
  1200. }
  1201. .commodity-price {
  1202. width: 224upx;
  1203. display: inline-block;
  1204. float: left;
  1205. }
  1206. .current-price {
  1207. font-size: 40upx;
  1208. color: #FF7159;
  1209. display: block;
  1210. line-height: 1.5;
  1211. }
  1212. .cost-price {
  1213. font-size: 26upx;
  1214. text-decoration: line-through;
  1215. /* margin-left: 8rpx; */
  1216. display: block;
  1217. }
  1218. .commodity-salesvolume {
  1219. width: 240upx;
  1220. display: inline-block;
  1221. font-size: 22upx;
  1222. float: left;
  1223. padding: 16upx 0;
  1224. }
  1225. .commodity-salesvolume>text {
  1226. display: block;
  1227. }
  1228. .commodity-time-img {
  1229. display: block;
  1230. width: 0;
  1231. height: 0;
  1232. border-width: 56upx 28upx 56upx 0;
  1233. border-style: solid;
  1234. border-color: transparent #FF7159 transparent transparent;
  1235. /*透明 黄 透明 透明 */
  1236. position: absolute;
  1237. top: 0px;
  1238. left: 462upx;
  1239. }
  1240. .commodity-time {
  1241. display: inline-block;
  1242. width: 260upx;
  1243. text-align: center;
  1244. font-size: 24upx;
  1245. background-color: #FF7159;
  1246. padding: 16upx 0 18upx;
  1247. color: #FF7159;
  1248. }
  1249. .commodity-time>text {
  1250. color: rgb(252, 226, 80);
  1251. }
  1252. .commodity-day>text {
  1253. display: inline-block;
  1254. background-color: rgb(255, 212, 176);
  1255. color: rgb(255, 115, 0);
  1256. padding: 0 6upx;
  1257. border-radius: 6upx;
  1258. }
  1259. .tl {
  1260. width: 70% !important;
  1261. }
  1262. .group-swiper {
  1263. /* padding: 20upx 26upx; */
  1264. }
  1265. .group-swiper-c {
  1266. height: 242upx;
  1267. }
  1268. .group-swiper-c .swiper-item .cell-item {
  1269. height: 50%;
  1270. }
  1271. .group-swiper-c .swiper-item .cell-item .user-head-img {
  1272. width: 80upx;
  1273. height: 80upx;
  1274. border-radius: 50%;
  1275. }
  1276. .group-swiper-c .swiper-item .cell-item .cell-hd-title {
  1277. position: absolute;
  1278. top: 50%;
  1279. left: 100upx;
  1280. transform: translateY(-50%);
  1281. max-width: 260upx;
  1282. width: 100%;
  1283. overflow: hidden;
  1284. text-overflow: ellipsis;
  1285. white-space: nowrap;
  1286. }
  1287. .group-swiper-c .swiper-item .cell-item .cell-item-bd {
  1288. min-width: 150upx;
  1289. max-width: 150upx
  1290. }
  1291. .group-swiper-c .swiper-item .cell-item .cell-item-ft .btn {
  1292. font-size: 26upx;
  1293. color: #fff;
  1294. background-color: #FF7159;
  1295. /* padding: 0; */
  1296. text-align: center;
  1297. }
  1298. .price-salesvolume .commodity-day .uni-countdown__splitor {
  1299. color: rgb(252, 226, 80);
  1300. }
  1301. .group-swiper .commodity-day .uni-countdown__splitor {
  1302. color: #666;
  1303. }
  1304. @import url('@/components/u-parse/u-parse.css')
  1305. </style>
payment
auth.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="content-c">
  4. <image class="load-img" src="/static/image/loading.gif" mode=""></image>
  5. <view class="load-text color-9">信息加载中.....</view>
  6. </view>
  7. </view>
  8. </template>
  9. <script>
  10. export default {
  11. data() {
  12. return {
  13. type: '',
  14. openid: '',
  15. orderId: '',
  16. state: ''
  17. }
  18. },
  19. onLoad(options) {
  20. this.orderId = options.order_id
  21. this.money = Number(options.money)
  22. this.type = Number(options.type)
  23. this.uid = Number(options.uid)
  24. this.state = this.$common.getQueryString('state')
  25. this.getCode()
  26. },
  27. methods: {
  28. getCode() {
  29. var code = this.$common.getQueryString('code')
  30. code && this.getOpenId(code)
  31. },
  32. getOpenId(code) {
  33. let data = {
  34. code: code,
  35. scope: 2,
  36. state: this.state
  37. }
  38. //模拟接口
  39. this.$api.getOpenId(data, res => {
  40. if (res.status) {
  41. this.openid = res.data.openid
  42. this.toPayHandler('wechatpay')
  43. } else {
  44. this.$common.errorToShow(res.msg)
  45. }
  46. })
  47. },
  48. checkWXJSBridge(data) {
  49. let that = this
  50. let interval = setInterval(() => {
  51. if (typeof window.WeixinJSBridge != 'undefined') {
  52. clearTimeout(interval)
  53. that.onBridgeReady(data)
  54. }
  55. }, 200)
  56. },
  57. onBridgeReady(data) {
  58. var _this = this
  59. window.WeixinJSBridge.invoke(
  60. 'getBrandWCPayRequest',
  61. {
  62. appId: data.appid, // 公众号名称,由商户传入
  63. timeStamp: data.timeStamp, // 时间戳,自1970年以来的秒数
  64. nonceStr: data.nonceStr, // 随机串
  65. package: data.package,
  66. signType: data.signType, // 微信签名方式:
  67. paySign: data.paySign // 微信签名
  68. },
  69. function(res) {
  70. if (res.err_msg === 'get_brand_wcpay_request:ok') {
  71. _this.$common.successToShow('支付成功')
  72. } else if (res.err_msg === 'get_brand_wcpay_request:cancel') {
  73. _this.$common.errorToShow('取消支付')
  74. } else {
  75. _this.$common.errorToShow('支付失败')
  76. }
  77. setTimeout(() => {
  78. _this.$common.redirectTo(
  79. '/pages/goods/payment/result?id=' + data.payment_id
  80. )
  81. },1000)
  82. }
  83. )
  84. },
  85. toPayHandler(code) {
  86. let data = {
  87. payment_code: code,
  88. payment_type: this.type
  89. }
  90. data['ids'] = (this.type == 1 || this.type == 5 || this.type == 6) ? this.orderId : this.uid
  91. //data['ids'] = this.type == 1 ? this.orderId : this.uid
  92. if (this.type == 1 && this.orderId) {
  93. // 微信jsapi支付
  94. if (this.openid) {
  95. data['params'] = {
  96. trade_type: 'JSAPI_OFFICIAL',
  97. openid: this.openid
  98. }
  99. }
  100. } else if (this.type == 2 && this.money) {
  101. if (this.openid) {
  102. data['params'] = {
  103. trade_type: 'JSAPI_OFFICIAL',
  104. money: this.money,
  105. openid: this.openid
  106. }
  107. }
  108. }else if ((this.type == 5 || this.type == 6) && this.recharge) {
  109. data['params'] = {
  110. trade_type: 'JSAPI_OFFICIAL',
  111. openid: this.openid,
  112. formid: this.orderId
  113. }
  114. }
  115. this.$api.pay(data, res => {
  116. if (res.status) {
  117. const data = res.data
  118. this.checkWXJSBridge(data)
  119. } else {
  120. this.$common.errorToShow(res.msg)
  121. }
  122. })
  123. }
  124. }
  125. }
  126. </script>
  127. <style>
  128. .content {
  129. position: relative;
  130. height: 80vh;
  131. }
  132. .content-c {
  133. position: absolute;
  134. top: 50%;
  135. left: 50%;
  136. transform: translate(-50%, -50%);
  137. text-align: center;
  138. }
  139. .load-img {
  140. width: 100upx;
  141. height: 100upx;
  142. }
  143. .load-text {
  144. font-size: 26upx;
  145. }
  146. </style>
index.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class='cell-group margin-cell-group'>
  4. <view class='cell-item'>
  5. <view class='cell-item-hd'>
  6. <view class='cell-hd-title'>订单类型</view>
  7. </view>
  8. <view class='cell-item-ft'>
  9. <text class="cell-ft-p" v-if="type == 1" @click="orderDetail(orderId)">商品订单</text>
  10. <text class="cell-ft-p" v-if="type == 2" @click="toRecharge()">充值订单</text>
  11. <text class="cell-ft-p" v-if="type == 5" >快捷下单</text>
  12. <text class="cell-ft-p" v-if="type == 6" >付款码</text>
  13. </view>
  14. </view>
  15. <view v-if="type == 1">
  16. <view class='cell-item'>
  17. <view class='cell-item-hd'>
  18. <view class='cell-hd-title'>订单编号</view>
  19. </view>
  20. <view class='cell-item-ft'>
  21. <text class="cell-ft-p" @click="orderDetail(orderId)">{{ orderId }}</text>
  22. </view>
  23. </view>
  24. <view class='cell-item'>
  25. <view class='cell-item-hd'>
  26. <view class='cell-hd-title'>订单金额</view>
  27. </view>
  28. <view class='cell-item-ft'>
  29. <text class="cell-ft-p red-price">¥{{ orderInfo.order_amount }}</text>
  30. </view>
  31. </view>
  32. </view>
  33. <view v-else-if="type == 2">
  34. <view class='cell-item'>
  35. <view class='cell-item-hd'>
  36. <view class='cell-hd-title'>充值金额</view>
  37. </view>
  38. <view class='cell-item-ft'>
  39. <text class="cell-ft-p red-price">¥ {{ recharge }}</text>
  40. </view>
  41. </view>
  42. </view>
  43. </view>
  44. <!-- #ifdef H5 -->
  45. <payments-by-h5
  46. :orderId="orderId"
  47. :recharge="recharge"
  48. :type="type"
  49. :uid="userInfo.id"
  50. ></payments-by-h5>
  51. <!-- #endif -->
  52. <!-- #ifdef MP-WEIXIN -->
  53. <payments-by-wx
  54. :orderId="orderId"
  55. :recharge="recharge"
  56. :type="type"
  57. :uid="userInfo.id"
  58. ></payments-by-wx>
  59. <!-- #endif -->
  60. <!-- #ifdef MP-ALIPAY -->
  61. <payments-by-ali
  62. :orderId="orderId"
  63. :recharge="recharge"
  64. :type="type"
  65. :uid="userInfo.id"
  66. ></payments-by-ali>
  67. <!-- #endif -->
  68. <!-- #ifdef APP-PLUS||APP-PLUS-NVUE -->
  69. <payments-by-app
  70. :orderId="orderId"
  71. :recharge="recharge"
  72. :type="type"
  73. :uid="userInfo.id"
  74. ></payments-by-app>
  75. <!-- #endif -->
  76. </view>
  77. </template>
  78. <script>
  79. // #ifdef H5
  80. import paymentsByH5 from '@/components/payments/paymentsByH5.vue'
  81. // #endif
  82. // #ifdef MP-WEIXIN
  83. import paymentsByWx from '@/components/payments/paymentsByWx.vue'
  84. // #endif
  85. // #ifdef MP-ALIPAY
  86. import paymentsByAli from '@/components/payments/paymentsByAli.vue'
  87. // #endif
  88. // #ifdef APP-PLUS||APP-PLUS-NVUE
  89. import paymentsByApp from '@/components/payments/paymentsByApp.vue'
  90. // #endif
  91. import { orders } from '@/config/mixins.js'
  92. export default {
  93. mixins: [orders],
  94. data () {
  95. return {
  96. orderId: 0,
  97. recharge: 0,
  98. type: 1, // 订单类型 1商品订单 2充值订单
  99. orderInfo: {}, // 订单详情
  100. userInfo: {}, // 用户信息
  101. form_id:0
  102. }
  103. },
  104. components: {
  105. // #ifdef H5
  106. paymentsByH5,
  107. // #endif
  108. // #ifdef MP-WEIXIN
  109. paymentsByWx,
  110. // #endif
  111. // #ifdef MP-ALIPAY
  112. paymentsByAli,
  113. // #endif
  114. // #ifdef APP-PLUS||APP-PLUS-NVUE
  115. paymentsByApp,
  116. // #endif
  117. },
  118. onLoad (options) {
  119. this.orderId = options.order_id
  120. this.recharge = Number(options.recharge)
  121. this.type = Number(options.type)
  122. this.form_id = Number(options.form_id)
  123. if (this.orderId && this.type == 1) {
  124. // 商品订单
  125. this.getOrderInfo()
  126. } else if (this.recharge && this.type == 2) {
  127. // 充值订单 获取用户id
  128. this.getUserInfo()
  129. } else if (this.form_id && (this.type == 5 || this.type == 6)) {
  130. // 表单订单 id传到订单上
  131. this.orderId = ''+this.form_id;
  132. } else {
  133. this.$common.errorToShow('订单支付参数错误', () => {
  134. uni.navigateBack({
  135. delta: 1
  136. })
  137. })
  138. }
  139. },
  140. methods: {
  141. // 获取订单详情
  142. getOrderInfo () {
  143. let data = {
  144. order_id: this.orderId
  145. }
  146. this.$api.orderDetail(data, res => {
  147. if (res.status) {
  148. this.orderInfo = res.data
  149. if(this.orderInfo.pay_status == 2){
  150. this.$common.redirectTo(
  151. '/pages/goods/payment/result?order_id=' + this.orderInfo.order_id
  152. )
  153. }
  154. }
  155. })
  156. },
  157. // 获取用户信息
  158. getUserInfo () {
  159. this.$api.userInfo({}, res => {
  160. if (res.status) {
  161. this.userInfo = res.data
  162. } else {
  163. this.$common.errorToShow(res.msg)
  164. }
  165. })
  166. },
  167. // 跳转我的余额页面
  168. toRecharge () {
  169. this.$common.navigateTo('/pages/member/balance/index')
  170. }
  171. }
  172. }
  173. </script>
  174. <style>
  175. .margin-cell-group{
  176. margin-bottom: 20upx;
  177. }
  178. .cell-hd-title{
  179. color: #999;
  180. }
  181. .payment-method .cell-item-hd{
  182. min-width: 70upx;
  183. }
  184. .payment-method .cell-hd-icon{
  185. width: 70upx;
  186. height: 70upx;
  187. }
  188. .payment-method .cell-item-bd{
  189. border-left: 2upx solid #F0F0F0;
  190. padding-left: 30upx;
  191. }
  192. .payment-method .cell-bd-text{
  193. font-size: 28upx;
  194. color: #666;
  195. }
  196. .payment-method .address{
  197. font-size: 24upx;
  198. color: #999;
  199. }
  200. </style>
result.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="result succsee" v-if="status && paymentInfo.status === 2">
  4. <image class="result-img" src="/static/image/win.png" mode=""></image>
  5. <view class="result-top">
  6. 支付成功
  7. </view>
  8. <view class="result-mid red-price">
  9. {{ paymentInfo.money }}
  10. </view>
  11. <view class="result-bot">
  12. <button class="btn btn-g" @click="orderDetail()">查看详情</button>
  13. </view>
  14. </view>
  15. <view class="result fail" v-else-if="status && paymentInfo.status === 1">
  16. <image class="result-img" src="/static/image/pastdue.png" mode=""></image>
  17. <view class="result-top">
  18. 支付失败
  19. </view>
  20. <view class="result-mid red-price">
  21. {{ paymentInfo.money }}
  22. </view>
  23. <view class="result-bot">
  24. <button class="btn btn-g" @click="orderDetail()">查看详情</button>
  25. </view>
  26. </view>
  27. </view>
  28. </template>
  29. <script>
  30. export default {
  31. data() {
  32. return {
  33. paymentId: 0,
  34. paymentInfo: {}, // 支付单详情
  35. orderId: 0,
  36. status: false
  37. }
  38. },
  39. onLoad(options) {
  40. if (options.id) {
  41. this.paymentId = options.id
  42. }
  43. if (options.order_id) {
  44. this.orderId = options.order_id
  45. }
  46. },
  47. mounted() {
  48. this.getPaymentInfo()
  49. },
  50. methods: {
  51. getPaymentInfo() {
  52. if (!this.paymentId) {
  53. this.status = true;
  54. this.paymentInfo.money = '0.00'
  55. this.paymentInfo.status = 2;
  56. this.paymentInfo.type = 1;
  57. return
  58. }
  59. let data = {
  60. payment_id: this.paymentId
  61. }
  62. this.$api.paymentInfo(data, res => {
  63. if (res.status) {
  64. let info = res.data
  65. if (info.payment_code === 'alipay') {
  66. info.payment_name = '支付宝支付'
  67. } else if (info.payment_code === 'wechatpay') {
  68. info.payment_name = '微信支付'
  69. } else if (info.payment_code === 'balancepay') {
  70. info.payment_name = '余额支付'
  71. }
  72. // 获取订单号
  73. if (info.rel.length) {
  74. for (let i = 0; i < info.rel.length; i++) {
  75. if (info.rel[i].source_id) {
  76. this.orderId = info.rel[i].source_id
  77. break;
  78. }
  79. }
  80. }
  81. this.status = true;
  82. this.paymentInfo = info
  83. } else {
  84. this.$common.errorToShow(res.msg)
  85. }
  86. })
  87. },
  88. orderDetail() {
  89. if (this.orderId && this.paymentInfo.type === 1) {
  90. this.$common.redirectTo('/pages/member/order/orderdetail?order_id=' + this.orderId)
  91. } else if (this.paymentInfo.type === 2) {
  92. this.$common.redirectTo('/pages/member/balance/details')
  93. } else if (this.paymentInfo.type === 5 || this.paymentInfo.type === 6) {
  94. uni.switchTab({
  95. url: '/pages/index/index'
  96. });
  97. }
  98. }
  99. }
  100. }
  101. </script>
  102. <style>
  103. .result {
  104. text-align: center;
  105. padding-top: 200upx;
  106. }
  107. .result-img {
  108. width: 140upx;
  109. height: 140upx;
  110. margin-bottom: 20upx;
  111. }
  112. .result-num {
  113. color: #666;
  114. font-size: 30upx;
  115. margin-bottom: 20upx;
  116. }
  117. .result-top {
  118. color: #666;
  119. font-size: 30upx;
  120. margin-bottom: 20upx;
  121. }
  122. .result-mid {
  123. margin-bottom: 60upx;
  124. }
  125. .result-bot .btn {
  126. margin-top: 40upx;
  127. font-size: 26upx;
  128. padding: 0 50upx;
  129. }
  130. </style>
place-order
index.vue
复制代码
  1. <template>
  2. <form class="content" @submit="toPay" report-submit="true">
  3. <view class="content-top">
  4. <uni-segmented-control :current="type_current" :values="type_items" @clickItem="onTypeItem" style-type="text" active-color="#333" v-if="storeSwitch == 1"></uni-segmented-control>
  5. <view class="content">
  6. <view v-show="type_current === 0">
  7. <!-- 收货地址信息 -->
  8. <view class='cell-group margin-cell-group' v-if="userShip.id" @click="showAddressList">
  9. <view class='cell-item add-title-item right-img'>
  10. <view class='cell-item-hd'>
  11. <image class='cell-hd-icon' src='/static/image/location.png'></image>
  12. </view>
  13. <view class='cell-item-bd'>
  14. <view class="cell-bd-view">
  15. <text class="cell-bd-text">收货人:{{ userShip.name }}</text>
  16. <text class="cell-bd-text-right">{{ userShip.mobile }}</text>
  17. </view>
  18. <view class="cell-bd-view">
  19. <text class="cell-bd-text address">{{ userShip.area_name }}</text>
  20. </view>
  21. </view>
  22. <view class='cell-item-ft'>
  23. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  24. </view>
  25. </view>
  26. </view>
  27. <view class="cell-group margin-cell-group" v-else>
  28. <view class='cell-item add-title-items'>
  29. <button class="btn btn-b" @click="goAddress()" hover-class="btn-hover2">添加收货地址</button>
  30. </view>
  31. </view>
  32. </view>
  33. <view v-show="type_current === 1">
  34. <!-- 门店信息 -->
  35. <view v-if="store.id != 0" class='cell-group margin-cell-group' @click="goStorelist()">
  36. <view class='cell-item add-title-item right-img'>
  37. <view class='cell-item-hd'>
  38. <image class='cell-hd-icon' src='/static/image/homepage.png'></image>
  39. </view>
  40. <view class='cell-item-bd'>
  41. <view class="cell-bd-view">
  42. <text class="cell-bd-text">{{store.name}}</text>
  43. <text class="cell-bd-text-right">{{store.mobile}}</text>
  44. </view>
  45. <view class="cell-bd-view">
  46. <text class="cell-bd-text address">{{store.address}}</text>
  47. </view>
  48. </view>
  49. <view class='cell-item-ft'>
  50. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  51. </view>
  52. </view>
  53. </view>
  54. <view v-else class='cell-group margin-cell-group'>
  55. <view class='cell-item add-title-item right-img no-store'>暂无门店</view>
  56. </view>
  57. </view>
  58. </view>
  59. <view class='cell-group margin-cell-group' v-if="storeSwitch == 1 && type_current === 1">
  60. <view class='cell-item user-head'>
  61. <view class='cell-item-hd'>
  62. <view class='cell-hd-title'>姓名</view>
  63. </view>
  64. <view class='cell-item-bd'>
  65. <input class='cell-bd-input' placeholder='请输入提货人姓名' v-model="store_pick.name"></input>
  66. </view>
  67. </view>
  68. <view class='cell-item'>
  69. <view class='cell-item-hd'>
  70. <view class='cell-hd-title'>电话</view>
  71. </view>
  72. <view class='cell-item-bd'>
  73. <input class='cell-bd-input' placeholder='请输入提货人电话' v-model="store_pick.mobile"></input>
  74. </view>
  75. </view>
  76. </view>
  77. <!-- 商品列表信息 -->
  78. <view class='img-list'>
  79. <view class='img-list-item' v-if="item.is_select == true" v-for="(item, index) in products" :key="index">
  80. <image class='img-list-item-l little-img have-none' :src='item.products.image_path' mode='aspectFill'></image>
  81. <view class='img-list-item-r little-right'>
  82. <view class='little-right-t'>
  83. <view class='goods-name list-goods-name' @click="goodsDetail(item.products.goods_id)">{{ item.products.name }}</view>
  84. <view class='goods-price'>¥{{ item.products.price }}</view>
  85. </view>
  86. <view class="romotion-tip" v-if="item.products.promotion_list">
  87. <view class="romotion-tip-item" :class="v.type !== 2 ? 'bg-gray' : ''" v-for="(v, k) in item.products.promotion_list" :key="k">
  88. {{ v.name }}
  89. </view>
  90. </view>
  91. <view class='goods-item-c'>
  92. <view class='goods-buy'>
  93. <view class='goods-salesvolume' v-if="item.products.spes_desc !== null">{{ item.products.spes_desc }}</view>
  94. <view class='goods-num'>× {{ item.nums }}</view>
  95. </view>
  96. </view>
  97. </view>
  98. </view>
  99. </view>
  100. <view class='cell-group'>
  101. <view class='cell-item'>
  102. <view class='cell-item-hd'>
  103. <view class='cell-hd-title'>优惠券</view>
  104. </view>
  105. <view class='cell-item-ft'>
  106. <text class="cell-ft-p" @click="toshow()">{{ usedCouponsCompute }}</text>
  107. </view>
  108. </view>
  109. <!-- 商户开启积分 并且用户有积分情况下 -->
  110. <view class='cell-item add-title-item right-img' v-if="isOpenPoint === 1 && userPointNums > 0">
  111. <view class='cell-item-bd'>
  112. <view class="cell-bd-view">
  113. 积分抵扣
  114. </view>
  115. <view class="cell-bd-view">
  116. <text class="cell-bd-text address color-9">可用 {{ canUsePoint }} 积分,可抵扣 {{ pointMoney }} 元,共有 {{ userPointNums }} 积分。</text>
  117. </view>
  118. </view>
  119. <view class='cell-item-ft' @click="changePointHandle">
  120. <label class="radio">
  121. <radio value="1" :checked="isUsePoint" color="#FF7159"/>
  122. <!-- <radio class="radioNo" disabled="true"/> -->
  123. </label>
  124. </view>
  125. </view>
  126. <view class='cell-item invoice right-img' v-if="invoiceSwitch == 1">
  127. <view class='cell-item-hd'>
  128. <view class='cell-hd-title'>发票</view>
  129. </view>
  130. <view class='cell-item-ft' @click="goInvoice()">
  131. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  132. <text class='cell-ft-text'>{{invoice.name}}</text>
  133. </view>
  134. </view>
  135. <view class='cell-item'>
  136. <view class='cell-item-hd'>
  137. <view class='cell-bd-view'>商品价格</view>
  138. <view class='cell-bd-view' v-if="cartData.goods_pmt_old > 0">商品优惠</view>
  139. <view class='cell-hd-view' v-if="cartData.order_pmt_old > 0">订单优惠</view>
  140. <view class='cell-hd-view' v-if="!couponIsUsed">优惠券抵扣</view>
  141. <view class='cell-hd-view' v-if="cartData.point > 0">积分抵扣</view>
  142. <view class='cell-hd-view'>运费</view>
  143. </view>
  144. <view class='cell-item-ft'>
  145. <view class="cell-ft-view red-price">{{ cartData.goods_amount }}</view>
  146. <view class="cell-ft-view" v-if="cartData.goods_pmt_old > 0">-{{ cartData.goods_pmt }}</view>
  147. <view class="cell-ft-view" v-if="cartData.order_pmt_old > 0">-{{ cartData.order_pmt }}</view>
  148. <view class="cell-ft-view" v-if="!couponIsUsed">-{{ cartData.coupon_pmt }}</view>
  149. <view class="cell-ft-view" v-if="cartData.point > 0">-{{ cartData.point_money }}</view>
  150. <view class="cell-ft-view">{{ cartData.cost_freight }}</view>
  151. </view>
  152. </view>
  153. </view>
  154. <view class='cell-group leave-message'>
  155. <view class='cell-item right-img'>
  156. <view class='cell-item-hd'>
  157. <view class='cell-hd-title'>买家留言</view>
  158. </view>
  159. </view>
  160. <view class="cell-textarea ">
  161. <!-- #ifndef MP-WEIXIN -->
  162. <textarea v-model="memo" placeholder="50字以内(选填)" maxlength="50"/>
  163. <!-- #endif -->
  164. <!-- #ifdef MP-WEIXIN -->
  165. <input v-model="memo" placeholder="50字以内(选填)"/>
  166. <!-- #endif -->
  167. </view>
  168. </view>
  169. </view>
  170. <!-- 优惠券信息 -->
  171. <lvv-popup position="bottom" ref="lvvpopref">
  172. <view style="width: 100%;height: 700upx;background: #F8F8F8;;position: absolute;left:0;bottom: 0;">
  173. <view class="pop-c">
  174. <!-- <view class="pop-t">
  175. <view class='cell-item invoice'>
  176. <view class='cell-item-hd'>
  177. <view class='cell-hd-title'>优惠券</view>
  178. </view>
  179. <view class='cell-item-ft'
  180. @click="toclose()">
  181. <image class='cell-ft-next icon' src='/static/image/close.png'></image>
  182. </view>
  183. </view>
  184. </view> -->
  185. <view class="pop-b">
  186. <view class="pop-b-t">
  187. <uni-segmented-control
  188. :current="current"
  189. :values="items"
  190. @clickItem="onClickItem"
  191. style-type="text"
  192. active-color="#333"
  193. ></uni-segmented-control>
  194. </view>
  195. <view class="" v-show="current === 0">
  196. <scroll-view class="coupon-c" scroll-y="true" style="" v-if="userCoupons.length">
  197. <view class="coupon-c-item" v-for="(item, index) in userCoupons" :key="index">
  198. <view :class="item.cla">
  199. <view class="cci-l-c color-f">
  200. coupon
  201. </view>
  202. </view>
  203. <view class="cci-r">
  204. <!-- <image class="cci-r-img" src="" mode=""></image> -->
  205. <view class="cci-r-c">
  206. <view class="ccirc-t color-9">
  207. {{ item.name }}
  208. </view>
  209. <view class="ccirc-b">
  210. <view class="ccirc-b-l">
  211. <view class="ccirc-b-tip">
  212. {{ item.expression1 + item.expression2 }}
  213. </view>
  214. <view class="ccirc-b-time color-9">
  215. 有效期:{{ item.stime + ' - ' + item.etime }}
  216. </view>
  217. </view>
  218. <view class="ccirc-b-r color-f"
  219. @click="couponHandle(index)"
  220. v-if="!item.checked && !item.disabled"
  221. >
  222. 立即使用
  223. </view>
  224. <view class="ccirc-b-r color-f"
  225. @click="couponHandle(index)"
  226. v-else-if="item.checked && !item.disabled"
  227. >
  228. 取消使用
  229. </view>
  230. <!-- <view class="ccirc-b-r color-f bg-c">
  231. 不可用
  232. </view> -->
  233. </view>
  234. </view>
  235. </view>
  236. </view>
  237. </scroll-view>
  238. <view class="coupon-none" v-else>
  239. <image class="coupon-none-img" src="/static/image/order.png" mode=""></image>
  240. </view>
  241. </view>
  242. <view class="coupon-c" v-show="current === 1">
  243. <view class="coupon-enter">
  244. <view class="coupon-input">
  245. <input type="text" v-model="inputCouponCode" placeholder="请输入优惠券码"/>
  246. </view>
  247. <!-- #ifdef MP-WEIXIN -->
  248. <!-- <view class="coupon-code">
  249. <image src="/static/image/ewm.png" class="icon" mode="" @click="scanCode"></image>
  250. </view> -->
  251. <!-- #endif -->
  252. <view class="coupon-enter-btn"
  253. @click="useInputCouponCode"
  254. >
  255. <button class="btn btn-b">确认</button>
  256. </view>
  257. </view>
  258. </view>
  259. </view>
  260. <view class="button-bottom">
  261. <button class="btn btn-square"
  262. @click="notUseCoupon()"
  263. >不使用优惠卷</button>
  264. <button class="btn btn-square btn-b"
  265. @click="toclose()"
  266. >确定</button>
  267. </view>
  268. </view>
  269. </view>
  270. </lvv-popup>
  271. <view class="button-bottom">
  272. <view class="button-bottom-c">
  273. <view class="button-bottom-c-t">共 {{ productNums }} 件商品</view>
  274. <view class="button-bottom-c-b">合计<text class="red-price"> {{ cartData.amount }}</text></view>
  275. </view>
  276. <button class='btn btn-square btn-b' hover-class="btn-hover2" form-type="submit" :disabled='submitStatus' :loading='submitStatus'>立即支付</button>
  277. </view>
  278. </form>
  279. </template>
  280. <script>
  281. import lvvPopup from '@/components/lvv-popup/lvv-popup.vue'
  282. import uniSegmentedControl from "@/components/uni-segmented-control/uni-segmented-control.vue"
  283. import { goods } from '@/config/mixins.js'
  284. export default {
  285. mixins: [ goods ],
  286. data () {
  287. return {
  288. type_items: ['快递配送','门店自提'],//门店自提切换
  289. type_current: 0,
  290. cartData: {}, // 购物车商品详情
  291. products: [], // 货品信息
  292. promotions: [], // 促销信息
  293. userShip: {}, // 用户收货地址
  294. receiptType: 1, // 订单类型 1是发货订单 2是门店自提订单
  295. params: {
  296. ids: 0, // 传递过来的购物车id
  297. area_id: 0, // 收货地址id
  298. coupon_code: '', // 优惠券码列表(string)多张逗号分隔
  299. point: 0 ,// 抵扣积分额
  300. type :1 ,//购物车类型
  301. }, // 监听params参数信息 以重新请求接口
  302. // 发票信息
  303. invoice: {
  304. type: '1', // 类型 1不开发票 2个人发票 3公司发票
  305. name: '不开发票', // 发票抬头
  306. code: '' // 发票税号
  307. },
  308. memo: '', // 买家留言
  309. items: [
  310. '选择优惠券',
  311. '输入券码',
  312. ],
  313. orderType: 1, // 商品订单类型 1
  314. current: 0,
  315. isUsePoint: false, // 是否勾选使用积分
  316. userPointNums: 0, // 用户的总积分
  317. canUsePoint: 0, // 可以使用的积分
  318. pointMoney: '', // 积分抵扣的金额
  319. userCoupons: [], // 用户的可用优惠券列表
  320. usedCoupons: {}, // 已经选择使用的优惠券
  321. inputCouponCode: '', // 输入的优惠券码
  322. optCoupon: '' ,// 当前选择使用的优惠券(暂存使用 如果接口返回不可用则剔除优惠券状态)
  323. store : {
  324. id: 0,
  325. name: '',
  326. mobile: '',
  327. address: ''
  328. },
  329. store_pick: {
  330. name: '',
  331. mobile: ''
  332. },
  333. team_id: 0, //拼团id
  334. submitStatus: false
  335. }
  336. },
  337. components: {lvvPopup,uniSegmentedControl},
  338. onLoad (options) {
  339. let cartIds = options.cart_ids;
  340. if(options.order_type){
  341. this.params.order_type = options.order_type;
  342. }
  343. if(options.team_id){
  344. this.team_id = options.team_id;
  345. }
  346. this.params.ids = JSON.parse(cartIds)
  347. if (!this.params.ids) {
  348. this.$common.successToShow('获取失败', function(){
  349. uni.navigateBack({
  350. delta: 1
  351. })
  352. })
  353. }
  354. // 获取用户的默认收货地址信息
  355. this.userDefaultShip()
  356. // 获取用户的可用优惠券信息
  357. this.getUserCounpons()
  358. //获取默认门店信息
  359. this.getDefaultStore();
  360. },
  361. methods: {
  362. // 切换门店
  363. onTypeItem(index) {
  364. if (this.type_current !== index) {
  365. this.type_current = index;
  366. }
  367. let receiptType = 1;
  368. if(this.type_current != 0){
  369. receiptType = 2;
  370. }
  371. this.receiptType = receiptType;
  372. this.getCartList();
  373. },
  374. // 跳转到门店列表
  375. goStorelist(){
  376. uni.navigateTo({
  377. url: './storelist'
  378. })
  379. },
  380. // 没有收货地址时跳转
  381. goAddress(){
  382. uni.navigateTo({
  383. url: '/pages/member/address/list?type=order'
  384. })
  385. },
  386. // 获取用户的默认收货地址
  387. userDefaultShip () {
  388. this.$api.userDefaultShip({}, res => {
  389. if (res.status && Object.keys(res.data).length) {
  390. this.userShip = res.data
  391. this.params.area_id = this.userShip.area_id
  392. }
  393. })
  394. },
  395. // 获取购物车商品详情
  396. getCartList () {
  397. let data = this.params
  398. data['receipt_type'] = this.receiptType // 区分订单类型 1快递订单 2门店自提订单
  399. this.$api.cartList(data, res => {
  400. if (res.status) {
  401. let data = res.data
  402. // 判断是否开启积分抵扣 并且 没有勾选积分使用
  403. if (this.isOpenPoint === 1 && !this.isUsePoint) {
  404. let money = {
  405. order_money: data.amount
  406. }
  407. this.$api.usablePoint(money, res => {
  408. if (res.status) {
  409. this.userPointNums = res.data // 用户总积分
  410. this.canUsePoint = res.available_point // 可以使用的积分
  411. this.pointMoney = res.point_rmb // 积分抵扣的总金额
  412. }
  413. })
  414. }
  415. // 所有价格转换
  416. data.amount = this.$common.formatMoney(data.amount);
  417. data.goods_amount = this.$common.formatMoney(data.goods_amount);
  418. data.goods_pmt_old = data.goods_pmt;
  419. data.goods_pmt = this.$common.formatMoney(data.goods_pmt);
  420. data.coupon_pmt = this.$common.formatMoney(data.coupon_pmt);
  421. data.order_pmt_old = data.order_pmt;
  422. data.order_pmt = this.$common.formatMoney(data.order_pmt);
  423. data.point_money = this.$common.formatMoney(data.point_money);
  424. data.cost_freight = this.$common.formatMoney(data.cost_freight);
  425. // 购物车详情
  426. this.cartData = data
  427. // 商品详情
  428. this.products = data.list
  429. // 优惠信息
  430. this.promotions = data.promotion_list
  431. // 使用的优惠券信息
  432. this.usedCoupons = data.coupon
  433. // 手动输入的优惠券使用成功后关闭弹窗并清除输入的优惠券码
  434. this.current === 1 && this.$refs.lvvpopref.popshow && this.inputCouponCode ? this.toclose() : ''
  435. this.inputCouponCode = ''
  436. this.optCoupon = ''
  437. } else {
  438. this.$common.errorToShow(res.msg, () => {
  439. // 优惠券不可用状态判断
  440. // 优惠券号码不存在 15009
  441. // 优惠券未开始 15010
  442. // 优惠券已使用 15013
  443. // 优惠券不符合使用规则 15014
  444. // 优惠券不可使用多张 15015
  445. let errStatus = [15009, 15010, 15013, 15014, 15015]
  446. if (errStatus.indexOf(res.data) !== -1) {
  447. // 删除使用的优惠券号码
  448. if (this.current === 1) {
  449. this.removeCouponCode(this.inputCouponCode, this.current)
  450. } else {
  451. // 取消选择使用的状态
  452. if (this.optCoupon) {
  453. this.userCoupons.forEach(item => {
  454. if (item.coupon_code === this.optCoupon) {
  455. item.checked = false
  456. }
  457. })
  458. }
  459. this.removeCouponCode(this.optCoupon, this.current)
  460. }
  461. }
  462. })
  463. }
  464. })
  465. },
  466. // 获取用户可用的优惠券信息
  467. getUserCounpons () {
  468. let data = {
  469. display: 'no_used'
  470. }
  471. this.$api.userCoupon(data, res => {
  472. if (res.status) {
  473. let _list = res.data.list
  474. let nowTime = Math.round(new Date().getTime() / 1000).toString()
  475. _list.forEach(item => {
  476. this.$set(item, 'checked', false)
  477. // 判断优惠券是否有效(开始时间)
  478. this.$set(item, 'disabled', item.start_time > nowTime ? true : false)
  479. this.$set(item, 'cla', item.disabled ? 'cci-l bg-c' : 'cci-l') // 绑定相应的class样式
  480. })
  481. this.userCoupons = _list
  482. }
  483. })
  484. },
  485. // 点击使用/取消优惠券操作
  486. couponHandle (index) {
  487. // 更改使用/取消状态
  488. this.userCoupons[index].checked = !this.userCoupons[index].checked
  489. // 暂存当次选中使用的优惠券key
  490. this.optCoupon = this.userCoupons[index].coupon_code
  491. let arr = []
  492. this.userCoupons.forEach(item => {
  493. if (item.checked) {
  494. arr.push(item.coupon_code)
  495. }
  496. })
  497. if (this.userCoupons[index].checked) {
  498. // 使用
  499. this.params.coupon_code = arr.join()
  500. } else {
  501. // 取消使用
  502. let paramsCodes = this.params.coupon_code.split(',')
  503. let usedIndex = paramsCodes.indexOf(this.userCoupons[index].coupon_code)
  504. if (usedIndex !== -1) {
  505. paramsCodes.splice(usedIndex, 1)
  506. this.params.coupon_code = paramsCodes.join()
  507. }
  508. }
  509. },
  510. // 手输的优惠券码使用
  511. useInputCouponCode () {
  512. if (!this.inputCouponCode) {
  513. this.$common.errorToShow('请输入优惠券码')
  514. } else {
  515. // 判断是否有使用的优惠券
  516. if (this.params.coupon_code.length > 0) {
  517. this.params.coupon_code += ',' + this.inputCouponCode
  518. } else {
  519. this.params.coupon_code = this.inputCouponCode
  520. }
  521. }
  522. },
  523. // 不使用优惠券
  524. notUseCoupon () {
  525. this.toclose()
  526. this.inputCouponCode = '' // 清空手输的优惠券码
  527. this.userCoupons.forEach(item => {
  528. item.checked = false
  529. }) // 取消所有选中的使用状态
  530. this.params.coupon_code = '' // 清空params优惠券码
  531. },
  532. // 移除/取消使用中的指定优惠券
  533. removeCouponCode (code, current) {
  534. let arr = this.params.coupon_code.split(',')
  535. arr.splice(arr.indexOf(code), 1)
  536. current === 0 ? this.optCoupon = '' : this.inputCouponCode = ''
  537. this.params.coupon_code = arr.join()
  538. },
  539. // 是否使用积分
  540. changePointHandle(){
  541. if(this.userPointNums > 0){
  542. this.isUsePoint = !this.isUsePoint;
  543. this.params.point = this.isUsePoint ? this.canUsePoint : 0;
  544. }
  545. },
  546. // 显示modal弹出框
  547. toshow(){
  548. this.$refs.lvvpopref.show();
  549. },
  550. // 关闭modal弹出框
  551. toclose(){
  552. this.$refs.lvvpopref.close();
  553. },
  554. // 去支付
  555. toPay (e) {
  556. this.submitStatus = true;
  557. let receiptType = 1;
  558. if(this.type_current != 0){
  559. receiptType = 2;
  560. }
  561. this.receiptType = receiptType;
  562. let data = {
  563. cart_ids: this.params.ids,
  564. memo: this.memo,
  565. coupon_code: this.params.coupon_code,
  566. point: this.params.point,
  567. receipt_type: this.receiptType
  568. }
  569. data['order_type'] = this.params.order_type; //订单类型
  570. if(this.team_id != 0){
  571. data['params'] = JSON.stringify({team_id:this.team_id}) //团id
  572. }
  573. let delivery = {}
  574. // 判断是快递配送还是门店自提
  575. if(this.receiptType == 1){
  576. if(!this.userShip.id || !this.params.area_id){
  577. this.$common.errorToShow('请选择收货地址');
  578. this.submitStatus = false;
  579. return false;
  580. }
  581. // 快递配送
  582. delivery = {
  583. uship_id: this.userShip.id,
  584. area_id: this.params.area_id
  585. }
  586. }
  587. if(this.receiptType == 2){
  588. if(!this.store.id){
  589. this.$common.errorToShow('请选择自提门店');
  590. this.submitStatus = false;
  591. return false;
  592. }
  593. if(!this.store_pick.name){
  594. this.$common.errorToShow('请输入提货人姓名');
  595. this.submitStatus = false;
  596. return false;
  597. }
  598. if(!this.store_pick.mobile){
  599. this.$common.errorToShow('请输入提货人电话');
  600. this.submitStatus = false;
  601. return false;
  602. }
  603. // 门店自提
  604. delivery = {
  605. store_id: this.store.id,
  606. lading_name: this.store_pick.name,
  607. lading_mobile: this.store_pick.mobile
  608. }
  609. }
  610. // 发票信息
  611. data['tax_type'] = this.invoice.type
  612. data['tax_name'] = this.invoice.name
  613. data['tax_code'] = this.invoice.code
  614. // #ifdef H5
  615. data['source'] = 2;
  616. // #endif
  617. // #ifdef MP-WEIXIN
  618. data['source'] = 3;
  619. data['formId'] = e.detail.formId;
  620. // #endif
  621. // #ifdef MP-ALIPAY
  622. data['source'] = 4;
  623. // #endif
  624. // #ifdef APP-PLUS|| APP-PLUS-NVUE
  625. data['source'] = 5;
  626. // #endif
  627. data = Object.assign(data, delivery)
  628. this.$api.createOrder(data, res => {
  629. if (res.status) {
  630. // 创建订单成功 去支付
  631. this.submitStatus = false;
  632. this.$common.redirectTo('/pages/goods/payment/index?order_id=' + res.data.order_id + '&type=' + this.orderType)
  633. }else{
  634. this.$common.errorToShow(res.msg);
  635. this.submitStatus = false;
  636. }
  637. })
  638. },
  639. // 跳转发票页面
  640. goInvoice () {
  641. this.$common.navigateTo('./invoice')
  642. },
  643. // 跳转我的收货地址列表
  644. showAddressList () {
  645. this.$common.navigateTo('/pages/member/address/list?type=order')
  646. },
  647. // tab点击切换
  648. onClickItem(index) {
  649. if (this.current !== index) {
  650. this.current = index;
  651. }
  652. },
  653. // 获取默认店铺
  654. getDefaultStore(){
  655. this.$api.defaultStore({}, res => {
  656. if(res.status){
  657. let store = {
  658. id: res.data.id,
  659. name: res.data.store_name,
  660. mobile: res.data.store_mobile,
  661. address: res.data.all_address
  662. }
  663. this.store = store;
  664. }
  665. });
  666. }
  667. //扫码
  668. // scanCode() {
  669. // console.log(1);
  670. // uni.scanCode({
  671. // success(res) {
  672. // console.log(2);
  673. // console.log(res)
  674. // },
  675. // complete(res){
  676. // console.log(3);
  677. // console.log(res)
  678. // },
  679. // fail(res) {
  680. // console.log(4);
  681. // console.log(res)
  682. // }
  683. // })
  684. // }
  685. },
  686. computed: {
  687. // 计算购物车商品数量
  688. productNums () {
  689. let nums = 0
  690. for (let i in this.cartData.list) {
  691. if(this.cartData.list[i].is_select){
  692. nums += this.cartData.list[i].nums;
  693. }
  694. }
  695. return nums
  696. },
  697. // 判断商户是否开启积分抵扣 1开启 2未开启
  698. isOpenPoint () {
  699. return this.$store.state.config.point_switch
  700. },
  701. // 获取使用的优惠券名称
  702. usedCouponsCompute () {
  703. let name = '未使用'
  704. if (Object.keys(this.usedCoupons).length) {
  705. let coupons = []
  706. for (let i in this.usedCoupons) {
  707. coupons.push(this.usedCoupons[i])
  708. }
  709. name = coupons.join()
  710. }
  711. return name
  712. },
  713. // 判断是否开启发票功能
  714. invoiceSwitch () {
  715. return this.$store.state.config.invoice_switch || 2;
  716. },
  717. // 判断店铺开关
  718. storeSwitch() {
  719. return this.$store.state.config.store_switch || 2;
  720. },
  721. // 根据接口返回数据判断是否使用优惠券
  722. couponIsUsed () {
  723. return this.cartData.coupon instanceof Array
  724. }
  725. },
  726. watch: {
  727. // 监听数据状态(切换收货地址, 是否使用优惠券, 是否使用积分) 重新请求订单数据
  728. params: {
  729. handler () {
  730. this.getCartList()
  731. },
  732. deep: true
  733. }
  734. }
  735. }
  736. </script>
  737. <style>
  738. .margin-cell-group {
  739. margin: 0 0 2upx 0;
  740. }
  741. .add-title-items{
  742. text-align: center;
  743. }
  744. .add-title-items .btn{
  745. height: ;
  746. font-size: 24upx;
  747. /* margin: 0 auto; */
  748. }
  749. .add-title-item .cell-item-hd {
  750. min-width: 40upx;
  751. color: #666;
  752. font-size: 28upx;
  753. }
  754. .add-title-item .cell-item-bd {
  755. color: #333;
  756. font-size: 28upx;
  757. }
  758. .add-title-item .cell-bd-text {
  759. bottom: 0;
  760. }
  761. .cell-bd-view:first-child {
  762. margin-bottom: 8upx;
  763. }
  764. .cell-ft-view:first-child {
  765. margin-bottom: 8upx;
  766. }
  767. .address {
  768. display: -webkit-box;
  769. -webkit-box-orient: vertical;
  770. -webkit-line-clamp: 2;
  771. overflow: hidden;
  772. width: 100%;
  773. }
  774. .img-list {
  775. margin-bottom: 20upx;
  776. }
  777. .button-bottom button{
  778. height: 100%;
  779. width: 280upx;
  780. }
  781. .button-bottom-c{
  782. display: inline-block;
  783. position: relative;
  784. padding: 10upx 26upx;
  785. height: 100%;
  786. width: 470upx;
  787. float: left;
  788. font-size: 22upx;
  789. color: #666;
  790. overflow: hidden;
  791. }
  792. .button-bottom-c-t{
  793. font-size: 22upx;
  794. color: #999;
  795. display: inline-block;
  796. float: left;
  797. height: 100%;
  798. line-height: 70upx;
  799. }
  800. .button-bottom-c-b{
  801. font-size: 26upx;
  802. color: #333;
  803. display: inline-block;
  804. float: right;
  805. height: 100%;
  806. line-height: 70upx;
  807. }
  808. .invoice .cell-ft-text{
  809. /* top: 4upx; */
  810. color: #666;
  811. font-size: 24upx;
  812. }
  813. .pop-t{
  814. border-bottom: 2upx solid #f4f4f4;
  815. background-color: #fff;
  816. }
  817. .pop-b{
  818. margin-bottom: 90upx;
  819. }
  820. .pop-b-t{
  821. background-color: #fff;
  822. width: 100%;
  823. padding-top: 10upx;
  824. }
  825. .coupon-c{
  826. /* padding: 50upx; */
  827. height: 546upx;
  828. box-sizing: border-box;
  829. }
  830. .coupon-c-item{
  831. margin: 30upx 50upx;
  832. /* width: 100%; */
  833. height: 150upx;
  834. margin-bottom: 20upx;
  835. }
  836. .cci-l{
  837. width: 60upx;
  838. height: 100%;
  839. background-color: #FF7159;
  840. font-size: 32upx;
  841. display: inline-block;
  842. box-sizing: border-box;
  843. float: left;
  844. border-top-left-radius: 16upx;
  845. border-bottom-left-radius: 16upx;
  846. }
  847. .cci-l-c{
  848. height: 60upx;
  849. line-height: 44upx;
  850. width: 150upx;
  851. text-align: center;
  852. transform-origin: 30upx 30upx;
  853. transform: rotate(90deg);
  854. }
  855. .cci-r{
  856. position: relative;
  857. height: 150upx;
  858. width: calc(100% - 70upx);
  859. margin-left: 10upx;
  860. display: inline-block;
  861. background-color: #fff;
  862. }
  863. .cci-r-img{
  864. position: absolute;
  865. width: 100%;
  866. height: 100%;
  867. background-color: #fff;
  868. }
  869. .cci-r-c{
  870. position: relative;
  871. z-index: 99;
  872. }
  873. .ccirc-t{
  874. font-size: 24upx;
  875. padding: 10upx 20upx;
  876. min-height: 56upx;
  877. }
  878. .ccirc-b{
  879. padding: 10upx;
  880. position: relative;
  881. }
  882. .ccirc-b-l{
  883. display: inline-block;
  884. max-width: 400upx;
  885. }
  886. .ccirc-b-tip{
  887. font-size: 28upx;
  888. width: 100%;
  889. overflow: hidden;
  890. text-overflow: ellipsis;
  891. white-space: nowrap;
  892. min-height: 38upx;
  893. }
  894. .ccirc-b-tip text{
  895. font-size: 34upx;
  896. }
  897. .ccirc-b-time{
  898. font-size: 24upx;
  899. }
  900. .ccirc-b-r{
  901. display: inline-block;
  902. background-color: #FF7159;
  903. font-size: 26upx;
  904. padding: 4upx 10upx;
  905. border-radius: 4upx;
  906. position: absolute;
  907. right: 20upx;
  908. bottom: 12upx;
  909. }
  910. .pop-c .btn{
  911. width: 100%;
  912. }
  913. .leave-message{
  914. margin: 20upx 0;
  915. }
  916. .leave-message .cell-item{
  917. border-bottom: 0;
  918. }
  919. .cell-textarea{
  920. padding: 0 26upx 20upx;
  921. }
  922. /* #ifndef MP-WEIXIN */
  923. .cell-textarea textarea{
  924. width: 100%;
  925. height: 100upx;
  926. font-size: 26upx;
  927. color: #333;
  928. }
  929. /* #endif */
  930. /* #ifdef MP-WEIXIN */
  931. .cell-textarea input{
  932. width: 100%;
  933. font-size: 26upx;
  934. color: #333;
  935. }
  936. /* #endif */
  937. .coupon-enter{
  938. display: flex;
  939. height: 60upx;
  940. margin: 40upx;
  941. }
  942. .coupon-enter>view{
  943. display: inline-block;
  944. }
  945. .coupon-input{
  946. /* width: 450upx; */
  947. flex: 1;
  948. border: 2upx solid #e8e8e8;
  949. background-color: #fff;
  950. height: 100%;
  951. }
  952. .coupon-input input{
  953. height: 100%;
  954. font-size: 26upx;
  955. padding: 2upx 10upx;
  956. }
  957. .coupon-code{
  958. margin: 4upx 30upx;
  959. }
  960. .coupon-enter-btn{
  961. height: 100%;
  962. margin-left: 20upx;
  963. }
  964. .coupon-enter-btn .btn{
  965. font-size: 24upx;
  966. height: 100%;
  967. width: 108upx;
  968. line-height: 58upx;
  969. }
  970. .bg-c{
  971. background-color: #ccc;
  972. }
  973. .no-store{
  974. text-align: center;
  975. padding: 30upx 0;
  976. font-size: 26upx;
  977. color: #666;
  978. /* min-height: 60upx; */
  979. }
  980. .coupon-none{
  981. text-align: center;
  982. padding: 120upx 0;
  983. }
  984. .coupon-none-img{
  985. width: 274upx;
  986. height: 274upx;
  987. }
  988. </style>
invoice.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="content-top">
  4. <view class='cell-group margin-cell-group'>
  5. <view class='cell-item'>
  6. <view class='cell-item-hd'>
  7. <view class='cell-hd-title'>发票类型</view>
  8. </view>
  9. <view class='cell-item-ft'>
  10. <view class="uni-form-item uni-column invoice-type">
  11. <radio-group class="uni-list" @change="radioChange">
  12. <label class="uni-list-cell uni-list-cell-pd" v-for="(item,index) in radioItems" :key="index">
  13. <view class="invoice-type-icon">
  14. <radio :id="item.name" :value="item.value" :checked="item.value == type"></radio>
  15. </view>
  16. <view class="invoice-type-c">
  17. <label class="label-2-text" :for="item.name">
  18. <text>{{item.name}}</text>
  19. </label>
  20. </view>
  21. </label>
  22. </radio-group>
  23. </view>
  24. </view>
  25. </view>
  26. <view class='cell-item'>
  27. <view class='cell-item-hd'>
  28. <view class='cell-hd-title'>发票抬头</view>
  29. </view>
  30. <view class='cell-item-ft'>
  31. <input class='cell-bd-input' v-model="name" placeholder='抬头名称'></input>
  32. </view>
  33. </view>
  34. <view class='cell-item' v-show="type === '3'">
  35. <view class='cell-item-hd'>
  36. <view class='cell-hd-title'>税号</view>
  37. </view>
  38. <view class='cell-item-ft'>
  39. <input class='cell-bd-input' v-model="code" placeholder='纳税人识别号'></input>
  40. </view>
  41. </view>
  42. </view>
  43. <view class='cell-group margin-cell-group'>
  44. <view class='cell-item'>
  45. <view class='cell-item-hd'>
  46. <view class='cell-hd-title'>发票内容</view>
  47. </view>
  48. <view class='cell-item-ft'>
  49. <view class="cell-ft-view">明细</view>
  50. </view>
  51. </view>
  52. </view>
  53. <view class='cell-group margin-cell-group'>
  54. <view class='cell-item right-img' @click="notNeedInvoice">
  55. <view class='cell-item-hd'>
  56. <view class='cell-hd-title'>本次不开具发票</view>
  57. </view>
  58. <view class='cell-item-ft'>
  59. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  60. </view>
  61. </view>
  62. </view>
  63. </view>
  64. <view class="button-bottom">
  65. <button class="btn btn-square btn-b" @click="saveInvoice" hover-class="btn-hover2">保存</button>
  66. </view>
  67. </view>
  68. </template>
  69. <script>
  70. export default {
  71. data() {
  72. return {
  73. radioItems: [
  74. {
  75. name: '个人或事业单位',
  76. value: '2'
  77. },
  78. {
  79. name: '企业',
  80. value: '3'
  81. }
  82. ],
  83. type: '3', // 发票类型 2个人 3企业
  84. name: '', // 抬头名称
  85. code: '' // 税号
  86. }
  87. },
  88. onLoad () {
  89. let invoice
  90. let pages = getCurrentPages()
  91. let pre = pages[pages.length - 2]
  92. // #ifdef H5
  93. invoice = pre.invoice
  94. // #endif
  95. // #ifdef MP-WEIXIN || APP-PLUS || APP-PLUS-NVUE
  96. invoice = pre.$vm.invoice
  97. // #endif
  98. // #ifdef MP-ALIPAY
  99. invoice = pre.rootVM.invoice;
  100. // #endif
  101. if (invoice && invoice.hasOwnProperty('type') && invoice.type !== '1') {
  102. // 发票不是未使用, 展示发票信息
  103. this.name = invoice.name
  104. this.code = invoice.code
  105. this.type = invoice.type
  106. }
  107. },
  108. methods: {
  109. // 单选框点击切换
  110. radioChange (evt) {
  111. this.radioItems.forEach(item => {
  112. if (item.value === evt.target.value) {
  113. this.type = item.value
  114. }
  115. })
  116. },
  117. // 不需要发票信息
  118. notNeedInvoice () {
  119. let data = {
  120. type: '1',
  121. name: '不开发票',
  122. code: ''
  123. }
  124. this.setPageData(data)
  125. },
  126. // 保存发票信息
  127. saveInvoice () {
  128. if (!this.name) {
  129. this.$common.errorToShow('请输入发票抬头')
  130. return false
  131. }
  132. // 企业类型需要输入税号
  133. if (this.type === '3' && !this.code) {
  134. this.$common.errorToShow('请输入发票税号信息')
  135. return false
  136. }
  137. let data = {
  138. type: this.type,
  139. name: this.name
  140. }
  141. // 不是企业类型不需要税号
  142. data['code'] = this.type === '3' ? this.code : ''
  143. this.setPageData(data)
  144. },
  145. // 向上个页面赋值并返回
  146. setPageData (data) {
  147. let pages = getCurrentPages();//当前页
  148. let beforePage = pages[pages.length - 2];//上个页面
  149. // #ifdef MP-ALIPAY
  150. beforePage.rootVM.invoice = data;
  151. // #endif
  152. // #ifdef MP-WEIXIN || APP-PLUS || APP-PLUS-NVUE
  153. beforePage.$vm.invoice = data;
  154. // #endif
  155. // #ifdef H5
  156. beforePage.invoice = data;
  157. // #endif
  158. uni.navigateBack({
  159. delta: 1
  160. })
  161. }
  162. }
  163. }
  164. </script>
  165. <style>
  166. /* .margin-cell-group{
  167. margin-bottom: 20upx;
  168. } */
  169. .invoice-type .uni-list-cell{
  170. display: inline-block;
  171. font-size: 26upx;
  172. color: #333;
  173. position: relative;
  174. margin-left: 50upx;
  175. }
  176. .invoice-type .uni-list-cell>view{
  177. display: inline-block;
  178. }
  179. .invoice-type-icon{
  180. position: absolute;
  181. top: 50%;
  182. transform: translateY(-50%);
  183. }
  184. .invoice-type-c{
  185. margin-left: 50upx;
  186. line-height: 2;
  187. }
  188. .cell-item-ft .cell-bd-input{
  189. text-align: right;
  190. width: 500upx;
  191. }
  192. .button-bottom .btn {
  193. width: 100%;
  194. }
  195. </style>
storelist.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class='search'>
  4. <view class='search-c'>
  5. <image class='icon search-icon' src='/static/image/zoom.png'></image>
  6. <input class='search-input' placeholder-class='search-input-p' placeholder='请输入门店名' v-model="key"></input>
  7. </view>
  8. <button class="btn btn-g" hover-class="btn-hover2" @click="storeSearch">搜索</button>
  9. </view>
  10. <view class='cell-group margin-cell-group'>
  11. <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)">
  12. <view class="cell-item-hd">
  13. <image class='cell-hd-icon' src='/static/image/homepage.png'></image>
  14. </view>
  15. <view class='cell-item-bd'>
  16. <view class="cell-bd-view black-text">
  17. <text class="cell-bd-text">{{item.store_name}}</text>
  18. </view>
  19. <view class="cell-bd-view">
  20. <text class="cell-bd-text">电话:{{item.mobile}}</text>
  21. </view>
  22. <view class="cell-bd-view">
  23. <text class="cell-bd-text">地址:{{item.all_address}}</text>
  24. </view>
  25. </view>
  26. <view class='cell-item-ft'>
  27. <image class='cell-ft-next icon' src='/static/image/location.png'></image>
  28. <text class="cell-ft-text color-9">{{item.distance}}</text>
  29. </view>
  30. </view>
  31. </view>
  32. </view>
  33. </template>
  34. <script>
  35. export default {
  36. data () {
  37. return {
  38. storeList: [],
  39. key: '',
  40. longitude: '',
  41. latitude: '',
  42. }
  43. },
  44. onShow () {
  45. this.getStoreList();
  46. },
  47. methods: {
  48. //门店搜索
  49. storeSearch(){
  50. this.getStoreList();
  51. },
  52. //获取门店列表
  53. getStoreList(){
  54. let _this = this;
  55. uni.getLocation({
  56. type: 'gcj02',
  57. success: function (res) {
  58. _this.longitude = res.longitude;
  59. _this.latitude = res.latitude;
  60. },
  61. complete: function (res) {
  62. let data = {
  63. 'key': _this.key,
  64. 'longitude': _this.longitude,
  65. 'latitude': _this.latitude
  66. }
  67. _this.$api.storeList(data, e => {
  68. _this.storeList = e.data;
  69. });
  70. }
  71. });
  72. },
  73. //门店选择
  74. selectStore(id, name, mobile, address){
  75. let pages = getCurrentPages()
  76. let pre = pages[pages.length - 2]
  77. let store = {};
  78. store['id'] = id;
  79. store['name'] = name;
  80. store['mobile'] = mobile;
  81. store['address'] = address;
  82. // #ifdef MP-ALIPAY
  83. pre.rootVM.store = store;
  84. // #endif
  85. // #ifdef MP-WEIXIN || APP-PLUS || APP-PLUS-NVUE
  86. pre.$vm.store = store
  87. // #endif
  88. // #ifdef H5
  89. pre.store = store
  90. // #endif
  91. uni.navigateBack({
  92. delta: 1
  93. });
  94. }
  95. }
  96. }
  97. </script>
  98. <style>
  99. .search{
  100. display: flex;
  101. }
  102. .search-c{
  103. width: 80%;
  104. margin-right: 2%;
  105. }
  106. .search-icon{
  107. left: 30upx;
  108. }
  109. .search-input {
  110. padding: 10upx 30upx 10upx 90upx;
  111. }
  112. .search-input-p{
  113. padding: 0 !important;
  114. }
  115. .search .btn{
  116. width: 18%;
  117. border: none;
  118. background-color: #f1f1f1;
  119. font-size: 28upx;
  120. color: #333;
  121. border-radius: 6upx;
  122. line-height: 72upx;
  123. }
  124. .add-title-item .cell-item-hd {
  125. min-width: 50upx;
  126. color: #666;
  127. font-size: 28upx;
  128. }
  129. .cell-bd-view {
  130. margin-bottom: 6upx;
  131. }
  132. .cell-bd-view .cell-bd-text{
  133. font-size: 22upx;
  134. color: #999;
  135. }
  136. .black-text .cell-bd-text{
  137. font-size: 28upx;
  138. color: #333;
  139. }
  140. </style>

index

custom.vue
复制代码
  1. <template>
  2. <view class="content" style="padding-top: 0upx;">
  3. <jshop :data="pageData"></jshop>
  4. <jihaiCopyright></jihaiCopyright>
  5. </view>
  6. </template>
  7. <script>
  8. import jshop from "@/components/jshop/jshop.vue"
  9. import jihaiCopyright from "@/components/jihai-copyright/jihaiCopyright.vue"
  10. import {
  11. goods
  12. } from '@/config/mixins.js'
  13. export default {
  14. mixins: [goods],
  15. components: {
  16. jihaiCopyright,
  17. jshop
  18. },
  19. data() {
  20. return {
  21. myShareCode: '', //分享Code
  22. imageUrl: '/static/image/share_image.png', //店铺分享图片
  23. pageData: [],
  24. pageCode: 'mobile_home', //页面布局编码
  25. statusBarHeight: '0',
  26. customBarOpacity: false,
  27. scrollTop: 0,
  28. showLoad: false, //是否显示loading
  29. share_name: ''
  30. }
  31. },
  32. computed: {
  33. appTitle() {
  34. return this.$store.state.config.shop_name;
  35. }
  36. },
  37. onLoad(e) {
  38. //增加页面编码,可自定义编码
  39. if (e.page_code) {
  40. this.pageCode = e.page_code
  41. }
  42. this.initData()
  43. },
  44. // 小程序沉浸式状态栏变色
  45. onPageScroll(e) {
  46. // console.log(e);
  47. e.scrollTop > 50 ? this.customBarOpacity = true : this.customBarOpacity = false
  48. },
  49. mounted() {
  50. // #ifdef H5
  51. window.addEventListener('scroll', this.handleScroll)
  52. // #endif
  53. },
  54. methods: {
  55. // 搜索框滑动变色
  56. handleScroll() {
  57. var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
  58. scrollTop > 50 ? this.searchBarOpacity = true : this.searchBarOpacity = false
  59. },
  60. destroyed() {
  61. window.removeEventListener('scroll', this.handleScroll)
  62. },
  63. goSearch() {
  64. uni.navigateTo({
  65. url: './search'
  66. });
  67. },
  68. // 首页初始化获取数据
  69. initData() {
  70. this.showLoad = true;
  71. //获取首页配置
  72. this.$api.getPageConfig({
  73. code: this.pageCode,
  74. }, res => {
  75. if (res.status == true) {
  76. this.pageData = res.data.items;
  77. this.share_name = res.data.name;
  78. uni.setNavigationBarTitle({
  79. title: res.data.name
  80. });
  81. //隐藏loading
  82. setTimeout(() => {
  83. this.showLoad = false;
  84. }, 600);
  85. }
  86. });
  87. this.getMyShareCode();
  88. },
  89. getMyShareCode() {
  90. let userToken = this.$db.get("userToken");
  91. if (userToken && userToken != '') {
  92. // 获取我的分享码
  93. this.$api.shareCode({}, res => {
  94. if (res.status) {
  95. this.myShareCode = res.data ? res.data : '';
  96. }
  97. });
  98. }
  99. }
  100. },
  101. onPullDownRefresh() {
  102. this.initData();
  103. uni.stopPullDownRefresh();
  104. },
  105. //分享
  106. onShareAppMessage() {
  107. let myInviteCode = this.myShareCode ? this.myShareCode : '';
  108. let ins = this.$common.shareParameterDecode('type=8&page_code=' + this.pageCode + '&invite=' + myInviteCode);
  109. let path = '/pages/share/jump?scene=' + ins;
  110. return {
  111. title: this.share_name,
  112. // #ifdef MP-ALIPAY
  113. //desc: this.$store.state.config.share_desc,
  114. // #endif
  115. //imageUrl: this.$store.state.config.share_image,
  116. path: path
  117. }
  118. }
  119. }
  120. </script>
  121. <style>
  122. .search {
  123. /* position: fixed; */
  124. /* #ifdef H5 */
  125. /* top: 44px; */
  126. /* #endif */
  127. /* #ifndef H5 */
  128. /* top: 0; */
  129. /* #endif */
  130. }
  131. .cell-item {
  132. border: none;
  133. }
  134. .cell-ft-text {
  135. font-size: 22upx;
  136. color: #999;
  137. }
  138. .status_bar {
  139. height: var(--status-bar-height);
  140. width: 100%;
  141. position: fixed;
  142. top: 0;
  143. z-index: 999;
  144. background: rgba(0, 0, 0, 0);
  145. transition: all .5s;
  146. }
  147. .custom-navbar {
  148. height: 40px;
  149. line-height: 34px;
  150. position: fixed;
  151. width: 100%;
  152. padding-left: 26upx;
  153. top: var(--status-bar-height);
  154. z-index: 999;
  155. background: rgba(0, 0, 0, 0);
  156. transition: all .5s;
  157. }
  158. .index-logo {
  159. width: 140upx;
  160. height: 70upx;
  161. /* margin: 0 auto; */
  162. }
  163. .index-logo-img {
  164. width: 100%;
  165. height: 100%;
  166. }
  167. .isOpacity {
  168. background: rgba(255, 255, 255, 1);
  169. transition: all .5s;
  170. }
  171. /* iPhone X in portrait & landscape */
  172. @media only screen and (min-device-width : 375px) and (max-device-width : 812px) and (-webkit-device-pixel-ratio : 3) {
  173. .status_bar {
  174. height: 50px;
  175. }
  176. .custom-navbar {
  177. top: 50px;
  178. }
  179. }
  180. /* iPhone X in landscape */
  181. @media only screen and (min-device-width : 375px) and (max-device-width : 812px) and (-webkit-device-pixel-ratio : 3) and (orientation : landscape) {
  182. .status_bar {
  183. height: 50px;
  184. }
  185. .custom-navbar {
  186. top: 50px;
  187. }
  188. }
  189. /* iPhone X in portrait */
  190. @media only screen and (min-device-width : 375px) and (max-device-width : 812px) and (-webkit-device-pixel-ratio : 3) and (orientation : portrait) {
  191. .status_bar {
  192. height: 50px;
  193. }
  194. .custom-navbar {
  195. top: 50px;
  196. }
  197. }
  198. </style>
index.vue
复制代码
  1. <template>
  2. <view class="content" style="padding-top: 0upx;">
  3. <jshop :data="pageData"></jshop>
  4. <jihaiCopyright></jihaiCopyright>
  5. <red-bag v-if="redBagShow" @click="handleGet"></red-bag>
  6. </view>
  7. </template>
  8. <script>
  9. import jshop from '@/components/jshop/jshop.vue'
  10. import jihaiCopyright from '@/components/jihai-copyright/jihaiCopyright.vue'
  11. import uniCountdown from '@/components/uni-countdown/uni-countdown.vue'
  12. import redBag from '@/components/red-bag/index'
  13. import {
  14. goods
  15. } from '@/config/mixins.js'
  16. import {
  17. goBack
  18. } from '@/config/mixins.js'
  19. export default {
  20. mixins: [goods],
  21. components: {
  22. jihaiCopyright,
  23. jshop,
  24. uniCountdown,
  25. redBag
  26. },
  27. data() {
  28. return {
  29. myShareCode: '', //分享Code
  30. imageUrl: '/static/image/share_image.png', //店铺分享图片
  31. pageData: [],
  32. pageCode: 'mobile_home', //页面布局编码
  33. pintuan: [], //拼团列表,
  34. redBagShow: false, //红包
  35. }
  36. },
  37. computed: {
  38. appTitle() {
  39. return this.$store.state.config.shop_name
  40. }
  41. },
  42. onLoad(e) {
  43. this.initData()
  44. if(this.$store.state.config.shop_name){
  45. uni.setNavigationBarTitle({
  46. title: this.$store.state.config.shop_name||''
  47. });
  48. }
  49. },
  50. methods: {
  51. //领取红包
  52. handleGet() {},
  53. destroyed() {
  54. window.removeEventListener('scroll', this.handleScroll)
  55. },
  56. goSearch() {
  57. uni.navigateTo({
  58. url: './search'
  59. })
  60. },
  61. // 首页初始化获取数据
  62. initData() {
  63. //获取首页配置
  64. this.$api.getPageConfig({
  65. code: this.pageCode
  66. },
  67. res => {
  68. if (res.status == true) {
  69. this.pageData = res.data.items;
  70. //隐藏loading
  71. setTimeout(() => {
  72. this.showLoad = false;
  73. }, 600);
  74. }
  75. }
  76. );
  77. this.getMyShareCode();
  78. },
  79. getMyShareCode() {
  80. let userToken = this.$db.get("userToken");
  81. if (userToken && userToken != '') {
  82. // 获取我的分享码
  83. this.$api.shareCode({}, res => {
  84. if (res.status) {
  85. this.myShareCode = res.data ? res.data : '';
  86. }
  87. });
  88. }
  89. }
  90. },
  91. onPullDownRefresh() {
  92. this.initData()
  93. //this.$db.del('all_cat');
  94. uni.stopPullDownRefresh()
  95. },
  96. //分享
  97. onShareAppMessage() {
  98. let myInviteCode = this.myShareCode ? this.myShareCode : '';
  99. let ins = this.$common.shareParameterDecode('type=1&invite=' + myInviteCode);
  100. let path = '/pages/share/jump?scene=' + ins;
  101. return {
  102. title: this.$store.state.config.share_title,
  103. // #ifdef MP-ALIPAY
  104. desc: this.$store.state.config.share_desc,
  105. // #endif
  106. imageUrl: this.$store.state.config.share_image,
  107. path: path
  108. }
  109. }
  110. }
  111. </script>
  112. <style>
  113. .search {
  114. /* position: fixed; */
  115. /* #ifdef H5 */
  116. /* top: 44px; */
  117. /* #endif */
  118. /* #ifndef H5 */
  119. /* top: 0; */
  120. /* #endif */
  121. }
  122. .cell-item {
  123. border: none;
  124. }
  125. .cell-ft-text {
  126. font-size: 22upx;
  127. color: #999;
  128. }
  129. /* .new-goods {
  130. min-height: 300upx;
  131. white-space: nowrap;
  132. width: 100%;
  133. }
  134. .new-goods-item {
  135. width: 200upx;
  136. display: inline-block;
  137. margin-right: 20upx;
  138. }
  139. .new-goods-item:last-child {
  140. margin-right: 0;
  141. }
  142. .news-goods-img {
  143. width: 200upx;
  144. height: 200upx;
  145. }
  146. .news-goods-img image {
  147. width: 100%;
  148. height: 100%;
  149. }
  150. .news-goods-bot {
  151. margin-top: 6upx;
  152. }
  153. .new-goods-name {
  154. display: block;
  155. font-size: 26upx;
  156. }
  157. .new-goods-price {
  158. display: block;
  159. font-size: 26upx;
  160. color: #e14d4d;
  161. } */
  162. </style>
search.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class='search'>
  4. <view class='search-c'>
  5. <image class='icon search-icon' src='/static/image/zoom.png'></image>
  6. <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>
  7. </view>
  8. <button class="btn btn-g" @click="search" hover-class="btn-hover2">搜索</button>
  9. </view>
  10. <view class="history-c" v-show="keys.length > 0">
  11. <view class="history-title">
  12. <view class='ht-left'>历史记录</view>
  13. <view class='ht-right' @click="deleteKey">清除</view>
  14. </view>
  15. <view class="history-body">
  16. <view class="hb-item" v-for="(item, key) in keys" :key="key" @click="toNav(item)">
  17. {{item}}
  18. </view>
  19. </view>
  20. </view>
  21. <view class="history-c" v-show="recommend && recommend.length > 0">
  22. <view class="history-title">
  23. <view class='ht-left'>搜索发现</view>
  24. </view>
  25. <view class="history-body">
  26. <view class="hb-item" v-for="(item, key) in recommend" :key="key" @click="toNav(item)">
  27. {{item}}
  28. </view>
  29. </view>
  30. </view>
  31. </view>
  32. </template>
  33. <script>
  34. export default {
  35. data() {
  36. return {
  37. keys: [],
  38. key: '',
  39. navType: 'toNav',
  40. focus: true,
  41. }
  42. },
  43. computed: {
  44. recommend() {
  45. return this.$store.state.config.recommend_keys
  46. }
  47. },
  48. methods: {
  49. //搜索
  50. search: function () {
  51. let keys = this.key;
  52. if(keys != '') {
  53. let search_key = this.$db.get('search_key');
  54. if (!search_key) {
  55. search_key = [];
  56. }
  57. let flag = true;
  58. for (var key in search_key) {
  59. if (search_key[key] == keys) {
  60. flag = false;
  61. }
  62. }
  63. if (flag) {
  64. search_key.unshift(keys);
  65. }
  66. this.$db.set('search_key', search_key);
  67. this.$db.set('search_term', keys);
  68. this.$common.navigateTo('/pages/classify/index?key=' + keys);
  69. }
  70. },
  71. //清除
  72. deleteKey: function () {
  73. //删除显示
  74. this.keys = [];
  75. //删除存储
  76. this.$db.del('search_key');
  77. },
  78. //跳转操作
  79. toNav: function (keys) {
  80. this.$db.set('search_term', keys);
  81. let search_key = this.$db.get('search_key');
  82. if (!search_key) {
  83. search_key = [];
  84. }
  85. var flag = true;
  86. for (var key in search_key) {
  87. if (search_key[key] == keys) {
  88. flag = false;
  89. }
  90. }
  91. if (flag) {
  92. search_key.unshift(keys);
  93. }
  94. this.$db.set('search_key', search_key);
  95. this.$common.navigateTo('/pages/classify/index?key=' + keys);
  96. },
  97. },
  98. //加载触发
  99. onShow(e) {
  100. this.keys = this.$db.get('search_key');
  101. this.key = this.$db.get('search_term');
  102. this.focus = true;
  103. },
  104. //页面卸载触发
  105. onUnload() {
  106. this.$db.set('search_term', '');
  107. }
  108. }
  109. </script>
  110. <style>
  111. .search{
  112. display: flex;
  113. }
  114. .search-c{
  115. width: 80%;
  116. margin-right: 2%;
  117. }
  118. .search-icon{
  119. left: 30upx;
  120. }
  121. .search-input {
  122. padding: 10upx 30upx 10upx 90upx;
  123. }
  124. .search-input-p{
  125. padding: 0 !important;
  126. }
  127. .search .btn{
  128. width: 18%;
  129. border: none;
  130. background-color: #f1f1f1;
  131. font-size: 28upx;
  132. color: #333;
  133. border-radius: 6upx;
  134. line-height: 72upx;
  135. }
  136. .history-c{
  137. /* background-color: #fff; */
  138. padding: 20upx 26upx;
  139. }
  140. .history-title{
  141. overflow: hidden;
  142. }
  143. .ht-left{
  144. float: left;
  145. font-size: 28upx;
  146. color: #333;
  147. }
  148. .ht-right{
  149. float: right;
  150. color: #999;
  151. font-size: 26upx;
  152. }
  153. .history-body{
  154. overflow: hidden;
  155. margin-top: 20upx;
  156. min-height: 200upx;
  157. }
  158. .hb-item{
  159. display: inline-block;
  160. float: left;
  161. background-color: #fff;
  162. color: #888;
  163. margin-right: 20upx;
  164. margin-bottom: 14upx;
  165. font-size: 26upx;
  166. padding: 10upx 20upx;
  167. }
  168. .square{
  169. border-radius: 0;
  170. }
  171. .radius{
  172. border-radius: 12upx;
  173. }
  174. </style>

login

choose
index.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="login-m">
  4. <view class="login-item">
  5. <view class="logo">
  6. <open-data type="userAvatarUrl"></open-data>
  7. </view>
  8. </view>
  9. <view class="login-tip">
  10. <view class="login-tip-big">
  11. 申请获取以下权限
  12. </view>
  13. <view class="login-tip-small">
  14. 获得你的公开信息 (昵称、头像等)
  15. </view>
  16. </view>
  17. </view>
  18. <view class="login-b flc">
  19. <!-- #ifdef MP-WEIXIN -->
  20. <button class="auth-btn refuse" @click="handleRefuse">拒绝</button>
  21. <button class="auth-btn " open-type="getUserInfo" @getuserinfo="getUserInfo" hover-class="btn-hover">允许</button>
  22. <!-- #endif -->
  23. <!-- #ifdef MP-ALIPAY -->
  24. <button class="auth-btn " @click="getALICode" hover-class="btn-hover">授权登录</button>
  25. <!-- #endif -->
  26. </view>
  27. </view>
  28. </template>
  29. <script>
  30. export default {
  31. data() {
  32. return {
  33. open_id: ''
  34. }
  35. },
  36. computed: {
  37. logoImage() {
  38. return this.$store.state.config.shop_logo
  39. }
  40. },
  41. onLoad() {
  42. const _this = this
  43. // #ifdef MP-WEIXIN
  44. this.getCode(function(code) {
  45. var data = {
  46. code: code
  47. }
  48. _this.$api.login1(data, (res)=>{
  49. if (!res.status) {
  50. _this.$common.successToShow(res.msg, function() {
  51. uni.navigateBack({
  52. delta: 1
  53. })
  54. })
  55. } else {
  56. _this.open_id = res.data
  57. }
  58. })
  59. })
  60. // #endif
  61. },
  62. // #ifdef MP-WEIXIN
  63. // onUnload: function() {
  64. // wx.reLaunch({
  65. // url: '/pages/index/index'
  66. // })
  67. // },
  68. // #endif
  69. methods: {
  70. getCode: function(callback) {
  71. uni.login({
  72. // #ifdef MP-ALIPAY
  73. scopes: 'auth_user',
  74. // #endif
  75. success: function(res) {
  76. if (res.code) {
  77. return callback(res.code)
  78. } else {
  79. //login成功,但是没有取到code
  80. this.$common.errorToShow('未取得code')
  81. }
  82. },
  83. fail: function(res) {
  84. this.$common.errorToShow('用户授权失败wx.login')
  85. }
  86. })
  87. },
  88. handleRefuse(){
  89. uni.showToast({
  90. title: '未授权',
  91. icon: 'none',
  92. duration: 1000,
  93. })
  94. setTimeout(() => {
  95. uni.hideToast();
  96. uni.navigateBack(-1);
  97. }, 1000);
  98. },
  99. getUserInfo: function(e) {
  100. //console.log(e);
  101. let _this = this
  102. //return false;
  103. if (e.detail.errMsg == 'getUserInfo:fail auth deny') {
  104. _this.$common.errorToShow('未授权')
  105. } else {
  106. var data = {
  107. open_id: _this.open_id,
  108. iv: e.detail.iv,
  109. edata: e.detail.encryptedData,
  110. signature: e.detail.signature
  111. }
  112. //有推荐码的话,带上
  113. var invitecode = _this.$db.get('invitecode')
  114. if (invitecode) {
  115. data.invitecode = invitecode
  116. }
  117. _this.toLogin(data)
  118. }
  119. },
  120. //实际的去登陆
  121. toLogin: function(data) {
  122. let _this = this
  123. _this.$api.login2(data, function(res) {
  124. if (res.status) {
  125. //判断是否返回了token,如果没有,就说明没有绑定账号,跳转到绑定页面
  126. if (typeof res.data.token == 'undefined') {
  127. uni.redirectTo({
  128. url: '/pages/login/login/index?user_wx_id=' + res.data.user_wx_id
  129. })
  130. } else {
  131. //登陆成功,设置token,并返回上一页
  132. _this.$db.set('userToken', res.data.token)
  133. uni.navigateBack({
  134. delta: 1
  135. })
  136. return false
  137. }
  138. } else {
  139. _this.$common.errorToShow('登录失败,请重试')
  140. }
  141. })
  142. },
  143. getALICode() {
  144. let that = this
  145. uni.login({
  146. scopes: 'auth_user',
  147. success: (res) => {
  148. if(res.authCode){
  149. uni.getUserInfo({
  150. provider: 'alipay',
  151. success: function (infoRes) {
  152. if(infoRes.errMsg == "getUserInfo:ok"){
  153. let user_info = {
  154. 'nickname': infoRes.nickName,
  155. 'avatar': infoRes.avatar
  156. }
  157. that.aLiLoginStep1(res.authCode, user_info);
  158. }
  159. },
  160. fail: function (errorRes) {
  161. this.$common.errorToShow('未取得用户昵称头像信息');
  162. }
  163. });
  164. }else{
  165. this.$common.errorToShow('未取得code');
  166. }
  167. },
  168. fail: function(res) {
  169. this.$common.errorToShow('用户授权失败my.login');
  170. }
  171. });
  172. },
  173. aLiLoginStep1(code, user_info) {
  174. let data = {
  175. 'code': code,
  176. 'user_info': user_info
  177. }
  178. this.$api.alilogin1(data, res => {
  179. this.alipayNoLogin = false;
  180. if (res.status) {
  181. this.open_id = res.data.user_wx_id
  182. //判断是否返回了token,如果没有,就说明没有绑定账号,跳转到绑定页面
  183. if (!res.data.hasOwnProperty('token')) {
  184. this.$common.redirectTo('/pages/login/login/index?user_wx_id=' + res.data.user_wx_id);
  185. } else {
  186. this.$db.set('userToken', res.data.token)
  187. uni.navigateBack({
  188. delta: 1
  189. });
  190. }
  191. } else {
  192. this.$common.errorToShow(res.msg)
  193. }
  194. })
  195. },
  196. }
  197. }
  198. </script>
  199. <style lang="scss">
  200. .content {
  201. background-color: #fff;
  202. height: 100vh;
  203. padding: 100upx 60upx 0;
  204. }
  205. .login-item {
  206. display: flex;
  207. justify-content: center;
  208. padding-bottom: 40upx;
  209. border-bottom: 1upx solid #dddddd;
  210. }
  211. .logo {
  212. display: block;
  213. width: 180upx;
  214. height: 180upx;
  215. border-radius: 50%;
  216. overflow: hidden;
  217. border: 2px solid #fff;
  218. box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.2);
  219. }
  220. .login-tip{
  221. padding:60upx 0;
  222. &-big{
  223. font-size: 28upx;
  224. line-height: 80upx;
  225. }
  226. &-small{
  227. font-size: 12px;
  228. color:#9e9e9e;
  229. }
  230. }
  231. .app-name {
  232. font-size: 28upx;
  233. color: #999;
  234. }
  235. .login-b .btn-g {
  236. margin-top: 40upx;
  237. }
  238. .auth-btn{
  239. flex:1;
  240. display: block;
  241. height: 80upx;
  242. line-height: 80upx;
  243. text-align: center;
  244. font-size: 12px;
  245. color:#FFF;
  246. background:#1aad19;
  247. border-radius: 40upx;
  248. &.refuse{
  249. background:#999;
  250. margin-right:40upx;
  251. }
  252. }
  253. </style>
login
index.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="login-t">
  4. <image class="login-logo" :src="logoImage" mode="aspectFill"></image>
  5. </view>
  6. <view class="login-m">
  7. <view class="login-item">
  8. <input type="number" v-model="mobile" :maxlength="maxMobile" placeholder="请输入手机号码" focus placeholder-class="login-item-i-p" />
  9. </view>
  10. <view class="login-item flc">
  11. <input class="login-item-input" placeholder-class="login-item-i-p" type="text" v-model="code" placeholder="请输入验证码" />
  12. <view :class="sendCodeBtn" @click="sendCode" v-if="verification">发送验证码</view>
  13. <view class="btn btn-g" v-if="!verification">{{ timer }} 秒后重新获取</view>
  14. </view>
  15. </view>
  16. <view class="login-b">
  17. <!-- #ifdef H5|APP-PLUS|APP-PLUS-NVUE -->
  18. <view v-if="user_wx_id">
  19. <button :class="regButtonClass" @click="toBind()" hover-class="btn-hover">登录</button>
  20. </view>
  21. <view v-else>
  22. <button :class="regButtonClass" @click="login()" hover-class="btn-hover">登录</button>
  23. <view class="login-other flc">
  24. <view class="fz12 item" @click="selectLoginType">
  25. 密码登录
  26. </view>
  27. <view class="fz12 item" @click="toReg">
  28. 注册
  29. </view>
  30. </view>
  31. </view>
  32. <!-- #endif -->
  33. <!-- #ifdef MP -->
  34. <button :class="regButtonClass" @click="showTopTips()" hover-class="btn-hover">登录</button>
  35. <!-- #endif -->
  36. </view>
  37. </view>
  38. </template>
  39. <script>
  40. import { goBack, jumpBackPage } from '@/config/mixins.js'
  41. export default {
  42. mixins: [goBack,jumpBackPage],
  43. data() {
  44. return {
  45. maxMobile: 11,
  46. mobile: '', // 用户手机号
  47. code: '', // 短信验证码
  48. user_wx_id: '', //授权id
  49. verification: true, // 通过v-show控制显示获取还是倒计时
  50. timer: 60, // 定义初始时间为60s
  51. btnb: 'btn btn-square btn-c btn-all', //按钮背景
  52. type: '', // 有值是第三方登录账号绑定
  53. isWeixinBrowser: this.$common.isWeiXinBrowser()
  54. }
  55. },
  56. onLoad(option) {
  57. if (option.user_wx_id) {
  58. this.user_wx_id = option.user_wx_id
  59. uni.setNavigationBarTitle({
  60. title: '绑定手机号'
  61. })
  62. }
  63. // H5第三方授权登录绑定
  64. // if (option.type && option.type === 'bind') {
  65. // this.type = option.type
  66. // uni.setNavigationBarTitle({
  67. // title: '绑定手机号'
  68. // })
  69. // }
  70. },
  71. computed: {
  72. // 验证手机号
  73. rightMobile() {
  74. let res = {}
  75. if (!this.mobile) {
  76. res.status = false
  77. res.msg = '请输入手机号'
  78. } else if (!/^1[3456789]{1}\d{9}$/gi.test(this.mobile)) {
  79. res.status = false
  80. res.msg = '手机号格式不正确'
  81. } else {
  82. res.status = true
  83. }
  84. return res
  85. },
  86. // 动态计算发送验证码按钮样式
  87. sendCodeBtn() {
  88. let btn = 'btn btn-g'
  89. if (this.mobile.length === this.maxMobile && this.rightMobile.status) {
  90. return btn + ' btn-b'
  91. } else {
  92. return btn
  93. }
  94. },
  95. // 动态更改登录按钮bg
  96. regButtonClass() {
  97. return this.mobile && this.mobile.length === this.maxMobile && this.code
  98. ? this.btnb + ' btn-b'
  99. : this.btnb
  100. },
  101. logoImage() {
  102. return this.$store.state.config.shop_logo
  103. }
  104. },
  105. onShow() {
  106. let _this = this
  107. let userToken = _this.$db.get('userToken')
  108. if (userToken) {
  109. uni.switchTab({
  110. url: '/pages/member/index/index'
  111. })
  112. return true
  113. }
  114. _this.timer = parseInt(_this.$db.get('timer'))
  115. if (_this.timer != null && _this.timer > 0) {
  116. _this.countDown()
  117. _this.verification = false
  118. }
  119. },
  120. methods: {
  121. // 发送短信验证码
  122. sendCode() {
  123. if (!this.rightMobile.status) {
  124. this.$common.errorToShow(this.rightMobile.msg)
  125. } else {
  126. this.$common.loadToShow('发送中...')
  127. setTimeout(() => {
  128. this.$common.loadToHide()
  129. this.$api.sms({ mobile: this.mobile, code: 'login' }, res => {
  130. if (res.status) {
  131. this.timer = 60
  132. this.verification = false
  133. this.$common.successToShow(res.msg)
  134. this.countDown() // 执行验证码计时
  135. // this.btnb = 'btn btn-square btn-all btn-b';
  136. } else {
  137. this.$common.errorToShow(res.msg)
  138. }
  139. })
  140. }, 1000)
  141. }
  142. },
  143. // 去注册
  144. toReg() {
  145. this.$common.navigateTo('/pages/login/register/index')
  146. },
  147. // 验证码倒计时
  148. countDown() {
  149. let auth_timer = setInterval(() => {
  150. // 定时器设置每秒递减
  151. this.timer-- // 递减时间
  152. uni.setStorage({
  153. key: 'timer',
  154. data: this.timer,
  155. success: function() {}
  156. })
  157. if (this.timer <= 0) {
  158. this.verification = true // 60s时间结束还原v-show状态并清除定时器
  159. clearInterval(auth_timer)
  160. }
  161. }, 1000)
  162. },
  163. // 登录
  164. login() {
  165. var _this = this
  166. if (!_this.rightMobile.status) {
  167. _this.$common.errorToShow(_this.rightMobile.msg)
  168. } else {
  169. // 短信验证码登录
  170. if (!_this.code) {
  171. _this.$common.errorToShow('请输入短信验证码!')
  172. } else {
  173. let data = {
  174. mobile: _this.mobile,
  175. code: _this.code
  176. }
  177. let invicode = _this.$db.get('invitecode')
  178. if (invicode) {
  179. data.invitecode = invicode
  180. }
  181. _this.$api.smsLogin(data, res => {
  182. if (res.status) {
  183. this.$db.set('userToken', res.data)
  184. _this.redirectHandler()
  185. } else {
  186. _this.$common.errorToShow(res.msg)
  187. }
  188. })
  189. }
  190. }
  191. },
  192. // 重定向跳转 或者返回上一个页面
  193. redirectHandler() {
  194. this.$common.successToShow('登录成功!', () => {
  195. this.$db.set('timer', 0)
  196. this.$db.del('invitecode')
  197. this.handleBack()
  198. })
  199. },
  200. // 跳转到普通登录
  201. toLogin() {
  202. uni.navigateTo({
  203. url: '../../login/login/index'
  204. })
  205. },
  206. //提交按钮
  207. showTopTips: function() {
  208. let _this = this
  209. if (_this.mobile == '') {
  210. _this.$common.errorToShow('请输入手机号码')
  211. return false
  212. }
  213. if (this.code == '') {
  214. _this.$common.errorToShow('请输入验证码')
  215. return false
  216. }
  217. if (_this.user_wx_id == 0) {
  218. _this.$common.errorToShow('登录失败,请稍后再试', function() {
  219. uni.navigateBack({
  220. delta: 1
  221. })
  222. })
  223. return false
  224. }
  225. var platform = 2
  226. //1就是h5登陆(h5端和微信公众号端),2就是微信小程序登陆,3是支付宝小程序,4是app,5是pc
  227. // #ifdef MP-ALIPAY
  228. platform = 3
  229. // #endif
  230. // #ifdef APP-PLUS||APP-PLUS-NVUE
  231. platform = 4
  232. // #endif
  233. var data = {
  234. mobile: _this.mobile,
  235. code: _this.code,
  236. platform: platform, //平台id,标识是小程序登陆的
  237. user_wx_id: _this.user_wx_id //微信小程序接口存不了session,所以要绑定的id只能传到前台
  238. }
  239. //有推荐码的话,带上
  240. var invitecode = _this.$db.get('invitecode')
  241. if (invitecode) {
  242. data.invitecode = invitecode
  243. }
  244. _this.$api.smsLogin(data, function(res) {
  245. if (res.status) {
  246. _this.$db.set('userToken', res.data)
  247. _this.redirectHandler()
  248. } else {
  249. //报错了
  250. _this.$common.errorToShow(res.msg)
  251. }
  252. })
  253. },
  254. // 公众号第三方登录账号绑定
  255. toBind() {
  256. if (this.mobile == '') {
  257. this.$common.errorToShow('请输入手机号码')
  258. return false
  259. }
  260. if (this.code == '') {
  261. this.$common.errorToShow('请输入验证码')
  262. return false
  263. }
  264. let data = {
  265. mobile: this.mobile,
  266. code: this.code,
  267. user_wx_id:this.user_wx_id
  268. }
  269. // 获取邀请码
  270. let invicode = this.$db.get('invitecode')
  271. if (invicode) {
  272. data.invitecode = invicode
  273. }
  274. this.$api.smsLogin(data, res => {
  275. if (res.status) {
  276. this.$db.set('userToken', res.data)
  277. this.redirectHandler()
  278. } else {
  279. this.$common.errorToShow(res.msg)
  280. }
  281. })
  282. },
  283. // 切换登录方式
  284. selectLoginType() {
  285. this.$common.redirectTo('./index1')
  286. }
  287. }
  288. }
  289. </script>
  290. <style lang="scss">
  291. .content {
  292. /* #ifdef H5 */
  293. height: calc(100vh - 90upx);
  294. /* #endif */
  295. /* #ifndef H5 */
  296. height: 100vh;
  297. /* #endif */
  298. background-color: #fff;
  299. padding: 0upx 100upx;
  300. }
  301. .login-t {
  302. text-align: center;
  303. padding: 50upx 0;
  304. }
  305. .login-logo {
  306. width: 180upx;
  307. height: 180upx;
  308. border-radius: 20upx;
  309. background-color: #f8f8f8;
  310. /* margin: 0 auto; */
  311. }
  312. .login-m {
  313. margin-bottom: 100upx;
  314. }
  315. .login-item {
  316. border-bottom: 2upx solid #d0d0d0;
  317. overflow: hidden;
  318. padding: 10upx;
  319. color: #333;
  320. margin-bottom: 30upx;
  321. }
  322. .login-item-input {
  323. display: inline-block;
  324. flex: 1;
  325. box-sizing: border-box;
  326. }
  327. .login-item .btn {
  328. border: none;
  329. width: 40%;
  330. text-align: right;
  331. padding: 0;
  332. &.btn-b {
  333. background: none;
  334. color: #333 !important;
  335. }
  336. }
  337. .login-b .btn {
  338. color: #999;
  339. }
  340. .btn-b {
  341. color: #fff !important;
  342. }
  343. .login-other {
  344. margin-bottom: 40upx;
  345. .item {
  346. padding: 20upx 0;
  347. }
  348. }
  349. .btn-square {
  350. color: #333;
  351. }
  352. </style>
index1.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="login-t">
  4. <image class="login-logo" :src="logoImage" mode="aspectFill"></image>
  5. </view>
  6. <view>
  7. <view class="login-m">
  8. <view class="login-item">
  9. <input type="number" v-model="mobile" :maxlength="maxMobile" placeholder="请输入手机号码" placeholder-class="login-item-i-p" />
  10. </view>
  11. <view class="login-item flc">
  12. <input class="login-item-input" :password="true" placeholder-class="login-item-i-p" type="text" v-model="pwd" placeholder="请输入密码" />
  13. </view>
  14. <view class="login-item" v-if="isCaptcha">
  15. <input class="login-item-input" placeholder-class="login-item-i-p" type="text" v-model="captcha" placeholder="输入验证码" />
  16. <img class='codeimg' :src="captchaUrl" alt="">
  17. </view>
  18. </view>
  19. <view class="login-b">
  20. <button :class="loginButtonClass" @click="loginHandler" hover-class="btn-hover">登录</button>
  21. <view class="login-other flc">
  22. <view class="fz12 item" @click="selectLoginType">
  23. 验证码登录
  24. </view>
  25. <view class="fz12 item" @click="toReg">
  26. 注册
  27. </view>
  28. </view>
  29. </view>
  30. </view>
  31. <!-- 微信浏览器里 -->
  32. <!-- #ifdef H5 -->
  33. <template v-if="weixinBrowser">
  34. <view class="fz12 g5">
  35. 第三方账号登录:
  36. </view>
  37. <view class="flc third-block">
  38. <view class="third-item" v-for="(item, key,index) in thirdPartyLogins" :key="index" @click="handleThirdLogin(item)">
  39. <image class="third-item-img" :src="getThirdLoginImg(key)" mode="aspectFill"></image>
  40. </view>
  41. </view>
  42. </template>
  43. <!-- #endif -->
  44. <!-- #ifdef APP-PLUS||APP-PLUS-NVUE -->
  45. <view class="fz12 g5">
  46. 第三方账号登录:
  47. </view>
  48. <view class="flc third-block" v-if="thirdPartyLogins.length>0">
  49. <view class="third-item" v-for="(item, key,index) in thirdPartyLogins" :key="key" @click="handleThirdLoginApp(item)">
  50. <image class="third-item-img" src="/static/image/ic-wechat.png" mode="aspectFill" v-if="item=='weixin'"></image>
  51. </view>
  52. </view>
  53. <!-- #endif -->
  54. </view>
  55. </template>
  56. <script>
  57. import { baseUrl } from '@/config/config.js'
  58. import { goBack,jumpBackPage} from '@/config/mixins.js'
  59. export default {
  60. mixins: [goBack,jumpBackPage],
  61. data() {
  62. return {
  63. maxMobile: 11,
  64. mobile: '', // 手机号
  65. pwd: '', // 密码
  66. isCaptcha: false, // 是否需要验证码
  67. captcha: '', // 输入的验证码
  68. captchaUrl: '', // 验证码图片地址
  69. btnb: 'btn btn-square btn-c btn-all', // 按钮bg
  70. weixinBrowser: false, // 是否是微信浏览器
  71. thirdPartyLogins: [], // 第三方登录列表
  72. }
  73. },
  74. onLoad(options) {
  75. if (options.invitecode) {
  76. this.$db.set('invitecode', options.invitecode)
  77. }
  78. // 判断浏览器环境
  79. this.weixinBrowser = this.$common.isWeiXinBrowser()
  80. if (this.weixinBrowser) {
  81. this.getAuths()
  82. }
  83. // #ifdef APP-PLUS||APP-PLUS-NVUE
  84. this.getAppAuths();
  85. // #endif
  86. },
  87. onShow() {
  88. if (this.$db.get('userToken')) {
  89. uni.switchTab({
  90. url:'/pages/index/index'
  91. })
  92. }
  93. },
  94. computed: {
  95. // 动态更改登录按钮bg
  96. loginButtonClass() {
  97. return this.mobile && this.mobile.length === 11 && this.pwd
  98. ? this.btnb + ' btn-b'
  99. : this.btnb
  100. },
  101. logoImage() {
  102. return this.$store.state.config.shop_logo
  103. },
  104. getThirdLoginImg(key) {
  105. return key => {
  106. if (key == 'Wxofficial') {
  107. return '/static/image/ic-wechat.png'
  108. }else if(key == 'weixin'){
  109. return '/static/image/ic-wechat.png'
  110. }
  111. }
  112. }
  113. },
  114. methods: {
  115. // 验证手机号
  116. rightMobile() {
  117. let res = {}
  118. if (!this.mobile) {
  119. res.status = false
  120. res.msg = '请输入手机号'
  121. } else if (!/^1[3456789]{1}\d{9}$/gi.test(this.mobile)) {
  122. res.status = false
  123. res.msg = '手机号格式不正确'
  124. } else if (!this.pwd) {
  125. res.status = false
  126. res.msg = '请输入密码'
  127. } else {
  128. res.status = true
  129. }
  130. return res
  131. },
  132. // 登录处理
  133. loginHandler() {
  134. if (this.mobile && this.mobile.length === 11 && this.pwd) {
  135. if (!this.rightMobile().status) {
  136. this.$common.errorToShow(this.rightMobile().msg)
  137. } else {
  138. this.toLogin()
  139. }
  140. }
  141. },
  142. // 获取验证码图片地址
  143. getCaptchaUrl() {
  144. this.captchaUrl = this.$config.apiBaseUrl + 'captcha.html'
  145. },
  146. // 去注册
  147. toReg() {
  148. this.$common.navigateTo('/pages/login/register/index')
  149. },
  150. // 去登录
  151. toLogin() {
  152. let data = {
  153. mobile: this.mobile,
  154. password: this.pwd
  155. }
  156. if (this.isCaptcha) {
  157. data.captcha = this.captcha
  158. }
  159. // 获取邀请码
  160. let invicode = this.$db.get('invitecode')
  161. if (invicode) {
  162. data.invitecode = invicode
  163. }
  164. this.$api.login(data, res => {
  165. if (res.status) {
  166. this.$db.set('userToken', res.data)
  167. this.redirectHandler()
  168. } else {
  169. this.$common.errorToShow(res.msg, () => {
  170. // 需要输入验证码 或者 验证码错误刷新
  171. if (res.data === 10013 || res.data === 10012) {
  172. this.isCaptcha = true
  173. }
  174. // 登录需要验证码
  175. if (this.isCaptcha) {
  176. this.getCaptchaUrl()
  177. }
  178. })
  179. }
  180. })
  181. },
  182. // 重定向跳转 或者返回上一个页面
  183. redirectHandler() {
  184. this.$db.del('invitecode')
  185. this.handleBack()
  186. },
  187. // 登录方式切换
  188. selectLoginType() {
  189. this.$common.redirectTo('/pages/login/login/index')
  190. },
  191. // 获取第三方登录列表
  192. getAuths() {
  193. let data = {
  194. url: baseUrl + 'wap/pages/author'
  195. }
  196. this.$api.getTrustLogin(data, res => {
  197. if (res.status) {
  198. this.thirdPartyLogins = res.data
  199. }
  200. })
  201. },
  202. // 第三方登录授权
  203. handleThirdLogin(url) {
  204. this.$common.redirectTo('')
  205. let redirect = this.$store.state.redirectPage
  206. this.$db.set('redirectPage', redirect)
  207. window.location.href = url
  208. },
  209. //获取APP信任登录
  210. getAppAuths(){
  211. let _this = this;
  212. _this.thirdPartyLogins = [];
  213. uni.getProvider({
  214. service: 'oauth',
  215. success: function (res) {
  216. if(res.errMsg == 'getProvider:ok'){
  217. _this.thirdPartyLogins = res.provider;
  218. }
  219. }
  220. });
  221. },
  222. //app第三方登录
  223. handleThirdLoginApp(type){
  224. uni.showLoading({
  225. title: '加载中'
  226. });
  227. let _this = this;
  228. uni.login({
  229. provider: type,
  230. success: function (loginRes) {
  231. // 获取用户信息
  232. uni.getUserInfo({
  233. provider: type,
  234. success: function (infoRes) {
  235. if(infoRes.errMsg == 'getUserInfo:ok'){
  236. var data = {
  237. user:infoRes.userInfo,
  238. type:type
  239. };
  240. var invitecode = _this.$db.get('invitecode')
  241. if (invitecode) {
  242. data.invitecode = invitecode
  243. }
  244. _this.$api.appTrustLogin(data,res=>{
  245. uni.hideLoading();
  246. if (res.status) {
  247. //判断是否返回了token,如果没有,就说明没有绑定账号,跳转到绑定页面
  248. if (typeof res.data.token == 'undefined') {
  249. uni.redirectTo({
  250. url: '/pages/login/login/index?user_wx_id=' + res.data.user_wx_id
  251. })
  252. } else {
  253. //登陆成功,设置token,并返回上一页
  254. _this.$db.set('userToken', res.data.token)
  255. uni.navigateBack({
  256. delta: 1
  257. })
  258. return false
  259. }
  260. } else {
  261. _this.$common.errorToShow('登录失败,请重试')
  262. }
  263. });
  264. }else{
  265. uni.hideLoading();
  266. _this.$common.errorToShow('登录失败,请重试')
  267. }
  268. }
  269. });
  270. }
  271. });
  272. }
  273. }
  274. }
  275. </script>
  276. <style lang="scss">
  277. .content {
  278. /* #ifdef H5 */
  279. height: calc(100vh - 90upx);
  280. /* #endif */
  281. /* #ifndef H5 */
  282. height: 100vh;
  283. /* #endif */
  284. background-color: #fff;
  285. padding: 0upx 100upx;
  286. }
  287. .login-t {
  288. text-align: center;
  289. padding: 50upx 0;
  290. }
  291. .login-logo {
  292. width: 180upx;
  293. height: 180upx;
  294. border-radius: 20upx;
  295. background-color: #f8f8f8;
  296. /* margin: 0 auto; */
  297. }
  298. .login-m {
  299. margin-bottom: 100upx;
  300. }
  301. .login-item {
  302. border-bottom: 2upx solid #d0d0d0;
  303. overflow: hidden;
  304. padding: 10upx;
  305. font-size: 28upx;
  306. color: #333;
  307. margin-bottom: 30upx;
  308. display: flex;
  309. align-items: center;
  310. }
  311. .login-item-input {
  312. display: inline-block;
  313. // width: 60%;
  314. flex: 1;
  315. box-sizing: border-box;
  316. }
  317. .codeimg{
  318. width: 210rpx;
  319. }
  320. .login-item .btn {
  321. display: inline-block;
  322. font-size: 28upx;
  323. border: none;
  324. width: 40%;
  325. padding: 0;
  326. line-height: 1.7;
  327. float: right;
  328. }
  329. .login-b .btn {
  330. color: #999;
  331. }
  332. .btn-b {
  333. color: #fff !important;
  334. }
  335. .registered-item {
  336. overflow: hidden;
  337. width: 100%;
  338. }
  339. .registered {
  340. float: right;
  341. }
  342. .registered-item .btn-square {
  343. color: #333;
  344. }
  345. .third-block {
  346. justify-content: center;
  347. padding-top: 40upx;
  348. .third-item {
  349. width: 80upx;
  350. height: 80upx;
  351. background: $g2;
  352. border-radius: 50%;
  353. padding: 16upx;
  354. &-img {
  355. display: block;
  356. width: 100%;
  357. height: 100%;
  358. }
  359. }
  360. }
  361. .login-other {
  362. margin-bottom: 40upx;
  363. .item {
  364. padding: 20upx 0;
  365. }
  366. }
  367. </style>
register
index.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="reg-t">
  4. <image class="reg-logo" :src="logoImage" mode="aspectFill"></image>
  5. </view>
  6. <view class="reg-m">
  7. <view class="reg-item">
  8. <input type="number" v-model="mobile" :maxlength="maxMobile" placeholder="请输入手机号码" focus placeholder-class="reg-item-i-p" />
  9. </view>
  10. <view class="reg-item flc">
  11. <input class="reg-item-input" placeholder-class="reg-item-i-p" type="text" v-model="code" placeholder="请输入验证码" />
  12. <view :class="sendCodeBtn" @click="sendCode" v-if="verification">发送验证码</view>
  13. <view class="btn btn-g" v-if="!verification">{{ timer }} 秒后重新获取</view>
  14. </view>
  15. <view class="reg-item">
  16. <input class="login-item-input" :password="true" placeholder-class="login-item-i-p" type="text" v-model="pwd" placeholder="请输入密码" />
  17. </view>
  18. </view>
  19. <view class="reg-b">
  20. <button :class="regButtonClass" @click="toReg()" hover-class="btn-hover">注册</button>
  21. </view>
  22. <view class="registered-item">
  23. <view class="btn btn-g btn-square registered" @click="toLogin">已有账号,立即登录</view>
  24. </view>
  25. </view>
  26. </template>
  27. <script>
  28. import { goBack } from '@/config/mixins.js'
  29. export default {
  30. mixins: [goBack],
  31. data() {
  32. return {
  33. maxMobile: 11,
  34. mobile: '', // 用户手机号
  35. code: '', // 短信验证码
  36. pwd: '', // 用户密码
  37. verification: true, // 通过v-show控制显示获取还是倒计时
  38. timer: 60, // 定义初始时间为60s
  39. btnb: 'btn btn-c btn-square btn-all' //按钮背景
  40. }
  41. },
  42. onLoad(options) {
  43. let _this = this
  44. _this.timer = parseInt(_this.$db.get('timer'))
  45. if (_this.timer != null && _this.timer > 0) {
  46. _this.countDown()
  47. _this.verification = false
  48. }
  49. if (options.invitecode) {
  50. this.$db.set('invitecode', options.invitecode)
  51. }
  52. },
  53. computed: {
  54. // 验证手机号
  55. rightMobile() {
  56. let res = {}
  57. if (!this.mobile) {
  58. res.status = false
  59. res.msg = '请输入手机号'
  60. } else if (!/^1[3456789]{1}\d{9}$/gi.test(this.mobile)) {
  61. res.status = false
  62. res.msg = '手机号格式不正确'
  63. } else {
  64. res.status = true
  65. }
  66. return res
  67. },
  68. // 动态更改登录按钮bg
  69. regButtonClass() {
  70. return this.mobile && this.mobile.length === 11 && this.pwd && this.code
  71. ? this.btnb + ' btn-b'
  72. : this.btnb
  73. },
  74. // 动态修改发送验证码按钮
  75. sendCodeBtn() {
  76. let btn = 'btn btn-g'
  77. if (this.mobile.length === this.maxMobile && this.rightMobile.status) {
  78. return btn + ' btn-b'
  79. } else {
  80. return btn
  81. }
  82. },
  83. logoImage() {
  84. return this.$store.state.config.shop_logo
  85. }
  86. },
  87. onShow() {
  88. let _this = this
  89. let userToken = _this.$db.get('userToken')
  90. if (userToken && userToken != '') {
  91. uni.switchTab({
  92. url: '/pages/member/index/index'
  93. })
  94. return true
  95. }
  96. _this.timer = parseInt(_this.$db.get('timer'))
  97. if (_this.timer != null && _this.timer > 0) {
  98. _this.countDown()
  99. _this.verification = false
  100. }
  101. },
  102. methods: {
  103. // 发送短信验证码
  104. sendCode() {
  105. if (!this.rightMobile.status) {
  106. this.$common.errorToShow(this.rightMobile.msg)
  107. } else {
  108. this.$common.loadToShow('发送中...')
  109. setTimeout(() => {
  110. this.$common.loadToHide()
  111. this.$api.sms({ mobile: this.mobile, code: 'reg' }, res => {
  112. if (res.status) {
  113. this.timer = 60
  114. this.verification = false
  115. this.$common.successToShow(res.msg)
  116. this.countDown() // 执行验证码计时
  117. this.btnb = 'btn btn-square btn-all btn-b'
  118. } else {
  119. this.$common.errorToShow(res.msg)
  120. }
  121. })
  122. }, 1000)
  123. }
  124. },
  125. // 验证码倒计时
  126. countDown() {
  127. let auth_timer = setInterval(() => {
  128. // 定时器设置每秒递减
  129. this.timer-- // 递减时间
  130. uni.setStorage({
  131. key: 'timer',
  132. data: this.timer,
  133. success: function() {}
  134. })
  135. if (this.timer <= 0) {
  136. this.verification = true // 60s时间结束还原v-show状态并清除定时器
  137. clearInterval(auth_timer)
  138. }
  139. }, 1000)
  140. },
  141. toReg() {
  142. if (!this.rightMobile.status) {
  143. this.$common.errorToShow(this.rightMobile.msg)
  144. } else if (!this.code) {
  145. this.$common.errorToShow('请输入短信验证码')
  146. } else if (!this.pwd) {
  147. this.$common.errorToShow('请输入登录密码')
  148. } else {
  149. let data = {
  150. mobile: this.mobile,
  151. code: this.code,
  152. password: this.pwd
  153. }
  154. // 获取邀请码
  155. let invicode = this.$db.get('invitecode')
  156. if (invicode) {
  157. data.invitecode = invicode
  158. }
  159. this.$api.smsLogin(data, res => {
  160. if (res.status) {
  161. this.$db.set('userToken', res.data)
  162. this.$common.successToShow('注册成功', () => {
  163. // 清除随机uid 和 邀请码
  164. this.$db.del('uuid')
  165. this.$db.del('invitecode')
  166. let redirect = this.$store.state.redirectPage
  167. ? this.$store.state.redirectPage
  168. : '/pages/member/index/index'
  169. this.$store.commit({
  170. type: 'redirect',
  171. page: ''
  172. })
  173. uni.reLaunch({
  174. url: redirect
  175. })
  176. })
  177. } else {
  178. this.$common.errorToShow(res.msg)
  179. }
  180. })
  181. }
  182. },
  183. toLogin() {
  184. this.$common.navigateTo('/pages/login/login/index1')
  185. }
  186. }
  187. }
  188. </script>
  189. <style lang="scss">
  190. .content {
  191. /* #ifdef H5 */
  192. height: calc(100vh - 90upx);
  193. /* #endif */
  194. /* #ifndef H5 */
  195. height: 100vh;
  196. /* #endif */
  197. background-color: #fff;
  198. padding: 0upx 100upx;
  199. }
  200. .reg-t {
  201. text-align: center;
  202. padding: 50upx 0;
  203. }
  204. .reg-logo {
  205. width: 180upx;
  206. height: 180upx;
  207. border-radius: 20upx;
  208. background-color: #f8f8f8;
  209. /* margin: 0 auto; */
  210. }
  211. .reg-m {
  212. margin-bottom: 100upx;
  213. }
  214. .reg-item {
  215. border-bottom: 2upx solid #d0d0d0;
  216. overflow: hidden;
  217. padding: 10upx;
  218. color: #333;
  219. margin-bottom: 30upx;
  220. .btn{
  221. border: none;
  222. width: 40%;
  223. text-align:right;
  224. &.btn-b {
  225. background: none;
  226. color: #333 !important;
  227. }
  228. }
  229. }
  230. .reg-item-input {
  231. flex:1;
  232. }
  233. .reg-b .btn {
  234. color: #999;
  235. }
  236. .registered-item {
  237. overflow: hidden;
  238. width: 100%;
  239. }
  240. .registered {
  241. float: right;
  242. }
  243. .btn-square {
  244. color: #333;
  245. height: 80upx;
  246. line-height: 80upx;
  247. padding:0;
  248. font-size:$fz12;
  249. }
  250. </style>

member

address
index.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="content-top">
  4. <view class='cell-group'>
  5. <view class='cell-item'>
  6. <view class='cell-item-hd'>
  7. <view class='cell-hd-title'>收货人</view>
  8. </view>
  9. <view class='cell-item-bd'>
  10. <input type="text" class='cell-bd-input' placeholder='请填写收货人姓名' v-model="name"></input>
  11. </view>
  12. </view>
  13. <view class='cell-item'>
  14. <view class='cell-item-hd'>
  15. <view class='cell-hd-title'>手机号</view>
  16. </view>
  17. <view class='cell-item-bd'>
  18. <input type="text" class='cell-bd-input' placeholder='请填写收货人手机号' v-model="mobile"></input>
  19. </view>
  20. </view>
  21. <view class='cell-item'>
  22. <view class='cell-item-hd'>
  23. <view class='cell-hd-title'>省市区</view>
  24. </view>
  25. <view class='cell-item-bd'>
  26. <input :value="pickerValue" @focus="showThreePicker"></input>
  27. <area-picker ref="areaPicker" :areaId="areaId" :defaultIndex="defaultIndex" @onConfirm="onConfirm"></area-picker>
  28. </view>
  29. <view class='cell-item-ft'>
  30. <image class='cell-ft-next icon' src='/static/image/ic-pull-down.png' @click="showThreePicker"></image>
  31. </view>
  32. </view>
  33. <view class='cell-item'>
  34. <view class='cell-item-hd'>
  35. <view class='cell-hd-title'>详细地址</view>
  36. </view>
  37. <view class='cell-item-bd'>
  38. <input type="text" class='cell-bd-input' placeholder='请填写收货详细地址' v-model="address"></input>
  39. </view>
  40. </view>
  41. <view class='cell-item' @click="defaultChange">
  42. <view class='cell-item-hd'>
  43. <view class='cell-hd-title'>设为默认</view>
  44. </view>
  45. <view class='cell-item-ft' >
  46. <label class="radio" ><radio value="1" :checked="checked" color="#FF7159"/></label>
  47. </view>
  48. </view>
  49. </view>
  50. </view>
  51. <view class="button-bottom">
  52. <button class="btn btn-square btn-w" @click="delShip" v-if="id && id != 0" hover-class="btn-hover2" :disabled='submitStatus' :loading='submitStatus'>删除</button>
  53. <button class="btn btn-square btn-b" @click="saveShip" hover-class="btn-hover2" :disabled='submitStatus' :loading='submitStatus'>保存</button>
  54. </view>
  55. </view>
  56. </template>
  57. <script>
  58. import areaPicker from "@/components/area-picker/areaPicker.vue";
  59. export default {
  60. components: {
  61. areaPicker
  62. },
  63. data() {
  64. return {
  65. id: 0,
  66. name: '',
  67. mobile: '',
  68. region: ['北京市', '北京市', '东城区'],
  69. areaId: 110101,
  70. address: '',
  71. is_def: 2,
  72. multiArray: [
  73. [],
  74. [],
  75. []
  76. ],
  77. multiIndex: [110000, 110100, 110101],
  78. checked: false,
  79. pickerValue: '',
  80. defaultIndex: [0, 0, 0],
  81. submitStatus: false
  82. }
  83. },
  84. computed: {},
  85. methods: {
  86. // 省市区联动初始化
  87. showThreePicker() {
  88. this.$refs.areaPicker.showPicker();
  89. },
  90. onConfirm(e) {
  91. let province_name = e[0].name;
  92. let city_name = e[1].name;
  93. let county_name = e[2].name;
  94. this.pickerValue = e[0].name+ " "+ e[1].name+" "+e[2].name
  95. let data = {
  96. province_name: province_name,
  97. city_name: city_name,
  98. county_name: county_name
  99. }
  100. let regionName = [province_name, city_name, county_name];
  101. this.$api.getAreaId(data, res => {
  102. if (res.status) {
  103. this.areaId = res.data
  104. } else {
  105. uni.showModal({
  106. title: '提示',
  107. content: '地区选择出现问题,请重新选择地区',
  108. showCancel: false
  109. });
  110. }
  111. });
  112. },
  113. // 信息验证
  114. checkData (data) {
  115. this.submitStatus = false;
  116. if (!data.name) {
  117. this.$common.errorToShow('请输入收货人姓名')
  118. return false
  119. } else if (!data.mobile) {
  120. this.$common.errorToShow('请输入收货人手机号')
  121. return false
  122. } else if (data.mobile.length !== 11) {
  123. this.$common.errorToShow('收货人手机号格式不正确')
  124. return false
  125. } else if (!data.area_id) {
  126. this.$common.errorToShow('请选择地区信息')
  127. return false
  128. } else if (!data.address) {
  129. this.$common.errorToShow('请输入收货地址详细信息')
  130. return false
  131. } else {
  132. return true
  133. }
  134. },
  135. //默认
  136. defaultChange(){
  137. if(this.checked){
  138. this.checked = false;
  139. this.is_def = 2;
  140. }else{
  141. this.checked = true;
  142. this.is_def = 1;
  143. }
  144. },
  145. //编辑获取收货地址信息
  146. getShipInfo() {
  147. let data = {
  148. 'id': this.id
  149. }
  150. this.$api.shipDetail(data, res => {
  151. if(res.status){
  152. let region = res.data.area_name.split(" ");
  153. this.name = res.data.name;
  154. this.mobile = res.data.mobile;
  155. this.region = region;
  156. this.areaId = res.data.area_id;
  157. this.pickerValue = this.region[0]+ " "+ this.region[1]+" "+this.region[2]
  158. this.$refs.areaPicker.init();//初始化插件
  159. this.address = res.data.address;
  160. this.is_def = res.data.is_def;
  161. if(res.data.is_def == 1){
  162. this.checked = true;
  163. }else{
  164. this.checked = false;
  165. }
  166. }else{
  167. this.$common.errorToShow('获取收货地址信息出现问题');
  168. this.submitStatus = false;
  169. }
  170. });
  171. },
  172. //删除地址
  173. delShip() {
  174. this.submitStatus = true;
  175. this.$api.removeShip({'id': this.id}, res => {
  176. if(res.status){
  177. this.$common.successToShow(res.msg, ress => {
  178. this.submitStatus = false;
  179. uni.navigateBack({
  180. delta: 1
  181. });
  182. });
  183. }else{
  184. this.$common.errorToShow(res.msg);
  185. this.submitStatus = false;
  186. }
  187. });
  188. },
  189. //存储收货地址
  190. saveShip() {
  191. this.submitStatus = true;
  192. let data = {
  193. name: this.name,
  194. address: this.address,
  195. mobile: this.mobile,
  196. is_def: this.is_def,
  197. area_id: this.areaId
  198. }
  199. if(this.id && this.id != 0){
  200. //编辑存储
  201. data.id = this.id
  202. if (this.checkData(data)) {
  203. this.$api.editShip(data, res => {
  204. if(res.status){
  205. this.$common.successToShow(res.msg, ress => {
  206. this.submitStatus = false;
  207. uni.navigateBack({
  208. delta: 1
  209. });
  210. });
  211. }else{
  212. this.$common.errorToShow(res.msg);
  213. this.submitStatus = false;
  214. }
  215. });
  216. }
  217. }else{
  218. //添加
  219. if (this.checkData(data)) {
  220. this.$api.saveUserShip(data, res => {
  221. if(res.status){
  222. this.$common.successToShow(res.msg, ress => {
  223. this.submitStatus = false;
  224. uni.navigateBack({
  225. delta: 1
  226. });
  227. });
  228. }else{
  229. this.$common.errorToShow(res.msg);
  230. this.submitStatus = false;
  231. }
  232. });
  233. }
  234. }
  235. }
  236. },
  237. onLoad(e) {
  238. if(e.ship_id){
  239. //编辑
  240. this.id = e.ship_id;
  241. this.getShipInfo();
  242. }else{
  243. //添加
  244. this.pickerValue = this.region[0]+ " "+ this.region[1]+" "+this.region[2];
  245. uni.setNavigationBarTitle({
  246. title: '添加地址'
  247. });
  248. }
  249. },
  250. onBackPress() {
  251. if (this.$refs.areaPicker.pickerShow) {
  252. this.$refs.areaPicker.closePicker();
  253. return true;
  254. }
  255. },
  256. }
  257. </script>
  258. <style>
  259. .user-head{
  260. height: 100upx;
  261. }
  262. .user-head-img{
  263. height: 90upx;
  264. width: 90upx;
  265. border-radius: 50%;
  266. }
  267. .cell-hd-title{
  268. color: #333;
  269. }
  270. .cell-item-bd{
  271. color: #666;
  272. font-size: 26upx;
  273. }
  274. .button-bottom .btn {
  275. width: 50%;
  276. }
  277. .cell-bd-input{
  278. width: 100%;
  279. }
  280. /* #ifdef MP-ALIPAY */
  281. input{
  282. font-size: 24upx;
  283. }
  284. /* #endif */
  285. </style>
list.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="content-top" v-if="list.length">
  4. <view class="uni-list-cell uni-list-cell-pd" v-for="(item, key) in list" :key="key">
  5. <view class='cell-group min-cell-group'>
  6. <view class='cell-item'>
  7. <view class='cell-item-hd' @click="isSelect(item)">
  8. <view class='cell-hd-title'>{{item.name}} <text class="phone-num">{{item.mobile}}</text></view>
  9. </view>
  10. <view class='cell-item-ft' v-show="type != 'order'">
  11. <image class='cell-ft-next icon' src='/static/image/compile.png' @click="toEdit(item.id)"></image>
  12. <text class="cell-ft-text"></text>
  13. </view>
  14. </view>
  15. <view class='cell-item' @click="isSelect(item)">
  16. <view class='cell-item-bd'>
  17. <view class="cell-bd-view">
  18. <view class="cell-tip" v-show="item.is_def === 1">默认</view>
  19. <text class="cell-bd-text">{{item.area_name + item.address}}</text>
  20. </view>
  21. </view>
  22. </view>
  23. </view>
  24. </view>
  25. </view>
  26. <view class="address-none" v-else>
  27. <image class="address-none-img" src="/static/image/order.png" mode=""></image>
  28. </view>
  29. <view class="button-bottom">
  30. <!-- #ifdef MP-WEIXIN -->
  31. <button class="btn btn-square btn-b" @click="wechatAddress" hover-class="btn-hover2">从微信获取</button>
  32. <!-- #endif -->
  33. <button class="btn btn-square btn-w" @click="toAdd()" hover-class="btn-hover2">新增收货地址</button>
  34. </view>
  35. </view>
  36. </template>
  37. <script>
  38. export default {
  39. data() {
  40. return {
  41. list: [] ,// 用户收货地址列表
  42. type: ''
  43. }
  44. },
  45. onLoad (e) {
  46. if(e.type){
  47. this.type = e.type;
  48. }
  49. },
  50. onShow () {
  51. this.userShipList();
  52. },
  53. methods: {
  54. // 获取收货地址列表
  55. userShipList () {
  56. this.$api.userShip({}, res => {
  57. if (res.status) {
  58. this.list = res.data
  59. }
  60. })
  61. },
  62. // 收货地址删除
  63. delShip (id) {
  64. this.$common.modelShow('提示', '确认删除此收货地址?', () => {
  65. let data = {
  66. id: id
  67. }
  68. this.$api.removeShip(data, res => {
  69. if (res.status) {
  70. this.$common.successToShow(res.msg, () => {
  71. this.userShipList();
  72. });
  73. } else {
  74. this.$common.errorToShow(res.msg);
  75. }
  76. })
  77. })
  78. },
  79. //编辑
  80. toEdit (id) {
  81. this.$common.navigateTo('./index?ship_id=' + id);
  82. },
  83. //添加
  84. toAdd() {
  85. this.$common.navigateTo('./index');
  86. },
  87. //选择
  88. isSelect(data) {
  89. if(this.type == 'order'){
  90. let pages = getCurrentPages();//当前页
  91. let beforePage = pages[pages.length - 2];//上个页面
  92. // #ifdef MP-ALIPAY
  93. beforePage.rootVM.userShip = data;
  94. beforePage.rootVM.params.area_id = data.area_id;
  95. // #endif
  96. // #ifdef H5
  97. beforePage.userShip = data;
  98. beforePage.params.area_id = data.area_id;
  99. // #endif
  100. // #ifdef MP-WEIXIN || APP-PLUS || APP-PLUS-NVUE
  101. beforePage.$vm.userShip = data;
  102. beforePage.$vm.params.area_id = data.area_id;
  103. // #endif
  104. uni.navigateBack({
  105. delta: 1
  106. });
  107. }
  108. },
  109. // #ifdef MP-WEIXIN
  110. wechatAddress: function () {
  111. wx.chooseAddress({
  112. success: res => {
  113. if (res.errMsg == "chooseAddress:ok") {
  114. //获取成功
  115. //存储这个收获地区信息到数据库
  116. let data = {
  117. province_name: res.provinceName,
  118. city_name: res.cityName,
  119. county_name: res.countyName,
  120. postal_code: res.postalCode
  121. };
  122. let areaId = 0;
  123. this.$api.getAreaId(data, res1 => {
  124. if (res1.status) {
  125. //存储用户收货信息
  126. let userShipId = 0;
  127. let userShipData = {
  128. area_id: res1.data,
  129. user_name: res.userName,
  130. detail_info: res.detailInfo,
  131. tel_number: res.telNumber,
  132. is_def: 2
  133. }
  134. this.$api.saveUserShipWx(userShipData, res2 => {
  135. if (res2.status) {
  136. this.$common.errorToShow('存储微信地址成功', r => {
  137. setTimeout(rp => {
  138. this.userShipList();
  139. }, 1000);
  140. });
  141. }else{
  142. uni.showModal({
  143. title: '提示',
  144. content: '存储微信地址失败',
  145. showCancel: false
  146. });
  147. }
  148. });
  149. }else{
  150. uni.showModal({
  151. title: '提示',
  152. content: '获取微信地址失败',
  153. showCancel: false
  154. });
  155. }
  156. });
  157. } else {
  158. uni.showModal({
  159. title: '提示',
  160. content: '获取微信地址失败',
  161. showCancel: false
  162. });
  163. }
  164. }
  165. });
  166. },
  167. // #endif
  168. }
  169. }
  170. </script>
  171. <style>
  172. .cell-tip{
  173. background-color: #FF7159;
  174. color: #fff;
  175. font-size: 24upx;
  176. display: inline-block;
  177. float: left;
  178. /* border-radius: 10upx; */
  179. padding: 4upx 10upx;
  180. margin-right: 10upx;
  181. transform: scale(.9);
  182. }
  183. .min-cell-group .cell-ft-text{
  184. font-size: 24upx;
  185. margin-right: 10upx;
  186. }
  187. .min-cell-group .cell-item-bd{
  188. color: #666;
  189. padding-right: 0;
  190. }
  191. .min-cell-group .default{
  192. color: #666;
  193. }
  194. .min-cell-group uni-radio .uni-radio-input{
  195. width: 36upx;
  196. height: 36upx;
  197. }
  198. .min-cell-group .default .checked-radio{
  199. display: inline-block;
  200. float: left;
  201. position: relative;
  202. bottom: 2upx;
  203. }
  204. .green{
  205. background-color: #999;
  206. }
  207. .cell-hd-title{
  208. font-size: 28upx;
  209. }
  210. .phone-num{
  211. margin-left: 20upx;
  212. color: #999;
  213. font-size: 24upx;
  214. }
  215. .address-none{
  216. text-align: center;
  217. padding: 200upx 0;
  218. }
  219. .address-none-img{
  220. width: 274upx;
  221. height: 274upx;
  222. }
  223. </style>
after_sale
detail.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="content-top">
  4. <!-- <view class="back-img">
  5. <view class="back-img-c">
  6. <view class="back-img-t">退款单状态</view>
  7. <view class="back-img-b">{{status_name}} {{refund_name}} {{reship_name}}...</view>
  8. </view>
  9. </view> -->
  10. <view class='cell-group margin-cell-group'>
  11. <view class='cell-item add-title-item'>
  12. <view class='cell-item-bd'>
  13. <view class="cell-bd-view black-text">
  14. <text class="cell-bd-text color-3">退款单状态</text>
  15. </view>
  16. <view class="cell-bd-view">
  17. <text class="cell-bd-text color-9">{{status_name}} {{refund_name}} {{reship_name}}...</text>
  18. </view>
  19. <view class="cell-bd-view">
  20. <!-- <text class="cell-bd-text">下单时间:{{ orderInfo.ctime }}</text> -->
  21. </view>
  22. </view>
  23. </view>
  24. </view>
  25. <view class='cell-group margin-cell-group'>
  26. <view class='cell-item'>
  27. <view class='cell-item-hd'><view class='cell-hd-title'>售后类型</view></view>
  28. <view class='cell-item-ft'><view class="cell-ft-p">{{type_name}}</view></view>
  29. </view>
  30. <view class='cell-item'>
  31. <view class='cell-item-hd'><view class='cell-hd-title'>退款金额</view></view>
  32. <view class='cell-item-ft'><view class="cell-ft-p red-price">{{refund}}元</view></view>
  33. </view>
  34. </view>
  35. <view class='cell-group margin-cell-group' v-if="images.length > 0">
  36. <view class='cell-item right-img'><view class='cell-item-hd'><view class='cell-hd-title'>图片凭证</view></view></view>
  37. <view class="">
  38. <view class="evaluate-c-b">
  39. <view class="goods-img-item" v-for="(item, key) in images" :key="key">
  40. <image :src="item.url" mode="aspectFit" @click="clickImg(item.url)"></image>
  41. </view>
  42. </view>
  43. </view>
  44. </view>
  45. <view class='cell-group margin-cell-group'>
  46. <view class='cell-item right-img'>
  47. <view class='cell-item-hd'>
  48. <view class='cell-hd-title'>问题描述</view>
  49. </view>
  50. </view>
  51. <view class="cell-textarea">
  52. <text v-if="reason">{{reason}}</text>
  53. <text v-else>暂无描述</text>
  54. </view>
  55. </view>
  56. <view class='cell-group margin-cell-group' v-show="status == 2 && reship_status == 1">
  57. <view class='cell-item right-img'>
  58. <view class='cell-item-hd'>
  59. <view class='cell-hd-title'>退货邮寄信息</view>
  60. </view>
  61. </view>
  62. <view class='cell-item'>
  63. <view class='cell-item-hd'>
  64. <view class='cell-hd-title'>收件人</view>
  65. </view>
  66. <view class='cell-item-bd'>
  67. <input class='cell-bd-input' type="text" disabled="false" :value="reship_info.reship_name" />
  68. </view>
  69. </view>
  70. <view class='cell-item'>
  71. <view class='cell-item-hd'>
  72. <view class='cell-hd-title'>联系方式</view>
  73. </view>
  74. <view class='cell-item-bd'>
  75. <input class='cell-bd-input' type="text" disabled="false" :value="reship_info.reship_mobile" />
  76. </view>
  77. </view>
  78. <view class='cell-item'>
  79. <view class='cell-item-hd'>
  80. <view class='cell-hd-title'>邮寄地址</view>
  81. </view>
  82. <view class='cell-item-bd'>
  83. <input class='cell-bd-input' type="text" disabled="false" :value="reship_info.reship_area + reship_info.reship_address" />
  84. </view>
  85. </view>
  86. </view>
  87. <view class='cell-group margin-cell-group' v-show="status == 2 && reship_status == 1">
  88. <view class='cell-item'>
  89. <view class='cell-item-hd'>
  90. <view class='cell-hd-title'>快递公司</view>
  91. </view>
  92. <view class='cell-item-bd'>
  93. <input class='cell-bd-input' type="text" v-model="logi_code" placeholder="请填写快递公司名称"/>
  94. </view>
  95. </view>
  96. <view class='cell-item'>
  97. <view class='cell-item-hd'>
  98. <view class='cell-hd-title'>物流单号</view>
  99. </view>
  100. <view class='cell-item-bd'>
  101. <input class='cell-bd-input' type="text" v-model="logi_no" placeholder="请填写物流单号" />
  102. </view>
  103. </view>
  104. </view>
  105. <view class='cell-group margin-cell-group' v-show="status == 2 && reship_status > 1">
  106. <view class='cell-item'>
  107. <view class='cell-item-hd'>
  108. <view class='cell-hd-title'>快递公司</view>
  109. </view>
  110. <view class='cell-item-bd'>
  111. <input class='cell-bd-input' type="text" disabled="false" :value="logi_code"/>
  112. </view>
  113. </view>
  114. <view class='cell-item'>
  115. <view class='cell-item-hd'>
  116. <view class='cell-hd-title'>物流单号</view>
  117. </view>
  118. <view class='cell-item-bd'>
  119. <input class='cell-bd-input' type="text" disabled="false" :value="logi_no"/>
  120. </view>
  121. </view>
  122. </view>
  123. </view>
  124. <view class="button-bottom" v-show="status == 2 && reship_status == 1">
  125. <button class="btn btn-b" @click="submitBtn" :disabled='submitStatus' :loading='submitStatus'>提交</button>
  126. </view>
  127. <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)">
  128. <button class="btn btn-b" @click="repeat">再次申请售后</button>
  129. </view>
  130. </view>
  131. </template>
  132. <script>
  133. export default {
  134. data() {
  135. return {
  136. delivers: ["请选择物流公司","顺丰", "中通", "圆通","韵达"],
  137. deliverIndex: 0,
  138. type_name:'', //售后类型显示
  139. refund:0, //退款金额
  140. images:[], //图片
  141. reason: '暂无', //问题描述
  142. ttype:1, //售后类型
  143. status:1, //售后单状态
  144. status_name: '审核中', //售后单状态文字描述
  145. reship_status:0, //退货单状态
  146. reship_name:'',
  147. refund_status:0, //退款单状态
  148. refund_name:'',
  149. reship_info:[], //退货单明细,如果售后单未审核呢,那么显示的是售后单明细,如果售后单审核通过了,显示退款单明细
  150. items:[], //退货明细
  151. mark:"暂无", //拒绝原因
  152. logi_no:'', //回填物流信息
  153. logi_code:'', //物流公司
  154. reship_id:'',
  155. mode: 'aspectFill',
  156. order_id: '', //订单号
  157. order_status: '', //订单状态
  158. submitStatus: false
  159. }
  160. },
  161. methods: {
  162. //提交按钮
  163. submitBtn() {
  164. this.submitStatus = true;
  165. if (this.logino == '') {
  166. this.$common.errorToShow('请输入退货快递信息');
  167. this.submitStatus = false;
  168. return false;
  169. }
  170. let data = {
  171. logi_no: this.logi_no,
  172. logi_code:this.logi_code,
  173. reship_id: this.reship_id,
  174. };
  175. this.$api.sendShip(data, res => {
  176. if (res.status) {
  177. this.$common.successToShow('提交成功', ress => {
  178. this.submitStatus = false;
  179. uni.navigateBack({
  180. delta: 1
  181. });
  182. });
  183. } else {
  184. this.$common.errorToShow(res.msg);
  185. this.submitStatus = false;
  186. }
  187. });
  188. },
  189. repeat() {
  190. this.$common.navigateTo('../after_sale/index?order_id='+this.order_id);
  191. },
  192. // 图片点击放大
  193. clickImg (img) {
  194. // 预览图片
  195. uni.previewImage({
  196. urls: img.split()
  197. });
  198. }
  199. },
  200. //页面加载
  201. onLoad(options) {
  202. let data = {
  203. aftersales_id: options.aftersales_id
  204. }
  205. this.$api.afterSalesInfo(data, res => {
  206. if(res.status){
  207. let info = res.data.info;
  208. if (info.type == 1){
  209. this.ttype = 1;
  210. this.type_name = '仅退款';
  211. }else{
  212. this.ttype = 2;
  213. this.type_name = '退款退货';
  214. }
  215. this.refund = info.refund;
  216. this.images = info.images;
  217. this.reason = info.reason;
  218. this.reship_info = res.data.reship;
  219. this.order_id = info.order_id;
  220. this.order_status = info.order_status;
  221. if(info.mark){
  222. this.mark = info.mark;
  223. }
  224. if(info.status == 1){
  225. this.status = 1;
  226. this.status_name = '审核中';
  227. }else if(info.status == 2){
  228. this.status = 2;
  229. this.status_name = '申请通过';
  230. //退款单状态
  231. if (info.bill_refund) {
  232. if (info.bill_refund.status == 1) {
  233. this.refund_status = 1;
  234. this.refund_name = '退款中';
  235. } else if (info.bill_refund.status == 2) {
  236. this.refund_status = 2;
  237. this.refund_name = '退款成功';
  238. }
  239. }
  240. //退货单状态
  241. if(info.bill_reship){
  242. this.reship_id = info.bill_reship.reship_id
  243. if(info.bill_reship.status == 1) {
  244. this.reship_status = 1;
  245. this.reship_name = '待发退货';
  246. } else if (info.bill_reship.status == 2) {
  247. this.reship_status = 2;
  248. this.reship_name = '待收退货';
  249. this.logi_no = info.bill_reship.logi_no;
  250. this.logi_code = info.bill_reship.logi_code;
  251. } else {
  252. this.reship_status = 3;
  253. this.reship_name = '已收退货';
  254. this.logi_no = info.bill_reship.logi_no;
  255. this.logi_code = info.bill_reship.logi_code;
  256. }
  257. }
  258. }else{
  259. this.status = 3;
  260. this.status_name = '申请驳回';
  261. }
  262. //售后单明细,如果有退货单明细,就用退货单明细,否则就用售后单明细
  263. // if(info.bill_reship.items){
  264. // page.data.items = info.bill_reship.items;
  265. // }else{
  266. // page.data.items = info.items;
  267. // }
  268. } else {
  269. this.$common.errorToShow(res.msg);
  270. }
  271. });
  272. }
  273. }
  274. </script>
  275. <style>
  276. .back-img{
  277. width: 100%;
  278. height: 200upx;
  279. position: relative;
  280. background-color: #FF7159;
  281. }
  282. .back-img image{
  283. width: 100%;
  284. height: 100%;
  285. position: absolute;
  286. }
  287. .back-img-c{
  288. width: 100%;
  289. height: 100%;
  290. color: #fff;
  291. position: relative;
  292. z-index: 99;
  293. padding: 50upx;
  294. }
  295. .back-img-t{
  296. font-size: 32upx;
  297. }
  298. .back-img-b{
  299. font-size: 24upx;
  300. }
  301. .list-goods-name{
  302. width: 100% !important;
  303. }
  304. .invoice-type .uni-list-cell{
  305. display: inline-block;
  306. font-size: 26upx;
  307. color: #333;
  308. position: relative;
  309. margin-left: 50upx;
  310. }
  311. .invoice-type .uni-list-cell>view{
  312. display: inline-block;
  313. }
  314. .invoice-type-icon{
  315. position: absolute;
  316. top: 50%;
  317. transform: translateY(-50%);
  318. }
  319. .invoice-type-c{
  320. margin-left: 50upx;
  321. line-height: 2;
  322. }
  323. .cell-item-ft .cell-bd-input{
  324. text-align: right;
  325. width: 500upx;
  326. font-size: 28upx;
  327. }
  328. .cell-item-bd .cell-bd-input{
  329. width: 100%;
  330. overflow: hidden;
  331. text-overflow: ellipsis;
  332. white-space: nowrap;
  333. }
  334. .right-img{
  335. border-bottom: 0;
  336. }
  337. .cell-textarea{
  338. padding: 0 26upx 20upx;
  339. font-size: 26upx;
  340. color: #333;
  341. word-wrap: break-word;
  342. }
  343. .evaluate-c-b{
  344. overflow: hidden;
  345. padding: 0 20upx;
  346. }
  347. .upload-img{
  348. width: 146upx;
  349. height: 146upx;
  350. margin: 14upx;
  351. text-align: center;
  352. color: #999999;
  353. font-size: 22upx;
  354. border: 2upx solid #E1E1E1;
  355. border-radius: 4upx;
  356. display: inline-block;
  357. float: left;
  358. padding: 24upx 0;
  359. }
  360. .goods-img-item{
  361. width: 174upx;
  362. height: 174upx;
  363. padding: 14upx;
  364. float: left;
  365. position: relative;
  366. }
  367. .goods-img-item:nth-child(4n){
  368. margin-right: 0;
  369. }
  370. .goods-img-item image{
  371. width: 100%;
  372. height: 100%;
  373. }
  374. .del{
  375. width: 30upx !important;
  376. height: 30upx !important;
  377. position: absolute;
  378. right: 0;
  379. top: 0;
  380. z-index: 999;
  381. }
  382. .black-text .cell-bd-text{
  383. font-size: 28upx;
  384. }
  385. </style>
index.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <form @submit="submit" report-submit='true'>
  4. <view class="content-top">
  5. <view class="img-list cart-list">
  6. <checkbox-group class="cart-checkbox" @change="checkboxChange">
  7. <view class="cart-checkbox-item" v-for="(item, key) in items" :key="key">
  8. <label class="uni-list-cell uni-list-cell-pd">
  9. <view class="cart-checkbox-c"><checkbox :value='item.id' :checked="item.checked" color="#FF7159"/></view>
  10. <view class="img-list-item">
  11. <image class="img-list-item-l little-img have-none" :src="item.image_url" mode="aspectFill"></image>
  12. <view class="img-list-item-r little-right">
  13. <view class="little-right-t">
  14. <view class="goods-name list-goods-name">{{item.name}}</view>
  15. </view>
  16. <view class="goods-item-c">
  17. <view class="goods-buy">
  18. <!-- 商品规格 -->
  19. <view class="goods-salesvolume">
  20. {{item.addon}} x{{item.nums}}
  21. </view>
  22. </view>
  23. </view>
  24. </view>
  25. </view>
  26. </label>
  27. </view>
  28. </checkbox-group>
  29. </view>
  30. <view class='cell-group margin-cell-group'>
  31. <view class='cell-item'>
  32. <view class='cell-item-hd'>
  33. <view class='cell-hd-title'>服务类型</view>
  34. </view>
  35. <view class='cell-item-ft'>
  36. <view class="uni-form-item uni-column invoice-type">
  37. <!-- <radio-group class="uni-list" @change="radioChange">
  38. <label class="uni-list-cell uni-list-cell-pd" v-for="(item,index) in type_list" :key="index">
  39. <view>
  40. <radio :id="item.name" :value="item.name" :checked="item.checked"></radio>
  41. </view>
  42. <view>
  43. <label class="label-2-text" :for="item.name">
  44. <text>{{item.value}}</text>
  45. </label>
  46. </view>
  47. </label>
  48. </radio-group> -->
  49. <!-- #ifndef MP-ALIPAY -->
  50. <radio-group class="uni-list" @change="radioChange">
  51. <label class="uni-list-cell uni-list-cell-pd" v-for="(item, index) in type_list" :key="index">
  52. <view class="invoice-type-icon">
  53. <radio class="a-radio" :id="item.name" :value="item.value" :checked="item.checked" :disabled="item.disabled"></radio>
  54. </view>
  55. <view class="invoice-type-c">
  56. <label class="label-2-text" :for="item.name">
  57. <text>{{item.name}}</text>
  58. </label>
  59. </view>
  60. </label>
  61. </radio-group>
  62. <!-- #endif -->
  63. <!-- #ifdef MP-ALIPAY -->
  64. <jhlable></jhlable>
  65. <!-- #endif -->
  66. </view>
  67. </view>
  68. </view>
  69. <view class='cell-item'>
  70. <view class='cell-item-hd'>
  71. <view class='cell-hd-title'>退款金额</view>
  72. </view>
  73. <view class='cell-item-ft'>
  74. <input class='cell-bd-input red-price' v-model="refund" :disabled="refund_input_noedit"></input>
  75. </view>
  76. </view>
  77. </view>
  78. <view class='cell-group margin-cell-group'>
  79. <view class='cell-item right-img'>
  80. <view class='cell-item-hd'>
  81. <view class='cell-hd-title'>上传凭证</view>
  82. </view>
  83. </view>
  84. <view class="">
  85. <view class="evaluate-c-b">
  86. <view class="goods-img-item" v-for="(item, key) in images" :key="key">
  87. <image class="del" src="/static/image/del.png" mode="" @click="delImage(item)"></image>
  88. <image class="" :src="item.url" mode="" @click="clickImg(item.url)"></image>
  89. </view>
  90. <view class="upload-img" v-show="isImage" @click="upImage">
  91. <image class="icon" src="/static/image/camera.png" mode=""></image>
  92. <view class="">上传照片</view>
  93. </view>
  94. </view>
  95. </view>
  96. </view>
  97. <view class='cell-group margin-cell-group'>
  98. <view class='cell-item right-img'>
  99. <view class='cell-item-hd'>
  100. <view class='cell-hd-title'>问题描述</view>
  101. </view>
  102. </view>
  103. <view class="cell-textarea ">
  104. <textarea v-model="reason" placeholder="请您在此描述问题(最多200字)" maxlength="200"/>
  105. </view>
  106. </view>
  107. </view>
  108. <view class="button-bottom">
  109. <button class="btn btn-b btn-square" formType="submit" :disabled='submitStatus' :loading='submitStatus'>提交</button>
  110. </view>
  111. </form>
  112. </view>
  113. </template>
  114. <script>
  115. import jhlable from '@/components/jihai-lable.vue'
  116. export default {
  117. data() {
  118. return {
  119. type_list: [
  120. { value: '1', name: '仅退款', checked: true, disabled: false },
  121. { value: '2', name: '退货退款', checked: false, disabled:false },
  122. ],
  123. order_id:'',
  124. items:[], //退货明细
  125. item_ids:[], //选择的退货
  126. aftersale_type:1, //售后类型1退款,2退款退货
  127. refund:0, //退款金额,等于已支付的金额减去已退款的金额
  128. refund_show:0,
  129. images:[], //图片
  130. reason:'', //原因
  131. image_max: 5, //用于前台判断上传图片按钮是否显示
  132. refund_input_noedit: true,
  133. mode: 'aspectFill',
  134. submitStatus: false
  135. }
  136. },
  137. components: { jhlable },
  138. computed: {
  139. isImage() {
  140. let num = this.image_max - this.images.length;
  141. if(num > 0) {
  142. return true;
  143. }else{
  144. return false;
  145. }
  146. }
  147. },
  148. methods: {
  149. // 单选框点击切换
  150. radioChange: function(evt) {
  151. this.type_list.forEach(item => {
  152. if (item.value === evt.target.value) {
  153. item.checked = true;
  154. this.aftersale_type = evt.target.value;
  155. }else{
  156. item.checked = false;
  157. }
  158. });
  159. if(this.type_list[0].checked){
  160. this.refund_input_noedit = true;
  161. }else{
  162. this.refund_input_noedit = false;
  163. }
  164. },
  165. //订单商品信息
  166. getOrderInfo() {
  167. let data = {
  168. order_id: this.order_id
  169. }
  170. this.$api.afterSalesStatus(data, res => {
  171. if (res.status) {
  172. //如果不是未支付的,已取消的,已完成的状态,就都可以售后
  173. if (res.data.text_status != 1 && res.data.text_status != 6 && res.data.text_status != 7){
  174. //判断是已付款未发货,如果是,就禁用退货
  175. let type_list = this.type_list;
  176. if (res.data.text_status == 2){
  177. type_list[1].disabled = true;
  178. }
  179. //设置已选中的商品
  180. let nums = 0;
  181. for(var i=0;i<res.data.items.length;i++){
  182. // if(res.data.items[i].sendnums > res.data.items[i].reship_nums){
  183. // nums = res.data.items[i].sendnums - res.data.items[i].reship_nums;
  184. // }
  185. res.data.items[i].id = res.data.items[i].id.toString();
  186. nums = res.data.items[i].nums;
  187. res.data.items[i].checked = true;
  188. this.item_ids = this.item_ids.concat({ id: res.data.items[i].id, nums: nums });
  189. }
  190. this.items = res.data.items;
  191. this.refund = res.data.payed - res.data.refunded;
  192. this.refund_show = res.data.payed - res.data.refunded;
  193. this.type_list = type_list;
  194. }else{
  195. this.$common.errorToBack('订单不可以进行售后');
  196. }
  197. } else {
  198. this.$common.errorToBack('没有找到此订单');
  199. }
  200. });
  201. },
  202. //退货商品选择
  203. checkboxChange (e) {
  204. let nums = 0;
  205. this.item_ids = [];
  206. for (var i = 0; i < e.detail.value.length; i++) {
  207. let k = e.detail.value[i];
  208. for(var j = 0; j < this.items.length; j++){
  209. if(this.items[j].id == k) {
  210. if(this.items[j].sendnums > this.items[j].reship_nums) {
  211. nums = this.items[j].sendnums - this.items[j].reship_nums;
  212. this.item_ids = this.item_ids.concat({ id: k, nums: nums });
  213. }
  214. }
  215. }
  216. }
  217. },
  218. //提交
  219. submit(e) {
  220. this.submitStatus = true;
  221. let images = [];
  222. for(var i = 0; i<this.images.length; i++) {
  223. images = images.concat(this.images[i].image_id);
  224. }
  225. //判断退款金额
  226. let reg = /^[0-9]+(.[0-9]{1,2})?$/;
  227. if (!reg.test(this.refund)) {
  228. this.$common.errorToShow('请输入正确金额');
  229. this.submitStatus = false;
  230. return false;
  231. } else {
  232. if (this.refund > this.refund_show) {
  233. this.$common.errorToShow('退款金额过大');
  234. this.submitStatus = false;
  235. return false;
  236. }
  237. }
  238. //组装数据,提交数据
  239. let data = {
  240. order_id:this.order_id,
  241. type: this.aftersale_type,
  242. items:this.item_ids,
  243. images:images,
  244. refund: this.refund,
  245. reason:this.reason
  246. };
  247. // #ifdef MP-WEIXIN
  248. data['formId'] = e.detail.formId;
  249. // #endif
  250. this.$api.addAfterSales(data, res => {
  251. if(res.status){
  252. this.$common.successToShow('提交成功', ress => {
  253. this.submitStatus = false;
  254. uni.navigateBack({
  255. delta: 1
  256. });
  257. });
  258. }else{
  259. this.$common.errorToShow(res.msg);
  260. this.submitStatus = false;
  261. }
  262. });
  263. },
  264. //上传图片
  265. upImage() {
  266. let num = this.image_max - this.images.length;
  267. if(num > 0){
  268. this.$api.uploadImage(num, res => {
  269. if(res.status){
  270. this.images.push(res.data);
  271. this.$common.successToShow(res.msg);
  272. }else{
  273. this.$common.errorToShow(res.msg);
  274. }
  275. });
  276. }
  277. },
  278. //删除图片
  279. delImage(e) {
  280. let newImages = [];
  281. for(var i = 0; i < this.images.length; i++) {
  282. if(this.images[i].image_id != e.image_id){
  283. newImages.push(this.images[i]);
  284. }
  285. }
  286. this.images = newImages;
  287. },
  288. // 图片点击放大
  289. clickImg (img) {
  290. // 预览图片
  291. uni.previewImage({
  292. urls: img.split()
  293. });
  294. }
  295. },
  296. onLoad(e) {
  297. this.order_id = e.order_id;
  298. this.getOrderInfo();
  299. }
  300. }
  301. </script>
  302. <style>
  303. .list-goods-name{
  304. width: 100% !important;
  305. }
  306. .cart-checkbox-item{
  307. position: relative;
  308. }
  309. .invoice-type .uni-list-cell{
  310. display: inline-block;
  311. font-size: 26upx;
  312. color: #333;
  313. position: relative;
  314. margin-left: 50upx;
  315. }
  316. .invoice-type .uni-list-cell>view{
  317. display: inline-block;
  318. }
  319. .invoice-type-icon{
  320. position: absolute;
  321. top: 50%;
  322. transform: translateY(-50%);
  323. }
  324. .invoice-type-c{
  325. margin-left: 50upx;
  326. line-height: 2;
  327. }
  328. .cell-item-ft .cell-bd-input{
  329. text-align: right;
  330. width: 500upx;
  331. font-size: 28upx;
  332. }
  333. .right-img{
  334. border-bottom: 0;
  335. }
  336. .cell-textarea{
  337. padding: 0 26upx 20upx;
  338. }
  339. .cell-textarea textarea{
  340. width: 100%;
  341. height: 200upx;
  342. font-size: 26upx;
  343. color: #333;
  344. }
  345. .evaluate-c-b{
  346. overflow: hidden;
  347. padding: 0 20upx;
  348. }
  349. .upload-img{
  350. width: 146upx;
  351. height: 146upx;
  352. margin: 14upx;
  353. text-align: center;
  354. color: #999999;
  355. font-size: 22upx;
  356. border: 2upx solid #E1E1E1;
  357. border-radius: 4upx;
  358. display: inline-block;
  359. float: left;
  360. padding: 24upx 0;
  361. }
  362. .goods-img-item{
  363. width: 174upx;
  364. height: 174upx;
  365. padding: 14upx;
  366. float: left;
  367. position: relative;
  368. }
  369. .goods-img-item:nth-child(4n){
  370. margin-right: 0;
  371. }
  372. .goods-img-item image{
  373. width: 100%;
  374. height: 100%;
  375. }
  376. .del{
  377. width: 30upx !important;
  378. height: 30upx !important;
  379. position: absolute;
  380. right: 0;
  381. top: 0;
  382. z-index: 999;
  383. }
  384. /* #ifdef MP-ALIPAY */
  385. /* #endif */
  386. </style>
list.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="order-list">
  4. <view class="goods-detail" v-for="(item, key) in order" :key="key" v-if="item.order && item.order.items">
  5. <view class="order-item">
  6. <view class='cell-group'>
  7. <view class='cell-item'>
  8. <view class='cell-item-hd'>
  9. <view class='cell-hd-title'>售后单号:{{item.aftersales_id}}</view>
  10. <button class='btn btn-g btn-small' hover-class="btn-hover" @click="copyData(item.aftersales_id)">复制</button>
  11. </view>
  12. <view class='cell-item-ft'>
  13. <text class='cell-ft-text' v-if="item.status == 1">待审核</text>
  14. <text class='cell-ft-text' v-else-if="item.status == 2">审核通过</text>
  15. <text class='cell-ft-text' v-else-if="item.status == 3">审核拒绝</text>
  16. </view>
  17. </view>
  18. </view>
  19. <view class='img-list' v-if="item.order && item.order.items">
  20. <view class='img-list-item' v-for="(v, k) in item.order.items" :key="k" @click="showOrder(item.aftersales_id)">
  21. <image class='img-list-item-l little-img' :src='v.image_url' mode='aspectFill'></image>
  22. <view class='img-list-item-r little-right'>
  23. <view class='little-right-t'>
  24. <view class='goods-name list-goods-name'>{{v.name}}</view>
  25. <view class='goods-price'>¥{{v.price}}</view>
  26. </view>
  27. <view class='goods-item-c'>
  28. <view class='goods-buy'>
  29. <view class='goods-salesvolume' v-if="v.addon">{{v.addon}}</view>
  30. <view class='goods-num'>× {{v.nums}}</view>
  31. </view>
  32. </view>
  33. </view>
  34. </view>
  35. </view>
  36. <!-- <view class='cell-group'>
  37. <view class='cell-item'>
  38. <view class='cell-item-ft goods-num'>
  39. <text class='cell-ft-text'>合计<text class="red-price">¥{{item.order.order_amount}}(含运费¥{{item.order.cost_freight}})</text></text>
  40. <text class='cell-ft-text'>共计{{item.countnum}}件商品</text>
  41. </view>
  42. </view>
  43. </view> -->
  44. <view class='order-list-button'>
  45. <button class='btn btn-circle btn-b' @click="showOrder(item.aftersales_id)">查看详情</button>
  46. </view>
  47. </view>
  48. </view>
  49. <uni-load-more :status="loadStatus"></uni-load-more>
  50. </view>
  51. </view>
  52. </template>
  53. <script>
  54. import {
  55. tools
  56. } from '@/config/mixins.js'
  57. import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue'
  58. export default {
  59. mixins: [tools],
  60. components: {
  61. uniLoadMore
  62. },
  63. data() {
  64. return {
  65. order: [], //订单列表
  66. page: 1, //当前页
  67. limit: 5, //每页显示几条
  68. loadStatus: 'more'
  69. }
  70. },
  71. onShow() {
  72. this.getOrderList();
  73. },
  74. onReachBottom () {
  75. if (this.loadStatus === 'more') {
  76. this.getOrderList()
  77. }
  78. },
  79. methods: {
  80. //获取订单数据
  81. getOrderList() {
  82. let data = {};
  83. this.loadStatus = 'loading'
  84. data['page'] = this.page;
  85. data['limit'] = this.limit;
  86. this.$api.afterSalesList(data, res => {
  87. let orderList = this.dataFormat(res.data.list);
  88. this.order = this.order.concat(orderList);
  89. this.page = res.data.page*1+1;
  90. let allpage = res.data.total_page;
  91. if(allpage < this.page){
  92. this.loadStatus = 'noMore'
  93. }else{
  94. this.loadStatus = 'more'
  95. }
  96. });
  97. },
  98. //数据格式处理
  99. dataFormat(data) {
  100. for (var i = 0; i < data.length; i++) {
  101. let countnum = 0
  102. if(data[i].order && data[i].order.items){
  103. for (var j = 0; j < data[i].order.items.length; j++) {
  104. countnum += data[i].order.items[j].nums;
  105. }
  106. data[i].countnum = countnum;
  107. }
  108. }
  109. return data;
  110. },
  111. //查看详情
  112. showOrder(aftersales_id) {
  113. this.$common.navigateTo('detail?aftersales_id=' + aftersales_id);
  114. }
  115. },
  116. }
  117. </script>
  118. <style>
  119. .segmented-control {
  120. width: 100%;
  121. background-color: #fff;
  122. position: fixed;
  123. top: 88upx;
  124. z-index: 999;
  125. }
  126. .segmented-control-item{
  127. line-height: 70upx;
  128. }
  129. .order-list{
  130. /* margin-top: 64upx; */
  131. }
  132. .order-item{
  133. margin-bottom: 20upx;
  134. }
  135. .img-list{
  136. margin-top: 2upx;
  137. }
  138. .cell-group,.img-list-item {
  139. background-color: #fff;
  140. }
  141. .cell-hd-title{
  142. font-size: 22upx;
  143. color: #666;
  144. }
  145. .cell-ft-text{
  146. top: 0;
  147. font-size: 22upx;
  148. color: #333;
  149. }
  150. .order-list-button{
  151. width: 100%;
  152. background-color: #fff;
  153. text-align: right;
  154. padding: 10upx 26upx;
  155. }
  156. .order-list-button .btn{
  157. height: 50upx;
  158. line-height: 50upx;
  159. }
  160. .order-list-button .btn-w{
  161. margin-left: 20upx;
  162. }
  163. .goods-num .cell-ft-text{
  164. color: #999;
  165. }
  166. .goods-num .cell-ft-text:first-child{
  167. margin-left: 10upx;
  168. }
  169. .order-none{
  170. text-align: center;
  171. padding: 200upx 0;
  172. }
  173. .order-none-img{
  174. width: 274upx;
  175. height: 274upx;
  176. }
  177. </style>
balance
add_bankcard.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="content-top">
  4. <view class='cell-group'>
  5. <view class='cell-item'>
  6. <view class='cell-item-hd'>
  7. <view class='cell-hd-title'>银行卡号</view>
  8. </view>
  9. <view class='cell-item-bd'>
  10. <input type="number" class='cell-bd-input' v-model="cardNumber" focus @blur="checkCard()" placeholder='请输入银行卡号'></input>
  11. </view>
  12. </view>
  13. <view class='cell-item'>
  14. <view class='cell-item-hd'>
  15. <view class='cell-hd-title'>持卡人</view>
  16. </view>
  17. <view class='cell-item-bd'>
  18. <input type="text" class='cell-bd-input' v-model="name" placeholder='请输入持卡人姓名'></input>
  19. </view>
  20. </view>
  21. <view class='cell-item'>
  22. <view class='cell-item-hd'>
  23. <view class='cell-hd-title'>银行名称</view>
  24. </view>
  25. <view class='cell-item-bd'>
  26. <input type="text" class='cell-bd-input' :disabled="true" v-model="bankName"></input>
  27. </view>
  28. </view>
  29. <view class='cell-item'>
  30. <view class='cell-item-hd'>
  31. <view class='cell-hd-title'>银行卡类型</view>
  32. </view>
  33. <view class='cell-item-bd'>
  34. <input type="text" class='cell-bd-input' :disabled="true" v-model='cardTypeName'></input>
  35. </view>
  36. </view>
  37. <view class='cell-item'>
  38. <view class='cell-item-hd'>
  39. <view class='cell-hd-title'>开户行名</view>
  40. </view>
  41. <view class='cell-item-bd'>
  42. <input type="text" class='cell-bd-input' v-model="accountBank" placeholder='请输入开户银行名'></input>
  43. </view>
  44. </view>
  45. <view class='cell-item'>
  46. <view class='cell-item-hd'>
  47. <view class='cell-hd-title'>开户行地址</view>
  48. </view>
  49. <view class='cell-item-bd'>
  50. <input :value="pickerValue" @focus="showThreePicker"></input>
  51. <area-picker ref="areaPicker" :areaId="areaId" :defaultIndex="defaultIndex" @onConfirm="onConfirm"></area-picker>
  52. </view>
  53. <view class='cell-item-ft'>
  54. <image class='cell-ft-next icon' src='/static/image/ic-pull-down.png' @click="showThreePicker"></image>
  55. </view>
  56. </view>
  57. <view class='cell-item'>
  58. <view class='cell-item-hd'>
  59. <view class='cell-hd-title'>设为默认</view>
  60. </view>
  61. <view @click="defaultChange">
  62. <view class='cell-item-ft'>
  63. <label class="radio"><radio value="1" :checked="checked" color="#333"/></label>
  64. </view>
  65. </view>
  66. </view>
  67. </view>
  68. </view>
  69. <view class="button-bottom">
  70. <!-- <button class="btn btn-square btn-w" @click="delShip" v-show="id && id != 0" hover-class="btn-hover2">删除</button> -->
  71. <button class="btn btn-square btn-b" @click="addCard" hover-class="btn-hover2" :disabled='submitStatus' :loading='submitStatus'>保存</button>
  72. </view>
  73. </view>
  74. </template>
  75. <script>
  76. import areaPicker from "@/components/area-picker/areaPicker.vue";
  77. export default {
  78. components: {
  79. areaPicker
  80. },
  81. data() {
  82. return {
  83. bankName: '', // 银行名称
  84. cardType: 1, // 卡类型
  85. cardTypeName: '', // 卡片类型
  86. bankCode: '', // 银行缩写码
  87. accountBank: '', // 开户行
  88. cardNumber: '', // 银行卡号
  89. name: '', // 开户人姓名
  90. mobile: '', //
  91. region: ['北京市', '北京市', '东城区'],
  92. areaId: 110101,
  93. address: '',
  94. is_def: 2,
  95. checked: false,
  96. pickerValue: '',
  97. defaultIndex: [0, 0, 0],
  98. submitStatus: false
  99. }
  100. },
  101. computed: {},
  102. methods: {
  103. // 省市区联动初始化
  104. showThreePicker() {
  105. this.$refs.areaPicker.showPicker();
  106. },
  107. // 选择收货地址
  108. onConfirm(e) {
  109. let province_name = e[0].name;
  110. let city_name = e[1].name;
  111. let county_name = e[2].name;
  112. this.pickerValue = e[0].name+ " "+ e[1].name+" "+e[2].name
  113. let data = {
  114. province_name: province_name,
  115. city_name: city_name,
  116. county_name: county_name
  117. }
  118. let regionName = [province_name, city_name, county_name];
  119. this.$api.getAreaId(data, res => {
  120. if (res.status) {
  121. this.areaId = res.data
  122. } else {
  123. uni.showModal({
  124. title: '提示',
  125. content: '地区选择出现问题,请重新选择地区',
  126. showCancel: false
  127. });
  128. }
  129. });
  130. },
  131. // 选择/取消默认
  132. defaultChange () {
  133. this.checked = !this.checked
  134. this.is_def = this.is_def === 1 ? 2 : 1
  135. },
  136. //存储收货地址
  137. saveShip() {
  138. if(this.id && this.id != 0){
  139. //编辑存储
  140. let data = {
  141. 'id': this.id,
  142. 'name': this.name,
  143. 'address': this.address,
  144. 'mobile': this.mobile,
  145. 'is_def': this.is_def
  146. }
  147. data['area_id'] = this.areaId,
  148. this.$api.editShip(data, res => {
  149. if(res.status){
  150. this.$common.successToShow('编辑成功', function(){
  151. uni.navigateBack({
  152. delta: 1
  153. });
  154. });
  155. }else{
  156. this.$common.errorToShow(res.msg);
  157. }
  158. });
  159. }else{
  160. //添加
  161. let data = {
  162. 'area_id': this.areaId,
  163. 'name': this.name,
  164. 'address': this.address,
  165. 'mobile': this.mobile,
  166. 'is_def': this.is_def
  167. }
  168. this.$api.saveUserShip(data, res => {
  169. if(res.status){
  170. this.$common.successToShow('添加成功', function(){
  171. uni.navigateBack({
  172. delta: 1
  173. });
  174. });
  175. }else{
  176. this.$common.errorToShow(res.msg);
  177. }
  178. });
  179. }
  180. },
  181. // 判断获取银行卡类型
  182. checkCard () {
  183. if (this.cardNumber) {
  184. let data = {
  185. card_code: this.cardNumber
  186. }
  187. this.$api.getBankCardOrganization(data, res => {
  188. if (res.status) {
  189. let data = res.data
  190. this.bankName = data.name
  191. this.cardType = data.type
  192. this.bankCode = data.bank_code
  193. this.cardTypeName = data.type_name
  194. } else {
  195. this.$common.errorToShow(res.msg, () => {
  196. this.bankCode = this.bankName = this.cardType = this.cardTypeName = ''
  197. })
  198. }
  199. })
  200. } else {
  201. this.bankCode = this.bankName = this.cardType = this.cardTypeName = ''
  202. }
  203. },
  204. // 添加银行卡
  205. addCard () {
  206. if (!this.cardNumber) {
  207. this.$common.errorToShow('请输入银行卡号')
  208. } else if (!this.bankName || !this.cardType || !this.bankCode) {
  209. this.$common.errorToShow('请输入正确的银行卡号')
  210. } else if (!/^[\u4E00-\u9FA5]{2,4}$/.test(this.name)) {
  211. this.$common.errorToShow('请输入正确的持卡人名称')
  212. } else if (!this.areaId) {
  213. this.$common.errorToShow('请选择开户行所在地区')
  214. } else if (!this.accountBank) {
  215. this.$common.errorToShow('请输入开户银行信息')
  216. } else {
  217. this.submitStatus = true;
  218. let data = {
  219. bankName: this.bankName,
  220. areaId: this.areaId,
  221. accountBank: this.accountBank,
  222. accountName: this.name,
  223. bankCode: this.bankCode,
  224. cardNumber: this.cardNumber,
  225. cardType: this.cardType,
  226. isDefault: this.is_def
  227. }
  228. this.$api.addBankCard(data, res => {
  229. if (res.status) {
  230. this.$common.successToShow(res.msg, ress => {
  231. this.submitStatus = false;
  232. uni.navigateBack({
  233. delta: 1
  234. });
  235. })
  236. } else {
  237. this.$common.errorToShow(res.msg);
  238. this.submitStatus = false;
  239. }
  240. })
  241. }
  242. },
  243. // #ifdef MP-ALIPAY
  244. // alipay bank
  245. aliPayBank() {
  246. if(this.cardNumber.length >= 16 && this.cardNumber.length <= 19){
  247. let data = {
  248. card_code: this.cardNumber
  249. }
  250. this.$api.getBankCardOrganization(data, res => {
  251. if (res.status) {
  252. let data = res.data
  253. this.bankName = data.name
  254. this.cardType = data.type
  255. this.bankCode = data.bank_code
  256. this.cardTypeName = data.type_name
  257. } else {
  258. this.$common.errorToShow(res.msg, () => {
  259. this.bankCode = this.bankName = this.cardType = this.cardTypeName = ''
  260. });
  261. }
  262. })
  263. } else {
  264. this.bankCode = this.bankName = this.cardType = this.cardTypeName = ''
  265. }
  266. }
  267. // #endif
  268. },
  269. onLoad(e) {
  270. if(e.ship_id){
  271. //编辑
  272. this.id = e.ship_id;
  273. this.getShipInfo();
  274. }else{
  275. //添加
  276. this.pickerValue = this.region[0]+ " "+ this.region[1]+" "+this.region[2];
  277. }
  278. },
  279. onBackPress() {
  280. if (this.$refs.areaPicker.pickerShow) {
  281. this.$refs.areaPicker.closePicker();
  282. return true;
  283. }
  284. },
  285. // #ifdef MP-ALIPAY
  286. watch: {
  287. cardNumber () {
  288. this.$common.throttle(this.aliPayBank, this, 450);
  289. }
  290. },
  291. // #endif
  292. }
  293. </script>
  294. <style>
  295. .user-head{
  296. height: 100upx;
  297. }
  298. .user-head-img{
  299. height: 90upx;
  300. width: 90upx;
  301. border-radius: 50%;
  302. }
  303. .cell-hd-title{
  304. color: #333;
  305. }
  306. .cell-item-bd{
  307. color: #666;
  308. font-size: 26upx;
  309. }
  310. .button-bottom .btn {
  311. width: 50%;
  312. }
  313. /* #ifdef MP-ALIPAY */
  314. input{
  315. font-size: 24upx;
  316. }
  317. /* #endif */
  318. </style>
bankcard.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="content-top" v-if="cards.length">
  4. <view class="card-item"
  5. v-for="(item, index) in cards"
  6. :key="index"
  7. >
  8. <view class="card-item-tip" v-if="item.is_default === 1">
  9. <view class="cit-bg"></view>
  10. <view class="cit-text"></view>
  11. </view>
  12. <view class="card-item-body">
  13. <view class="cib-left">
  14. <image class="bank-logo" :src="item.bank_logo" mode=""></image>
  15. </view>
  16. <view class="cib-right">
  17. <view class="cibr-t color-3">
  18. {{ item.bank_name }} - {{ item.card_type }}
  19. </view>
  20. <view class="cibr-b color-9">
  21. {{ item.card_number }}
  22. </view>
  23. </view>
  24. </view>
  25. <view class="mr-card"
  26. v-if="item.is_default === 2"
  27. @click="setDefault(item.id)"
  28. >
  29. <button class="btn btn-w" :disabled='submitStatus' :loading='submitStatus'>设为默认</button>
  30. </view>
  31. <view class="del-card"
  32. v-if="mold"
  33. @click="selected(index)"
  34. >
  35. <button class="btn btn-b">选择</button>
  36. </view>
  37. <view class="del-card"
  38. v-else
  39. @click="removeCard(item.id)"
  40. >
  41. <button class="btn btn-b" :disabled='delSubmitStatus' :loading='delSubmitStatus'>删除</button>
  42. </view>
  43. </view>
  44. </view>
  45. <view class="cards-none" v-else>
  46. <image class="cards-none-img" src="/static/image/order.png" mode=""></image>
  47. </view>
  48. <view class="button-bottom">
  49. <button class="btn btn-b" @click="goAddcard()">添加银行卡</button>
  50. </view>
  51. </view>
  52. </template>
  53. <script>
  54. export default {
  55. data () {
  56. return {
  57. mold: '',
  58. cards: [] ,// 我的银行卡列表
  59. submitStatus: false,
  60. delSubmitStatus: false
  61. }
  62. },
  63. onLoad (options) {
  64. if (options.mold && options.mold == 'select') {
  65. this.mold = options.mold
  66. }
  67. },
  68. onShow () {
  69. this.getBankCards()
  70. },
  71. methods:{
  72. // 获取我的银行卡列表
  73. getBankCards() {
  74. this.$api.getBankCardList({}, res => {
  75. if (res.status) {
  76. this.cards = res.data
  77. }
  78. })
  79. },
  80. // 删除银行卡
  81. removeCard (cardId) {
  82. this.$common.modelShow('提示', '确定删除该银行卡?', res => {
  83. this.delSubmitStatus = true;
  84. let data = {
  85. id: cardId
  86. }
  87. this.$api.removeBankCard(data, res => {
  88. if (res.status) {
  89. this.$common.successToShow(res.msg, ress => {
  90. this.delSubmitStatus = false;
  91. this.getBankCards();
  92. })
  93. } else {
  94. this.$common.errorToShow(res.msg);
  95. this.delSubmitStatus = false;
  96. }
  97. })
  98. })
  99. },
  100. // 设置默认卡
  101. setDefault (id) {
  102. this.submitStatus = true;
  103. let data = {
  104. id: id
  105. }
  106. this.$api.setDefaultBankCard(data, res => {
  107. if (res.status) {
  108. this.$common.successToShow(res.msg, ress => {
  109. this.submitStatus = false;
  110. this.getBankCards();
  111. })
  112. } else {
  113. this.$common.errorToShow(res.msg);
  114. this.submitStatus = false;
  115. }
  116. })
  117. },
  118. // 添加新的银行卡
  119. goAddcard(){
  120. this.$common.navigateTo('./add_bankcard')
  121. },
  122. selected (index) {
  123. let pages = getCurrentPages();//当前页
  124. let beforePage = pages[pages.length - 2];//上个页面
  125. // #ifdef H5
  126. beforePage.cardInfo = this.cards[index]
  127. // #endif
  128. // #ifdef MP-WEIXIN
  129. beforePage.$vm.cardInfo = this.cards[index]
  130. // #endif
  131. // #ifdef MP-ALIPAY
  132. beforePage.rootVM.cardInfo = this.cards[index]
  133. // #endif
  134. uni.navigateBack({
  135. delta: 1
  136. })
  137. }
  138. }
  139. }
  140. </script>
  141. <style>
  142. .card-item{
  143. position: relative;
  144. background-color: #fff;
  145. margin: 26upx;
  146. border-radius: 10upx;
  147. box-shadow: 0 0 20upx #ccc;
  148. padding: 60upx 30upx 80upx;
  149. }
  150. .card-item-tip{
  151. position:absolute;
  152. top:0upx;
  153. left:0upx;
  154. z-index:10;
  155. border-top-left-radius:10upx;
  156. overflow:hidden;
  157. width:100upx;
  158. height:100upx;
  159. }
  160. .cit-bg{
  161. position:absolute;
  162. top:0;
  163. left:0;
  164. z-index:11;
  165. color:#ffffff;
  166. width:0upx;
  167. height:0upx;
  168. border-bottom:solid 100upx transparent;
  169. border-right:solid 100upx transparent;
  170. border-top:solid 100upx #FF7159;
  171. }
  172. .cit-text{
  173. position:absolute;
  174. top:0;
  175. left:0;
  176. z-index:12;
  177. color:#ffffff;
  178. margin-top:4upx;
  179. margin-left:14upx;
  180. font-size:30upx;
  181. }
  182. .card-item-body{
  183. position: relative;
  184. }
  185. .cib-left{
  186. position: absolute;
  187. top: 60%;
  188. transform: translateY(-50%);
  189. width: 250upx;
  190. }
  191. .bank-logo{
  192. width: 240upx;
  193. height: 70upx;
  194. }
  195. .cib-right{
  196. margin-left: 250upx;
  197. }
  198. .cibr-t{
  199. font-size: 30upx;
  200. margin-bottom: 10upx;
  201. text-align: center;
  202. }
  203. .cibr-b{
  204. font-size: 26upx;
  205. text-align: center;
  206. }
  207. .mr-card{
  208. position: absolute;
  209. right: 140upx;
  210. bottom: 0upx;
  211. }
  212. .del-card{
  213. position: absolute;
  214. right: 30upx;
  215. bottom: 0upx;
  216. }
  217. .del-card .btn,.mr-card .btn{
  218. font-size: 24upx;
  219. height: 48upx;
  220. line-height: 46upx;
  221. padding: 0 16upx;
  222. }
  223. .cards-none{
  224. text-align: center;
  225. padding: 200upx 0;
  226. }
  227. .cards-none-img{
  228. width: 274upx;
  229. height: 274upx;
  230. }
  231. </style>
cashlist.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class='cell-group'>
  4. <view class='cell-item right-img'>
  5. <view class='cell-item-hd'>
  6. <view class='cell-hd-title color-6'>类型筛选</view>
  7. </view>
  8. <view class='cell-item-bd'>
  9. <view class="uni-list">
  10. <view class="uni-list-cell-db color-6">
  11. <picker @change="changeState" :value="index" :range="objectType">
  12. <view class="uni-input">{{objectType[index]}}</view>
  13. </picker>
  14. </view>
  15. <image class='right-img icon' src='/static/image/ic-pull-down.png'></image>
  16. </view>
  17. </view>
  18. </view>
  19. </view>
  20. <view class="type-c"
  21. v-if="list.length"
  22. >
  23. <view class="cell-group margin-cell-group"
  24. v-for="(item, index) in list"
  25. :key="index"
  26. >
  27. <view class="cell-item">
  28. <view class="cell-item-hd">
  29. <view class='cell-hd-title'>{{ item.type }}</view>
  30. </view>
  31. <view class="cell-item-ft">
  32. <view class="cell-ft-p color-9">
  33. {{ item.ctime }}
  34. </view>
  35. </view>
  36. </view>
  37. <view class="cell-item">
  38. <view class="cell-item-hd">
  39. <view class='cell-hd-title color-9'>提现卡号:{{ item.card_number }}</view>
  40. </view>
  41. <view class="cell-item-ft red-price">
  42. {{ item.money }}
  43. </view>
  44. </view>
  45. </view>
  46. <uni-load-more
  47. :status="loadStatus"
  48. ></uni-load-more>
  49. </view>
  50. <view class="order-none" v-else>
  51. <image class="cash-none-img" src="/static/image/order.png" mode=""></image>
  52. </view>
  53. </view>
  54. </template>
  55. <script>
  56. import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue'
  57. export default {
  58. components: {
  59. uniLoadMore
  60. },
  61. data() {
  62. return {
  63. objectType: ['全部', '待审核', '提现成功', '提现失败'],
  64. index: 0, // 默认选中的类型 索引
  65. page: 1,
  66. limit: 10,
  67. list: [],
  68. states: [0, 1, 2, 3], // 不同类型的状态
  69. loadStatus: 'more'
  70. }
  71. },
  72. onLoad () {
  73. this.getCash()
  74. },
  75. onReachBottom () {
  76. if (this.loadStatus === 'more') {
  77. this.getCash()
  78. }
  79. },
  80. methods: {
  81. // 切换类型
  82. changeState (e) {
  83. if (this.index !== e.target.value) {
  84. this.index = e.target.value;
  85. this.page = 1
  86. this.list = []
  87. }
  88. },
  89. // 获取余额明细
  90. getCash () {
  91. let data = {
  92. page: this.page,
  93. limit: this.limit
  94. }
  95. if (this.states[this.index]) {
  96. data.type = this.states[this.index]
  97. }
  98. this.loadStatus = 'loading'
  99. this.$api.cashList(data, res => {
  100. if (res.status) {
  101. if (this.page >= res.total) {
  102. // 没有数据了
  103. this.loadStatus = 'noMore'
  104. } else {
  105. // 未加载完毕
  106. this.loadStatus = 'more'
  107. this.page ++
  108. }
  109. this.list = [...this.list, ...res.data]
  110. } else {
  111. this.$common.errorToShow(res.msg)
  112. }
  113. })
  114. }
  115. },
  116. watch: {
  117. index () {
  118. this.getCash()
  119. }
  120. }
  121. }
  122. </script>
  123. <style>
  124. .uni-list{
  125. overflow: hidden;
  126. }
  127. .uni-list-cell-db{
  128. float: left;
  129. padding-top: 8upx;
  130. margin-right: 6upx;
  131. display: inline-block;
  132. }
  133. .uni-list .right-img{
  134. float: left;
  135. }
  136. .cell-item-bd{
  137. font-size: 26upx;
  138. }
  139. .type-c .cell-group{
  140. padding: 10upx 0;
  141. }
  142. .type-c .cell-item{
  143. border: none;
  144. min-height: 70upx;
  145. padding: 0 26upx 0 0;
  146. }
  147. .type-c .cell-item .red-price{
  148. font-size: 50upx;
  149. }
  150. .type-c .cell-item .color-9{
  151. font-size: 24upx;
  152. }
  153. .order-none{
  154. text-align: center;
  155. padding: 200upx 0;
  156. }
  157. .cash-none-img{
  158. width: 274upx;
  159. height: 274upx;
  160. }
  161. </style>
details.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class='cell-group'>
  4. <view class='cell-item right-img'>
  5. <view class='cell-item-hd'>
  6. <view class='cell-hd-title color-6' style="top: 0;">类型筛选</view>
  7. </view>
  8. <view class='cell-item-bd down-pull'>
  9. <view class="uni-list">
  10. <view class="uni-list-cell-db color-6">
  11. <picker @change="changeState" :value="index" :range="objectType">
  12. <view class="uni-input">{{objectType[index]}}</view>
  13. </picker>
  14. </view>
  15. <image class='right-img icon' src='/static/image/ic-pull-down.png'></image>
  16. </view>
  17. </view>
  18. </view>
  19. </view>
  20. <view class="type-c"
  21. v-if="list.length"
  22. >
  23. <view class="cell-group margin-cell-group"
  24. v-for="(item, index) in list"
  25. :key="index"
  26. >
  27. <view class="cell-item">
  28. <view class="cell-item-hd">
  29. <view class='cell-hd-title'>{{ item.type }}</view>
  30. </view>
  31. <view class="cell-item-ft">
  32. <view class="cell-ft-p color-9">
  33. {{ item.ctime }}
  34. </view>
  35. </view>
  36. </view>
  37. <view class="cell-item">
  38. <view class="cell-item-hd">
  39. <view class='cell-hd-title color-9'>余额:{{ item.balance }}</view>
  40. </view>
  41. <view class="cell-item-ft red-price">
  42. {{ item.money }}
  43. </view>
  44. </view>
  45. </view>
  46. <uni-load-more
  47. :status="loadStatus"
  48. ></uni-load-more>
  49. </view>
  50. <view class="order-none" v-else>
  51. <image class="balance-none-img" src="/static/image/order.png" mode=""></image>
  52. </view>
  53. </view>
  54. </template>
  55. <script>
  56. import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue'
  57. export default {
  58. components: {
  59. uniLoadMore
  60. },
  61. data() {
  62. return {
  63. objectType: ['全部', '消费', '退款', '充值', '提现', '佣金', '平台调整'],
  64. index: 0, // 默认选中的类型 索引
  65. page: 1,
  66. limit: 10,
  67. list: [],
  68. states: [0, 1, 2, 3, 4, 5, 7], // 不同类型的状态
  69. loadStatus: 'more'
  70. }
  71. },
  72. onLoad (e) {
  73. if(e.status){
  74. this.index = this.states.indexOf(parseInt(e.status));
  75. }else{
  76. this.balances()//修复多次加载问题
  77. }
  78. },
  79. onReachBottom () {
  80. if (this.loadStatus === 'more') {
  81. this.balances()
  82. }
  83. },
  84. methods: {
  85. // 切换类型
  86. changeState (e) {
  87. if (this.index !== e.target.value) {
  88. this.index = e.target.value;
  89. this.page = 1
  90. this.list = []
  91. }
  92. },
  93. // 获取余额明细
  94. balances () {
  95. let data = {
  96. type: this.states[this.index],
  97. page: this.page,
  98. limit: this.limit
  99. }
  100. this.loadStatus = 'loading'
  101. this.$api.getBalanceList(data, res => {
  102. if (res.status) {
  103. if (this.page >= res.total) {
  104. // 没有数据了
  105. this.loadStatus = 'noMore'
  106. } else {
  107. // 未加载完毕
  108. this.loadStatus = 'more'
  109. this.page ++
  110. }
  111. this.list = [...this.list, ...res.data]
  112. } else {
  113. this.$common.errorToShow(res.msg)
  114. }
  115. })
  116. }
  117. },
  118. watch: {
  119. index () {
  120. this.balances();
  121. }
  122. }
  123. }
  124. </script>
  125. <style>
  126. .uni-list{
  127. overflow: hidden;
  128. }
  129. .uni-list-cell-db{
  130. float: left;
  131. /* padding-top: 8upx; */
  132. margin-right: 6upx;
  133. display: inline-block;
  134. height: 50upx;
  135. line-height: 50upx;
  136. }
  137. .uni-list .right-img{
  138. float: left;
  139. }
  140. .cell-item-bd{
  141. font-size: 26upx;
  142. }
  143. .type-c .cell-group{
  144. padding: 10upx 0;
  145. }
  146. .type-c .cell-item{
  147. border: none;
  148. min-height: 70upx;
  149. padding: 0 26upx 0 0;
  150. }
  151. .type-c .cell-item .red-price{
  152. font-size: 50upx;
  153. }
  154. .type-c .cell-item .color-9{
  155. font-size: 24upx;
  156. }
  157. .order-none{
  158. text-align: center;
  159. padding: 200upx 0;
  160. }
  161. .balance-none-img{
  162. width: 274upx;
  163. height: 274upx;
  164. }
  165. .down-pull{
  166. position: absolute;
  167. top: 50%;
  168. transform: translateY(-50%);
  169. left: 120upx;
  170. }
  171. </style>
index.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class='withdrawcash-top'>
  4. <text class='withdrawcash-title'>账户余额(元)</text>
  5. <text class='withdrawcash-num'>{{ userInfo.balance }}</text>
  6. </view>
  7. <view class='cell-group margin-cell-group right-img'>
  8. <view class='cell-item'>
  9. <view class='cell-item-hd' @click="navigateToHandle('./recharge')">
  10. <image class='cell-hd-icon' src='/static/image/topup.png'></image>
  11. <view class='cell-hd-title'>账户充值</view>
  12. </view>
  13. <view class='cell-item-ft'>
  14. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  15. </view>
  16. </view>
  17. <view class='cell-item'>
  18. <view class='cell-item-hd' @click="navigateToHandle('./withdraw_cash')">
  19. <image class='cell-hd-icon' src='/static/image/withdraw.png'></image>
  20. <view class='cell-hd-title'>余额提现</view>
  21. </view>
  22. <view class='cell-item-ft'>
  23. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  24. </view>
  25. </view>
  26. <view class='cell-item'>
  27. <view class='cell-item-hd' @click="navigateToHandle('./details')">
  28. <image class='cell-hd-icon' src='/static/image/detail.png'></image>
  29. <view class='cell-hd-title'>余额明细</view>
  30. </view>
  31. <view class='cell-item-ft'>
  32. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  33. </view>
  34. </view>
  35. <view class='cell-item'>
  36. <view class='cell-item-hd' @click="navigateToHandle('./cashlist')">
  37. <image class='cell-hd-icon' src='/static/image/record.png'></image>
  38. <view class='cell-hd-title'>提现记录</view>
  39. </view>
  40. <view class='cell-item-ft'>
  41. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  42. </view>
  43. </view>
  44. <view class='cell-item'>
  45. <view class='cell-item-hd' @click="navigateToHandle('./bankcard')">
  46. <image class='cell-hd-icon' src='/static/image/card.png'></image>
  47. <view class='cell-hd-title'>我的银行卡</view>
  48. </view>
  49. <view class='cell-item-ft'>
  50. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  51. </view>
  52. </view>
  53. </view>
  54. </view>
  55. </template>
  56. <script>
  57. export default {
  58. data () {
  59. return {
  60. userInfo: {}
  61. }
  62. },
  63. onShow () {
  64. this.getUserInfo()
  65. },
  66. methods: {
  67. // 获取用户信息
  68. getUserInfo () {
  69. this.$api.userInfo({}, res => {
  70. if (res.status) {
  71. this.userInfo = res.data
  72. } else {
  73. this.$common.errorToShow(res.msg)
  74. }
  75. })
  76. },
  77. // 页面跳转
  78. navigateToHandle (pageUrl) {
  79. this.$common.navigateTo(pageUrl)
  80. }
  81. }
  82. }
  83. </script>
  84. <style>
  85. .withdrawcash-top{
  86. padding: 40upx 26upx;
  87. background-color: #FF7159;
  88. color: #fff;
  89. }
  90. .withdrawcash-title{
  91. font-size: 28upx;
  92. display: block
  93. }
  94. .withdrawcash-num{
  95. font-size: 70upx;
  96. display: block;
  97. margin-top: 20upx;
  98. margin-left: 50upx;
  99. }
  100. .margin-cell-group {
  101. margin: 20upx 0;
  102. color: #666666;
  103. }
  104. </style>
recharge.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="content-top">
  4. <view class='cell-group margin-cell-group'>
  5. <view class='cell-item'>
  6. <view class='cell-item-hd'>
  7. <view class='cell-hd-title'>当前金额</view>
  8. </view>
  9. <view class='cell-item-bd'>
  10. <text class="cell-bd-view">¥{{ user.balance }}</text>
  11. </view>
  12. </view>
  13. <view class='cell-item'>
  14. <view class='cell-item-hd'>
  15. <view class='cell-hd-title'>充值金额</view>
  16. </view>
  17. <view class='cell-item-bd'>
  18. <input class='cell-bd-input' placeholder='请输入要充值的金额' v-model="money" focus type="digit"></input>
  19. </view>
  20. </view>
  21. </view>
  22. </view>
  23. <view class="button-bottom">
  24. <button class="btn btn-square btn-b" hover-class="btn-hover2" @click="navigateToHandle">去支付</button>
  25. </view>
  26. </view>
  27. </template>
  28. <script>
  29. export default {
  30. data () {
  31. return {
  32. user: {}, // 用户信息
  33. payments: [], // 可用充值方式列表
  34. money: '', // 充值的金额
  35. orderType: 2 // 充值类型
  36. }
  37. },
  38. onLoad () {
  39. this.userInfo()
  40. },
  41. methods: {
  42. // 获取用户信息
  43. userInfo () {
  44. this.$api.userInfo({}, res => {
  45. if (res.status) {
  46. this.user = res.data
  47. }
  48. })
  49. },
  50. // 去充值
  51. navigateToHandle () {
  52. if (!Number(this.money)) {
  53. this.$common.errorToShow('请输入要充值的金额')
  54. } else {
  55. this.$common.navigateTo('/pages/goods/payment/index?recharge=' + Number(this.money) + '&type=' + this.orderType)
  56. }
  57. }
  58. }
  59. }
  60. </script>
  61. <style>
  62. .user-head{
  63. height: 100upx;
  64. }
  65. .user-head-img{
  66. height: 90upx;
  67. width: 90upx;
  68. border-radius: 50%;
  69. }
  70. .cell-hd-title{
  71. color: #333;
  72. }
  73. .cell-item-bd{
  74. color: #666;
  75. font-size: 26upx;
  76. }
  77. .button-bottom .btn {
  78. width: 100%;
  79. }
  80. </style>
withdraw_cash.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="content-top">
  4. <!-- 我的银行卡信息 -->
  5. <view class='cell-group margin-cell-group'
  6. v-if="userbankCard"
  7. @click="toBankCardList"
  8. >
  9. <view class='cell-item right-img'>
  10. <view class='cell-item-hd'>
  11. <image class="yl-logo" :src="cardInfo.bank_logo" mode=""></image>
  12. </view>
  13. <view class='cell-item-bd'>
  14. <text class="cell-bd-view">{{ cardInfo.card_number }}</text>
  15. </view>
  16. <view class="cell-item-ft">
  17. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  18. </view>
  19. </view>
  20. </view>
  21. <view class='cell-group margin-cell-group'
  22. v-else
  23. @click="toBankCardList"
  24. >
  25. <view class='cell-item right-img'>
  26. <view class='cell-item-hd'>
  27. <image class="yl-logo" src="/static/image/yl.png" mode=""></image>
  28. </view>
  29. <view class='cell-item-bd'>
  30. <text class="cell-bd-view">请添加银行卡</text>
  31. </view>
  32. <view class="cell-item-ft">
  33. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  34. </view>
  35. </view>
  36. </view>
  37. <!-- 提现金额手续费 提现金额input -->
  38. <view class='cell-group margin-cell-group'>
  39. <view class='cell-item'>
  40. <view class='cell-item-bd' v-if="tocashExplain">
  41. <view class='cell-hd-title' style="color: #666;">{{ tocashExplain }}</view>
  42. </view>
  43. </view>
  44. <view class='cell-item'>
  45. <view class='cell-item-bd withdrawcash-input'>
  46. <view class='cell-hd-title'><text></text><input type="number" focus v-model="money"/></view>
  47. </view>
  48. </view>
  49. <view class='cell-item'>
  50. <view class='cell-item-bd'>
  51. <view class='cell-hd-title' style="color: #666;" v-show="!isError">可用余额 {{ user.balance }} 元</view>
  52. <view class='cell-hd-title' style="color: #f00;" v-show="isError">提现金额超过可用余额</view>
  53. </view>
  54. </view>
  55. </view>
  56. </view>
  57. <view class="button-bottom">
  58. <button class="btn btn-square btn-b" hover-class="btn-hover2" v-if="isSubmit" @click="toCash" :disabled='submitStatus' :loading='submitStatus'>确认提现</button>
  59. <button class="btn btn-square btn-b" hover-class="btn-hover2" v-else-if="!isSubmit" disabled>确认提现</button>
  60. </view>
  61. </view>
  62. </template>
  63. <script>
  64. export default {
  65. data () {
  66. return {
  67. cardInfo: {}, // 我的银行卡信息
  68. user: {}, // 用户信息
  69. isError: false, // 当提现金额大于可用余额 显示错误提示
  70. isSubmit: false, // 提现点击
  71. money: '', // 用户输入的提现金额
  72. submitStatus: false
  73. }
  74. },
  75. onLoad () {
  76. this.userBankCard()
  77. this.userInfo()
  78. },
  79. computed: {
  80. userbankCard () {
  81. if (Object.keys(this.cardInfo).length) {
  82. return true
  83. } else {
  84. return false
  85. }
  86. },
  87. // 店铺提现手续费
  88. tocashMoneyRate () {
  89. return this.$store.state.config.tocash_money_rate
  90. },
  91. // 店铺提现最低金额
  92. tocashMoneyLow () {
  93. return this.$store.state.config.tocash_money_low
  94. },
  95. // 提现文字说明
  96. tocashExplain () {
  97. if (this.tocashMoneyRate && this.tocashMoneyLow) {
  98. return '最低提现金额 ' + this.tocashMoneyLow + ' 元(收取 ' + this.tocashMoneyRate + ' %服务费)'
  99. } else if (this.tocashMoneyLow) {
  100. return '最低提现金额 ' + this.tocashMoneyLow + ' 元'
  101. } else if (this.tocashMoneyRate) {
  102. return '收取 ' + this.tocashMoneyRate + ' %服务费'
  103. } else {
  104. return ''
  105. }
  106. }
  107. },
  108. methods: {
  109. // 获取我的默认银行卡信息
  110. userBankCard () {
  111. this.$api.getDefaultBankCard({}, res => {
  112. if (res.status) {
  113. this.cardInfo = res.data
  114. }
  115. })
  116. },
  117. // 获取用户信息
  118. userInfo () {
  119. // 获取我的余额信息
  120. // 获取用户的可用余额
  121. this.$api.userInfo({}, res => {
  122. this.user = res.data
  123. })
  124. },
  125. // 去提现
  126. toCash () {
  127. if (!Object.keys(this.cardInfo).length) {
  128. this.$common.errorToShow('请选择要提现的银行卡')
  129. return false
  130. } else if (!this.money) {
  131. this.$common.errorToShow('请输入要提现的金额')
  132. return false
  133. } else if (Number(this.money) === 0) {
  134. this.$common.errorToShow('提现金额不能为0')
  135. } else {
  136. this.submitStatus = true;
  137. this.$api.userToCash({
  138. money: this.money,
  139. cardId: this.cardInfo.id
  140. }, res => {
  141. if (res.status) {
  142. this.$common.successToShow(res.msg, () => {
  143. this.submitStatus = false;
  144. uni.navigateBack({
  145. delta: 1
  146. });
  147. })
  148. } else {
  149. this.$common.errorToShow(res.msg);
  150. this.submitStatus = false;
  151. }
  152. })
  153. }
  154. },
  155. // 跳转我的银行卡列表
  156. toBankCardList () {
  157. this.$common.navigateTo('./bankcard?mold=select')
  158. }
  159. },
  160. watch: {
  161. money () {
  162. // 比较用户的输入金额 如果大于可用金额
  163. if (this.money === '' || Number(this.money) <= 0) {
  164. this.isSubmit = false
  165. } else if (Number(this.money) > Number(this.user.balance)) {
  166. this.isError = true
  167. this.isSubmit = false
  168. } else if (Number(this.money) < Number(this.tocashMoneyLow)) {
  169. this.isError = false
  170. this.isSubmit = false
  171. } else {
  172. this.isError = false
  173. this.isSubmit = true
  174. }
  175. }
  176. }
  177. }
  178. </script>
  179. <style>
  180. .user-head{
  181. height: 100upx;
  182. }
  183. .user-head-img{
  184. height: 90upx;
  185. width: 90upx;
  186. border-radius: 50%;
  187. }
  188. .cell-hd-title{
  189. color: #333;
  190. }
  191. .cell-item{
  192. border: none;
  193. }
  194. .cell-item-bd{
  195. color: #666;
  196. font-size: 26upx;
  197. }
  198. .button-bottom .btn {
  199. width: 100%;
  200. }
  201. .yl-logo{
  202. width: 188upx;
  203. height: 54upx;
  204. float: left;
  205. }
  206. .withdrawcash-input{
  207. font-size: 50upx;
  208. border-bottom: 2upx solid #e8e8e8;
  209. padding-bottom: 20upx;
  210. }
  211. .withdrawcash-input text{
  212. font-size: 40upx;
  213. }
  214. .withdrawcash-input input{
  215. display: inline-block;
  216. min-width: 500upx;
  217. padding-left: 20upx;
  218. }
  219. /* #ifdef MP-ALIPAY */
  220. .cell-hd-title input {
  221. font-size: 24px;
  222. height: 18px;
  223. }
  224. /* #endif */
  225. </style>
collection
index.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="collection" v-if="list.length">
  4. <view class="container_of_slide"
  5. v-for="(item, index) in list"
  6. :key="index"
  7. >
  8. <view class="slide_list"
  9. @touchstart="touchStart($event,index)"
  10. @touchend="touchEnd($event,index)"
  11. @touchmove="touchMove($event,index)"
  12. @tap="recover(index)"
  13. :style="{transform:'translate3d('+item.slide_x+'px, 0, 0)'}"
  14. v-if="item.goods"
  15. >
  16. <view class="now-message-info" hover-class="uni-list-cell-hover" :style="{width:Screen_width+'px'}"
  17. @click="goodsDetail(item.goods_id)">
  18. <view class="icon-circle">
  19. <image class='goods-img' :src="item.goods.image_url" mode="aspectFill"></image>
  20. </view>
  21. <view class="list-right">
  22. <view class="list-title">{{ item.goods.name }}</view>
  23. <view class="red-price">¥{{ item.goods.price }}</view>
  24. <view class="list-detail">{{ item.ctime }}</view>
  25. </view>
  26. <view class="list-right-1">
  27. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  28. </view>
  29. </view>
  30. <view class="group-btn">
  31. <view class="removeM btn-div" @tap="collect(index)">
  32. 取消
  33. </view>
  34. </view>
  35. <view style="clear:both"></view>
  36. </view>
  37. </view>
  38. <uni-load-more
  39. :status="loadStatus"
  40. ></uni-load-more>
  41. </view>
  42. <view class="collection-none" v-else>
  43. <image class="collection-none-img" src="/static/image/order.png" mode=""></image>
  44. </view>
  45. </view>
  46. </template>
  47. <script>
  48. import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue'
  49. import { goods } from '@/config/mixins.js'
  50. export default {
  51. mixins: [ goods ],
  52. components: {
  53. uniLoadMore
  54. },
  55. computed: {
  56. Screen_width() {
  57. return uni.getSystemInfoSync().windowWidth;
  58. }
  59. },
  60. data() {
  61. return {
  62. visible: false,
  63. start_slide_x: 0,
  64. btnWidth: 0,
  65. startX: 0,
  66. LastX: 0,
  67. startTime: 0,
  68. screenName: '',
  69. page: 1,
  70. limit: 10,
  71. list: [], // 商品浏览足迹
  72. loadStatus: 'more'
  73. };
  74. },
  75. onLoad () {
  76. this.goodsCollectionList()
  77. },
  78. onShow() {
  79. const res = uni.getSystemInfoSync();
  80. },
  81. onReachBottom () {
  82. if (this.loadStatus === 'more') {
  83. this.goodsCollectionList()
  84. }
  85. },
  86. methods: {
  87. goodsCollectionList () {
  88. let data = {
  89. page: this.page,
  90. limit: this.limit
  91. }
  92. this.loadStatus = 'loading'
  93. this.$api.goodsCollectionList(data, res => {
  94. if (res.status) {
  95. let _list = res.data.list
  96. _list.forEach (item => {
  97. this.$set(item, 'slide_x', 0)
  98. item.ctime = this.$common.timeToDate(item.ctime)
  99. })
  100. this.list = [...this.list, ..._list]
  101. if (res.data.count > this.list.length) {
  102. this.page ++
  103. this.loadStatus = 'more'
  104. } else {
  105. this.loadStatus = 'noMore'
  106. }
  107. } else {
  108. this.$common.errorToShow(res.msg)
  109. }
  110. })
  111. },
  112. cancelEvent(){
  113. this.visible = false
  114. },
  115. // 滑动开始
  116. touchStart(e, index) {
  117. this.startCilentY = e.touches[0].clientY;
  118. //记录手指放上去的时间
  119. this.startTime = e.timeStamp;
  120. //记录滑块的初始位置
  121. this.start_slide_x = this.list[index].slide_x;
  122. // 按钮宽度
  123. uni.createSelectorQuery()
  124. .selectAll('.group-btn')
  125. .boundingClientRect()
  126. .exec(res => {
  127. if (res[0] != null) {
  128. this.btnWidth = res[0][index].width * -1;
  129. }
  130. });
  131. // 记录上一次开始时手指所处位置
  132. this.startX = e.touches[0].pageX;
  133. // 记录上一次手指位置
  134. this.lastX = this.startX;
  135. //初始化非当前滑动消息列的位置
  136. this.list.forEach((item, eq) => {
  137. if (eq !== index) {
  138. item.slide_x = 0;
  139. }
  140. });
  141. },
  142. // 滑动中
  143. touchMove(e, index) {
  144. var endCilentY = e.touches[0].clientY;
  145. var moveClientY = endCilentY - this.startCilentY;
  146. if (this.direction === 'Y' || Math.abs(moveClientY ) > 20 || e.currentTarget.dataset.disabled === true) { this.direction = ''; return; }
  147. const endX = e.touches[0].pageX;
  148. const distance = endX - this.lastX;
  149. // 预测滑块所处位置
  150. const duang = this.list[index].slide_x + distance;
  151. // 如果在可行区域内
  152. if (duang <= 0 && duang >= this.btnWidth) {
  153. this.list[index].slide_x = duang;
  154. }
  155. // 此处手指所处位置将成为下次手指移动时的上一次位置
  156. this.lastX = endX;
  157. },
  158. // 滑动结束
  159. touchEnd(e, index) {
  160. let distance = 10;
  161. const endTime = e.timeStamp;
  162. const x_end_distance = this.startX - this.lastX;
  163. if (Math.abs(endTime - this.startTime) > 200) {
  164. distance = this.btnWidth / -2;
  165. }
  166. // 判断手指最终位置与手指开始位置的位置差距
  167. if (x_end_distance > distance) {
  168. this.list[index].slide_x = this.btnWidth;
  169. } else if (x_end_distance < distance * -1) {
  170. this.list[index].slide_x = 0;
  171. } else {
  172. this.list[index].slide_x = this.start_slide_x;
  173. }
  174. },
  175. // 点击回复原状
  176. recover(index) {
  177. this.list[index].slide_x = 0;
  178. },
  179. // 取消收藏
  180. collect (index) {
  181. let data = {
  182. goods_id: this.list[index].goods_id
  183. }
  184. this.$api.goodsCollection(data, res => {
  185. if (res.status) {
  186. this.$common.successToShow(res.msg, () => {
  187. this.$nextTick(() => {
  188. this.list.splice(index, 1)
  189. })
  190. })
  191. } else {
  192. this.$common.errorToShow(res.msg)
  193. }
  194. })
  195. }
  196. }
  197. };
  198. </script>
  199. <style scoped>
  200. .collection .goods-img{
  201. width: 150upx;
  202. height: 150upx;
  203. }
  204. .container_of_slide {
  205. width: 100%;
  206. overflow: hidden;
  207. }
  208. .slide_list {
  209. transition: all 100ms;
  210. transition-timing-function: ease-out;
  211. min-width: 200%;
  212. }
  213. .now-message-info {
  214. box-sizing:border-box;
  215. display: flex;
  216. align-items: center;
  217. font-size: 16px;
  218. clear:both;
  219. padding: 20upx 26upx;
  220. margin-bottom: 2upx;
  221. background: #FFFFFF;
  222. }
  223. .now-message-info,
  224. .group-btn {
  225. float: left;
  226. }
  227. .group-btn {
  228. display: flex;
  229. flex-direction: row;
  230. height: 190upx;
  231. min-width: 100upx;
  232. align-items: center;
  233. }
  234. .group-btn .btn-div {
  235. height: 190upx;
  236. color: #fff;
  237. text-align: center;
  238. padding: 0 50upx;
  239. font-size: 34upx;
  240. line-height: 190upx;
  241. }
  242. .group-btn .top {
  243. background-color: #FFAA33;
  244. }
  245. .group-btn .removeM {
  246. background-color: #ff3b44;
  247. }
  248. .icon-circle{
  249. width:150upx;
  250. height: 150upx;
  251. float: left;
  252. }
  253. .list-right{
  254. float: left;
  255. margin-left: 25upx;
  256. height: 150upx;
  257. }
  258. .list-right-1{
  259. float: right;
  260. color: #A9A9A9;
  261. }
  262. .list-title{
  263. width: 490upx;
  264. line-height:1.5;
  265. overflow:hidden;
  266. color:#333;
  267. display:-webkit-box;
  268. -webkit-box-orient:vertical;
  269. -webkit-line-clamp:2;
  270. overflow:hidden;
  271. font-size: 26upx;
  272. color: #333;
  273. min-height: 80upx;
  274. }
  275. .list-detail{
  276. width: 460upx;
  277. font-size: 24upx;
  278. color: #a9a9a9;
  279. display:-webkit-box;
  280. -webkit-box-orient:vertical;
  281. -webkit-line-clamp:1;
  282. overflow:hidden;
  283. }
  284. .collection-none{
  285. text-align: center;
  286. padding: 200upx 0;
  287. }
  288. .collection-none-img{
  289. width: 274upx;
  290. height: 274upx;
  291. }
  292. </style>
coupon
index.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <uni-segmented-control :current="current" :values="items" @clickItem="onClickItem" style-type="text" active-color="#333"></uni-segmented-control>
  4. <view class="">
  5. <view class="coupon-c-item" v-for="(item, key) in listData" :key="key">
  6. <view class="cci-l">
  7. <view class="cci-l-c color-f" v-if="current == 0">
  8. coupon
  9. </view>
  10. <view class="cci-l-c color-f color-b" v-if="current != 0">
  11. coupon
  12. </view>
  13. </view>
  14. <view class="cci-r">
  15. <view class="cci-r-c">
  16. <view class="ccirc-t color-9">
  17. {{item.name}}
  18. </view>
  19. <view class="ccirc-b">
  20. <view class="ccirc-b-l">
  21. <view class="ccirc-b-tip">
  22. {{ item.expression1 + item.expression2 }}
  23. </view>
  24. <view class="ccirc-b-time color-9">
  25. 有效期:{{item.stime}} - {{item.etime}}
  26. </view>
  27. </view>
  28. <view class="ccirc-b-r color-f" @click="goIndex" v-if="current == 0">
  29. 立即使用
  30. </view>
  31. </view>
  32. </view>
  33. </view>
  34. </view>
  35. <uni-load-more :status="loadStatus"></uni-load-more>
  36. </view>
  37. </view>
  38. </template>
  39. <script>
  40. import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue'
  41. import uniSegmentedControl from "@/components/uni-segmented-control/uni-segmented-control.vue";
  42. export default {
  43. components: {
  44. uniSegmentedControl,uniLoadMore
  45. },
  46. data() {
  47. return {
  48. items: ['未使用','已使用','已失效'],
  49. current: 0,
  50. page: 1,
  51. limit: 10,
  52. listData: [],
  53. loadStatus: 'more'
  54. }
  55. },
  56. onLoad() {
  57. this.getData();
  58. },
  59. onReachBottom () {
  60. if (this.loadStatus === 'more') {
  61. this.getData();
  62. }
  63. },
  64. methods: {
  65. // tab点击切换
  66. onClickItem(index) {
  67. if (this.current !== index) {
  68. this.current = index;
  69. this.page = 1;
  70. this.listData = [];
  71. this.getData();
  72. }
  73. },
  74. //获取优惠券列表
  75. getData() {
  76. this.loadStatus = 'loading'
  77. let data = {
  78. page: this.page,
  79. limit: this.limit
  80. }
  81. if (this.current == 0) {
  82. data['display'] = 'no_used';
  83. }
  84. if (this.current == 1) {
  85. data['display'] = 'yes_used';
  86. }
  87. if (this.current == 2) {
  88. data['display'] = 'invalid';
  89. }
  90. this.$api.userCoupon(data, res => {
  91. if (res.status) {
  92. let now_type = 'no_used';
  93. if (this.current == 1) {
  94. now_type = 'yes_used';
  95. }
  96. if (this.current == 2) {
  97. now_type = 'invalid';
  98. }
  99. if (now_type == res.data.q_type) {
  100. if (res.data.page >= this.page) {
  101. let newList = this.listData.concat(res.data.list);
  102. this.listData = newList;
  103. if (res.data.count > this.listData.length) {
  104. this.page ++
  105. this.loadStatus = 'more'
  106. } else {
  107. this.loadStatus = 'noMore'
  108. }
  109. }
  110. }
  111. }else{
  112. this.$common.errorToShow(res.msg);
  113. }
  114. });
  115. },
  116. //跳转首页
  117. goIndex() {
  118. uni.switchTab({
  119. url: '/pages/index/index'
  120. });
  121. }
  122. }
  123. }
  124. </script>
  125. <style>
  126. .coupon-c-item{
  127. margin: 30upx 50upx;
  128. /* width: 100%; */
  129. height: 150upx;
  130. margin-bottom: 20upx;
  131. }
  132. .cci-l{
  133. width: 60upx;
  134. height: 100%;
  135. background-color: #FF7159;
  136. font-size: 32upx;
  137. display: inline-block;
  138. box-sizing: border-box;
  139. float: left;
  140. border-top-left-radius: 16upx;
  141. border-bottom-left-radius: 16upx;
  142. }
  143. .cci-l-c{
  144. height: 60upx;
  145. line-height: 44upx;
  146. width: 150upx;
  147. text-align: center;
  148. transform-origin: 30upx 30upx;
  149. transform: rotate(90deg);
  150. }
  151. .cci-r{
  152. position: relative;
  153. height: 150upx;
  154. width: calc(100% - 70upx);
  155. margin-left: 10upx;
  156. display: inline-block;
  157. background-color: #fff;
  158. }
  159. .cci-r-img{
  160. position: absolute;
  161. width: 100%;
  162. height: 100%;
  163. background-color: #fff;
  164. }
  165. .cci-r-c{
  166. position: relative;
  167. z-index: 99;
  168. }
  169. .ccirc-t{
  170. font-size: 24upx;
  171. padding: 10upx 20upx;
  172. }
  173. .ccirc-b{
  174. padding: 10upx;
  175. position: relative;
  176. }
  177. .ccirc-b-l{
  178. display: inline-block;
  179. max-width: 400upx;
  180. }
  181. .ccirc-b-tip{
  182. font-size: 28upx;
  183. width: 100%;
  184. overflow: hidden;
  185. text-overflow: ellipsis;
  186. white-space: nowrap;
  187. }
  188. .ccirc-b-tip text{
  189. font-size: 34upx;
  190. }
  191. .ccirc-b-time{
  192. font-size: 24upx;
  193. }
  194. .ccirc-b-r{
  195. display: inline-block;
  196. background-color: #FF7159;
  197. font-size: 26upx;
  198. padding: 4upx 10upx;
  199. border-radius: 4upx;
  200. position: absolute;
  201. right: 20upx;
  202. bottom: 16upx;
  203. }
  204. .color-b{
  205. background-color: #e5e5e5;
  206. border-bottom-right-radius: 12upx;
  207. border-bottom-left-radius: 12upx;
  208. color: #fff;
  209. }
  210. </style>
distribution
agreement.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="article">
  4. <view class="article-content">
  5. <rich-text :nodes="content"></rich-text>
  6. </view>
  7. </view>
  8. </view>
  9. </template>
  10. <script>
  11. import htmlParser from '@/common/html-parser'
  12. export default {
  13. data() {
  14. return {
  15. content:this.$store.state.config.distribution_agreement,
  16. }
  17. },
  18. onLoad(e) {
  19. },
  20. computed: {
  21. },
  22. methods: {
  23. }
  24. }
  25. </script>
  26. <style>
  27. .content {
  28. /* #ifdef H5 */
  29. height: calc(100vh - 90upx);
  30. /* #endif */
  31. /* #ifndef H5 */
  32. height: 100vh;
  33. /* #endif */
  34. background-color: #fff;
  35. }
  36. .article {
  37. padding: 20upx;
  38. }
  39. .article-title {
  40. font-size: 32upx;
  41. color: #333;
  42. margin-bottom: 20upx;
  43. /* text-align: center; */
  44. position: relative;
  45. height: 100upx;
  46. }
  47. .article-time {
  48. /* text-align: right; */
  49. margin-left: 20upx;
  50. }
  51. .article-content {
  52. font-size: 28upx !important;
  53. color: #666;
  54. line-height: 1.6;
  55. margin-top: 20upx;
  56. }
  57. .article-content p img {
  58. width: 100% !important;
  59. }
  60. .shop-logo {
  61. width: 60upx;
  62. height: 60upx;
  63. border-radius: 50%;
  64. position: absolute;
  65. top: 50%;
  66. transform: translateY(-50%);
  67. }
  68. .shop-name {
  69. line-height: 100upx;
  70. margin-left: 80upx;
  71. }
  72. </style>
apply.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="apply-c">
  4. <view class="apply-top">
  5. <view class='cell-group'>
  6. <view class='cell-item'>
  7. <view class='cell-item-hd'>
  8. <view class='cell-hd-title'>姓名</view>
  9. </view>
  10. <view class='cell-item-bd'>
  11. <input type="text" class='cell-bd-input' placeholder='请填您的姓名' v-model="name"></input>
  12. </view>
  13. </view>
  14. <view class='cell-item'>
  15. <view class='cell-item-hd'>
  16. <view class='cell-hd-title'>微信</view>
  17. </view>
  18. <view class='cell-item-bd'>
  19. <input type="text" class='cell-bd-input' placeholder='请填您的微信' v-model="weixin"></input>
  20. </view>
  21. </view>
  22. <view class='cell-item'>
  23. <view class='cell-item-hd'>
  24. <view class='cell-hd-title'>QQ</view>
  25. </view>
  26. <view class='cell-item-bd'>
  27. <input type="number" class='cell-bd-input' placeholder='请填您的QQ' v-model="qq"></input>
  28. </view>
  29. </view>
  30. <view class='cell-item'>
  31. <view class='cell-item-hd'>
  32. <view class='cell-hd-title'>手机</view>
  33. </view>
  34. <view class='cell-item-bd'>
  35. <input type="number" class='cell-bd-input' placeholder='请填写您的手机号码' v-model="mobile"></input>
  36. </view>
  37. </view>
  38. </view>
  39. <view class="apply-tip color-6 fsz26">
  40. <label class="radio" @click="agreeAgreement"><radio value="1" :checked="checked" color="#FF7159"/>我已经阅读并接受</label><text class="" @click="goAgreement()">"分销协议"</text>
  41. </view>
  42. </view>
  43. <view class="apply-bot">
  44. <button class="btn btn-square btn-o btn-all" hover-class="btn-hover" @click="goApplyState()">申请成为分销</button>
  45. </view>
  46. </view>
  47. </view>
  48. </template>
  49. <script>
  50. export default {
  51. data() {
  52. return {
  53. name: '',
  54. weixin: '',
  55. qq: '',
  56. mobile: '',
  57. checked: false,
  58. is_agree: 'off'
  59. }
  60. },
  61. methods: {
  62. // 是否同意协议
  63. agreeAgreement(){
  64. if(this.checked){
  65. this.checked = false;
  66. this.is_agree = 'off';
  67. }else{
  68. this.checked = true;
  69. this.is_agree = 'on';
  70. }
  71. // console.log(this.checked)
  72. },
  73. // 信息验证
  74. checkData (data) {
  75. if (!data.name) {
  76. this.$common.errorToShow('请输入您的姓名')
  77. return false
  78. } else if (!data.weixin) {
  79. this.$common.errorToShow('请输入您的微信')
  80. return false
  81. } else if (!data.qq) {
  82. // console.log(this.is_agree)
  83. this.$common.errorToShow('请输入您的QQ')
  84. return false
  85. } else if (!data.mobile) {
  86. this.$common.errorToShow('请输入您的手机号')
  87. return false
  88. } else if (data.mobile.length !== 11) {
  89. this.$common.errorToShow('手机号格式不正确')
  90. return false
  91. } else if (data.agreement != 'on') {
  92. //console.log(data)
  93. this.$common.errorToShow('请钩选分销协议')
  94. return false
  95. } else {
  96. return true
  97. }
  98. },
  99. // 提交审核
  100. goApplyState() {
  101. let data = {
  102. name: this.name,
  103. weixin: this.weixin,
  104. qq: this.qq,
  105. mobile: this.mobile,
  106. agreement: this.is_agree,
  107. }
  108. if (this.checkData(data)) {
  109. this.$api.applyDistribution(data, res => {
  110. if(res.status){
  111. this.$common.successToShow(res.msg, function(){
  112. uni.navigateTo({
  113. url:'./apply_state'
  114. });
  115. });
  116. }else{
  117. this.$common.errorToShow(res.msg);
  118. }
  119. });
  120. }
  121. },
  122. goAgreement(){
  123. uni.navigateTo({
  124. url: './agreement'
  125. })
  126. }
  127. }
  128. }
  129. </script>
  130. <style>
  131. .content{
  132. background-color: #FF7159;
  133. height: calc(100vh - 44px);
  134. padding-top: 50upx;
  135. }
  136. .apply-c{
  137. margin: 40upx auto;
  138. padding: 26upx 0;
  139. border-radius: 30upx;
  140. box-shadow: 0 0 10px #aaa;
  141. width: 670upx;
  142. min-height: 400upx;
  143. background-color: #fff;
  144. }
  145. .apply-top .cell-item{
  146. width: 610upx;
  147. }
  148. .apply-top .cell-item:last-child{
  149. border-bottom: 1px solid #f3f3f3;
  150. }
  151. .apply-top .cell-item .cell-item-hd{
  152. min-width: 120upx;
  153. }
  154. .apply-top .cell-item .cell-bd-input{
  155. width: 100%;
  156. }
  157. .apply-tip{
  158. padding: 26upx;
  159. }
  160. .apply-bot{
  161. width: 100%;
  162. text-align: center;
  163. }
  164. .apply-bot .btn{
  165. border-radius: 50upx;
  166. width: 90%;
  167. margin: 40upx auto 0;
  168. }
  169. </style>
apply_state.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="apply-c">
  4. <view class="apply-top fsz36 color-o" v-if="info.verify==2">
  5. 恭喜,您的申请已提交!
  6. </view>
  7. <view class="apply-top-refuse fsz36 color-o" v-if="info.verify==3">
  8. 抱歉,您的申请被驳回!
  9. </view>
  10. <view class="apply-top fsz36 color-o" v-if="info.verify==1">
  11. 恭喜,您的申请已通过!
  12. </view>
  13. <view class="apply-bot" v-if="info.verify==2">
  14. <view class="apply-bot-sop">
  15. <view class="abs-img">
  16. <image class="icon" src="/static/image/del.png" mode=""></image>
  17. </view>
  18. <view class="color-9 abs-mid" >
  19. <image class="dot" src="/static/image/dot-o.png" mode=""></image>
  20. <image class="dot" src="/static/image/dot-o.png" mode=""></image>
  21. <image class="dot" src="/static/image/dot-o.png" mode=""></image>
  22. <image class="dot" src="/static/image/dot-o.png" mode=""></image>
  23. <image class="dot" src="/static/image/dot-o.png" mode=""></image>
  24. <image class="dot" src="/static/image/dot-o.png" mode=""></image>
  25. <image class="dot" src="/static/image/dot-g.png" mode=""></image>
  26. <image class="dot" src="/static/image/dot-g.png" mode="" ></image>
  27. <image class="dot" src="/static/image/dot-g.png" mode="" ></image>
  28. <image class="dot" src="/static/image/dot-g.png" mode="" ></image>
  29. <image class="dot" src="/static/image/dot-g.png" mode="" ></image>
  30. <image class="dot" src="/static/image/dot-g.png" mode="" ></image>
  31. </view>
  32. <view class="abs-img">
  33. <image class="icon" src="/static/image/close.png" mode=""></image>
  34. </view>
  35. </view>
  36. <view class="apply-bot-text">
  37. <view class="abt-c">
  38. <view class="color-6 fsz30">
  39. 申请提交成功
  40. </view>
  41. <view class="color-9 fsz24">
  42. {{info.ctime}}
  43. </view>
  44. </view>
  45. <view class="abt-c">
  46. <view class="color-6 fsz30" v-if="info.verify==2">
  47. 等待审核
  48. </view>
  49. <view class="color-6 fsz30" v-if="info.verify==3">
  50. 审核驳回
  51. </view>
  52. <view class="color-6 fsz30" v-if="info.verify==1">
  53. 审核通过
  54. </view>
  55. </view>
  56. </view>
  57. </view>
  58. </view>
  59. </view>
  60. </template>
  61. <script>
  62. export default {
  63. data() {
  64. return {
  65. info: {}
  66. }
  67. },
  68. onLoad:function() {
  69. var _this = this;
  70. _this.$api.getDistributioninfo({check_condition:true}, function(res) {
  71. if (res.status) {
  72. if(res.data.need_apply && res.data.condition_status ==false){
  73. _this.$common.redirectTo('/pages/member/distribution/index');
  74. }
  75. if(res.data.verify == 1){//审核通过
  76. _this.$common.redirectTo('/pages/member/distribution/user');
  77. }
  78. _this.info = res.data;
  79. } else {
  80. //报错了
  81. _this.$common.errorToShow(res.msg);
  82. }
  83. });
  84. },
  85. methods: {
  86. }
  87. }
  88. </script>
  89. <style>
  90. .content{
  91. height: calc(100vh - 44px);
  92. padding-top: 50upx;
  93. }
  94. .apply-c{
  95. margin: 40upx auto;
  96. text-align: center;
  97. padding: 26upx;
  98. border-radius: 30upx;
  99. box-shadow: 0 0 10px #aaa;
  100. width: 670upx;
  101. min-height: 400upx;
  102. background-color: #fff;
  103. }
  104. .apply-top{
  105. margin-top: 40upx;
  106. }
  107. .apply-top-refuse{
  108. margin-top: 140upx;
  109. }
  110. .apply-bot{
  111. width: 100%;
  112. text-align: center;
  113. }
  114. .apply-bot-sop{
  115. position: relative;
  116. height: 60upx;
  117. width: 65%;
  118. margin: 40upx auto 20upx;
  119. display: flex;
  120. line-height: 1.7555;
  121. /* vertical-align: middle; */
  122. }
  123. .apply-bot-sop>view{
  124. display: inline-block;
  125. }
  126. .abs-img{
  127. flex: 1;
  128. }
  129. .abs-img image{
  130. position: relative;
  131. top: 50%;
  132. transform: translateY(-50%);
  133. }
  134. .abs-mid{
  135. /* font-size: 70upx; */
  136. flex: 2;
  137. display: flex;
  138. }
  139. .apply-bot-text{
  140. display: flex;
  141. }
  142. .abt-c{
  143. flex: 1;
  144. }
  145. .dot{
  146. width: 8upx;
  147. height: 8upx;
  148. margin: 0 4upx;
  149. }
  150. </style>
index.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="content-top">
  4. <view class="dist-head">
  5. <view class="dist-head-top">
  6. <view class="dht-margin color-f fsz34" v-if="condition.condition_status">已达标</view>
  7. <view class="dht-margin color-f fsz34" v-if="!condition.condition_status">未达标</view>
  8. <cmd-progress class="dht-margin" :percent="condition.condition_progress" :stroke-width="23" stroke-color="linear-gradient(to right, #ef32d9, #89fffd)"></cmd-progress>
  9. <view class="dht-margin color-d fsz28">{{condition.condition_msg}}</view>
  10. </view>
  11. <view class="dist-head-tip color-f fsz24">
  12. 注:消费金额只算实付金额部分,储值抵扣/退款退货金额不算在内。
  13. </view>
  14. </view>
  15. <view class="dist-body">
  16. <view class="db-title color-3 fsz34">
  17. 分销商须知
  18. </view>
  19. <view class="db-body color-6 fsz30">
  20. <text class="db-item">{{distributionNotes}}</text>
  21. </view>
  22. </view>
  23. </view>
  24. <view class="button-bottom">
  25. <button class="btn btn-square btn-o" hover-class="btn-hover" v-if="condition.condition_status" @click="goApply()">申请</button>
  26. <button class="btn btn-square btn-g" v-else >您的条件暂不满足</button>
  27. </view>
  28. </view>
  29. </template>
  30. <script>
  31. import cmdProgress from '@/components/cmd-progress/cmd-progress.vue'
  32. export default {
  33. components: { cmdProgress },
  34. data() {
  35. return {
  36. condition: {}
  37. }
  38. },
  39. methods: {
  40. goApply() {
  41. this.$common.navigateTo('./apply');
  42. }
  43. },
  44. computed: {
  45. distributionNotes () {
  46. return this.$store.state.config.distribution_notes
  47. }
  48. },
  49. onLoad: function() {
  50. var _this = this;
  51. _this.$api.getDistributioninfo({}, function(res) {
  52. if (res.status) {
  53. _this.condition = res.data;
  54. if(_this.condition.hasOwnProperty('verify')){
  55. if(_this.condition.verify == 1 || (!_this.condition.need_apply && _this.condition_status)){
  56. _this.$common.redirectTo('/pages/member/distribution/user');
  57. }else if(_this.condition.condition_status){
  58. _this.$common.redirectTo('/pages/member/distribution/apply_state');//待审核
  59. }
  60. }
  61. } else {
  62. //报错了
  63. _this.$common.errorToShow(res.msg);
  64. }
  65. });
  66. }
  67. }
  68. </script>
  69. <style>
  70. .content{
  71. background-color: #fff;
  72. height: calc(100vh - 44px);
  73. }
  74. .dist-head{
  75. padding: 50upx 26upx 20upx;
  76. text-align: center;
  77. background: linear-gradient( #FF7159, #ff9785);
  78. }
  79. .dist-head-top{
  80. padding: 0upx 50upx 30upx;
  81. }
  82. .dht-margin{
  83. margin-bottom: 26upx;
  84. }
  85. .dht-margin.color-d{
  86. padding: 0 40upx;
  87. }
  88. .dht-mid{
  89. margin-bottom: 12upx;
  90. }
  91. .dist-head-tip{
  92. text-align: left;
  93. }
  94. .dist-body{
  95. padding: 26upx;
  96. }
  97. .db-title{
  98. border-bottom: 2upx solid #ccc;
  99. padding-bottom: 26upx;
  100. }
  101. .db-body{
  102. padding: 26upx 10upx;
  103. }
  104. .db-item{
  105. /* padding: ; */
  106. margin-bottom: 14upx;
  107. }
  108. pre {
  109. white-space: pre-wrap; /* css-3 */
  110. white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
  111. white-space: -pre-wrap; /* Opera 4-6 */
  112. white-space: -o-pre-wrap; /* Opera 7 */
  113. word-wrap: break-word; /* Internet Explorer 5.5+ */
  114. }
  115. </style>
my_store.vue
复制代码
  1. <template>
  2. <view class="content my-store">
  3. <view class="" ref="myStore">
  4. <view class="my-store-t">
  5. <view class="mst-top">
  6. <image :src="store_banner_src" mode="widthFix"></image>
  7. </view>
  8. <view class="mst-bot">
  9. <view class='member-grid'>
  10. <view class='member-item'>
  11. <image class='member-item-img' :src='store_logo_src'></image>
  12. </view>
  13. <view class='member-item'>
  14. <view class="color-o fsz36">{{total_goods}}</view>
  15. <text class='member-item-text'>全部宝贝</text>
  16. </view>
  17. <view class='member-item' @click="openPopup()">
  18. <image class='member-item-icon' src='/static/image/ic-me-collect.png'></image>
  19. <text class='member-item-text'>收藏本店</text>
  20. </view>
  21. <view class='member-item'>
  22. <!-- #ifdef MP-WEIXIN -->
  23. <button class='share btn' open-type="share">
  24. <image class='member-item-icon' src='/static/image/qr_code.png'></image>
  25. <text class='member-item-text'>二维码</text>
  26. </button>
  27. <!-- #endif -->
  28. <!-- #ifndef MP-WEIXIN -->
  29. <button class='share btn' @click="createPoster()">
  30. <image class='member-item-icon' src='/static/image/qr_code.png'></image>
  31. <text class='member-item-text'>二维码</text>
  32. </button>
  33. <!-- #endif -->
  34. </view>
  35. </view>
  36. </view>
  37. </view>
  38. <view class="my-store-m">
  39. <view class="search">
  40. <view class="search-c" @click="goSearch">
  41. <view class="search-input search-input-p">
  42. <view class="search-input-p-c">
  43. {{ searchKey }}
  44. </view>
  45. </view>
  46. <image class="icon search-icon" src="/static/image/zoom.png"></image>
  47. </view>
  48. </view>
  49. </view>
  50. <!-- 收藏弹出窗 -->
  51. <lvv-popup position="bottom" ref="lvvpopref" @click="closePopup()">
  52. <view class="collect-pop" @click="closePopup()">
  53. <image v-if="isWeixinBrowser" src="/static/image/wxh5.png" mode="widthFix"></image>
  54. <!-- #ifdef MP-WEIXIN -->
  55. <image src="/static/image/wxxcx.png" mode="widthFix"></image>
  56. <!-- #endif -->
  57. <!-- #ifdef H5 -->
  58. <view class="h5-tip color-f fsz38">
  59. <view>请将此页面添加浏览器书签</view>
  60. <view>方便下次浏览</view>
  61. </view>
  62. <!-- #endif -->
  63. </view>
  64. </lvv-popup>
  65. </view>
  66. <!-- 商品列表 -->
  67. <view class="img-grids">
  68. <view v-if="goodsList.length>0">
  69. <view class="img-grids-item" v-for="(item, index) in goodsList" :key="index" @click="goodsDetail(item.id)">
  70. <image class="img-grids-item-t have-none" :src="item.image_url" mode='aspectFill'></image>
  71. <view class="img-grids-item-b">
  72. <view class="goods-name grids-goods-name">
  73. {{item.name}}
  74. </view>
  75. <view class="goods-item-c">
  76. <view class="goods-price red-price">¥{{item.price}}</view>
  77. <image class="goods-cart" src="../../static/image/ic-car.png"></image>
  78. </view>
  79. </view>
  80. </view>
  81. </view>
  82. <!-- 无数据时默认显示 -->
  83. <view class="order-none" v-else>
  84. <image class="order-none-img" src="../../static/image/order.png" mode=""></image>
  85. </view>
  86. </view>
  87. <uni-load-more :status="loadStatus"></uni-load-more>
  88. </view>
  89. </template>
  90. <script>
  91. import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue'
  92. import lvvPopup from '@/components/lvv-popup/lvv-popup.vue';
  93. import {
  94. apiBaseUrl
  95. } from '@/config/config.js'
  96. export default {
  97. components: {
  98. lvvPopup,
  99. uniLoadMore
  100. },
  101. data() {
  102. return {
  103. goodsList: [],
  104. loadStatus: 'more',
  105. orderItems: [{
  106. name: '全部宝贝',
  107. nums: '115'
  108. },
  109. {
  110. name: '收藏本店',
  111. icon: '/static/image/ic-me-collect.png',
  112. },
  113. {
  114. name: '二维码',
  115. icon: '/static/image/qr_code.png',
  116. }
  117. ],
  118. storeCode: '',
  119. store_name: '', //店铺名称
  120. store_logo: '',
  121. store_logo_src: '',
  122. store_banner: '',
  123. store_desc: '', //店铺介绍
  124. store_banner_src: '',
  125. isWeixinBrowser: this.$common.isWeiXinBrowser(), //判断是否是微信浏览器
  126. total_goods: 0,
  127. myShareCode: '', //邀请码
  128. page: 1, //默认页码
  129. searchKey: '请输入关键字搜索'
  130. }
  131. },
  132. onShow: function() {
  133. if (this.$store.state.config.distribution_store == '2') {
  134. //跳转到首页
  135. uni.switchTab({
  136. url: '/pages/index/index'
  137. });
  138. }
  139. },
  140. //加载执行
  141. onLoad: function(options) {
  142. let store = options.store;
  143. this.storeCode = store;
  144. this.getDistribution(store);
  145. this.getGoods();
  146. this.getMyShareCode()
  147. },
  148. mounted() {
  149. // #ifdef H5 || APP-PLUS
  150. window.addEventListener('scroll', this.handleScroll)
  151. // #endif
  152. },
  153. updated() {
  154. // #ifndef MP-WEIXIN
  155. // 获取上半部分的整体高度
  156. this.$nextTick(() => {
  157. let h = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; //浏览器高度
  158. this.top_height = this.$refs.myStore.$el.clientHeight;
  159. })
  160. // #endif
  161. },
  162. methods: {
  163. // 显示modal弹出框
  164. openPopup() {
  165. this.$refs.lvvpopref.show();
  166. },
  167. // 关闭modal弹出框
  168. closePopup() {
  169. this.$refs.lvvpopref.close();
  170. },
  171. //去搜索
  172. goSearch() {
  173. let pages = getCurrentPages();
  174. let prevPage = pages[pages.length - 2];
  175. // #ifdef H5 || MP-WEIXIN
  176. if (prevPage && prevPage.route) {
  177. let search_flag = prevPage.route;
  178. if (search_flag == 'pages/index/search') {
  179. uni.navigateBack({
  180. delta: 1
  181. });
  182. } else {
  183. this.$common.navigateTo('/pages/index/search');
  184. }
  185. } else {
  186. this.$common.navigateTo('/pages/index/search');
  187. }
  188. // #endif
  189. // #ifdef MP-ALIPAY
  190. if (prevPage && prevPage.__proto__.route) {
  191. let search_flag = prevPage.__proto__.route;
  192. if (search_flag == 'pages/index/search') {
  193. uni.navigateBack({
  194. delta: 1
  195. });
  196. } else {
  197. this.$common.navigateTo('/pages/index/search');
  198. }
  199. } else {
  200. this.$common.navigateTo('/pages/index/search');
  201. }
  202. // #endif
  203. },
  204. //跳转到商品详情页面
  205. goodsDetail: function(id) {
  206. let url = '/pages/goods/index/index?id=' + id;
  207. this.$common.navigateTo(url);
  208. },
  209. //取得商品数据
  210. getGoods: function() {
  211. let data = {
  212. page: this.page,
  213. limit: 10
  214. }
  215. this.loadStatus = 'loading'
  216. this.$api.goodsList(data, res => {
  217. if (res.status) {
  218. if (this.page >= res.data.total_page) {
  219. // 没有数据了
  220. this.loadStatus = 'noMore'
  221. } else {
  222. // 未加载完毕
  223. this.loadStatus = 'more'
  224. this.page++
  225. }
  226. this.goodsList = [...this.goodsList, ...res.data.list]
  227. } else {
  228. this.$common.errorToShow(res.msg)
  229. }
  230. });
  231. },
  232. //获取分销商信息
  233. getDistribution: function(store) {
  234. let _this = this;
  235. _this.$api.getStoreInfo({
  236. store: store
  237. }, function(res) {
  238. if (res.status) {
  239. _this.store_name = res.data.store_name;
  240. _this.store_desc = res.data.store_desc;
  241. _this.store_logo_src = res.data.store_logo_src;
  242. _this.store_logo = res.data.store_logo;
  243. _this.store_banner_src = res.data.store_banner_src;
  244. _this.total_goods = res.data.total_goods;
  245. uni.setNavigationBarTitle({
  246. title: _this.store_name
  247. });
  248. } else {
  249. //报错了
  250. _this.$common.errorToShow(res.msg);
  251. }
  252. });
  253. },
  254. // 生成邀请海报
  255. createPoster() {
  256. let data = {
  257. type: 4,
  258. id: this.storeCode
  259. }
  260. let pages = getCurrentPages()
  261. let page = pages[pages.length - 1]
  262. let page_path = '/pages/share/jump';
  263. // #ifdef H5
  264. data.source = 1;
  265. data.return_url = apiBaseUrl + 'wap/' + page_path;
  266. // #endif
  267. // #ifdef MP-WEIXIN
  268. data.source = 2;
  269. data.return_url = page_path;
  270. // #endif
  271. // #ifdef MP-ALIPAY
  272. data.source = 3;
  273. data.return_url = page_path;
  274. // #endif
  275. let userToken = this.$db.get('userToken')
  276. if (userToken) {
  277. data.token = userToken
  278. }
  279. this.$api.createPoster(data, res => {
  280. if (res.status) {
  281. this.$common.navigateTo('/pages/share?poster=' + res.data)
  282. } else {
  283. this.$common.errorToShow(res.msg)
  284. }
  285. })
  286. },
  287. getMyShareCode() {
  288. let userToken = this.$db.get("userToken");
  289. if (userToken && userToken != '') {
  290. // 获取我的分享码
  291. this.$api.shareCode({}, res => {
  292. if (res.status) {
  293. this.myShareCode = res.data ? res.data : '';
  294. }
  295. });
  296. }
  297. }
  298. },
  299. //上拉加载
  300. onReachBottom() {
  301. if (this.loadStatus === 'more') {
  302. this.getGoods();
  303. }
  304. },
  305. //分享
  306. onShareAppMessage() {
  307. let myInviteCode = this.myShareCode ? this.myShareCode : '';
  308. let ins = this.$common.shareParameterDecode('type=9&invite=' + myInviteCode + "&id=" + this.storeCode);
  309. let path = '/pages/share/jump?scene=' + ins;
  310. return {
  311. title: this.$store.state.config.share_title,
  312. // #ifdef MP-ALIPAY
  313. desc: this.$store.state.config.share_desc,
  314. // #endif
  315. imageUrl: this.$store.state.config.share_image,
  316. path: path
  317. }
  318. }
  319. }
  320. </script>
  321. <style>
  322. .mst-top {
  323. width: 100%;
  324. }
  325. .mst-top image {
  326. width: 100%;
  327. }
  328. .member-grid {
  329. border-top: 2upx solid #ddd;
  330. background-color: #fff;
  331. margin-bottom: 20upx;
  332. }
  333. .member-item {
  334. border-right: 2upx solid #eee;
  335. height: 90upx;
  336. }
  337. .member-item:last-child {
  338. border-right: none;
  339. }
  340. .member-item-img {
  341. width: 150upx;
  342. height: 150upx;
  343. top: -70upx;
  344. position: absolute;
  345. left: 42%;
  346. transform: translateX(-50%);
  347. border-radius: 10upx;
  348. background-color: #fff;
  349. border-radius: 6upx;
  350. box-shadow: 0 0 10upx #ccc;
  351. }
  352. .img-grids {
  353. padding-bottom: 26upx;
  354. }
  355. .img-grids-item {
  356. margin-bottom: 0;
  357. }
  358. .scroll-Y {
  359. /* #ifdef H5 */
  360. height: calc(100vh - 44px - 0upx);
  361. /* #endif */
  362. /* #ifndef H5 */
  363. height: calc(100vh - 0upx);
  364. /* #endif */
  365. position: position;
  366. /* bottom: 0; */
  367. /* padding-bottom:200upx */
  368. }
  369. .collect-pop {
  370. width: 100%;
  371. height: 100%;
  372. /* background: #FFFFFF; */
  373. position: absolute;
  374. left: 0;
  375. bottom: 0;
  376. /* transform: ; */
  377. }
  378. .collect-pop image {
  379. width: 100%;
  380. }
  381. .h5-tip {
  382. text-align: center;
  383. margin-top: 300upx;
  384. }
  385. .member-item .share {
  386. background: none !important;
  387. line-height: normal;
  388. }
  389. </style>
order.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="type-c" v-if="list.length">
  4. <view class="cell-group margin-cell-group" v-for="(item, index) in list" :key="index">
  5. <view class="cell-item">
  6. <view class="cell-item-hd">
  7. <view class='cell-hd-title'>下单人:{{ item.buy_user }}</view>
  8. </view>
  9. <view class="cell-item-ft">
  10. <view class="cell-ft-p color-9">
  11. {{ item.ctime }}
  12. </view>
  13. </view>
  14. </view>
  15. <view class="cell-item">
  16. <view class="cell-item-hd">
  17. <view class='cell-hd-title color-9'>订单号:{{ item.order_id }}</view>
  18. </view>
  19. <view class="cell-item-ft red-price">
  20. {{ item.amount }}
  21. </view>
  22. </view>
  23. </view>
  24. <uni-load-more
  25. :status="loadStatus"
  26. ></uni-load-more>
  27. </view>
  28. <view class="order-none" v-else>
  29. <image class="balance-none-img" src="/static/image/order.png" mode=""></image>
  30. </view>
  31. </view>
  32. </template>
  33. <script>
  34. import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue'
  35. import { goods } from '@/config/mixins.js'
  36. export default {
  37. mixins: [ goods ],
  38. components: {
  39. uniLoadMore
  40. },
  41. data() {
  42. return {
  43. startTime: 0,
  44. screenName: '',
  45. page: 1,
  46. limit: 10,
  47. list: [], // 商品浏览足迹
  48. loadStatus: 'more'
  49. };
  50. },
  51. onLoad () {
  52. this.getDistributionOrder()
  53. },
  54. onShow() {
  55. const res = uni.getSystemInfoSync();
  56. },
  57. onReachBottom () {
  58. if (this.loadStatus === 'more') {
  59. this.getDistributionOrder()
  60. }
  61. },
  62. methods: {
  63. getDistributionOrder () {
  64. let data = {
  65. page: this.page,
  66. limit: this.limit
  67. }
  68. this.loadStatus = 'loading'
  69. this.$api.getDistributionOrder(data, res => {
  70. //console.log(res);
  71. if (res.status) {
  72. let _list = res.data.list
  73. _list.forEach (item => {
  74. this.$set(item, 'slide_x', 0)
  75. })
  76. this.list = [...this.list, ..._list]
  77. if (res.data.count > this.list.length) {
  78. this.page ++
  79. this.loadStatus = 'more'
  80. } else {
  81. this.loadStatus = 'noMore'
  82. }
  83. } else {
  84. this.$common.errorToShow(res.msg)
  85. }
  86. })
  87. },
  88. }
  89. };
  90. </script>
  91. <style scoped>
  92. .type-c .cell-group{
  93. padding: 10upx 0;
  94. margin-top: 0;
  95. }
  96. .type-c .cell-item{
  97. border: none;
  98. min-height: 70upx;
  99. padding: 0 26upx 0 0;
  100. }
  101. .type-c .cell-item .red-price{
  102. font-size: 50upx;
  103. }
  104. .type-c .cell-item .color-9{
  105. font-size: 24upx;
  106. }
  107. .order-none{
  108. text-align: center;
  109. padding: 200upx 0;
  110. }
  111. .balance-none-img{
  112. width: 274upx;
  113. height: 274upx;
  114. }
  115. </style>
popularize.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="content-c">
  4. <view class="content-c-top color-6 fsz28">
  5. 将网站分享给您的好友,您的好友通过您的分享购买网站商品,你将会获得佣金。
  6. </view>
  7. <image class="qrcode-img" src="/static/demo-img/qcode.png" mode="widthFix"></image>
  8. <view class="color-3 fsz26">
  9. 长按保存二维码图片
  10. </view>
  11. </view>
  12. </view>
  13. </template>
  14. <script>
  15. </script>
  16. <style>
  17. .content-c{
  18. text-align: center;
  19. padding: 50upx 0;
  20. width: 80%;
  21. margin: 0 auto;
  22. }
  23. .content-c-top{
  24. text-align: left;
  25. }
  26. .qrcode-img{
  27. width: 400upx;
  28. height: 400upx;
  29. /* margin-top: 50upx; */
  30. margin: 50upx auto;
  31. }
  32. </style>
store_setting.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="content-top">
  4. <view class='cell-group'>
  5. <view class='cell-item'>
  6. <view class='cell-item-hd'>
  7. <view class='cell-hd-title'>名称</view>
  8. </view>
  9. <view class='cell-item-bd'>
  10. <input class='cell-bd-input' placeholder='请输入店铺名称' v-model="store_name"></input>
  11. </view>
  12. </view>
  13. <view class='cell-item user-head'>
  14. <view class='cell-item-hd'>
  15. <view class='cell-hd-title'>图标</view>
  16. </view>
  17. <view class='cell-item-ft'>
  18. <image class='cell-ft-next user-head-img have-none' mode="aspectFill" :src="logo" @click="uploadLogo"></image>
  19. </view>
  20. </view>
  21. </view>
  22. <view class='cell-group'>
  23. <view class='cell-item right-img'>
  24. <view class='cell-item-hd'>
  25. <view class='cell-hd-title'>店招</view>
  26. </view>
  27. </view>
  28. <view class="">
  29. <view class="evaluate-c-b">
  30. <view class="goods-img-item" v-for="(item, key) in images" :key="key">
  31. <image class="del" src="/static/image/del.png" mode="" @click="delImage(item)"></image>
  32. <image class="" :src="item.url" mode="" @click="clickImg(item.url)"></image>
  33. </view>
  34. <view class="upload-img" v-show="isImage" @click="upImage">
  35. <image class="icon" src="/static/image/camera.png" mode=""></image>
  36. <view class="">上传照片</view>
  37. </view>
  38. </view>
  39. </view>
  40. </view>
  41. <view class='cell-group'>
  42. <view class='cell-item right-img'>
  43. <view class='cell-item-hd'>
  44. <view class='cell-hd-title'>简介</view>
  45. </view>
  46. </view>
  47. <view class="cell-textarea ">
  48. <textarea v-model="store_desc" placeholder="请您在此描述问题(最多200字)" maxlength="200" />
  49. </view>
  50. </view>
  51. </view>
  52. <view class="button-bottom">
  53. <button class="btn btn-square btn-b" hover-class="btn-hover2" @click="submitHandler()">保存</button>
  54. </view>
  55. </view>
  56. </template>
  57. <script>
  58. export default {
  59. data() {
  60. return {
  61. title: 'picker',
  62. logo: '',
  63. index: 2,
  64. images:[],
  65. image_max: 1,
  66. store_name:'',//店铺名称
  67. store_logo:'',
  68. store_banner:'',
  69. store_desc:'',//店铺介绍
  70. store_logo_src:'',
  71. store_banner_src:'',
  72. }
  73. },
  74. computed: {
  75. isImage() {
  76. let num = this.image_max - this.images.length;
  77. if(num > 0) {
  78. return true;
  79. }else{
  80. return false;
  81. }
  82. }
  83. },
  84. methods: {
  85. // 用户上传头像
  86. uploadLogo () {
  87. this.$api.uploadFiles(res => {
  88. if (res.status) {
  89. this.store_logo = res.data.image_id;
  90. this.logo = res.data.url;
  91. } else {
  92. this.$common.errorToShow(res.msg)
  93. }
  94. })
  95. },
  96. // 保存资料
  97. submitHandler() {
  98. if(!this.store_name||this.store_name==''){
  99. this.$common.errorToShow('请填写店铺名称');
  100. return;
  101. }
  102. if(this.images.length <= 0){
  103. this.$common.errorToShow('请上传店招');
  104. return;
  105. }
  106. if(!this.store_logo){
  107. this.$common.errorToShow('请上传图标');
  108. return;
  109. }
  110. this.store_banner = this.images[0].image_id;
  111. this.$api.setStore({
  112. store_name: this.store_name,
  113. store_logo: this.store_logo,
  114. store_banner: this.store_banner,
  115. store_desc: this.store_desc
  116. }, res => {
  117. if(res.status){
  118. this.$common.successToShow(res.msg, result => {
  119. uni.navigateBack({
  120. delta: 1
  121. });
  122. });
  123. }else{
  124. this.$common.errorToShow(res.msg);
  125. }
  126. }
  127. );
  128. },
  129. //上传图片
  130. upImage() {
  131. let num = this.image_max - this.images.length;
  132. if(num > 0){
  133. this.$api.uploadImage(num, res => {
  134. if(res.status){
  135. this.images.push(res.data);
  136. this.$common.successToShow(res.msg);
  137. }else{
  138. this.$common.errorToShow(res.msg);
  139. }
  140. });
  141. }
  142. },
  143. //删除图片
  144. delImage(e) {
  145. let newImages = [];
  146. for(var i = 0; i < this.images.length; i++) {
  147. if(this.images[i].image_id != e.image_id){
  148. newImages.push(this.images[i]);
  149. }
  150. }
  151. this.images = newImages;
  152. },
  153. // 图片点击放大
  154. clickImg (img) {
  155. // 预览图片
  156. uni.previewImage({
  157. urls: img.split()
  158. });
  159. }
  160. },
  161. onLoad: function() {
  162. var _this = this;
  163. _this.$api.getDistributioninfo({check_condition:false}, function(res) {
  164. if (res.status) {
  165. _this.store_name = res.data.store_name;
  166. _this.store_desc = res.data.store_desc;
  167. _this.store_logo = res.data.store_logo;
  168. if( res.data.store_logo){
  169. _this.logo = res.data.store_logo_src;
  170. }
  171. _this.store_banner = res.data.store_banner;
  172. if(_this.store_banner){
  173. _this.images.push({
  174. image_id:res.data.store_banner,
  175. url:res.data.store_banner_src
  176. });
  177. }
  178. } else {
  179. //报错了
  180. _this.$common.errorToShow(res.msg);
  181. }
  182. });
  183. }
  184. }
  185. </script>
  186. <style>
  187. .user-head{
  188. height: 100upx;
  189. }
  190. .user-head-img{
  191. height: 90upx;
  192. width: 90upx;
  193. border-radius: 50%;
  194. }
  195. .cell-hd-title{
  196. color: #333;
  197. }
  198. .cell-item-bd{
  199. color: #666;
  200. font-size: 26upx;
  201. }
  202. .list-goods-name{
  203. width: 100% !important;
  204. }
  205. .cart-checkbox-item{
  206. position: relative;
  207. }
  208. .invoice-type .uni-list-cell{
  209. display: inline-block;
  210. font-size: 26upx;
  211. color: #333;
  212. position: relative;
  213. margin-left: 50upx;
  214. }
  215. .invoice-type .uni-list-cell>view{
  216. display: inline-block;
  217. }
  218. .invoice-type-icon{
  219. position: absolute;
  220. top: 50%;
  221. transform: translateY(-50%);
  222. }
  223. .invoice-type-c{
  224. margin-left: 50upx;
  225. line-height: 2;
  226. }
  227. .cell-item-ft .cell-bd-input{
  228. text-align: right;
  229. width: 500upx;
  230. font-size: 28upx;
  231. }
  232. .right-img{
  233. border-bottom: 0;
  234. }
  235. .cell-textarea{
  236. padding: 0 26upx 20upx;
  237. }
  238. .cell-textarea textarea{
  239. width: 100%;
  240. height: 200upx;
  241. font-size: 26upx;
  242. color: #333;
  243. }
  244. .evaluate-c-b{
  245. overflow: hidden;
  246. padding: 0 20upx;
  247. }
  248. .upload-img{
  249. width: 146upx;
  250. height: 146upx;
  251. margin: 14upx;
  252. text-align: center;
  253. color: #999999;
  254. font-size: 22upx;
  255. border: 2upx solid #E1E1E1;
  256. border-radius: 4upx;
  257. display: inline-block;
  258. float: left;
  259. padding: 24upx 0;
  260. }
  261. .goods-img-item{
  262. width: 174upx;
  263. height: 174upx;
  264. padding: 14upx;
  265. float: left;
  266. position: relative;
  267. }
  268. .goods-img-item:nth-child(4n){
  269. margin-right: 0;
  270. }
  271. .goods-img-item image{
  272. width: 100%;
  273. height: 100%;
  274. }
  275. .del{
  276. width: 30upx !important;
  277. height: 30upx !important;
  278. position: absolute;
  279. right: 0;
  280. top: 0;
  281. z-index: 999;
  282. }
  283. .cell-textarea textarea{
  284. background-color: #f8f8f8;
  285. padding: 12upx 20upx;
  286. box-sizing: border-box;
  287. }
  288. </style>
user.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <!-- 用户头像header -->
  4. <view class='member-top'>
  5. <!-- <image class='bg-img' src='/static/image/member-bg.png'></image> -->
  6. <view class='member-top-c'>
  7. <view class="fsz50 color-f">{{info.total_settlement_amount}}</view>
  8. <view class='fsz26 color-d'>累计收入</view>
  9. </view>
  10. </view>
  11. <!-- 用户头像header end -->
  12. <!-- 其他功能菜单 -->
  13. <view class='member-grid'>
  14. <view class='member-item' v-for="(item, index) in orderItems" :key="index">
  15. <text class='member-item-text'>{{ item.name }}</text>
  16. <view class="color-o fsz38">{{ item.nums }}</view>
  17. </view>
  18. </view>
  19. <view class='cell-group margin-cell-group right-img'>
  20. <view class='cell-item' v-for="(item, index) in utilityMenus" :key="index">
  21. <view class='cell-item-hd' @click="navigateToHandle(item.router)">
  22. <image class='cell-hd-icon' :src='item.icon'></image>
  23. <view class='cell-hd-title'>{{ item.name }}</view>
  24. </view>
  25. <view class='cell-item-ft'>
  26. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  27. </view>
  28. </view>
  29. <view class='cell-item'>
  30. <view class='cell-item-hd' @click="createPoster()">
  31. <image class='cell-hd-icon' src='/static/image/extension.png'></image>
  32. <view class='cell-hd-title'>我要推广</view>
  33. </view>
  34. <view class='cell-item-ft'>
  35. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  36. </view>
  37. </view>
  38. </view>
  39. <!-- 其他功能菜单end -->
  40. <jihaiCopyright></jihaiCopyright>
  41. </view>
  42. </template>
  43. <script>
  44. import jihaiCopyright from '@/components/jihai-copyright/jihaiCopyright.vue'
  45. import {
  46. checkLogin
  47. } from '@/config/mixins.js'
  48. import {
  49. apiBaseUrl
  50. } from '@/config/config.js'
  51. export default {
  52. components: {
  53. jihaiCopyright
  54. },
  55. mixins: [checkLogin],
  56. data() {
  57. return {
  58. // isClerk: false,
  59. orderItems: {
  60. freeze: {
  61. name: '冻结金额',
  62. nums: "0"
  63. },
  64. settlement: {
  65. name: '已结算金额',
  66. nums: '0'
  67. },
  68. current_month_order: {
  69. name: '本月订单数',
  70. nums: '0'
  71. }
  72. },
  73. utilityMenus: {
  74. invite: {
  75. name: '我的邀请',
  76. icon: '/static/image/ic-me-invite.png',
  77. router: '../invite/list'
  78. },
  79. order: {
  80. name: '推广订单',
  81. icon: '/static/image/extension_order.png',
  82. router: './order'
  83. },
  84. balance: {
  85. name: '我的佣金',
  86. icon: '/static/image/ic-me-balance.png',
  87. router: '../balance/details?status=5'
  88. },
  89. my_store: {
  90. name: '我的店铺',
  91. icon: '/static/image/my_store.png',
  92. router: './my_store'
  93. },
  94. store_setting: {
  95. name: '店铺设置',
  96. icon: '/static/image/me-ic-set.png',
  97. router: './store_setting'
  98. }
  99. },
  100. info: {}, //分销商信息
  101. }
  102. },
  103. onShow() {
  104. var _this = this;
  105. if (_this.$store.state.config.distribution_store != '1') {
  106. delete this.utilityMenus.my_store;
  107. delete this.utilityMenus.store_setting;
  108. }
  109. _this.$api.getDistributioninfo({}, function(res) {
  110. if (res.status) {
  111. _this.info = res.data;
  112. if (res.data.verify != 1) { //审核通过
  113. _this.$common.redirectTo('/pages/member/distribution/index');
  114. }
  115. _this.orderItems.freeze.nums = _this.info.freeze_amount;
  116. _this.orderItems.settlement.nums = _this.info.settlement_amount;
  117. _this.orderItems.current_month_order.nums = _this.info.current_month_order;
  118. if (_this.$store.state.config.distribution_store == '1') {
  119. _this.utilityMenus.my_store.router = './my_store?store=' + _this.info.store;
  120. }
  121. } else {
  122. //报错了
  123. _this.$common.errorToShow(res.msg);
  124. }
  125. });
  126. },
  127. methods: {
  128. navigateToHandle(pageUrl) {
  129. this.$common.navigateTo(pageUrl)
  130. },
  131. orderNavigateHandle(url, tab = 0) {
  132. if (!this.hasLogin) {
  133. return this.checkIsLogin()
  134. }
  135. this.$store.commit('orderTab', tab)
  136. this.$common.navigateTo(url)
  137. },
  138. goAfterSaleList() {
  139. if (!this.hasLogin) {
  140. return this.checkIsLogin()
  141. }
  142. this.$common.navigateTo('../after_sale/list')
  143. },
  144. // 生成邀请海报
  145. createPoster() {
  146. let data = {
  147. type: 4,
  148. id: this.info.store,
  149. }
  150. //console.log(this.info.store)
  151. let pages = getCurrentPages()
  152. let page = pages[pages.length - 1]
  153. let page_path = '/pages/share/jump';
  154. // #ifdef H5
  155. data.source = 1;
  156. data.return_url = apiBaseUrl + 'wap/' + page_path;
  157. // #endif
  158. // #ifdef MP-WEIXIN
  159. data.source = 2;
  160. data.return_url = page_path;
  161. // #endif
  162. // #ifdef MP-ALIPAY
  163. data.source = 3;
  164. data.return_url = page_path;
  165. // #endif
  166. let userToken = this.$db.get('userToken')
  167. if (userToken) {
  168. data.token = userToken
  169. }
  170. this.$api.createPoster(data, res => {
  171. if (res.status) {
  172. this.$common.navigateTo('/pages/share?poster=' + res.data)
  173. } else {
  174. this.$common.errorToShow(res.msg)
  175. }
  176. })
  177. },
  178. },
  179. //分享
  180. onShareAppMessage() {
  181. let myInviteCode = this.myShareCode ? this.myShareCode : '';
  182. let ins = this.$common.shareParameterDecode('type=3&invite=' + myInviteCode);
  183. let path = '/pages/share/jump?scene=' + ins;
  184. return {
  185. title: this.$store.state.config.share_title,
  186. // #ifdef MP-ALIPAY
  187. desc: this.$store.state.config.share_desc,
  188. // #endif
  189. imageUrl: this.$store.state.config.share_image,
  190. path: path
  191. }
  192. }
  193. }
  194. </script>
  195. <style>
  196. .member-top {
  197. position: relative;
  198. width: 100%;
  199. height: 340upx;
  200. background-color: #FF7159;
  201. }
  202. .bg-img {
  203. position: absolute;
  204. width: 100%;
  205. height: 100%;
  206. }
  207. .member-top-c {
  208. position: absolute;
  209. top: 50%;
  210. left: 50%;
  211. transform: translate(-50%, -50%);
  212. text-align: center;
  213. }
  214. .user-head-img {
  215. display: block;
  216. width: 160upx;
  217. height: 160upx;
  218. border-radius: 50%;
  219. overflow: hidden;
  220. background-color: rgba(255, 255, 255, 0.7);
  221. }
  222. .user-name {
  223. font-size: 30upx;
  224. color: #fff;
  225. }
  226. .member-grid {
  227. background-color: #fff;
  228. border-top: 2upx solid #eee;
  229. padding: 20upx 0;
  230. }
  231. .margin-cell-group {
  232. margin: 20upx 0;
  233. color: #666666;
  234. }
  235. .badge {
  236. left: 80upx;
  237. top: -6upx;
  238. }
  239. button.cell-item-hd {
  240. background-color: #fff;
  241. padding: 0;
  242. line-height: 1.4;
  243. color: #333;
  244. }
  245. button.cell-item-hd:after {
  246. border: none;
  247. }
  248. .login-btn {
  249. color: #fff;
  250. width: 160upx;
  251. height: 50upx;
  252. line-height: 50upx;
  253. border-radius: 25upx;
  254. background: #ff7159;
  255. font-size: 12px;
  256. margin-top: 16upx;
  257. }
  258. </style>
history
index.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="collection" v-if="list.length">
  4. <view class="container_of_slide"
  5. v-for="(item, index) in list"
  6. :key="index"
  7. >
  8. <view class="slide_list"
  9. @touchstart="touchStart($event,index)"
  10. @touchend="touchEnd($event,index)"
  11. @touchmove="touchMove($event,index)"
  12. @tap="recover(index)"
  13. :style="{transform:'translate3d('+item.slide_x+'px, 0, 0)'}"
  14. v-if="item.goods"
  15. >
  16. <view class="now-message-info" hover-class="uni-list-cell-hover" :style="{width:Screen_width+'px'}"
  17. @click="goodsDetail(item.goods_id)">
  18. <view class="icon-circle">
  19. <image class='goods-img' :src="item.goods.image_url" mode="aspectFill"></image>
  20. </view>
  21. <view class="list-right">
  22. <view class="list-title">{{ item.goods.name }}</view>
  23. <view class="red-price">¥{{ item.goods.price }}</view>
  24. <view class="list-detail">{{ item.ctime }}</view>
  25. </view>
  26. <view class="list-right-1">
  27. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  28. </view>
  29. </view>
  30. <view class="group-btn">
  31. <view class="top btn-div" @tap="collect(index)" v-if="item.isCollection">
  32. 取消
  33. </view>
  34. <view class="top btn-div" @tap="collect(index)" v-if="!item.isCollection">
  35. 收藏
  36. </view>
  37. <view class="removeM btn-div" @tap="remove(index)">
  38. 删除
  39. </view>
  40. </view>
  41. <view style="clear:both"></view>
  42. </view>
  43. </view>
  44. <uni-load-more
  45. :status="loadStatus"
  46. ></uni-load-more>
  47. </view>
  48. <view class="history-none" v-else>
  49. <image class="history-none-img" src="/static/image/order.png" mode=""></image>
  50. </view>
  51. </view>
  52. </template>
  53. <script>
  54. import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue'
  55. import { goods } from '@/config/mixins.js'
  56. export default {
  57. mixins: [ goods ],
  58. components: {
  59. uniLoadMore
  60. },
  61. computed: {
  62. Screen_width() {
  63. return uni.getSystemInfoSync().windowWidth;
  64. }
  65. },
  66. data() {
  67. return {
  68. visible: false,
  69. start_slide_x: 0,
  70. btnWidth: 0,
  71. startX: 0,
  72. LastX: 0,
  73. startTime: 0,
  74. screenName: '',
  75. page: 1,
  76. limit: 10,
  77. list: [], // 商品浏览足迹
  78. loadStatus: 'more'
  79. };
  80. },
  81. onLoad () {
  82. this.goodsBrowsing()
  83. },
  84. onShow() {
  85. const res = uni.getSystemInfoSync();
  86. },
  87. onReachBottom () {
  88. if (this.loadStatus === 'more') {
  89. this.goodsBrowsing()
  90. }
  91. },
  92. methods: {
  93. goodsBrowsing () {
  94. let data = {
  95. page: this.page,
  96. limit: this.limit
  97. }
  98. this.loadStatus = 'loading'
  99. this.$api.goodsBrowsing(data, res => {
  100. if (res.status) {
  101. let _list = res.data.list
  102. _list.forEach (item => {
  103. this.$set(item, 'slide_x', 0)
  104. item.ctime = this.$common.timeToDate(item.ctime)
  105. })
  106. this.list = [...this.list, ..._list]
  107. if (res.data.count > this.list.length) {
  108. this.page ++
  109. this.loadStatus = 'more'
  110. } else {
  111. this.loadStatus = 'noMore'
  112. }
  113. } else {
  114. this.$common.errorToShow(res.msg)
  115. }
  116. })
  117. },
  118. cancelEvent(){
  119. this.visible = false
  120. },
  121. // 滑动开始
  122. touchStart(e, index) {
  123. this.startCilentY = e.touches[0].clientY;
  124. //记录手指放上去的时间
  125. this.startTime = e.timeStamp;
  126. //记录滑块的初始位置
  127. this.start_slide_x = this.list[index].slide_x;
  128. // 按钮宽度
  129. uni.createSelectorQuery()
  130. .selectAll('.group-btn')
  131. .boundingClientRect()
  132. .exec(res => {
  133. if (res[0] != null) {
  134. this.btnWidth = res[0][index].width * -1;
  135. }
  136. });
  137. // 记录上一次开始时手指所处位置
  138. this.startX = e.touches[0].pageX;
  139. // 记录上一次手指位置
  140. this.lastX = this.startX;
  141. //初始化非当前滑动消息列的位置
  142. this.list.forEach((item, eq) => {
  143. if (eq !== index) {
  144. item.slide_x = 0;
  145. }
  146. });
  147. },
  148. // 滑动中
  149. touchMove(e, index) {
  150. var endCilentY = e.touches[0].clientY;
  151. var moveClientY = endCilentY - this.startCilentY;
  152. if (this.direction === 'Y' || Math.abs(moveClientY ) > 20 || e.currentTarget.dataset.disabled === true) { this.direction = ''; return; }
  153. const endX = e.touches[0].pageX;
  154. const distance = endX - this.lastX;
  155. // 预测滑块所处位置
  156. const duang = this.list[index].slide_x + distance;
  157. // 如果在可行区域内
  158. if (duang <= 0 && duang >= this.btnWidth) {
  159. this.list[index].slide_x = duang;
  160. }
  161. // 此处手指所处位置将成为下次手指移动时的上一次位置
  162. this.lastX = endX;
  163. },
  164. // 滑动结束
  165. touchEnd(e, index) {
  166. let distance = 10;
  167. const endTime = e.timeStamp;
  168. const x_end_distance = this.startX - this.lastX;
  169. if (Math.abs(endTime - this.startTime) > 200) {
  170. distance = this.btnWidth / -2;
  171. }
  172. // 判断手指最终位置与手指开始位置的位置差距
  173. if (x_end_distance > distance) {
  174. this.list[index].slide_x = this.btnWidth;
  175. } else if (x_end_distance < distance * -1) {
  176. this.list[index].slide_x = 0;
  177. } else {
  178. this.list[index].slide_x = this.start_slide_x;
  179. }
  180. },
  181. // 点击回复原状
  182. recover(index) {
  183. this.list[index].slide_x = 0;
  184. },
  185. // 收藏/取消
  186. collect (index) {
  187. let data = {
  188. goods_id: this.list[index].goods_id
  189. }
  190. this.$api.goodsCollection(data, res => {
  191. if (res.status) {
  192. this.$common.successToShow(res.msg, () => {
  193. this.$nextTick(() => {
  194. this.list[index].isCollection = !this.list[index].isCollection
  195. })
  196. })
  197. } else {
  198. this.$common.errorToShow(res.msg)
  199. }
  200. })
  201. },
  202. // 删除
  203. remove(index) {
  204. let data = {
  205. goods_ids: this.list[index].goods_id
  206. }
  207. this.$api.delGoodsBrowsing(data, res => {
  208. if (res.status) {
  209. this.$common.successToShow(res.msg, () => {
  210. this.list.splice(index, 1)
  211. })
  212. } else {
  213. this.$common.errorToShow(res.msg)
  214. }
  215. })
  216. }
  217. }
  218. };
  219. </script>
  220. <style scoped>
  221. .collection .goods-img{
  222. width: 150upx;
  223. height: 150upx;
  224. }
  225. .container_of_slide {
  226. width: 100%;
  227. overflow: hidden;
  228. }
  229. .slide_list {
  230. transition: all 100ms;
  231. transition-timing-function: ease-out;
  232. min-width: 200%;
  233. }
  234. .now-message-info {
  235. box-sizing:border-box;
  236. display: flex;
  237. align-items: center;
  238. font-size: 16px;
  239. clear:both;
  240. padding: 20upx 26upx;
  241. margin-bottom: 2upx;
  242. background: #FFFFFF;
  243. }
  244. .now-message-info,
  245. .group-btn {
  246. float: left;
  247. }
  248. .group-btn {
  249. display: flex;
  250. flex-direction: row;
  251. height: 190upx;
  252. min-width: 100upx;
  253. align-items: center;
  254. }
  255. .group-btn .btn-div {
  256. height: 190upx;
  257. color: #fff;
  258. text-align: center;
  259. padding: 0 50upx;
  260. font-size: 34upx;
  261. line-height: 190upx;
  262. }
  263. .group-btn .top {
  264. background-color: #FF7159;
  265. }
  266. .group-btn .removeM {
  267. background-color: #999;
  268. }
  269. .icon-circle{
  270. width:150upx;
  271. height: 150upx;
  272. float: left;
  273. }
  274. .list-right{
  275. float: left;
  276. margin-left: 25upx;
  277. height: 150upx;
  278. }
  279. .list-right-1{
  280. float: right;
  281. color: #A9A9A9;
  282. }
  283. .list-title{
  284. width: 490upx;
  285. line-height:1.5;
  286. overflow:hidden;
  287. color:#333;
  288. display:-webkit-box;
  289. -webkit-box-orient:vertical;
  290. -webkit-line-clamp:2;
  291. overflow:hidden;
  292. font-size: 26upx;
  293. color: #333;
  294. min-height: 80upx;
  295. }
  296. .list-detail{
  297. width: 460upx;
  298. font-size: 24upx;
  299. color: #a9a9a9;
  300. display:-webkit-box;
  301. -webkit-box-orient:vertical;
  302. -webkit-line-clamp:1;
  303. overflow:hidden;
  304. }
  305. .history-none{
  306. text-align: center;
  307. padding: 200upx 0;
  308. }
  309. .history-none-img{
  310. width: 274upx;
  311. height: 274upx;
  312. }
  313. </style>
index
index.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <!-- 用户头像header -->
  4. <view class='member-top'>
  5. <image class='bg-img' src='/static/image/member-bg.png'></image>
  6. <view class='member-top-c'>
  7. <template v-if="hasLogin">
  8. <image class='user-head-img' mode="aspectFill" :src='userInfo.avatar'></image>
  9. <view class='user-name'>{{ userInfo.nickname }}</view>
  10. <view class="fz12 grade" v-if="userInfo.grade_name">
  11. {{userInfo.grade_name}}
  12. </view>
  13. </template>
  14. <template v-else>
  15. <!-- #ifdef H5 || APP-PLUS -->
  16. <image class='user-head-img' mode="aspectFill" :src='$store.state.config.shop_logo'></image>
  17. <view class="login-btn" @click="toLogin">
  18. 登录/注册
  19. </view>
  20. <!-- #endif -->
  21. <!-- #ifdef MP-WEIXIN -->
  22. <view class="user-head-img">
  23. <open-data type="userAvatarUrl"></open-data>
  24. </view>
  25. <view>
  26. <!-- open-type="getUserInfo" @getuserinfo="getUserInfo" -->
  27. <button class="login-btn" hover-class="btn-hover" @click="goLogin()">授权登录</button>
  28. </view>
  29. <!-- #endif -->
  30. <!-- #ifdef MP-ALIPAY -->
  31. <view class="user-head-img"></view>
  32. <view>
  33. <button class="login-btn" open-type="getAuthorize" @click="getALICode" hover-class="btn-hover">授权登录</button>
  34. </view>
  35. <!-- #endif -->
  36. </template>
  37. </view>
  38. </view>
  39. <!-- 用户头像header end -->
  40. <!-- 订单列表信息 -->
  41. <view class='cell-group'>
  42. <view class='cell-item right-img' @click="orderNavigateHandle('../order/orderlist')">
  43. <view class='cell-item-hd'>
  44. <view class='cell-hd-title'>我的订单</view>
  45. </view>
  46. <view class='cell-item-ft'>
  47. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  48. </view>
  49. </view>
  50. </view>
  51. <view class='member-grid'>
  52. <view class='member-item' v-for="(item, index) in orderItems" :key="index" @click="orderNavigateHandle('../order/orderlist', index + 1)">
  53. <view class="badge color-f" v-if="item.nums">{{ item.nums }}</view>
  54. <image class='member-item-icon' :src='item.icon'></image>
  55. <text class='member-item-text'>{{ item.name }}</text>
  56. </view>
  57. <view class='member-item' @click="goAfterSaleList">
  58. <view class="badge color-f" v-if="afterSaleNums != 0">{{afterSaleNums}}</view>
  59. <image class='member-item-icon' src='/static/image/me-ic-evaluate.png'></image>
  60. <text class='member-item-text'>退换货</text>
  61. </view>
  62. </view>
  63. <!-- 订单列表end -->
  64. <!-- 其他功能菜单 -->
  65. <view class='cell-group margin-cell-group right-img'>
  66. <view class='cell-item' v-for="(item, index) in utilityMenus" :key="index" v-if="!item.unshowItem">
  67. <view class='cell-item-hd' @click="navigateToHandle(item.router)">
  68. <image class='cell-hd-icon' :src='item.icon'></image>
  69. <view class='cell-hd-title'>{{ item.name }}</view>
  70. </view>
  71. <view class='cell-item-ft'>
  72. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  73. </view>
  74. </view>
  75. <!-- #ifdef H5 || APP-PLUS -->
  76. <view class='cell-item'>
  77. <view class='cell-item-hd' @click="showChat()">
  78. <image class='cell-hd-icon' src='/static/image/me-ic-phone.png'></image>
  79. <view class='cell-hd-title'>联系客服</view>
  80. </view>
  81. <view class='cell-item-ft'>
  82. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  83. </view>
  84. </view>
  85. <!-- #endif -->
  86. <!-- #ifdef MP-WEIXIN -->
  87. <view class='cell-item'>
  88. <button class="cell-item-hd " hover-class="none" open-type="contact" bindcontact="showChat" :session-from="kefupara">
  89. <image src='/static/image/me-ic-phone.png' class='cell-hd-icon'></image>
  90. <view class='cell-hd-title'>联系客服</view>
  91. </button>
  92. <view class='cell-item-ft'>
  93. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  94. </view>
  95. </view>
  96. <!-- #endif -->
  97. <!-- #ifdef MP-ALIPAY -->
  98. <view class='cell-item'>
  99. <contact-button icon="/static/image/kefu2.png" size="170rpx*76rpx" tnt-inst-id="WKPKUZXG" scene="SCE00040186"
  100. class="cell-item-hd " hover-class="none" />
  101. <view class='cell-item-ft'>
  102. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  103. </view>
  104. </view>
  105. <!-- #endif -->
  106. </view>
  107. <view class='cell-group margin-cell-group right-img' v-if="isClerk">
  108. <view class='cell-item' v-for="(item, index) in clerk" :key="index">
  109. <view class='cell-item-hd' @click="navigateToHandle(item.router)">
  110. <image class='cell-hd-icon' :src='item.icon'></image>
  111. <view class='cell-hd-title'>{{ item.name }}</view>
  112. </view>
  113. <view class='cell-item-ft'>
  114. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  115. </view>
  116. </view>
  117. </view>
  118. <!-- 其他功能菜单end -->
  119. <jihaiCopyright></jihaiCopyright>
  120. </view>
  121. </template>
  122. <script>
  123. import jihaiCopyright from '@/components/jihai-copyright/jihaiCopyright.vue'
  124. import {
  125. checkLogin
  126. } from '@/config/mixins.js'
  127. export default {
  128. components: {
  129. jihaiCopyright
  130. },
  131. mixins: [checkLogin],
  132. data() {
  133. return {
  134. open_id: '',
  135. hasLogin: false,
  136. userInfo: {}, // 用户信息
  137. kefupara: '', //客服传递资料
  138. afterSaleNums: 0,
  139. isClerk: false,
  140. alipayNoLogin: true,
  141. alipayName: '',
  142. alipayAvatar: '',
  143. config:'',//配置信息
  144. orderItems: [{
  145. name: '待付款',
  146. icon: '/static/image/me-ic-obligation.png',
  147. nums: 0
  148. },
  149. {
  150. name: '待发货',
  151. icon: '/static/image/me-ic-sendout.png',
  152. nums: 0
  153. },
  154. {
  155. name: '待收货',
  156. icon: '/static/image/me-ic-receiving.png',
  157. nums: 0
  158. },
  159. {
  160. name: '待评价',
  161. icon: '/static/image/me-ic-evaluate.png',
  162. nums: 0
  163. }
  164. ],
  165. utilityMenus: {
  166. distribution: {
  167. name: '分销中心',
  168. icon: '/static/image/distribution.png',
  169. router: '../distribution/user',
  170. unshowItem: false
  171. },
  172. coupon: {
  173. name: '我的优惠券',
  174. icon: '/static/image/ic-me-coupon.png',
  175. router: '../coupon/index',
  176. unshowItem: false
  177. },
  178. balance: {
  179. name: '我的余额',
  180. icon: '/static/image/ic-me-balance.png',
  181. router: '../balance/index',
  182. unshowItem: false
  183. },
  184. integral: {
  185. name: '我的积分',
  186. icon: '/static/image/integral.png',
  187. router: '../integral/index',
  188. unshowItem: false
  189. },
  190. address: {
  191. name: '地址管理',
  192. icon: '/static/image/me-ic-site.png',
  193. router: '../address/list',
  194. unshowItem: false
  195. },
  196. collection: {
  197. name: '我的收藏',
  198. icon: '/static/image/ic-me-collect.png',
  199. router: '../collection/index',
  200. unshowItem: false
  201. },
  202. history: {
  203. name: '我的足迹',
  204. icon: '/static/image/ic-me-track.png',
  205. router: '../history/index',
  206. unshowItem: false
  207. },
  208. invite: {
  209. name: '邀请好友',
  210. icon: '/static/image/ic-me-invite.png',
  211. router: '../invite/index',
  212. unshowItem: true
  213. },
  214. setting: {
  215. name: '系统设置',
  216. icon: '/static/image/me-ic-set.png',
  217. router: '../setting/index',
  218. unshowItem: false
  219. }
  220. },
  221. clerk: [{
  222. name: '提货单列表',
  223. icon: '/static/image/me-ic-phone.png',
  224. router: '../take_delivery/list'
  225. },
  226. {
  227. name: '提货单核销',
  228. icon: '/static/image/me-ic-about.png',
  229. router: '../take_delivery/index'
  230. }
  231. ]
  232. }
  233. },
  234. onShow() {
  235. this.initData()
  236. },
  237. methods: {
  238. goLogin(){
  239. uni.navigateTo({
  240. url:'/pages/login/choose/index'
  241. })
  242. },
  243. getUserInfo(e) {
  244. let _this = this
  245. //return false;
  246. if (e.detail.errMsg == 'getUserInfo:fail auth deny') {
  247. _this.$common.errorToShow('未授权')
  248. } else {
  249. var data = {
  250. open_id: _this.open_id,
  251. iv: e.detail.iv,
  252. edata: e.detail.encryptedData,
  253. signature: e.detail.signature
  254. }
  255. //有推荐码的话,带上
  256. var invitecode = _this.$db.get('invitecode')
  257. if (invitecode) {
  258. data.invitecode = invitecode
  259. }
  260. _this.toWxLogin(data)
  261. }
  262. },
  263. getALICode() {
  264. let that = this
  265. uni.login({
  266. scopes: 'auth_user',
  267. success: (res) => {
  268. if (res.authCode) {
  269. uni.getUserInfo({
  270. provider: 'alipay',
  271. success: function(infoRes) {
  272. if (infoRes.errMsg == "getUserInfo:ok") {
  273. let user_info = {
  274. 'nickname': infoRes.nickName,
  275. 'avatar': infoRes.avatar
  276. }
  277. that.aLiLoginStep1(res.authCode, user_info);
  278. }
  279. },
  280. fail: function(errorRes) {
  281. this.$common.errorToShow('未取得用户昵称头像信息');
  282. }
  283. });
  284. } else {
  285. this.$common.errorToShow('未取得code');
  286. }
  287. },
  288. fail: function(res) {
  289. this.$common.errorToShow('用户授权失败my.login');
  290. }
  291. });
  292. },
  293. getWxCode() {
  294. let that = this
  295. uni.login({
  296. scopes: 'auth_user',
  297. success: function(res) {
  298. if (res.code) {
  299. that.wxLoginStep1(res.code)
  300. } else {
  301. this.$common.errorToShow('未取得code')
  302. }
  303. },
  304. fail: function(res) {
  305. this.$common.errorToShow('用户授权失败wx.login')
  306. }
  307. })
  308. },
  309. wxLoginStep1(code) {
  310. this.$api.login1({
  311. code
  312. }, res => {
  313. if (res.status) {
  314. this.open_id = res.data
  315. } else {
  316. this.$common.errorToShow(res.msg, function() {
  317. uni.navigateBack({
  318. delta: 1
  319. })
  320. })
  321. }
  322. })
  323. },
  324. aLiLoginStep1(code, user_info) {
  325. let data = {
  326. 'code': code,
  327. 'user_info': user_info
  328. }
  329. this.$api.alilogin1(data, res => {
  330. this.alipayNoLogin = false;
  331. if (res.status) {
  332. this.open_id = res.data.user_wx_id
  333. //判断是否返回了token,如果没有,就说明没有绑定账号,跳转到绑定页面
  334. if (!res.data.hasOwnProperty('token')) {
  335. this.$common.redirectTo('/pages/login/login/index?user_wx_id=' + res.data.user_wx_id);
  336. } else {
  337. this.$db.set('userToken', res.data.token)
  338. this.initData()
  339. }
  340. } else {
  341. this.$common.errorToShow(res.msg)
  342. }
  343. })
  344. },
  345. toWxLogin(data) {
  346. let _this = this
  347. _this.$api.login2(data, function(res) {
  348. if (res.status) {
  349. //判断是否返回了token,如果没有,就说明没有绑定账号,跳转到绑定页面
  350. if (typeof res.data.token == 'undefined') {
  351. uni.redirectTo({
  352. url: '/pages/login/login/index?user_wx_id=' + res.data.user_wx_id
  353. })
  354. } else {
  355. _this.$db.set('userToken', res.data.token)
  356. _this.initData()
  357. }
  358. } else {
  359. _this.$common.errorToShow('登录失败,请重试')
  360. }
  361. })
  362. },
  363. toLogin() {
  364. this.$common.navigateTo('../../login/login/index1')
  365. },
  366. initData() {
  367. // 获取用户信息
  368. var _this = this
  369. //判断是开启分销还是原始推广
  370. this.$api.shopConfig(res => {
  371. this.config = res;
  372. if (res.open_distribution) {
  373. this.utilityMenus.invite.unshowItem = true
  374. } else {
  375. this.utilityMenus.distribution.unshowItem = true
  376. this.utilityMenus.invite.unshowItem = false
  377. }
  378. })
  379. if (this.$db.get('userToken')) {
  380. this.hasLogin = true
  381. this.$api.userInfo({}, res => {
  382. if (res.status) {
  383. _this.userInfo = res.data
  384. // #ifdef MP-WEIXIN
  385. //微信小程序打开客服时,传递用户信息
  386. var kefupara = {}
  387. kefupara.nickName = res.data.nickname
  388. kefupara.tel = res.data.mobile
  389. _this.kefupara = JSON.stringify(kefupara)
  390. // #endif
  391. // 获取订单不同状态的数量
  392. let data = {
  393. ids: '1,2,3,4',
  394. isAfterSale: true
  395. }
  396. _this.$api.getOrderStatusSum(data, res => {
  397. if (res.status) {
  398. _this.orderItems.forEach((item, key) => {
  399. item.nums = res.data[key + 1]
  400. })
  401. _this.afterSaleNums = res.data.isAfterSale ?
  402. res.data.isAfterSale :
  403. 0
  404. }
  405. })
  406. //判断是否是店员
  407. this.$api.isStoreUser({}, res => {
  408. this.isClerk = res.flag
  409. })
  410. }
  411. })
  412. } else {
  413. this.hasLogin = false
  414. // #ifdef MP-WEIXIN
  415. this.getWxCode()
  416. // #endif
  417. }
  418. },
  419. navigateToHandle(pageUrl) {
  420. if (!this.hasLogin) {
  421. return this.checkIsLogin()
  422. }
  423. this.$common.navigateTo(pageUrl)
  424. },
  425. orderNavigateHandle(url, tab = 0) {
  426. if (!this.hasLogin) {
  427. return this.checkIsLogin()
  428. }
  429. this.$store.commit('orderTab', tab)
  430. this.$common.navigateTo(url)
  431. },
  432. goAfterSaleList() {
  433. if (!this.hasLogin) {
  434. return this.checkIsLogin()
  435. }
  436. this.$common.navigateTo('../after_sale/list')
  437. },
  438. //在线客服,只有手机号的,请自己替换为手机号
  439. showChat() {
  440. // #ifdef H5
  441. let _this = this
  442. window._AIHECONG('ini', {
  443. entId: this.config.ent_id,
  444. button: false,
  445. appearance: {
  446. panelMobile: {
  447. tone: '#FF7159',
  448. sideMargin: 30,
  449. ratio: 'part',
  450. headHeight: 50
  451. }
  452. }
  453. })
  454. //传递客户信息
  455. window._AIHECONG('customer', {
  456. head: _this.userInfo.avatar,
  457. '名称': _this.userInfo.nickname,
  458. '手机': _this.userInfo.mobile
  459. })
  460. window._AIHECONG('showChat')
  461. // #endif
  462. // 拨打电话
  463. // #ifdef APP-PLUS
  464. if (this.kfmobile) {
  465. uni.makePhoneCall({
  466. phoneNumber: '' + this.kfmobile,
  467. success: () => {
  468. // console.log("成功拨打电话")
  469. }
  470. })
  471. } else {
  472. this.$common.errorToShow('商户未设置客服手机号')
  473. }
  474. // #endif
  475. }
  476. },
  477. computed: {
  478. // 获取店铺联系人手机号
  479. kfmobile() {
  480. return this.$store.state.config.shop_mobile || 0
  481. }
  482. },
  483. watch: {}
  484. }
  485. </script>
  486. <style>
  487. .member-top {
  488. position: relative;
  489. width: 100%;
  490. height: 340upx;
  491. }
  492. .bg-img {
  493. position: absolute;
  494. width: 100%;
  495. height: 100%;
  496. }
  497. .member-top-c {
  498. position: absolute;
  499. top: 50%;
  500. left: 50%;
  501. transform: translate(-50%, -50%);
  502. text-align: center;
  503. }
  504. .user-head-img {
  505. display: block;
  506. width: 160upx;
  507. height: 160upx;
  508. border-radius: 50%;
  509. overflow: hidden;
  510. background-color: rgba(255, 255, 255, 0.7);
  511. margin: 0 auto 16upx;
  512. }
  513. .user-name {
  514. font-size: 30upx;
  515. color: #fff;
  516. margin-bottom: 16upx;
  517. }
  518. .grade {
  519. color: #FFF;
  520. }
  521. .member-grid {
  522. background-color: #fff;
  523. border-top: 2upx solid #eee;
  524. padding: 20upx 0;
  525. }
  526. .margin-cell-group {
  527. margin: 20upx 0;
  528. color: #666666;
  529. }
  530. .badge {
  531. left: 80upx;
  532. top: -6upx;
  533. }
  534. button.cell-item-hd {
  535. background-color: #fff;
  536. padding: 0;
  537. line-height: 1.4;
  538. color: #333;
  539. }
  540. button.cell-item-hd:after {
  541. border: none;
  542. }
  543. .login-btn {
  544. color: #fff;
  545. width: 180upx;
  546. height: 50upx;
  547. line-height: 50upx;
  548. border-radius: 25upx;
  549. background: #ff7159;
  550. font-size: 12px;
  551. }
  552. </style>
integral
index.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="integral-top">
  4. <view class="integral-top-t">
  5. 可用积分
  6. </view>
  7. <view class="integral-top-n">
  8. {{ pointList.length ? pointList[0].balance : 0}}
  9. </view>
  10. <view class="integral-top-d">
  11. {{ nowDate }}
  12. </view>
  13. </view>
  14. <view class="integral-bottom">
  15. <view class='cell-group margin-cell-group'>
  16. <view class='cell-item add-title-item cell-title'>
  17. <view class='cell-item-bd'>
  18. <view class="cell-bd-view black-text">
  19. <text class="cell-bd-text">积分记录</text>
  20. </view>
  21. </view>
  22. </view>
  23. <view
  24. class='cell-item add-title-item'
  25. v-for="item in pointList"
  26. :key="item.id"
  27. >
  28. <view class='cell-item-bd'>
  29. <view class="cell-bd-view black-text">
  30. <text class="cell-bd-text">{{ item.remarks }}</text>
  31. </view>
  32. <view class="cell-bd-view">
  33. <text class="cell-bd-text">{{ item.ctime }}</text>
  34. </view>
  35. </view>
  36. <view class="cell-item-ft">
  37. <text class="cell-ft-p">{{ item.num > 0 ? '+' + item.num : item.num }}</text>
  38. </view>
  39. </view>
  40. <uni-load-more
  41. :status="loadStatus"
  42. :show-icon="true"
  43. ></uni-load-more>
  44. </view>
  45. </view>
  46. </view>
  47. </template>
  48. <script>
  49. import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue'
  50. export default {
  51. data () {
  52. return {
  53. page: 1,
  54. limit: 10,
  55. pointList: [], // 积分记录
  56. loadStatus: 'more'
  57. }
  58. },
  59. components: { uniLoadMore },
  60. onLoad () {
  61. this.userPointLog()
  62. },
  63. computed: {
  64. nowDate () {
  65. return this.$common.timeToDate(Math.round(new Date().getTime()/1000))
  66. }
  67. },
  68. methods: {
  69. userPointLog () {
  70. let _this = this
  71. let data = {
  72. page: _this.page,
  73. limit: _this.limit
  74. }
  75. _this.loadStatus = 'loading'
  76. _this.$api.pointLog(data, function (res) {
  77. if (res.status) {
  78. _this.pointList = [..._this.pointList, ...res.data]
  79. // 判断数据是否加载完毕
  80. if (res.count > _this.pointList.length) {
  81. _this.page ++
  82. _this.loadStatus = 'more'
  83. } else {
  84. _this.loadStatus = 'noMore'
  85. }
  86. } else {
  87. // 接口請求出錯
  88. _this.$common.errorToShow(res.msg)
  89. _this.loadStatus = 'more'
  90. }
  91. })
  92. }
  93. },
  94. // 页面滚动到底部触发事件
  95. onReachBottom () {
  96. let _this = this
  97. if (_this.loadStatus === 'more') {
  98. _this.userPointLog()
  99. }
  100. }
  101. }
  102. </script>
  103. <style>
  104. .content{
  105. background-color: #fff;
  106. padding-top: 20upx;
  107. }
  108. .integral-top{
  109. background-color: #F7F7F7;
  110. text-align: center;
  111. width: 698upx;
  112. margin: 0 auto 10upx;
  113. border-radius: 12upx;
  114. padding: 40upx 0;
  115. border: 2upx solid #E9E9E9;
  116. box-shadow: 0 0 10upx #ddd;
  117. }
  118. .integral-top-t{
  119. font-size: 28upx;
  120. color: #666;
  121. margin-bottom: 16upx;
  122. }
  123. .integral-top-n{
  124. font-size: 58upx;
  125. color: #333;
  126. margin-bottom: 16upx;
  127. }
  128. .integral-top-d{
  129. font-size: 22upx;
  130. color: #999;
  131. }
  132. .cell-title .cell-bd-text{
  133. font-size: 34upx !important;
  134. }
  135. .cell-bd-view{
  136. font-size: 22upx;
  137. color: #999;
  138. }
  139. .cell-item .black-text .cell-bd-text{
  140. font-size: 28upx;
  141. color: #333;
  142. }
  143. </style>
invite
index.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <image class="invite-bg" src="/static/image/invite-bg.png" mode=""></image>
  4. <view class="invite-c">
  5. <view class="invite-w">
  6. <view class='invite-w-t'>我的专属邀请码</view>
  7. <text class='invite-w-num'>{{code}}</text>
  8. <view class='invite-w-detail'>快去分享您的邀请码吧,让更多的好友加入到【{{appTitle}}】,您也可以获得丰厚的奖励!</view>
  9. <view class='invite-w-bot'>
  10. <view bindtap='commission' @click="toMoney">
  11. <image class='invite-w-bot-ic' src='/static/image/ic-earnings.png'></image>
  12. <text class='invite-w-bot-red'>¥{{money}}元</text>
  13. <text class='invite-w-bot-gray'>邀请收益</text>
  14. </view>
  15. <view bindtap='recommendlist' @click="toList">
  16. <image class='invite-w-bot-ic' src='/static/image/ic-number.png'></image>
  17. <text class='invite-w-bot-red'>{{number}}人</text>
  18. <text class='invite-w-bot-gray'>邀请人数</text>
  19. </view>
  20. </view>
  21. </view>
  22. <view class="invite-w" v-if="!is_superior">
  23. <text class='invite-w-t-blue'>谁推荐你的?</text>
  24. <input class='invite-w-input' placeholder='请输入推荐人邀请码' v-model="inviteKey"></input>
  25. <view class='invite-w-btn' @click="setMyInvite">提交</view>
  26. </view>
  27. <view class='invite-btn'>
  28. <!-- #ifdef MP-WEIXIN -->
  29. <button class='share btn' open-type="share">
  30. <image src='/static/image/ic-wechat.png'></image>
  31. </button>
  32. <!-- #endif -->
  33. <!-- #ifdef H5 -->
  34. <button class='share btn' @click="copyUrl()">
  35. <image src='/static/image/ic-link.png'></image>
  36. </button>
  37. <!-- #endif -->
  38. <button class='share btn' @click="createPoster()">
  39. <image src='/static/image/ic-img.png'></image>
  40. </button>
  41. </view>
  42. </view>
  43. </view>
  44. </template>
  45. <script>
  46. import {
  47. apiBaseUrl
  48. } from '@/config/config.js'
  49. export default {
  50. data() {
  51. return {
  52. myShareCode: '', //分享Code
  53. code: '',
  54. money: 0,
  55. number: 0,
  56. is_superior: false,
  57. inviteKey: '',
  58. imageUrl: '/static/image/share_image.png'
  59. }
  60. },
  61. computed: {
  62. appTitle() {
  63. return this.$store.state.config.shop_name;
  64. }
  65. },
  66. onShow() {
  67. this.getInviteData();
  68. this.getMyShareCode();
  69. },
  70. methods: {
  71. //获取数据
  72. getInviteData() {
  73. this.$api.myInvite(res => {
  74. this.code = res.data.code;
  75. this.money = res.data.money;
  76. this.number = res.data.number;
  77. this.is_superior = res.data.is_superior;
  78. });
  79. },
  80. //去佣金明细
  81. toMoney() {
  82. this.$common.navigateTo('../balance/details?status=5');
  83. },
  84. //去邀请列表
  85. toList() {
  86. this.$common.navigateTo('./list');
  87. },
  88. //填写设置要求
  89. setMyInvite() {
  90. let data = {
  91. code: this.inviteKey
  92. }
  93. this.$api.setMyInvite(data, res => {
  94. if (res.status) {
  95. this.$common.successToShow('邀请码填写成功');
  96. this.is_superior = true;
  97. } else {
  98. this.$common.errorToShow(res.msg);
  99. }
  100. });
  101. },
  102. // 生成邀请海报
  103. createPoster() {
  104. let data = {
  105. type: 2
  106. }
  107. let page_path = '/pages/share/jump';
  108. // #ifdef H5
  109. data.source = 1;
  110. data.return_url = apiBaseUrl + 'wap/' + page_path;
  111. // #endif
  112. // #ifdef MP-WEIXIN
  113. data.source = 2;
  114. data.return_url = page_path;
  115. // #endif
  116. // #ifdef MP-ALIPAY
  117. data.source = 3;
  118. data.return_url = page_path;
  119. // #endif
  120. let userToken = this.$db.get('userToken')
  121. if (userToken) {
  122. data.token = userToken
  123. }
  124. this.$api.createPoster(data, res => {
  125. if (res.status) {
  126. this.$common.navigateTo('/pages/share?poster=' + res.data)
  127. } else {
  128. this.$common.errorToShow(res.msg)
  129. }
  130. })
  131. },
  132. //复制URL链接
  133. copyUrl() {
  134. let data = {
  135. type: 2
  136. }
  137. let page_path = '/pages/share/jump';
  138. data.return_url = apiBaseUrl + 'wap' + page_path;
  139. let userToken = this.$db.get('userToken')
  140. if (userToken) {
  141. data.token = userToken
  142. }
  143. let _this = this;
  144. _this.$api.createShareUrl(data, res => {
  145. if(res.status) {
  146. //todo::要复制的内容是 res.data
  147. uni.setClipboardData({
  148. data:res.data,
  149. success:function(data){
  150. _this.$common.successToShow('复制成功');
  151. },
  152. fail:function(err){
  153. _this.$common.errorToShow('复制分享URL失败');
  154. }
  155. })
  156. } else {
  157. _this.$common.errorToShow('复制分享URL失败');
  158. }
  159. });
  160. },
  161. getMyShareCode() {
  162. let userToken = this.$db.get("userToken");
  163. if (userToken && userToken != '') {
  164. // 获取我的分享码
  165. this.$api.shareCode({}, res => {
  166. if (res.status) {
  167. this.myShareCode = res.data ? res.data : '';
  168. }
  169. });
  170. }
  171. }
  172. },
  173. //分享
  174. onShareAppMessage() {
  175. let myInviteCode = this.myShareCode ? this.myShareCode : '';
  176. let ins = this.$common.shareParameterDecode('type=3&invite=' + myInviteCode);
  177. let path = '/pages/share/jump?scene=' + ins;
  178. return {
  179. title: this.$store.state.config.share_title,
  180. // #ifdef MP-ALIPAY
  181. desc: this.$store.state.config.share_desc,
  182. // #endif
  183. imageUrl: this.$store.state.config.share_image,
  184. path: path
  185. }
  186. }
  187. }
  188. </script>
  189. <style>
  190. .invite {
  191. width: 100%;
  192. height: 100%;
  193. background: linear-gradient(to right, #4c21d2, #4864f8);
  194. }
  195. .invite-bg {
  196. position: absolute;
  197. width: 750upx;
  198. height: 683upx;
  199. z-index: 66;
  200. }
  201. .invite-c {
  202. position: relative;
  203. z-index: 67;
  204. width: 750upx;
  205. padding: 0 30upx;
  206. top: 488upx;
  207. background: linear-gradient(to right, #4c21d2, #4864f8);
  208. }
  209. .invite-w {
  210. background-color: #fff;
  211. width: 690upx;
  212. text-align: center;
  213. padding: 40upx 100upx;
  214. box-sizing: border-box;
  215. border-radius: 30upx;
  216. margin-bottom: 70upx;
  217. position: relative;
  218. top: -148upx;
  219. }
  220. .invite-w-t {
  221. width: 70%;
  222. margin: 0 auto;
  223. color: #fff;
  224. border-radius: 50upx;
  225. font-size: 30upx;
  226. box-sizing: border-box;
  227. padding: 10upx;
  228. display: block;
  229. background: linear-gradient(to right, #5f2ef6, #b945dd);
  230. }
  231. .invite-w-num {
  232. color: #5f2ef6;
  233. display: block;
  234. font-size: 36upx;
  235. margin-top: 20upx;
  236. }
  237. .invite-w-detail {
  238. color: #666;
  239. font-size: 24upx;
  240. line-height: 1.5;
  241. margin-top: 20upx;
  242. }
  243. .invite-w-bot {
  244. margin: 20upx 0 50upx;
  245. }
  246. .invite-w-bot>view {
  247. width: 49%;
  248. display: inline-block;
  249. }
  250. .invite-w-bot-ic {
  251. width: 48upx;
  252. height: 48upx;
  253. }
  254. .invite-w-bot-red {
  255. font-size: 24upx;
  256. color: #ca0400;
  257. display: block;
  258. }
  259. .invite-w-bot-gray {
  260. font-size: 24upx;
  261. color: #acacac;
  262. display: block;
  263. }
  264. .invite-w-t-blue {
  265. color: #348dfc;
  266. font-size: 30upx;
  267. margin-bottom: 50upx;
  268. display: block;
  269. }
  270. .invite-w-input {
  271. font-size: 30upx;
  272. border-bottom: 1px solid #dadada;
  273. margin-bottom: 50upx;
  274. color: #999;
  275. }
  276. .invite-w-btn {
  277. background: linear-gradient(to right, #4a6af9, #28c4ff);
  278. color: #fff;
  279. width: 50%;
  280. margin: 0 auto;
  281. border-radius: 50upx;
  282. font-size: 30upx;
  283. padding: 10upx 0;
  284. }
  285. .invite-btn {
  286. position: relative;
  287. top: -150upx;
  288. text-align: center;
  289. width: 690upx;
  290. }
  291. .share {
  292. background-color: none;
  293. position: relative;
  294. width: 98upx;
  295. height: 98upx;
  296. display: inline-block;
  297. border-radius: 50%;
  298. padding: 0;
  299. margin: 0 40rpx 40rpx;
  300. }
  301. .invite-btn image {
  302. width: 98upx;
  303. height: 98upx;
  304. }
  305. </style>
list.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="collection">
  4. <view class="container_of_slide" v-for="(item, index) in lists" :key="index">
  5. <view class="slide_list">
  6. <view class="now-message-info" hover-class="uni-list-cell-hover">
  7. <view class="icon-circle">
  8. <image class='goods-img' :src="item.avatar" mode="aspectFill"></image>
  9. </view>
  10. <view class="list-right">
  11. <view class="list-title">昵称: {{ item.nickname }}</view>
  12. <view class="list-detail color-6">手机号: {{ item.mobile }}</view>
  13. <view class="list-detail">推荐时间: {{ item.ctime }}</view>
  14. </view>
  15. </view>
  16. <view style="clear:both"></view>
  17. </view>
  18. </view>
  19. <uni-load-more :status="loadStatus"></uni-load-more>
  20. </view>
  21. </view>
  22. </template>
  23. <script>
  24. import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue'
  25. export default {
  26. components: {
  27. uniLoadMore
  28. },
  29. data() {
  30. return {
  31. lists: [],
  32. page: 1, //当前页
  33. limit: 10, //每页显示几条
  34. loadStatus: 'more'
  35. };
  36. },
  37. onLoad () {
  38. this.getShareCode();
  39. this.getDataList();
  40. },
  41. onReachBottom () {
  42. if (this.loadStatus === 'more') {
  43. this.getDataList()
  44. }
  45. },
  46. methods: {
  47. getDataList() {
  48. this.loadStatus = 'loading'
  49. let data = {
  50. page: this.page,
  51. limit: this.limit
  52. }
  53. this.$api.recommendList(data, res => {
  54. if (res.status) {
  55. for (let i = 0; i < res.data.length; i++) {
  56. if (res.data[i].avatar == null) {
  57. res.data[i].avatar = this.$store.state.config.shop_default_image;
  58. }
  59. if (res.data[i].nickname == null) {
  60. res.data[i].nickname = '暂无昵称'
  61. }
  62. }
  63. let lists = this.lists.concat(res.data);
  64. this.lists = lists;
  65. if (res.total > this.page) {
  66. this.page++
  67. this.loadStatus = 'more'
  68. } else {
  69. this.loadStatus = 'noMore'
  70. }
  71. }else{
  72. this.$common.errorToShow(res.msg)
  73. }
  74. });
  75. },
  76. //获取邀请码
  77. getShareCode(){
  78. let userToken = this.$db.get("userToken");
  79. if (userToken && userToken != '') {
  80. // 获取我的分享码
  81. this.$api.shareCode({}, res => {
  82. if (res.status) {
  83. this.myShareCode = res.data;
  84. }
  85. });
  86. }
  87. }
  88. },
  89. };
  90. </script>
  91. <style scoped>
  92. .collection .goods-img{
  93. width: 150upx;
  94. height: 150upx;
  95. }
  96. .container_of_slide {
  97. width: 100%;
  98. overflow: hidden;
  99. }
  100. .slide_list {
  101. transition: all 100ms;
  102. transition-timing-function: ease-out;
  103. min-width: 100%;
  104. }
  105. .now-message-info {
  106. box-sizing:border-box;
  107. display: flex;
  108. align-items: center;
  109. font-size: 16px;
  110. clear:both;
  111. padding: 20upx 26upx;
  112. margin-bottom: 2upx;
  113. background: #FFFFFF;
  114. width: 100%;
  115. }
  116. .now-message-info,
  117. .group-btn {
  118. float: left;
  119. }
  120. .group-btn {
  121. display: flex;
  122. flex-direction: row;
  123. height: 190upx;
  124. min-width: 100upx;
  125. align-items: center;
  126. }
  127. .group-btn .btn-div {
  128. height: 190upx;
  129. color: #fff;
  130. text-align: center;
  131. padding: 0 50upx;
  132. font-size: 34upx;
  133. line-height: 190upx;
  134. }
  135. .group-btn .top {
  136. background-color: #FF7159;
  137. }
  138. .group-btn .removeM {
  139. background-color: #999;
  140. }
  141. .icon-circle{
  142. width:150upx;
  143. height: 150upx;
  144. float: left;
  145. }
  146. .list-right{
  147. float: left;
  148. margin-left: 25upx;
  149. height: 150upx;
  150. }
  151. .list-right-1{
  152. float: right;
  153. color: #A9A9A9;
  154. }
  155. .list-title{
  156. width: 490upx;
  157. line-height:1.5;
  158. overflow:hidden;
  159. color:#333;
  160. font-size: 26upx;
  161. min-height: 60upx;
  162. }
  163. .list-detail{
  164. width: 460upx;
  165. font-size: 24upx;
  166. color: #a9a9a9;
  167. display:-webkit-box;
  168. -webkit-box-orient:vertical;
  169. -webkit-line-clamp:1;
  170. overflow:hidden;
  171. height: 50upx;
  172. }
  173. </style>
order
evaluate.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="content-top">
  4. <view class='img-list'>
  5. <view class='img-list-item'
  6. v-for="item in info.items"
  7. :key="item.id"
  8. >
  9. <view class="img-list-item-gray">
  10. <image class='img-list-item-l small-img' :src='item.image_url' mode='aspectFill'></image>
  11. <view class='img-list-item-r small-right'
  12. @click="goodsDetail(item.goods_id)"
  13. >
  14. <view class='little-right-t'>
  15. <view class='goods-name list-goods-name'>{{ item.name }}</view>
  16. </view>
  17. </view>
  18. </view>
  19. <view class="evaluate-num">
  20. <view class="evaluate-num-t">商品评分</view>
  21. <view class="evaluate-num-b">
  22. <uni-rate
  23. size="18"
  24. :id="item.id"
  25. :value="score[item.id]"
  26. @change="changeScore"
  27. ></uni-rate>
  28. </view>
  29. </view>
  30. <view class="evaluate-content">
  31. <view class="evaluate-c-t">
  32. <textarea v-model="textarea[item.id]" placeholder="宝贝满足你的期待吗? 说说你的使用心得" />
  33. </view>
  34. <view class="evaluate-c-b">
  35. <view class="goods-img-item"
  36. v-if="images[item.id].length"
  37. v-for="(img, key) in images[item.id]"
  38. :key="key"
  39. >
  40. <image class="del" src="/static/image/del.png" mode="" @click="removeImg(item.id, key)"></image>
  41. <image class="" :src="img.url" mode="" @click="clickImg(img.url)"></image>
  42. </view>
  43. <view class="upload-img" v-show="isupload[item.id]">
  44. <image class="icon" src="/static/image/camera.png" mode="" @click="uploadImg(item.id)"></image>
  45. <view class="">上传照片</view>
  46. </view>
  47. </view>
  48. </view>
  49. </view>
  50. </view>
  51. </view>
  52. <view class="button-bottom">
  53. <button class="btn btn-square btn-b" hover-class="btn-hover" @click="toEvaluate" :disabled='submitStatus' :loading='submitStatus'>提交评论</button>
  54. </view>
  55. </view>
  56. </template>
  57. <script>
  58. import uniRate from "@/components/uni-rate/uni-rate.vue"
  59. import { goods } from '@/config/mixins.js'
  60. export default {
  61. mixins: [goods],
  62. components: {uniRate},
  63. data () {
  64. return {
  65. orderId: 0,
  66. info: {}, // 订单详情
  67. images: [],
  68. score: [], // 商品评价
  69. textarea: [], // 商品评价信息
  70. isupload: [], // 启/禁用 图片上传按钮
  71. rate: 5,
  72. submitStatus: false
  73. }
  74. },
  75. onLoad (options) {
  76. this.orderId = options.order_id
  77. this.orderId
  78. ? this.orderInfo()
  79. : this.$common.errorToShow('获取失败', () => {
  80. uni.navigateBack({
  81. delta: 1
  82. })
  83. })
  84. },
  85. computed: {
  86. // 获取vuex中状态
  87. maxUploadImg () {
  88. return this.$store.state.config.image_max
  89. }
  90. },
  91. methods: {
  92. // 获取订单详情
  93. orderInfo () {
  94. let data = {
  95. order_id: this.orderId
  96. }
  97. this.$api.orderDetail(data, res => {
  98. if (res.status && res.data.text_status === 4) {
  99. const _info = res.data
  100. let images = []
  101. let textarea = []
  102. let upload = []
  103. let score = []
  104. _info.items.forEach (item => {
  105. images[item.id] = []
  106. textarea[item.id] = ''
  107. upload[item.id] = true
  108. score[item.id] = 5
  109. })
  110. this.info = _info
  111. this.images = images
  112. this.textarea = textarea
  113. this.score = score
  114. this.isupload = upload
  115. } else {
  116. this.$common.errorToShow('订单不存在或状态不可评价!')
  117. }
  118. })
  119. },
  120. // 上传图片
  121. uploadImg (key) {
  122. this.$api.uploadFiles(res => {
  123. if (res.status) {
  124. let img = {
  125. url: res.data.url,
  126. id: res.data.image_id
  127. }
  128. this.images[key].push(img)
  129. this.$common.successToShow(res.msg)
  130. } else {
  131. this.$common.errorToShow(res.msg)
  132. }
  133. })
  134. },
  135. // 删除图片
  136. removeImg (id, key) {
  137. this.images[id].splice(key, 1)
  138. },
  139. // 图片点击放大
  140. clickImg (img) {
  141. // 预览图片
  142. uni.previewImage({
  143. urls: img.split()
  144. });
  145. },
  146. // 改变评分
  147. changeScore (e) {
  148. this.score[e.id] = e.value
  149. },
  150. // 提交评价
  151. toEvaluate () {
  152. this.submitStatus = true;
  153. let items = {}
  154. this.images.forEach((item, key) => {
  155. items[key] = {
  156. images: item,
  157. score: this.score[key],
  158. textarea: this.textarea[key]
  159. }
  160. })
  161. let data = {
  162. order_id: this.orderId,
  163. items: items
  164. }
  165. this.$api.orderEvaluate(data, res => {
  166. if (res.status) {
  167. this.$common.successToShow(res.msg, ress => {
  168. // 更改订单列表页的订单状态
  169. let pages = getCurrentPages(); // 当前页
  170. let beforePage = pages[pages.length - 2]; // 上个页面
  171. if (beforePage !== undefined && beforePage.route === 'pages/member/order/orderlist') {
  172. // #ifdef MP-WEIXIN
  173. beforePage.$vm.isReload = true
  174. // #endif
  175. // #ifdef H5
  176. beforePage.isReload = true
  177. // #endif
  178. // #ifdef MP-ALIPAY
  179. beforePage.rootVM.isReload = true
  180. // #endif
  181. }
  182. this.submitStatus = false;
  183. uni.navigateBack({
  184. delta: 1
  185. })
  186. })
  187. } else {
  188. this.$common.errorToShow(res.msg)
  189. this.submitStatus = false;
  190. }
  191. })
  192. }
  193. },
  194. watch: {
  195. images: {
  196. handler () {
  197. this.images.forEach((item, key) => {
  198. this.isupload[key] = item.length > this.maxUploadImg ? false : true
  199. })
  200. },
  201. deep: true
  202. }
  203. }
  204. }
  205. </script>
  206. <style>
  207. .img-list-item{
  208. padding: 30upx 20upx;
  209. }
  210. .img-list-item-gray{
  211. background-color: #F7F7F7;
  212. overflow: hidden;
  213. padding: 18upx 20upx;
  214. }
  215. .small-right{
  216. width: 520upx;
  217. }
  218. .evaluate-content{
  219. background-color: #fff;
  220. padding: 20upx 0upx;
  221. }
  222. .evaluate-c-t{
  223. width: 100%;
  224. height: 240upx;
  225. }
  226. .evaluate-c-t textarea{
  227. width: 100%;
  228. height: 100%;
  229. font-size: 26upx;
  230. padding: 10upx;
  231. }
  232. .evaluate-c-b{
  233. overflow: hidden;
  234. }
  235. .upload-img{
  236. width: 146upx;
  237. height: 146upx;
  238. margin: 14upx;
  239. text-align: center;
  240. color: #999999;
  241. font-size: 22upx;
  242. border: 2upx solid #E1E1E1;
  243. /* #ifdef MP-ALIPAY */
  244. border-top: 8upx solid #E1E1E1;
  245. /* #endif */
  246. border-radius: 4upx;
  247. display: inline-block;
  248. float: left;
  249. padding: 24upx 0;
  250. }
  251. .goods-img-item{
  252. width: 174upx;
  253. height: 174upx;
  254. padding: 14upx;
  255. float: left;
  256. position: relative;
  257. }
  258. .goods-img-item:nth-child(4n){
  259. margin-right: 0;
  260. }
  261. .goods-img-item image{
  262. width: 100%;
  263. height: 100%;
  264. }
  265. .del{
  266. width: 30upx !important;
  267. height: 30upx !important;
  268. position: absolute;
  269. right: 0;
  270. top: 0;
  271. z-index: 999;
  272. }
  273. .evaluate-num{
  274. padding: 20upx 26upx;
  275. background-color: #fff;
  276. margin-top: 20upx;
  277. }
  278. .evaluate-num-t{
  279. color: #333;
  280. font-size: 28upx;
  281. margin-bottom: 20upx;
  282. }
  283. .button-bottom .btn{
  284. width: 100%;
  285. }
  286. </style>
express_delivery.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="ed-head color-6"
  4. v-if="add.length"
  5. >
  6. 收货地址:{{ add }}
  7. </view>
  8. <view class="ed-body">
  9. <view v-if="isExpress">
  10. <view class="ed-body-item"
  11. v-for="(item, index) in express.data"
  12. :key="index"
  13. >
  14. <view class="edbi-left">
  15. <view class="edbi-date color-6">
  16. {{ item.date }}
  17. </view>
  18. <view class="edbi-time color-9">
  19. {{ item.utime }}
  20. </view>
  21. </view>
  22. <view class="edbi-circle last-circle" v-if="item.end">
  23. <view></view>
  24. </view>
  25. <view class="edbi-circle"v-else>
  26. <view></view>
  27. </view>
  28. <view class="edbi-right">
  29. <view class="edbi-title color-3">
  30. {{ item.title }}
  31. </view>
  32. <view class="edbi-content color-9">
  33. {{ item.content }}
  34. </view>
  35. </view>
  36. </view>
  37. </view>
  38. <view class="ed-none" v-else>
  39. 暂无物流信息
  40. </view>
  41. </view>
  42. </view>
  43. </template>
  44. <script>
  45. export default {
  46. data () {
  47. return {
  48. add: '', // 收货地址
  49. express: {}, // 快递物流信息
  50. // no:"70433978952894",
  51. // data:[
  52. // {"time":"2019-03-25 11:19:15","context":"郑州市【郑州二七区七部】,已送达 已签收"},
  53. // {"time":"2019-03-25 08:42:02","context":"郑州市【郑州二七区七部】,【左颜璞\/15837175131】正在派件"},
  54. // {"time":"2019-03-25 07:43:35","context":"到郑州市【郑州二七区七部】"},
  55. // {"time":"2019-03-24 16:59:41","context":"郑州市【郑州转运中心】,正发往【郑州二七区七部】"},
  56. // {"time":"2019-03-24 16:25:55","context":"到郑州市【郑州转运中心】"},
  57. // {"time":"2019-03-23 22:43:27","context":"漯河市【漯河转运中心】,正发往【郑州转运中心】"},
  58. // {"time":"2019-03-23 22:41:13","context":"到漯河市【漯河转运中心】"},
  59. // {"time":"2019-03-23 01:35:51","context":"杭州市【杭州转运中心】,正发往【漯河转运中心】"},
  60. // {"time":"2019-03-23 01:34:46","context":"到杭州市【杭州转运中心】"},
  61. // {"time":"2019-03-22 22:27:29","context":"杭州市【杭州萧山区十部】,正发往【杭州转运中心】"},
  62. // {"time":"2019-03-22 20:10:58","context":"到杭州市【杭州萧山区十部集货点】"},
  63. // {"time":"2019-03-22 18:49:57","context":"杭州市【杭州萧山区十部】,【吴永海\/15885770819】已揽收"},
  64. // ],
  65. // state:"3",
  66. // state_name:"已签收"
  67. }
  68. },
  69. onLoad (options) {
  70. let params = options.params
  71. let arr = decodeURIComponent(params).split('&')
  72. let code, no
  73. for (var i = 0; i < arr.length; i++) {
  74. let key = arr[i].split("=")[0]
  75. if (key == 'code') {
  76. code = arr[i].split("=")[1]
  77. }
  78. if (key == 'no') {
  79. no = arr[i].split("=")[1]
  80. }
  81. if (key == 'add') {
  82. this.add = arr[i].split('=')[1]
  83. }
  84. }
  85. if (!code || !no) {
  86. this.$common.errorToShow('缺少物流查询参数', () => {
  87. uni.navigateBack({
  88. delta: 1
  89. })
  90. })
  91. }
  92. this.expressInfo(code, no)
  93. },
  94. computed: {
  95. isExpress () {
  96. return Object.keys(this.express).length ? true : false
  97. }
  98. },
  99. methods: {
  100. expressInfo (code, no) {
  101. let data = {
  102. code: code,
  103. no: no
  104. }
  105. this.$api.logistics(data, res => {
  106. if (res.status) {
  107. let _info = res.data.info
  108. _info.data.forEach((item, key) => {
  109. // 日期时间重新格式化处理
  110. let times = item.time.split(' ')
  111. this.$set(item, 'date', times[0].substring(5, times[0].length))
  112. this.$set(item, 'utime', times[1].substring(0, 5))
  113. // 快递信息格式化处理
  114. let contents = item.context.split(',')
  115. this.$set(item, 'title', contents[0])
  116. this.$set(item, 'content', contents[1] ? contents[1] : '')
  117. // 签收状态logo处理
  118. this.$set(item, 'end', _info.state === 3 && key === 0 ? true : false)
  119. })
  120. this.express = _info
  121. } else {
  122. this.$common.errorToShow(res.msg)
  123. }
  124. })
  125. }
  126. }
  127. }
  128. </script>
  129. <style>
  130. .ed-head{
  131. font-size: 30upx;
  132. padding: 20upx 26upx;
  133. }
  134. .ed-body{
  135. margin: 0 26upx;
  136. background-color: #fff;
  137. box-shadow: 0 0 20upx #ccc;
  138. padding: 26upx;
  139. }
  140. .ed-body-item{
  141. /* display: flex; */
  142. overflow: hidden;
  143. position: relative;
  144. }
  145. .edbi-left{
  146. display: inline-block;
  147. width: 96upx;
  148. float: left;
  149. padding: 4upx 0;
  150. }
  151. .edbi-date{
  152. font-size: 26upx;
  153. }
  154. .edbi-time{
  155. font-size: 24upx;
  156. }
  157. .edbi-circle{
  158. display: inline-block;
  159. width: 18upx;
  160. height: 18upx;
  161. border: 2upx solid #ccc;
  162. border-radius: 50%;
  163. position: absolute;
  164. left: 88upx;
  165. top: 12upx;
  166. background-color: #fff;
  167. z-index: 99;
  168. }
  169. .last-circle{
  170. width: 40upx;
  171. height: 40upx;
  172. font-size: 24upx;
  173. left: 78upx;
  174. text-align: center;
  175. line-height: 40upx;
  176. color: #fff;
  177. background-color: #FF7159;
  178. border: none;
  179. top: 0;
  180. }
  181. .edbi-right{
  182. display: inline-block;
  183. width: 550upx;
  184. float: right;
  185. border-left: 2upx solid #e8e8e8;
  186. padding-left: 30upx;
  187. position: relative;
  188. padding-bottom: 30upx;
  189. }
  190. .edbi-title{
  191. font-size: 30upx;
  192. }
  193. .edbi-content{
  194. font-size: 26upx;
  195. margin-top: 4upx;
  196. }
  197. .ed-none{
  198. text-align: center;
  199. font-size: 26upx;
  200. color: #666;
  201. padding: 100upx;
  202. }
  203. </style>
invitation_group.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="ig-top">
  4. <view class="ig-top-t">
  5. <view class="">
  6. 剩余时间:<uni-countdown :day="lasttime.day" :hour="lasttime.hour" :minute="lasttime.minute" :second="lasttime.second"></uni-countdown>
  7. </view>
  8. </view>
  9. <view class="ig-top-m">
  10. <view class="user-head-img-c" v-for="(item, index) in teamInfo.list" :key="index">
  11. <view class="user-head-img-tip" v-if="item.id == item.team_id">拼主</view>
  12. <image class="user-head-img cell-hd-icon have-none" :src='item.user_avatar' mode=""></image>
  13. </view>
  14. <view class="user-head-img-c uhihn" v-if="teamInfo.team_nums" v-for="n in teamInfo.team_nums" :key="n"><text>?</text></view>
  15. </view>
  16. <view class="ig-top-b">
  17. <view class="igtb-top">
  18. 还差<text class="red-price">{{ teamInfo.team_nums }}</text>人,赶快邀请好友来拼单吧
  19. </view>
  20. <view class="igtb-mid">
  21. <button class="btn" @click="goShare()">邀请好友拼单</button>
  22. </view>
  23. <view class="igtb-bot">
  24. 分享好友越多,成团越快
  25. </view>
  26. </view>
  27. </view>
  28. <!-- 弹出层 -->
  29. <lvv-popup position="bottom" ref="share">
  30. <!-- #ifdef H5 -->
  31. <shareByH5 :shareType='3' :goodsId="goodsInfo.goods_id" :teamId="teamInfo.team_id" :groupId="teamInfo.rule_id"
  32. :shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief" :shareHref="shareHref"
  33. @close="closeShare()"></shareByH5>
  34. <!-- #endif -->
  35. <!-- #ifdef MP-WEIXIN -->
  36. <shareByWx :shareType='3' :goodsId="goodsInfo.goods_id" :teamId="teamInfo.team_id" :groupId="teamInfo.rule_id"
  37. :shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief" :shareHref="shareHref"
  38. @close="closeShare()"></shareByWx>
  39. <!-- #endif -->
  40. <!-- #ifdef MP-ALIPAY -->
  41. <shareByAli :shareType='3' :goodsId="goodsInfo.goods_id" :teamId="teamInfo.team_id" :groupId="teamInfo.rule_id"
  42. :shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief" :shareHref="shareHref"
  43. @close="closeShare()"></shareByAli>
  44. <!-- #endif -->
  45. <!-- #ifdef APP-PLUS -->
  46. <shareByApp :shareType='3' :goodsId="goodsInfo.goods_id" :teamId="teamInfo.team_id" :groupId="teamInfo.rule_id"
  47. :shareImg="goodsInfo.image_url" :shareTitle="goodsInfo.name" :shareContent="goodsInfo.brief" :shareHref="shareHref"
  48. @close="closeShare()"></shareByApp>
  49. <!-- #endif -->
  50. </lvv-popup>
  51. <view class="cell-group margin-cell-group">
  52. <view class='cell-item'>
  53. <view class='cell-item-hd'>
  54. <view class='cell-hd-title'>商品名称</view>
  55. </view>
  56. <view class='cell-item-ft'>
  57. <text class="cell-ft-text">{{ goodsInfo.name }}</text>
  58. </view>
  59. </view>
  60. <view class='cell-item'>
  61. <view class='cell-item-hd'>
  62. <view class='cell-hd-title'>拼单时间</view>
  63. </view>
  64. <view class='cell-item-ft'>
  65. <text class="cell-ft-text">{{ orderInfo.ctime }}</text>
  66. </view>
  67. </view>
  68. <view class='cell-item'>
  69. <view class='cell-item-hd'>
  70. <view class='cell-hd-title'>拼单须知</view>
  71. </view>
  72. <view class='cell-item-ft group-notice'>
  73. <text class="cell-ft-text">* 好友拼单 </text>
  74. <text class="cell-ft-text">* 人满发货 </text>
  75. <text class="cell-ft-text">* 人不满退款 </text>
  76. </view>
  77. </view>
  78. </view>
  79. </view>
  80. </template>
  81. <script>
  82. import lvvPopup from '@/components/lvv-popup/lvv-popup.vue';
  83. import uniCountdown from "@/components/uni-countdown/uni-countdown.vue"
  84. import {
  85. get
  86. } from '@/config/db.js';
  87. import {
  88. apiBaseUrl
  89. } from '@/config/config.js';
  90. import share from '@/components/share/share.vue';
  91. // #ifdef H5
  92. import shareByH5 from '@/components/share/shareByh5.vue'
  93. // #endif
  94. // #ifdef MP-WEIXIN
  95. import shareByWx from '@/components/share/shareByWx.vue'
  96. // #endif
  97. // #ifdef MP-ALIPAY
  98. import shareByAli from '@/components/share/shareByAli.vue'
  99. // #endif
  100. // #ifdef APP-PLUS
  101. import shareByApp from '@/components/share/shareByApp.vue'
  102. // #endif
  103. import htmlParser from '@/common/html-parser'
  104. export default {
  105. components: {
  106. lvvPopup,
  107. uniCountdown,
  108. share,
  109. // #ifdef H5
  110. shareByH5,
  111. // #endif
  112. // #ifdef MP-WEIXIN
  113. shareByWx,
  114. // #endif
  115. // #ifdef MP-ALIPAY
  116. shareByAli,
  117. // #endif
  118. // #ifdef APP-PLUS
  119. shareByApp,
  120. // #endif
  121. // spec
  122. },
  123. data() {
  124. return {
  125. myShareCode: '', //分享Code
  126. shareType: 3,
  127. providerList: [], // 分享通道 包含生成海报
  128. swiper: {
  129. indicatorDots: true,
  130. autoplay: true,
  131. interval: 3000,
  132. duration: 800,
  133. }, // 轮播图属性设置
  134. goodsInfo: [],
  135. teamInfo: [],
  136. favLogo: [
  137. '/static/image/ic-me-collect.png',
  138. '/static/image/ic-me-collect2.png'
  139. ],
  140. horizontal: 'right', //右下角弹出按钮
  141. vertical: 'bottom',
  142. direction: 'vertical',
  143. pattern: {
  144. color: '#7A7E83',
  145. backgroundColor: '#fff',
  146. selectedColor: '#007AFF',
  147. buttonColor: "#FF7159"
  148. },
  149. query: '', // query参数登录跳转回来使用
  150. indicatorDots: false,
  151. autoplay: false,
  152. interval: 2000,
  153. duration: 500,
  154. lasttime: {
  155. day: 0,
  156. hour: 0,
  157. minute: 0,
  158. second: 0
  159. }, //购买倒计时
  160. userToken: 0,
  161. time: 0,
  162. order_id:'',//订单号
  163. orderInfo:{}
  164. }
  165. },
  166. onLoad(options) {
  167. if(options.order_id){
  168. this.order_id = options.order_id;
  169. }else{
  170. this.$common.errorToShow('参数错误');
  171. }
  172. let teamInfo,orderInfo,goodsInfo
  173. let pages = getCurrentPages()
  174. let pre = pages[pages.length - 2]
  175. if(typeof pre!='undefined'){
  176. // #ifdef H5
  177. teamInfo = pre.teamInfo
  178. orderInfo = pre.orderInfo
  179. // #endif
  180. // #ifdef MP-WEIXIN || APP-PLUS || APP-PLUS-NVUE
  181. teamInfo = pre.$vm.teamInfo
  182. orderInfo = pre.$vm.orderInfo
  183. // #endif
  184. // #ifdef MP-ALIPAY
  185. teamInfo = pre.rootVM.teamInfo;
  186. orderInfo = pre.rootVM.orderInfo
  187. // #endif
  188. }
  189. if(teamInfo && orderInfo){
  190. this.teamInfo = teamInfo;
  191. this.orderInfo = orderInfo;
  192. this.goodsInfo = orderInfo.items[0];
  193. }else{
  194. this.orderDetail();
  195. this.getTeam();
  196. }
  197. let timestamp = Date.parse(new Date())/1000;
  198. this.lasttime = this.$common.timeToDateObj(options.close_time-timestamp);
  199. this.getMyShareCode();
  200. },
  201. computed: {
  202. shareHref() {
  203. let pages = getCurrentPages()
  204. let page = pages[pages.length - 1]
  205. // #ifdef H5 || MP-WEIXIN || APP-PLUS || APP-PLUS-NVUE
  206. return apiBaseUrl + 'wap/' + page.route + '?scene=' + this.query;
  207. // #endif
  208. // #ifdef MP-ALIPAY
  209. return apiBaseUrl + 'wap/' + page.__proto__.route + '?scene=' + this.query;
  210. // #endif
  211. }
  212. },
  213. onReachBottom() {
  214. if (this.current === 2 && this.goodsComments.loadStatus === 'more') {
  215. this.getGoodsComments();
  216. }
  217. },
  218. methods: {
  219. //拼团信息
  220. getTeam(){
  221. this.$api.getOrderPintuanTeamInfo({order_id:this.order_id},res=>{
  222. if (res.status) {
  223. this.teamInfo = {
  224. list:res.data.teams,
  225. current_count:res.data.teams.length,
  226. people_number:res.data.people_number,
  227. team_nums:res.data.team_nums,//剩余
  228. close_time:res.data.close_time,//关闭时间
  229. id:res.data.id,//拼团id
  230. team_id:res.data.team_id,//拼团团队id
  231. rule_id:res.data.rule_id,
  232. };
  233. console.log(this.lasttime);
  234. }else{
  235. this.$common.errorToShow(res.msg)
  236. }
  237. });
  238. },
  239. //获取订单详情
  240. orderDetail () {
  241. let _this = this
  242. let data = {
  243. order_id: _this.order_id
  244. }
  245. _this.$api.orderDetail(data, function(res) {
  246. if (res.status) {
  247. let data = res.data
  248. // 支付时间转换
  249. if (data.ctime !== null) {
  250. data.ctime = _this.$common.timeToDate(data.ctime)
  251. }
  252. _this.orderInfo = data
  253. _this.goodsInfo = data.items[0];
  254. } else {
  255. _this.$common.errorToShow(res.msg)
  256. }
  257. })
  258. },
  259. // 关闭弹出层
  260. close() {
  261. this.$emit('close')
  262. },
  263. // 点击操作
  264. clickHandler(e) {
  265. if (e.cate === 'poster') {
  266. this.createPoster()
  267. } else {
  268. // 去分享
  269. this.share(e)
  270. }
  271. },
  272. // 显示modal弹出框
  273. toshow(type, team_id = 0) {
  274. if (type == 1) {
  275. this.lvvpopref_type = 1;
  276. }
  277. if (team_id !== 0) {
  278. this.team_id = team_id;
  279. }
  280. this.$refs.lvvpopref.show();
  281. },
  282. // 关闭modal弹出框
  283. toclose() {
  284. this.$refs.lvvpopref.close();
  285. },
  286. // 跳转到h5分享页面
  287. goShare() {
  288. this.$refs.share.show();
  289. },
  290. closeShare() {
  291. this.$refs.share.close();
  292. },
  293. getMyShareCode() {
  294. let userToken = this.$db.get("userToken");
  295. if (userToken && userToken != '') {
  296. // 获取我的分享码
  297. this.$api.shareCode({}, res => {
  298. if (res.status) {
  299. this.myShareCode = res.data ? res.data : '';
  300. }
  301. });
  302. }
  303. }
  304. },
  305. //分享
  306. onShareAppMessage() {
  307. let myInviteCode = this.myShareCode ? this.myShareCode : '';
  308. let teamId = this.teamInfo.list[0].team_id;
  309. let ins = this.$common.shareParameterDecode('type=5&invite=' + myInviteCode+'&id='+ this.goodsInfo.goods_id +'&team_id=' + teamId );
  310. let path = '/pages/share/jump?scene=' + ins;
  311. console.log(path);
  312. return {
  313. title: this.goodsInfo.name,
  314. // #ifdef MP-ALIPAY
  315. desc: this.goodsInfo.brief,
  316. // #endif
  317. imageUrl: this.goodsInfo.image_url,
  318. path: path
  319. }
  320. }
  321. }
  322. </script>
  323. <style>
  324. .ig-top {
  325. text-align: center;
  326. background-color: #fff;
  327. padding: 20upx 26upx;
  328. }
  329. .ig-top-t,
  330. .ig-top-m {
  331. margin-bottom: 20upx;
  332. }
  333. .ig-top-t>view {
  334. display: inline-block;
  335. padding: 0 10upx;
  336. color: #999;
  337. }
  338. .user-head-img-c {
  339. position: relative;
  340. width: 80upx;
  341. height: 80upx;
  342. border-radius: 50%;
  343. margin-right: 20upx;
  344. box-sizing: border-box;
  345. display: inline-block;
  346. /* float: left; */
  347. border: 1px solid #f3f3f3;
  348. }
  349. .user-head-img-tip {
  350. position: absolute;
  351. top: -6upx;
  352. left: -10upx;
  353. display: inline-block;
  354. background-color: #FF7159;
  355. color: #fff;
  356. font-size: 22upx;
  357. z-index: 98;
  358. padding: 0 10upx;
  359. border-radius: 10upx;
  360. transform: scale(.8);
  361. }
  362. .user-head-img-c .user-head-img {
  363. width: 100%;
  364. height: 100%;
  365. border-radius: 50%;
  366. }
  367. .user-head-img-c:first-child {
  368. border: 1px solid #FF7159;
  369. }
  370. .uhihn {
  371. width: 80upx;
  372. height: 80upx;
  373. border-radius: 50%;
  374. display: inline-block;
  375. border: 2upx dashed #e1e1e1;
  376. text-align: center;
  377. color: #d1d1d1;
  378. font-size: 40upx;
  379. box-sizing: border-box;
  380. position: relative;
  381. }
  382. .uhihn>text {
  383. position: absolute;
  384. left: 50%;
  385. top: 50%;
  386. transform: translate(-50%, -50%);
  387. }
  388. .igtb-top {
  389. font-size: 32upx;
  390. color: #333;
  391. margin-bottom: 16upx;
  392. }
  393. .igtb-mid {
  394. margin-bottom: 16upx;
  395. }
  396. .igtb-mid .btn {
  397. width: 100%;
  398. background-color: #FF7159;
  399. color: #fff;
  400. }
  401. .igtb-bot {
  402. font-size: 24upx;
  403. color: #666;
  404. }
  405. .cell-ft-text {
  406. max-width: 520upx;
  407. overflow: hidden;
  408. text-overflow: ellipsis;
  409. white-space: nowrap;
  410. }
  411. .group-notice .cell-ft-text {
  412. color: #999;
  413. margin-left: 20upx;
  414. font-size: 26upx;
  415. }
  416. </style>
orderdetail.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="content-top">
  4. <view class='cell-group margin-cell-group'>
  5. <view class='cell-item add-title-item'>
  6. <view class='cell-item-bd'>
  7. <view class="cell-bd-view black-text" v-if="orderInfo.order_type != 2">
  8. <text class="cell-bd-text">{{ orderInfo.status_name }}</text>
  9. </view>
  10. <view class="cell-bd-view">
  11. <text class="cell-bd-text">订单号:{{ orderInfo.order_id }}</text>
  12. <button class='btn btn-g btn-small' hover-class="btn-hover" @click="copyData(orderInfo.order_id)">复制</button>
  13. </view>
  14. <view class="cell-bd-view">
  15. <text class="cell-bd-text">下单时间:{{ orderInfo.ctime }}</text>
  16. </view>
  17. </view>
  18. </view>
  19. </view>
  20. <view class='cell-group margin-cell-group'>
  21. <view class='cell-item add-title-item' v-if="isDelivery" @click="logistics">
  22. <view class='cell-item-bd'>
  23. <view class="cell-bd-view black-text">
  24. <text class="cell-bd-text">{{ orderInfo.express_delivery.context }}</text>
  25. </view>
  26. <view class="cell-bd-view">
  27. <text class="cell-bd-text">{{ orderInfo.express_delivery.time }}</text>
  28. </view>
  29. </view>
  30. <view class="cell-item-ft">
  31. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  32. </view>
  33. </view>
  34. <view class='cell-item add-title-item' v-if="!orderInfo.store">
  35. <view class='cell-item-bd'>
  36. <view class="cell-bd-view black-text">
  37. <text class="cell-bd-text">收件人:{{ orderInfo.ship_name }}</text>
  38. </view>
  39. <view class="cell-bd-view">
  40. <text class="cell-bd-text">{{ orderInfo.ship_area_name + orderInfo.ship_address }}</text>
  41. </view>
  42. </view>
  43. </view>
  44. </view>
  45. <view class='cell-group margin-cell-group' v-if="orderInfo.store">
  46. <view class='cell-item add-title-item'>
  47. <view class="cell-item-hd">
  48. <image class='cell-hd-icon' src='/static/image/homepage.png'></image>
  49. </view>
  50. <view class='cell-item-bd'>
  51. <view class="cell-bd-view black-text">
  52. <text class="cell-bd-text">{{orderInfo.store.store_name}}</text>
  53. </view>
  54. <view class="cell-bd-view">
  55. <text class="cell-bd-text">门店电话:{{orderInfo.store.mobile}}</text>
  56. </view>
  57. <view class="cell-bd-view">
  58. <text class="cell-bd-text">门店地址:{{orderInfo.store.all_address}}</text>
  59. </view>
  60. <view class="cell-bd-view">
  61. <text class="cell-bd-text">提货人信息:{{orderInfo.ship_name}}</text><text class="cell-bd-text" style="margin-left: 10rpx;">{{orderInfo.ship_mobile}}</text>
  62. </view>
  63. <view class="cell-bd-view" v-if="lading.status">
  64. <text class="cell-bd-text">提货码:<text class="red-price">{{lading.code}}</text></text>
  65. </view>
  66. </view>
  67. </view>
  68. </view>
  69. <!-- 团购分享拼单 -->
  70. <view class="cell-group margin-cell-group" v-if="(orderInfo.text_status == 1 || orderInfo.text_status == 2 ) && orderInfo.order_type==2">
  71. <view class='cell-item right-img'>
  72. <view class='cell-item-hd'>
  73. <view v-if="teamInfo.status==1" class='cell-hd-title'>待拼团,还差{{ teamInfo.team_nums }}人</view>
  74. <view v-else-if="teamInfo.status==2" class='cell-hd-title'>拼团成功,待发货</view>
  75. <view v-else-if="teamInfo.status==3" class='cell-hd-title'>拼团失败</view>
  76. </view>
  77. </view>
  78. <view class="group-swiper">
  79. <view class='cell-item' v-if="teamInfo.current_count">
  80. <view class='cell-item-hd'>
  81. <view class="user-head-img-c" v-for="(item, index) in teamInfo.list" :key="index">
  82. <view class="user-head-img-tip" v-if="item.id == item.team_id">拼主</view>
  83. <image class="user-head-img cell-hd-icon have-none" :src='item.user_avatar' mode=""></image>
  84. </view>
  85. <view v-if="teamInfo.team_nums > 3">
  86. <view class="uhihn" v-for="n in 3" :key="n">?</view>
  87. <view class="uhihn">···</view>
  88. </view>
  89. <view v-else>
  90. <view class="uhihn" v-for="n in teamInfo.team_nums" :key="n">?</view>
  91. </view>
  92. </view>
  93. <view class="cell-item-ft" v-if="teamInfo.status==1">
  94. <button class="btn" @click="goInvition()">邀请拼单</button>
  95. </view>
  96. </view>
  97. </view>
  98. </view>
  99. <view class='img-list'>
  100. <view class='img-list-item' v-for="item in orderInfo.items" :key="item.id">
  101. <image class='img-list-item-l little-img have-none' :src='item.image_url' mode='aspectFill'></image>
  102. <view class='img-list-item-r little-right'>
  103. <view class='little-right-t'>
  104. <view class='goods-name list-goods-name' @click="goodsDetail(item.goods_id)" v-if="orderInfo.order_type == 1">{{ item.name }}</view>
  105. <view class='goods-name list-goods-name' @click="pintuanDetail(item.goods_id)" v-else-if="orderInfo.order_type == 2">{{ item.name }}</view>
  106. <view class='goods-price'>¥{{ item.price }}</view>
  107. </view>
  108. <view class="romotion-tip">
  109. <view class="romotion-tip-item" v-for="(promotion, key) in formatPormotions(item.promotion_list)" :key="key">
  110. {{ promotion }}
  111. </view>
  112. </view>
  113. <view class='goods-item-c'>
  114. <view class='goods-buy'>
  115. <view class='goods-salesvolume' v-if="item.addon !== null">{{ item.addon }}</view>
  116. <view class='goods-num'>× {{ item.nums }}</view>
  117. </view>
  118. </view>
  119. </view>
  120. </view>
  121. </view>
  122. <view class='cell-group margin-cell-group' v-if="orderInfo.tax_type != 1">
  123. <view class='cell-item add-title-item'>
  124. <view class='cell-item-bd'>
  125. <view class="cell-bd-view black-text">
  126. <text class="cell-bd-text">发票信息</text>
  127. </view>
  128. <view class="cell-bd-view" v-if="orderInfo.tax_type != 1">
  129. <text class="cell-bd-text">发票抬头:{{orderInfo.tax_title}}</text>
  130. </view>
  131. <view class="cell-bd-view" v-if="orderInfo.tax_type == 3">
  132. <text class="cell-bd-text">发票税号:{{orderInfo.tax_code}}</text>
  133. </view>
  134. </view>
  135. </view>
  136. </view>
  137. <view class='cell-group margin-cell-group order-offer' v-if="orderInfo.promotion_list && orderInfo.promotion_list.length > 0">
  138. <view class='cell-item add-title-item'>
  139. <view class='cell-item-hd'>
  140. <view class="cell-bd-view promotion-title">
  141. <text class="cell-bd-text promotion-title-text">订单优惠</text>
  142. </view>
  143. </view>
  144. <view class='cell-item-bd'>
  145. <view v-for="(item, key) in orderInfo.promotion_list" :key="key" v-show="item.type == 2" class="order-promotion">{{item.name}}</view>
  146. </view>
  147. </view>
  148. </view>
  149. <view class='cell-group margin-cell-group order-price'>
  150. <view class='cell-item add-title-item'>
  151. <view class='cell-item-bd'>
  152. <view class="cell-bd-view">
  153. <text class="cell-bd-text">商品总价</text>
  154. </view>
  155. </view>
  156. <view class='cell-item-ft'>
  157. <text class="cell-ft-p">¥{{ orderInfo.goods_amount }}</text>
  158. </view>
  159. </view>
  160. <view class='cell-item add-title-item'>
  161. <view class='cell-item-bd'>
  162. <view class="cell-bd-view">
  163. <text class="cell-bd-text">运费</text>
  164. </view>
  165. </view>
  166. <view class='cell-item-ft'>
  167. <text class="cell-ft-p">¥{{ orderInfo.cost_freight }}</text>
  168. </view>
  169. </view>
  170. <view class='cell-item add-title-item' v-if="orderInfo.goods_pmt > 0">
  171. <view class='cell-item-bd'>
  172. <view class="cell-bd-view">
  173. <text class="cell-bd-text">商品优惠</text>
  174. </view>
  175. </view>
  176. <view class='cell-item-ft'>
  177. <text class="cell-ft-p">-¥{{ orderInfo.goods_pmt }}</text>
  178. </view>
  179. </view>
  180. <view class='cell-item add-title-item' v-if="orderInfo.point_money > 0">
  181. <view class='cell-item-bd'>
  182. <view class="cell-bd-view">
  183. <text class="cell-bd-text">积分优惠</text>
  184. </view>
  185. </view>
  186. <view class='cell-item-ft'>
  187. <text class="cell-ft-p">-¥{{ orderInfo.point_money }}</text>
  188. </view>
  189. </view>
  190. <view class='cell-item add-title-item' v-if="orderInfo.order_pmt > 0">
  191. <view class='cell-item-bd'>
  192. <view class="cell-bd-view">
  193. <text class="cell-bd-text">订单优惠</text>
  194. </view>
  195. </view>
  196. <view class='cell-item-ft'>
  197. <text class="cell-ft-p">-¥{{ orderInfo.order_pmt }}</text>
  198. </view>
  199. </view>
  200. <view class='cell-item add-title-item' v-if="orderInfo.coupon_pmt > 0">
  201. <view class='cell-item-bd'>
  202. <view class="cell-bd-view">
  203. <text class="cell-bd-text">其他优惠</text>
  204. </view>
  205. </view>
  206. <view class='cell-item-ft'>
  207. <text class="cell-ft-p">-¥{{ orderInfo.coupon_pmt }}</text>
  208. </view>
  209. </view>
  210. <view class='cell-item add-title-item'>
  211. <view class='cell-item-bd'>
  212. <view class="cell-bd-view">
  213. <text class="cell-bd-text">订单总价</text>
  214. </view>
  215. </view>
  216. <view class='cell-item-ft'>
  217. <text class="cell-ft-p red-price">¥{{ orderInfo.order_amount }}</text>
  218. </view>
  219. </view>
  220. <view class='cell-item add-title-item' v-if="orderInfo.pay_status > 1">
  221. <view class='cell-item-bd'>
  222. <view class="cell-bd-view">
  223. <text class="cell-bd-text">支付方式</text>
  224. </view>
  225. </view>
  226. <view class='cell-item-ft'>
  227. <text class="cell-ft-p">{{ orderInfo.payment_name }}</text>
  228. </view>
  229. </view>
  230. <view class='cell-item add-title-item' v-if="orderInfo.pay_status > 1">
  231. <view class='cell-item-bd'>
  232. <view class="cell-bd-view">
  233. <text class="cell-bd-text">支付时间</text>
  234. </view>
  235. </view>
  236. <view class='cell-item-ft'>
  237. <text class="cell-ft-p">{{ orderInfo.payment_time }}</text>
  238. </view>
  239. </view>
  240. </view>
  241. </view>
  242. <view class="button-bottom" v-if="orderInfo.text_status === 1">
  243. <button class='btn btn-circle btn-g' hover-class="btn-hover" @click="cancelOrder(orderInfo.order_id)">取消订单</button>
  244. <button class='btn btn-circle btn-w' hover-class="btn-hover" @click="toPay(orderInfo.order_id)">立即支付</button>
  245. </view>
  246. <view class="button-bottom" v-if="orderInfo.text_status === 2">
  247. <button class='btn btn-circle btn-w' hover-class="btn-hover" @click="customerService(orderInfo.order_id)" v-if="orderInfo.bill_aftersales_id == false">申请售后</button>
  248. <button class='btn btn-circle btn-w' hover-class="btn-hover" @click="showCustomerService(orderInfo.bill_aftersales_id)"
  249. v-else-if="orderInfo.bill_aftersales_id && orderInfo.bill_aftersales_id != false">查看售后</button>
  250. </view>
  251. <view class="button-bottom" v-if="orderInfo.text_status === 3">
  252. <button class='btn btn-circle btn-g' hover-class="btn-hover" @click="customerService(orderInfo.order_id)" v-if="orderInfo.bill_aftersales_id == false">申请售后</button>
  253. <button class='btn btn-circle btn-g' hover-class="btn-hover" @click="showCustomerService(orderInfo.bill_aftersales_id)"
  254. v-else-if="orderInfo.bill_aftersales_id && orderInfo.bill_aftersales_id != false">查看售后</button>
  255. <button class='btn btn-circle btn-g' hover-class="btn-hover" @click="logistics">查看物流</button>
  256. <button class='btn btn-circle btn-w' hover-class="btn-hover" @click="tackDeliery(orderInfo.order_id)">确认收货</button>
  257. </view>
  258. <view class="button-bottom" v-if="orderInfo.text_status === 4">
  259. <button class='btn btn-circle btn-g' hover-class="btn-hover" @click="customerService(orderInfo.order_id)" v-if="orderInfo.bill_aftersales_id == false">申请售后</button>
  260. <button class='btn btn-circle btn-g' hover-class="btn-hover" @click="showCustomerService(orderInfo.bill_aftersales_id)"
  261. v-else-if="orderInfo.bill_aftersales_id && orderInfo.bill_aftersales_id != false">查看售后</button>
  262. <button class='btn btn-circle btn-w' hover-class="btn-hover" @click="toEvaluate(orderInfo.order_id)">立即评价</button>
  263. </view>
  264. <view class="button-bottom" v-if="orderInfo.text_status === 5">
  265. <button class='btn btn-circle btn-w' hover-class="btn-hover" @click="customerService(orderInfo.order_id)" v-if="orderInfo.bill_aftersales_id == false">申请售后</button>
  266. <button class='btn btn-circle btn-w' hover-class="btn-hover" @click="showCustomerService(orderInfo.bill_aftersales_id)"
  267. v-else-if="orderInfo.bill_aftersales_id && orderInfo.bill_aftersales_id != false">查看售后</button>
  268. </view>
  269. </view>
  270. </template>
  271. <script>
  272. import {
  273. orders,
  274. goods,
  275. tools
  276. } from '@/config/mixins.js'
  277. export default {
  278. mixins: [orders, goods,tools],
  279. data() {
  280. return {
  281. orderId: 0,
  282. orderInfo: {}, // 订单详情
  283. teamInfo: [], //拼团团信息
  284. lading: {
  285. status: false,
  286. code: ''
  287. }, //提货信息
  288. }
  289. },
  290. onLoad(options) {
  291. this.orderId = options.order_id
  292. if (this.orderId) {
  293. //this.orderDetail()
  294. } else {
  295. this.$common.errorToShow('', () => {
  296. uni.navigateBack({
  297. delta: 1,
  298. })
  299. })
  300. }
  301. },
  302. onShow() {
  303. this.orderDetail();
  304. },
  305. computed: {
  306. // 判断是否发货
  307. isDelivery() {
  308. if (this.orderInfo.text_status > 2 &&
  309. this.orderInfo.express_delivery != null &&
  310. this.orderInfo.hasOwnProperty('express_delivery') &&
  311. Object.keys(this.orderInfo.express_delivery).length
  312. ) {
  313. return true
  314. } else {
  315. return false
  316. }
  317. }
  318. },
  319. methods: {
  320. // 获取订单详情
  321. orderDetail() {
  322. let _this = this
  323. let data = {
  324. order_id: _this.orderId
  325. }
  326. _this.$api.orderDetail(data, function(res) {
  327. if (res.status) {
  328. let data = res.data
  329. // 订单状态文字转化
  330. switch (data.text_status) {
  331. case 1:
  332. _this.$set(data, 'status_name', '待付款')
  333. break
  334. case 2:
  335. _this.$set(data, 'status_name', '待发货')
  336. break
  337. case 3:
  338. _this.$set(data, 'status_name', '待收货')
  339. break
  340. case 4:
  341. _this.$set(data, 'status_name', '待评价')
  342. break
  343. case 6:
  344. _this.$set(data, 'status_name', '交易完成')
  345. break
  346. case 7:
  347. _this.$set(data, 'status_name', '交易取消')
  348. break
  349. case 8:
  350. _this.$set(data, 'status_name', '待分享')
  351. break
  352. default:
  353. _this.$set(data, 'status_name', '交易成功')
  354. break
  355. }
  356. // 订单时间转换
  357. data.ctime = _this.$common.timeToDate(data.ctime)
  358. // 支付时间转换
  359. if (data.payment_time !== null) {
  360. data.payment_time = _this.$common.timeToDate(data.payment_time)
  361. }
  362. _this.orderInfo = data
  363. if (data.order_type == 2 && (data.text_status == 2 || data.text_status == 1)) {
  364. _this.getTeam(data.order_id);
  365. }
  366. if(data.ladingItem[0]){
  367. _this.lading = {
  368. status: true,
  369. code: data.ladingItem[0].id
  370. }
  371. }
  372. } else {
  373. _this.$common.errorToShow(res.msg)
  374. }
  375. })
  376. },
  377. // 取消订单
  378. cancelOrder(orderId) {
  379. this.$common.modelShow('提示', '确认要取消订单吗?', () => {
  380. let data = {
  381. order_ids: orderId
  382. }
  383. this.$api.cancelOrder(data, res => {
  384. if (res.status) {
  385. this.$common.successToShow(res.msg, () => {
  386. this.orderDetail()
  387. })
  388. } else {
  389. this.$common.errorToShow(res.msg)
  390. }
  391. })
  392. })
  393. },
  394. // 确认收货
  395. tackDeliery(orderId) {
  396. this.$common.modelShow('提示', '确认收货操作吗?', () => {
  397. let data = {
  398. order_id: orderId
  399. }
  400. this.$api.confirmOrder(data, res => {
  401. if (res.status) {
  402. this.$common.successToShow('确认收货成功', () => {
  403. // 更改订单列表页的订单状态
  404. let pages = getCurrentPages(); // 当前页
  405. let beforePage = pages[pages.length - 2]; // 上个页面
  406. if (beforePage !== undefined && beforePage.route === 'pages/member/order/orderlist') {
  407. // #ifdef MP-WEIXIN
  408. beforePage.$vm.isReload = true
  409. // #endif
  410. // #ifdef H5
  411. beforePage.isReload = true
  412. // #endif
  413. // #ifdef MP-ALIPAY
  414. beforePage.rootVM.isReload = true
  415. // #endif
  416. }
  417. this.orderDetail()
  418. })
  419. } else {
  420. this.$common.errorToShow(res.msg)
  421. }
  422. })
  423. })
  424. },
  425. formatPormotions(promotion) {
  426. let obj = {}
  427. obj = JSON.parse(promotion)
  428. return obj
  429. },
  430. //申请售后
  431. customerService(id) {
  432. this.$common.navigateTo('../after_sale/index?order_id=' + id);
  433. },
  434. //快递信息
  435. logistics() {
  436. let address1 = this.orderInfo.ship_area_name ? this.orderInfo.ship_area_name : ''
  437. let address2 = this.orderInfo.ship_address ? this.orderInfo.ship_address : ''
  438. let address = address1 + address2
  439. this.showExpress(this.orderInfo.delivery[0].logi_code, this.orderInfo.delivery[0].logi_no, address)
  440. },
  441. //查看售后
  442. showCustomerService(id) {
  443. this.$common.navigateTo('../after_sale/detail?aftersales_id=' + id);
  444. },
  445. goInvition() {
  446. uni.navigateTo({
  447. url: './invitation_group?order_id=' + this.orderInfo.order_id + '&close_time=' + this.teamInfo.close_time
  448. })
  449. },
  450. //拼团信息
  451. getTeam(id) {
  452. this.$api.getOrderPintuanTeamInfo({
  453. order_id: id
  454. }, res => {
  455. if (res.status) {
  456. this.teamInfo = {
  457. list: res.data.teams,
  458. current_count: res.data.teams.length,
  459. people_number: res.data.people_number,
  460. team_nums: res.data.team_nums, //剩余
  461. close_time: res.data.close_time, //关闭时间
  462. id: res.data.id, //拼团id
  463. team_id: res.data.team_id, //拼团团队id
  464. rule_id: res.data.rule_id,
  465. status: res.data.status
  466. };
  467. } else {
  468. this.$common.errorToShow(res.msg)
  469. }
  470. });
  471. }
  472. }
  473. }
  474. </script>
  475. <style>
  476. .cell-group {
  477. margin-bottom: 20upx;
  478. }
  479. .cell-bd-view {
  480. margin-bottom: 8upx;
  481. }
  482. .cell-bd-view .cell-bd-text {
  483. font-size: 22upx;
  484. color: #999;
  485. }
  486. .black-text .cell-bd-text {
  487. font-size: 28upx;
  488. color: #333;
  489. }
  490. .button-bottom {
  491. padding: 15upx 26upx;
  492. text-align: right;
  493. display: block;
  494. }
  495. .button-bottom .btn {
  496. margin-left: 20upx;
  497. }
  498. .order-price {
  499. padding: 10upx 0 20upx;
  500. }
  501. .order-price .cell-item {
  502. border-bottom: none;
  503. padding-bottom: 0;
  504. padding-top: 0;
  505. min-height: 40upx;
  506. }
  507. .order-price .cell-bd-view {
  508. margin-bottom: 0;
  509. }
  510. .order-offer .cell-item-hd {
  511. vertical-align: top;
  512. padding-top: 8upx;
  513. }
  514. .order-offer .cell-item-bd {
  515. padding: 0;
  516. }
  517. .order-promotion {
  518. font-size: 24upx;
  519. color: #fff;
  520. background-color: #ff7159;
  521. margin: 0 0 4upx 6upx;
  522. padding: 2upx 10upx;
  523. display: inline-block;
  524. float: right;
  525. }
  526. .tax_name {}
  527. .tax_code {}
  528. .user-head-img-c {
  529. position: relative;
  530. width: 80upx;
  531. height: 80upx;
  532. border-radius: 50%;
  533. margin-right: 20upx;
  534. box-sizing: border-box;
  535. display: inline-block;
  536. float: left;
  537. border: 1px solid #f3f3f3;
  538. }
  539. .user-head-img-tip {
  540. position: absolute;
  541. top: -6upx;
  542. left: -10upx;
  543. display: inline-block;
  544. background-color: #FF7159;
  545. color: #fff;
  546. font-size: 22upx;
  547. z-index: 99;
  548. padding: 0 10upx;
  549. border-radius: 10upx;
  550. transform: scale(.8);
  551. }
  552. .group-swiper .cell-item .user-head-img {
  553. width: 100%;
  554. height: 100%;
  555. border-radius: 50%;
  556. }
  557. .group-swiper .cell-item .user-head-img-c:first-child {
  558. border: 1px solid #FF7159;
  559. }
  560. .uhihn {
  561. width: 80upx;
  562. height: 80upx;
  563. border-radius: 50%;
  564. margin-right: 20upx;
  565. display: inline-block;
  566. border: 2upx dashed #e1e1e1;
  567. text-align: center;
  568. line-height: 80upx;
  569. color: #d1d1d1;
  570. font-size: 40upx;
  571. box-sizing: border-box;
  572. }
  573. .group-swiper .cell-item .cell-item-ft .btn {
  574. font-size: 26upx;
  575. color: #fff;
  576. background-color: #FF7159;
  577. /* padding: 0; */
  578. text-align: center;
  579. }
  580. .add-title-item .cell-item-hd {
  581. min-width: 20px;
  582. color: #666;
  583. font-size: 14px;
  584. }
  585. </style>
orderlist.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <uni-segmented-control
  4. :current="tab"
  5. :values="items"
  6. @clickItem="onClickItem"
  7. style-type="text"
  8. active-color="#333"
  9. ></uni-segmented-control>
  10. <view class="order-list">
  11. <view class="goods-detail"
  12. v-if="list.length">
  13. <view class="order-item"
  14. v-for="(item, index) in list"
  15. :key="index"
  16. >
  17. <view class='cell-group'>
  18. <view class='cell-item'
  19. @click="orderDetail(item.order_id)"
  20. >
  21. <view class='cell-item-hd'>
  22. <view class='cell-hd-title'>订单编号:{{ item.order_id }}</view>
  23. </view>
  24. <view class='cell-item-ft'>
  25. <text class='cell-ft-text'>{{ item.order_status_name }}</text>
  26. </view>
  27. </view>
  28. </view>
  29. <view class='img-list'>
  30. <view class='img-list-item'
  31. v-for="(goods, key) in item.items"
  32. :key="key"
  33. >
  34. <image class='img-list-item-l little-img have-none' :src='goods.image_url' mode='aspectFill'></image>
  35. <view class='img-list-item-r little-right'>
  36. <view class='little-right-t'>
  37. <view class='goods-name list-goods-name'
  38. @click="orderDetail(item.order_id)"
  39. >{{ goods.name }}</view>
  40. <view class='goods-price'>¥{{ goods.price }}</view>
  41. </view>
  42. <view class="romotion-tip">
  43. <view class="romotion-tip-item"
  44. v-for="(promotion, k) in formatPromotions(goods.promotion_list)"
  45. :key="k"
  46. >
  47. {{ promotion }}
  48. </view>
  49. </view>
  50. <view class='goods-item-c'>
  51. <view class='goods-buy'>
  52. <view class='goods-salesvolume'
  53. v-if="goods.addon !== null"
  54. >{{ goods.addon }}</view>
  55. <view class='goods-num'>× {{ goods.nums }}</view>
  56. </view>
  57. </view>
  58. </view>
  59. </view>
  60. </view>
  61. <view class='cell-group'>
  62. <view class='cell-item'>
  63. <view class='cell-item-ft goods-num'>
  64. <text class='cell-ft-text'>合计<text class="red-price">¥ {{ item.order_amount }}</text></text>
  65. <text class='cell-ft-text'>共 {{ item.items.length }} 件</text>
  66. </view>
  67. </view>
  68. </view>
  69. <view class='order-list-button'>
  70. <button class='btn btn-circle btn-g' hover-class="btn-hover" @click="orderDetail(item.order_id)">查看详情</button>
  71. <button class='btn btn-circle btn-w'
  72. hover-class="btn-hover"
  73. v-if="item.status === 1 && item.pay_status === 1"
  74. @click="toPay(item.order_id)"
  75. >立即支付</button>
  76. <button class='btn btn-circle btn-w'
  77. hover-class="btn-hover"
  78. v-if="item.status === 1 && item.pay_status === 2 && item.ship_status === 3 && item.confirm === 1"
  79. @click="tackDelivery(index)"
  80. >确认收货</button>
  81. <button class='btn btn-circle btn-w'
  82. hover-class="btn-hover"
  83. v-if="item.status === 1 && item.pay_status === 2 && item.ship_status === 3 && item.confirm === 2 && item.is_comment === 1"
  84. @click="toEvaluate(item.order_id)"
  85. >立即评价</button>
  86. </view>
  87. </view>
  88. <uni-load-more
  89. :status="loadStatus"
  90. ></uni-load-more>
  91. </view>
  92. <view class="order-none" v-else>
  93. <image class="order-none-img" src="/static/image/order.png" mode=""></image>
  94. </view>
  95. <!-- <view class="goods-detail" v-show="current === 1">
  96. <view class="order-none">
  97. <image class="order-none-img" src="/static/image/order.png" mode=""></image>
  98. </view>
  99. </view>
  100. <view class="goods-detail" v-show="current === 2">
  101. 3
  102. </view>
  103. <view class="goods-detail" v-show="current === 3">
  104. 4
  105. </view>
  106. <view class="goods-detail" v-show="current === 4">
  107. 5
  108. </view> -->
  109. </view>
  110. </view>
  111. </template>
  112. <script>
  113. import uniSegmentedControl from "@/components/uni-segmented-control/uni-segmented-control.vue"
  114. import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue'
  115. import { orders, goods } from '@/config/mixins.js'
  116. export default {
  117. mixins: [orders, goods],
  118. components: {
  119. uniSegmentedControl, uniLoadMore
  120. },
  121. data() {
  122. return {
  123. items: [
  124. '全部',
  125. '待付款',
  126. '待发货',
  127. '待收货',
  128. '待评价',
  129. ],
  130. list: [],
  131. page: 1,
  132. limit: 5, // 每页订单显示数量
  133. loadStatus: 'more',
  134. status: [0, 1, 2, 3, 4] ,// 订单状态 0全部 1待付款 2待发货 3待收货 4待评价
  135. isReload: false, // 页面是否刷新?重载
  136. }
  137. },
  138. onLoad () {
  139. this.initData()
  140. },
  141. onShow () {
  142. if (this.isReload) {
  143. this.initData()
  144. }
  145. },
  146. computed: {
  147. // 获取订单列表tab
  148. tab () {
  149. return this.$store.state.orderTab
  150. }
  151. },
  152. methods: {
  153. // 初始化数据并获取订单列表
  154. initData (page = 1) {
  155. this.page = page
  156. this.list = []
  157. this.orderList()
  158. },
  159. // 订单状态切换
  160. onClickItem(index) {
  161. if (this.tab !== index) {
  162. this.$store.commit('orderTab', index)
  163. this.initData()
  164. }
  165. },
  166. // 获取订单列表
  167. orderList () {
  168. let data = {
  169. page: this.page,
  170. limit: this.limit,
  171. status: this.status[this.tab]
  172. }
  173. this.loadStatus = 'loading'
  174. this.$api.orderList(data, res => {
  175. if (res.status) {
  176. let _list = res.data.list
  177. if (res.data.status == this.status[this.tab]) {
  178. this.list = [...this.list, ...this.formatOrderStatus(_list)]
  179. // 判断所有数据是否请求完毕
  180. if (res.data.count > this.list.length) {
  181. this.page ++
  182. this.loadStatus = 'more'
  183. } else {
  184. this.loadStatus = 'noMore'
  185. }
  186. }
  187. } else {
  188. this.$common.errorToShow(res.msg)
  189. }
  190. })
  191. if (this.isReload) {
  192. this.isReload = false
  193. }
  194. },
  195. // 确认收货
  196. tackDelivery (index) {
  197. this.$common.modelShow('提示', '确认执行收货操作吗?', () => {
  198. let data = {
  199. order_id: this.list[index].order_id
  200. }
  201. this.$api.confirmOrder(data, res => {
  202. if (res.status) {
  203. this.$common.successToShow('确认收货成功', () => {
  204. if (this.tab !== 0) {
  205. this.list.splice(index, 1)
  206. } else {
  207. this.initData()
  208. }
  209. })
  210. } else {
  211. this.$common.errorToShow(res.msg)
  212. }
  213. })
  214. })
  215. },
  216. // 订单状态统一在这处理
  217. formatOrderStatus (orderList) {
  218. orderList.forEach (item => {
  219. switch (item.status) {
  220. case 1:
  221. if (item.pay_status === 1) {
  222. this.$set(item, 'order_status_name', '待付款')
  223. }
  224. if (item.pay_status === 2 && item.ship_status === 1){
  225. this.$set(item, 'order_status_name', '待发货')
  226. }
  227. if (item.pay_status === 2 && item.ship_status === 3 && item.confirm === 1) {
  228. this.$set(item, 'order_status_name', '待收货')
  229. }
  230. if (item.pay_status === 2 && item.ship_status === 3 && item.confirm === 2 && item.is_comment === 1) {
  231. this.$set(item, 'order_status_name', '待评价')
  232. }
  233. if (item.pay_status === 2 && item.ship_status === 3 && item.confirm === 2 && item.is_comment === 2) {
  234. this.$set(item, 'order_status_name', '已评价')
  235. }
  236. if (item.pay_status === 4) {
  237. this.$set(item, 'order_status_name', '售后单')
  238. }
  239. break
  240. case 2:
  241. this.$set(item, 'order_status_name', '已完成')
  242. break
  243. case 3:
  244. this.$set(item, 'order_status_name', '已取消')
  245. break
  246. }
  247. })
  248. return orderList
  249. },
  250. formatPromotions (promotions) {
  251. let obj = {}
  252. obj = JSON.parse(promotions)
  253. return obj
  254. }
  255. },
  256. // 页面下拉到底部触发
  257. onReachBottom () {
  258. if (this.loadStatus == 'more') {
  259. this.orderList()
  260. }
  261. }
  262. }
  263. </script>
  264. <style>
  265. .segmented-control {
  266. /* #ifdef H5 */
  267. top: 44px;
  268. /* #endif */
  269. /* #ifndef H5 */
  270. top: 0;
  271. /* #endif */
  272. width: 100%;
  273. background-color: #fff;
  274. position: fixed;
  275. z-index: 999;
  276. }
  277. .segmented-control-item{
  278. line-height: 70upx;
  279. }
  280. .order-list{
  281. margin-top: 64upx;
  282. }
  283. .order-item{
  284. margin-bottom: 20upx;
  285. }
  286. .img-list{
  287. margin-top: 2upx;
  288. }
  289. .cell-group,.img-list-item {
  290. background-color: #fff;
  291. }
  292. .cell-hd-title{
  293. font-size: 22upx;
  294. color: #666;
  295. }
  296. .cell-ft-text{
  297. top: 0;
  298. font-size: 22upx;
  299. color: #333;
  300. }
  301. .order-list-button{
  302. width: 100%;
  303. background-color: #fff;
  304. text-align: right;
  305. padding: 10upx 26upx;
  306. /* border-top: 2upx solid #f8f8f8; */
  307. }
  308. .order-list-button .btn{
  309. height: 50upx;
  310. line-height: 50upx;
  311. }
  312. .order-list-button .btn-w{
  313. margin-left: 20upx;
  314. }
  315. .goods-num .cell-ft-text{
  316. color: #999;
  317. line-height: 32upx;
  318. }
  319. .goods-num .cell-ft-text:first-child{
  320. margin-left: 10upx;
  321. }
  322. .order-none{
  323. text-align: center;
  324. padding: 200upx 0;
  325. }
  326. .order-none-img{
  327. width: 274upx;
  328. height: 274upx;
  329. }
  330. .goods-name{
  331. min-height: 74upx;
  332. }
  333. </style>
setting
index.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="content-top">
  4. <view class='cell-group right-img'>
  5. <view class='cell-item'>
  6. <view class='cell-item-hd' @click="navigateToHandle('./user_info/index')">
  7. <!-- <image class='cell-hd-icon' src=''></image> -->
  8. <view class='cell-hd-title'>个人信息</view>
  9. </view>
  10. <view class='cell-item-ft'>
  11. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  12. </view>
  13. </view>
  14. <view class='cell-item'>
  15. <view class='cell-item-hd' @click="navigateToHandle('./user_info/password')">
  16. <view class='cell-hd-title'>修改密码</view>
  17. </view>
  18. <view class='cell-item-ft'>
  19. <image class='cell-ft-next icon' src='../../../static/image/right.png'></image>
  20. </view>
  21. </view>
  22. <view class='cell-item'>
  23. <view class='cell-item-hd' @click="clearCache">
  24. <!-- <image class='cell-hd-icon' src=''></image> -->
  25. <view class='cell-hd-title'>清除缓存</view>
  26. </view>
  27. <view class='cell-item-ft'>
  28. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  29. </view>
  30. </view>
  31. <view class='cell-item'>
  32. <view class='cell-item-hd' @click="aboutUs">
  33. <!-- <image class='cell-hd-icon' src='/static/image/me-ic-about.png'></image> -->
  34. <view class='cell-hd-title'>关于我们</view>
  35. </view>
  36. <view class='cell-item-ft'>
  37. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  38. </view>
  39. </view>
  40. <view class='cell-item'>
  41. <view class='cell-item-hd' @click="logOff">
  42. <!-- <image class='cell-hd-icon' src='/static/image/me-ic-about.png'></image> -->
  43. <view class='cell-hd-title'>退出</view>
  44. </view>
  45. <view class='cell-item-ft'>
  46. <image class='cell-ft-next icon' src='/static/image/right.png'></image>
  47. </view>
  48. </view>
  49. </view>
  50. </view>
  51. <!-- <view class="button-bottom">
  52. <button class="btn btn-b">退出登录</button>
  53. </view> -->
  54. </view>
  55. </template>
  56. <script>
  57. export default {
  58. methods: {
  59. navigateToHandle(pageUrl) {
  60. this.$common.navigateTo(pageUrl)
  61. },
  62. // 清除缓存
  63. clearCache() {
  64. // 重新获取统一配置信息
  65. this.$api.shopConfig(res => {
  66. this.$store.commit('config', res)
  67. })
  68. // 删除地区缓存信息
  69. this.$db.del('areaList')
  70. setTimeout(() => {
  71. this.$common.successToShow('清除成功')
  72. }, 500)
  73. },
  74. // 关于我们
  75. aboutUs() {
  76. let articleId = this.$store.state.config.about_article_id;
  77. this.$common.navigateTo('/pages/article/index?id_type=1&id=' + articleId);
  78. },
  79. // 退出登录
  80. logOff() {
  81. this.$common.modelShow('退出', '确认退出登录吗?', () => {
  82. this.$db.del('userToken')
  83. uni.reLaunch({
  84. url: '/pages/index/index'
  85. })
  86. })
  87. }
  88. }
  89. }
  90. </script>
  91. <style>
  92. </style>
user_info
index.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="content-top">
  4. <view class='cell-group'>
  5. <view class='cell-item user-head'>
  6. <view class='cell-item-hd'>
  7. <view class='cell-hd-title'>头像</view>
  8. </view>
  9. <view class='cell-item-ft'>
  10. <image class='cell-ft-next user-head-img have-none' mode="aspectFill" :src="avatar" @click="uploadAvatar"></image>
  11. </view>
  12. </view>
  13. <view class='cell-item'>
  14. <view class='cell-item-hd'>
  15. <view class='cell-hd-title'>昵称</view>
  16. </view>
  17. <view class='cell-item-bd'>
  18. <input class='cell-bd-input' placeholder='' v-model="nickname" ></input>
  19. </view>
  20. </view>
  21. <view class='cell-item right-img'>
  22. <view class='cell-item-hd'>
  23. <view class='cell-hd-title'>性别</view>
  24. </view>
  25. <view class='cell-item-bd'>
  26. <view class="uni-list">
  27. <view class="uni-list-cell-db">
  28. <picker @change="bindPickerChange" :value="index" :range="objectSex">
  29. <view class="uni-input">{{objectSex[sex]}}</view>
  30. </picker>
  31. </view>
  32. </view>
  33. </view>
  34. <view class='cell-item-ft'>
  35. <image class='cell-ft-next icon' src='/static/image/ic-pull-down.png'></image>
  36. </view>
  37. </view>
  38. <view class='cell-item right-img'>
  39. <view class='cell-item-hd'>
  40. <view class='cell-hd-title'>生日</view>
  41. </view>
  42. <view class='cell-item-bd'>
  43. <view class="uni-list">
  44. <view class="uni-list-cell-db">
  45. <picker mode="date" :value="date" :start="startDate" :end="endDate" @change="bindDateChange">
  46. <view class="uni-input">{{birthday}}</view>
  47. </picker>
  48. </view>
  49. </view>
  50. </view>
  51. <view class='cell-item-ft'>
  52. <image class='cell-ft-next icon' src='/static/image/ic-pull-down.png'></image>
  53. </view>
  54. </view>
  55. </view>
  56. </view>
  57. <view class="button-bottom">
  58. <button class="btn btn-square btn-b" hover-class="btn-hover2" @click="submitHandler()" :disabled='submitStatus' :loading='submitStatus'>保存</button>
  59. </view>
  60. </view>
  61. </template>
  62. <script>
  63. export default {
  64. data() {
  65. return {
  66. title: 'picker',
  67. avatar: '',
  68. objectSex: ['男', '女', '未知'],
  69. index: 2,
  70. nickname: '',
  71. mobile: '',
  72. date: '1990-01-01',
  73. birthday: '请选择',
  74. sex: 0,
  75. submitStatus: false
  76. }
  77. },
  78. computed: {
  79. startDate() {
  80. return this.getDate('start');
  81. },
  82. endDate() {
  83. return this.getDate('end');
  84. }
  85. },
  86. methods: {
  87. //性别
  88. bindPickerChange: function(e) {
  89. this.sex = e.target.value;
  90. },
  91. //生日
  92. bindDateChange: function(e) {
  93. this.birthday = e.target.value;
  94. },
  95. getDate(type) {
  96. const date = new Date();
  97. let year = date.getFullYear();
  98. let month = date.getMonth() + 1;
  99. let day = date.getDate();
  100. if (type === 'start') {
  101. year = year - 60;
  102. } else if (type === 'end') {
  103. year = year + 2;
  104. }
  105. month = month > 9 ? month : '0' + month;;
  106. day = day > 9 ? day : '0' + day;
  107. return `${year}-${month}-${day}`;
  108. },
  109. // 用户上传头像
  110. uploadAvatar () {
  111. this.$api.uploadFiles(res => {
  112. if (res.status) {
  113. let avatar = res.data.url // 上传成功的图片地址
  114. // 执行头像修改
  115. this.$api.changeAvatar({
  116. avatar: avatar
  117. }, res => {
  118. if (res.status) {
  119. this.$common.successToShow('上传成功', () => {
  120. this.avatar = res.data.avatar
  121. })
  122. } else {
  123. this.$common.errorToShow(res.msg)
  124. }
  125. })
  126. } else {
  127. this.$common.errorToShow(res.msg)
  128. }
  129. })
  130. },
  131. // 保存资料
  132. submitHandler() {
  133. this.submitStatus = true;
  134. let sex = this.sex +1;
  135. if(this.birthday == '请选择'){
  136. this.$common.successToShow('请选择出生日期');
  137. this.submitStatus = false;
  138. return false;
  139. }else{
  140. this.$api.editInfo({
  141. sex: sex,
  142. birthday: this.birthday,
  143. nickname: this.nickname
  144. }, res => {
  145. this.$common.successToShow(res.msg, result => {
  146. this.submitStatus = false;
  147. uni.navigateBack({
  148. delta: 1
  149. });
  150. });
  151. }
  152. );
  153. }
  154. }
  155. },
  156. onLoad: function() {
  157. var _this = this;
  158. _this.$api.userInfo({}, function(res) {
  159. if (res.status) {
  160. var the_sex = res.data.sex - 1;
  161. if (res.data.birthday == null) {
  162. res.data.birthday = '请选择';
  163. }
  164. _this.nickname = res.data.nickname;
  165. _this.mobile = res.data.mobile;
  166. _this.sex = the_sex;
  167. _this.index = the_sex;
  168. _this.birthday = res.data.birthday;
  169. _this.avatar = res.data.avatar;
  170. if(_this.birthday!='请选择'){
  171. _this.date = _this.birthday;
  172. }
  173. } else {
  174. //报错了
  175. _this.$common.errorToShow(res.msg);
  176. }
  177. });
  178. }
  179. }
  180. </script>
  181. <style>
  182. .user-head{
  183. height: 100upx;
  184. }
  185. .user-head-img{
  186. height: 90upx;
  187. width: 90upx;
  188. border-radius: 50%;
  189. }
  190. .cell-hd-title{
  191. color: #333;
  192. }
  193. .cell-item-bd{
  194. color: #666;
  195. font-size: 26upx;
  196. }
  197. </style>
password.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="content-top">
  4. <view class='cell-group'>
  5. <view class='cell-item'>
  6. <view class='cell-item-hd'>
  7. <view class='cell-hd-title'>旧密码</view>
  8. </view>
  9. <view class='cell-item-bd'>
  10. <input class='cell-bd-input' placeholder='' v-model="pwd"></input>
  11. </view>
  12. </view>
  13. </view>
  14. <view class='cell-group'>
  15. <view class='cell-item'>
  16. <view class='cell-item-hd'>
  17. <view class='cell-hd-title'>新密码</view>
  18. </view>
  19. <view class='cell-item-bd'>
  20. <input class='cell-bd-input' placeholder='' v-model="newPwd"></input>
  21. </view>
  22. </view>
  23. </view>
  24. <view class='cell-group'>
  25. <view class='cell-item'>
  26. <view class='cell-item-hd'>
  27. <view class='cell-hd-title'>确认密码</view>
  28. </view>
  29. <view class='cell-item-bd'>
  30. <input class='cell-bd-input' placeholder='' v-model="rePwd"></input>
  31. </view>
  32. </view>
  33. </view>
  34. </view>
  35. <view class="button-bottom">
  36. <button class="btn btn-square btn-b" hover-class="btn-hover2" @click="submitHandler()" :disabled='submitStatus'
  37. :loading='submitStatus'>保存</button>
  38. </view>
  39. </view>
  40. </template>
  41. <script>
  42. export default {
  43. data() {
  44. return {
  45. pwd: '',
  46. newPwd: '',
  47. rePwd: '',
  48. sex: 0,
  49. submitStatus: false
  50. }
  51. },
  52. computed: {},
  53. methods: {
  54. // 保存资料
  55. submitHandler() {
  56. this.submitStatus = true;
  57. if (this.pwd === '') {
  58. this.$common.errorToShow('请输入旧密码')
  59. this.submitStatus = false;
  60. } else if (this.newPwd === '') {
  61. this.$common.errorToShow('请输入新密码')
  62. this.submitStatus = false;
  63. } else if (this.rePwd === '') {
  64. this.$common.errorToShow('请输入重复密码')
  65. this.submitStatus = false;
  66. } else {
  67. this.$api.editPwd({
  68. pwd: this.pwd,
  69. newpwd: this.newPwd,
  70. repwd: this.rePwd
  71. }, res => {
  72. this.submitStatus = false;
  73. this.$common.successToShow(res.msg)
  74. this.pwd = this.newPwd = this.rePwd = '';
  75. })
  76. }
  77. }
  78. },
  79. onLoad: function() {
  80. var _this = this;
  81. _this.$api.userInfo({}, function(res) {
  82. if (res.status) {
  83. var the_sex = res.data.sex - 1;
  84. if (res.data.birthday == null) {
  85. res.data.birthday = '请选择';
  86. }
  87. _this.nickname = res.data.nickname;
  88. _this.mobile = res.data.mobile;
  89. _this.sex = the_sex;
  90. _this.index = the_sex;
  91. _this.birthday = res.data.birthday;
  92. _this.avatar = res.data.avatar;
  93. if (_this.birthday != '请选择') {
  94. _this.date = _this.birthday;
  95. }
  96. } else {
  97. //报错了
  98. _this.$common.errorToShow(res.msg);
  99. }
  100. });
  101. }
  102. }
  103. </script>
  104. <style>
  105. .user-head {
  106. height: 100upx;
  107. }
  108. .user-head-img {
  109. height: 90upx;
  110. width: 90upx;
  111. border-radius: 50%;
  112. }
  113. .cell-hd-title {
  114. color: #333;
  115. }
  116. .cell-item-bd {
  117. color: #666;
  118. font-size: 26upx;
  119. }
  120. </style>
take_delivery
index.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="content-top">
  4. <view class="ad" >
  5. <image class="ad-img" src="/static/demo-img/banner.png" mode="widthFix" ></image>
  6. </view>
  7. <view class='search'>
  8. <view class='search-c'>
  9. <image class='icon search-icon' src='/static/image/zoom.png'></image>
  10. <input class='search-input' placeholder-class='search-input-p' placeholder='请输入完整提货单号、订单号、提货手机号' v-model="key"></input>
  11. </view>
  12. <button class="btn btn-g" hover-class="btn-hover2" @click="search">查询</button>
  13. </view>
  14. <view v-if="allData.length">
  15. <checkbox-group @change="checkboxChange">
  16. <view class="img-list">
  17. <view class="img-list-c" v-for="(item, index) in allData" :key="index">
  18. <view class="img-list-title">
  19. <view class="ilt-left">
  20. <text class="color-6">订单号:</text><text class="color-9">{{ item.order_id }}</text>
  21. </view>
  22. <view class="ilt-right color-9">
  23. {{ item.status_name }}
  24. </view>
  25. </view>
  26. <view class="img-list-bot">
  27. <label class="uni-list-cell uni-list-cell-pd">
  28. <view v-if="!item.disabled" class="img-list-checkbox">
  29. <checkbox color="#FF7159" :value="item.id" :checked="item.checked" :disabled="item.disabled" v-if="item.disabled" class="checkboxNo"/>
  30. <checkbox color="#FF7159" :value="item.id" :checked="item.checked" :disabled="item.disabled" v-else/>
  31. </view>
  32. </label>
  33. <view class="img-list-right">
  34. <view class="img-list-content" v-for="(i, key) in item.goods" :key="key">
  35. <view class="img-list-item">
  36. <image class="img-list-item-l" :src="i.image_url" mode='aspectFill'></image>
  37. <view class="img-list-item-r">
  38. <view class="goods-name list-goods-name">{{i.name}}</view>
  39. <view class="goods-item-c">
  40. <view class="goods-buy">
  41. <view class="goods-salesvolume">规格:{{i.addon}}</view>
  42. <view class="goods-salesvolume">数量:{{i.nums}}</view>
  43. <view class="goods-salesvolume">SN码:{{i.sn}}</view>
  44. <view class="goods-salesvolume">BN码:{{i.bn}}</view>
  45. </view>
  46. </view>
  47. </view>
  48. </view>
  49. </view>
  50. </view>
  51. </view>
  52. </view>
  53. </view>
  54. </checkbox-group>
  55. </view>
  56. </view>
  57. <view class="button-bottom" v-if="allData.length">
  58. <button class="btn btn-b btn-square" @click="write" v-if="checkedIds.length">确认核销</button>
  59. <button class="btn btn-b btn-square completed" v-else>请选择待核销订单</button>
  60. </view>
  61. </view>
  62. </template>
  63. <script>
  64. export default {
  65. data(){
  66. return {
  67. key: '', // 筛选条件
  68. isgo: false,
  69. isgotext: '确认核销',
  70. allData: [] // 提货单列表
  71. }
  72. },
  73. onLoad(e){
  74. if(e.id){
  75. this.key = e.id;
  76. }
  77. this.getLadingInfo();
  78. },
  79. computed: {
  80. // 获取选中的提货单id
  81. checkedIds () {
  82. let ids = []
  83. this.allData.forEach(item => {
  84. // 判断不是禁用状态 并且是选中状态 并且是未核销状态
  85. if (!item.disabled && item.checked && item.status === 1) {
  86. ids.push(item.id)
  87. }
  88. })
  89. return ids
  90. },
  91. },
  92. methods: {
  93. // 多选框点击事件处理
  94. checkboxChange (e) {
  95. var values = e.detail.value;
  96. this.allData.forEach(item => {
  97. if (values.includes(item.id)) {
  98. item.checked = true
  99. } else {
  100. item.checked = false
  101. }
  102. })
  103. },
  104. //获取提货单详情
  105. getLadingInfo() {
  106. if(this.key){
  107. let data = {
  108. 'key': this.key
  109. }
  110. this.$api.ladingInfo(data, e => {
  111. if (e.status) {
  112. this.allData = this.formatData(e.data);
  113. } else {
  114. this.allData = []; // 清空数据
  115. this.$common.modelShow('提示', e.msg, function(){});
  116. }
  117. });
  118. }
  119. },
  120. //搜索
  121. search() {
  122. if(this.key != ''){
  123. this.getLadingInfo();
  124. }else{
  125. this.$common.errorToShow('请输入查询关键字');
  126. return false;
  127. }
  128. },
  129. //查询判断是否可以核销
  130. isGoWrite(data) {
  131. let isgo = false;
  132. if (data.order_info.pay_status == 2 && data.order_info.ship_status == 3){
  133. isgo = true;
  134. this.lading_id = data.id;
  135. this.goodsList = data.goods;
  136. this.allData = data;
  137. } else {
  138. this.$common.modelShow('无法核销', '订单必须支付并已发货才可以核销', function(){});
  139. }
  140. this.isgo = isgo;
  141. },
  142. // 数据转化
  143. formatData (data){
  144. data.forEach (item => {
  145. if (item.status === 2) {
  146. // 已提货
  147. this.$set(item, 'checked', false)
  148. this.$set(item, 'disabled', true)
  149. } else {
  150. // 未提货
  151. this.$set(item, 'checked', true)
  152. this.$set(item, 'disabled', false)
  153. }
  154. })
  155. return data
  156. },
  157. //去核销
  158. write() {
  159. let _this = this;
  160. this.$common.modelShow('提示', '您确认核销吗?', function(res){
  161. //去核销
  162. let data = {
  163. lading_ids: _this.checkedIds.join()
  164. }
  165. _this.$api.ladingExec(data, res => {
  166. if(res.status) {
  167. _this.$common.successToShow(res.msg, _this.afterChangeDataStatus())
  168. }
  169. });
  170. });
  171. },
  172. // 核销完成后更改数据状态
  173. afterChangeDataStatus () {
  174. this.allData.forEach(item => {
  175. if (this.checkedIds.indexOf(item.id) > -1) {
  176. item.status = 2
  177. item.checked = false
  178. item.disabled = true
  179. }
  180. })
  181. }
  182. }
  183. }
  184. </script>
  185. <style>
  186. .ad {
  187. width: 100%;
  188. /* margin: 20upx 0; */
  189. overflow: hidden;
  190. }
  191. .ad-img{
  192. width: 100%;
  193. float: left;
  194. margin-bottom: 20upx;
  195. }
  196. .ad-img:last-child{
  197. margin-bottom: 0;
  198. }
  199. .search{
  200. display: flex;
  201. }
  202. .search-c{
  203. width: 85%;
  204. margin-right: 2%;
  205. }
  206. .search-icon{
  207. left: 20upx;
  208. }
  209. .search-input {
  210. padding: 10upx 30upx 10upx 70upx;
  211. }
  212. .search-input-p{
  213. padding: 0 !important;
  214. }
  215. .search .btn{
  216. width: 15%;
  217. border: none;
  218. background-color: #f1f1f1;
  219. font-size: 26upx;
  220. color: #333;
  221. border-radius: 6upx;
  222. line-height: 72upx;
  223. padding-left: 18upx;
  224. padding-right: 18upx;
  225. }
  226. .list-goods-name{
  227. margin-bottom: 8upx;
  228. }
  229. .goods-salesvolume{
  230. display: block;
  231. margin-bottom: 6upx;
  232. }
  233. .completed{
  234. background-color: #d9d9d9;
  235. color: #4e4e4e;
  236. }
  237. .img-list-bot{
  238. background-color: #fff;
  239. display: flex;
  240. padding: 30upx 26upx;
  241. }
  242. .img-list-title{
  243. padding: 26upx 26upx 0;
  244. background-color: #fff;
  245. font-size: 28upx;
  246. overflow: hidden;
  247. }
  248. .ilt-left{
  249. float: left;
  250. }
  251. .ilt-right{
  252. float: right;
  253. }
  254. .img-list-checkbox{
  255. /* display: inline-block; */
  256. position: relative;
  257. height: 100%;
  258. }
  259. .img-list-checkbox uni-checkbox{
  260. position: absolute;
  261. top: 50%;
  262. transform: translateY(-50%);
  263. }
  264. .img-list-right{
  265. /* display: inline-block; */
  266. margin-left: 60upx;
  267. }
  268. .img-list-item{
  269. padding: 0;
  270. }
  271. .img-list-item-r{
  272. width: 360upx;
  273. }
  274. </style>
list.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="order-list">
  4. <view class="goods-detail">
  5. <view class="order-item" v-for="(item, key) in ladingList" :key="key">
  6. <view class='cell-group'>
  7. <view class='cell-item' style="padding: 10upx 26upx 0 0;">
  8. <view class='cell-item-hd'>
  9. <view class='cell-hd-title'>提货码:{{item.id}}</view>
  10. </view>
  11. <view class='cell-item-ft'>
  12. <text class='cell-ft-text'>{{item.status_name}}</text>
  13. </view>
  14. </view>
  15. </view>
  16. <view class='cell-group'>
  17. <view class='cell-item'>
  18. <view class='cell-item-hd'>
  19. <view class='cell-hd-title'>订单编号:{{item.order_id}}</view>
  20. </view>
  21. <view class='cell-item-ft'>
  22. <!-- <text class='cell-ft-text' v-if="item.status == 1">待提货</text>
  23. <text class='cell-ft-text' v-else-if="item.status === 2">已提货</text>
  24. <text class='cell-ft-text' v-else>未知状态</text> -->
  25. </view>
  26. </view>
  27. </view>
  28. <view class='img-list'>
  29. <view class='img-list-item' v-for="(v, k) in item.order_items" :key="k">
  30. <image class='img-list-item-l little-img have-none' :src='v.image_url' mode='aspectFill'></image>
  31. <view class='img-list-item-r little-right'>
  32. <view class='little-right-t'>
  33. <view class='goods-name list-goods-name'>{{v.name}}</view>
  34. <view class='goods-price'>¥{{v.price}}</view>
  35. </view>
  36. <view class='goods-item-c'>
  37. <view class='goods-buy'>
  38. <view class='goods-salesvolume' v-show="v.addon">{{v.addon}}</view>
  39. <view class='goods-num'>×{{v.nums}}</view>
  40. </view>
  41. </view>
  42. </view>
  43. </view>
  44. </view>
  45. <view class='order-list-button'>
  46. <button class='btn btn-circle btn-g' hover-class="btn-hover" v-if="item.status == 2" @click="ladingDel(item.id)">删除</button>
  47. <button class='btn btn-circle btn-w' hover-class="btn-hover" v-if="item.status == 1" @click="ladingWrite(item.id)">提货单核销</button>
  48. </view>
  49. </view>
  50. </view>
  51. </view>
  52. </view>
  53. </template>
  54. <script>
  55. export default {
  56. data(){
  57. return {
  58. ladingList: [],
  59. }
  60. },
  61. onShow(){
  62. this.getLadingList();
  63. },
  64. methods: {
  65. //获取提货单列表
  66. getLadingList() {
  67. this.$api.storeLadingList({}, res => {
  68. this.ladingList = res.data;
  69. });
  70. },
  71. //提货单核销
  72. ladingWrite(id) {
  73. this.$common.navigateTo('./index?id=' + id);
  74. },
  75. //删除
  76. ladingDel(id) {
  77. this.$common.modelShow('提示', '删除提货单后将无法找回!', res => {
  78. let data = {
  79. 'lading_id': id
  80. }
  81. this.$api.ladingDel(data, res => {
  82. this.$common.successToShow(res.msg, res => {
  83. this.getLadingList();
  84. });
  85. });
  86. });
  87. }
  88. }
  89. }
  90. </script>
  91. <style>
  92. .segmented-control {
  93. /* #ifdef H5 */
  94. top: 44px;
  95. /* #endif */
  96. /* #ifndef H5 */
  97. top: 0;
  98. /* #endif */
  99. width: 100%;
  100. background-color: #fff;
  101. position: fixed;
  102. z-index: 999;
  103. }
  104. .segmented-control-item{
  105. line-height: 70upx;
  106. }
  107. .order-list{
  108. /* margin-top: 64upx; */
  109. }
  110. .order-item{
  111. margin-bottom: 20upx;
  112. }
  113. .img-list{
  114. margin-top: 2upx;
  115. }
  116. .cell-group,.img-list-item {
  117. background-color: #fff;
  118. }
  119. .cell-hd-title{
  120. font-size: 22upx;
  121. color: #666;
  122. }
  123. .cell-ft-text{
  124. top: 0;
  125. font-size: 22upx;
  126. color: #333;
  127. }
  128. .order-list-button{
  129. width: 100%;
  130. background-color: #fff;
  131. text-align: right;
  132. padding: 10upx 26upx;
  133. /* border-top: 2upx solid #f8f8f8; */
  134. }
  135. .order-list-button .btn{
  136. height: 50upx;
  137. line-height: 50upx;
  138. }
  139. .order-list-button .btn-w{
  140. margin-left: 20upx;
  141. }
  142. .goods-num .cell-ft-text{
  143. color: #999;
  144. line-height: 32upx;
  145. }
  146. .goods-num .cell-ft-text:first-child{
  147. margin-left: 10upx;
  148. }
  149. .order-none{
  150. text-align: center;
  151. padding: 200upx 0;
  152. }
  153. .order-none-img{
  154. width: 274upx;
  155. height: 274upx;
  156. }
  157. </style>

model

index.vue

share

jump.vue
复制代码
  1. <template>
  2. <view></view>
  3. </template>
  4. <script>
  5. export default {
  6. data() {
  7. return {};
  8. },
  9. onLoad(e) {
  10. let url = this.$common.shareParameterEncode(e.scene);
  11. let arr1 = url.split('&');
  12. let type = '',
  13. invite = '',
  14. page_code = '',
  15. id = '',
  16. id_type = '',
  17. group_id = '',
  18. team_id = '';
  19. for (var i = 0; i < arr1.length; i++) {
  20. let key = arr1[i].split('=')[0]
  21. if (key == 'type') {
  22. type = arr1[i].split('=')[1]
  23. }
  24. if (key == 'invite') {
  25. invite = arr1[i].split('=')[1]
  26. }
  27. if (key == 'page_code') {
  28. page_code = arr1[i].split('=')[1]
  29. }
  30. if (key == 'id') {
  31. id = arr1[i].split('=')[1]
  32. }
  33. if (key == 'id_type') {
  34. id_type = arr1[i].split('=')[1]
  35. }
  36. if (key == 'group_id') {
  37. group_id = arr1[i].split('=')[1]
  38. }
  39. if (key == 'team_id') {//拼团参团id
  40. team_id = arr1[i].split('=')[1]
  41. }
  42. }
  43. this.saveInviteCode(invite); //存储邀请码
  44. switch (type) {
  45. case '1': //首页
  46. this.gotoIndex();
  47. break;
  48. case '2': //商品详情页面
  49. this.gotoGoods(id);
  50. break;
  51. case '3': //首页
  52. this.gotoIndex();
  53. break;
  54. case '4': //文章页面
  55. this.gotoArticle(id, id_type);
  56. break;
  57. case '5': //拼团页面
  58. this.gotoPinTuan(id, team_id);
  59. break;
  60. case '6': //团购页面
  61. this.gotoGroup(id, group_id);
  62. break;
  63. case '7': //参团页面
  64. // todo:: 功能暂无后续开发
  65. // this.gotoInvitationGroup(id, group_id, team_id);
  66. break;
  67. case '8': //自定义页面
  68. this.gotoCustom(page_code);
  69. break;
  70. case '9': //店铺邀请
  71. this.gotoStore(id);
  72. break;
  73. case '10': //智能表单
  74. this.gotoForm(id);
  75. break;
  76. default:
  77. this.gotoIndex();
  78. break;
  79. }
  80. },
  81. methods: {
  82. //存储邀请码
  83. saveInviteCode(invite) {
  84. if (invite && invite != '') {
  85. this.$db.set('invitecode', invite);
  86. }
  87. },
  88. //跳转到首页
  89. gotoIndex() {
  90. uni.switchTab({
  91. url: '/pages/index/index'
  92. });
  93. },
  94. //跳转到商品
  95. gotoGoods(id) {
  96. if(id && id != ''){
  97. let url = '/pages/goods/index/index?id=' + id;
  98. this.$common.redirectTo(url);
  99. }else{
  100. this.gotoIndex();
  101. }
  102. },
  103. //跳转到文章
  104. gotoArticle(id, id_type) {
  105. if(id && id != ''){
  106. let url = '/pages/article/index?id=' + id + '&id_type=' + id_type;
  107. this.$common.redirectTo(url);
  108. }else{
  109. this.gotoIndex();
  110. }
  111. },
  112. //跳转到拼团
  113. gotoPinTuan(id, team_id) {
  114. if(id && id != ''){
  115. let url = '/pages/goods/index/pintuan?id=' + id + '&team_id=' + team_id;
  116. this.$common.redirectTo(url);
  117. }else{
  118. this.gotoIndex();
  119. }
  120. },
  121. //跳转到团购
  122. gotoGroup(id, group_id) {
  123. if(id && id != ''){
  124. let url = '/pages/goods/index/group?id=' + id + '&group_id=' + group_id;
  125. this.$common.redirectTo(url);
  126. }else{
  127. this.gotoIndex();
  128. }
  129. },
  130. //跳转到参团
  131. //todo:: 功能暂无后续开发
  132. // gotoInvitationGroup(id, group_id, team_id) {
  133. // if(id && id != '' && group_id && group_id != '' && team_id && team_id != ''){
  134. // let url = '/pages/member/order/invitation_group?id=' + id + '&group_id=' + group_id + '&team_id=' + team_id;
  135. // this.$common.redirectTo(url);
  136. // }else{
  137. // this.gotoIndex();
  138. // }
  139. // },
  140. //跳转到自定义页
  141. gotoCustom(page_code) {
  142. if(page_code && page_code != ''){
  143. let url = '/pages/index/custom?page_code=' + page_code;
  144. this.$common.redirectTo(url);
  145. }else{
  146. this.gotoIndex();
  147. }
  148. },
  149. gotoStore(id) {
  150. if(id && id != ''){
  151. let url = '/pages/member/distribution/my_store?store=' + id;
  152. this.$common.redirectTo(url);
  153. }else{
  154. this.gotoIndex();
  155. }
  156. },
  157. //跳转表单
  158. gotoForm(id){
  159. if(id && id != ''){
  160. let url = '/pages/form/detail/form?id=' + id;
  161. this.$common.redirectTo(url);
  162. }else{
  163. this.gotoIndex();
  164. }
  165. }
  166. }
  167. };
  168. </script>

share.vue

复制代码
  1. <template>
  2. <view class="content">
  3. <view class="share-top"><img class="share-img" :src="poster" mode="widthFix"/></view>
  4. <view class="share-bot">
  5. <button class="btn btn-b" v-if="weiXinBrowser">长按图片保存到手机</button>
  6. <button class="btn btn-b" @click="savePoster()" v-else>保存到本地</button>
  7. <button class="btn btn-w" @click="goBack()">返回</button>
  8. </view>
  9. </view>
  10. </template>
  11. <script>
  12. export default {
  13. data() {
  14. return {
  15. poster: ''
  16. };
  17. },
  18. onLoad(options) {
  19. this.poster = options.poster;
  20. },
  21. computed: {
  22. weiXinBrowser () {
  23. return this.$common.isWeiXinBrowser()
  24. }
  25. },
  26. methods: {
  27. goBack() {
  28. uni.navigateBack({
  29. delta: 1
  30. });
  31. },
  32. // 保存海报到本地
  33. savePoster() {
  34. let _this = this;
  35. // #ifdef H5
  36. _this.downloadIamge(_this.poster, 'image');
  37. // #endif
  38. // #ifdef MP || MP-ALIPAY || APP-PLUS || APP-PLUS-NVUE
  39. _this.downloadImageOfMp(_this.poster)
  40. // #endif
  41. },
  42. //下载图片地址和图片名
  43. downloadIamge(imgsrc, name) {
  44. var image = new Image();
  45. // 解决跨域 Canvas 污染问题
  46. image.setAttribute('crossorigin', 'anonymous');
  47. image.onload = () => {
  48. var canvas = document.createElement('canvas');
  49. canvas.width = image.width;
  50. canvas.height = image.height;
  51. var context = canvas.getContext('2d');
  52. context.drawImage(image, 0, 0, image.width, image.height);
  53. var url = canvas.toDataURL('image/png'); //得到图片的base64编码数据
  54. var a = document.createElement('a'); // 生成一个a元素
  55. var event = new MouseEvent('click'); // 创建一个单击事件
  56. a.download = name || 'photo'; // 设置图片名称
  57. a.href = url; // 将生成的URL设置为a.href属性
  58. a.dispatchEvent(event); // 触发a的单击事件
  59. };
  60. image.src = imgsrc;
  61. },
  62. downloadImageOfMp (image) {
  63. let _this = this
  64. // #ifdef APP-PLUS
  65. uni.downloadFile({
  66. url: image,
  67. success (res) {
  68. uni.saveImageToPhotosAlbum({
  69. filePath: res.tempFilePath,
  70. success() {
  71. _this.$common.successToShow('保存成功')
  72. },
  73. fail() {
  74. _this.$common.errorToShow('图片保存失败')
  75. }
  76. });
  77. },
  78. fail () {
  79. _this.$common.errorToShow('下载失败')
  80. }
  81. })
  82. // #endif
  83. // #ifdef MP
  84. uni.authorize({
  85. scope: 'scope.writePhotosAlbum',
  86. success() {
  87. // 先下载到本地
  88. uni.downloadFile({
  89. url: image,
  90. success (res) {
  91. uni.saveImageToPhotosAlbum({
  92. filePath: res.tempFilePath,
  93. success() {
  94. _this.$common.successToShow('保存成功')
  95. },
  96. fail() {
  97. _this.$common.errorToShow('图片保存失败')
  98. }
  99. });
  100. },
  101. fail () {
  102. _this.$common.errorToShow('下载失败')
  103. }
  104. })
  105. },
  106. fail() {
  107. //console.log('授权失败')
  108. }
  109. })
  110. // #endif
  111. }
  112. }
  113. };
  114. </script>
  115. <style>
  116. .share-top {
  117. margin-bottom: 50upx;
  118. padding-top: 50upx;
  119. text-align: center;
  120. }
  121. .share-img {
  122. box-shadow: 0 0 20upx #ccc;
  123. width: 80%;
  124. }
  125. .share-bot {
  126. width: 80%;
  127. margin: 0 auto;
  128. }
  129. .share-bot .btn {
  130. width: 100%;
  131. margin: 20upx 0;
  132. }
  133. </style>

store_map

index.vue
复制代码
  1. <template>
  2. <view class="content">
  3. <view class="map-body">
  4. <cover-view></cover-view>
  5. <map id="storeMap" :latitude="latitude" :longitude="longitude" :markers="covers" style="width: 100%;height: 100%;"></map>
  6. </view>
  7. <scroll-view class="store-list" scroll-y>
  8. <view class="cell-item add-title-item" v-for="(item, index) in storeList" :key="index" @click="goMarkers(item.id)">
  9. <view class="cell-item-hd"><image class="store-img" :src="item.logo"></image></view>
  10. <view class="cell-item-bd">
  11. <view class="cell-bd-view">
  12. <text class="cell-bd-text fsz30">{{ item.store_name }}</text>
  13. </view>
  14. <view class="cell-bd-view">
  15. <text class="cell-bd-text color-6 fsz24">电话:{{ item.mobile }}</text>
  16. </view>
  17. <view class="cell-bd-view">
  18. <text class="cell-bd-text color-6 fsz24">地址:{{ item.all_address }}</text>
  19. </view>
  20. </view>
  21. <view class="cell-item-ft"><image class="cell-ft-next icon" src="/static/image/right.png"></image></view>
  22. </view>
  23. </scroll-view>
  24. </view>
  25. </template>
  26. <script>
  27. export default {
  28. data() {
  29. return {
  30. storeList: [],
  31. longitude: 0,
  32. latitude: 0,
  33. covers: [{
  34. 'longitude': 0,
  35. 'latitude': 0
  36. }]
  37. };
  38. },
  39. onLoad() {
  40. this.getMyLocation();
  41. this.getStoreList();
  42. },
  43. methods: {
  44. // 获取自己的位置信息
  45. getMyLocation() {
  46. let _this = this;
  47. uni.getLocation({
  48. type: 'wgs84',
  49. success: function (res) {
  50. _this.longitude = res.longitude;
  51. _this.latitude = res.latitude;
  52. },
  53. fail: function () {
  54. _this.$common.errorToShow("获取位置信息失败")
  55. }
  56. });
  57. },
  58. // 获取店铺列表信息
  59. getStoreList() {
  60. let _this = this;
  61. _this.$api.storeList({}, res => {
  62. if (res.status) {
  63. _this.storeList = res.data;
  64. let storeList = res.data;
  65. let covers = [];
  66. for (let i=0; i < storeList.length; i++) {
  67. let newArr = {}
  68. newArr.latitude = storeList[i].latitude;
  69. newArr.longitude = storeList[i].longitude;
  70. newArr.width = '50rpx';
  71. newArr.height = '50rpx';
  72. newArr.iconPath = '/static/image/gps-blue.png'
  73. covers.push(newArr)
  74. }
  75. console.log(covers)
  76. _this.covers = covers;
  77. } else {
  78. }
  79. // console.log(res)
  80. });
  81. }
  82. }
  83. };
  84. </script>
  85. <style scoped>
  86. .content {
  87. width: 100%;
  88. /* #ifdef H5 */
  89. height: calc(100vh - 44px);
  90. /* #endif */
  91. /* height: 100vh; */
  92. }
  93. .map-body {
  94. width: 100%;
  95. height: 700rpx;
  96. position: relative;
  97. }
  98. .store-list {
  99. background-color: #fff;
  100. height: calc(100vh - 44px - 700rpx);
  101. }
  102. .store-item {
  103. display: flex;
  104. }
  105. .store-img {
  106. width: 140rpx;
  107. height: 140rpx;
  108. }
  109. .store-right {
  110. flex: 1;
  111. }
  112. </style>

pages.json

复制代码
  1. {
  2. "pages": [
  3. {
  4. "path": "pages/index/index",
  5. "style": {
  6. "navigationBarTitleText": "首页",
  7. // #ifdef H5
  8. "titleNView": false,
  9. // #endif
  10. "enablePullDownRefresh": true
  11. }
  12. },
  13. {
  14. "path": "pages/index/custom",
  15. "style": {
  16. "navigationBarTitleText": "页面",
  17. // #ifdef H5
  18. "titleNView": false,
  19. // #endif
  20. "enablePullDownRefresh": true
  21. }
  22. },
  23. {
  24. "path": "pages/index/search",
  25. "style": {
  26. "navigationBarTitleText": "搜索"
  27. }
  28. },
  29. {
  30. "path": "pages/classify/classify",
  31. "style": {
  32. "navigationBarTitleText": "分类"
  33. }
  34. },
  35. {
  36. "path": "pages/classify/index",
  37. "style": {
  38. "navigationBarTitleText": "商品列表"
  39. }
  40. },
  41. {
  42. "path": "pages/cart/index/index",
  43. "style": {
  44. "navigationBarTitleText": "购物车"
  45. }
  46. },
  47. {
  48. "path": "pages/member/index/index",
  49. "style": {
  50. // #ifdef H5
  51. "titleNView": false,
  52. // #endif
  53. "navigationBarTitleText": "个人中心"
  54. }
  55. },
  56. {
  57. "path": "pages/member/coupon/index",
  58. "style": {
  59. "navigationBarTitleText": "我的优惠券"
  60. }
  61. },
  62. {
  63. "path": "pages/member/balance/index",
  64. "style": {
  65. "navigationBarTitleText": "我的余额"
  66. }
  67. },
  68. {
  69. "path": "pages/member/balance/recharge",
  70. "style": {
  71. "navigationBarTitleText": "充值"
  72. }
  73. },
  74. {
  75. "path": "pages/member/balance/withdraw_cash",
  76. "style": {
  77. "navigationBarTitleText": "提现"
  78. }
  79. },
  80. {
  81. "path": "pages/member/balance/details",
  82. "style": {
  83. "navigationBarTitleText": "余额明细"
  84. }
  85. },
  86. {
  87. "path": "pages/member/balance/cashlist",
  88. "style": {
  89. "navigationBarTitleText": "提现记录"
  90. }
  91. },
  92. {
  93. "path": "pages/member/balance/bankcard",
  94. "style": {
  95. "navigationBarTitleText": "我的银行卡"
  96. }
  97. },
  98. {
  99. "path": "pages/member/balance/add_bankcard",
  100. "style": {
  101. "navigationBarTitleText": "添加银行卡"
  102. }
  103. },
  104. {
  105. "path": "pages/member/collection/index",
  106. "style": {
  107. "navigationBarTitleText": "我的收藏"
  108. }
  109. },
  110. {
  111. "path": "pages/member/history/index",
  112. "style": {
  113. "navigationBarTitleText": "我的足迹"
  114. }
  115. },
  116. {
  117. "path": "pages/member/address/list",
  118. "style": {
  119. "navigationBarTitleText": "地址管理"
  120. }
  121. },
  122. {
  123. "path": "pages/member/address/index",
  124. "style": {
  125. "navigationBarTitleText": "修改地址"
  126. }
  127. },
  128. {
  129. "path": "pages/member/setting/index",
  130. "style": {
  131. "navigationBarTitleText": "设置"
  132. }
  133. },
  134. {
  135. "path": "pages/member/setting/user_info/index",
  136. "style": {
  137. "navigationBarTitleText": "个人信息"
  138. }
  139. },
  140. {
  141. "path": "pages/member/setting/user_info/password",
  142. "style": {
  143. "navigationBarTitleText": "修改密码"
  144. }
  145. },
  146. {
  147. "path": "pages/member/integral/index",
  148. "style": {
  149. "navigationBarTitleText": "我的积分"
  150. }
  151. },
  152. {
  153. "path": "pages/member/invite/index",
  154. "style": {
  155. "navigationBarTitleText": "邀请好友"
  156. }
  157. },
  158. {
  159. "path": "pages/member/invite/list",
  160. "style": {
  161. "navigationBarTitleText": "邀请列表"
  162. }
  163. },
  164. {
  165. "path": "pages/member/take_delivery/index",
  166. "style": {
  167. "navigationBarTitleText": "提货单核销"
  168. }
  169. },
  170. {
  171. "path": "pages/member/take_delivery/list",
  172. "style": {
  173. "navigationBarTitleText": "提货单列表"
  174. }
  175. },
  176. {
  177. "path": "pages/goods/index/index",
  178. "style": {
  179. // #ifdef H5
  180. "titleNView": false,
  181. // #endif
  182. "navigationBarTitleText": "商品详情",
  183. "navigationStyle": "custom"
  184. }
  185. },
  186. {
  187. "path": "pages/goods/index/group",
  188. "style": {
  189. "navigationBarTitleText": "促销详情",
  190. "navigationStyle": "custom"
  191. }
  192. },
  193. {
  194. "path": "pages/goods/place-order/index",
  195. "style": {
  196. "navigationBarTitleText": "提交订单"
  197. }
  198. },
  199. {
  200. "path": "pages/goods/place-order/invoice",
  201. "style": {
  202. "navigationBarTitleText": "发票"
  203. }
  204. },
  205. {
  206. "path": "pages/goods/place-order/storelist",
  207. "style": {
  208. "navigationBarTitleText": "门店列表"
  209. }
  210. },
  211. {
  212. "path": "pages/goods/payment/index",
  213. "style": {
  214. "navigationBarTitleText": "支付"
  215. }
  216. },
  217. {
  218. "path": "pages/goods/payment/auth",
  219. "style": {
  220. "navigationBarTitleText": "等待支付"
  221. }
  222. },
  223. {
  224. "path": "pages/goods/payment/result",
  225. "style": {
  226. "navigationBarTitleText": "支付结果"
  227. }
  228. },
  229. {
  230. "path": "pages/member/order/orderlist",
  231. "style": {
  232. "navigationBarTitleText": "订单列表"
  233. }
  234. },
  235. {
  236. "path": "pages/member/order/orderdetail",
  237. "style": {
  238. "navigationBarTitleText": "订单详情"
  239. }
  240. },
  241. {
  242. "path": "pages/member/order/invitation_group",
  243. "style": {
  244. "navigationBarTitleText": "邀请拼单"
  245. }
  246. },
  247. {
  248. "path": "pages/member/after_sale/index",
  249. "style": {
  250. "navigationBarTitleText": "申请售后"
  251. }
  252. },
  253. {
  254. "path": "pages/member/after_sale/list",
  255. "style": {
  256. "navigationBarTitleText": "售后列表"
  257. }
  258. },
  259. {
  260. "path": "pages/member/after_sale/detail",
  261. "style": {
  262. "navigationBarTitleText": "售后详情"
  263. }
  264. },
  265. {
  266. "path": "pages/member/order/evaluate",
  267. "style": {
  268. "navigationBarTitleText": "订单评价"
  269. }
  270. },
  271. {
  272. "path": "pages/member/order/express_delivery",
  273. "style": {
  274. "navigationBarTitleText": "物流信息"
  275. }
  276. },
  277. {
  278. "path": "pages/article/index",
  279. "style": {
  280. "navigationBarTitleText": "文章详情"
  281. }
  282. },
  283. {
  284. "path": "pages/article/list",
  285. "style": {
  286. "navigationBarTitleText": "文章列表"
  287. }
  288. },
  289. {
  290. "path": "pages/login/choose/index",
  291. "style": {
  292. "navigationBarTitleText": "授权登录"
  293. }
  294. },
  295. {
  296. "path": "pages/login/login/index",
  297. "style": {
  298. "navigationBarTitleText": "登录"
  299. }
  300. },
  301. {
  302. "path": "pages/login/login/index1",
  303. "style": {
  304. "navigationBarTitleText": "登录"
  305. }
  306. },
  307. {
  308. "path": "pages/share",
  309. "style": {
  310. "navigationBarTitleText": "分享"
  311. }
  312. },
  313. {
  314. "path": "pages/author",
  315. "style": {
  316. // #ifdef H5
  317. "titleNView": false,
  318. // #endif
  319. "navigationBarTitleText": "获取授权中"
  320. }
  321. },
  322. {
  323. "path": "pages/login/register/index",
  324. "style": {
  325. "navigationBarTitleText": "注册"
  326. }
  327. },
  328. {
  329. "path": "pages/classify/pintuan_list",
  330. "style": {
  331. "navigationBarTitleText": "拼团列表"
  332. }
  333. },
  334. {
  335. "path": "pages/goods/index/pintuan",
  336. "style": {
  337. "navigationBarTitleText": "拼团详情",
  338. "navigationStyle": "custom"
  339. }
  340. },
  341. {
  342. "path": "pages/form/detail/form",
  343. "style": {
  344. "navigationBarTitleText": "万能表单"
  345. }
  346. },
  347. {
  348. "path": "pages/member/distribution/index",
  349. "style": {
  350. "navigationBarTitleText": "分销中心"
  351. }
  352. },
  353. {
  354. "path": "pages/member/distribution/apply",
  355. "style": {
  356. "navigationBarTitleText": "申请成为分销"
  357. }
  358. },
  359. {
  360. "path": "pages/member/distribution/apply_state",
  361. "style": {
  362. "navigationBarTitleText": "审核状态"
  363. }
  364. },
  365. {
  366. "path": "pages/member/distribution/user",
  367. "style": {
  368. "navigationBarTitleText": "分销中心"
  369. }
  370. },
  371. {
  372. "path": "pages/member/distribution/agreement",
  373. "style": {
  374. "navigationBarTitleText": "分销协议"
  375. }
  376. },
  377. {
  378. "path": "pages/member/distribution/order",
  379. "style": {
  380. "navigationBarTitleText": "推广订单"
  381. }
  382. },
  383. {
  384. "path": "pages/member/distribution/popularize",
  385. "style": {
  386. "navigationBarTitleText": "我要推广"
  387. }
  388. },
  389. {
  390. "path": "pages/member/distribution/my_store",
  391. "style": {
  392. "navigationBarTitleText": "我的店铺"
  393. }
  394. },
  395. {
  396. "path": "pages/member/distribution/store_setting",
  397. "style": {
  398. "navigationBarTitleText": "店铺设置"
  399. }
  400. },
  401. {
  402. "path": "pages/activity/index",
  403. "style": {
  404. "navigationBarTitleText": "转盘抽奖"
  405. }
  406. },
  407. {
  408. "path": "pages/share/jump",
  409. "style": {
  410. // #ifdef H5
  411. "titleNView": false,
  412. // #endif
  413. "navigationBarTitleText": "加载中..."
  414. }
  415. },
  416. {
  417. "path": "pages/store_map/index",
  418. "style": {
  419. "navigationBarTitleText": "门店列表"
  420. }
  421. }
  422. ],
  423. "globalStyle": {
  424. "navigationBarTextStyle": "black",
  425. "navigationBarTitleText": "新模板",
  426. "navigationBarBackgroundColor": "#fff",
  427. "backgroundColor": "#F8F8F8"
  428. },
  429. "tabBar": {
  430. "color": "#999",
  431. "selectedColor": "#333",
  432. "backgroundColor": "#fff",
  433. "list": [
  434. {
  435. "pagePath": "pages/index/index",
  436. "text": "首页",
  437. "iconPath": "static/image/index_gray.png",
  438. "selectedIconPath": "static/image/index_black.png"
  439. },
  440. {
  441. "pagePath": "pages/classify/classify",
  442. "text": "分类",
  443. "iconPath": "static/image/classify_gray.png",
  444. "selectedIconPath": "static/image/classify_black.png"
  445. },
  446. {
  447. "pagePath": "pages/cart/index/index",
  448. "text": "购物车",
  449. "iconPath": "static/image/cart_gray.png",
  450. "selectedIconPath": "static/image/cart_black.png"
  451. },
  452. {
  453. "pagePath": "pages/member/index/index",
  454. "text": "我的",
  455. "iconPath": "static/image/user_gray.png",
  456. "selectedIconPath": "static/image/user_black.png"
  457. }
  458. ]
  459. },
  460. "condition": {
  461. //模式配置,仅开发期间生效
  462. "current": 0, //当前激活的模式(list 的索引项)
  463. "list": [
  464. {
  465. "name": "", //模式名称
  466. "path": "", //启动页面,必选
  467. "query": "" //启动参数,在页面的onLoad函数里面得到
  468. }
  469. ]
  470. }
  471. }

README.md

复制代码
  1. # Jshop小程序uniapp前台简约模板
  2. #### 介绍
  3. 当前版本已支持可视化操作首页
  4. uni-app简约前台H5+小程序模板,全新UI设计,更多交互细节,我们倾尽全力为您提供更加流畅舒爽的体验。
  5. 增加对支付宝小程序、APP的支持,实现一个后台,管理5个前端。
  6. 同时又实现了一套前端代码,发布多个平台,为您的业务可以提供更加强有力的支撑!
  7. #### Jshop小程序商城介绍
  8. Jshop小程序商城,是一款开源的电商系统,包含微信小程序和H5端,为大中小企业提供移动电子商务优秀的解决方案。
  9. 后台采用Thinkphp5.1框架开发,执行效率、扩展性、稳定性值得信赖。并且Jshop小程序商城上手难度低,可大量节省定制化开发周期。
  10. 前台H5使用Vue开发,在页面的打开和渲染效率上更快,下单流程流畅自然,可大大增加用户体验,提升订单量。
  11. 强大的促销引擎,多种促销方式自由搭配,满足各种场景的促销方式需求,做活动更灵活简单,并且在促销的扩展上也非常方便。
  12. #### 关于开源
  13. 这不是一款免费的系统,商用记得授权哦。
  14. 之所以不彻底免费,一方面是可以让我们有持续维护下去的动力和资源,另外一方面也是不想让您有后顾之忧,避免后期尴尬。
  15. 我们的团队水平有限,也是在探索中学习,在改进。之所以开源,就是为了方便大家,也是为了提升下该项目的质量,我们相信有您的参与,可以使我们的系统更加完善和健壮。
  16. #### 功能介绍
  17. + 商品管理,单规格、多规格商品管理,品牌、分类管理、商品评价
  18. + 订单管理,订单支付、发货、取消、售后等
  19. + 会员管理,会员列表,消息管理等
  20. + 运营管理,广告管理、文章管理
  21. + 微信管理,小程序管理、微信公众号管理、模板列表、公众号菜单管理
  22. + 促销管理,商品促销、订单促销、优惠券、团购秒杀
  23. + 财务管理,支付单、退款单管理、提现管理、账户资金管理
  24. + 控制面板,计划任务、插件、图片、地区、消息、店铺配置、支付方式、配送方式、物流公司管理。信任登录插件、阿里云OSS插件、阿里云短信插件、微信消息模板插件、分销功能
  25. + 门店管理,门店列表。门店核销、店员管理、提货单管理。
  26. + 智能表单,表单列表、表单统计、表单提交管理、表单小程序码等
  27. + 统计报表,商品销量统计、财务收款统计、订单销量统计
  28. + 页面管理,布局管理,页面可视化操作
  29. #### 项目演示
  30. - H5体验地址:https://demo.jihainet.com/wap/
  31. - 后台项目地址:https://gitee.com/hnjihai/jshop_mall
  32. - QQ交流群:823732583(开发手册、接口文档、操作手册请进群查看哦~)
  33. - 交流社区:[https://bbs.jihainet.com/](https://bbs.jihainet.com/)
  34. - H5体验二维码
  35. ![输入图片说明](https://gitee.com/uploads/images/2019/0426/090608_1a1f0073_8503.png "H5.png")
  36. - APP体验二维码
  37. ![输入图片说明](https://gitee.com/uploads/images/2019/0426/090622_d1d4b372_8503.png "app.png")
  38. - 微信小程序体验码
  39. ![输入图片说明](https://gitee.com/uploads/images/2019/0426/082533_e2f315f9_8503.jpeg "gh_f9fafa5a7066_344.jpg")
  40. #### 项目截图
  41. ![输入图片说明](https://gitee.com/uploads/images/2019/0404/180847_9615f414_8503.png "未标题-1.png")
  42. #### 目录结构
  43. 初始的目录结构如下:

wap WEB部署目录(或者子目录)
├─components uniapp组件目录
├─pages 应用页面
│ ├─article 文章相关页面
│ ├─cart 购物车相关页面
│ ├─classify 分类以及商品列表页面
│ ├─goods 商品详情页等相关页面
│ ├─index 首页以及搜索页
│ ├─login 登录相关页面
│ ├─member 会员中心相关页面

├─config 配置文件目录
├─static 静态文件目录
├─unpackage 编译后目录
├─index.html 入口文件模板

复制代码
  1. #### 更新说明
  2. 2019-07-31 v1.0.6
  3. 更新日志
  4. 1. 可视化图片分组添加最小高度
  5. 2. 禁止可视化垃圾桶拖拽
  6. 3. 1086短信接口改为curl
  7. 4. 增加是否绑定手机号码选项,优化后台生成用户方法
  8. 5. 修复购物车数量加减的问题
  9. 6. 生成订单的时候,有几个值没有保存成功的bug,感谢@打酱油网友提供的bug
  10. 7. 修复运费包邮bug
  11. 8. 开启规格处增加提示
  12. 9. 新增拼团功能
  13. 10. 微信登陆免手机号码校验
  14. 11. 第三方登录的时候,免手机号码验证登陆的时候,保存推荐人信息
  15. 12. 如果是第三方微信登陆,增加直接登陆
  16. 13. 用户列表显示编号
  17. 14. 修复团购秒杀删除商品后依然显示问题
  18. 15. 门店表距离获取 表前缀bug修复
  19. 16. 修复商品商品详情页品牌为空的时候,显示null的问题
  20. 17. 门店列表表前缀sql修复
  21. 18. 小程序可视化单图组件添加按钮功能
  22. 19. 订单列表加类型筛选
  23. 20. 商品详情显示优化
  24. 21. 修复库存问题
  25. 22. 可视化编辑添加文字按钮颜色
  26. 23. 小程序价格区间问题修复
  27. 24. 微信公众号无感登陆支付
  28. 25. 公众号自动登陆调整
  29. 26. 修复售后单详情查询的时候必填user_id的问题
  30. 27. 商品分类排序问题修复
  31. 28. 文章详情接口修改(文章发布时间修改为相对时间)
  32. 29. 手机号验证规则修复
  33. 30. 修复后台用户信息保存推荐人信息错误的bug
  34. 31. 修复多规格商品添加时,第一次无法保存库存问题
  35. 32. 修改可视化商品组件手动选择数据绑定
  36. 33. 修复团购秒杀问题
  37. 34. 微信和支付宝同步回调地址增加上支付单号
  38. 35. 修复门店订单有运费问题
  39. 36. 后台提货单操作,提货单详情接口修改
  40. 37. 订单售后状态简单修改
  41. 38. 修复首页多个商品组件时问题
  42. 39. 商品列表问题修复
  43. 40. 商品列表筛选调整
  44. 41. 商品分类优化
  45. 42. 页面布局修改
  46. 43. 修改商品和货品库存显示
  47. 44. 优化权限问题,修复订单支付无权限bug
  48. 45. 优化角色权限选择,可以单独选择父节点
  49. 46. 商品添加扩展分类
  50. 47. 后台商品列表动态计算库存
  51. 48. 修复公众号菜单问题
  52. 49. 修复关键词菜单
  53. 50. 图文编辑原文地址必填项问题修复,增加系统图文地址
  54. 51. 商品增加批量出库库存,改价
  55. 52. 修复商品评论,评论优化
  56. 53. 分类增加是否显示
  57. 54. 页面增加添加功能
  58. 55. 会员增加批量删除
  59. 56. 新增分销插件
  60. 57. 增加每日提现上限
  61. 58. 接口增加全局安全过滤
  62. 59. 后台登录添加背景动画,优化后台登录
  63. 60. 后台管理弹框显示修改
  64. 61. 余额变动优化,增加余额当前页统计,余额筛选类型修复
  65. 62. 修复收货地址前端输入换行问题
  66. 63. 修复后台修改管理员密码问题
  67. 64. 优化后台优化输出结构,避免节点无权限时乱码
  68. 65. 优化公众号配置地址
  69. 66. 修复原生小程序商品列表翻页问题
  70. 67. 海报生成提出来,统一处理
  71. 68. 订单发货问题优化
  72. 69. 修复vue,H5底部遮挡问题
  73. 70. 优化添加商品按钮
  74. 71. 增加加解密函数
  75. 72. 增加图片缓存,路由缓存
  76. 73. 优化分享设置,后台可设置分享
  77. 74. 后台商品列表修复高级筛选
  78. 75. 商品评价列表优化
  79. 76. 表单功能修复
  80. 77. uniapp增加智能表单
  81. 78. 表单增加提交次数限制
  82. 79. uniapp增加微信模板消息
  83. 80. 增加关于我们后台可直接配置
  84. 81. 添加批量购物车接口
  85. 82. 修复商品规格编辑问题
  86. 83. 购物车和促销价格使用精确计算
  87. 84. 微信图文增加创建和更新时间
  88. 85. 最低提现金额不能小于0.01
  89. 86. 自定义页面增加操作说明
  90. 87. 配置统一获取方法优化确保只查询一次数据库
  91. 88. 修复广告位
  92. 89. 修复编辑文章时分类问题
  93. 90. 可视化单图组件增加按钮以及颜色
  94. 2019-05-23 v1.0.5
  95. 1.修复图片组件跳转问题
  96. 2019-05-22 v1.0.4
  97. 1.增加可视化支持
  98. 2019-04-25 v1.0.3
  99. 1. 修复海报生成
  100. 2. 修复支付宝支付问题
  101. 3. 微信授权登录修复
  102. 4. 修复app登录返回问题
  103. 5. 修复支付宝绑定账户时短信验证码ip问题
  104. #### 安装教程
  105. 1. 小程序发布教程
  106. 具体配置稍后提供
  107. 开发相关介绍:https://uniapp.dcloud.io/
  108. 2. H5发布教程
  109. 具体配置稍后提供
  110. 开发相关开发介绍:https://uniapp.dcloud.io/
  111. ## 配置
  112. ### 服务器地址
  113. config/config.js中

export const baseUrl = 'http://www.b2c.com/';//注意最后斜杠,填写你的域名地址
export const entId = '';//客服ID 在https://www.jihainet.com中找客服开通

复制代码
  1. ### 海报H5中保存图片跨域
  2. nginx中添加以下配置
复制代码
  1. location ~ .*\.(gif|jpg|jpeg|png)$ {
  2. add_header Access-Control-Allow-Origin *;
  3. add_header Access-Control-Allow-Headers X-Requested-With;
  4. add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
  5. }
复制代码
  1. #### 安全&缺陷
  2. 如果你发现了一个安全漏洞或缺陷,请发送邮件到 jima@jihainet.com。所有的安全漏洞都将及时得到解决。
  3. #### License
  4. Jshop小程序商城遵循JPPL(吉海科技Jshop系列付费产品许可)协议。
  5. 本项目包含的第三方源码和二进制文件之版权信息另行标注。
  6. 版权所有Copyright © 2019 by 吉海科技 (https://www.jihainet.com)
  7. All rights reserved。
  8. 吉海科技Jshop系列付费产品许可协议详情请参阅 [LICENSE.txt](LICENSE.txt)

static

css

style.css
复制代码
  1. body{
  2. background-color: #f8f8f8;
  3. font-size: 28upx;
  4. }
  5. view{
  6. box-sizing: border-box;
  7. }
  8. /* #ifdef MP-ALIPAY */
  9. image{
  10. background-size: 100% 100%;
  11. }
  12. button{
  13. height: auto;
  14. border: none;
  15. line-height: 2.55555556;
  16. padding: 0 28upx;
  17. }
  18. input{
  19. background: none;
  20. padding: 0;
  21. }
  22. shared-checkbox{
  23. border-radius: 50%;
  24. }
  25. shared-checkbox{
  26. border-radius: 50%;
  27. height: 36rpx;
  28. width: 36rpx;
  29. margin-top: -4rpx;
  30. border: 1rpx solid #d1d1d1;
  31. color: #FF7159;
  32. }
  33. shared-checkbox:checked {
  34. /* width: 36rpx;
  35. height: 36rpx;
  36. line-height: 36rpx;
  37. border-radius: 50%;
  38. text-align: center;
  39. font-size: 28rpx;
  40. color: #fff;
  41. background: transparent;
  42. transform: translate(-50%, -50%) scale(1);
  43. -webkit-transform: translate(-50%, -50%) scale(1);
  44. background-color: #FF7159;
  45. border: 1rpx solid #FF7159; */
  46. background-color: #000;
  47. color: #000;
  48. }
  49. ._radio{
  50. border-radius: 50%;/* 圆角 */
  51. width: 36rpx;
  52. height: 36rpx;
  53. margin-top: -4rpx;
  54. border: 1rpx solid #d1d1d1;
  55. }
  56. /* 选中后的 背景样式 (红色背景 无边框 可根据UI需求自己修改) */
  57. ._radio:checked{
  58. border: 1rpx solid #FF7159;
  59. background: #FF7159;
  60. }
  61. /* 选中后的 对勾样式 (白色对勾 可根据UI需求自己修改) */
  62. ._radio:checked::before{
  63. border-radius: 50%;/* 圆角 */
  64. width: 36rpx; /* 选中后对勾大小,不要超过背景的尺寸 */
  65. height: 36rpx; /* 选中后对勾大小,不要超过背景的尺寸 */
  66. line-height: 36rpx;
  67. text-align: center;
  68. font-size:28rpx; /* 对勾大小 30rpx */
  69. color:#fff; /* 对勾颜色 白色 */
  70. background: transparent;
  71. transform:translate(-50%, -50%) scale(1);
  72. -webkit-transform:translate(-50%, -50%) scale(1);
  73. }
  74. /* #endif */
  75. uni-toast .uni-toast{
  76. /* width: 6em; */
  77. font-size: 24upx;
  78. border-radius: 10px;
  79. background: rgba(17,17,17,.5);
  80. }
  81. uni-input div, uni-input div div,uni-input, uni-input input{
  82. /* min-height: 1rem !important; */
  83. }
  84. uni-input{
  85. /* height: 1rem; */
  86. }
  87. uni-input div div.input-placeholder{
  88. /* padding: 8upx 0; */
  89. }
  90. .content-top{
  91. margin-bottom: 116upx;
  92. }
  93. .have-none{
  94. background-color: #f3f3f3;
  95. }
  96. .color-o{
  97. color: #FF7159 !important;
  98. }
  99. .color-f{
  100. color: #fff !important;
  101. }
  102. .color-d{
  103. color: #ddd !important;
  104. }
  105. .color-3{
  106. color: #333 !important;
  107. }
  108. .color-6{
  109. color: #666 !important;
  110. }
  111. .color-9{
  112. color: #999 !important;
  113. }
  114. .fsz24{
  115. font-size: 24upx !important;
  116. }
  117. .fsz26{
  118. font-size: 26upx !important;
  119. }
  120. .fsz28{
  121. font-size: 28upx !important;
  122. }
  123. .fsz30{
  124. font-size: 30upx !important;
  125. }
  126. .fsz32{
  127. font-size: 32upx !important;
  128. }
  129. .fsz34{
  130. font-size: 34upx !important;
  131. }
  132. .fsz36{
  133. font-size: 36upx !important;
  134. }
  135. .fsz38{
  136. font-size: 38upx !important;
  137. }
  138. .fsz50{
  139. font-size: 50upx !important;
  140. }
  141. .search{
  142. width: 100%;
  143. height: 104upx;
  144. padding: 16upx 26upx;
  145. background-color: rgba(255,255,255,1);
  146. z-index: 999;
  147. transition: all .5s;
  148. }
  149. .search-c{
  150. width: 100%;
  151. height: 100%;
  152. position: relative;
  153. }
  154. .search-input{
  155. background-color: #E9E9E9;
  156. width: 100%;
  157. height: 100%;
  158. box-sizing: border-box;
  159. line-height: 52upx;
  160. padding: 10upx 90upx 10upx 40upx;
  161. border-radius: 50upx;
  162. font-size: 24upx;
  163. transition: all .5s;
  164. }
  165. .search-input-p{
  166. color: #999;
  167. width: 100%;
  168. height: 100%;
  169. }
  170. .search-input-p-c{
  171. position: relative;
  172. top: 50%;
  173. transform: translateY(-50%);
  174. }
  175. .search-icon{
  176. position: absolute;
  177. top: 50%;
  178. right: 30upx;
  179. transform: translateY(-50%);
  180. z-index: 99;
  181. }
  182. .swiper-c{
  183. height: 100%;
  184. }
  185. .swiper-c image{
  186. height: 100%;
  187. width: 100%;
  188. }
  189. .btn{
  190. display: inline-block;
  191. box-sizing: border-box;
  192. border-radius: 0;
  193. font-size: 28upx;
  194. transform: scale(1);
  195. transition: all .5s;
  196. }
  197. /*按钮按下缩小变色*/
  198. .btn-hover{
  199. transform: scale(.90);
  200. transition: all .5s;
  201. opacity: .8;
  202. }
  203. /*按钮按下只变色*/
  204. .btn-hover2{
  205. /* transform: scale(.95); */
  206. transition: all .1s;
  207. opacity: .6;
  208. }
  209. .btn::after{
  210. border: none;
  211. }
  212. .btn-circle{
  213. padding: 0upx 20upx;
  214. height: 60upx;
  215. line-height: 60upx;
  216. min-width: 140upx;
  217. /* border-radius: 6upx; */
  218. font-size: 22upx;
  219. }
  220. .btn-square{
  221. padding: 0upx 40upx;
  222. height: 90upx;
  223. line-height: 90upx;
  224. min-width: 150upx;
  225. border: none !important;
  226. }
  227. .btn-fillet{
  228. border-radius: 50upx;
  229. }
  230. .btn-c{
  231. background-color: #f7f7f7;
  232. }
  233. .btn-w{
  234. border: 2upx solid #333;
  235. color: #333;
  236. background-color: #fff;
  237. }
  238. .btn-g{
  239. border: 2upx solid #E0E0E0;
  240. color: #999;
  241. background-color: #fff;
  242. }
  243. .btn-b{
  244. border: 2upx solid #333;
  245. background-color: #333;
  246. color: #fff;
  247. }
  248. .btn-o{
  249. border: 2upx solid #FF7159;
  250. background-color: #FF7159;
  251. color: #fff;
  252. }
  253. .btn-half{
  254. width: 50%;
  255. }
  256. .btn-all{
  257. width: 100%;
  258. }
  259. .img-grids{
  260. overflow: hidden;
  261. /* padding-bottom: 26upx; */
  262. }
  263. .img-grids .goods-name{
  264. height: 72upx;
  265. }
  266. .column3.img-grids .goods-name{
  267. height: 68upx;
  268. }
  269. .img-grids-item{
  270. width: 336upx;
  271. margin: 26upx;
  272. display: inline-block;
  273. background-color: #fff;
  274. float: left;
  275. min-height: 130upx;
  276. /* #ifdef MP-ALIPAY */
  277. width: 330rpx;
  278. margin: 25rpx;
  279. min-height: 130rpx;
  280. /* #endif */
  281. }
  282. .img-grids-item:nth-child(2n-1){
  283. margin-right: 0;
  284. }
  285. .img-grids-item-t{
  286. width: 336upx;
  287. height: 336upx;
  288. /* #ifdef MP-ALIPAY */
  289. width: 330rpx;
  290. height: 330rpx;
  291. /* #endif */
  292. }
  293. .img-grids-item-b{
  294. padding: 0 10upx 10upx;
  295. }
  296. .goods-name{
  297. display: -webkit-box;
  298. -webkit-box-orient: vertical;
  299. -webkit-line-clamp: 2;
  300. overflow: hidden;
  301. color: #333;
  302. width: 100%;
  303. /* height: 72upx; */
  304. /* #ifdef MP-ALIPAY */
  305. min-height: 20px;
  306. /* #endif */
  307. }
  308. .grids-goods-name{
  309. font-size: 26upx;
  310. }
  311. .goods-item-c{
  312. overflow: hidden;
  313. margin-top: 10upx;
  314. }
  315. .goods-price{
  316. min-width: 120upx;
  317. min-height: 40upx;
  318. color: #333;
  319. font-size: 28upx;
  320. display: inline-block;
  321. float: left;
  322. }
  323. .red-price{
  324. color: #FF7159 !important;
  325. }
  326. .img-list{
  327. }
  328. .img-list .goods-name{
  329. min-height: 74upx;
  330. }
  331. .img-list-item{
  332. padding: 30upx 26upx;
  333. background-color: #fff;
  334. margin-bottom: 2upx;
  335. overflow: hidden;
  336. }
  337. .img-list-item-l{
  338. width: 250upx;
  339. height: 250upx;
  340. display: inline-block;
  341. float: left;
  342. }
  343. .img-list-item-r{
  344. width: 410upx;
  345. min-height: 250upx;
  346. display: inline-block;
  347. margin-left: 26upx;
  348. float: left;
  349. padding: 10upx 0;
  350. position: relative;
  351. }
  352. .list-goods-name{
  353. font-size: 28upx;
  354. }
  355. .img-list-item .goods-item-c{
  356. /* position: absolute; */
  357. /* bottom: 0; */
  358. width: 100%;
  359. margin-top: 0;
  360. }
  361. .img-list-item .goods-price{
  362. min-width: 150upx;
  363. min-height: 50upx;
  364. font-size: 38upx;
  365. float: none;
  366. }
  367. .goods-buy{
  368. overflow: hidden;
  369. }
  370. .goods-salesvolume{
  371. min-width: 100upx;
  372. height: 30upx;
  373. font-size: 20upx;
  374. color: #999;
  375. display: inline-block;
  376. }
  377. .goods-cart{
  378. width: 40upx;
  379. height: 40upx;
  380. float: right;
  381. }
  382. .medium-img{
  383. width: 196upx;
  384. height: 196upx;
  385. }
  386. .little-img{
  387. width: 140upx;
  388. height: 140upx;
  389. }
  390. .small-img{
  391. width: 120upx;
  392. height: 120upx;
  393. }
  394. .medium-right{
  395. width: 340upx;
  396. min-height: 140upx;
  397. }
  398. .little-right{
  399. width: 520upx;
  400. min-height: 140upx;
  401. padding: 0;
  402. }
  403. .small-right{
  404. width: 540upx;
  405. height: 120upx;
  406. padding: 0;
  407. min-height: 60upx;
  408. }
  409. .little-right-t{
  410. overflow: hidden;
  411. }
  412. .little-right .list-goods-name{
  413. float: left;
  414. width: 360upx;
  415. margin-bottom: 6upx;
  416. }
  417. .small-right .list-goods-name{
  418. width: 100%;
  419. }
  420. .little-right .goods-price{
  421. float: right;
  422. font-size: 28upx;
  423. text-align: right;
  424. min-width: 120upx;
  425. max-width: 150upx;
  426. overflow: hidden;
  427. white-space: nowrap;
  428. text-overflow: ellipsis;
  429. min-height: 40upx;
  430. }
  431. .goods-num{
  432. float: right;
  433. color: #999;
  434. font-size: 24upx;
  435. height: 30upx;
  436. min-width: 50upx;
  437. }
  438. .goods-numbox{
  439. float: right;
  440. }
  441. .little-right .goods-salesvolume{
  442. font-size: 24upx;
  443. /* float: left; */
  444. }
  445. .cell-group{
  446. background-color: #fff;
  447. }
  448. .cell-item{
  449. padding: 20upx 26upx 20upx 0;
  450. width: 724upx;
  451. margin-left: 26upx;
  452. border-bottom: 2upx solid #f3f3f3;
  453. position: relative;
  454. overflow: hidden;
  455. background-color: #fff;
  456. color: #333;
  457. display: table;
  458. min-height: 90upx;
  459. }
  460. .cell-item:last-child{
  461. border: none;
  462. }
  463. .cell-item-hd{
  464. display: table-cell;
  465. vertical-align: middle;
  466. min-width: 160upx;
  467. max-width: 180upx;
  468. font-size: 28upx;
  469. position: relative;
  470. }
  471. .cell-hd-icon{
  472. width: 40upx;
  473. height: 40upx;
  474. display: inline-block;
  475. float: left;
  476. margin-right: 8upx;
  477. }
  478. .cell-hd-title{
  479. float: left;
  480. display: inline-block;
  481. position: relative;
  482. /* #ifdef MP-ALIPAY */
  483. top: 4upx;
  484. /* #endif */
  485. /* word-wrap: break-word; */
  486. }
  487. .cell-item-bd{
  488. display: table-cell;
  489. vertical-align: middle;
  490. margin-left: 20upx;
  491. min-height: 30upx;
  492. overflow: hidden;
  493. min-width: 440upx;
  494. max-width: 480upx;
  495. padding-right: 50upx;
  496. }
  497. .cell-bd-view {
  498. position: relative;
  499. overflow: hidden;
  500. }
  501. .cell-bd-text{
  502. float: left;
  503. position: relative;
  504. font-size: 24upx;
  505. }
  506. .cell-bd-text-right{
  507. float: right;
  508. }
  509. .cell-bd-input{
  510. display: inline-block;
  511. float: left;
  512. font-size: 26upx;
  513. }
  514. .cell-item-ft{
  515. display: inline-block;
  516. position: absolute;
  517. top: 50%;
  518. right: 26upx;
  519. transform: translateY(-50%);
  520. overflow: hidden;
  521. }
  522. .right-img .cell-item-ft{
  523. right: 8upx;
  524. height: 50upx;
  525. }
  526. .cell-ft-view{
  527. position: relative;
  528. overflow: hidden;
  529. color: #666;
  530. font-size: 28upx;
  531. text-align: right;
  532. }
  533. .cell-ft-p{
  534. font-size: 24upx;
  535. color: #666;
  536. }
  537. .cell-ft-text{
  538. font-size: 28upx;
  539. float: right;
  540. position: relative;
  541. /* top: 8upx; */
  542. line-height: 50upx;
  543. }
  544. .cell-ft-next{
  545. float: right;
  546. }
  547. .margin-cell-group{
  548. margin: 20upx 0;
  549. }
  550. .bottom-cell-group{
  551. margin-bottom: 20upx;
  552. }
  553. .min-cell-group{
  554. margin-bottom: 1px;
  555. padding: 20upx 0;
  556. }
  557. .min-cell-group .cell-item{
  558. border-bottom: none;
  559. min-height: 50upx;
  560. padding: 0 26upx 0 0;
  561. }
  562. .icon{
  563. width: 50upx;
  564. height: 50upx;
  565. /* #ifdef MP-ALIPAY */
  566. background-size: 100% 100%;
  567. /* #endif */
  568. }
  569. .swiper-grids .swiper-list{
  570. white-space:nowrap;
  571. width:100%;
  572. min-height: 200upx;
  573. }
  574. .swiper-grids .img-grids-item{
  575. float: none;
  576. margin-right: 0;
  577. width: 255upx;
  578. margin-top: 0;
  579. }
  580. .swiper-grids .img-grids-item:last-child{
  581. margin-right: 26upx;
  582. }
  583. .swiper-grids .img-grids-item-t{
  584. width: 255upx;
  585. height: 255upx;
  586. }
  587. .swiper-grids .goods-name{
  588. white-space: normal;
  589. }
  590. .member-grid{
  591. padding: 20upx 26upx;
  592. /* overflow: hidden; */
  593. width: 100%;
  594. display: flex;
  595. }
  596. .member-item{
  597. /* width: 20%; */
  598. flex: 1;
  599. /* float: left; */
  600. /* display: inline-block; */
  601. text-align: center;
  602. position: relative;
  603. }
  604. /*会员中心图标按下事件*/
  605. .member-item:active{
  606. transform: scale(.90);
  607. transition: all .5s;
  608. opacity: .8;
  609. }
  610. .member-item-icon{
  611. width: 50upx;
  612. height: 50upx;
  613. display: block;
  614. margin: 0 auto;
  615. }
  616. .member-item-text{
  617. font-size: 24upx;
  618. color: #666;
  619. display: block;
  620. }
  621. .cart-list{
  622. }
  623. .cart-checkbox{
  624. position: relative;
  625. height: 100%;
  626. }
  627. .cart-checkbox-c{
  628. display: inline-block;
  629. position: absolute;
  630. top: 50%;
  631. left: 26upx;
  632. transform: translateY(-50%);
  633. z-index: 99;
  634. }
  635. .cart-list .img-list-item{
  636. padding-left: 90upx;
  637. }
  638. .cart-list .little-right{
  639. width: 468upx;
  640. }
  641. .cart-list .little-right .list-goods-name{
  642. width: 300upx;
  643. }
  644. .uni-checkbox-input{
  645. border-radius: 50% !important;
  646. color: #fff !important;
  647. }
  648. uni-radio .uni-radio-input,uni-checkbox .uni-checkbox-input{
  649. width: 36upx;
  650. height: 36upx;
  651. }
  652. uni-checkbox .uni-checkbox-input.uni-checkbox-input-checked,.uni-radio-input.uni-radio-input-checked{
  653. background-color: #FF7159 !important;
  654. border-color: #FF7159 !important;
  655. width: 36upx;
  656. height: 36upx;
  657. }
  658. uni-checkbox.checkboxNo .uni-checkbox-input{
  659. background-color: #e1e1e1 !important;
  660. border-color: #e1e1e1 !important;
  661. }
  662. uni-radio.radioNo .uni-radio-input{
  663. background-color: #e1e1e1 !important;
  664. border-color: #e1e1e1 !important;
  665. }
  666. uni-checkbox .uni-checkbox-input.uni-checkbox-input-checked:before{
  667. font-size: 36rpx;
  668. }
  669. .login-item-i-p{
  670. color: #999;
  671. }
  672. .two-line{
  673. display: -webkit-box;
  674. -webkit-box-orient: vertical;
  675. -webkit-line-clamp: 2;
  676. overflow: hidden;
  677. }
  678. .badge{
  679. display: inline-block;
  680. position: absolute;
  681. min-width:13px;
  682. height:13px;
  683. line-height:13px;
  684. background-color:#FF7159;
  685. color:#fff;
  686. font-size:12px;
  687. border-radius:50upx;
  688. padding:0 3px;
  689. z-index: 99;
  690. }
  691. .button-bottom{
  692. background-color: #fff;
  693. position: fixed;
  694. bottom: 0;
  695. height: 90upx;
  696. width: 100%;
  697. display: flex;
  698. z-index: 66;
  699. box-shadow: 0 0 10px #ccc;
  700. }
  701. .button-bottom .btn{
  702. flex: 1;
  703. }
  704. .romotion-tip{
  705. /* display: inline-block; */
  706. overflow: hidden;
  707. }
  708. .romotion-tip-item{
  709. display: inline-block;
  710. float: left;
  711. margin-right: 10upx;
  712. margin-bottom: 4upx;
  713. background-color: #FF7159;
  714. color: #fff;
  715. height: 34upx;
  716. font-size: 24upx;
  717. line-height: 34upx;
  718. padding: 0 10upx;
  719. }
  720. .bg-gray{
  721. background-color: #D0D0D0;
  722. }
  723. /* #ifdef MP */
  724. checkbox .wx-checkbox-input{
  725. border-radius: 50%;
  726. height: 36rpx;
  727. width: 36rpx;
  728. margin-top: -4rpx;
  729. border: 1rpx solid #d1d1d1;
  730. }
  731. checkbox .wx-checkbox-input.wx-checkbox-input-checked::before {
  732. width: 36rpx;
  733. height: 36rpx;
  734. line-height: 36rpx;
  735. border-radius: 50%;
  736. text-align: center;
  737. font-size: 28rpx;
  738. color: #fff;
  739. background: transparent;
  740. transform: translate(-50%, -50%) scale(1);
  741. -webkit-transform: translate(-50%, -50%) scale(1);
  742. background-color: #FF7159;
  743. border: 1rpx solid #FF7159;
  744. }
  745. radio .wx-radio-input{
  746. border-radius: 50%;/* 圆角 */
  747. width: 36rpx;
  748. height: 36rpx;
  749. margin-top: -4rpx;
  750. border: 1rpx solid #d1d1d1;
  751. }
  752. /* 选中后的 背景样式 (红色背景 无边框 可根据UI需求自己修改) */
  753. radio .wx-radio-input.wx-radio-input-checked{
  754. border: 1rpx solid #FF7159;
  755. background: #FF7159;
  756. }
  757. /* 选中后的 对勾样式 (白色对勾 可根据UI需求自己修改) */
  758. radio .wx-radio-input.wx-radio-input-checked::before{
  759. border-radius: 50%;/* 圆角 */
  760. width: 36rpx; /* 选中后对勾大小,不要超过背景的尺寸 */
  761. height: 36rpx; /* 选中后对勾大小,不要超过背景的尺寸 */
  762. line-height: 36rpx;
  763. text-align: center;
  764. font-size:28rpx; /* 对勾大小 30rpx */
  765. color:#fff; /* 对勾颜色 白色 */
  766. background: transparent;
  767. transform:translate(-50%, -50%) scale(1);
  768. -webkit-transform:translate(-50%, -50%) scale(1);
  769. }
  770. /* #endif */
  771. .goods-bottom{
  772. z-index: 97;
  773. }
  774. .btn-small{
  775. padding: 0 10rpx;
  776. height: 36rpx;
  777. line-height: 32rpx;
  778. font-size: 24rpx;
  779. margin: 0 10rpx;
  780. }

image

img

store

index.js

复制代码
  1. import Vue from 'vue'
  2. import Vuex from 'vuex'
  3. Vue.use(Vuex)
  4. const store = new Vuex.Store({
  5. state: {
  6. config: {}, // 店铺配置信息
  7. orderTab: 0, // 选中的订单tab页
  8. redirectPage: '',
  9. uuid:'',//当前客户端
  10. searchStyle: ''
  11. },
  12. mutations: {
  13. config (state, payload) {
  14. state.config = payload
  15. },
  16. orderTab (state, tab) {
  17. state.orderTab = tab
  18. },
  19. redirect (state, payload) {
  20. state.redirectPage = payload.page
  21. },
  22. searchStyle (state, style) {
  23. state.searchStyle = style
  24. }
  25. },
  26. actions: {
  27. },
  28. getters: {
  29. shopConfig: state => state.config,
  30. uuid: state => state.uuid,
  31. }
  32. })
  33. export default store

uni.scss

复制代码
  1. /**
  2. * 这里是uni-app内置的常用样式变量
  3. *
  4. * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
  5. * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
  6. *
  7. */
  8. /**
  9. * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
  10. *
  11. * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
  12. */
  13. /* 颜色变量 */
  14. /* 行为相关颜色 */
  15. $uni-color-primary: #007aff;
  16. $uni-color-success: #4cd964;
  17. $uni-color-warning: #f0ad4e;
  18. $uni-color-error: #dd524d;
  19. /* 文字基本颜色 */
  20. $uni-text-color:#333;//基本色
  21. $uni-text-color-inverse:#fff;//反色
  22. $uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息
  23. $uni-text-color-placeholder: #808080;
  24. $uni-text-color-disable:#c0c0c0;
  25. /* 背景颜色 */
  26. $uni-bg-color:#ffffff;
  27. $uni-bg-color-grey:#f8f8f8;
  28. $uni-bg-color-hover:#f1f1f1;//点击状态颜色
  29. $uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
  30. /* 边框颜色 */
  31. $uni-border-color:#c8c7cc;
  32. /* 尺寸变量 */
  33. /* 文字尺寸 */
  34. $uni-font-size-sm:24upx;
  35. $uni-font-size-base:28upx;
  36. $uni-font-size-lg:32upx;
  37. /* 图片尺寸 */
  38. $uni-img-size-sm:40upx;
  39. $uni-img-size-base:52upx;
  40. $uni-img-size-lg:80upx;
  41. /* Border Radius */
  42. $uni-border-radius-sm: 4upx;
  43. $uni-border-radius-base: 6upx;
  44. $uni-border-radius-lg: 12upx;
  45. $uni-border-radius-circle: 50%;
  46. /* 水平间距 */
  47. $uni-spacing-row-sm: 10px;
  48. $uni-spacing-row-base: 20upx;
  49. $uni-spacing-row-lg: 30upx;
  50. /* 垂直间距 */
  51. $uni-spacing-col-sm: 8upx;
  52. $uni-spacing-col-base: 16upx;
  53. $uni-spacing-col-lg: 24upx;
  54. /* 透明度 */
  55. $uni-opacity-disabled: 0.3; // 组件禁用态的透明度
  56. /* 文章场景相关 */
  57. $uni-color-title: #2C405A; // 文章标题颜色
  58. $uni-font-size-title:40upx;
  59. $uni-color-subtitle: #555555; // 二级标题颜色
  60. $uni-font-size-subtitle:36upx;
  61. $uni-color-paragraph: #3F536E; // 文章段落颜色
  62. $uni-font-size-paragraph:30upx;
  63. //自定义变量
  64. $theme-color: #28b8a1;
  65. $bg-grey: #f4f4f4;
  66. $bd-color: #f0f0f0;
  67. $color-light: #5e5e5e;
  68. $g2: #eeeeee;
  69. $g5: #9e9e9e;
  70. $fz12: 24upx;
  71. $fz16: 32upx;
  72. $fz18: 36upx;
  73. $fz20: 40upx;