lilei 8 місяців тому
батько
коміт
a817722731
100 змінених файлів з 4210 додано та 793 видалено
  1. 21 201
      App.vue
  2. 0 22
      components/jyf-parser/libs/handler.wxs
  3. 3 1
      components/kk-printer/printer/cpcl.js
  4. 0 9
      components/kk-printer/printer/encoding-indexes.js
  5. 16 39
      components/kk-printer/printer/encoding.js
  6. 5 3
      components/kk-printer/printer/esc.js
  7. 5 3
      components/kk-printer/printer/tsc.js
  8. 1 1
      components/kk-printer/utils/printUtil-GBK.js
  9. 1 1
      components/kk-printer/utils/util.js
  10. 20 0
      index.html
  11. 1 1
      js_sdk/dc-clipboard/clipboard.js
  12. 1 1
      js_sdk/dc-market/market.js
  13. 2 2
      js_sdk/u-charts/u-charts/u-charts.js
  14. 0 0
      js_sdk/u-charts/u-charts/u-charts.min.js
  15. 11 11
      libs/axios.js
  16. 1 1
      libs/helper.js
  17. 4 4
      libs/jgPush.js
  18. 7 4
      libs/tools.js
  19. 51 62
      main.js
  20. 4 2
      manifest.json
  21. 0 18
      package-lock.json
  22. 1 2
      package.json
  23. 18 14
      pages.json
  24. 1 1
      pages/approveStore/authPass.vue
  25. 3 3
      pages/batchShelves/batchPrint/productList.vue
  26. 3 3
      pages/batchShelves/cartList.vue
  27. 3 3
      pages/batchShelves/editShelfHw.vue
  28. 3 3
      pages/batchShelves/printStickerModal.vue
  29. 1 1
      pages/batchShelves/scanProduct.vue
  30. 3 3
      pages/batchShelves/searchProduct.vue
  31. 4 4
      pages/common/partList.vue
  32. 3 3
      pages/common/printTag/printTag.vue
  33. 3 3
      pages/index/index.vue
  34. 1 1
      pages/latePlay/chooseProduct.vue
  35. 1 1
      pages/login/apply-trial.vue
  36. 8 7
      pages/login/login.scss
  37. 13 13
      pages/login/login.vue
  38. 1 1
      pages/login/userAuthYs.vue
  39. 4 4
      pages/replenishmentManage/confirm.vue
  40. 3 3
      pages/replenishmentManage/printStickerModal.vue
  41. 1 1
      pages/replenishmentManage/scanCodePrint.vue
  42. 1 1
      pages/replenishmentManage/sendOutGoods.vue
  43. 1 1
      pages/sales/bill.vue
  44. 2 2
      pages/sales/billHistoryDetail.vue
  45. 1 1
      pages/sales/chooseCustomer.vue
  46. 1 1
      pages/sales/chooseCustomerBill.vue
  47. 1 1
      pages/sales/chooseProduct.vue
  48. 1 1
      pages/sales/edit.vue
  49. 1 1
      pages/sales/index.vue
  50. 1 1
      pages/sales/productModal.vue
  51. 6 6
      pages/sales/productPricing.vue
  52. 1 1
      pages/sales/productSearch.vue
  53. 0 2
      pages/sales/productUniversal.vue
  54. 2 2
      pages/sales/salesDetail.vue
  55. 1 1
      pages/sales/selectedProductsModal.vue
  56. 2 2
      pages/shelfOrder/shelfList.vue
  57. 3 3
      pages/shelfSetting/productList.vue
  58. 3 3
      pages/shelfSetting/quickProductList.vue
  59. 1 1
      pages/shelfSetting/shelfSet.vue
  60. 5 6
      pages/shuntBackManage/addBackOrder.vue
  61. 0 1
      pages/shuntBackManage/chooseProduct.vue
  62. 1 1
      pages/shuntBackManage/detail.vue
  63. 3 3
      pages/shuntBackManage/productList.vue
  64. 1 1
      pages/soldOut/chooseProduct.vue
  65. 3 3
      pages/soldOut/productList.vue
  66. 2 1
      pages/statistics/index.vue
  67. 1 1
      pages/stock/detaiList.vue
  68. 8 8
      pages/stock/index.vue
  69. 1 1
      pages/stock/stockDetail.vue
  70. 4 4
      pages/stock/stockSearch.vue
  71. 1 1
      pages/stock/warehouseDetail.vue
  72. 1 1
      pages/userCenter/changePwd.vue
  73. 7 12
      pages/userCenter/index.vue
  74. 1 1
      pages/userCenter/setData.vue
  75. 1 1
      pages/vinAnalyse/fitProductlist.vue
  76. 2 2
      pages/vinAnalyse/shelfAnalyse.vue
  77. 1 1
      pages/webviews/openview.vue
  78. 1 5
      pages/xtNotice/xtNoticeDetail/xtNoticeDetail.vue
  79. 1 1
      store/$u.mixin.js
  80. 8 6
      store/index.js
  81. 13 0
      uni.promisify.adaptor.js
  82. 199 35
      uni.scss
  83. 194 0
      uni_modules/mp-html/README.md
  84. 150 0
      uni_modules/mp-html/changelog.md
  85. 498 0
      uni_modules/mp-html/components/mp-html/mp-html.vue
  86. 587 0
      uni_modules/mp-html/components/mp-html/node/node.vue
  87. 1393 0
      uni_modules/mp-html/components/mp-html/parser.js
  88. 76 0
      uni_modules/mp-html/package.json
  89. 0 0
      uni_modules/mp-html/static/app-plus/mp-html/js/handler.js
  90. 0 0
      uni_modules/mp-html/static/app-plus/mp-html/js/uni.webview.min.js
  91. 1 0
      uni_modules/mp-html/static/app-plus/mp-html/local.html
  92. 74 0
      uni_modules/qiun-data-charts/changelog.md
  93. 37 26
      uni_modules/qiun-data-charts/components/qiun-data-charts/qiun-data-charts.vue
  94. 10 5
      uni_modules/qiun-data-charts/js_sdk/u-charts/config-ucharts.js
  95. 443 133
      uni_modules/qiun-data-charts/js_sdk/u-charts/u-charts.js
  96. 0 0
      uni_modules/qiun-data-charts/js_sdk/u-charts/u-charts.min.js
  97. 6 10
      uni_modules/qiun-data-charts/package.json
  98. 14 32
      uni_modules/qiun-data-charts/readme.md
  99. 172 0
      uni_modules/vk-uview-ui/changelog.md
  100. 29 0
      uni_modules/vk-uview-ui/components/u--text/u--text.vue

+ 21 - 201
App.vue

@@ -1,5 +1,7 @@
 <script>
+	//#ifdef APP-PLUS
 	import skJGPush from '@/libs/jgPush.js'
+	//#endif
 	import {openMessagePage} from '@/libs/tools.js'
 	export default {
 		globalData: {  
@@ -7,26 +9,26 @@
 			token: '',
 			changeOrg:'',
 			version: '', // 当前版本号
-			buildType: 'uat', // 打包环境对应类型,pro 生产 uat 预发布 dev 本地开发
+			buildType: 'dev', // 打包环境对应类型,pro 生产 uat 预发布 dev 本地开发
 			envTips: '', // 环境文字提示
 			theme: 'default', // 主题,default
-			isIphoneXup: false //是否iphonex以及以上的版本
-		},
-		mounted() {
-			// 非V3模式
-			if (this.$scope) {
-				this.$scope.globalData.token = this.$store.state.vuex_token;
-				this.$scope.globalData.changeOrg = this.$store.state.vuex_changeOrg;
-			} else {
-				// V3模式
-				getApp({ allowDefault: true }).globalData.token = this.$store.state.vuex_token;
-				getApp({ allowDefault: true }).globalData.changeOrg = this.$store.state.vuex_changeOrg;
-			}
-			this.$config('init');
 		},
 		onLaunch: function() {
 			console.log('App launch')
+			const App = getApp({ allowDefault: true })
+			App.globalData.token = this.$store.state.vuex_token;
+			App.globalData.changeOrg = this.$store.state.vuex_changeOrg;
+			const theme = App.globalData.theme
+			const envText = {pro:'生产环境',dev:'开发环境',uat:'预发布环境'}
+			let buildType = App.globalData.buildType
+			let baseUrl = this.$config(buildType+'_URL')
+			App.globalData.baseUrl = baseUrl
+			App.globalData.envTips = envText[buildType]
+			this.$store.state.vuex_theme = App.globalData.theme
 			this.$store.state.vuex_tempData = ''
+			
+			// 消息推送
+			//#ifdef APP-PLUS
 			let bgAudioManager = uni.getBackgroundAudioManager();
 			if(uni.getSystemInfoSync().platform == "ios"){
 				// 请求定位权限
@@ -102,6 +104,7 @@
 			skJGPush.addConnectEventListener(result => {
 				console.log('【连接状态】', result)
 			})
+		//#endif
 		},
 		onShow: function() {
 			console.log('App Show')
@@ -110,9 +113,9 @@
 			console.log('App Hide')
 		},
 		methods:{
-			setRead(item){
-				const api = require("@/api/user.js")
-				const token = getApp().globalData.token
+			async setRead(item){
+				const api = await import("@/api/user.js")
+				const token = getApp({ allowDefault: true }).globalData.token
 				if(token){
 					api.setReadNotice({'noticeId': item.extras.noticeId}).then(res => {
 						console.log(res,'setRead')                                                                                     
@@ -128,190 +131,7 @@
 
 <style lang="scss">
 	@import "./static/iconfont/iconfont.css";
-	@import "uview-ui/index.scss";
-	/*每个页面公共css */
-	page {
-		width: 100%;
-		min-height: 100%;
-		display: flex;
+	page{
 		background-color: #F8F8F8;
 	}
-	/* 登录页是否记住密码多选框样式 */
-	uni-checkbox.login-form-checkbox .uni-checkbox-input{
-		width: 24upx !important;
-		height: 24upx !important;
-	}
-	.status_bar {
-	      height: var(--status-bar-height);
-	      width: 100%;
-	  }
-	.isIPXup{
-		padding-bottom: 64rpx !important;
-	}
-	/*  form表单样式 */
-	.form-box{
-		background-color: #fff;
-		padding: 0 30rpx;
-	}
-	.form-input {
-		font-size: 28rpx;
-		color: #333;
-		text-align: right;
-		width: 95%;
-		box-sizing: border-box;
-		height: 60rpx;
-		line-height: 60rpx;
-		&.textarea{
-			height: 240rpx;
-			padding: 24rpx 0;
-			text-align: left;
-		}
-	}
-	
-	.form-input-placeholder {
-		font-size: 28rpx;
-		color: #999;
-	}
-	.form-textarea{
-		height: 240rpx;
-		padding: 24rpx 0;
-		text-align: left;
-	}
-	.form-number-input{
-		margin: 0 auto;
-	}
-	.u-required{
-		position: relative;
-	}
-	.u-required:before{
-		content: '*';
-		position: absolute;
-		left: -8px;
-		top: 10upx;
-		font-size: 14px;
-		color: #fa3534;
-		height: 9px;
-		line-height: 1;
-	}
-	/* 元素宽度 百分比 */
-	.uni-col-1{
-		box-sizing: border-box;
-		width: 10%;
-	}
-	.uni-col-2{
-		box-sizing: border-box;
-		width: 20%;
-	}
-	.uni-col-3{
-		box-sizing: border-box;
-		width: 30%;
-	}
-	.uni-col-4{
-		box-sizing: border-box;
-		width: 40%;
-	}
-	.uni-col-5{
-		box-sizing: border-box;
-		width: 50%;
-	}
-	.uni-col-6{
-		box-sizing: border-box;
-		width: 60%;
-	}
-	.uni-col-7{
-		box-sizing: border-box;
-		width: 70%;
-	}
-	.uni-col-8{
-		box-sizing: border-box;
-		width: 80%;
-	}
-	.uni-col-9{
-		box-sizing: border-box;
-		width: 90%;
-	}
-	.uni-col-10{
-		box-sizing: border-box;
-		width: 100%;
-	}
-	
-	/* felx布局 */
-	.flex{
-		display: -webkit-flex; /* Chrome 21+, Safari 6.1+, iOS Safari 7+, Opera 15/16 */  
-		display: -moz-flex; /* Firefox 18+ */  
-		display: -ms-flexbox; /* IE 10 */  
-		display: flex; /* Chrome 29+, Firefox 22+, IE 11+, Opera 12.1/17/18, Android 4.4+ */
-	}
-	/*伸缩流方向*/
-	.flex_column{
-	    -webkit-box-orient: vertical;
-	    -ms-flex-direction: column;
-	    -webkit-flex-direction: column;
-	    flex-direction: column;
-	}
-	/*主轴对齐*/
-	.justify_center{
-	    -webkit-box-pack: center;
-	    -ms-flex-pack: center;
-	    -webkit-justify-content: center;
-	    justify-content: center;
-	}
-	.justify_end{
-	    -webkit-box-pack: end;
-	    -ms-flex-pack: end;
-	    -webkit-justify-content: flex-end;
-	    justify-content: flex-end;
-	}
-	.justify_between{
-	    -webkit-box-pack: justify;
-	    -ms-flex-pack: justify;
-	    -webkit-justify-content: space-between;
-	    justify-content: space-between;
-	}
-	/*侧轴对齐*/
-	.align_start{
-	    -webkit-box-align: start;
-	    -ms-flex-align: start;
-	    -webkit-align-items: flex-start;
-	    align-items: flex-start;
-	}
-	.align_end{
-	    -webkit-box-align: end;
-	    -ms-flex-align: end;
-	    -webkit-align-items: flex-end;
-	    align-items: flex-end;
-	}
-	.align_center{
-	    -webkit-box-align: center;
-	    -ms-flex-align: center;
-	    -webkit-align-items: center;
-	    align-items: center;
-	}
-	.align_baseline{
-	    -webkit-box-align: baseline;
-	    -ms-flex-align: baseline;
-	    -webkit-align-items: baseline;
-	    align-items: baseline;
-	}
-	/*伸缩性*/
-	.flex_auto{
-	    -webkit-box-flex: 1;
-	    -ms-flex: auto;
-	    -webkit-flex: auto;
-	    flex: auto;
-	}
-	.flex_1{
-	    -webkit-box-flex: 1;
-	    -ms-flex: 1;
-	    -webkit-flex: 1;
-	    flex: 1;    
-	}
-	// ios15原生input的type=search时会默认自带搜索图标。
-	// 在全局的公共样式隐藏ios自带搜索图标即可
-	[type="search"]::-webkit-search-decoration {
-		display: none;
-	}
-	uni-toast {
-		z-index: 1000000;
-	}
 </style>

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

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

+ 3 - 1
components/kk-printer/printer/cpcl.js

@@ -285,4 +285,6 @@ export function addCPCLImageCmd(x, y, data) {
 	//console.log(strImgCmd);
 	return strImgCmd;
 }
-module.exports.type = 'cpcl';
+export default{
+	type : 'cpcl'
+}

Різницю між файлами не показано, бо вона завелика
+ 0 - 9
components/kk-printer/printer/encoding-indexes.js


+ 16 - 39
components/kk-printer/printer/encoding.js

@@ -1,20 +1,8 @@
-// This is free and unencumbered software released into the public domain.
-// See LICENSE.md for more information.
-
-/**
- * @fileoverview Global |this| required for resolving indexes in node.
- * @suppress {globalThis}
- */
-(function(global) {
-  'use strict';
-
+  // This is free and unencumbered software released into the public domain.
+  // See LICENSE.md for more information.
   // If we're in node require encoding-indexes and attach it to the global.
-  if (typeof module !== "undefined" && module.exports &&
-    !global["encoding-indexes"]) {
-    global["encoding-indexes"] =
-      require("./encoding-indexes.js")["encoding-indexes"];
-  }
-
+  import codeIndexes from './encoding-indexes.js';
+  
   //
   // Utilities
   //
@@ -843,11 +831,11 @@
    * @return {(!Array.<number>|!Array.<Array.<number>>)}
    *  */
   function index(name) {
-    if (!('encoding-indexes' in global)) {
+    if (!codeIndexes) {
       throw Error("Indexes missing." +
                   " Did you forget to include encoding-indexes.js first?");
     }
-    return global['encoding-indexes'][name];
+    return codeIndexes[name];
   }
 
   /**
@@ -1241,10 +1229,10 @@
       // Standard behavior.
       enc._encoding = getEncoding('utf-8');
 
-      if (label !== undefined && 'console' in global) {
-        console.warn('TextEncoder constructor called with encoding label, '
-                     + 'which is ignored.');
-      }
+      // if (label !== undefined && 'console' in global) {
+      //   console.warn('TextEncoder constructor called with encoding label, '
+      //                + 'which is ignored.');
+      // }
     }
 
     // For pre-ES5 runtimes:
@@ -1627,7 +1615,7 @@
   }
 
   (function() {
-    if (!('encoding-indexes' in global))
+    if (!codeIndexes)
       return;
     encodings.forEach(function(category) {
       if (category.heading !== 'Legacy single-byte encodings')
@@ -3294,19 +3282,8 @@
     return new XUserDefinedDecoder(options);
   };
 
-  if (!global['TextEncoder'])
-    global['TextEncoder'] = TextEncoder;
-  if (!global['TextDecoder'])
-    global['TextDecoder'] = TextDecoder;
-
-  if (typeof module !== "undefined" && module.exports) {
-    module.exports = {
-      TextEncoder: global['TextEncoder'],
-      TextDecoder: global['TextDecoder'],
-      EncodingIndexes: global["encoding-indexes"]
-    };
-  }
-
-// For strict environments where `this` inside the global scope
-// is `undefined`, take a pure object instead
-}(this || {}));
+  export default {
+    TextEncoder: TextEncoder,
+    TextDecoder: TextDecoder,
+    EncodingIndexes: codeIndexes
+  };

+ 5 - 3
components/kk-printer/printer/esc.js

@@ -1,4 +1,4 @@
-var encode = require("./encoding.js")
+import encode from "./encoding.js"
 var jpPrinter = {
 	createNew: function() {
 		var jpPrinter = {};
@@ -310,5 +310,7 @@ var jpPrinter = {
 
 };
 
-module.exports.jpPrinter = jpPrinter;
-module.exports.type = 'esc';
+export default{
+	jpPrinter,
+	type:'esc'
+}

+ 5 - 3
components/kk-printer/printer/tsc.js

@@ -3,7 +3,7 @@
  * 2021.04.26 uni-app版本
  * @auth boolTrue
  */
-var encode = require("./encoding.js");
+import encode from "./encoding.js"
 var jpPrinter = {
 	createNew: function() {
 		var jpPrinter = {};
@@ -383,5 +383,7 @@ var jpPrinter = {
 	}
 };
 
-module.exports.jpPrinter = jpPrinter;
-module.exports.type = 'tsc';
+export default{
+	jpPrinter,
+	type: 'tsc'
+}

+ 1 - 1
components/kk-printer/utils/printUtil-GBK.js

@@ -1,4 +1,4 @@
-module.exports = {
+export default {
   parseHex: parseHex,//提取十六进制
   stringTrim: stringTrim,//剔除空格回车
   strToGBKHex: strToGBKHex,//字符串转GBK十六进制内码

+ 1 - 1
components/kk-printer/utils/util.js

@@ -161,7 +161,7 @@ function buf2hex(buffer) {
   return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join('');
 }
 
-module.exports = {
+export default {
   hexStringToArrayBuffer: hexStringToArrayBuffer,
   send0X0A: send0X0A,
   ab2hex: ab2hex,

+ 20 - 0
index.html

@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <script>
+      var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
+        CSS.supports('top: constant(a)'))
+      document.write(
+        '<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
+        (coverSupport ? ', viewport-fit=cover' : '') + '" />')
+    </script>
+    <title></title>
+    <!--preload-links-->
+    <!--app-context-->
+  </head>
+  <body>
+    <div id="app"><!--app-html--></div>
+    <script type="module" src="/main.js"></script>
+  </body>
+</html>

+ 1 - 1
js_sdk/dc-clipboard/clipboard.js

@@ -43,7 +43,7 @@ function getClipboardText(){
 }
 
 
-module.exports = {
+export default {
 	setText: setClipboardText,
 	getText: getClipboardText
 }

+ 1 - 1
js_sdk/dc-market/market.js

@@ -39,6 +39,6 @@ function openMarket(options){
 }
 
 
-module.exports = {
+export default {
 	open: openMarket
 }

+ 2 - 2
js_sdk/u-charts/u-charts/u-charts.js

@@ -5657,6 +5657,6 @@ Charts.prototype.scrollEnd = function(e) {
   }
 };
 if (typeof module === "object" && typeof module.exports === "object") {
-  module.exports = Charts;
-  //export default Charts;//建议使用nodejs的module导出方式,如报错请使用export方式导出
+  // module.exports = Charts;
+  export default Charts;//建议使用nodejs的module导出方式,如报错请使用export方式导出
 }

Різницю між файлами не показано, бо вона завелика
+ 0 - 0
js_sdk/u-charts/u-charts/u-charts.min.js


+ 11 - 11
libs/axios.js

@@ -1,11 +1,12 @@
 import { objToUrl } from '@/libs/tools.js';
-const baseUrl = getApp().globalData.baseUrl
 import store from '@/store/index.js'
 //带Token请求
 const request = (opts, hasToken) => {
-	const authorization = getApp().globalData.token
-	const changeOrg = getApp().globalData.changeOrg
-	const curVer = getApp().globalData.version
+	const App = getApp({ allowDefault: true })
+	const baseUrl = App.globalData.baseUrl
+	const authorization = App.globalData.token
+	const changeOrg = App.globalData.changeOrg
+	const curVer = App.globalData.version
 	console.log(changeOrg, !hasToken,'changeOrg')
 	//  hasToken是否传入token,为true则不传token
 	const header = {
@@ -31,7 +32,7 @@ const request = (opts, hasToken) => {
 				console.log(res)
 				// 是否超时已跳转
 				let loginTimeOut = uni.getStorageSync('loginTimeOut');
-				if(res[0]&&res[0].errMsg.indexOf('request:fail')>=0){
+				if(res&&res.errMsg.indexOf('request:fail')>=0){
 					uni.showToast({
 						icon:'none',
 						title: '网络请求失败,请检查网络连接情况',
@@ -43,14 +44,14 @@ const request = (opts, hasToken) => {
 						message: "网络请求失败"
 					})
 				}
-				let ret = res[1]
+				let ret = res
 				if(!ret.status){
 					ret.status = ret.statusCode
 				}
-				if(res[1].data.status){
-					ret = res[1].data
-				}else if(res[1].status){
-					ret = res[1]
+				if(res.data.status){
+					ret = res.data
+				}else if(res.status){
+					ret = res
 				}
 				if(ret.status == '200'){
 					resolve(ret)
@@ -117,6 +118,5 @@ function getRoutePath() {
 }
 
 export default {
-	baseUrl,
 	request
 }

+ 1 - 1
libs/helper.js

@@ -17,4 +17,4 @@ const permission = {
 	AnalysisURL:AnalysisURL
 }
 
-module.exports = permission
+export default permission

+ 4 - 4
libs/jgPush.js

@@ -1,7 +1,8 @@
 // 引用方式
+var jpushModule = null
+//#ifdef APP-PLUS
 var jpushModule = uni.requireNativePlugin("JG-JPush");
-console.log(jpushModule,'【sk】【引用方式】【jpushModule】【requireNativePlugin】')
- 
+//#endif 
 // 开启 debug 模式,默认是关闭
 function openDebug() {
     jpushModule.setLoggerEnable(true);
@@ -261,8 +262,7 @@ function addMobileNumberListener(skBack) {
     })
 }
  
- 
-module.exports = {
+export default {
     openDebug: openDebug,
     closeDebug: closeDebug,
     getRegistrationID: getRegistrationID,

+ 7 - 4
libs/tools.js

@@ -1,5 +1,7 @@
+//#ifdef APP-PLUS
 let carmera = uni.requireNativePlugin('ziteng-maskcamera')
 let cameraModule = uni.requireNativePlugin("SMUniPlugin-CameraModule")
+//#endif
 // 处理数字千位分隔符  num 数值,decimal要保留的小数位数
 export const toThousands = (num, decimal) => {
   if (decimal) {
@@ -281,7 +283,7 @@ export const checkVersionToLoadUpdate = function(newVersion,type,callback){
 	if(newVersion.version == '2001'||newVersion.version == '2002'){
 		newVersion.version = 201
 	}
-	const curVer = getApp().globalData.version  // 当前版本信息
+	const curVer = getApp({ allowDefault: true }).globalData.version  // 当前版本信息
 	console.log(newVersion,curVer,callback)
 	if(!newVersion || !curVer){
 		callback()
@@ -414,10 +416,11 @@ export const numberToFixed = function (val, num, max) {
 }
 // 保存图片到阿里云
 export const saveImgToAliOss = function(src,callback){
-	console.log(src,getApp().globalData.baseUrl,'getApp().globalData.baseUrl')
-	const authorization = getApp().globalData.token
+	const App = getApp({ allowDefault: true })
+	console.log(src,App.globalData.baseUrl,'getApp({ allowDefault: true }).globalData.baseUrl')
+	const authorization = App.globalData.token
 	uni.uploadFile({
-		url: getApp().globalData.baseUrl + 'upload/', //自行修改各自的对应的接口 
+		url: App.globalData.baseUrl + 'upload/', //自行修改各自的对应的接口 
 		filePath: src,
 		name: 'file',
 		header: {'X-AUTH-TOKEN':authorization},

+ 51 - 62
main.js

@@ -1,69 +1,58 @@
-import Vue from 'vue'
 import App from './App'
+import { createSSRApp } from 'vue'
 import store from '@/store'
+import uView from "@/uni_modules/vk-uview-ui/index.js"
 import getConfig from '@/config'
 import {delayDel} from '@/libs/tools.js'
-Vue.config.productionTip = false
+import vuexStore from "@/store/$u.mixin.js"
 
-App.mpType = 'app'
-import uView from "uview-ui"
-Vue.use(uView)
-
-let vuexStore = require("@/store/$u.mixin.js")
-Vue.mixin(vuexStore)
-//延迟执行函数
-Vue.prototype.$delayDel = delayDel
-// 系统配置
-Vue.prototype.$config = function (key) {
-	const envText = {pro:'生产环境',dev:'开发环境',uat:'预发布环境'}
-	const theme = getApp().globalData.theme
-	const config = getConfig(theme)
-	if(key == 'init'){
-		let buildType = getApp().globalData.buildType
-		let baseUrl = config[buildType+'_URL']
-		getApp().globalData.baseUrl = baseUrl
-		getApp().globalData.envTips = envText[buildType]
-	}
-	return config[key]
-}
-/**
- * 权限检查
- */
-Vue.prototype.$hasPermissions = function (value) {
- let isExist = false;
- let permissionsStr = store.state.vuex_userData.permCodes;
- if (permissionsStr == undefined || permissionsStr == null) {
-  return false;
- }
- let has = permissionsStr.find(item => {
-   return item == value
- })
- if (has) {
-  isExist = true;
- }
- return isExist;
-}
-/*
-* 提示信息
-*/ 
-Vue.prototype.toashMsg = function (title,duration) {
-	title = title == undefined ? "系统繁忙" : title;
-	uni.showToast({
-		title:title,
-		icon:'none',
-		duration: duration||4000
-	})
-}
-Vue.prototype.showLoading = function (title) {
-	title = title == undefined ? "正在加载..." : title;
-	uni.showLoading({
-		title:title,
-		mask: true
-	})
+export function createApp() {
+  const app = createSSRApp(App)
+  app.config.productionTip = false
+  app.use(store)
+  app.use(uView)
+  app.mixin(vuexStore)
+  
+  //延迟执行函数
+  app.config.globalProperties.$delayDel = delayDel
+  // 系统配置
+  app.config.globalProperties.$config = function (key) {
+	const theme = store.state.vuex_theme
+  	return getConfig(theme)[key]
+  }
+  /**
+   * 权限检查
+   */
+  app.config.globalProperties.$hasPermissions = function (value) {
+   let isExist = false;
+   let permissionsStr = store.state.vuex_userData.permCodes;
+   if (permissionsStr == undefined || permissionsStr == null) {
+    return false;
+   }
+   let has = permissionsStr.find(item => item == value)
+   if (has) {isExist = true;}
+   return isExist;
+  }
+  /*
+  * 提示信息
+  */ 
+  app.config.globalProperties.toashMsg = function (title,duration) {
+  	title = title == undefined ? "系统繁忙" : title;
+  	uni.showToast({
+  		title:title,
+  		icon:'none',
+  		duration: duration||4000
+  	})
+  }
+  app.config.globalProperties.showLoading = function (title) {
+  	title = title == undefined ? "正在加载..." : title;
+  	uni.showLoading({
+  		title:title,
+  		mask: true
+  	})
+  }
+  return {
+    app
+  }
 }
 
-const app = new Vue({
-	store,
-    ...App
-})
-app.$mount()

+ 4 - 2
manifest.json

@@ -90,7 +90,8 @@
                     "<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>",
                     "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
                 ],
-                "abiFilters" : [ "armeabi-v7a", "arm64-v8a" ]
+                "abiFilters" : [ "armeabi-v7a", "arm64-v8a" ],
+                "minSdkVersion" : 21
             },
             /* ios打包配置 */
             "ios" : {
@@ -346,5 +347,6 @@
     },
     "uniStatistics" : {
         "enable" : false
-    }
+    },
+    "vueVersion" : "3"
 }

+ 0 - 18
package-lock.json

@@ -1,18 +0,0 @@
-{
-  "name": "qpls-md-app",
-  "version": "1.0.0",
-  "lockfileVersion": 1,
-  "requires": true,
-  "dependencies": {
-    "moment": {
-      "version": "2.29.1",
-      "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
-      "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
-    },
-    "uview-ui": {
-      "version": "1.8.7",
-      "resolved": "https://registry.npmjs.org/uview-ui/-/uview-ui-1.8.7.tgz",
-      "integrity": "sha512-5oOGf6NHiSTCj6/dklKjm8LCSJ7kov3azWEcloEYTTf2Mv+cbov/aARc/8QR0ce6y1hqEtwK/YkBkP+OVKuaWw=="
-    }
-  }
-}

+ 1 - 2
package.json

@@ -14,7 +14,6 @@
   "author": "",
   "license": "ISC",
   "dependencies": {
-    "moment": "^2.29.1",
-    "uview-ui": "^1.8.7"
+    "moment": "^2.29.1"
   }
 }

+ 18 - 14
pages.json

@@ -6,7 +6,10 @@
 		{
 			"path": "pages/login/login",
 			"style": {
-				"navigationBarTitleText": ""
+				"enablePullDownRefresh": false,
+				"navigationStyle": "custom",
+				// 将回弹属性关掉
+				"bounce":"none"
 			}
 		},
 		{
@@ -60,7 +63,7 @@
 			"path": "pages/xtNotice/xtNotice",		//  我的>消息
 			"style": {
 				"navigationBarTitleText": "消息",
-				"navigationStyle":"custom",
+				"enablePullDownRefresh": false,
 				"app-plus":{
 					"titleNView": {
 						"titleAlign": "left",
@@ -94,7 +97,7 @@
             "path" : "pages/latePlay/chooseProduct",
             "style": {
             	"navigationBarTitleText": "打印贴签",
-            	"navigationStyle":"custom",
+            	"enablePullDownRefresh": false,
             	"app-plus":{
             		"titleNView": {
             			"titleAlign": "left",
@@ -124,7 +127,7 @@
             "style" :                                                                                    
             {
                 "navigationBarTitleText": "调回管理",
-				"navigationStyle":"custom",
+				"enablePullDownRefresh": false,
 				"app-plus":{
 					"titleNView": {
 						"titleAlign": "left",
@@ -149,7 +152,6 @@
                 "enablePullDownRefresh": false,
 				// 将回弹属性关掉
 				"bounce":"none",
-				"navigationStyle":"custom",
 				"app-plus":{
 					"titleNView": {
 						"titleAlign": "left",
@@ -203,7 +205,7 @@
 		    "style" :
 		    {
 		        "navigationBarTitleText": "补货管理",
-		        "navigationStyle":"custom",
+		        "enablePullDownRefresh": false,
 		        "app-plus":{
 		        	"titleNView": {
 		        		"titleAlign": "left",
@@ -342,7 +344,7 @@
 			"path": "pages/sales/list", // 销售列表
 			"style": {
 				"navigationBarTitleText": "销售单",
-				"navigationStyle":"custom",
+				"enablePullDownRefresh": false,
 				"app-plus":{
 					"titleNView": {
 						"titleAlign": "left",
@@ -376,6 +378,7 @@
 			"style": {
 				"navigationBarTitleText": "对账单详情",
 				"navigationBarTextStyle": "black",
+				"enablePullDownRefresh": false,
 				"app-plus":{
 					"titleNView": {
 						"titleAlign": "left",
@@ -404,6 +407,7 @@
 			"style": {
 				"navigationBarTitleText": "应收对账单",
 				"navigationBarTextStyle": "black",
+				"enablePullDownRefresh": false,
 				"app-plus":{
 					"titleNView": {
 						"titleAlign": "left",
@@ -445,7 +449,7 @@
 			"path": "pages/sales/chooseProduct", // 选择产品
 			"style": {
 				"navigationBarTitleText": "选择产品",
-				"navigationStyle":"custom",
+				"enablePullDownRefresh": false,
 				"app-plus":{
 					"titleNView": {
 						"titleAlign": "left",
@@ -479,7 +483,7 @@
 			"path": "pages/sales/productPricing", // 产品报价
 			"style": {
 				"navigationBarTitleText": "产品报价",
-				"navigationStyle":"custom",
+				"enablePullDownRefresh": false,
 				"app-plus":{
 					"titleNView": {
 						"titleAlign": "left",
@@ -649,7 +653,7 @@
             "path" : "pages/stockCheck/startCheck",
             "style": {
             	"navigationBarTitleText": "库存盘点",
-            	"navigationStyle":"custom",
+            	"enablePullDownRefresh": false,
             	"app-plus":{
             		"titleNView": {
             			"titleAlign": "left",
@@ -830,7 +834,7 @@
             "style" :                                                                                    
             {
                 "navigationBarTitleText": "销售统计",
-                "navigationStyle":"custom",
+                "enablePullDownRefresh": false,
                 "app-plus":{
                 	"titleNView": {
                 		"titleAlign": "left",
@@ -869,8 +873,8 @@
 		    "path" : "pages/vinAnalyse/fitProductlist",
 		    "style" :                                                                                    
 		    {
-		        "navigationBarTitleText": "适配产品统计",
-		       "navigationStyle":"custom",
+			   "navigationBarTitleText": "适配产品统计",
+		       "enablePullDownRefresh": false,
 			   "app-plus":{
 			   	"titleNView": {
 			   		"titletext": "适配产品统计"
@@ -881,7 +885,7 @@
         ,{
             "path" : "pages/vinAnalyse/shelfAnalyse",
             "style": {
-            	"navigationStyle":"custom",
+            	"enablePullDownRefresh": false,
             	"app-plus":{
             		"titleNView": {
 						"titletext":"VIN分析",

+ 1 - 1
pages/approveStore/authPass.vue

@@ -82,7 +82,7 @@
 	import { xprhStoreApplyDetail, xprhStoreApplyAudit } from '@/api/approveStore'
 	import {updateShelfPriceShow} from '@/api/shelf'
 	import { clzConfirm, numberToFixed } from '@/libs/tools';
-	const baseUrl = getApp().globalData.baseUrl
+	const baseUrl = getApp({ allowDefault: true }).globalData.baseUrl
 	export default{
 		components: {
 			Address,

+ 3 - 3
pages/batchShelves/batchPrint/productList.vue

@@ -206,16 +206,16 @@
 				border-radius: 50rpx;
 				padding: 0 6rpx;
 			}
-			/deep/ .u-icon-disabled{
+			::v-deep .u-icon-disabled{
 				background: #fff!important;
 			}
-			/deep/ .u-number-input{
+			::v-deep .u-number-input{
 				margin: 0 0;
 				border: 2rpx solid #eee;
 				border-top: 0;
 				border-bottom: 0;
 			}
-			/deep/ .u-icon-plus, /deep/ .u-icon-minus{
+			::v-deep .u-icon-plus, ::v-deep .u-icon-minus{
 				border-radius: 50rpx;
 			}
 		}

+ 3 - 3
pages/batchShelves/cartList.vue

@@ -513,16 +513,16 @@
 							border-radius: 50rpx;
 							padding: 0 6rpx;
 						}
-						/deep/ .u-icon-disabled{
+						::v-deep .u-icon-disabled{
 							background: #fff!important;
 						}
-						/deep/ .u-number-input{
+						::v-deep .u-number-input{
 							margin: 0 0;
 							border: 2rpx solid #eee;
 							border-top: 0;
 							border-bottom: 0;
 						}
-						/deep/ .u-icon-plus, /deep/ .u-icon-minus{
+						::v-deep .u-icon-plus, ::v-deep .u-icon-minus{
 							border-radius: 50rpx;
 						}
 					}

+ 3 - 3
pages/batchShelves/editShelfHw.vue

@@ -261,16 +261,16 @@
 			border-radius: 50rpx;
 			padding: 0 6rpx;
 		}
-		/deep/ .u-icon-disabled{
+		::v-deep .u-icon-disabled{
 			background: #fff!important;
 		}
-		/deep/ .u-number-input{
+		::v-deep .u-number-input{
 			margin: 0 0;
 			border: 2rpx solid #eee;
 			border-top: 0;
 			border-bottom: 0;
 		}
-		/deep/ .u-icon-plus, /deep/ .u-icon-minus{
+		::v-deep .u-icon-plus, ::v-deep .u-icon-minus{
 			border-radius: 50rpx;
 		}
 	}

+ 3 - 3
pages/batchShelves/printStickerModal.vue

@@ -92,16 +92,16 @@
 			}
 			.modal-main{
 				margin: 20upx 0 30upx;
-				/deep/ .u-radio{
+				::v-deep .u-radio{
 					width: 94%!important;
 					flex-direction: row-reverse;
 					justify-content: space-between;
 					margin: 0 3%;
 				}
-				/deep/ .u-radio__icon-wrap{
+				::v-deep .u-radio__icon-wrap{
 					flex-shrink: 0;
 				}
-				/deep/ .u-radio__label{
+				::v-deep .u-radio__label{
 					flex-grow: 1;
 					border-bottom: 2upx dashed #E5E5E5;
 					padding: 3% 0;

+ 1 - 1
pages/batchShelves/scanProduct.vue

@@ -255,7 +255,7 @@
 					_this.barcode.start()
 				}
 				
-				 const currentWebview = this.$mp.page.$getAppWebview()
+				 const currentWebview = this.$scope.$getAppWebview()
 				 currentWebview.append(this.barcode)
 				 this.barcode.start()
 			}

+ 3 - 3
pages/batchShelves/searchProduct.vue

@@ -266,16 +266,16 @@
 						border-radius: 50rpx;
 						padding: 0 6rpx;
 					}
-					/deep/ .u-icon-disabled{
+					::v-deep .u-icon-disabled{
 						background: #fff!important;
 					}
-					/deep/ .u-number-input{
+					::v-deep .u-number-input{
 						margin: 0 0;
 						border: 2rpx solid #eee;
 						border-top: 0;
 						border-bottom: 0;
 					}
-					/deep/ .u-icon-plus, /deep/ .u-icon-minus{
+					::v-deep .u-icon-plus, ::v-deep .u-icon-minus{
 						border-radius: 50rpx;
 					}
 				}

+ 4 - 4
pages/common/partList.vue

@@ -155,7 +155,7 @@
 			}
 		},
 		onLoad() {
-			this.theme = getApp().globalData.theme
+			this.theme = getApp({ allowDefault: true }).globalData.theme
 		},
 		data() {
 			return {
@@ -280,16 +280,16 @@
 				border-radius: 50rpx;
 				padding: 0 6rpx;
 			}
-			/deep/ .u-icon-disabled{
+			::v-deep .u-icon-disabled{
 				background: #fff!important;
 			}
-			/deep/ .u-number-input{
+			::v-deep .u-number-input{
 				margin: 0 0;
 				border: 2rpx solid #eee;
 				border-top: 0;
 				border-bottom: 0;
 			}
-			/deep/ .u-icon-plus, /deep/ .u-icon-minus{
+			::v-deep .u-icon-plus, ::v-deep .u-icon-minus{
 				border-radius: 50rpx;
 			}
 		}

+ 3 - 3
pages/common/printTag/printTag.vue

@@ -219,16 +219,16 @@
 			border-radius: 50rpx;
 			padding: 0 12rpx;
 		}
-		/deep/ .u-icon-disabled{
+		::v-deep .u-icon-disabled{
 			background: #fff!important;
 		}
-		/deep/ .u-number-input{
+		::v-deep .u-number-input{
 			margin: 0 2rpx;
 			border: 2rpx solid #eee;
 			border-top: 0;
 			border-bottom: 0;
 		}
-		/deep/ .u-icon-plus, /deep/ .u-icon-minus{
+		::v-deep .u-icon-plus, ::v-deep .u-icon-minus{
 			border-radius: 50rpx;
 		}
 	}

+ 3 - 3
pages/index/index.vue

@@ -86,7 +86,7 @@
 		},
 		onLoad() {
 			// 设置底部tabbar 样式
-			const theme = getApp().globalData.theme
+			const theme = getApp({ allowDefault: true }).globalData.theme
 			this.theme = theme
 			// 数字货架导航按钮
 			this.storageRacksNavList = [
@@ -172,7 +172,7 @@
 			background-color: #ffffff;
 			border-radius: 30upx;
 			padding: 10upx 20upx;
-			box-shadow: 3upx 2upx 6upx #eee;
+			box-shadow: 0 0 6upx #eee;
 			margin-bottom: 20upx;
 			.graid-box-1{
 				padding: 20rpx 0;
@@ -195,7 +195,7 @@
 			background-color: #ffffff;
 			border-radius: 30upx;
 			padding: 10upx 20upx;
-			box-shadow: 3upx 2upx 6upx #eee;
+			box-shadow: 0 0 6upx #eee;
 			margin-top: 20upx;
 			margin-bottom: 20upx;
 			.panel-title {

+ 1 - 1
pages/latePlay/chooseProduct.vue

@@ -109,7 +109,7 @@
 			}
 		},
 		onLoad(options) {
-			this.theme = getApp().globalData.theme
+			this.theme = getApp({ allowDefault: true }).globalData.theme
 			this.shelfInfo = {
 				shelfSn: options.shelfSn,
 				shelfName: options.shelfName

+ 1 - 1
pages/login/apply-trial.vue

@@ -82,7 +82,7 @@
 		// 必须要在onReady生命周期,因为onLoad生命周期组件可能尚未创建完毕
 		onReady() {
 			this.$refs.uForm.setRules(this.rules);
-			this.theme = getApp().globalData.theme;
+			this.theme = getApp({ allowDefault: true }).globalData.theme;
 		},
 		methods: {
 			//  表单提交

+ 8 - 7
pages/login/login.scss

@@ -2,18 +2,17 @@
 	background-color: #FFFFFF;
 	width: 100%;
 	height: 100vh;
-	box-sizing: border-box;
 	display: flex;
 	flex-direction: column;
 	align-items: center;
+	justify-content: space-around;
 	.login-head{
-		padding: 10upx 0;
+		padding: 20upx 0;
 		text-align: center;
 		color: #999999;
 	}
 	.login-body{
-		flex-grow: 1;
-		width: 80%;
+		width: 70%;
 		display: flex;
 		flex-direction: column;
 		align-items: center;
@@ -21,7 +20,7 @@
 	}
 	.logo{
 		display: block;
-		margin-bottom: 120upx;
+		margin-bottom: 80upx;
 		width: 160upx;
 		height: 160upx;
 	}
@@ -91,11 +90,13 @@
 	}
 	
 	.authUserYs{
-		width: 100%;
 		padding: 60upx;
-		font-size: 26upx;
+		font-size: 24upx;
 		display: flex;
 		align-items: center;
+		.xieyi{
+			margin-left: -22rpx;
+		}
 		text{
 			color: #0485F6;
 		}

+ 13 - 13
pages/login/login.vue

@@ -16,7 +16,7 @@
 					<view class="remember-pass">
 						<checkbox-group @change="rememberChange">
 							<label>
-								<u-checkbox v-model="isRemember" label-size="13px" shape="circle">记住密码</u-checkbox>
+								<u-checkbox v-model="isRemember" :icon-size="24" :label-size="24">记住密码</u-checkbox>
 							</label>
 						</checkbox-group>
 					</view>
@@ -30,12 +30,10 @@
 		</view>
 		<!-- 隐私协议 -->
 		<view class="authUserYs">
-			<u-checkbox-group width="45rpx" @change="authuserChange">
-				<u-checkbox v-model="isAuthuserYs" :label-disabled="false" shape="circle">
-				</u-checkbox>
+			<u-checkbox-group @change="authuserChange" :icon-size="24">
+				<u-checkbox v-model="isAuthuserYs" :label-disabled="false" :label-size="24">登录代表同意</u-checkbox>
 			</u-checkbox-group>
-			<view>登录代表同意</view>
-			<view @click="toYsPage">
+			<view class="xieyi" @click="toYsPage">
 				<text>用户协议</text>及<text>隐私保护政策</text>
 			</view>
 		</view>
@@ -47,7 +45,9 @@ import { checkVersionToLoadUpdate, setStorageForAppVersion,clzConfirm } from '@/
 import { isvalidNumLetter } from '@/libs/validate.js';
 import { login } from '@/api/user.js';
 import { getSysVersion } from '@/api/data.js'
+//#ifdef APP-PLUS
 import skJGPush from '@/libs/jgPush.js'
+//#endif
 export default {
 	data() {
 		return {
@@ -86,20 +86,21 @@ export default {
 		uni.$off('openMessage')
 	},
 	onShow() {
+		const _this = this
+		this.theme = this.$store.state.vuex_theme;
 		this.isRemember = this.$store.state.vuex_isRemember;
-		this.envTips = getApp().globalData.envTips;
+		this.envTips = getApp({ allowDefault: true }).globalData.envTips;
 		this.showEnvTips = process.env.NODE_ENV == 'development';
-		this.theme = getApp().globalData.theme;
 		
 		//#ifdef APP-PLUS
 		  this.isAuthuserYs = this.$store.state.vuex_isUsrAuthYs
 		  uni.getSystemInfo({
 			  success:(res) => {
-				  console.log(res)
 				  // 获取最新版本信息
 				  plus.runtime.getProperty(plus.runtime.appid,(wgtinfo)=>{
 					wgtinfo.platform = res.platform
-				  	getApp().globalData.version = wgtinfo
+					console.log(wgtinfo)
+				  	getApp({ allowDefault: true }).globalData.version = wgtinfo
 				  })
 			  }  
 		  })
@@ -115,7 +116,6 @@ export default {
 		// 版本更新
 		AndroidCheckUpdate(type){
 			let _this = this
-			let version = getApp().globalData.version
 			uni.showLoading({
 				title: '正在登录...'
 			});
@@ -174,11 +174,11 @@ export default {
 					_this.$u.vuex('vuex_userData', _this.fiterAuthCode(res.data.auth_user));
 					_this.$u.vuex('vuex_token', res.data.access_token);
 					_this.$u.vuex('vuex_authOrgs',res.data.auth_orgs);
-					getApp().globalData.token = res.data.access_token;
+					getApp({ allowDefault: true }).globalData.token = res.data.access_token;
 					console.log(res.data.auth_user)
 					// 设置别名
 					//#ifdef APP-PLUS
-					 skJGPush.setAlias({'alias':'user_'+ getApp().globalData.buildType +'_' + res.data.auth_user.userid ,'sequence': new Date().getTime()})
+					 skJGPush.setAlias({'alias':'user_'+ getApp({ allowDefault: true }).globalData.buildType +'_' + res.data.auth_user.userid ,'sequence': new Date().getTime()})
 					//#endif
 					//登录成功将用户名密码存储到用户本地
 					if (_this.isRemember) {

+ 1 - 1
pages/login/userAuthYs.vue

@@ -54,7 +54,7 @@
 			}
 		},
 		onLoad() {
-			this.theme = getApp().globalData.theme
+			this.theme = getApp({ allowDefault: true }).globalData.theme
 		}
 	}
 </script>

+ 4 - 4
pages/replenishmentManage/confirm.vue

@@ -60,7 +60,7 @@
 			})
 		},
 		onLoad(options){
-			this.theme = getApp().globalData.theme
+			this.theme = getApp({ allowDefault: true }).globalData.theme
 			this.replenishBillSn = options.sn
 			this.getRow()
 		},
@@ -209,16 +209,16 @@
 							border-radius: 50rpx;
 							padding: 0 6rpx;
 						}
-						/deep/ .u-icon-disabled{
+						::v-deep .u-icon-disabled{
 							background: #fff!important;
 						}
-						/deep/ .u-number-input{
+						::v-deep .u-number-input{
 							margin: 0 0;
 							border: 2rpx solid #eee;
 							border-top: 0;
 							border-bottom: 0;
 						}
-						/deep/ .u-icon-plus, /deep/ .u-icon-minus{
+						::v-deep .u-icon-plus, ::v-deep .u-icon-minus{
 							border-radius: 50rpx;
 						}
 					}

+ 3 - 3
pages/replenishmentManage/printStickerModal.vue

@@ -87,16 +87,16 @@
 			}
 			.modal-main{
 				margin: 20upx 0 30upx;
-				/deep/ .u-radio{
+				::v-deep .u-radio{
 					width: 94%!important;
 					flex-direction: row-reverse;
 					justify-content: space-between;
 					margin: 0 3%;
 				}
-				/deep/ .u-radio__icon-wrap{
+				::v-deep .u-radio__icon-wrap{
 					flex-shrink: 0;
 				}
-				/deep/ .u-radio__label{
+				::v-deep .u-radio__label{
 					flex-grow: 1;
 					border-bottom: 2upx dashed #E5E5E5;
 					padding: 3% 0;

+ 1 - 1
pages/replenishmentManage/scanCodePrint.vue

@@ -185,7 +185,7 @@
 					_this.barcode.start()
 				}
 				
-				 const currentWebview = this.$mp.page.$getAppWebview()
+				 const currentWebview = this.$scope.$getAppWebview()
 				 currentWebview.append(this.barcode)
 				 this.barcode.start()
 			}

+ 1 - 1
pages/replenishmentManage/sendOutGoods.vue

@@ -252,7 +252,7 @@
 				// 	_this.barcode.start()
 				// }
 				
-				//  const currentWebview = this.$mp.page.$getAppWebview()
+				//  const currentWebview = this.$scope.$getAppWebview()
 				//  currentWebview.append(this.barcode)
 				//  this.barcode.start()
 			}

+ 1 - 1
pages/sales/bill.vue

@@ -456,7 +456,7 @@ export default {
 			let verifyId = Date.now()+this.nanoid();
 			this.verifyIdNum = verifyId
 			let settlement=this.chooseTotalPayPrice - this.backDiscountVal
-			let jumpUrl = getApp().globalData.baseUrl.replace('qpls-md/','')
+			let jumpUrl = getApp({ allowDefault: true }).globalData.baseUrl.replace('qpls-md/','')
 			let url = jumpUrl +'dzd/index.html?' + this.userData.orgSn + '&'+verifyId;
 			if (uni.getSystemInfoSync().platform == 'ios') {
 				this.setBillOrder();

+ 2 - 2
pages/sales/billHistoryDetail.vue

@@ -277,7 +277,7 @@ export default {
 		//关闭编辑按钮
 		isShowEditBtn(){
 			// #ifdef APP-PLUS
-			let webview = this.$mp.page.$getAppWebview();
+			let webview = this.$scope.$getAppWebview();
 			if(this.billInfo.billStatus != 'UNSETTLE' || !this.billArr || this.showPayment || this.modalShow){
 				webview.setTitleNViewButtonStyle(0, {
 						  width:'0px'
@@ -438,7 +438,7 @@ export default {
 		},
 		// 分享图文
 		handleShare() {
-			let jumpUrl = getApp().globalData.baseUrl.replace('qpls-md/','')
+			let jumpUrl = getApp({ allowDefault: true }).globalData.baseUrl.replace('qpls-md/','')
 			let url = jumpUrl+'dzd/index.html?' + this.userData.orgSn + '&' + this.verifySn;
 			if (uni.getSystemInfoSync().platform == 'ios') {
 				uni.share({

+ 1 - 1
pages/sales/chooseCustomer.vue

@@ -187,7 +187,7 @@
 		.picker-content{
 			padding: 6upx 0 20upx;
 			width: 100%;
-			height: calc(100vh-144upx);
+			height: calc(100vh - 144upx);
 			flex: 1;
 			overflow-y: scroll;
 			.picker-main{

+ 1 - 1
pages/sales/chooseCustomerBill.vue

@@ -125,7 +125,7 @@ export default {
 		});
 	},
 	onLoad() {
-		this.theme = getApp().globalData.theme;
+		this.theme = getApp({ allowDefault: true }).globalData.theme;
 		this.getSetInfo();
 		//获取日期集合
 		this.dayGatherArr = getDate.getWeekGather();

+ 1 - 1
pages/sales/chooseProduct.vue

@@ -114,7 +114,7 @@
 			uni.$emit("refreshEditBL")
 		},
 		onLoad(opt) {
-			this.theme = getApp().globalData.theme
+			this.theme = getApp({ allowDefault: true }).globalData.theme
 			if(opt){
 				this.salesInfo = opt.data ? JSON.parse(opt.data) : null
 			}

+ 1 - 1
pages/sales/edit.vue

@@ -151,7 +151,7 @@
 			}
 		},
 		onLoad(opt) {
-			this.theme = getApp().globalData.theme
+			this.theme = getApp({ allowDefault: true }).globalData.theme
 			if(opt){
 				this.pageData = {
 					type: opt.pageType || 'edit',

+ 1 - 1
pages/sales/index.vue

@@ -104,7 +104,7 @@
 				})
 			}
 			// 底部tab
-			const theme = getApp().globalData.theme
+			const theme = getApp({ allowDefault: true }).globalData.theme
 			this.theme = theme
 			uni.setTabBarItem({
 			  "index": 0,

+ 1 - 1
pages/sales/productModal.vue

@@ -65,7 +65,7 @@
 		},
 		mounted() {
 			this.$refs.uForm.setRules(this.rules)
-			this.theme = getApp().globalData.theme
+			this.theme = getApp({ allowDefault: true }).globalData.theme
 		},
 		methods: {
 			// 确认

+ 6 - 6
pages/sales/productPricing.vue

@@ -8,8 +8,8 @@
 		<scroll-view class="product-list" scroll-y @scrolltolower="onreachBottom">
 			<view class="st-detailList-main">
 				<view class="st-detailList-main-item" v-for="(item, index) in listData" :key="item.id">
-					<view class="st-detailList-tit flex justify_between">
-						<!-- <view class="u-line" :style="{backgroundColor: $config('primaryColor')}"></view> -->
+					<view class="st-detailList-tit flex justify_between align_center">
+						<view class="u-line" :style="{backgroundColor: $config('primaryColor')}"></view>
 						<view class="u-name">
 							<text style="margin-right: 20upx;">{{item.name}}</text>
 							<u-tag size="mini" :type="item.onlineFalg==1?'success':'info'" :text="item.onlineFalgDictValue"></u-tag>
@@ -134,7 +134,7 @@
 			}
 		},
 		onLoad(option) {
-			this.theme = getApp().globalData.theme
+			this.theme = getApp({ allowDefault: true }).globalData.theme
 			this.getList()
 			this.getDealer()
 		},
@@ -218,7 +218,7 @@
 		.product-list{
 			height: calc(100vh - 94upx);
 				.st-detailList-main{
-					padding: 20upx;
+					padding: 0 20upx 20upx;
 					.st-detailList-main-item{
 						background: #ffffff;
 						padding: 20upx;
@@ -237,8 +237,8 @@
 								display: inline-block;
 								width: 6upx;
 								height: 30upx;
-								background-color: red;
-								margin: 6upx 10upx 0 10upx;
+								margin: 0 10upx 0;
+								border-radius: 5rpx;
 							}
 							.u-last{
 								text-align: right;

+ 1 - 1
pages/sales/productSearch.vue

@@ -53,7 +53,7 @@
 	import productBrand from '@/pages/common/productBrand.vue'
 	import productType from '@/pages/common/productType.vue'
 	import { warehouseAllList, vinCodeParse } from '@/api/sales'
-	const baseUrl = getApp().globalData.baseUrl
+	const baseUrl = getApp({ allowDefault: true }).globalData.baseUrl
 	export default{
 		components: { productBrand, productType },
 		props: {

+ 0 - 2
pages/sales/productUniversal.vue

@@ -4,7 +4,6 @@
 			<view class="st-detailList-main">
 				<view class="st-detailList-main-item" v-for="(item, index) in listData" :key="item.id">
 					<view class="st-detailList-tit">
-						 <!-- @click="item.titFlag=!item.titFlag" -->
 						<text style="font-weight: bold;">{{item.product.name}}</text>
 						<view class="p-tit-box" v-show="item.titFlag">{{item.product.name}}</view>
 						<u-tag size="mini" style="margin:10rpx 0 0 20rpx;" :type="item.product.onlineFalg==1?'success':'info'" :text="item.product.onlineFalgDictValue"></u-tag>
@@ -14,7 +13,6 @@
 						<view class="flex_1">
 							<view class="padding_3">产品编码:{{item.productCode}} <copyText :text="item.productCode" label="产品编码"></copyText></view>
 							<view class="padding_3">通用产品编码:{{item.productCommonCode}} </view>
-							<!-- @click="item.c_titFlag=!item.c_titFlag" -->
 							<view class="padding_3" >
 								<text>通用产品名称:{{item.productCommon.name || '--'}}</text>
 								<u-tag style="margin:10rpx 0 0 20rpx;" size="mini" :type="item.productCommon.onlineFalg==1?'success':'info'" :text="item.productCommon.onlineFalgDictValue"></u-tag>	

+ 2 - 2
pages/sales/salesDetail.vue

@@ -80,7 +80,7 @@
 			<view class="flex flex_column" v-show="current == 1">
 			<view class="sales-list-box">
 				<scroll-view class="sales-list-con" :style="{height:scrollH+'upx'}" scroll-y>
-					<view class="sales-list-item flex align_center justify_between" v-for="(con,i) in payRecode" :key="">
+					<view class="sales-list-item flex align_center justify_between" v-for="(con,i) in payRecode" :key="i">
 						<view class="sales-list-l">
 							<view>{{con.settleTime}}</view>
 							<view v-if="con.settleStyleSnDictValue">{{con.settleStyleSnDictValue}}</view>
@@ -291,7 +291,7 @@
 		.sales-product-con{
 			background-color: #fff;
 			.sales-product-header{
-				/deep/.u-tab-item{
+				::v-deep .u-tab-item{
 					border-bottom:1rpx solid #e4e7ed;
 				}
 			}

+ 1 - 1
pages/sales/selectedProductsModal.vue

@@ -78,7 +78,7 @@
 			}
 		},
 		mounted() {
-			this.theme = getApp().globalData.theme
+			this.theme = getApp({ allowDefault: true }).globalData.theme
 		},
 		methods: {
 			// 列表

+ 2 - 2
pages/shelfOrder/shelfList.vue

@@ -204,11 +204,11 @@
 			box-sizing: border-box;
 			 
 			.nav-right-item{
-				 /deep/ .u-checkbox{
+				 ::v-deep .u-checkbox{
 					 border-bottom: 1rpx solid #f8f8f8;
 					 padding: 20upx 10upx;
 				 }
-				 /deep/ .u-checkbox__label{
+				 ::v-deep .u-checkbox__label{
 					 flex-grow: 1;
 					 margin-right: 0;
 				 }

+ 3 - 3
pages/shelfSetting/productList.vue

@@ -223,16 +223,16 @@
 				border-radius: 50rpx;
 				padding: 0 6rpx;
 			}
-			/deep/ .u-icon-disabled{
+			::v-deep .u-icon-disabled{
 				background: #fff!important;
 			}
-			/deep/ .u-number-input{
+			::v-deep .u-number-input{
 				margin: 0 0;
 				border: 2rpx solid #eee;
 				border-top: 0;
 				border-bottom: 0;
 			}
-			/deep/ .u-icon-plus, /deep/ .u-icon-minus{
+			::v-deep .u-icon-plus, ::v-deep .u-icon-minus{
 				border-radius: 50rpx;
 			}
 		}

+ 3 - 3
pages/shelfSetting/quickProductList.vue

@@ -171,16 +171,16 @@
 				border-radius: 50rpx;
 				padding: 0 6rpx;
 			}
-			/deep/ .u-icon-disabled{
+			::v-deep .u-icon-disabled{
 				background: #fff!important;
 			}
-			/deep/ .u-number-input{
+			::v-deep .u-number-input{
 				margin: 0 0;
 				border: 2rpx solid #eee;
 				border-top: 0;
 				border-bottom: 0;
 			}
-			/deep/ .u-icon-plus, /deep/ .u-icon-minus{
+			::v-deep .u-icon-plus, ::v-deep .u-icon-minus{
 				border-radius: 50rpx;
 			}
 		}

+ 1 - 1
pages/shelfSetting/shelfSet.vue

@@ -243,7 +243,7 @@
 			// 获取货物
 			this.getShelfPlace()
 			this.isLoad = true
-			// this.webView = this.$mp.page.$getAppWebview(); 
+			// this.webView = this.$scope.$getAppWebview(); 
 			uni.$on("editCustome", (data) => {
 				this.isLoad = true
 				this.saveShelf(data, 0)

+ 5 - 6
pages/shuntBackManage/addBackOrder.vue

@@ -49,7 +49,6 @@
 								</view>
 							</view>
 						</view>
-						</u-checkbox>
 					</view>
 					<view class="ptools flex align_center u-row-between">
 						<view class="ptools_l u-flex">
@@ -134,7 +133,7 @@ export default {
 	},
 	onLoad(options) {
 		const _this = this
-		_this.theme = getApp().globalData.theme;
+		_this.theme = getApp({ allowDefault: true }).globalData.theme;
 		_this.shelfSn = options.shelfSn;
 		_this.shelfName = options.shelfName;
 		_this.recallBillList=_this.$store.state.vuex_shuntBackList || []
@@ -415,17 +414,17 @@ export default {
 					border-radius: 50rpx;
 					padding: 0 6rpx;
 				}
-				/deep/ .u-icon-disabled {
+				::v-deep .u-icon-disabled {
 					background: #fff !important;
 				}
-				/deep/ .u-number-input {
+				::v-deep .u-number-input {
 					margin: 0 0;
 					border: 2rpx solid #eee;
 					border-top: 0;
 					border-bottom: 0;
 				}
-				/deep/ .u-icon-plus,
-				/deep/ .u-icon-minus {
+				::v-deep .u-icon-plus,
+				::v-deep .u-icon-minus {
 					border-radius: 50rpx;
 				}
 			}

+ 0 - 1
pages/shuntBackManage/chooseProduct.vue

@@ -106,7 +106,6 @@
 									</view>
 								</view>
 							</view>
-							</u-checkbox>
 						</view>
 						<view class="ptools flex align_center">
 							<view class="ptools_l u-flex">

+ 1 - 1
pages/shuntBackManage/detail.vue

@@ -102,7 +102,7 @@
 						this.basicInfoData = res.data || null;
 						this.salesOrderList = res.data.salesReturnBillList ? res.data.salesReturnBillList:[];
 						//#ifdef APP-PLUS
-						let webView = this.$mp.page.$getAppWebview();
+						let webView = this.$scope.$getAppWebview();
 						let zeroFlag=this.partList.every(item=>{
 							return item.confirmQty ==0
 						})

+ 3 - 3
pages/shuntBackManage/productList.vue

@@ -218,16 +218,16 @@
 				border-radius: 50rpx;
 				padding: 0 6rpx;
 			}
-			/deep/ .u-icon-disabled{
+			::v-deep .u-icon-disabled{
 				background: #fff!important;
 			}
-			/deep/ .u-number-input{
+			::v-deep .u-number-input{
 				margin: 0 0;
 				border: 2rpx solid #eee;
 				border-top: 0;
 				border-bottom: 0;
 			}
-			/deep/ .u-icon-plus, /deep/ .u-icon-minus{
+			::v-deep .u-icon-plus, ::v-deep .u-icon-minus{
 				border-radius: 50rpx;
 			}
 		}

+ 1 - 1
pages/soldOut/chooseProduct.vue

@@ -515,7 +515,7 @@
 					border-radius: 50rpx;
 					text-align: center;
 					margin-bottom: 15rpx;
-					/deep/ .u-checkbox__label{
+					::v-deep .u-checkbox__label{
 						flex-grow: 1;
 					}
 				}

+ 3 - 3
pages/soldOut/productList.vue

@@ -213,16 +213,16 @@
 				border-radius: 50rpx;
 				padding: 0 6rpx;
 			}
-			/deep/ .u-icon-disabled{
+			::v-deep .u-icon-disabled{
 				background: #fff!important;
 			}
-			/deep/ .u-number-input{
+			::v-deep .u-number-input{
 				margin: 0 0;
 				border: 2rpx solid #eee;
 				border-top: 0;
 				border-bottom: 0;
 			}
-			/deep/ .u-icon-plus, /deep/ .u-icon-minus{
+			::v-deep .u-icon-plus, ::v-deep .u-icon-minus{
 				border-radius: 50rpx;
 			}
 		}

+ 2 - 1
pages/statistics/index.vue

@@ -184,7 +184,7 @@
 				this.getServerData()
 			})
 			//#ifdef APP-PLUS
-			this.webView = this.$mp.page.$getAppWebview(); 
+			this.webView = this.$scope.$getAppWebview(); 
 			//#endif
 			// 默认数据
 			this.tabChange(this.placeTab[2])
@@ -308,6 +308,7 @@
 				  params = this.getQueryDate()
 			  }
 			  salesStatistics(Object.assign(this.queryPramas,params)).then(res => {
+				  console.log(res)
 				  if(res.status == 200){
 					  this.allData = JSON.parse(JSON.stringify(res.data))
 					  this.chartData = this.getFormatData(res.data.salesDateList,res.data.salesAmountList,"销售金额")

+ 1 - 1
pages/stock/detaiList.vue

@@ -111,7 +111,7 @@
 			}
 		},
 		onLoad(option) {
-			this.theme = getApp().globalData.theme
+			this.theme = getApp({ allowDefault: true }).globalData.theme
 			this.stockInfo = option.data ? JSON.parse(option.data) : null
 			this.getList()
 		},

+ 8 - 8
pages/stock/index.vue

@@ -24,12 +24,12 @@
 				<u-form-item label="产品品牌"><u-input v-model="brandName" @click="brandModal=true" clearable @clear="brandClean" type="select" placeholder="请选择产品品牌" input-align="right" /></u-form-item>
 				<u-form-item label="产品分类"><u-input v-model="productTypeNameArr" @click="showTypeModal=true" clearable @clear="typeClean" type="select" placeholder="请选择产品分类" input-align="right" /></u-form-item>
 				<u-form-item label="滞销天数">
-					<u-input type="number" :min="0" :max="999999" v-model.trim="form.minUnsalableDays" placeholder="起始天数" input-align="left" />
+					<u-input type="number" :min="0" :max="999999" v-model.trim="form.minUnsalableDays" placeholder="起始天数" input-align="center" />
 					<text style="display: block;text-align: center;line-height: 32px;">至</text>
-					<u-input type="number" :min="0" :max="999999" v-model.trim="form.maxUnsalableDays" placeholder="截止天数" input-align="right" />
+					<u-input type="number" :min="0" :max="999999" v-model.trim="form.maxUnsalableDays" placeholder="截止天数" input-align="center" />
 				</u-form-item>
-				<u-form-item label="只查看有库存"><u-switch slot="right" v-model="form.zeroQtyFlag"></u-switch></u-form-item>
-				<u-form-item label="包括禁用产品"><u-switch slot="right" v-model="form.enableFlag"></u-switch></u-form-item>
+				<u-form-item label="只查看有库存" inputAlign="right"><u-switch slot="right" v-model="form.zeroQtyFlag"></u-switch></u-form-item>
+				<u-form-item label="包括禁用产品" inputAlign="right"><u-switch slot="right" v-model="form.enableFlag"></u-switch></u-form-item>
 			</u-form>
 			<view class="form-footer-btn">
 				<u-button size="medium" shape="circle" hover-class="none" @click="handleClean">清空</u-button>
@@ -208,13 +208,13 @@
 <style lang="scss">
 	.stock-wrap{
 		width: 100%;
-		padding: 30upx;
+		padding: 0 30upx 30upx;
 		.panel-box {
 			background-color: #ffffff;
 			padding: 20upx 20upx;
 			border-radius: 20upx;
-			box-shadow: 3upx 2upx 6upx #eee;
-			margin-bottom: 30upx;
+			box-shadow: 0 0 6upx #eee;
+			margin-bottom: 20upx;
 			.item-box{
 				text-align: center;
 				display: flex;
@@ -225,7 +225,7 @@
 		.stock-con{
 			background-color: #ffffff;
 			border-radius: 20upx;
-			box-shadow: 3upx 2upx 6upx #eee;
+			box-shadow: 0 0 6upx #eee;
 			padding: 20upx;
 			.stock-tit{
 				font-weight: bold;

+ 1 - 1
pages/stock/stockDetail.vue

@@ -54,7 +54,7 @@
 			}
 		},
 		onLoad(option) {
-			this.theme = getApp().globalData.theme
+			this.theme = getApp({ allowDefault: true }).globalData.theme
 			this.productData = option.productData ? JSON.parse(option.productData) : null
 			this.paramsData = option.data ? JSON.parse(option.data) : null
 		},

+ 4 - 4
pages/stock/stockSearch.vue

@@ -19,7 +19,7 @@
 		<scroll-view class="stockSearch-con" scroll-y @scrolltolower="onreachBottom">
 			<view class="stockSearch-main">
 				<view class="stockSearch-main-item" v-for="(item, index) in listData" :key="item.id" @click.stop="getDetail(item)">
-					<view class="stockSearch-tit flex">
+					<view class="stockSearch-tit flex align_center">
 						<view class="u-line" :style="{backgroundColor: $config('primaryColor')}"></view>
 						<view class="u-name">
 							{{item.productName}}
@@ -88,7 +88,7 @@
 			}
 		},
 		onLoad(option) {
-			this.theme = getApp().globalData.theme
+			this.theme = getApp({ allowDefault: true }).globalData.theme
 			this.params = option.data ? JSON.parse(option.data) : {}
 			this.getList()
 		},
@@ -207,7 +207,7 @@
 					padding: 20upx;
 					margin: 25upx;
 					border-radius: 20upx;
-					box-shadow: 1px 1px 3px #EEEEEE;
+					box-shadow: 0 0 3px #EEEEEE;
 					&:first-child{
 						margin-top: 0;
 					}
@@ -222,7 +222,7 @@
 							display: inline-block;
 							width: 6upx;
 							height: 30upx;
-							margin: 6upx 10upx 0 10upx;
+							margin: 0 10upx;
 							border-radius: 5upx;
 						}
 						.u-name{

+ 1 - 1
pages/stock/warehouseDetail.vue

@@ -89,7 +89,7 @@
 			}
 		},
 		onLoad(option) {
-			this.theme = getApp().globalData.theme
+			this.theme = getApp({ allowDefault: true }).globalData.theme
 			this.productData = option.productData ? JSON.parse(option.productData) : null
 			this.paramsData = option.data ? JSON.parse(option.data) : null
 		},

+ 1 - 1
pages/userCenter/changePwd.vue

@@ -171,7 +171,7 @@
 			position: relative;
 			bottom: 10rpx;
 		}
-		/deep/ .m-input-view{
+		::v-deep .m-input-view{
 			margin-top: 0;
 		}
 		.form-footer-btn{

+ 7 - 12
pages/userCenter/index.vue

@@ -46,7 +46,7 @@
 		<!-- <u-action-sheet :list="orglist" v-model="show" @click="changeAcount" :tips="tips" :cancel-btn="true"></u-action-sheet> -->
 	</view>
 </template>
-
+ 
 <script>
 	import { getUserInfo, logout, login, getUnreadCount, logoff } from '@/api/user.js'
 	import { getSysVersion } from '@/api/data.js'
@@ -98,7 +98,7 @@
 				backgroundColor: this.$config('primaryColor')
 			})
 			this.isRemember = this.$store.state.vuex_isRemember;
-			this.curVer = getApp().globalData.version;
+			this.curVer = getApp({ allowDefault: true }).globalData.version;
 		},
 		methods:{
 			// 未读消息
@@ -134,7 +134,7 @@
 			changeAcount(item){
 				const _this = this
 				_this.$store.state.vuex_changeOrg = item[0].value
-				_this.$set(getApp().globalData,'changeOrg',item[0].value)
+				_this.$set(getApp({ allowDefault: true }).globalData,'changeOrg',item[0].value)
 				setTimeout(()=>{
 					//  登录
 					login({ username: '', password: '' }).then(res => {
@@ -144,7 +144,7 @@
 							_this.$u.vuex('vuex_userData', _this.fiterAuthCode(res.data.auth_user));
 							_this.$u.vuex('vuex_token', res.data.access_token);
 							_this.$u.vuex('vuex_authOrgs',res.data.auth_orgs);
-							getApp().globalData.token = res.data.access_token;
+							getApp({ allowDefault: true }).globalData.token = res.data.access_token;
 							uni.setStorageSync('loginTimeOut', 'NO');
 							this.toMain()
 							uni.$emit("refreshSalesHomeBL")
@@ -214,12 +214,12 @@
 			},
 			toLogin(){
 				// this.$store.commit("$closeWebsocket")
-				this.$set(getApp().globalData,'changeOrg','')
+				this.$set(getApp({ allowDefault: true }).globalData,'changeOrg','')
 				uni.setStorageSync('setStatusIndexFunc', 0);
 				this.$u.vuex('vuex_userData', '');
 				this.$u.vuex('vuex_token', '');
 				this.$u.vuex('vuex_authOrgs','');
-				getApp().globalData.token = '';
+				getApp({ allowDefault: true }).globalData.token = '';
 				this.$u.vuex('vuex_tempData', '');
 				setTimeout(function() {
 					uni.reLaunch({
@@ -229,7 +229,7 @@
 			},
 			// 获取最新版本信息
 			getVersion() {
-				let version = getApp().globalData.version
+				let version = getApp({ allowDefault: true }).globalData.version
 				console.log(version)
 				getSysVersion({versionType:version.platform=='android'?'ANDROID':'IOS', applyCode: 'jgqp'}).then(ret => {
 					console.log(ret)
@@ -294,9 +294,4 @@
 			padding: 85rpx 200rpx;
 		}
 	}
-	/deep/.u-select__header__title{
-		color:#999 !important;
-		font-size: 32upx;
-		font-weight: bold;
-	}
 </style>

+ 1 - 1
pages/userCenter/setData.vue

@@ -161,7 +161,7 @@ export default {
 		.u-cell {
 			padding: 14rpx 26rpx;
 			color: #333;
-			/deep/.u-cell_right {
+			::v-deep .u-cell_right {
 				max-width: 40% !important;
 			}
 		}

+ 1 - 1
pages/vinAnalyse/fitProductlist.vue

@@ -111,7 +111,7 @@ export default {
 		};
 	},
 	onLoad(options) {
-		this.theme = getApp().globalData.theme;
+		this.theme = getApp({ allowDefault: true }).globalData.theme;
 		this.shelfSn = options.shelfSn;
 		this.shelfName = options.shelfName;
 		let ajaxData = {

+ 2 - 2
pages/vinAnalyse/shelfAnalyse.vue

@@ -183,7 +183,7 @@ export default {
 		}
 	},
 	onLoad(option) {
-		this.theme = getApp().globalData.theme;
+		this.theme = getApp({ allowDefault: true }).globalData.theme;
 		this.shelfSn = option.shelfSn;
 		this.shelfName = option.shelfName;
 		let ajaxData = {
@@ -479,7 +479,7 @@ export default {
 			.emptyStyle{
 				align-items: center !important;
 				margin:160rpx auto 0;
-				/deep/.u-empty{
+				::v-deep .u-empty{
 					justify-content:flex-start !important;
 				}
 			} 

+ 1 - 1
pages/webviews/openview.vue

@@ -39,7 +39,7 @@
 				})
 				this.wv.setStyle({ height:uni.getSystemInfoSync().windowHeight})
 				this.wv.loadURL(url)
-				var currentWebview = this.$mp.page.$getAppWebview() //获取当前页面的webview对象
+				var currentWebview = this.$scope.$getAppWebview() //获取当前页面的webview对象
 				currentWebview.append(this.wv);//一定要append到当前的页面里!!!才能跟随当前页面一起做动画,一起关闭
 				setTimeout(()=>{this.wv.getStyle()}, 1000);//如果是首页的onload调用时需要延时一下,二级页面无需延时,可直接获取
 				// #endif

+ 1 - 5
pages/xtNotice/xtNoticeDetail/xtNoticeDetail.vue

@@ -6,7 +6,7 @@
 				<view class="messageTime">{{detailsData.releaseDate}} 发布</view>
 			</view>
 			<view class="messageContent" v-if="detailsData.type!='tx'">
-			  <jyf-parser :html="detailsData.content" ref="article"></jyf-parser>
+			  <mp-html :content="detailsData.content" />
 			  <view class="msgFujian">
 				  <view v-if="detailsData.imgPaths&&detailsData.imgPaths.length">
 					  <view class="tits">图片:</view>
@@ -35,12 +35,8 @@
 </template>
 
 <script>
-	import jyfParser from "@/components/jyf-parser/jyf-parser"
 	import {noticeUserDetail} from "@/api/user.js"
 	export default{
-		components: {
-		    jyfParser
-		},
 		data(){
 			return{
 				itemId: null,

+ 1 - 1
store/$u.mixin.js

@@ -9,7 +9,7 @@ try{
 	
 }
 
-module.exports = {
+export default {
 	created() {
 		// 将vuex方法挂在到$u中
 		// 使用方法为:如果要修改vuex的state中的user.name变量为"史诗" => this.$u.vuex('user.name', '史诗')

+ 8 - 6
store/index.js

@@ -1,7 +1,4 @@
-import Vue from 'vue'
-import Vuex from 'vuex'
-Vue.use(Vuex)
-
+import { createStore } from "vuex";
 let lifeData = {}
 
 try {
@@ -20,6 +17,7 @@ let saveStateKeys = [
 	'vuex_isRemember',
 	'vuex_isUsrAuthYs',
 	'vuex_versionInfo',
+	'vuex_theme'
 ];
 
 // 保存变量到本地存储中
@@ -83,7 +81,7 @@ const SocketInit = function($store,state,wsUrl){
 }
 
 // store 对象
-const store = new Vuex.Store({
+const store = createStore({
 	// 下面这些值仅为示例,使用过程中请删除
 	state: {
 		// 如果上面从本地获取的lifeData对象下有对应的属性,就赋值给state中对应的变量
@@ -95,6 +93,10 @@ const store = new Vuex.Store({
 		vuex_isRemember: lifeData.vuex_isRemember ? lifeData.vuex_isRemember : true,
 		vuex_isUsrAuthYs: lifeData.vuex_isUsrAuthYs ? lifeData.vuex_isUsrAuthYs : false,
 		vuex_versionInfo: lifeData.vuex_versionInfo ? lifeData.vuex_versionInfo : {}, // 版本信息
+		vuex_theme: lifeData.vuex_theme ? lifeData.vuex_theme : 'default', // 主题
+		vuex_envTips:'', // 环境提示
+		vuex_baseUrl: '', // 基础地址
+		vuex_buildType: 'dev', // 构建类型
 		vuex_changeOrg: null, // 要切换的org
 		vuex_socket: null, // 消息通知ws对象
 		vuex_wsMessageData: null, // 消息对象
@@ -143,7 +145,7 @@ const store = new Vuex.Store({
 		$webSocket(state, params) {
 			let _this = this
 			let userInfo = state.vuex_userData
-			let url = getApp().globalData.baseUrl
+			let url = getApp({ allowDefault: true }).globalData.baseUrl
 			let wsBaseUrl = url.indexOf("https:")>=0 ? url.replace("https:","wss:") : url.replace("http:","ws:")
 			let wsUrl = wsBaseUrl + 'websocket/app/' + 's' + userInfo.parentOrgId + 'o' + userInfo.orgId + 'u' + userInfo.userid + 'eapp'
 			SocketInit(_this,state,wsUrl)

+ 13 - 0
uni.promisify.adaptor.js

@@ -0,0 +1,13 @@
+uni.addInterceptor({
+  returnValue (res) {
+    if (!(!!res && (typeof res === "object" || typeof res === "function") && typeof res.then === "function")) {
+      return res;
+    }
+    return new Promise((resolve, reject) => {
+      res.then((res) => {
+        if (!res) return resolve(res) 
+        return res[0] ? reject(res[0]) : resolve(res[1])
+      });
+    });
+  },
+});

+ 199 - 35
uni.scss

@@ -1,4 +1,5 @@
-@import 'uview-ui/theme.scss';
+@import "@/uni_modules/vk-uview-ui/theme.scss";
+@import "@/uni_modules/vk-uview-ui/index.scss";
 /**
  * 这里是uni-app内置的常用样式变量
  *
@@ -40,55 +41,218 @@ $uni-border-color:#c8c7cc;
 /* 尺寸变量 */
 
 /* 文字尺寸 */
-$uni-font-size-sm:24rpx;
-$uni-font-size-base:28rpx;
-$uni-font-size-lg:32rpx;
+$uni-font-size-sm:12px;
+$uni-font-size-base:14px;
+$uni-font-size-lg:16px;
 
 /* 图片尺寸 */
-$uni-img-size-sm:40rpx;
-$uni-img-size-base:52rpx;
-$uni-img-size-lg:80rpx;
+$uni-img-size-sm:20px;
+$uni-img-size-base:26px;
+$uni-img-size-lg:40px;
 
 /* Border Radius */
-$uni-border-radius-sm: 4rpx;
-$uni-border-radius-base: 6rpx;
-$uni-border-radius-lg: 12rpx;
+$uni-border-radius-sm: 2px;
+$uni-border-radius-base: 3px;
+$uni-border-radius-lg: 6px;
 $uni-border-radius-circle: 50%;
 
 /* 水平间距 */
-$uni-spacing-row-sm: 10px;
-$uni-spacing-row-base: 20rpx;
-$uni-spacing-row-lg: 30rpx;
+$uni-spacing-row-sm: 5px;
+$uni-spacing-row-base: 10px;
+$uni-spacing-row-lg: 15px;
 
 /* 垂直间距 */
-$uni-spacing-col-sm: 8rpx;
-$uni-spacing-col-base: 16rpx;
-$uni-spacing-col-lg: 24rpx;
+$uni-spacing-col-sm: 4px;
+$uni-spacing-col-base: 8px;
+$uni-spacing-col-lg: 12px;
 
 /* 透明度 */
 $uni-opacity-disabled: 0.3; // 组件禁用态的透明度
 
 /* 文章场景相关 */
 $uni-color-title: #2C405A; // 文章标题颜色
-$uni-font-size-title:40rpx;
+$uni-font-size-title:20px;
 $uni-color-subtitle: #555555; // 二级标题颜色
-$uni-font-size-subtitle:36rpx;
+$uni-font-size-subtitle:26px;
 $uni-color-paragraph: #3F536E; // 文章段落颜色
-$uni-font-size-paragraph:30rpx;
-
-/* 显示一行省略号 */
-.ellipsis-one{
-	white-space: nowrap;
-	text-overflow: ellipsis;
-	overflow: hidden;
-	word-break: break-all;
-}
-/* 显示两行,省略号 */
-.ellipsis-two{
-	overflow: hidden;
-	text-overflow: ellipsis;
-	display: -webkit-box;
-	-webkit-line-clamp: 2;
-	line-clamp: 2;
-	-webkit-box-orient: vertical;
+$uni-font-size-paragraph:15px;
+
+
+/* 登录页是否记住密码多选框样式 */
+uni-checkbox.login-form-checkbox .uni-checkbox-input{
+width: 24upx !important;
+height: 24upx !important;
+}
+.status_bar {
+  height: var(--status-bar-height);
+  width: 100%;
+}
+.isIPXup{
+padding-bottom: 64rpx !important;
+}
+/*  form表单样式 */
+.form-box{
+background-color: #fff;
+padding: 0 30rpx;
+}
+.form-input {
+font-size: 28rpx;
+color: #333;
+text-align: right;
+width: 95%;
+box-sizing: border-box;
+height: 60rpx;
+line-height: 60rpx;
+&.textarea{
+	height: 240rpx;
+	padding: 24rpx 0;
+	text-align: left;
+}
+}
+
+.form-input-placeholder {
+font-size: 28rpx;
+color: #999;
+}
+.form-textarea{
+height: 240rpx;
+padding: 24rpx 0;
+text-align: left;
+}
+.form-number-input{
+margin: 0 auto;
+}
+.u-required{
+position: relative;
+}
+.u-required:before{
+content: '*';
+position: absolute;
+left: -8px;
+top: 10upx;
+font-size: 14px;
+color: #fa3534;
+height: 9px;
+line-height: 1;
+}
+/* 元素宽度 百分比 */
+.uni-col-1{
+box-sizing: border-box;
+width: 10%;
+}
+.uni-col-2{
+box-sizing: border-box;
+width: 20%;
+}
+.uni-col-3{
+box-sizing: border-box;
+width: 30%;
+}
+.uni-col-4{
+box-sizing: border-box;
+width: 40%;
+}
+.uni-col-5{
+box-sizing: border-box;
+width: 50%;
+}
+.uni-col-6{
+box-sizing: border-box;
+width: 60%;
+}
+.uni-col-7{
+box-sizing: border-box;
+width: 70%;
+}
+.uni-col-8{
+box-sizing: border-box;
+width: 80%;
+}
+.uni-col-9{
+box-sizing: border-box;
+width: 90%;
+}
+.uni-col-10{
+box-sizing: border-box;
+width: 100%;
+}
+
+/* felx布局 */
+.flex{
+display: -webkit-flex; /* Chrome 21+, Safari 6.1+, iOS Safari 7+, Opera 15/16 */  
+display: -moz-flex; /* Firefox 18+ */  
+display: -ms-flexbox; /* IE 10 */  
+display: flex; /* Chrome 29+, Firefox 22+, IE 11+, Opera 12.1/17/18, Android 4.4+ */
+}
+/*伸缩流方向*/
+.flex_column{
+-webkit-box-orient: vertical;
+-ms-flex-direction: column;
+-webkit-flex-direction: column;
+flex-direction: column;
+}
+/*主轴对齐*/
+.justify_center{
+-webkit-box-pack: center;
+-ms-flex-pack: center;
+-webkit-justify-content: center;
+justify-content: center;
+}
+.justify_end{
+-webkit-box-pack: end;
+-ms-flex-pack: end;
+-webkit-justify-content: flex-end;
+justify-content: flex-end;
+}
+.justify_between{
+-webkit-box-pack: justify;
+-ms-flex-pack: justify;
+-webkit-justify-content: space-between;
+justify-content: space-between;
+}
+/*侧轴对齐*/
+.align_start{
+-webkit-box-align: start;
+-ms-flex-align: start;
+-webkit-align-items: flex-start;
+align-items: flex-start;
+}
+.align_end{
+-webkit-box-align: end;
+-ms-flex-align: end;
+-webkit-align-items: flex-end;
+align-items: flex-end;
+}
+.align_center{
+-webkit-box-align: center;
+-ms-flex-align: center;
+-webkit-align-items: center;
+align-items: center;
+}
+.align_baseline{
+-webkit-box-align: baseline;
+-ms-flex-align: baseline;
+-webkit-align-items: baseline;
+align-items: baseline;
+}
+/*伸缩性*/
+.flex_auto{
+-webkit-box-flex: 1;
+-ms-flex: auto;
+-webkit-flex: auto;
+flex: auto;
+}
+.flex_1{
+-webkit-box-flex: 1;
+-ms-flex: 1;
+-webkit-flex: 1;
+flex: 1;    
+}
+// ios15原生input的type=search时会默认自带搜索图标。
+// 在全局的公共样式隐藏ios自带搜索图标即可
+[type="search"]::-webkit-search-decoration {
+display: none;
+}
+uni-toast {
+z-index: 1000000;
 }

+ 194 - 0
uni_modules/mp-html/README.md

@@ -0,0 +1,194 @@
+## 为减小组件包的大小,默认组件包中不包含编辑、latex 公式等扩展功能,需要使用扩展功能的请参考下方的 插件扩展 栏的说明
+
+## 功能介绍
+- 全端支持(含 `v3、NVUE`)
+- 支持丰富的标签(包括 `table`、`video`、`svg` 等)
+- 支持丰富的事件效果(自动预览图片、链接处理等)
+- 支持设置占位图(加载中、出错时、预览时)
+- 支持锚点跳转、长按复制等丰富功能
+- 支持大部分 *html* 实体
+- 丰富的插件(关键词搜索、内容编辑、`latex` 公式等)
+- 效率高、容错性强且轻量化
+
+查看 [功能介绍](https://jin-yufeng.gitee.io/mp-html/#/overview/feature) 了解更多
+
+## 使用方法
+- `uni_modules` 方式  
+  1. 点击右上角的 `使用 HBuilder X 导入插件` 按钮直接导入项目或点击 `下载插件 ZIP` 按钮下载插件包并解压到项目的 `uni_modules/mp-html` 目录下  
+  2. 在需要使用页面的 `(n)vue` 文件中添加  
+     ```html
+     <!-- 不需要引入,可直接使用 -->
+     <mp-html :content="html" />
+     ```
+     ```javascript
+     export default {
+       data() {
+         return {
+           html: '<div>Hello World!</div>'
+         }
+       }
+     }
+     ```
+  3. 需要更新版本时在 `HBuilder X` 中右键 `uni_modules/mp-html` 目录选择 `从插件市场更新` 即可  
+
+- 源码方式  
+  1. 从 [github](https://github.com/jin-yufeng/mp-html/tree/master/dist/uni-app) 或 [gitee](https://gitee.com/jin-yufeng/mp-html/tree/master/dist/uni-app) 下载源码  
+     插件市场的 **非 uni_modules 版本** 无法更新,不建议从插件市场获取  
+  2. 在需要使用页面的 `(n)vue` 文件中添加  
+     ```html
+     <mp-html :content="html" />
+     ```
+     ```javascript
+     import mpHtml from '@/components/mp-html/mp-html'
+     export default {
+       // HBuilderX 2.5.5+ 可以通过 easycom 自动引入
+       components: {
+         mpHtml
+       },
+       data() {
+         return {
+           html: '<div>Hello World!</div>'
+         }
+       }
+     }
+     ```
+
+- npm 方式  
+  1. 在项目根目录下执行  
+     ```bash
+     npm install mp-html
+     ```
+  2. 在需要使用页面的 `(n)vue` 文件中添加  
+     ```html
+     <mp-html :content="html" />
+     ```
+     ```javascript
+     import mpHtml from 'mp-html/dist/uni-app/components/mp-html/mp-html'
+     export default {
+       // 不可省略
+       components: {
+         mpHtml
+       },
+       data() {
+         return {
+           html: '<div>Hello World!</div>'
+         }
+       }
+     }
+     ```
+  3. 需要更新版本时执行以下命令即可  
+     ```bash
+     npm update mp-html
+     ```
+  
+  使用 *cli* 方式运行的项目,通过 *npm* 方式引入时,需要在 *vue.config.js* 中配置 *transpileDependencies*,详情可见 [#330](https://github.com/jin-yufeng/mp-html/issues/330#issuecomment-913617687)  
+  如果在 **nvue** 中使用还要将 `dist/uni-app/static` 目录下的内容拷贝到项目的 `static` 目录下,否则无法运行  
+
+查看 [快速开始](https://jin-yufeng.gitee.io/mp-html/#/overview/quickstart) 了解更多
+
+## 组件属性
+
+| 属性 | 类型 | 默认值 | 说明 |
+|:---:|:---:|:---:|---|
+| container-style | String |  | 容器的样式([2.1.0+](https://jin-yufeng.gitee.io/mp-html/#/changelog/changelog#v210)) |
+| content | String |  | 用于渲染的 html 字符串 |
+| copy-link | Boolean | true | 是否允许外部链接被点击时自动复制 |
+| domain | String |  | 主域名(用于链接拼接) |
+| error-img | String |  | 图片出错时的占位图链接 |
+| lazy-load | Boolean | false | 是否开启图片懒加载 |
+| loading-img | String |  | 图片加载过程中的占位图链接 |
+| pause-video | Boolean | true | 是否在播放一个视频时自动暂停其他视频 |
+| preview-img | Boolean | true | 是否允许图片被点击时自动预览 |
+| scroll-table | Boolean | false | 是否给每个表格添加一个滚动层使其能单独横向滚动 |
+| selectable | Boolean | false | 是否开启文本长按复制 |
+| set-title | Boolean | true | 是否将 title 标签的内容设置到页面标题 |
+| show-img-menu | Boolean | true | 是否允许图片被长按时显示菜单 |
+| tag-style | Object |  | 设置标签的默认样式 |
+| use-anchor | Boolean | false | 是否使用锚点链接 |
+
+查看 [属性](https://jin-yufeng.gitee.io/mp-html/#/basic/prop) 了解更多
+
+## 组件事件
+
+| 名称 | 触发时机 |
+|:---:|---|
+| load | dom 树加载完毕时 |
+| ready | 图片加载完毕时 |
+| error | 发生渲染错误时 |
+| imgtap | 图片被点击时 |
+| linktap | 链接被点击时 |
+| play | 音视频播放时 |
+
+查看 [事件](https://jin-yufeng.gitee.io/mp-html/#/basic/event) 了解更多
+
+## api
+组件实例上提供了一些 `api` 方法可供调用
+
+| 名称 | 作用 |
+|:---:|---|
+| in | 将锚点跳转的范围限定在一个 scroll-view 内 |
+| navigateTo | 锚点跳转 |
+| getText | 获取文本内容 |
+| getRect | 获取富文本内容的位置和大小 |
+| setContent | 设置富文本内容 |
+| imgList | 获取所有图片的数组 |
+| pauseMedia | 暂停播放音视频([2.2.2+](https://jin-yufeng.gitee.io/mp-html/#/changelog/changelog#v222)) |
+| setPlaybackRate | 设置音视频播放速率([2.4.0+](https://jin-yufeng.gitee.io/mp-html/#/changelog/changelog#v240)) |
+
+查看 [api](https://jin-yufeng.gitee.io/mp-html/#/advanced/api) 了解更多
+
+## 插件扩展  
+除基本功能外,本组件还提供了丰富的扩展,可按照需要选用
+
+| 名称 | 作用 |
+|:---:|---|
+| audio | 音乐播放器 |
+| editable | 富文本 **编辑**([示例项目](https://mp-html.oss-cn-hangzhou.aliyuncs.com/editable.zip)) |
+| emoji | 解析 emoji |
+| highlight | 代码块高亮显示 |
+| markdown | 渲染 markdown |
+| search | 关键词搜索 |
+| style | 匹配 style 标签中的样式 |
+| txv-video | 使用腾讯视频 |
+| img-cache | 图片缓存 by [@PentaTea](https://github.com/PentaTea) |
+| latex | 渲染 latex 公式 by [@Zeng-J](https://github.com/Zeng-J) |
+
+从插件市场导入的包中 **不含有** 扩展插件,使用插件需通过微信小程序 `富文本插件` 获取或参考以下方法进行打包:  
+1. 获取完整组件包  
+   ```bash
+   npm install mp-html
+   ```
+2. 编辑 `tools/config.js` 中的 `plugins` 项,选择需要的插件  
+3. 生成新的组件包  
+   在 `node_modules/mp-html` 目录下执行  
+   ```bash
+   npm install
+   npm run build:uni-app
+   ```
+4. 拷贝 `dist/uni-app` 中的内容到项目根目录  
+
+查看 [插件](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin) 了解更多
+
+## 关于 nvue
+`nvue` 使用原生渲染,不支持部分 `css` 样式,为实现和 `html` 相同的效果,组件内部通过 `web-view` 进行渲染,性能上差于原生,根据 `weex` 官方建议,`web` 标签仅应用在非常规的降级场景。因此,如果通过原生的方式(如 `richtext`)能够满足需要,则不建议使用本组件,如果有较多的富文本内容,则可以直接使用 `vue` 页面  
+由于渲染方式与其他端不同,有以下限制:  
+1. 不支持 `lazy-load` 属性
+2. 视频不支持全屏播放
+3. 如果在 `flex-direction: row` 的容器中使用,需要给组件设置宽度或设置 `flex: 1` 占满剩余宽度
+
+纯 `nvue` 模式下,[此问题](https://ask.dcloud.net.cn/question/119678) 修复前,不支持通过 `uni_modules` 引入,需要本地引入(将 [dist/uni-app](https://github.com/jin-yufeng/mp-html/tree/master/dist/uni-app) 中的内容拷贝到项目根目录下)  
+
+## 立即体验
+![富文本插件](https://mp-html.oss-cn-hangzhou.aliyuncs.com/qrcode.jpg)
+
+## 问题反馈
+遇到问题时,请先查阅 [常见问题](https://jin-yufeng.gitee.io/mp-html/#/question/faq) 和 [issue](https://github.com/jin-yufeng/mp-html/issues) 中是否已有相同的问题  
+可通过 [issue](https://github.com/jin-yufeng/mp-html/issues/new/choose) 、插件问答或发送邮件到 [mp_html@126.com](mailto:mp_html@126.com) 提问,不建议在评论区提问(不方便回复)  
+提问请严格按照 [issue 模板](https://github.com/jin-yufeng/mp-html/issues/new/choose) ,描述清楚使用环境、`html` 内容或可复现的 `demo` 项目以及复现方式,对于 **描述不清**、**无法复现** 或重复的问题将不予回复  
+
+欢迎加入 `QQ` 交流群:  
+群1(已满):`699734691`  
+群2(已满):`778239129`  
+群3:`960265313`  
+
+查看 [问题反馈](https://jin-yufeng.gitee.io/mp-html/#/question/feedback) 了解更多

+ 150 - 0
uni_modules/mp-html/changelog.md

@@ -0,0 +1,150 @@
+## v2.5.0(2024-04-22)
+1. `U` `play` 事件增加返回 `src` 等信息 [详细](https://github.com/jin-yufeng/mp-html/issues/526)
+2. `U` `preview-img` 属性支持设置为 `all` 开启 `base64` 图片预览 [详细](https://github.com/jin-yufeng/mp-html/issues/536)
+3. `U` `editable` 插件增加简易模式(点击文字直接编辑)
+4. `U` `latex` 插件支持块级公式 [详细](https://github.com/jin-yufeng/mp-html/issues/582)
+5. `F` 修复了表格部分情况下背景丢失的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/587)
+6. `F` 修复了部分 `svg` 无法显示的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/591)
+7. `F` 修复了 `h5` 和 `app` 端部分情况下样式无法识别的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/518)
+8. `F` 修复了 `latex` 插件部分情况下显示不正确的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/580)
+9. `F` 修复了 `editable` 插件表格无法删除的问题
+10. `F` 修复了 `editable` 插件 `vue3` `h5` 端点击图片报错的问题
+11. `F` 修复了 `editable` 插件点击表格没有菜单栏的问题
+## v2.4.3(2024-01-21)
+1. `A` 增加 [card](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#card) 插件 [详细](https://github.com/jin-yufeng/mp-html/pull/533) by [@whoooami](https://github.com/whoooami)
+2. `F` 修复了 `svg` 中包含 `foreignobject` 可能不显示的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/523)
+3. `F` 修复了合并单元格的表格部分情况下显示不正确的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/561)
+4. `F` 修复了 `img` 标签设置 `object-fit` 无效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/567)
+5. `F` 修复了 `latex` 插件公式会换行的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/540) 
+6. `F` 修复了 `editable` 和 `audio` 插件共用时点击 `audio` 无法编辑的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/529) by [@whoooami](https://github.com/whoooami)
+7. `F` 修复了微信小程序部分情况下图片会报错 `replace of undefined` 的问题
+8. `F` 修复了快手小程序图片不显示的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/571)
+## v2.4.2(2023-05-14)
+1. `A` `editable` 插件支持修改文字颜色 [详细](https://github.com/jin-yufeng/mp-html/issues/254)
+2. `F` 修复了 `svg` 中有 `style` 不生效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/505)
+3. `F` 修复了使用旧版编译器可能报错 `Bad attr nodes` 的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/472)
+4. `F` 修复了 `app` 端可能出现无法读取 `lazyLoad` 的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/513)
+5. `F` 修复了 `editable` 插件在点击换图时未拼接 `domain` 的问题 [详细](https://github.com/jin-yufeng/mp-html/pull/497) by [@TwoKe945](https://github.com/TwoKe945)
+6. `F` 修复了 `latex` 插件部分情况下不显示的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/515) 
+7. `F` 修复了 `editable` 插件点击音视频时其他标签框不消失的问题
+## v2.4.1(2022-12-25)
+1. `F` 修复了没有图片时 `ready` 事件可能不触发的问题
+2. `F` 修复了加载过程中可能出现 `Root label not found` 错误的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/470)
+3. `F` 修复了 `audio` 插件退出页面可能会报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/457)
+4. `F` 修复了 `vue3` 运行到 `app` 在 `HBuilder X 3.6.10` 以上报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/480)
+5. `F` 修复了 `nvue` 端链接中包含 `%22` 时可能无法显示的问题
+6. `F` 修复了 `vue3` 使用 `highlight` 插件可能报错的问题
+## v2.4.0(2022-08-27)
+1. `A` 增加了 [setPlaybackRate](https://jin-yufeng.gitee.io/mp-html/#/advanced/api#setPlaybackRate) 的 `api`,可以设置音视频的播放速率 [详细](https://github.com/jin-yufeng/mp-html/issues/452)
+2. `A` 示例小程序代码开源 [详细](https://github.com/jin-yufeng/mp-html-demo)
+3. `U` 优化 `ready` 事件触发时机,未设置懒加载的情况下基本可以准确触发 [详细](https://github.com/jin-yufeng/mp-html/issues/195)
+4. `U` `highlight` 插件在编辑状态下不进行高亮处理,便于编辑
+5. `F` 修复了 `flex` 布局下图片大小可能不正确的问题
+6. `F` 修复了 `selectable` 属性没有设置 `force` 也可能出现渲染异常的问题
+7. `F` 修复了表格中的图片大小可能不正确的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/448)
+8. `F` 修复了含有合并单元格的表格可能无法设置竖直对齐的问题
+9. `F` 修复了 `editable` 插件在 `scroll-view` 中使用时工具条位置可能不正确的问题
+10. `F` 修复了 `vue3` 使用 [search](advanced/plugin#search) 插件可能导致错误换行的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/449)
+## v2.3.2(2022-08-13)
+1. `A` 增加 [latex](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#latex) 插件,可以渲染数学公式 [详细](https://github.com/jin-yufeng/mp-html/pull/447) by [@Zeng-J](https://github.com/Zeng-J)
+2. `U` 优化根节点下有很多标签的长内容渲染速度
+3. `U` `highlight` 插件适配 `lang-xxx` 格式
+4. `F` 修复了 `table` 标签设置 `border` 属性后可能无法修改边框样式的问题 [详细](https://github.com/jin-yufeng/mp-html/pull/439) by [@zouxingjie](https://github.com/zouxingjie)
+5. `F` 修复了 `editable` 插件输入连续空格无效的问题
+6. `F` 修复了 `vue3` 图片设置 `inline` 会报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/438)
+7. `F` 修复了 `vue3` 使用 `table` 可能报错的问题
+## v2.3.1(2022-05-20)
+1. `U` `app` 端支持使用本地图片
+2. `U` 优化了微信小程序 `selectable` 属性在 `ios` 端的处理 [详细](https://jin-yufeng.gitee.io/mp-html/#/basic/prop#selectable)
+3. `F` 修复了 `editable` 插件不在顶部时 `tooltip` 位置可能错误的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/430)
+4. `F` 修复了 `vue3` 运行到微信小程序可能报错丢失内容的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/414)
+5. `F` 修复了 `vue3` 部分标签可能被错误换行的问题
+6. `F` 修复了 `editable` 插件 `app` 端插入视频无法预览的问题
+## v2.3.0(2022-04-01)
+1. `A` 增加了 `play` 事件,音视频播放时触发,可用于与页面其他音视频进行互斥播放 [详细](basic/event#play)
+2. `U` `show-img-menu` 属性支持控制预览时是否长按弹出菜单
+3. `U` 优化 `wxs` 处理,提高渲染性能 [详细](https://developers.weixin.qq.com/community/develop/article/doc/0006cc2b204740f601bd43fa25a413)  
+4. `U` `video` 标签支持 `object-fit` 属性
+5. `U` 增加支持一些常用实体编码 [详细](https://github.com/jin-yufeng/mp-html/issues/418)
+6. `F` 修复了图片仅设置高度可能不显示的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/410)
+7. `F` 修复了 `video` 标签高度设置为 `auto` 不显示的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/411)
+8. `F` 修复了使用 `grid` 布局时可能样式错误的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/413)
+9. `F` 修复了含有合并单元格的表格部分情况下显示异常的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/417)
+10. `F` 修复了 `editable` 插件连续插入内容时顺序不正确的问题
+11. `F` 修复了 `uni-app` 包 `vue3` 使用 `audio` 插件报错的问题
+12. `F` 修复了 `uni-app` 包 `highlight` 插件使用自定义的 `prism.min.js` 报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/416)
+## v2.2.2(2022-02-26)
+1. `A` 增加了 [pauseMedia](https://jin-yufeng.gitee.io/mp-html/#/advanced/api#pauseMedia) 的 `api`,可用于暂停播放音视频 [详细](https://github.com/jin-yufeng/mp-html/issues/317)
+2. `U` 优化了长内容的加载速度  
+3. `U` 适配 `vue3` [#389](https://github.com/jin-yufeng/mp-html/issues/389)、[#398](https://github.com/jin-yufeng/mp-html/pull/398) by [@zhouhuafei](https://github.com/zhouhuafei)、[#400](https://github.com/jin-yufeng/mp-html/issues/400)
+4. `F` 修复了小程序端图片高度设置为百分比时可能不显示的问题
+5. `F` 修复了 `highlight` 插件部分情况下可能显示不完整的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/403)
+## v2.2.1(2021-12-24)
+1. `A` `editable` 插件增加上下移动标签功能
+2. `U` `editable` 插件支持在文本中间光标处插入内容
+3. `F` 修复了 `nvue` 端设置 `margin` 后可能导致高度不正确的问题
+4. `F` 修复了 `highlight` 插件使用压缩版的 `prism.css` 可能导致背景失效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/367)
+5. `F` 修复了编辑状态下使用 `emoji` 插件内容为空时可能报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/371)
+6. `F` 修复了使用 `editable` 插件后将 `selectable` 属性设置为 `force` 不生效的问题
+## v2.2.0(2021-10-12)
+1. `A` 增加 `customElements` 配置项,便于添加自定义功能性标签 [详细](https://github.com/jin-yufeng/mp-html/issues/350)
+2. `A` `editable` 插件增加切换音视频自动播放状态的功能 [详细](https://github.com/jin-yufeng/mp-html/pull/341) by [@leeseett](https://github.com/leeseett)
+3. `A` `editable` 插件删除媒体标签时触发 `remove` 事件,便于删除已上传的文件
+4. `U` `editable` 插件 `insertImg` 方法支持同时插入多张图片 [详细](https://github.com/jin-yufeng/mp-html/issues/342)
+5. `U` `editable` 插入图片和音视频时支持拼接 `domian` 主域名
+6. `F` 修复了内部链接参数中包含 `://` 时被认为是外部链接的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/356)
+7. `F` 修复了部分 `svg` 标签名或属性名大小写不正确时不生效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/351)
+8. `F` 修复了 `nvue` 页面运行到非 `app` 平台时可能样式错误的问题
+## v2.1.5(2021-08-13)
+1. `A` 增加支持标签的 `dir` 属性
+2. `F` 修复了 `ruby` 标签文字与拼音没有居中对齐的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/325)
+3. `F` 修复了音视频标签内有 `a` 标签时可能无法播放的问题
+4. `F` 修复了 `externStyle` 中的 `class` 名包含下划线或数字时可能失效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/326)
+5. `F` 修复了 `h5` 端引入 `externStyle` 可能不生效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/326)
+## v2.1.4(2021-07-14)
+1. `F` 修复了 `rt` 标签无法设置样式的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/318)
+2. `F` 修复了表格中有单元格同时合并行和列时可能显示不正确的问题
+3. `F` 修复了 `app` 端无法关闭图片长按菜单的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/322)
+4. `F` 修复了 `editable` 插件只能添加图片链接不能修改的问题 [详细](https://github.com/jin-yufeng/mp-html/pull/312) by [@leeseett](https://github.com/leeseett)
+## v2.1.3(2021-06-12)
+1. `A` `editable` 插件增加 `insertTable` 方法
+2. `U` `editable` 插件支持编辑表格中的空白单元格 [详细](https://github.com/jin-yufeng/mp-html/issues/310)
+3. `F` 修复了 `externStyle` 中使用伪类可能失效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/298)
+4. `F` 修复了多个组件同时使用时 `tag-style` 属性时可能互相影响的问题 [详细](https://github.com/jin-yufeng/mp-html/pull/305) by [@woodguoyu](https://github.com/woodguoyu)
+5. `F` 修复了包含 `linearGradient` 的 `svg` 可能无法显示的问题
+6. `F` 修复了编译到头条小程序时可能报错的问题
+7. `F` 修复了 `nvue` 端不触发 `click` 事件的问题
+8. `F` 修复了 `editable` 插件尾部插入时无法撤销的问题
+9. `F` 修复了 `editable` 插件的 `insertHtml` 方法只能在末尾插入的问题
+10. `F` 修复了 `editable` 插件插入音频不显示的问题
+## v2.1.2(2021-04-24)
+1. `A` 增加了 [img-cache](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#img-cache) 插件,可以在 `app` 端缓存图片 [详细](https://github.com/jin-yufeng/mp-html/issues/292) by [@PentaTea](https://github.com/PentaTea)
+2. `U` 支持通过 `container-style` 属性设置 `white-space` 来保留连续空格和换行符 [详细](https://jin-yufeng.gitee.io/mp-html/#/question/faq#space)
+3. `U` 代码风格符合 [standard](https://standardjs.com) 标准
+4. `U` `editable` 插件编辑状态下支持预览视频 [详细](https://github.com/jin-yufeng/mp-html/issues/286)
+5. `F` 修复了 `svg` 标签内嵌 `svg` 时无法显示的问题
+6. `F` 修复了编译到支付宝和头条小程序时部分区域不可复制的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/291)
+## v2.1.1(2021-04-09)
+1. 修复了对 `p` 标签设置 `tag-style` 可能不生效的问题
+2. 修复了 `svg` 标签中的文本无法显示的问题
+3. 修复了使用 `editable` 插件编辑表格时可能报错的问题
+4. 修复了使用 `highlight` 插件运行到头条小程序时可能没有样式的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/280)
+5. 修复了使用 `editable` 插件 `editable` 属性为 `false` 时会报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/284)
+6. 修复了 `style` 插件连续子选择器失效的问题
+7. 修复了 `editable` 插件无法修改图片和字体大小的问题
+## v2.1.0.2(2021-03-21)
+修复了 `nvue` 端使用可能报错的问题
+## v2.1.0(2021-03-20)
+1. `A` 增加了 [container-style](https://jin-yufeng.gitee.io/mp-html/#/basic/prop#container-style) 属性 [详细](https://gitee.com/jin-yufeng/mp-html/pulls/1)
+2. `A` 增加支持 `strike` 标签
+3. `A` `editable` 插件增加 `placeholder` 属性 [详细](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#editable)
+4. `A` `editable` 插件增加 `insertHtml` 方法 [详细](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#editable)
+5. `U` 外部样式支持标签名选择器 [详细](https://jin-yufeng.gitee.io/mp-html/#/overview/quickstart#setting)
+6. `F` 修复了 `nvue` 端部分情况下可能不显示的问题
+## v2.0.5(2021-03-12)
+1. `U` [linktap](https://jin-yufeng.gitee.io/mp-html/#/basic/event#linktap) 事件增加返回内部文本内容 `innerText` [详细](https://github.com/jin-yufeng/mp-html/issues/271)
+2. `U` [selectable](https://jin-yufeng.gitee.io/mp-html/#/basic/prop#selectable) 属性设置为 `force` 时能够在微信 `iOS` 端生效(文本块会变成 `inline-block`) [详细](https://github.com/jin-yufeng/mp-html/issues/267)
+3. `F` 修复了部分情况下竖向无法滚动的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/182)
+4. `F` 修复了多次修改富文本数据时部分内容可能不显示的问题
+5. `F` 修复了 [腾讯视频](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#txv-video) 插件可能无法播放的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/265)
+6. `F` 修复了 [highlight](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#highlight) 插件没有设置高亮语言时没有应用默认样式的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/276) by [@fuzui](https://github.com/fuzui)

+ 498 - 0
uni_modules/mp-html/components/mp-html/mp-html.vue

@@ -0,0 +1,498 @@
+<template>
+  <view id="_root" :class="(selectable?'_select ':'')+'_root'" :style="containerStyle">
+    <slot v-if="!nodes[0]" />
+    <!-- #ifndef APP-PLUS-NVUE -->
+    <node v-else :childs="nodes" :opts="[lazyLoad,loadingImg,errorImg,showImgMenu,selectable]" name="span" />
+    <!-- #endif -->
+    <!-- #ifdef APP-PLUS-NVUE -->
+    <web-view ref="web" src="/uni_modules/mp-html/static/app-plus/mp-html/local.html" :style="'margin-top:-2px;height:' + height + 'px'" @onPostMessage="_onMessage" />
+    <!-- #endif -->
+  </view>
+</template>
+
+<script>
+/**
+ * mp-html v2.5.0
+ * @description 富文本组件
+ * @tutorial https://github.com/jin-yufeng/mp-html
+ * @property {String} container-style 容器的样式
+ * @property {String} content 用于渲染的 html 字符串
+ * @property {Boolean} copy-link 是否允许外部链接被点击时自动复制
+ * @property {String} domain 主域名,用于拼接链接
+ * @property {String} error-img 图片出错时的占位图链接
+ * @property {Boolean} lazy-load 是否开启图片懒加载
+ * @property {string} loading-img 图片加载过程中的占位图链接
+ * @property {Boolean} pause-video 是否在播放一个视频时自动暂停其他视频
+ * @property {Boolean} preview-img 是否允许图片被点击时自动预览
+ * @property {Boolean} scroll-table 是否给每个表格添加一个滚动层使其能单独横向滚动
+ * @property {Boolean | String} selectable 是否开启长按复制
+ * @property {Boolean} set-title 是否将 title 标签的内容设置到页面标题
+ * @property {Boolean} show-img-menu 是否允许图片被长按时显示菜单
+ * @property {Object} tag-style 标签的默认样式
+ * @property {Boolean | Number} use-anchor 是否使用锚点链接
+ * @event {Function} load dom 结构加载完毕时触发
+ * @event {Function} ready 所有图片加载完毕时触发
+ * @event {Function} imgtap 图片被点击时触发
+ * @event {Function} linktap 链接被点击时触发
+ * @event {Function} play 音视频播放时触发
+ * @event {Function} error 媒体加载出错时触发
+ */
+// #ifndef APP-PLUS-NVUE
+import node from './node/node'
+// #endif
+import Parser from './parser'
+const plugins=[]
+// #ifdef APP-PLUS-NVUE
+const dom = weex.requireModule('dom')
+// #endif
+export default {
+  name: 'mp-html',
+  data () {
+    return {
+      nodes: [],
+      // #ifdef APP-PLUS-NVUE
+      height: 3
+      // #endif
+    }
+  },
+  props: {
+    containerStyle: {
+      type: String,
+      default: ''
+    },
+    content: {
+      type: String,
+      default: ''
+    },
+    copyLink: {
+      type: [Boolean, String],
+      default: true
+    },
+    domain: String,
+    errorImg: {
+      type: String,
+      default: ''
+    },
+    lazyLoad: {
+      type: [Boolean, String],
+      default: false
+    },
+    loadingImg: {
+      type: String,
+      default: ''
+    },
+    pauseVideo: {
+      type: [Boolean, String],
+      default: true
+    },
+    previewImg: {
+      type: [Boolean, String],
+      default: true
+    },
+    scrollTable: [Boolean, String],
+    selectable: [Boolean, String],
+    setTitle: {
+      type: [Boolean, String],
+      default: true
+    },
+    showImgMenu: {
+      type: [Boolean, String],
+      default: true
+    },
+    tagStyle: Object,
+    useAnchor: [Boolean, Number]
+  },
+  // #ifdef VUE3
+  emits: ['load', 'ready', 'imgtap', 'linktap', 'play', 'error'],
+  // #endif
+  // #ifndef APP-PLUS-NVUE
+  components: {
+    node
+  },
+  // #endif
+  watch: {
+    content (content) {
+      this.setContent(content)
+    }
+  },
+  created () {
+    this.plugins = []
+    for (let i = plugins.length; i--;) {
+      this.plugins.push(new plugins[i](this))
+    }
+  },
+  mounted () {
+    if (this.content && !this.nodes.length) {
+      this.setContent(this.content)
+    }
+  },
+  beforeDestroy () {
+    this._hook('onDetached')
+  },
+  methods: {
+    /**
+     * @description 将锚点跳转的范围限定在一个 scroll-view 内
+     * @param {Object} page scroll-view 所在页面的示例
+     * @param {String} selector scroll-view 的选择器
+     * @param {String} scrollTop scroll-view scroll-top 属性绑定的变量名
+     */
+    in (page, selector, scrollTop) {
+      // #ifndef APP-PLUS-NVUE
+      if (page && selector && scrollTop) {
+        this._in = {
+          page,
+          selector,
+          scrollTop
+        }
+      }
+      // #endif
+    },
+
+    /**
+     * @description 锚点跳转
+     * @param {String} id 要跳转的锚点 id
+     * @param {Number} offset 跳转位置的偏移量
+     * @returns {Promise}
+     */
+    navigateTo (id, offset) {
+      return new Promise((resolve, reject) => {
+        if (!this.useAnchor) {
+          reject(Error('Anchor is disabled'))
+          return
+        }
+        offset = offset || parseInt(this.useAnchor) || 0
+        // #ifdef APP-PLUS-NVUE
+        if (!id) {
+          dom.scrollToElement(this.$refs.web, {
+            offset
+          })
+          resolve()
+        } else {
+          this._navigateTo = {
+            resolve,
+            reject,
+            offset
+          }
+          this.$refs.web.evalJs('uni.postMessage({data:{action:"getOffset",offset:(document.getElementById(' + id + ')||{}).offsetTop}})')
+        }
+        // #endif
+        // #ifndef APP-PLUS-NVUE
+        let deep = ' '
+        // #ifdef MP-WEIXIN || MP-QQ || MP-TOUTIAO
+        deep = '>>>'
+        // #endif
+        const selector = uni.createSelectorQuery()
+          // #ifndef MP-ALIPAY
+          .in(this._in ? this._in.page : this)
+          // #endif
+          .select((this._in ? this._in.selector : '._root') + (id ? `${deep}#${id}` : '')).boundingClientRect()
+        if (this._in) {
+          selector.select(this._in.selector).scrollOffset()
+            .select(this._in.selector).boundingClientRect()
+        } else {
+          // 获取 scroll-view 的位置和滚动距离
+          selector.selectViewport().scrollOffset() // 获取窗口的滚动距离
+        }
+        selector.exec(res => {
+          if (!res[0]) {
+            reject(Error('Label not found'))
+            return
+          }
+          const scrollTop = res[1].scrollTop + res[0].top - (res[2] ? res[2].top : 0) + offset
+          if (this._in) {
+            // scroll-view 跳转
+            this._in.page[this._in.scrollTop] = scrollTop
+          } else {
+            // 页面跳转
+            uni.pageScrollTo({
+              scrollTop,
+              duration: 300
+            })
+          }
+          resolve()
+        })
+        // #endif
+      })
+    },
+
+    /**
+     * @description 获取文本内容
+     * @return {String}
+     */
+    getText (nodes) {
+      let text = '';
+      (function traversal (nodes) {
+        for (let i = 0; i < nodes.length; i++) {
+          const node = nodes[i]
+          if (node.type === 'text') {
+            text += node.text.replace(/&amp;/g, '&')
+          } else if (node.name === 'br') {
+            text += '\n'
+          } else {
+            // 块级标签前后加换行
+            const isBlock = node.name === 'p' || node.name === 'div' || node.name === 'tr' || node.name === 'li' || (node.name[0] === 'h' && node.name[1] > '0' && node.name[1] < '7')
+            if (isBlock && text && text[text.length - 1] !== '\n') {
+              text += '\n'
+            }
+            // 递归获取子节点的文本
+            if (node.children) {
+              traversal(node.children)
+            }
+            if (isBlock && text[text.length - 1] !== '\n') {
+              text += '\n'
+            } else if (node.name === 'td' || node.name === 'th') {
+              text += '\t'
+            }
+          }
+        }
+      })(nodes || this.nodes)
+      return text
+    },
+
+    /**
+     * @description 获取内容大小和位置
+     * @return {Promise}
+     */
+    getRect () {
+      return new Promise((resolve, reject) => {
+        uni.createSelectorQuery()
+          // #ifndef MP-ALIPAY
+          .in(this)
+          // #endif
+          .select('#_root').boundingClientRect().exec(res => res[0] ? resolve(res[0]) : reject(Error('Root label not found')))
+      })
+    },
+
+    /**
+     * @description 暂停播放媒体
+     */
+    pauseMedia () {
+      for (let i = (this._videos || []).length; i--;) {
+        this._videos[i].pause()
+      }
+      // #ifdef APP-PLUS
+      const command = 'for(var e=document.getElementsByTagName("video"),i=e.length;i--;)e[i].pause()'
+      // #ifndef APP-PLUS-NVUE
+      let page = this.$parent
+      while (!page.$scope) page = page.$parent
+      page.$scope.$getAppWebview().evalJS(command)
+      // #endif
+      // #ifdef APP-PLUS-NVUE
+      this.$refs.web.evalJs(command)
+      // #endif
+      // #endif
+    },
+
+    /**
+     * @description 设置媒体播放速率
+     * @param {Number} rate 播放速率
+     */
+    setPlaybackRate (rate) {
+      this.playbackRate = rate
+      for (let i = (this._videos || []).length; i--;) {
+        this._videos[i].playbackRate(rate)
+      }
+      // #ifdef APP-PLUS
+      const command = 'for(var e=document.getElementsByTagName("video"),i=e.length;i--;)e[i].playbackRate=' + rate
+      // #ifndef APP-PLUS-NVUE
+      let page = this.$parent
+      while (!page.$scope) page = page.$parent
+      page.$scope.$getAppWebview().evalJS(command)
+      // #endif
+      // #ifdef APP-PLUS-NVUE
+      this.$refs.web.evalJs(command)
+      // #endif
+      // #endif
+    },
+
+    /**
+     * @description 设置内容
+     * @param {String} content html 内容
+     * @param {Boolean} append 是否在尾部追加
+     */
+    setContent (content, append) {
+      if (!append || !this.imgList) {
+        this.imgList = []
+      }
+      const nodes = new Parser(this).parse(content)
+      // #ifdef APP-PLUS-NVUE
+      if (this._ready) {
+        this._set(nodes, append)
+      }
+      // #endif
+      this.$set(this, 'nodes', append ? (this.nodes || []).concat(nodes) : nodes)
+
+      // #ifndef APP-PLUS-NVUE
+      this._videos = []
+      this.$nextTick(() => {
+        this._hook('onLoad')
+        this.$emit('load')
+      })
+
+      if (this.lazyLoad || this.imgList._unloadimgs < this.imgList.length / 2) {
+        // 设置懒加载,每 350ms 获取高度,不变则认为加载完毕
+        let height = 0
+        const callback = rect => {
+          if (!rect || !rect.height) rect = {}
+          // 350ms 总高度无变化就触发 ready 事件
+          if (rect.height === height) {
+            this.$emit('ready', rect)
+          } else {
+            height = rect.height
+            setTimeout(() => {
+              this.getRect().then(callback).catch(callback)
+            }, 350)
+          }
+        }
+        this.getRect().then(callback).catch(callback)
+      } else {
+        // 未设置懒加载,等待所有图片加载完毕
+        if (!this.imgList._unloadimgs) {
+          this.getRect().then(rect => {
+            this.$emit('ready', rect)
+          }).catch(() => {
+            this.$emit('ready', {})
+          })
+        }
+      }
+      // #endif
+    },
+
+    /**
+     * @description 调用插件钩子函数
+     */
+    _hook (name) {
+      for (let i = plugins.length; i--;) {
+        if (this.plugins[i][name]) {
+          this.plugins[i][name]()
+        }
+      }
+    },
+
+    // #ifdef APP-PLUS-NVUE
+    /**
+     * @description 设置内容
+     */
+    _set (nodes, append) {
+      this.$refs.web.evalJs('setContent(' + JSON.stringify(nodes).replace(/%22/g, '') + ',' + JSON.stringify([this.containerStyle.replace(/(?:margin|padding)[^;]+/g, ''), this.errorImg, this.loadingImg, this.pauseVideo, this.scrollTable, this.selectable]) + ',' + append + ')')
+    },
+
+    /**
+     * @description 接收到 web-view 消息
+     */
+    _onMessage (e) {
+      const message = e.detail.data[0]
+      switch (message.action) {
+        // web-view 初始化完毕
+        case 'onJSBridgeReady':
+          this._ready = true
+          if (this.nodes) {
+            this._set(this.nodes)
+          }
+          break
+        // 内容 dom 加载完毕
+        case 'onLoad':
+          this.height = message.height
+          this._hook('onLoad')
+          this.$emit('load')
+          break
+        // 所有图片加载完毕
+        case 'onReady':
+          this.getRect().then(res => {
+            this.$emit('ready', res)
+          }).catch(() => {
+            this.$emit('ready', {})
+          })
+          break
+        // 总高度发生变化
+        case 'onHeightChange':
+          this.height = message.height
+          break
+        // 图片点击
+        case 'onImgTap':
+          this.$emit('imgtap', message.attrs)
+          if (this.previewImg) {
+            uni.previewImage({
+              current: parseInt(message.attrs.i),
+              urls: this.imgList
+            })
+          }
+          break
+        // 链接点击
+        case 'onLinkTap': {
+          const href = message.attrs.href
+          this.$emit('linktap', message.attrs)
+          if (href) {
+            // 锚点跳转
+            if (href[0] === '#') {
+              if (this.useAnchor) {
+                dom.scrollToElement(this.$refs.web, {
+                  offset: message.offset
+                })
+              }
+            } else if (href.includes('://')) {
+              // 打开外链
+              if (this.copyLink) {
+                plus.runtime.openWeb(href)
+              }
+            } else {
+              uni.navigateTo({
+                url: href,
+                fail () {
+                  uni.switchTab({
+                    url: href
+                  })
+                }
+              })
+            }
+          }
+          break
+        }
+        case 'onPlay':
+          this.$emit('play')
+          break
+        // 获取到锚点的偏移量
+        case 'getOffset':
+          if (typeof message.offset === 'number') {
+            dom.scrollToElement(this.$refs.web, {
+              offset: message.offset + this._navigateTo.offset
+            })
+            this._navigateTo.resolve()
+          } else {
+            this._navigateTo.reject(Error('Label not found'))
+          }
+          break
+        // 点击
+        case 'onClick':
+          this.$emit('tap')
+          this.$emit('click')
+          break
+        // 出错
+        case 'onError':
+          this.$emit('error', {
+            source: message.source,
+            attrs: message.attrs
+          })
+      }
+    }
+    // #endif
+  }
+}
+</script>
+
+<style>
+/* #ifndef APP-PLUS-NVUE */
+/* 根节点样式 */
+._root {
+  padding: 1px 0;
+  overflow-x: auto;
+  overflow-y: hidden;
+  -webkit-overflow-scrolling: touch;
+}
+
+/* 长按复制 */
+._select {
+  user-select: text;
+}
+/* #endif */
+</style>

+ 587 - 0
uni_modules/mp-html/components/mp-html/node/node.vue

@@ -0,0 +1,587 @@
+<template>
+  <view :id="attrs.id" :class="'_block _'+name+' '+attrs.class" :style="attrs.style">
+    <block v-for="(n, i) in childs" v-bind:key="i">
+      <!-- 图片 -->
+      <!-- 占位图 -->
+      <image v-if="n.name==='img'&&!n.t&&((opts[1]&&!ctrl[i])||ctrl[i]<0)" class="_img" :style="n.attrs.style" :src="ctrl[i]<0?opts[2]:opts[1]" mode="widthFix" />
+      <!-- 显示图片 -->
+      <!-- #ifdef H5 || (APP-PLUS && VUE2) -->
+      <img v-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl[i]===-1?'display:none;':'')+n.attrs.style" :src="n.attrs.src||(ctrl.load?n.attrs['data-src']:'')" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
+      <!-- #endif -->
+      <!-- #ifndef H5 || (APP-PLUS && VUE2) -->
+      <!-- 表格中的图片,使用 rich-text 防止大小不正确 -->
+      <rich-text v-if="n.name==='img'&&n.t" :style="'display:'+n.t" :nodes="[{attrs:{style:n.attrs.style||'',src:n.attrs.src},name:'img'}]" :data-i="i" @tap.stop="imgTap" />
+      <!-- #endif -->
+      <!-- #ifndef H5 || APP-PLUS || MP-KUAISHOU -->
+      <image v-else-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl[i]===-1?'display:none;':'')+'width:'+(ctrl[i]||1)+'px;height:1px;'+n.attrs.style" :src="n.attrs.src" :mode="!n.h?'widthFix':(!n.w?'heightFix':(n.m||'scaleToFill'))" :lazy-load="opts[0]" :webp="n.webp" :show-menu-by-longpress="opts[3]&&!n.attrs.ignore" :image-menu-prevent="!opts[3]||n.attrs.ignore" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
+      <!-- #endif -->
+      <!-- #ifdef MP-KUAISHOU -->
+      <image v-else-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl[i]===-1?'display:none;':'')+n.attrs.style" :src="n.attrs.src" :lazy-load="opts[0]" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap"></image>
+      <!-- #endif -->
+      <!-- #ifdef APP-PLUS && VUE3 -->
+      <image v-else-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl[i]===-1?'display:none;':'')+'width:'+(ctrl[i]||1)+'px;'+n.attrs.style" :src="n.attrs.src||(ctrl.load?n.attrs['data-src']:'')" :mode="!n.h?'widthFix':(!n.w?'heightFix':(n.m||''))" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
+      <!-- #endif -->
+      <!-- 文本 -->
+      <!-- #ifdef MP-WEIXIN -->
+      <text v-else-if="n.text" :user-select="opts[4]=='force'&&isiOS" decode>{{n.text}}</text>
+      <!-- #endif -->
+      <!-- #ifndef MP-WEIXIN || MP-BAIDU || MP-ALIPAY || MP-TOUTIAO -->
+      <text v-else-if="n.text" decode>{{n.text}}</text>
+      <!-- #endif -->
+      <text v-else-if="n.name==='br'">\n</text>
+      <!-- 链接 -->
+      <view v-else-if="n.name==='a'" :id="n.attrs.id" :class="(n.attrs.href?'_a ':'')+n.attrs.class" hover-class="_hover" :style="'display:inline;'+n.attrs.style" :data-i="i" @tap.stop="linkTap">
+        <node name="span" :childs="n.children" :opts="opts" style="display:inherit" />
+      </view>
+      <!-- 视频 -->
+      <!-- #ifdef APP-PLUS -->
+      <view v-else-if="n.html" :id="n.attrs.id" :class="'_video '+n.attrs.class" :style="n.attrs.style" v-html="n.html" @vplay.stop="play" />
+      <!-- #endif -->
+      <!-- #ifndef APP-PLUS -->
+      <video v-else-if="n.name==='video'" :id="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :autoplay="n.attrs.autoplay" :controls="n.attrs.controls" :loop="n.attrs.loop" :muted="n.attrs.muted" :object-fit="n.attrs['object-fit']" :poster="n.attrs.poster" :src="n.src[ctrl[i]||0]" :data-i="i" @play="play" @error="mediaError" />
+      <!-- #endif -->
+      <!-- #ifdef H5 || APP-PLUS -->
+      <iframe v-else-if="n.name==='iframe'" :style="n.attrs.style" :allowfullscreen="n.attrs.allowfullscreen" :frameborder="n.attrs.frameborder" :src="n.attrs.src" />
+      <embed v-else-if="n.name==='embed'" :style="n.attrs.style" :src="n.attrs.src" />
+      <!-- #endif -->
+      <!-- #ifndef MP-TOUTIAO || ((H5 || APP-PLUS) && VUE3) -->
+      <!-- 音频 -->
+      <audio v-else-if="n.name==='audio'" :id="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :author="n.attrs.author" :controls="n.attrs.controls" :loop="n.attrs.loop" :name="n.attrs.name" :poster="n.attrs.poster" :src="n.src[ctrl[i]||0]" :data-i="i" @play="play" @error="mediaError" />
+      <!-- #endif -->
+      <view v-else-if="(n.name==='table'&&n.c)||n.name==='li'" :id="n.attrs.id" :class="'_'+n.name+' '+n.attrs.class" :style="n.attrs.style">
+        <node v-if="n.name==='li'" :childs="n.children" :opts="opts" />
+        <view v-else v-for="(tbody, x) in n.children" v-bind:key="x" :class="'_'+tbody.name+' '+tbody.attrs.class" :style="tbody.attrs.style">
+          <node v-if="tbody.name==='td'||tbody.name==='th'" :childs="tbody.children" :opts="opts" />
+          <block v-else v-for="(tr, y) in tbody.children" v-bind:key="y">
+            <view v-if="tr.name==='td'||tr.name==='th'" :class="'_'+tr.name+' '+tr.attrs.class" :style="tr.attrs.style">
+              <node :childs="tr.children" :opts="opts" />
+            </view>
+            <view v-else :class="'_'+tr.name+' '+tr.attrs.class" :style="tr.attrs.style">
+              <view v-for="(td, z) in tr.children" v-bind:key="z" :class="'_'+td.name+' '+td.attrs.class" :style="td.attrs.style">
+                <node :childs="td.children" :opts="opts" />
+              </view>
+            </view>
+          </block>
+        </view>
+      </view>
+      
+      <!-- 富文本 -->
+      <!-- #ifdef H5 || ((MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE2) -->
+      <rich-text v-else-if="!n.c&&!handler.isInline(n.name, n.attrs.style)" :id="n.attrs.id" :style="n.f" :user-select="opts[4]" :nodes="[n]" />
+      <!-- #endif -->
+      <!-- #ifndef H5 || ((MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE2) -->
+      <rich-text v-else-if="!n.c" :id="n.attrs.id" :style="'display:inline;'+n.f" :preview="false" :selectable="opts[4]" :user-select="opts[4]" :nodes="[n]" />
+      <!-- #endif -->
+      <!-- 继续递归 -->
+      <view v-else-if="n.c===2" :id="n.attrs.id" :class="'_block _'+n.name+' '+n.attrs.class" :style="n.f+';'+n.attrs.style">
+        <node v-for="(n2, j) in n.children" v-bind:key="j" :style="n2.f" :name="n2.name" :attrs="n2.attrs" :childs="n2.children" :opts="opts" />
+      </view>
+      <node v-else :style="n.f" :name="n.name" :attrs="n.attrs" :childs="n.children" :opts="opts" />
+    </block>
+  </view>
+</template>
+<script module="handler" lang="wxs">
+// 行内标签列表
+var inlineTags = {
+  abbr: true,
+  b: true,
+  big: true,
+  code: true,
+  del: true,
+  em: true,
+  i: true,
+  ins: true,
+  label: true,
+  q: true,
+  small: true,
+  span: true,
+  strong: true,
+  sub: true,
+  sup: true
+}
+/**
+ * @description 判断是否为行内标签
+ */
+module.exports = {
+  isInline: function (tagName, style) {
+    return inlineTags[tagName] || (style || '').indexOf('display:inline') !== -1
+  }
+}
+</script>
+<script>
+
+import node from './node'
+export default {
+  name: 'node',
+  options: {
+    // #ifdef MP-WEIXIN
+    virtualHost: true,
+    // #endif
+    // #ifdef MP-TOUTIAO
+    addGlobalClass: false
+    // #endif
+  },
+  data () {
+    return {
+      ctrl: {},
+      // #ifdef MP-WEIXIN
+      isiOS: uni.getSystemInfoSync().system.includes('iOS')
+      // #endif
+    }
+  },
+  props: {
+    name: String,
+    attrs: {
+      type: Object,
+      default () {
+        return {}
+      }
+    },
+    childs: Array,
+    opts: Array
+  },
+  components: {
+
+    // #ifndef (H5 || APP-PLUS) && VUE3
+    node
+    // #endif
+  },
+  mounted () {
+    this.$nextTick(() => {
+      for (this.root = this.$parent; this.root.$options.name !== 'mp-html'; this.root = this.root.$parent);
+    })
+    // #ifdef H5 || APP-PLUS
+    if (this.opts[0]) {
+      let i
+      for (i = this.childs.length; i--;) {
+        if (this.childs[i].name === 'img') break
+      }
+      if (i !== -1) {
+        this.observer = uni.createIntersectionObserver(this).relativeToViewport({
+          top: 500,
+          bottom: 500
+        })
+        this.observer.observe('._img', res => {
+          if (res.intersectionRatio) {
+            this.$set(this.ctrl, 'load', 1)
+            this.observer.disconnect()
+          }
+        })
+      }
+    }
+    // #endif
+  },
+  beforeDestroy () {
+    // #ifdef H5 || APP-PLUS
+    if (this.observer) {
+      this.observer.disconnect()
+    }
+    // #endif
+  },
+  methods:{
+    // #ifdef MP-WEIXIN
+    toJSON () { return this },
+    // #endif
+    /**
+     * @description 播放视频事件
+     * @param {Event} e
+     */
+    play (e) {
+      const i = e.currentTarget.dataset.i
+      const node = this.childs[i]
+      this.root.$emit('play', {
+        source: node.name,
+        attrs: {
+          ...node.attrs,
+          src: node.src[this.ctrl[i] || 0]
+        }
+      })
+      // #ifndef APP-PLUS
+      if (this.root.pauseVideo) {
+        let flag = false
+        const id = e.target.id
+        for (let i = this.root._videos.length; i--;) {
+          if (this.root._videos[i].id === id) {
+            flag = true
+          } else {
+            this.root._videos[i].pause() // 自动暂停其他视频
+          }
+        }
+        // 将自己加入列表
+        if (!flag) {
+          const ctx = uni.createVideoContext(id
+            // #ifndef MP-BAIDU
+            , this
+            // #endif
+          )
+          ctx.id = id
+          if (this.root.playbackRate) {
+            ctx.playbackRate(this.root.playbackRate)
+          }
+          this.root._videos.push(ctx)
+        }
+      }
+      // #endif
+    },
+
+    /**
+     * @description 图片点击事件
+     * @param {Event} e
+     */
+    imgTap (e) {
+      const node = this.childs[e.currentTarget.dataset.i]
+      if (node.a) {
+        this.linkTap(node.a)
+        return
+      }
+      if (node.attrs.ignore) return
+      // #ifdef H5 || APP-PLUS
+      node.attrs.src = node.attrs.src || node.attrs['data-src']
+      // #endif
+      this.root.$emit('imgtap', node.attrs)
+      // 自动预览图片
+      if (this.root.previewImg) {
+        uni.previewImage({
+          // #ifdef MP-WEIXIN
+          showmenu: this.root.showImgMenu,
+          // #endif
+          // #ifdef MP-ALIPAY
+          enablesavephoto: this.root.showImgMenu,
+          enableShowPhotoDownload: this.root.showImgMenu,
+          // #endif
+          current: parseInt(node.attrs.i),
+          urls: this.root.imgList
+        })
+      }
+    },
+
+    /**
+     * @description 图片长按
+     */
+    imgLongTap (e) {
+      // #ifdef APP-PLUS
+      const attrs = this.childs[e.currentTarget.dataset.i].attrs
+      if (this.opts[3] && !attrs.ignore) {
+        uni.showActionSheet({
+          itemList: ['保存图片'],
+          success: () => {
+            const save = path => {
+              uni.saveImageToPhotosAlbum({
+                filePath: path,
+                success () {
+                  uni.showToast({
+                    title: '保存成功'
+                  })
+                }
+              })
+            }
+            if (this.root.imgList[attrs.i].startsWith('http')) {
+              uni.downloadFile({
+                url: this.root.imgList[attrs.i],
+                success: res => save(res.tempFilePath)
+              })
+            } else {
+              save(this.root.imgList[attrs.i])
+            }
+          }
+        })
+      }
+      // #endif
+    },
+
+    /**
+     * @description 图片加载完成事件
+     * @param {Event} e
+     */
+    imgLoad (e) {
+      const i = e.currentTarget.dataset.i
+      /* #ifndef H5 || (APP-PLUS && VUE2) */
+      if (!this.childs[i].w) {
+        // 设置原宽度
+        this.$set(this.ctrl, i, e.detail.width)
+      } else /* #endif */ if ((this.opts[1] && !this.ctrl[i]) || this.ctrl[i] === -1) {
+        // 加载完毕,取消加载中占位图
+        this.$set(this.ctrl, i, 1)
+      }
+      this.checkReady()
+    },
+
+    /**
+     * @description 检查是否所有图片加载完毕
+     */
+    checkReady () {
+      if (this.root && !this.root.lazyLoad) {
+        this.root._unloadimgs -= 1
+        if (!this.root._unloadimgs) {
+          setTimeout(() => {
+            this.root.getRect().then(rect => {
+              this.root.$emit('ready', rect)
+            }).catch(() => {
+              this.root.$emit('ready', {})
+            })
+          }, 350)
+        }
+      }
+    },
+
+    /**
+     * @description 链接点击事件
+     * @param {Event} e
+     */
+    linkTap (e) {
+      const node = e.currentTarget ? this.childs[e.currentTarget.dataset.i] : {}
+      const attrs = node.attrs || e
+      const href = attrs.href
+      this.root.$emit('linktap', Object.assign({
+        innerText: this.root.getText(node.children || []) // 链接内的文本内容
+      }, attrs))
+      if (href) {
+        if (href[0] === '#') {
+          // 跳转锚点
+          this.root.navigateTo(href.substring(1)).catch(() => { })
+        } else if (href.split('?')[0].includes('://')) {
+          // 复制外部链接
+          if (this.root.copyLink) {
+            // #ifdef H5
+            window.open(href)
+            // #endif
+            // #ifdef MP
+            uni.setClipboardData({
+              data: href,
+              success: () =>
+                uni.showToast({
+                  title: '链接已复制'
+                })
+            })
+            // #endif
+            // #ifdef APP-PLUS
+            plus.runtime.openWeb(href)
+            // #endif
+          }
+        } else {
+          // 跳转页面
+          uni.navigateTo({
+            url: href,
+            fail () {
+              uni.switchTab({
+                url: href,
+                fail () { }
+              })
+            }
+          })
+        }
+      }
+    },
+
+    /**
+     * @description 错误事件
+     * @param {Event} e
+     */
+    mediaError (e) {
+      const i = e.currentTarget.dataset.i
+      const node = this.childs[i]
+      // 加载其他源
+      if (node.name === 'video' || node.name === 'audio') {
+        let index = (this.ctrl[i] || 0) + 1
+        if (index > node.src.length) {
+          index = 0
+        }
+        if (index < node.src.length) {
+          this.$set(this.ctrl, i, index)
+          return
+        }
+      } else if (node.name === 'img') {
+        // #ifdef H5 && VUE3
+        if (this.opts[0] && !this.ctrl.load) return
+        // #endif
+        // 显示错误占位图
+        if (this.opts[2]) {
+          this.$set(this.ctrl, i, -1)
+        }
+        this.checkReady()
+      }
+      if (this.root) {
+        this.root.$emit('error', {
+          source: node.name,
+          attrs: node.attrs,
+          // #ifndef H5 && VUE3
+          errMsg: e.detail.errMsg
+          // #endif
+        })
+      }
+    }
+  }
+}
+</script>
+<style>
+/* a 标签默认效果 */
+._a {
+  padding: 1.5px 0 1.5px 0;
+  color: #366092;
+  word-break: break-all;
+}
+
+/* a 标签点击态效果 */
+._hover {
+  text-decoration: underline;
+  opacity: 0.7;
+}
+
+/* 图片默认效果 */
+._img {
+  max-width: 100%;
+  -webkit-touch-callout: none;
+}
+
+/* 内部样式 */
+
+._block {
+  display: block;
+}
+
+._b,
+._strong {
+  font-weight: bold;
+}
+
+._code {
+  font-family: monospace;
+}
+
+._del {
+  text-decoration: line-through;
+}
+
+._em,
+._i {
+  font-style: italic;
+}
+
+._h1 {
+  font-size: 2em;
+}
+
+._h2 {
+  font-size: 1.5em;
+}
+
+._h3 {
+  font-size: 1.17em;
+}
+
+._h5 {
+  font-size: 0.83em;
+}
+
+._h6 {
+  font-size: 0.67em;
+}
+
+._h1,
+._h2,
+._h3,
+._h4,
+._h5,
+._h6 {
+  display: block;
+  font-weight: bold;
+}
+
+._image {
+  height: 1px;
+}
+
+._ins {
+  text-decoration: underline;
+}
+
+._li {
+  display: list-item;
+}
+
+._ol {
+  list-style-type: decimal;
+}
+
+._ol,
+._ul {
+  display: block;
+  padding-left: 40px;
+  margin: 1em 0;
+}
+
+._q::before {
+  content: '"';
+}
+
+._q::after {
+  content: '"';
+}
+
+._sub {
+  font-size: smaller;
+  vertical-align: sub;
+}
+
+._sup {
+  font-size: smaller;
+  vertical-align: super;
+}
+
+._thead,
+._tbody,
+._tfoot {
+  display: table-row-group;
+}
+
+._tr {
+  display: table-row;
+}
+
+._td,
+._th {
+  display: table-cell;
+  vertical-align: middle;
+}
+
+._th {
+  font-weight: bold;
+  text-align: center;
+}
+
+._ul {
+  list-style-type: disc;
+}
+
+._ul ._ul {
+  margin: 0;
+  list-style-type: circle;
+}
+
+._ul ._ul ._ul {
+  list-style-type: square;
+}
+
+._abbr,
+._b,
+._code,
+._del,
+._em,
+._i,
+._ins,
+._label,
+._q,
+._span,
+._strong,
+._sub,
+._sup {
+  display: inline;
+}
+
+/* #ifdef APP-PLUS */
+._video {
+  width: 300px;
+  height: 225px;
+}
+/* #endif */
+</style>

+ 1393 - 0
uni_modules/mp-html/components/mp-html/parser.js

@@ -0,0 +1,1393 @@
+/**
+ * @fileoverview html 解析器
+ */
+
+// 配置
+const config = {
+  // 信任的标签(保持标签名不变)
+  trustTags: makeMap('a,abbr,ad,audio,b,blockquote,br,code,col,colgroup,dd,del,dl,dt,div,em,fieldset,h1,h2,h3,h4,h5,h6,hr,i,img,ins,label,legend,li,ol,p,q,ruby,rt,source,span,strong,sub,sup,table,tbody,td,tfoot,th,thead,tr,title,ul,video'),
+
+  // 块级标签(转为 div,其他的非信任标签转为 span)
+  blockTags: makeMap('address,article,aside,body,caption,center,cite,footer,header,html,nav,pre,section'),
+
+  // #ifdef (MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE3
+  // 行内标签
+  inlineTags: makeMap('abbr,b,big,code,del,em,i,ins,label,q,small,span,strong,sub,sup'),
+  // #endif
+
+  // 要移除的标签
+  ignoreTags: makeMap('area,base,canvas,embed,frame,head,iframe,input,link,map,meta,param,rp,script,source,style,textarea,title,track,wbr'),
+
+  // 自闭合的标签
+  voidTags: makeMap('area,base,br,col,circle,ellipse,embed,frame,hr,img,input,line,link,meta,param,path,polygon,rect,source,track,use,wbr'),
+
+  // html 实体
+  entities: {
+    lt: '<',
+    gt: '>',
+    quot: '"',
+    apos: "'",
+    ensp: '\u2002',
+    emsp: '\u2003',
+    nbsp: '\xA0',
+    semi: ';',
+    ndash: '–',
+    mdash: '—',
+    middot: '·',
+    lsquo: '‘',
+    rsquo: '’',
+    ldquo: '“',
+    rdquo: '”',
+    bull: '•',
+    hellip: '…',
+    larr: '←',
+    uarr: '↑',
+    rarr: '→',
+    darr: '↓'
+  },
+
+  // 默认的标签样式
+  tagStyle: {
+    // #ifndef APP-PLUS-NVUE
+    address: 'font-style:italic',
+    big: 'display:inline;font-size:1.2em',
+    caption: 'display:table-caption;text-align:center',
+    center: 'text-align:center',
+    cite: 'font-style:italic',
+    dd: 'margin-left:40px',
+    mark: 'background-color:yellow',
+    pre: 'font-family:monospace;white-space:pre',
+    s: 'text-decoration:line-through',
+    small: 'display:inline;font-size:0.8em',
+    strike: 'text-decoration:line-through',
+    u: 'text-decoration:underline'
+    // #endif
+  },
+
+  // svg 大小写对照表
+  svgDict: {
+    animatetransform: 'animateTransform',
+    lineargradient: 'linearGradient',
+    viewbox: 'viewBox',
+    attributename: 'attributeName',
+    repeatcount: 'repeatCount',
+    repeatdur: 'repeatDur',
+    foreignobject: 'foreignObject'
+  }
+}
+const tagSelector={}
+const {
+  windowWidth,
+  // #ifdef MP-WEIXIN
+  system
+  // #endif
+} = uni.getSystemInfoSync()
+const blankChar = makeMap(' ,\r,\n,\t,\f')
+let idIndex = 0
+
+// #ifdef H5 || APP-PLUS
+config.ignoreTags.iframe = undefined
+config.trustTags.iframe = true
+config.ignoreTags.embed = undefined
+config.trustTags.embed = true
+// #endif
+// #ifdef APP-PLUS-NVUE
+config.ignoreTags.source = undefined
+config.ignoreTags.style = undefined
+// #endif
+
+/**
+ * @description 创建 map
+ * @param {String} str 逗号分隔
+ */
+function makeMap (str) {
+  const map = Object.create(null)
+  const list = str.split(',')
+  for (let i = list.length; i--;) {
+    map[list[i]] = true
+  }
+  return map
+}
+
+/**
+ * @description 解码 html 实体
+ * @param {String} str 要解码的字符串
+ * @param {Boolean} amp 要不要解码 &amp;
+ * @returns {String} 解码后的字符串
+ */
+function decodeEntity (str, amp) {
+  let i = str.indexOf('&')
+  while (i !== -1) {
+    const j = str.indexOf(';', i + 3)
+    let code
+    if (j === -1) break
+    if (str[i + 1] === '#') {
+      // &#123; 形式的实体
+      code = parseInt((str[i + 2] === 'x' ? '0' : '') + str.substring(i + 2, j))
+      if (!isNaN(code)) {
+        str = str.substr(0, i) + String.fromCharCode(code) + str.substr(j + 1)
+      }
+    } else {
+      // &nbsp; 形式的实体
+      code = str.substring(i + 1, j)
+      if (config.entities[code] || (code === 'amp' && amp)) {
+        str = str.substr(0, i) + (config.entities[code] || '&') + str.substr(j + 1)
+      }
+    }
+    i = str.indexOf('&', i + 1)
+  }
+  return str
+}
+
+/**
+ * @description 合并多个块级标签,加快长内容渲染
+ * @param {Array} nodes 要合并的标签数组
+ */
+function mergeNodes (nodes) {
+  let i = nodes.length - 1
+  for (let j = i; j >= -1; j--) {
+    if (j === -1 || nodes[j].c || !nodes[j].name || (nodes[j].name !== 'div' && nodes[j].name !== 'p' && nodes[j].name[0] !== 'h') || (nodes[j].attrs.style || '').includes('inline')) {
+      if (i - j >= 5) {
+        nodes.splice(j + 1, i - j, {
+          name: 'div',
+          attrs: {},
+          children: nodes.slice(j + 1, i + 1)
+        })
+      }
+      i = j - 1
+    }
+  }
+}
+
+/**
+ * @description html 解析器
+ * @param {Object} vm 组件实例
+ */
+function Parser (vm) {
+  this.options = vm || {}
+  this.tagStyle = Object.assign({}, config.tagStyle, this.options.tagStyle)
+  this.imgList = vm.imgList || []
+  this.imgList._unloadimgs = 0
+  this.plugins = vm.plugins || []
+  this.attrs = Object.create(null)
+  this.stack = []
+  this.nodes = []
+  this.pre = (this.options.containerStyle || '').includes('white-space') && this.options.containerStyle.includes('pre') ? 2 : 0
+}
+
+/**
+ * @description 执行解析
+ * @param {String} content 要解析的文本
+ */
+Parser.prototype.parse = function (content) {
+  // 插件处理
+  for (let i = this.plugins.length; i--;) {
+    if (this.plugins[i].onUpdate) {
+      content = this.plugins[i].onUpdate(content, config) || content
+    }
+  }
+
+  new Lexer(this).parse(content)
+  // 出栈未闭合的标签
+  while (this.stack.length) {
+    this.popNode()
+  }
+  if (this.nodes.length > 50) {
+    mergeNodes(this.nodes)
+  }
+  return this.nodes
+}
+
+/**
+ * @description 将标签暴露出来(不被 rich-text 包含)
+ */
+Parser.prototype.expose = function () {
+  // #ifndef APP-PLUS-NVUE
+  for (let i = this.stack.length; i--;) {
+    const item = this.stack[i]
+    if (item.c || item.name === 'a' || item.name === 'video' || item.name === 'audio') return
+    item.c = 1
+  }
+  // #endif
+}
+
+/**
+ * @description 处理插件
+ * @param {Object} node 要处理的标签
+ * @returns {Boolean} 是否要移除此标签
+ */
+Parser.prototype.hook = function (node) {
+  for (let i = this.plugins.length; i--;) {
+    if (this.plugins[i].onParse && this.plugins[i].onParse(node, this) === false) {
+      return false
+    }
+  }
+  return true
+}
+
+/**
+ * @description 将链接拼接上主域名
+ * @param {String} url 需要拼接的链接
+ * @returns {String} 拼接后的链接
+ */
+Parser.prototype.getUrl = function (url) {
+  const domain = this.options.domain
+  if (url[0] === '/') {
+    if (url[1] === '/') {
+      // // 开头的补充协议名
+      url = (domain ? domain.split('://')[0] : 'http') + ':' + url
+    } else if (domain) {
+      // 否则补充整个域名
+      url = domain + url
+    } /* #ifdef APP-PLUS */ else {
+      url = plus.io.convertLocalFileSystemURL(url)
+    } /* #endif */
+  } else if (!url.includes('data:') && !url.includes('://')) {
+    if (domain) {
+      url = domain + '/' + url
+    } /* #ifdef APP-PLUS */ else {
+      url = plus.io.convertLocalFileSystemURL(url)
+    } /* #endif */
+  }
+  return url
+}
+
+/**
+ * @description 解析样式表
+ * @param {Object} node 标签
+ * @returns {Object}
+ */
+Parser.prototype.parseStyle = function (node) {
+  const attrs = node.attrs
+  const list = (this.tagStyle[node.name] || '').split(';').concat((attrs.style || '').split(';'))
+  const styleObj = {}
+  let tmp = ''
+
+  if (attrs.id && !this.xml) {
+    // 暴露锚点
+    if (this.options.useAnchor) {
+      this.expose()
+    } else if (node.name !== 'img' && node.name !== 'a' && node.name !== 'video' && node.name !== 'audio') {
+      attrs.id = undefined
+    }
+  }
+
+  // 转换 width 和 height 属性
+  if (attrs.width) {
+    styleObj.width = parseFloat(attrs.width) + (attrs.width.includes('%') ? '%' : 'px')
+    attrs.width = undefined
+  }
+  if (attrs.height) {
+    styleObj.height = parseFloat(attrs.height) + (attrs.height.includes('%') ? '%' : 'px')
+    attrs.height = undefined
+  }
+
+  for (let i = 0, len = list.length; i < len; i++) {
+    const info = list[i].split(':')
+    if (info.length < 2) continue
+    const key = info.shift().trim().toLowerCase()
+    let value = info.join(':').trim()
+    if ((value[0] === '-' && value.lastIndexOf('-') > 0) || value.includes('safe')) {
+      // 兼容性的 css 不压缩
+      tmp += `;${key}:${value}`
+    } else if (!styleObj[key] || value.includes('import') || !styleObj[key].includes('import')) {
+      // 重复的样式进行覆盖
+      if (value.includes('url')) {
+        // 填充链接
+        let j = value.indexOf('(') + 1
+        if (j) {
+          while (value[j] === '"' || value[j] === "'" || blankChar[value[j]]) {
+            j++
+          }
+          value = value.substr(0, j) + this.getUrl(value.substr(j))
+        }
+      } else if (value.includes('rpx')) {
+        // 转换 rpx(rich-text 内部不支持 rpx)
+        value = value.replace(/[0-9.]+\s*rpx/g, $ => parseFloat($) * windowWidth / 750 + 'px')
+      }
+      styleObj[key] = value
+    }
+  }
+
+  node.attrs.style = tmp
+  return styleObj
+}
+
+/**
+ * @description 解析到标签名
+ * @param {String} name 标签名
+ * @private
+ */
+Parser.prototype.onTagName = function (name) {
+  this.tagName = this.xml ? name : name.toLowerCase()
+  if (this.tagName === 'svg') {
+    this.xml = (this.xml || 0) + 1 // svg 标签内大小写敏感
+    config.ignoreTags.style = undefined // svg 标签内 style 可用
+  }
+}
+
+/**
+ * @description 解析到属性名
+ * @param {String} name 属性名
+ * @private
+ */
+Parser.prototype.onAttrName = function (name) {
+  name = this.xml ? name : name.toLowerCase()
+  // #ifdef (VUE3 && (H5 || APP-PLUS)) || APP-PLUS-NVUE
+  if (name.includes('?') || name.includes(';')) {
+    this.attrName = undefined
+    return
+  }
+  // #endif
+  if (name.substr(0, 5) === 'data-') {
+    if (name === 'data-src' && !this.attrs.src) {
+      // data-src 自动转为 src
+      this.attrName = 'src'
+    } else if (this.tagName === 'img' || this.tagName === 'a') {
+      // a 和 img 标签保留 data- 的属性,可以在 imgtap 和 linktap 事件中使用
+      this.attrName = name
+    } else {
+      // 剩余的移除以减小大小
+      this.attrName = undefined
+    }
+  } else {
+    this.attrName = name
+    this.attrs[name] = 'T' // boolean 型属性缺省设置
+  }
+}
+
+/**
+ * @description 解析到属性值
+ * @param {String} val 属性值
+ * @private
+ */
+Parser.prototype.onAttrVal = function (val) {
+  const name = this.attrName || ''
+  if (name === 'style' || name === 'href') {
+    // 部分属性进行实体解码
+    this.attrs[name] = decodeEntity(val, true)
+  } else if (name.includes('src')) {
+    // 拼接主域名
+    this.attrs[name] = this.getUrl(decodeEntity(val, true))
+  } else if (name) {
+    this.attrs[name] = val
+  }
+}
+
+/**
+ * @description 解析到标签开始
+ * @param {Boolean} selfClose 是否有自闭合标识 />
+ * @private
+ */
+Parser.prototype.onOpenTag = function (selfClose) {
+  // 拼装 node
+  const node = Object.create(null)
+  node.name = this.tagName
+  node.attrs = this.attrs
+  // 避免因为自动 diff 使得 type 被设置为 null 导致部分内容不显示
+  if (this.options.nodes.length) {
+    node.type = 'node'
+  }
+  this.attrs = Object.create(null)
+
+  const attrs = node.attrs
+  const parent = this.stack[this.stack.length - 1]
+  const siblings = parent ? parent.children : this.nodes
+  const close = this.xml ? selfClose : config.voidTags[node.name]
+
+  // 替换标签名选择器
+  if (tagSelector[node.name]) {
+    attrs.class = tagSelector[node.name] + (attrs.class ? ' ' + attrs.class : '')
+  }
+
+  // 转换 embed 标签
+  if (node.name === 'embed') {
+    // #ifndef H5 || APP-PLUS
+    const src = attrs.src || ''
+    // 按照后缀名和 type 将 embed 转为 video 或 audio
+    if (src.includes('.mp4') || src.includes('.3gp') || src.includes('.m3u8') || (attrs.type || '').includes('video')) {
+      node.name = 'video'
+    } else if (src.includes('.mp3') || src.includes('.wav') || src.includes('.aac') || src.includes('.m4a') || (attrs.type || '').includes('audio')) {
+      node.name = 'audio'
+    }
+    if (attrs.autostart) {
+      attrs.autoplay = 'T'
+    }
+    attrs.controls = 'T'
+    // #endif
+    // #ifdef H5 || APP-PLUS
+    this.expose()
+    // #endif
+  }
+
+  // #ifndef APP-PLUS-NVUE
+  // 处理音视频
+  if (node.name === 'video' || node.name === 'audio') {
+    // 设置 id 以便获取 context
+    if (node.name === 'video' && !attrs.id) {
+      attrs.id = 'v' + idIndex++
+    }
+    // 没有设置 controls 也没有设置 autoplay 的自动设置 controls
+    if (!attrs.controls && !attrs.autoplay) {
+      attrs.controls = 'T'
+    }
+    // 用数组存储所有可用的 source
+    node.src = []
+    if (attrs.src) {
+      node.src.push(attrs.src)
+      attrs.src = undefined
+    }
+    this.expose()
+  }
+  // #endif
+
+  // 处理自闭合标签
+  if (close) {
+    if (!this.hook(node) || config.ignoreTags[node.name]) {
+      // 通过 base 标签设置主域名
+      if (node.name === 'base' && !this.options.domain) {
+        this.options.domain = attrs.href
+      } /* #ifndef APP-PLUS-NVUE */ else if (node.name === 'source' && parent && (parent.name === 'video' || parent.name === 'audio') && attrs.src) {
+        // 设置 source 标签(仅父节点为 video 或 audio 时有效)
+        parent.src.push(attrs.src)
+      } /* #endif */
+      return
+    }
+
+    // 解析 style
+    const styleObj = this.parseStyle(node)
+
+    // 处理图片
+    if (node.name === 'img') {
+      if (attrs.src) {
+        // 标记 webp
+        if (attrs.src.includes('webp')) {
+          node.webp = 'T'
+        }
+        // data url 图片如果没有设置 original-src 默认为不可预览的小图片
+        if (attrs.src.includes('data:') && this.options.previewImg !== 'all' && !attrs['original-src']) {
+          attrs.ignore = 'T'
+        }
+        if (!attrs.ignore || node.webp || attrs.src.includes('cloud://')) {
+          for (let i = this.stack.length; i--;) {
+            const item = this.stack[i]
+            if (item.name === 'a') {
+              node.a = item.attrs
+            }
+            if (item.name === 'table' && !node.webp && !attrs.src.includes('cloud://')) {
+              if (!styleObj.display || styleObj.display.includes('inline')) {
+                node.t = 'inline-block'
+              } else {
+                node.t = styleObj.display
+              }
+              styleObj.display = undefined
+            }
+            // #ifndef H5 || APP-PLUS
+            const style = item.attrs.style || ''
+            if (style.includes('flex:') && !style.includes('flex:0') && !style.includes('flex: 0') && (!styleObj.width || parseInt(styleObj.width) > 100)) {
+              styleObj.width = '100% !important'
+              styleObj.height = ''
+              for (let j = i + 1; j < this.stack.length; j++) {
+                this.stack[j].attrs.style = (this.stack[j].attrs.style || '').replace('inline-', '')
+              }
+            } else if (style.includes('flex') && styleObj.width === '100%') {
+              for (let j = i + 1; j < this.stack.length; j++) {
+                const style = this.stack[j].attrs.style || ''
+                if (!style.includes(';width') && !style.includes(' width') && style.indexOf('width') !== 0) {
+                  styleObj.width = ''
+                  break
+                }
+              }
+            } else if (style.includes('inline-block')) {
+              if (styleObj.width && styleObj.width[styleObj.width.length - 1] === '%') {
+                item.attrs.style += ';max-width:' + styleObj.width
+                styleObj.width = ''
+              } else {
+                item.attrs.style += ';max-width:100%'
+              }
+            }
+            // #endif
+            item.c = 1
+          }
+          attrs.i = this.imgList.length.toString()
+          let src = attrs['original-src'] || attrs.src
+          // #ifndef H5 || MP-ALIPAY || APP-PLUS || MP-360
+          if (this.imgList.includes(src)) {
+            // 如果有重复的链接则对域名进行随机大小写变换避免预览时错位
+            let i = src.indexOf('://')
+            if (i !== -1) {
+              i += 3
+              let newSrc = src.substr(0, i)
+              for (; i < src.length; i++) {
+                if (src[i] === '/') break
+                newSrc += Math.random() > 0.5 ? src[i].toUpperCase() : src[i]
+              }
+              newSrc += src.substr(i)
+              src = newSrc
+            }
+          }
+          // #endif
+          this.imgList.push(src)
+          if (!node.t) {
+            this.imgList._unloadimgs += 1
+          }
+          // #ifdef H5 || APP-PLUS
+          if (this.options.lazyLoad) {
+            attrs['data-src'] = attrs.src
+            attrs.src = undefined
+          }
+          // #endif
+        }
+      }
+      if (styleObj.display === 'inline') {
+        styleObj.display = ''
+      }
+      // #ifndef APP-PLUS-NVUE
+      if (attrs.ignore) {
+        styleObj['max-width'] = styleObj['max-width'] || '100%'
+        attrs.style += ';-webkit-touch-callout:none'
+      }
+      // #endif
+      // 设置的宽度超出屏幕,为避免变形,高度转为自动
+      if (parseInt(styleObj.width) > windowWidth) {
+        styleObj.height = undefined
+      }
+      // 记录是否设置了宽高
+      if (!isNaN(parseInt(styleObj.width))) {
+        node.w = 'T'
+      }
+      if (!isNaN(parseInt(styleObj.height)) && (!styleObj.height.includes('%') || (parent && (parent.attrs.style || '').includes('height')))) {
+        node.h = 'T'
+      }
+      if (node.w && node.h && styleObj['object-fit']) {
+        if (styleObj['object-fit'] === 'contain') {
+          node.m = 'aspectFit'
+        } else if (styleObj['object-fit'] === 'cover') {
+          node.m = 'aspectFill'
+        }
+      }
+    } else if (node.name === 'svg') {
+      siblings.push(node)
+      this.stack.push(node)
+      this.popNode()
+      return
+    }
+    for (const key in styleObj) {
+      if (styleObj[key]) {
+        attrs.style += `;${key}:${styleObj[key].replace(' !important', '')}`
+      }
+    }
+    attrs.style = attrs.style.substr(1) || undefined
+    // #ifdef (MP-WEIXIN || MP-QQ) && VUE3
+    if (!attrs.style) {
+      delete attrs.style
+    }
+    // #endif
+  } else {
+    if ((node.name === 'pre' || ((attrs.style || '').includes('white-space') && attrs.style.includes('pre'))) && this.pre !== 2) {
+      this.pre = node.pre = 1
+    }
+    node.children = []
+    this.stack.push(node)
+  }
+
+  // 加入节点树
+  siblings.push(node)
+}
+
+/**
+ * @description 解析到标签结束
+ * @param {String} name 标签名
+ * @private
+ */
+Parser.prototype.onCloseTag = function (name) {
+  // 依次出栈到匹配为止
+  name = this.xml ? name : name.toLowerCase()
+  let i
+  for (i = this.stack.length; i--;) {
+    if (this.stack[i].name === name) break
+  }
+  if (i !== -1) {
+    while (this.stack.length > i) {
+      this.popNode()
+    }
+  } else if (name === 'p' || name === 'br') {
+    const siblings = this.stack.length ? this.stack[this.stack.length - 1].children : this.nodes
+    siblings.push({
+      name,
+      attrs: {
+        class: tagSelector[name] || '',
+        style: this.tagStyle[name] || ''
+      }
+    })
+  }
+}
+
+/**
+ * @description 处理标签出栈
+ * @private
+ */
+Parser.prototype.popNode = function () {
+  const node = this.stack.pop()
+  let attrs = node.attrs
+  const children = node.children
+  const parent = this.stack[this.stack.length - 1]
+  const siblings = parent ? parent.children : this.nodes
+
+  if (!this.hook(node) || config.ignoreTags[node.name]) {
+    // 获取标题
+    if (node.name === 'title' && children.length && children[0].type === 'text' && this.options.setTitle) {
+      uni.setNavigationBarTitle({
+        title: children[0].text
+      })
+    }
+    siblings.pop()
+    return
+  }
+
+  if (node.pre && this.pre !== 2) {
+    // 是否合并空白符标识
+    this.pre = node.pre = undefined
+    for (let i = this.stack.length; i--;) {
+      if (this.stack[i].pre) {
+        this.pre = 1
+      }
+    }
+  }
+
+  const styleObj = {}
+
+  // 转换 svg
+  if (node.name === 'svg') {
+    if (this.xml > 1) {
+      // 多层 svg 嵌套
+      this.xml--
+      return
+    }
+    // #ifdef APP-PLUS-NVUE
+    (function traversal (node) {
+      if (node.name) {
+        // 调整 svg 的大小写
+        node.name = config.svgDict[node.name] || node.name
+        for (const item in node.attrs) {
+          if (config.svgDict[item]) {
+            node.attrs[config.svgDict[item]] = node.attrs[item]
+            node.attrs[item] = undefined
+          }
+        }
+        for (let i = 0; i < (node.children || []).length; i++) {
+          traversal(node.children[i])
+        }
+      }
+    })(node)
+    // #endif
+    // #ifndef APP-PLUS-NVUE
+    let src = ''
+    const style = attrs.style
+    attrs.style = ''
+    attrs.xmlns = 'http://www.w3.org/2000/svg';
+    (function traversal (node) {
+      if (node.type === 'text') {
+        src += node.text
+        return
+      }
+      const name = config.svgDict[node.name] || node.name
+      if (name === 'foreignObject') {
+        for (const child of (node.children || [])) {
+          if (child.attrs && !child.attrs.xmlns) {
+            child.attrs.xmlns = 'http://www.w3.org/1999/xhtml'
+            break
+          }
+        }
+      }
+      src += '<' + name
+      for (const item in node.attrs) {
+        const val = node.attrs[item]
+        if (val) {
+          src += ` ${config.svgDict[item] || item}="${val.replace(/"/g, '')}"`
+        }
+      }
+      if (!node.children) {
+        src += '/>'
+      } else {
+        src += '>'
+        for (let i = 0; i < node.children.length; i++) {
+          traversal(node.children[i])
+        }
+        src += '</' + name + '>'
+      }
+    })(node)
+    node.name = 'img'
+    node.attrs = {
+      src: 'data:image/svg+xml;utf8,' + src.replace(/#/g, '%23'),
+      style,
+      ignore: 'T'
+    }
+    node.children = undefined
+    // #endif
+    this.xml = false
+    config.ignoreTags.style = true
+    return
+  }
+
+  // #ifndef APP-PLUS-NVUE
+  // 转换 align 属性
+  if (attrs.align) {
+    if (node.name === 'table') {
+      if (attrs.align === 'center') {
+        styleObj['margin-inline-start'] = styleObj['margin-inline-end'] = 'auto'
+      } else {
+        styleObj.float = attrs.align
+      }
+    } else {
+      styleObj['text-align'] = attrs.align
+    }
+    attrs.align = undefined
+  }
+
+  // 转换 dir 属性
+  if (attrs.dir) {
+    styleObj.direction = attrs.dir
+    attrs.dir = undefined
+  }
+
+  // 转换 font 标签的属性
+  if (node.name === 'font') {
+    if (attrs.color) {
+      styleObj.color = attrs.color
+      attrs.color = undefined
+    }
+    if (attrs.face) {
+      styleObj['font-family'] = attrs.face
+      attrs.face = undefined
+    }
+    if (attrs.size) {
+      let size = parseInt(attrs.size)
+      if (!isNaN(size)) {
+        if (size < 1) {
+          size = 1
+        } else if (size > 7) {
+          size = 7
+        }
+        styleObj['font-size'] = ['x-small', 'small', 'medium', 'large', 'x-large', 'xx-large', 'xxx-large'][size - 1]
+      }
+      attrs.size = undefined
+    }
+  }
+  // #endif
+
+  // 一些编辑器的自带 class
+  if ((attrs.class || '').includes('align-center')) {
+    styleObj['text-align'] = 'center'
+  }
+
+  Object.assign(styleObj, this.parseStyle(node))
+
+  if (node.name !== 'table' && parseInt(styleObj.width) > windowWidth) {
+    styleObj['max-width'] = '100%'
+    styleObj['box-sizing'] = 'border-box'
+  }
+
+  // #ifndef APP-PLUS-NVUE
+  if (config.blockTags[node.name]) {
+    node.name = 'div'
+  } else if (!config.trustTags[node.name] && !this.xml) {
+    // 未知标签转为 span,避免无法显示
+    node.name = 'span'
+  }
+
+  if (node.name === 'a' || node.name === 'ad'
+    // #ifdef H5 || APP-PLUS
+    || node.name === 'iframe' // eslint-disable-line
+    // #endif
+  ) {
+    this.expose()
+  } else if (node.name === 'video') {
+    if ((styleObj.height || '').includes('auto')) {
+      styleObj.height = undefined
+    }
+    /* #ifdef APP-PLUS */
+    let str = '<video style="width:100%;height:100%"'
+    for (const item in attrs) {
+      if (attrs[item]) {
+        str += ' ' + item + '="' + attrs[item] + '"'
+      }
+    }
+    if (this.options.pauseVideo) {
+      str += ' onplay="this.dispatchEvent(new CustomEvent(\'vplay\',{bubbles:!0}));for(var e=document.getElementsByTagName(\'video\'),t=0;t<e.length;t++)e[t]!=this&&e[t].pause()"'
+    }
+    str += '>'
+    for (let i = 0; i < node.src.length; i++) {
+      str += '<source src="' + node.src[i] + '">'
+    }
+    str += '</video>'
+    node.html = str
+    /* #endif */
+  } else if ((node.name === 'ul' || node.name === 'ol') && node.c) {
+    // 列表处理
+    const types = {
+      a: 'lower-alpha',
+      A: 'upper-alpha',
+      i: 'lower-roman',
+      I: 'upper-roman'
+    }
+    if (types[attrs.type]) {
+      attrs.style += ';list-style-type:' + types[attrs.type]
+      attrs.type = undefined
+    }
+    for (let i = children.length; i--;) {
+      if (children[i].name === 'li') {
+        children[i].c = 1
+      }
+    }
+  } else if (node.name === 'table') {
+    // 表格处理
+    // cellpadding、cellspacing、border 这几个常用表格属性需要通过转换实现
+    let padding = parseFloat(attrs.cellpadding)
+    let spacing = parseFloat(attrs.cellspacing)
+    const border = parseFloat(attrs.border)
+    const bordercolor = styleObj['border-color']
+    const borderstyle = styleObj['border-style']
+    if (node.c) {
+      // padding 和 spacing 默认 2
+      if (isNaN(padding)) {
+        padding = 2
+      }
+      if (isNaN(spacing)) {
+        spacing = 2
+      }
+    }
+    if (border) {
+      attrs.style += `;border:${border}px ${borderstyle || 'solid'} ${bordercolor || 'gray'}`
+    }
+    if (node.flag && node.c) {
+      // 有 colspan 或 rowspan 且含有链接的表格通过 grid 布局实现
+      styleObj.display = 'grid'
+      if (styleObj['border-collapse'] === 'collapse') {
+        styleObj['border-collapse'] = undefined
+        spacing = 0
+      }
+      if (spacing) {
+        styleObj['grid-gap'] = spacing + 'px'
+        styleObj.padding = spacing + 'px'
+      } else if (border) {
+        // 无间隔的情况下避免边框重叠
+        attrs.style += ';border-left:0;border-top:0'
+      }
+
+      const width = [] // 表格的列宽
+      const trList = [] // tr 列表
+      const cells = [] // 保存新的单元格
+      const map = {}; // 被合并单元格占用的格子
+
+      (function traversal (nodes) {
+        for (let i = 0; i < nodes.length; i++) {
+          if (nodes[i].name === 'tr') {
+            trList.push(nodes[i])
+          } else if (nodes[i].name === 'colgroup') {
+            let colI = 1
+            for (const col of (nodes[i].children || [])) {
+              if (col.name === 'col') {
+                const style = col.attrs.style || ''
+                const start = style.indexOf('width') ? style.indexOf(';width') : 0
+                // 提取出宽度
+                if (start !== -1) {
+                  let end = style.indexOf(';', start + 6)
+                  if (end === -1) {
+                    end = style.length
+                  }
+                  width[colI] = style.substring(start ? start + 7 : 6, end)
+                }
+                colI += 1
+              }
+            }
+          } else {
+            traversal(nodes[i].children || [])
+          }
+        }
+      })(children)
+
+      for (let row = 1; row <= trList.length; row++) {
+        let col = 1
+        for (let j = 0; j < trList[row - 1].children.length; j++) {
+          const td = trList[row - 1].children[j]
+          if (td.name === 'td' || td.name === 'th') {
+            // 这个格子被上面的单元格占用,则列号++
+            while (map[row + '.' + col]) {
+              col++
+            }
+            let style = td.attrs.style || ''
+            let start = style.indexOf('width') ? style.indexOf(';width') : 0
+            // 提取出 td 的宽度
+            if (start !== -1) {
+              let end = style.indexOf(';', start + 6)
+              if (end === -1) {
+                end = style.length
+              }
+              if (!td.attrs.colspan) {
+                width[col] = style.substring(start ? start + 7 : 6, end)
+              }
+              style = style.substr(0, start) + style.substr(end)
+            }
+            // 设置竖直对齐
+            style += ';display:flex'
+            start = style.indexOf('vertical-align')
+            if (start !== -1) {
+              const val = style.substr(start + 15, 10)
+              if (val.includes('middle')) {
+                style += ';align-items:center'
+              } else if (val.includes('bottom')) {
+                style += ';align-items:flex-end'
+              }
+            } else {
+              style += ';align-items:center'
+            }
+            // 设置水平对齐
+            start = style.indexOf('text-align')
+            if (start !== -1) {
+              const val = style.substr(start + 11, 10)
+              if (val.includes('center')) {
+                style += ';justify-content: center'
+              } else if (val.includes('right')) {
+                style += ';justify-content: right'
+              }
+            }
+            style = (border ? `;border:${border}px ${borderstyle || 'solid'} ${bordercolor || 'gray'}` + (spacing ? '' : ';border-right:0;border-bottom:0') : '') + (padding ? `;padding:${padding}px` : '') + ';' + style
+            // 处理列合并
+            if (td.attrs.colspan) {
+              style += `;grid-column-start:${col};grid-column-end:${col + parseInt(td.attrs.colspan)}`
+              if (!td.attrs.rowspan) {
+                style += `;grid-row-start:${row};grid-row-end:${row + 1}`
+              }
+              col += parseInt(td.attrs.colspan) - 1
+            }
+            // 处理行合并
+            if (td.attrs.rowspan) {
+              style += `;grid-row-start:${row};grid-row-end:${row + parseInt(td.attrs.rowspan)}`
+              if (!td.attrs.colspan) {
+                style += `;grid-column-start:${col};grid-column-end:${col + 1}`
+              }
+              // 记录下方单元格被占用
+              for (let rowspan = 1; rowspan < td.attrs.rowspan; rowspan++) {
+                for (let colspan = 0; colspan < (td.attrs.colspan || 1); colspan++) {
+                  map[(row + rowspan) + '.' + (col - colspan)] = 1
+                }
+              }
+            }
+            if (style) {
+              td.attrs.style = style
+            }
+            cells.push(td)
+            col++
+          }
+        }
+        if (row === 1) {
+          let temp = ''
+          for (let i = 1; i < col; i++) {
+            temp += (width[i] ? width[i] : 'auto') + ' '
+          }
+          styleObj['grid-template-columns'] = temp
+        }
+      }
+      node.children = cells
+    } else {
+      // 没有使用合并单元格的表格通过 table 布局实现
+      if (node.c) {
+        styleObj.display = 'table'
+      }
+      if (!isNaN(spacing)) {
+        styleObj['border-spacing'] = spacing + 'px'
+      }
+      if (border || padding) {
+        // 遍历
+        (function traversal (nodes) {
+          for (let i = 0; i < nodes.length; i++) {
+            const td = nodes[i]
+            if (td.name === 'th' || td.name === 'td') {
+              if (border) {
+                td.attrs.style = `border:${border}px ${borderstyle || 'solid'} ${bordercolor || 'gray'};${td.attrs.style || ''}`
+              }
+              if (padding) {
+                td.attrs.style = `padding:${padding}px;${td.attrs.style || ''}`
+              }
+            } else if (td.children) {
+              traversal(td.children)
+            }
+          }
+        })(children)
+      }
+    }
+    // 给表格添加一个单独的横向滚动层
+    if (this.options.scrollTable && !(attrs.style || '').includes('inline')) {
+      const table = Object.assign({}, node)
+      node.name = 'div'
+      node.attrs = {
+        style: 'overflow:auto'
+      }
+      node.children = [table]
+      attrs = table.attrs
+    }
+  } else if ((node.name === 'tbody' || node.name === 'tr') && node.flag && node.c) {
+    node.flag = undefined;
+    (function traversal (nodes) {
+      for (let i = 0; i < nodes.length; i++) {
+        if (nodes[i].name === 'td') {
+          // 颜色样式设置给单元格避免丢失
+          for (const style of ['color', 'background', 'background-color']) {
+            if (styleObj[style]) {
+              nodes[i].attrs.style = style + ':' + styleObj[style] + ';' + (nodes[i].attrs.style || '')
+            }
+          }
+        } else {
+          traversal(nodes[i].children || [])
+        }
+      }
+    })(children)
+  } else if ((node.name === 'td' || node.name === 'th') && (attrs.colspan || attrs.rowspan)) {
+    for (let i = this.stack.length; i--;) {
+      if (this.stack[i].name === 'table' || this.stack[i].name === 'tbody' || this.stack[i].name === 'tr') {
+        this.stack[i].flag = 1 // 指示含有合并单元格
+      }
+    }
+  } else if (node.name === 'ruby') {
+    // 转换 ruby
+    node.name = 'span'
+    for (let i = 0; i < children.length - 1; i++) {
+      if (children[i].type === 'text' && children[i + 1].name === 'rt') {
+        children[i] = {
+          name: 'div',
+          attrs: {
+            style: 'display:inline-block;text-align:center'
+          },
+          children: [{
+            name: 'div',
+            attrs: {
+              style: 'font-size:50%;' + (children[i + 1].attrs.style || '')
+            },
+            children: children[i + 1].children
+          }, children[i]]
+        }
+        children.splice(i + 1, 1)
+      }
+    }
+  } else if (node.c) {
+    (function traversal (node) {
+      node.c = 2
+      for (let i = node.children.length; i--;) {
+        const child = node.children[i]
+        // #ifdef (MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE3
+        if (child.name && (config.inlineTags[child.name] || ((child.attrs.style || '').includes('inline') && child.children)) && !child.c) {
+          traversal(child)
+        }
+        // #endif
+        if (!child.c || child.name === 'table') {
+          node.c = 1
+        }
+      }
+    })(node)
+  }
+
+  if ((styleObj.display || '').includes('flex') && !node.c) {
+    for (let i = children.length; i--;) {
+      const item = children[i]
+      if (item.f) {
+        item.attrs.style = (item.attrs.style || '') + item.f
+        item.f = undefined
+      }
+    }
+  }
+  // flex 布局时部分样式需要提取到 rich-text 外层
+  const flex = parent && ((parent.attrs.style || '').includes('flex') || (parent.attrs.style || '').includes('grid'))
+    // #ifdef MP-WEIXIN
+    // 检查基础库版本 virtualHost 是否可用
+    && !(node.c && wx.getNFCAdapter) // eslint-disable-line
+    // #endif
+    // #ifndef MP-WEIXIN || MP-QQ || MP-BAIDU || MP-TOUTIAO
+    && !node.c // eslint-disable-line
+  // #endif
+  if (flex) {
+    node.f = ';max-width:100%'
+  }
+
+  if (children.length >= 50 && node.c && !(styleObj.display || '').includes('flex')) {
+    mergeNodes(children)
+  }
+  // #endif
+
+  for (const key in styleObj) {
+    if (styleObj[key]) {
+      const val = `;${key}:${styleObj[key].replace(' !important', '')}`
+      /* #ifndef APP-PLUS-NVUE */
+      if (flex && ((key.includes('flex') && key !== 'flex-direction') || key === 'align-self' || key.includes('grid') || styleObj[key][0] === '-' || (key.includes('width') && val.includes('%')))) {
+        node.f += val
+        if (key === 'width') {
+          attrs.style += ';width:100%'
+        }
+      } else /* #endif */ {
+        attrs.style += val
+      }
+    }
+  }
+  attrs.style = attrs.style.substr(1) || undefined
+  // #ifdef (MP-WEIXIN || MP-QQ) && VUE3
+  for (const key in attrs) {
+    if (!attrs[key]) {
+      delete attrs[key]
+    }
+  }
+  // #endif
+}
+
+/**
+ * @description 解析到文本
+ * @param {String} text 文本内容
+ */
+Parser.prototype.onText = function (text) {
+  if (!this.pre) {
+    // 合并空白符
+    let trim = ''
+    let flag
+    for (let i = 0, len = text.length; i < len; i++) {
+      if (!blankChar[text[i]]) {
+        trim += text[i]
+      } else {
+        if (trim[trim.length - 1] !== ' ') {
+          trim += ' '
+        }
+        if (text[i] === '\n' && !flag) {
+          flag = true
+        }
+      }
+    }
+    // 去除含有换行符的空串
+    if (trim === ' ') {
+      if (flag) return
+      // #ifdef VUE3
+      else {
+        const parent = this.stack[this.stack.length - 1]
+        if (parent && parent.name[0] === 't') return
+      }
+      // #endif
+    }
+    text = trim
+  }
+  const node = Object.create(null)
+  node.type = 'text'
+  // #ifdef (MP-BAIDU || MP-ALIPAY || MP-TOUTIAO) && VUE3
+  node.attrs = {}
+  // #endif
+  node.text = decodeEntity(text)
+  if (this.hook(node)) {
+    // #ifdef MP-WEIXIN
+    if (this.options.selectable === 'force' && system.includes('iOS') && !uni.canIUse('rich-text.user-select')) {
+      this.expose()
+    }
+    // #endif
+    const siblings = this.stack.length ? this.stack[this.stack.length - 1].children : this.nodes
+    siblings.push(node)
+  }
+}
+
+/**
+ * @description html 词法分析器
+ * @param {Object} handler 高层处理器
+ */
+function Lexer (handler) {
+  this.handler = handler
+}
+
+/**
+ * @description 执行解析
+ * @param {String} content 要解析的文本
+ */
+Lexer.prototype.parse = function (content) {
+  this.content = content || ''
+  this.i = 0 // 标记解析位置
+  this.start = 0 // 标记一个单词的开始位置
+  this.state = this.text // 当前状态
+  for (let len = this.content.length; this.i !== -1 && this.i < len;) {
+    this.state()
+  }
+}
+
+/**
+ * @description 检查标签是否闭合
+ * @param {String} method 如果闭合要进行的操作
+ * @returns {Boolean} 是否闭合
+ * @private
+ */
+Lexer.prototype.checkClose = function (method) {
+  const selfClose = this.content[this.i] === '/'
+  if (this.content[this.i] === '>' || (selfClose && this.content[this.i + 1] === '>')) {
+    if (method) {
+      this.handler[method](this.content.substring(this.start, this.i))
+    }
+    this.i += selfClose ? 2 : 1
+    this.start = this.i
+    this.handler.onOpenTag(selfClose)
+    if (this.handler.tagName === 'script') {
+      this.i = this.content.indexOf('</', this.i)
+      if (this.i !== -1) {
+        this.i += 2
+        this.start = this.i
+      }
+      this.state = this.endTag
+    } else {
+      this.state = this.text
+    }
+    return true
+  }
+  return false
+}
+
+/**
+ * @description 文本状态
+ * @private
+ */
+Lexer.prototype.text = function () {
+  this.i = this.content.indexOf('<', this.i) // 查找最近的标签
+  if (this.i === -1) {
+    // 没有标签了
+    if (this.start < this.content.length) {
+      this.handler.onText(this.content.substring(this.start, this.content.length))
+    }
+    return
+  }
+  const c = this.content[this.i + 1]
+  if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
+    // 标签开头
+    if (this.start !== this.i) {
+      this.handler.onText(this.content.substring(this.start, this.i))
+    }
+    this.start = ++this.i
+    this.state = this.tagName
+  } else if (c === '/' || c === '!' || c === '?') {
+    if (this.start !== this.i) {
+      this.handler.onText(this.content.substring(this.start, this.i))
+    }
+    const next = this.content[this.i + 2]
+    if (c === '/' && ((next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z'))) {
+      // 标签结尾
+      this.i += 2
+      this.start = this.i
+      this.state = this.endTag
+      return
+    }
+    // 处理注释
+    let end = '-->'
+    if (c !== '!' || this.content[this.i + 2] !== '-' || this.content[this.i + 3] !== '-') {
+      end = '>'
+    }
+    this.i = this.content.indexOf(end, this.i)
+    if (this.i !== -1) {
+      this.i += end.length
+      this.start = this.i
+    }
+  } else {
+    this.i++
+  }
+}
+
+/**
+ * @description 标签名状态
+ * @private
+ */
+Lexer.prototype.tagName = function () {
+  if (blankChar[this.content[this.i]]) {
+    // 解析到标签名
+    this.handler.onTagName(this.content.substring(this.start, this.i))
+    while (blankChar[this.content[++this.i]]);
+    if (this.i < this.content.length && !this.checkClose()) {
+      this.start = this.i
+      this.state = this.attrName
+    }
+  } else if (!this.checkClose('onTagName')) {
+    this.i++
+  }
+}
+
+/**
+ * @description 属性名状态
+ * @private
+ */
+Lexer.prototype.attrName = function () {
+  let c = this.content[this.i]
+  if (blankChar[c] || c === '=') {
+    // 解析到属性名
+    this.handler.onAttrName(this.content.substring(this.start, this.i))
+    let needVal = c === '='
+    const len = this.content.length
+    while (++this.i < len) {
+      c = this.content[this.i]
+      if (!blankChar[c]) {
+        if (this.checkClose()) return
+        if (needVal) {
+          // 等号后遇到第一个非空字符
+          this.start = this.i
+          this.state = this.attrVal
+          return
+        }
+        if (this.content[this.i] === '=') {
+          needVal = true
+        } else {
+          this.start = this.i
+          this.state = this.attrName
+          return
+        }
+      }
+    }
+  } else if (!this.checkClose('onAttrName')) {
+    this.i++
+  }
+}
+
+/**
+ * @description 属性值状态
+ * @private
+ */
+Lexer.prototype.attrVal = function () {
+  const c = this.content[this.i]
+  const len = this.content.length
+  if (c === '"' || c === "'") {
+    // 有冒号的属性
+    this.start = ++this.i
+    this.i = this.content.indexOf(c, this.i)
+    if (this.i === -1) return
+    this.handler.onAttrVal(this.content.substring(this.start, this.i))
+  } else {
+    // 没有冒号的属性
+    for (; this.i < len; this.i++) {
+      if (blankChar[this.content[this.i]]) {
+        this.handler.onAttrVal(this.content.substring(this.start, this.i))
+        break
+      } else if (this.checkClose('onAttrVal')) return
+    }
+  }
+  while (blankChar[this.content[++this.i]]);
+  if (this.i < len && !this.checkClose()) {
+    this.start = this.i
+    this.state = this.attrName
+  }
+}
+
+/**
+ * @description 结束标签状态
+ * @returns {String} 结束的标签名
+ * @private
+ */
+Lexer.prototype.endTag = function () {
+  const c = this.content[this.i]
+  if (blankChar[c] || c === '>' || c === '/') {
+    this.handler.onCloseTag(this.content.substring(this.start, this.i))
+    if (c !== '>') {
+      this.i = this.content.indexOf('>', this.i)
+      if (this.i === -1) return
+    }
+    this.start = ++this.i
+    this.state = this.text
+  } else {
+    this.i++
+  }
+}
+
+export default Parser

+ 76 - 0
uni_modules/mp-html/package.json

@@ -0,0 +1,76 @@
+{
+    "id": "mp-html",
+    "displayName": "mp-html 富文本组件【全端支持,支持编辑、latex等扩展】",
+    "version": "v2.5.0",
+    "description": "一个强大的富文本组件,高效轻量,功能丰富",
+    "keywords": [
+        "富文本",
+        "编辑器",
+        "html",
+        "rich-text",
+        "editor"
+    ],
+    "repository": "https://github.com/jin-yufeng/mp-html",
+    "dcloudext": {
+        "sale": {
+            "regular": {
+                "price": "0.00"
+            },
+            "sourcecode": {
+                "price": "0.00"
+            }
+        },
+        "contact": {
+            "qq": ""
+        },
+        "declaration": {
+            "ads": "无",
+            "data": "无",
+            "permissions": "无"
+        },
+        "npmurl": "https://www.npmjs.com/package/mp-html",
+        "type": "component-vue"
+    },
+    "uni_modules": {
+        "platforms": {
+            "cloud": {
+                "tcb": "y",
+                "aliyun": "y"
+            },
+            "client": {
+                "App": {
+                    "app-vue": "y",
+                    "app-nvue": "y"
+                },
+                "H5-mobile": {
+                    "Safari": "y",
+                    "Android Browser": "y",
+                    "微信浏览器(Android)": "y",
+                    "QQ浏览器(Android)": "y"
+                },
+                "H5-pc": {
+                    "Chrome": "y",
+                    "IE": "u",
+                    "Edge": "y",
+                    "Firefox": "y",
+                    "Safari": "y"
+                },
+                "小程序": {
+                    "微信": "y",
+                    "阿里": "y",
+                    "百度": "y",
+                    "字节跳动": "y",
+                    "QQ": "y"
+                },
+                "快应用": {
+                    "华为": "y",
+                    "联盟": "y"
+                },
+                "Vue": {
+                    "vue2": "y",
+                    "vue3": "y"
+                }
+            }
+        }
+    }
+}

Різницю між файлами не показано, бо вона завелика
+ 0 - 0
uni_modules/mp-html/static/app-plus/mp-html/js/handler.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 0
uni_modules/mp-html/static/app-plus/mp-html/js/uni.webview.min.js


+ 1 - 0
uni_modules/mp-html/static/app-plus/mp-html/local.html

@@ -0,0 +1 @@
+<head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"><style>body,html{width:100%;height:100%;overflow-x:scroll;overflow-y:hidden}body{margin:0}video{width:300px;height:225px}img{max-width:100%;-webkit-touch-callout:none}</style></head><body><div id="content" style="overflow:hidden"></div><script type="text/javascript" src="./js/uni.webview.min.js"></script><script type="text/javascript" src="./js/handler.js"></script></body>

+ 74 - 0
uni_modules/qiun-data-charts/changelog.md

@@ -1,3 +1,77 @@
+## 2.5.0-20230101(2023-01-01)
+- 秋云图表组件 修改条件编译顺序,确保uniapp的cli方式的项目依赖不完整时可以正常显示
+- 秋云图表组件 恢复props属性directory的使用,以修复vue3项目中,开启echarts后,echarts目录识别错误的bug
+- uCharts.js 修复区域图、混合图只有一个数据时图表显示不正确的bug
+- uCharts.js 修复折线图、区域图中时间轴类别图表tooltip指示点显示不正确的bug
+- uCharts.js 修复x轴使用labelCount时,并且boundaryGap = 'justify' 并且关闭Y轴显示的时候,最后一个坐标值不显示的bug
+- uCharts.js 修复折线图只有一组数据时 ios16 渲染颜色不正确的bug
+- uCharts.js 修复玫瑰图半径显示不正确的bug
+- uCharts.js 柱状图、山峰图增加正负图功能,y轴网格如果需要显示0轴则由 min max 及 splitNumber 确定,后续版本优化自动显示0轴
+- uCharts.js 柱状图column增加 opts.extra.column.labelPosition,数据标签位置,有效值为 outside外部, insideTop内顶部, center内中间, bottom内底部
+- uCharts.js 雷达图radar增加 opts.extra.radar.labelShow,否显示各项标识文案是,默认true
+- uCharts.js 提示窗tooltip增加 opts.extra.tooltip.boxPadding,提示窗边框填充距离,默认3px
+- uCharts.js 提示窗tooltip增加 opts.extra.tooltip.fontSize,提示窗字体大小配置,默认13px
+- uCharts.js 提示窗tooltip增加 opts.extra.tooltip.lineHeight,提示窗文字行高,默认20px
+- uCharts.js 提示窗tooltip增加 opts.extra.tooltip.legendShow,是否显示左侧图例,默认true
+- uCharts.js 提示窗tooltip增加 opts.extra.tooltip.legendShape,图例形状,图例标识样式,有效值为 auto自动跟随图例, diamond◆, circle●, triangle▲, square■, rect▬, line-
+- uCharts.js 标记线markLine增加 opts.extra.markLine.labelFontSize,字体大小配置,默认13px
+- uCharts.js 标记线markLine增加 opts.extra.markLine.labelPadding,标签边框内填充距离,默认6px
+- uCharts.js 折线图line增加 opts.extra.line.linearType,渐变色类型,可选值 none关闭渐变色,custom 自定义渐变色。使用自定义渐变色时请赋值serie.linearColor作为颜色值
+- uCharts.js 折线图line增加 serie.linearColor,渐变色数组,格式为2维数组[起始位置,颜色值],例如[[0,'#0EE2F8'],[0.3,'#2BDCA8'],[0.6,'#1890FF'],[1,'#9A60B4']]
+- uCharts.js 折线图line增加 opts.extra.line.onShadow,是否开启折线阴影,开启后请赋值serie.setShadow阴影设置
+- uCharts.js 折线图line增加 serie.setShadow,阴影配置,格式为4位数组:[offsetX,offsetY,blur,color]
+- uCharts.js 折线图line增加 opts.extra.line.animation,动画效果方向,可选值为vertical 垂直动画效果,horizontal 水平动画效果
+- uCharts.js X轴xAxis增加 opts.xAxis.lineHeight,X轴字体行高,默认20px
+- uCharts.js X轴xAxis增加 opts.xAxis.marginTop,X轴文字距离轴线的距离,默认0px
+- uCharts.js X轴xAxis增加 opts.xAxis.title,当前X轴标题
+- uCharts.js X轴xAxis增加 opts.xAxis.titleFontSize,标题字体大小,默认13px
+- uCharts.js X轴xAxis增加 opts.xAxis.titleOffsetY,标题纵向偏移距离,负数为向上偏移,正数向下偏移
+- uCharts.js X轴xAxis增加 opts.xAxis.titleOffsetX,标题横向偏移距离,负数为向左偏移,正数向右偏移
+- uCharts.js X轴xAxis增加 opts.xAxis.titleFontColor,标题字体颜色,默认#666666
+
+## 报错TypeError: Cannot read properties of undefined (reading 'length')
+- 如果是uni-modules版本组件,请先登录HBuilderX账号;
+- 在HBuilderX中的manifest.json,点击重新获取uniapp的appid,或者删除appid重新粘贴,重新运行;
+- 如果是cli项目请使用码云上的非uniCloud版本组件;
+- 或者添加uniCloud的依赖;
+- 或者使用原生uCharts;
+## 2.4.5-20221130(2022-11-30)
+- uCharts.js 优化tooltip当文字很多变为左侧显示时,如果画布仍显显示不下,提示框错位置变为以左侧0位置起画
+- uCharts.js 折线图修复特殊情况下只有单点数据,并改变线宽后点变为圆形的bug
+- uCharts.js 修复Y轴disabled启用后无效并报错的bug
+- uCharts.js 修复仪表盘起始结束角度特殊情况下显示不正确的bug
+- uCharts.js 雷达图新增参数 opts.extra.radar.radius , 自定义雷达图半径
+- uCharts.js 折线图、区域图增加tooltip指示点,opts.extra.line.activeType/opts.extra.area.activeType,可选值"none"不启用激活指示点,"hollow"空心点模式,"solid"实心点模式
+## 2.4.4-20221102(2022-11-02)
+- 秋云图表组件 修复使用echarts时reload、reshow无法调用重新渲染的bug,[详见码云PR](https://gitee.com/uCharts/uCharts/pulls/40)
+- 秋云图表组件 修复使用echarts时,初始化时宽高不正确的bug,[详见码云PR](https://gitee.com/uCharts/uCharts/pulls/42)
+- 秋云图表组件 修复uniapp的h5使用history模式时,无法加载echarts的bug
+- 秋云图表组件 小程序端@complete、@scrollLeft、@scrollRight、@getTouchStart、@getTouchMove、@getTouchEnd事件增加opts参数传出,方便一些特殊需求的交互获取数据。
+
+- uCharts.js 修复calTooltipYAxisData方法内formatter格式化方法未与y轴方法同步的问题,[详见码云PR](https://gitee.com/uCharts/uCharts/pulls/43)
+- uCharts.js 地图新增参数opts.series[i].fillOpacity,以透明度方式来设置颜色过度效果,[详见码云PR](https://gitee.com/uCharts/uCharts/pulls/38)
+- uCharts.js 地图新增参数opts.extra.map.active,是否启用点击激活变色
+- uCharts.js 地图新增参数opts.extra.map.activeTextColor,是否启用点击激活变色
+- uCharts.js 地图新增渲染完成事件renderComplete
+- uCharts.js 漏斗图修复当部分数据相同时tooltip提示窗点击错误的bug
+- uCharts.js 漏斗图新增参数series.data[i].centerText 居中标签文案
+- uCharts.js 漏斗图新增参数series.data[i].centerTextSize 居中标签文案字体大小,默认opts.fontSize
+- uCharts.js 漏斗图新增参数series.data[i].centerTextColor 居中标签文案字体颜色,默认#FFFFFF
+- uCharts.js 漏斗图新增参数opts.extra.funnel.minSize 最小值的最小宽度,默认0
+- uCharts.js 进度条新增参数opts.extra.arcbar.direction,动画方向,可选值为cw顺时针、ccw逆时针
+- uCharts.js 混合图新增参数opts.extra.mix.line.width,折线的宽度,默认2
+- uCharts.js 修复tooltip开启horizentalLine水平横线标注时,图表显示错位的bug
+- uCharts.js 优化tooltip当文字很多变为左侧显示时,如果画布仍显显示不下,提示框错位置变为以左侧0位置起画
+- uCharts.js 修复开启滚动条后X轴文字超出绘图区域后的隐藏逻辑
+- uCharts.js 柱状图、条状图修复堆叠模式不能通过{value,color}赋值单个柱子颜色的问题
+- uCharts.js 气泡图修复不识别series.textSize和series.textColor的bug
+
+## 报错TypeError: Cannot read properties of undefined (reading 'length')
+1. 如果是uni-modules版本组件,请先登录HBuilderX账号;
+2. 在HBuilderX中的manifest.json,点击重新获取uniapp的appid,或者删除appid重新粘贴,重新运行;
+3. 如果是cli项目请使用码云上的非uniCloud版本组件;
+4. 或者添加uniCloud的依赖;
+5. 或者使用原生uCharts;
 ## 2.4.3-20220505(2022-05-05)
 - 秋云图表组件 修复开启canvas2d后将series赋值为空数组显示加载图标时,再次赋值后画布闪动的bug
 - 秋云图表组件 修复升级hbx最新版后ECharts的highlight方法报错的bug

+ 37 - 26
uni_modules/qiun-data-charts/components/qiun-data-charts/qiun-data-charts.vue

@@ -97,7 +97,7 @@
     </block>
     <!-- #endif -->
     <!-- 其他小程序通过vue渲染图表 -->
-    <!-- #ifdef MP-360 || MP-BAIDU || MP-QQ || MP-TOUTIAO || MP-WEIXIN || MP-KUAISHOU || MP-LARK || MP-JD -->
+    <!-- #ifdef MP-WEIXIN || MP-BAIDU || MP-QQ || MP-TOUTIAO || MP-KUAISHOU || MP-LARK || MP-JD || MP-360 -->
     <block v-if="type2d">
       <view v-if="ontouch" @tap="_tap">
         <canvas
@@ -407,7 +407,9 @@ export default {
       cHeight: 250,
       showchart: false,
       echarts: false,
-      echartsResize:false,
+      echartsResize:{
+        state:false
+      },
       uchartsOpts: {},
       echartsOpts: {},
       drawData:{},
@@ -495,7 +497,7 @@ export default {
           return;
         }
         if (_this.echarts) {
-          _this.echartsResize = !_this.echartsResize;
+          _this.echartsResize.state = !_this.echartsResize.state;
         } else {
           _this.resizeHandler();
         }
@@ -590,7 +592,7 @@ export default {
       if (val === true && this.mixinDatacomLoading === false) {
         setTimeout(() => {
           this.mixinDatacomErrorMessage = null;
-          this.echartsResize = !this.echartsResize;
+          this.echartsResize.state = !this.echartsResize.state;
           this.checkData(this.drawData);
         }, 200);
       }
@@ -863,10 +865,10 @@ export default {
     },
     _clearChart() {
       let cid = this.cid
-      if (this.echrts !== true && cfu.option[cid] && cfu.option[cid].context) {
+      if (this.echarts !== true && cfu.option[cid] && cfu.option[cid].context) {
         const ctx = cfu.option[cid].context;
-        if(typeof ctx === "object" && !cfu.option[cid].update){
-          ctx.clearRect(0, 0, this.cWidth, this.cHeight);
+        if(typeof ctx === "object" && !!!cfu.option[cid].update){
+          ctx.clearRect(0, 0, this.cWidth*this.pixel, this.cHeight*this.pixel);
           ctx.draw();
         }
       }
@@ -1036,14 +1038,14 @@ export default {
       this.showchart = true;
       cfu.instance[cid] = new uCharts(cfu.option[cid]);
       cfu.instance[cid].addEventListener('renderComplete', () => {
-        this.emitMsg({name: 'complete', params: {type:"complete", complete: true, id: cid}});
+        this.emitMsg({name: 'complete', params: {type:"complete", complete: true, id: cid, opts: cfu.instance[cid].opts}});
         cfu.instance[cid].delEventListener('renderComplete')
       });
       cfu.instance[cid].addEventListener('scrollLeft', () => {
-        this.emitMsg({name: 'scrollLeft', params: {type:"scrollLeft", scrollLeft: true, id: cid}});
+        this.emitMsg({name: 'scrollLeft', params: {type:"scrollLeft", scrollLeft: true, id: cid, opts: cfu.instance[cid].opts}});
       });
       cfu.instance[cid].addEventListener('scrollRight', () => {
-        this.emitMsg({name: 'scrollRight', params: {type:"scrollRight", scrollRight: true, id: cid}});
+        this.emitMsg({name: 'scrollRight', params: {type:"scrollRight", scrollRight: true, id: cid, opts: cfu.instance[cid].opts}});
       });
     },
     _updataUChart(cid) {
@@ -1160,7 +1162,7 @@ export default {
       if(cfu.option[cid].enableScroll === true && e.touches.length == 1){
         cfu.instance[cid].scrollStart(e);
       }
-      this.emitMsg({name:'getTouchStart', params:{type:"touchStart", event:e.changedTouches[0], id:cid}});
+      this.emitMsg({name:'getTouchStart', params:{type:"touchStart", event:e.changedTouches[0], id:cid, opts: cfu.instance[cid].opts}});
     },
     _touchMove(e) {
       let cid = this.cid
@@ -1178,14 +1180,14 @@ export default {
       if(this.ontouch === true && cfu.option[cid].enableScroll === true && this.onzoom === true && e.changedTouches.length == 2){
         cfu.instance[cid].dobuleZoom(e);
       }
-      this.emitMsg({name: 'getTouchMove', params: {type:"touchMove", event:e.changedTouches[0], id: cid}});
+      this.emitMsg({name: 'getTouchMove', params: {type:"touchMove", event:e.changedTouches[0], id: cid, opts: cfu.instance[cid].opts}});
     },
     _touchEnd(e) {
       let cid = this.cid
       if(cfu.option[cid].enableScroll === true && e.touches.length == 0){
         cfu.instance[cid].scrollEnd(e);
       }
-      this.emitMsg({name:'getTouchEnd', params:{type:"touchEnd", event:e.changedTouches[0], id:cid}});
+      this.emitMsg({name:'getTouchEnd', params:{type:"touchEnd", event:e.changedTouches[0], id:cid, opts: cfu.instance[cid].opts}});
       if(this.ontap === true && cfu.option[cid].enableScroll === false && this.onmovetip === true){
         this._tap(e,true)
       }
@@ -1307,9 +1309,9 @@ export default {
         script.src = './uni_modules/qiun-data-charts/static/app-plus/echarts.min.js'
         // #endif
         // #ifdef H5
-        const { origin, pathname } = window.location
-        const rooturl = origin + pathname
-        script.src = rooturl + 'uni_modules/qiun-data-charts/static/h5/echarts.min.js'
+        const rooturl = window.location.origin
+        const directory = instance.getDataset().directory
+        script.src = rooturl + directory + 'uni_modules/qiun-data-charts/static/h5/echarts.min.js'
         // #endif
         script.onload = this.newEChart
         document.head.appendChild(script)
@@ -1368,7 +1370,16 @@ export default {
         if(cfe.instance[cid]){
           cfe.instance[cid].off('finished')
         }
-      })
+      });
+
+      //修复init初始化实例获取宽高不正确问题
+      if(
+        typeof that[cid].$el.children[0].clientWidth != 'undefined' &&
+          (
+            Math.abs( that[cid].$el.children[0].clientWidth - cfe.instance[cid].getWidth() )>3 ||
+            Math.abs( that[cid].$el.children[0].clientHeight - cfe.instance[cid].getHeight() )>3
+          )
+      ){this.ecresize();}
     },
     tooltipPosition(){
       return (point, params, dom, rect, size) => {
@@ -1420,14 +1431,14 @@ export default {
       let cid = this.rid
       cfu.instance[cid] = new uChartsRD(cfu.option[cid])
       cfu.instance[cid].addEventListener('renderComplete', () => {
-        that[cid].callMethod('emitMsg',{name:"complete",params:{type:"complete",complete:true,id:cid}})
+        that[cid].callMethod('emitMsg',{name:"complete",params:{type:"complete",complete:true,id:cid, opts: cfu.instance[cid].opts}})
         cfu.instance[cid].delEventListener('renderComplete')
       });
       cfu.instance[cid].addEventListener('scrollLeft', () => {
-        that[cid].callMethod('emitMsg',{name:"scrollLeft",params:{type:"scrollLeft",scrollLeft:true,id:cid}})
+        that[cid].callMethod('emitMsg',{name:"scrollLeft",params:{type:"scrollLeft",scrollLeft:true,id:cid, opts: cfu.instance[cid].opts}})
       });
       cfu.instance[cid].addEventListener('scrollRight', () => {
-        that[cid].callMethod('emitMsg',{name:"scrollRight",params:{type:"scrollRight",scrollRight:true,id:cid}})
+        that[cid].callMethod('emitMsg',{name:"scrollRight",params:{type:"scrollRight",scrollRight:true,id:cid, opts: cfu.instance[cid].opts}})
       });
     },
     updataUChart() {
@@ -1514,7 +1525,7 @@ export default {
       if(cfu.option[cid].enableScroll === true && e.touches.length == 1){
         cfu.instance[cid].scrollStart(e);
       }
-      that[cid].callMethod('emitMsg',{name:"getTouchStart",params:{type:"touchStart",event:e.changedTouches[0],id:cid}})
+      that[cid].callMethod('emitMsg',{name:"getTouchStart",params:{type:"touchStart",event:e.changedTouches[0],id:cid, opts: cfu.instance[cid].opts}})
     },
     touchMove(e) {
       let cid = this.rid
@@ -1534,7 +1545,7 @@ export default {
       if(ontouch === true && cfu.option[cid].enableScroll === true && cfu.option[cid].onzoom === true && e.changedTouches.length == 2){
         cfu.instance[cid].dobuleZoom(e);
       }
-      that[cid].callMethod('emitMsg',{name:"getTouchMove",params:{type:"touchMove",event:e.changedTouches[0],id:cid}})
+      that[cid].callMethod('emitMsg',{name:"getTouchMove",params:{type:"touchMove",event:e.changedTouches[0],id:cid, opts: cfu.instance[cid].opts}})
     },
     touchEnd(e) {
       let cid = this.rid
@@ -1543,7 +1554,7 @@ export default {
       if(cfu.option[cid].enableScroll === true && e.touches.length == 0){
         cfu.instance[cid].scrollEnd(e);
       }
-      that[cid].callMethod('emitMsg',{name:"getTouchEnd",params:{type:"touchEnd",event:e.changedTouches[0],id:cid}})
+      that[cid].callMethod('emitMsg',{name:"getTouchEnd",params:{type:"touchEnd",event:e.changedTouches[0],id:cid, opts: cfu.instance[cid].opts}})
     },
     mouseDown(e) {
       let cid = this.rid
@@ -1556,7 +1567,7 @@ export default {
       e.changedTouches.unshift(tmpe)
       cfu.instance[cid].scrollStart(e)
       cfu.option[cid].mousedown=true;
-      that[cid].callMethod('emitMsg',{name:"getTouchStart",params:{type:"mouseDown",event:tmpe,id:cid}})
+      that[cid].callMethod('emitMsg',{name:"getTouchStart",params:{type:"mouseDown",event:tmpe,id:cid, opts: cfu.instance[cid].opts}})
     },
     mouseMove(e) {
       let cid = this.rid
@@ -1570,7 +1581,7 @@ export default {
       e.changedTouches.unshift(tmpe)
       if(cfu.option[cid].mousedown){
         cfu.instance[cid].scroll(e)
-        that[cid].callMethod('emitMsg',{name:"getTouchMove",params:{type:"mouseMove",event:tmpe,id:cid}})
+        that[cid].callMethod('emitMsg',{name:"getTouchMove",params:{type:"mouseMove",event:tmpe,id:cid, opts: cfu.instance[cid].opts}})
       }else if(cfu.instance[cid]){
         if(tooltipShow==true){
           this.showTooltip(e,cid)
@@ -1588,7 +1599,7 @@ export default {
       e.changedTouches.unshift(tmpe)
       cfu.instance[cid].scrollEnd(e)
       cfu.option[cid].mousedown=false;
-      that[cid].callMethod('emitMsg',{name:"getTouchEnd",params:{type:"mouseUp",event:tmpe,id:cid}})
+      that[cid].callMethod('emitMsg',{name:"getTouchEnd",params:{type:"mouseUp",event:tmpe,id:cid, opts: cfu.instance[cid].opts}})
     },
   }
 }

+ 10 - 5
uni_modules/qiun-data-charts/js_sdk/u-charts/config-ucharts.js

@@ -251,7 +251,8 @@ const cfu = {
 		"extra": {
 			"line": {
 				"type": "straight",
-				"width": 2
+				"width": 2,
+        "activeType": "hollow"
 			},
 		}
 	},
@@ -278,7 +279,8 @@ const cfu = {
   	"extra": {
   		"line": {
   			"type": "curve",
-  			"width": 2
+  			"width": 2,
+        "activeType": "hollow"
   		},
   	}
   },
@@ -308,7 +310,8 @@ const cfu = {
   			"opacity": 0.2,
   			"addLine": true,
   			"width": 2,
-  			"gradient": true
+  			"gradient": true,
+        "activeType": "hollow"
   		},
   	}
   },
@@ -396,7 +399,8 @@ const cfu = {
 				"opacity": 0.2,
 				"addLine": true,
 				"width": 2,
-				"gradient": false
+				"gradient": false,
+        "activeType": "hollow"
 			},
 		}
 	},
@@ -416,7 +420,8 @@ const cfu = {
 				"gridColor": "#CCCCCC",
 				"gridCount": 3,
 				"opacity": 0.2,
-				"max": 200
+				"max": 200,
+				"labelShow": true
 			},
 		}
 	},

Різницю між файлами не показано, бо вона завелика
+ 443 - 133
uni_modules/qiun-data-charts/js_sdk/u-charts/u-charts.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 0
uni_modules/qiun-data-charts/js_sdk/u-charts/u-charts.min.js


+ 6 - 10
uni_modules/qiun-data-charts/package.json

@@ -1,8 +1,8 @@
 {
   "id": "qiun-data-charts",
   "displayName": "秋云 ucharts echarts 高性能跨全端图表组件",
-  "version": "2.4.3-20220505",
-  "description": "uCharts 新增双指缩放、新增山峰图!支持H5及APP用 ucharts echarts 渲染图表,uniapp可视化首选组件",
+  "version": "2.5.0-20230101",
+  "description": "uCharts 新增正负柱状图!支持H5及APP用 ucharts echarts 渲染图表,uniapp可视化首选组件",
   "keywords": [
     "ucharts",
     "echarts",
@@ -11,14 +11,9 @@
     "可视化"
 ],
   "repository": "https://gitee.com/uCharts/uCharts",
-  "engines": {
-    "HBuilderX": "^3.3.8"
+"engines": {
   },
-  "dcloudext": {
-    "category": [
-        "前端组件",
-        "通用组件"
-    ],
+"dcloudext": {
     "sale": {
       "regular": {
         "price": "0.00"
@@ -35,7 +30,8 @@
       "data": "插件不采集任何数据",
       "permissions": "无"
     },
-    "npmurl": "https://www.npmjs.com/~qiun"
+    "npmurl": "https://www.npmjs.com/~qiun",
+    "type": "component-vue"
   },
   "uni_modules": {
     "dependencies": [],

+ 14 - 32
uni_modules/qiun-data-charts/readme.md

@@ -1,32 +1,3 @@
-
-
-## <font color='red'>写给uCharts使用者的一封信</font>
-<font color='red'>
-亲爱的用户:
-
-- 由于最近上线的官网中实行了部分收费体验,收到了许多用户的使用反馈,大致反馈的问题都指向同一矛头:为何新官网的在线工具也要收费?对于这件事,我们深表歉意。由于新官网本身未提供技术文档,使得用户误以为我们对文档实行了收费。经我们连夜整改,新官网目前已经将技术文档开放出来供大家阅读使用,并免费对外开放了【演示】中的查看全端全平台的代码的功能,为此再次向所受影响的用户们致以诚恳的歉意。
-
-- 其次,我们须澄清几点,如下:
-1. uCharts的插件本身遵循开源原则,并不收费,用户可自行到DCloud市场与Gitee码云上获取源码
-2. uCharts的技术文档永久对用户开放
-3. 收费内容仅针对原生工具、组件工具、定制功能以及模板市场的部分收费模板
-
-- uCharts为什么实行收费原则?
-1. 服务器的费用支撑
-2. 团队的运营支出;正如你所见,我们的群里有大量的用户在请教图表配置与反馈问题,群里的每一位管理员都在花费不少精力在积极解决用户的问题,然而遇到巨大的咨询量时,我们无法及时、精准解答回复,因此,我们推出了会员优先服务
-3. 与其说模板市场是收费,倒不如说给野生用户提供了创造价值的机会,用户既可以在上面发布模板赚取费用,遇到心动的模板也能免费/付费使用
-
-- 收费不是目的,正如你们所见,用户可以申请成为[【开发者】](https://www.ucharts.cn/v2/#/agreement/developer),开发者不限制任何官网功能,并享有官方指导、开发、改造uCharts的权力,并且活动期间【返还超级会员费用】!我们想说的是,我们新版官网上线旨在希望更多的用户加入到开发者的队伍,我们共同去维护uCharts!
-       
-我们相信:星星之火可以燎原!
-
-uCharts技术团队
-
-2022.4.23
-
-</font>
-
-
 ![logo](https://img-blog.csdnimg.cn/4a276226973841468c1be356f8d9438b.png)
 
 
@@ -50,19 +21,30 @@ uCharts技术团队
 
 ![](https://www.ucharts.cn/images/web/guide/qrcode20220224.png)
 
+![](https://img-blog.csdnimg.cn/7d0115593ff24ac39a224fb7c6ed72a4.png)
+
 ## 致开发者
 
-感谢各位开发者`四年`来对秋云及uCharts的支持,uCharts的进步离不开各位开发者的鼓励与贡献。为更好的帮助各位开发者使用图表工具,我们推出了新版官网,增加了在线定制、问答社区、在线配置等一些增值服务,为确保您能更好的应用图表组件,建议您先`仔细阅读本页指南`以及`常见问题`,而不是下载下来`直接使用`。如仍然不能解决,请到`官网社区`或开通会员后加入`专属VIP会员群`提问将会很快得到回答。
+感谢各位开发者`五年`来对秋云及uCharts的支持,uCharts的进步离不开各位开发者的鼓励与贡献。为更好的帮助各位开发者使用图表工具,我们推出了新版官网,增加了在线定制、问答社区、在线配置等一些增值服务,为确保您能更好的应用图表组件,建议您先`仔细阅读官网指南`以及`常见问题`,而不是下载下来`直接使用`。如仍然不能解决,请到`官网社区`或开通会员后加入`专属VIP会员群`提问将会很快得到回答。
+
+## 视频教程
+
+## [uCharts新手入门教程](https://www.bilibili.com/video/BV1qA411Q7se/?share_source=copy_web&vd_source=42a1242f9aaade6427736af69eb2e1d9)
+
 
 ## 社群支持
 
-uCharts官方拥有4个2000人的QQ群及专属VIP会员群支持,庞大的用户量证明我们一直在努力,请各位放心使用!uCharts的开源图表组件的开发,团队付出了大量的时间与精力,经过四来的考验,不会有比较明显的bug,请各位放心使用。如果您有更好的想法,可以在`码云提交Pull Requests`以帮助更多开发者完成需求,再次感谢各位对uCharts的鼓励与支持!
+uCharts官方拥有5个2000人的QQ群及专属VIP会员群支持,庞大的用户量证明我们一直在努力,请各位放心使用!uCharts的开源图表组件的开发,团队付出了大量的时间与精力,经过四来的考验,不会有比较明显的bug,请各位放心使用。如果您有更好的想法,可以在`码云提交Pull Requests`以帮助更多开发者完成需求,再次感谢各位对uCharts的鼓励与支持!
 
 #### 官方交流群
 - 交流群1:371774600(已满)
 - 交流群2:619841586(已满)
 - 交流群3:955340127(已满)
-- 交流群4:641669795
+- 交流群4:641669795(已满)
+- 交流群5:236294809(只能扫码加入)
+
+![](https://www.ucharts.cn/images/web/qq5.jpg)
+
 - 口令`uniapp`
 
 #### 专属VIP会员群

+ 172 - 0
uni_modules/vk-uview-ui/changelog.md

@@ -0,0 +1,172 @@
+## 1.5.7(2024-09-02)
+* 【修复】`u-input` type 为select时,在支付宝小程序无法点击的问题
+* 【修复】`u-picker` 在微信小程序部分情况下会报警告的问题
+## 1.5.6(2024-09-02)
+* 【修复】Vue3模式下,支付宝小程序启动报错的问题
+## 1.5.5(2024-08-29)
+* 【修复】`u-collapse-item` 在部分情况下始终折叠无法打开的问题
+* 【修复】`u-popup` 初始化时 `@close` 事件就会执行的bug
+## 1.5.4(2024-07-17)
+* 【修复】`u-input` 设置 maxlength 后,在ios输入法中表现异常的问题
+* 【修复】`u-input` 在抖音小程序中会报错的问题
+* 【优化】部分组件在抖音小程序中的兼容性问题
+* 【优化】`u-tabbar` 跳转能力,支持非tabbar页面
+* 【优化】`u-table`新增属性tdStyle
+## 1.5.3(2024-05-28)
+* 【修复】`u-form` 属性 `borderBottom` 不生效的问题
+* 【修复】`u-picker` 的 `columnchange` 事件第一行不触发的问题
+* 【修复】`u-parse` 解析富文本后得到的对象传递到 `u-trees` 时不存在style时报错的问题
+* 【优化】`u-calendar` 多选时,未选择结束时间则不能点击确认按钮
+* 【优化】`u-picker` 组件,弹窗的默认时间若未设置,则为当前时间
+## 1.5.2(2023-12-28)
+* 【修复】`u-input` 缺少emits选项 `confirm` 的问题
+## 1.5.1(2023-10-13)
+* 【修复】`u-parse` 在小程序上部分情况下不显示图片的问题
+* 【修复】`u-alert-tips` 使用 `closeText` 时 `close` 事件无效的问题 & 样式微调
+## 1.5.0(2023-06-01)
+* 【修复】`u-parse` 在vue3真机白屏问题和h5样式污染问题
+* 【修复】`u-select` 默认值的问题
+* 【修复】`u-parse` 在app和微信小程序中 `preview` 属性不生效的问题
+## 1.4.8(2023-05-17)
+* 【优化】部分组件属性的可选值的代码提示
+* 【优化】`u-circle-progres` 组件 在进度条到100%的时候发出一个 `finish` 事件
+* 【修复】`u-picker` 的时间选择器在ios下默认值无效的bug
+* 【修复】`u-card` 圆角问题
+* 【修复】`u-button` 支持 `info` 类型
+## 1.4.7(2023-04-24)
+* 【修复】`u-picker` 在vue3的App环境下默认值无效的bug
+## 1.4.5(2022-12-05)
+* 【修复】`u-row`、`u-col` 使用 `@click.stop` 会报错的问题,同时建议改用 `@click.native.stop` 来代替 `@click.stop`
+## 1.4.4(2022-11-12)
+* 【修复】`u-calendar` `u-modal` `u-picker` `u-popup` 组件在页面进入后马上需要弹窗时,无法正常弹窗的问题。
+## 1.4.3(2022-10-22)
+* 【优化】部分组件的细节
+## 1.4.2(2022-10-15)
+* 【修复】`1.4.1` 引出的 `u-subsection` 的部分问题
+## 1.4.1(2022-10-14)
+* 【修复】`u-count-to` 若设置了千分位符合,会错误显示-的问题
+* 【修复】`u-subsection` 部分细节问题
+## 1.4.0(2022-10-07)
+* 【修复】`u-section` 点击更多,会触发两次事件的问题
+* 【修复】`loadMore` 加载更多,icon-type为circle不会转动的问题
+* 【修复】`u-subsection` current 有转入值时,变更值,样式不更新(需用 `v-model="current"` 代替 `:current="current"`)
+## 1.3.13(2022-09-28)
+* 【修复】`u-avatar-cropper` 组件在vue3中会报错的问题。
+## 1.3.12(2022-08-30)
+* 【优化】`u-keyboard` 组件内部细节。
+## 1.3.11(2022-08-30)
+* 【修复】`u-subsection` 组件的 `list` 属性不支持动态修改的问题。
+## 1.3.10(2022-07-30)
+* 【优化】上传组件部分细节
+## 1.3.9(2022-07-07)
+* 【更新】省市区数据源
+* 【优化】`u-subsection` 组件支持在右上角显示数字角标 
+```html
+<template>
+	<u-subsection :list="list"></u-subsection>
+</template>
+```
+
+```js
+export default {
+	data() {
+		return {
+			list: [
+				{
+					name: '待发货',
+					num: 10
+				}, 
+				{
+					name: '待付款',
+					num: 5
+				}, 
+				{
+					name: '待评价',
+					num: 15
+				}
+			]
+		}
+	}
+}
+```
+## 1.3.8(2022-06-13)
+* 【优化】组件 `u-icon`,使之更方便的兼容第三方icon(满足规则自动计算customPrefix)
+**规则如下:**
+* 当 `name` 中包含 `-icon-` 字符串时
+* 如 `vk-icon-goods`,则组件的 `customPrefix` 属性自动识别为 `vk-icon` ,`name`属性 自动识别为 `goods`
+* 如 `vk-2-icon-goods-list`,则组件的 `customPrefix` 属性自动识别为 `vk-2-icon` ,`name`属性 自动识别为 `goods-list`
+## 1.3.7(2022-06-10)
+* 【优化】组件 `u-action-sheet` `u-calendar` `u-dropdown-item` `u-field` `u-input` `u-keyboard` `u-modal` `u-radio-group` `u-rate` `u-search` `u-slider` `u-switch` `u-tabbar` `u-waterfall` 在 `vue3` 模式下的细节问题。
+## 1.3.6(2022-06-10)
+* 【优化】组件 `u-action-sheet` `u-calendar` `u-dropdown-item` `u-field` `u-input` `u-keyboard` `u-modal` `u-radio-group` `u-rate` `u-search` `u-slider` `u-switch` `u-tabbar` `u-waterfall` 在 `vue3` 模式下的细节问题。
+## 1.3.5(2022-05-28)
+* 【优化】组件 `u-mask` `u-popup` `u-select` `u-modal` `u-keyboard` `u-calendar` `u-action-sheet` `u-picker` 均新增 `blur` 属性,可用于设置弹出遮罩的模糊度,默认为0(不模糊)
+* ![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/49b773a3-273f-4b1c-95e8-a42dcba1a53c.png)
+## 1.3.4(2022-05-03)
+* 【修复】`u-tabs` 组件细节问题。
+## 1.1.4(2022-03-22)
+* 【修复】`u-field` 组件 `arrowDirection` 属性无效的问题。
+## 1.1.3(2022-03-21)
+* 【优化】部分细节。
+## 1.1.2(2022-03-21)
+* 【优化】部分细节。
+## 1.1.1(2022-03-17)
+* 【优化】部分细节。
+## 1.1.0(2022-03-12)
+* 【重要】`u-picker` 组件新增 `regionDiscern` 方法 智能识别省市区街道地址
+如将字符串 `浙江省杭州市西湖区希望路1333弄是啊我庭12号楼1203` 中识别为
+```json
+{
+	"province": {
+		"code": "330000",
+		"name": "浙江省"
+	},
+	"city": {
+		"code": "330100",
+		"name": "杭州市"
+	},
+	"area": {
+		"code": "330106",
+		"name": "西湖区"
+	},
+	"address": "龙井路1号",
+	"formatted_address": "浙江省杭州市西湖区龙井路1号"
+}
+```
+而组件的 `addressDiscern` 方法还可以识别收货信息,如 `张三 13888888888 上海市嘉定区希望路1333弄是啊我庭12号楼1203` 中识别姓名、手机号、地址(支持多种格式)
+## 1.0.13(2022-03-12)
+* 【优化】部分细节。
+## 1.0.12(2022-03-09)
+* 【修复】`u-radio-group` 在 vue3 模式下,设置默认值可能会无效的问题。
+## 1.0.11(2022-03-07)
+* 【优化】部分细节。
+## 1.0.10(2022-03-05)
+* 【修复】`u-radio` 中的值相等的判断 == 改为 === 
+* 【优化】部分注释的错别字。
+## 1.0.9(2022-03-03)
+* 【修复】`u-parse` 在 vue3模式下编译到app无法正常显示的问题。
+## 1.0.8(2022-02-26)
+* 【优化】`u-form` 组件新增2个属性 `inputAlign` 和 `clearable` 用于统一设置表单内所有 `u-input` 组件的对应属性默认值
+* 【优化】更新城市数据源信息
+## 1.0.7(2022-02-25)
+* 【重要】`u-picker` 组件新增 `addressDiscern` 方法 智能识别收货信息
+
+如在 `张三 13888888888 上海市嘉定区希望路1333弄是啊我庭12号楼1203` 中识别姓名、手机号、地址(支持多种格式)
+即使这样的字符串也能识别 `!!!!~~~$张三~~~上海市嘉定区希望路1333弄是啊我庭12号楼1203【【【【13888888888】`
+## 1.0.6(2022-02-24)
+* 【优化】`u-form-item` 组件的 `prop` 属性支持 a.b 形式
+## 1.0.5(2022-01-11)
+* 【修复】`u-sticky` 组件 在微信小程序中无法正常吸顶的问题
+## 1.0.4(2021-12-31)
+* 【优化】`u-dropdown-item` 组件 0和"" 无法区分的问题。
+* 【修复】`u-modal` 在Vue3版本中使用了mask-close-able属性无效的问题
+## 1.0.3(2021-12-20)
+【优化】u-icon在微信小程序下可能会显示null字符串的问题
+## 1.0.2(2021-12-09)
+* 1、【优化】`u-button` 组件新增 `timerId` 属性
+* 之前的效果是:所有按钮一定时间内只能点击1次(`共用计算时间`)导致点击按钮A后无法马上点击按钮B
+* 优化的效果是:每个按钮一定时间内只能点击1次(`分开计算时间`)且支持设置相同的 timerId 来达到指定按钮 `共用计算时间`
+## 1.0.1(2021-11-22)
+* 修复 u-parse 组件在微信小程序上的显示问题。
+## 1.0.0(2021-11-18)
+uView Vue3.0 横空出世,继承uView1.0意志,再战江湖,风云再起!by vk 2021-11-18

+ 29 - 0
uni_modules/vk-uview-ui/components/u--text/u--text.vue

@@ -0,0 +1,29 @@
+<template>
+	<uvText :type="type" :show="show" :text="text" :prefixIcon="prefixIcon" :suffixIcon="suffixIcon" :mode="mode" :href="href" :format="format" :call="call" :openType="openType"
+		:bold="bold" :block="block" :lines="lines" :color="color" :decoration="decoration" :size="size" :iconStyle="iconStyle" :margin="margin" :lineHeight="lineHeight" :align="align"
+		:wordWrap="wordWrap" :customStyle="customStyle" @click="$emit('click')"></uvText>
+</template>
+
+<script>
+	/**
+	 * 此组件存在的理由是,在nvue下,u-text被uni-app官方占用了,u-text在nvue中相当于input组件
+	 * 所以在nvue下,取名为u--input,内部其实还是u-text.vue,只不过做一层中转
+	 * 不使用v-bind="$attrs",而是分开独立写传参,是因为微信小程序不支持此写法
+	 */
+	import uvText from "../u-text/u-text.vue";
+	import props from "../u-text/props.js";
+	import mixin from '../u-text/libs/mixin/mixin.js'
+	export default {
+		name: "u--text",
+		// #ifdef MP-WEIXIN
+		// 将自定义节点设置成虚拟的,更加接近Vue组件的表现,能更好的使用flex属性
+		options: {
+			virtualHost: true
+		},
+		// #endif
+		mixins: [props, mixin],
+		components: {
+			uvText,
+		},
+	};
+</script>

Деякі файли не було показано, через те що забагато файлів було змінено