fanghuisheng 3 месяцев назад
Родитель
Сommit
34961fa440
100 измененных файлов с 5850 добавлено и 2937 удалено
  1. 51 0
      src/uni_modules/lime-echart/changelog.md
  2. 31 17
      src/uni_modules/lime-echart/components/l-echart/canvas.js
  3. 303 121
      src/uni_modules/lime-echart/components/l-echart/l-echart.uvue
  4. 434 456
      src/uni_modules/lime-echart/components/l-echart/l-echart.vue
  5. 515 0
      src/uni_modules/lime-echart/components/l-echart/l-echart_old.vue
  6. 6 1
      src/uni_modules/lime-echart/components/l-echart/nvue.js
  7. 27 0
      src/uni_modules/lime-echart/components/l-echart/props.ts
  8. 11 0
      src/uni_modules/lime-echart/components/l-echart/type.ts
  9. 57 21
      src/uni_modules/lime-echart/components/l-echart/utils.js
  10. 44 13
      src/uni_modules/lime-echart/components/l-echart/uvue.uts
  11. 16 0
      src/uni_modules/lime-echart/components/l-echart/vue.ts
  12. 227 0
      src/uni_modules/lime-echart/components/lime-echart/lime-echart-old.vue
  13. 64 0
      src/uni_modules/lime-echart/components/lime-echart/lime-echart.nvue
  14. 143 81
      src/uni_modules/lime-echart/components/lime-echart/lime-echart.uvue
  15. 54 65
      src/uni_modules/lime-echart/components/lime-echart/lime-echart.vue
  16. 63 42
      src/uni_modules/lime-echart/package.json
  17. 427 341
      src/uni_modules/lime-echart/readme.md
  18. 408 0
      src/uni_modules/lime-echart/readme.old.md
  19. 0 0
      src/uni_modules/lime-echart/static/app/ecStat.min.js
  20. 34 0
      src/uni_modules/lime-echart/static/app/echarts.min.js
  21. 0 0
      src/uni_modules/lime-echart/static/app/uni.webview.1.5.5.js
  22. 184 0
      src/uni_modules/lime-echart/static/app/uvue.html
  23. 34 0
      src/uni_modules/lime-echart/static/web/echarts.esm.min.js
  24. 2 0
      src/uni_modules/uni-calendar/changelog.md
  25. 0 2
      src/uni_modules/uni-calendar/components/uni-calendar/calendar.js
  26. 1 1
      src/uni_modules/uni-calendar/components/uni-calendar/util.js
  27. 4 3
      src/uni_modules/uni-calendar/package.json
  28. 12 0
      src/uni_modules/uni-collapse/changelog.md
  29. 1 1
      src/uni_modules/uni-collapse/components/uni-collapse-item/uni-collapse-item.vue
  30. 14 14
      src/uni_modules/uni-collapse/components/uni-collapse/uni-collapse.vue
  31. 58 41
      src/uni_modules/uni-collapse/package.json
  32. 2 0
      src/uni_modules/uni-combox/changelog.md
  33. 16 7
      src/uni_modules/uni-combox/components/uni-combox/uni-combox.vue
  34. 7 9
      src/uni_modules/uni-combox/package.json
  35. 11 7
      src/uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/package.json
  36. 6 0
      src/uni_modules/uni-countdown/changelog.md
  37. 27 20
      src/uni_modules/uni-countdown/components/uni-countdown/uni-countdown.vue
  38. 11 11
      src/uni_modules/uni-countdown/package.json
  39. 4 0
      src/uni_modules/uni-data-checkbox/changelog.md
  40. 316 0
      src/uni_modules/uni-data-checkbox/components/uni-data-checkbox/clientdb.js
  41. 78 46
      src/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue
  42. 7 4
      src/uni_modules/uni-data-checkbox/package.json
  43. 2 0
      src/uni_modules/uni-data-picker/changelog.md
  44. 18 9
      src/uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.vue
  45. 7 5
      src/uni_modules/uni-data-picker/package.json
  46. 14 0
      src/uni_modules/uni-data-select/changelog.md
  47. 391 81
      src/uni_modules/uni-data-select/components/uni-data-select/uni-data-select.vue
  48. 60 39
      src/uni_modules/uni-data-select/package.json
  49. 21 0
      src/uni_modules/uni-datetime-picker/changelog.md
  50. 91 72
      src/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.vue
  51. 22 8
      src/uni_modules/uni-datetime-picker/components/uni-datetime-picker/time-picker.vue
  52. 36 13
      src/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue
  53. 4 4
      src/uni_modules/uni-datetime-picker/components/uni-datetime-picker/util.js
  54. 60 40
      src/uni_modules/uni-datetime-picker/package.json
  55. 18 0
      src/uni_modules/uni-easyinput/changelog.md
  56. 613 615
      src/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue
  57. 57 37
      src/uni_modules/uni-easyinput/package.json
  58. 2 0
      src/uni_modules/uni-fab/changelog.md
  59. 1 1
      src/uni_modules/uni-fab/components/uni-fab/uni-fab.vue
  60. 3 2
      src/uni_modules/uni-fab/package.json
  61. 20 0
      src/uni_modules/uni-file-picker/changelog.md
  62. 44 4
      src/uni_modules/uni-file-picker/components/uni-file-picker/choose-and-upload-file.js
  63. 50 47
      src/uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue
  64. 7 9
      src/uni_modules/uni-file-picker/components/uni-file-picker/upload-file.vue
  65. 5 12
      src/uni_modules/uni-file-picker/components/uni-file-picker/upload-image.vue
  66. 1 0
      src/uni_modules/uni-file-picker/components/uni-file-picker/utils.js
  67. 60 38
      src/uni_modules/uni-file-picker/package.json
  68. 1 2
      src/uni_modules/uni-file-picker/readme.md
  69. 6 0
      src/uni_modules/uni-forms/changelog.md
  70. 5 0
      src/uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue
  71. 8 1
      src/uni_modules/uni-forms/components/uni-forms/uni-forms.vue
  72. 3 2
      src/uni_modules/uni-forms/package.json
  73. 4 0
      src/uni_modules/uni-icons/changelog.md
  74. 5 5
      src/uni_modules/uni-icons/components/uni-icons/uni-icons.uvue
  75. 3 3
      src/uni_modules/uni-icons/components/uni-icons/uni-icons.vue
  76. 66 43
      src/uni_modules/uni-icons/package.json
  77. 4 0
      src/uni_modules/uni-id-common/changelog.md
  78. 6 6
      src/uni_modules/uni-id-common/package.json
  79. 0 0
      src/uni_modules/uni-id-common/uniCloud/cloudfunctions/common/uni-id-common/index.js
  80. 18 14
      src/uni_modules/uni-id-common/uniCloud/cloudfunctions/common/uni-id-common/package.json
  81. 6 0
      src/uni_modules/uni-list/changelog.md
  82. 17 9
      src/uni_modules/uni-list/components/uni-list-item/uni-list-item.vue
  83. 56 36
      src/uni_modules/uni-list/package.json
  84. 3 303
      src/uni_modules/uni-list/readme.md
  85. 4 0
      src/uni_modules/uni-load-more/changelog.md
  86. 7 2
      src/uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue
  87. 59 40
      src/uni_modules/uni-load-more/package.json
  88. 9 0
      src/uni_modules/uni-nav-bar/changelog.md
  89. 44 18
      src/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-nav-bar.vue
  90. 7 1
      src/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-status-bar.vue
  91. 59 39
      src/uni_modules/uni-nav-bar/package.json
  92. 2 0
      src/uni_modules/uni-notice-bar/changelog.md
  93. 15 23
      src/uni_modules/uni-notice-bar/components/uni-notice-bar/uni-notice-bar.vue
  94. 7 4
      src/uni_modules/uni-notice-bar/package.json
  95. 8 0
      src/uni_modules/uni-number-box/changelog.md
  96. 19 8
      src/uni_modules/uni-number-box/components/uni-number-box/uni-number-box.vue
  97. 3 2
      src/uni_modules/uni-number-box/package.json
  98. 26 0
      src/uni_modules/uni-popup/changelog.md
  99. 48 12
      src/uni_modules/uni-popup/components/uni-popup-dialog/uni-popup-dialog.vue
  100. 5 4
      src/uni_modules/uni-popup/components/uni-popup-share/uni-popup-share.vue

+ 51 - 0
src/uni_modules/lime-echart/changelog.md

@@ -1,3 +1,54 @@
+## 2.0.3(2025-12-04)
+- feat: autoHideTooltip默认为false
+## 2.0.2(2025-11-24)
+- feat: 增加`autoHideTooltip`属性
+## 2.0.1(2025-10-28)
+- chore: 更新文档
+## 2.0.0(2025-10-28)
+- feat: 基于 Vue 3 Composition API 重构 uni-app 端组件,提升代码可维护性和性能
+- feat: 升级内置 ECharts 至 v6 版本,支持最新图表特性和性能优化
+## 1.0.4(2025-05-16)
+- fix: 修复uniappx ios尺寸
+## 1.0.3(2025-05-10)
+- fix: 修复nvue缺少`isDisposed`
+## 1.0.2(2025-03-21)
+- fix: 修复词云无法设置字体大小的问题
+## 1.0.1(2025-03-14)
+- fix: 修复抖音小程序不显示问题
+## 1.0.0(2025-02-27)
+- fix: 修复uniappx微信小程序不显示问题
+## 0.9.9(2025-02-24)
+- feat: 更新v4
+## 0.9.8(2024-12-20)
+- fix: 修复 APP 无法放大问题
+## 0.9.7(2024-12-02)
+- feat: uniapp 增加`landscape`,当`landscape`为`true`时旋转90deg达到横屏效果。
+- feat: 支持uniapp x 微信小程序
+## 0.9.6(2024-07-23)
+- fix: 修复 uni is not defined
+## 0.9.5(2024-07-19)
+- chore: 鸿蒙`measureText`为异步,异步字体不正常,使用模拟方式。
+## 0.9.4(2024-07-18)
+- chore: 更新文档
+## 0.9.3(2024-07-16)
+- feat: 鸿蒙 canvas 事件缺失,待官方修复,如何在鸿蒙使用请看文档`常见问题 vue3` 
+## 0.9.2(2024-07-12)
+- chore: 删除多余文件
+## 0.9.1(2024-07-12)
+- fix: 修复 安卓5不显示图表问题
+## 0.9.0(2024-06-13)
+- chore: 合并nvue和uvue
+## 0.8.9(2024-05-19)
+- chore: 更新文档
+## 0.8.8(2024-05-13)
+- chore: 更新文档和uvue示例
+## 0.8.7(2024-04-26)
+- fix: uniapp x需要HBX 4.13以上
+## 0.8.6(2024-04-10)
+- feat: 支持 uniapp x ios
+## 0.8.5(2024-04-03)
+- fix: 修复 nvue `reset`传值不生效问题
+- feat: 支持 uniapp x web
 ## 0.8.4(2024-01-27)
 - chore: 更新文档
 ## 0.8.3(2024-01-21)

+ 31 - 17
src/uni_modules/lime-echart/components/l-echart/canvas.js

@@ -1,3 +1,5 @@
+import {getDeviceInfo} from './utils';
+
 const cacheChart = {}
 const fontSizeReg = /([\d\.]+)px/;
 class EventEmit {
@@ -145,14 +147,14 @@ export class Canvas {
 	}
 	createOffscreenCanvas(param){
 		if(!this.children) {
-			this.com.isOffscreenCanvas = true
-			this.com.offscreenWidth = param.width||300
-			this.com.offscreenHeight = param.height||300
-			const com = this.com
-			const canvasId = this.com.offscreenCanvasId
-			const context = uni.createCanvasContext(canvasId, this.com)
-			this._initStyle(context)
-			this.children = new OffscreenCanvas(context, com, canvasId)
+			// this.com.isOffscreenCanvas = true
+			// this.com.offscreenWidth = param.width||300
+			// this.com.offscreenHeight = param.height||300
+			// const com = this.com
+			// const canvasId = this.com.offscreenCanvasId
+			// const context = uni.createCanvasContext(canvasId, this.com)
+			// this._initStyle(context)
+			// this.children = new OffscreenCanvas(context, com, canvasId)
 		} 
 		return this.children
 	}
@@ -201,17 +203,22 @@ export class Canvas {
 			'lineJoin',
 			'lineDash',
 			'miterLimit',
-			// 'font'
+			// #ifdef H5 || APP
+			'font',
+			// #endif
 		];
 		const colorReg = /#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])\b/g;
 		styles.forEach(style => {
 			Object.defineProperty(ctx, style, {
 				set: value => {
-					// if (style === 'font' && fontSizeReg.test(value)) {
-					// 	const match = fontSizeReg.exec(value);
-					// 	ctx.setFontSize(match[1]);
-					// 	return;
-					// }
+					// #ifdef H5 || APP
+					if (style === 'font' && fontSizeReg.test(value)) {
+						const match = fontSizeReg.exec(value);
+						ctx.setFontSize(match[1]);
+						return;
+					}
+					// #endif
+					
 					if (style === 'opacity') {
 						ctx.setGlobalAlpha(value)
 						return;
@@ -253,8 +260,10 @@ export class Canvas {
 				ctx.fillText(...a)
 			}
 		}
-		// 钉钉不支持 
-		if (!ctx.measureText) {
+		
+		// 钉钉不支持 , 鸿蒙是异步
+		if (!ctx.measureText || getDeviceInfo().osName == 'harmonyos') {
+			ctx._measureText = ctx.measureText
 			const strLen = (str) => {
 				let len = 0;
 				for (let i = 0; i < str.length; i++) {
@@ -274,6 +283,7 @@ export class Canvas {
 				fontSize /= 2;
 				let isBold = fontSize >= 16;
 				const widthFactor = isBold ? 1.3 : 1;
+				// ctx._measureText(text, (res) => {})
 				return {
 					width: strLen(text) * fontSize * widthFactor
 				};
@@ -342,7 +352,6 @@ export function dispatch(name, {x,y, wheelDelta}) {
 	});
 }
 export function setCanvasCreator(echarts, {canvas, node}) {
-	// echarts.setCanvasCreator(() => canvas);
 	if(echarts && !echarts.registerPreprocessor) {
 		return console.warn('echarts 版本不对或未传入echarts,vue3请使用esm格式')
 	}
@@ -381,5 +390,10 @@ export function setCanvasCreator(echarts, {canvas, node}) {
 				return uni.canIUse(key) && uni[key] ? uni[key]({type: '2d'}) : canvas
 			}
 		})
+	} else if(echarts.setCanvasCreator) {
+		echarts.setCanvasCreator(() => {
+		    return canvas;
+		});
 	}
+	
 }

+ 303 - 121
src/uni_modules/lime-echart/components/l-echart/l-echart.uvue

@@ -1,141 +1,323 @@
 <template>
-	<web-view class="lime-echart" ref="limeEchart" :style="[customStyle]" :webview-styles="[webviewStyles]"
-		src="/uni_modules/lime-echart/static/uvue.html?v=1011">
+	<!-- #ifdef APP -->
+	<web-view class="lime-echart" ref="chartRef" @load="loaded" :style="[lStyle]" :webview-styles="[webviewStyles]"
+		src="/uni_modules/lime-echart/static/app/uvue.html?v=10112">
 	</web-view>
+	<!-- #endif -->
+	<!-- #ifdef WEB -->
+	<div class="lime-echart" ref="chartRef"></div>
+	<!-- #endif -->
+	<!-- #ifndef WEB || APP-->
+	<view  class="lime-echart">
+		<canvas style="width:100%; height:100%" v-if="canvasid" :id="canvasid" @touchstart="touchstart" @touchmove="touchmove" @touchend="touchend"></canvas>
+	</view>
+	<!-- #endif -->
 </template>
 
-<script lang="uts">
+<script lang="uts" setup>
+	// @ts-nocheck
+	import { echartsProps } from './type';
 	import { Echarts } from './uvue';
-	type EchartsResolve = (value : Echarts) => void
-	export default {
-		name: 'l-echart',
-		props: {
-			webviewStyles: {
-				type: Object
-			},
-			customStyle: {
-				type: Object
-			},
-			isDisableScroll: {
-				type: Boolean,
-				default: false
-			},
-			isClickable: {
-				type: Boolean,
-				default: true
-			},
-			enableHover: {
-				type: Boolean,
-				default: false
-			},
-			beforeDelay: {
-				type: Number,
-				default: 30
+	// #ifdef WEB
+	import { dispatch } from './canvas';
+	import * as echartsLibrary from '@/uni_modules/lime-echart/static/web/echarts.esm.min.js';
+	// #endif
+	// #ifndef APP || WEB
+	import { Canvas, setCanvasCreator, dispatch } from './canvas';
+	import { wrapTouch, convertTouchesToArray, devicePixelRatio, sleep, canIUseCanvas2d, getRect } from './utils';
+	// #endif
+	type EChartsResolveCallback = (value : Echarts) => void
+	
+	const emits = defineEmits(['finished'])
+	const props = withDefaults(defineProps<echartsProps>(), {
+		isDisableScroll: false,
+		isClickable: true,
+		autoHideTooltip: false,
+		enableHover: false,
+		landscape: false,
+		beforeDelay: 30,
+	}) 
+	const instance = getCurrentInstance()!;
+	const canvasid = `lime-echart-${instance.uid}`
+	const finished = ref(false)
+	const initializationQueue = [] as EChartsResolveCallback[]
+	const callbackQueue = [] as EChartsResolveCallback[]
+	// let context = null as UniWebViewElement | null
+	let chartInstance = null as Echarts | null
+	let chartRef = ref<UniWebViewElement | null>(null)
+	let canvasNode:any|null = null
+	const processInitializationQueue = () => {
+		// #ifdef APP
+		if (finished.value) {
+			if (chartInstance == null) {
+				chartInstance = new Echarts(chartRef.value!)
 			}
-		},
-		data() {
-			return {
-				finished: false,
-				map: [] as EchartsResolve[],
-				context: null as UniWebViewElement | null,
-				// el: null as  UniWebViewElement | null,
-				chart: null as Echarts | null
-			};
-		},
-		computed: {
+			while (initializationQueue.length > 0) {
+				const resolve = initializationQueue.pop() as EChartsResolveCallback
+				resolve(chartInstance!)
+			}
+		}
+		// #endif
+		// #ifndef APP
+		while (initializationQueue.length > 0) {
+			if (chartInstance != null) {
+				const resolve = initializationQueue.pop() as EChartsResolveCallback
+				resolve(chartInstance!)
+			}
+		}
+		// #endif
 
-		},
-		unmounted() {
+		if (chartInstance != null) {
+			while (callbackQueue.length > 0) {
+				const callback = callbackQueue.pop() as EChartsResolveCallback
+				callback(chartInstance!)
+			}
+		}
+	}
 
-		},
-		created() {
+	// #ifdef APP
+	const loaded = (event : UniWebViewLoadEvent) => {
+		event.stopPropagation()
+		event.preventDefault()
+		nextTick(()=> {
+			chartRef.value?.getBoundingClientRectAsync()?.then(res => {
+				if(res.width > 0 && res.height > 0) {
+					finished.value = true
+					processInitializationQueue()
+					emits('finished')
+				} else {
+					console.warn('【lime-echart】获取尺寸失败,请检查代码样式')
+				}
+			})
+		})
+	}
+	// #endif
 
-		},
-		mounted() {
-			this.createSelectorQuery().select('.lime-echart').boundingClientRect(_ => {
-				const context = this.$el as UniWebViewElement
-				this.context = context
-				// context.addEventListener('error', (_ : WebViewErrorEvent) => { })
-				// context.addEventListener('loading', (_ : WebViewLoadingEvent) => { })
-				context.addEventListener('loaded', (event : WebViewLoadedEvent) => {
-					this.finished = true
-					event.stopPropagation()
-					event.preventDefault()
-					this.trigger()
-					this.$emit('finished')
-				})
-				
-			}).exec()
 
-		},
-		methods: {
-			_next() {
-				if (this.chart == null) {
-					console.warn(`组件还未初始化,请先使用 init`)
-					return
-				}
-			},
-			setOption(option : UTSJSONObject) {
-				this._next()
-				this.chart?.setOption(option);
-			},
-			showLoading() {
-				this._next()
-				this.chart?.showLoading();
-			},
-			hideLoading() {
-				this._next()
-				this.chart?.hideLoading();
-			},
-			clear() { 
-				this._next()
-				this.chart?.clear();
-			},
-			dispose() {
-				this._next()
-				this.chart?.dispose();
-			},
-			resize(size:UTSJSONObject) { 
-				this._next()
-				this.chart?.resize(size);
-			},
-			canvasToTempFilePath(opt: UTSJSONObject) {
-				this._next()
-				this.chart?.canvasToTempFilePath(opt)
-			},
-			trigger() {
-				if (this.finished) {
-					if (this.chart == null) {
-						this.chart = new Echarts(this.context!)
-					}
-					while (this.map.length > 0) {
-						const resolve = this.map.pop() as EchartsResolve
-						resolve(this.chart!)
+	const checkInitialization = () : boolean => {
+		if (chartInstance == null) {
+			console.warn(`组件还未初始化,请先使用 init`)
+			return true
+		}
+		return false
+	}
+	const setOption = (option : UTSJSONObject) => {
+		if (checkInitialization()) return
+		chartInstance!.setOption(option);
+	}
+	const showLoading = () => {
+		if (checkInitialization()) return
+		chartInstance!.showLoading();
+	}
+	const hideLoading = () => {
+		if (checkInitialization()) return
+		chartInstance!.hideLoading();
+	}
+	const clear = () => {
+		if (checkInitialization()) return
+		chartInstance!.clear();
+	}
+	const dispose = () => {
+		if (checkInitialization()) return
+		chartInstance!.dispose();
+	}
+	const resize = (size : UTSJSONObject) => {
+		if (checkInitialization()) return
+		chartInstance!.resize(size);
+	}
+	const canvasToTempFilePath = (opt : UTSJSONObject) => {
+		if (checkInitialization()) return
+		// #ifdef APP
+		chartInstance!.canvasToTempFilePath(opt);
+		// #endif
+		// #ifdef WEB
+		options.success?.({
+			tempFilePath: chartInstance._api.getDataURL()
+		}) 
+		// #endif
+		// #ifndef WEB || APP
+		if(canvasNode) {
+			options.success?.({
+				tempFilePath: canvasNode.toDataURL()
+			}) 
+		} else {
+			uni.canvasToTempFilePath({
+				...options,
+				canvasId
+			}, instance.proxy);
+		}
+		// #endif
+	}
+
+	// #ifdef APP
+	function init(callback : ((chartInstance : Echarts) => void) | null) : Promise<Echarts> {
+		if (callback != null) {
+			callbackQueue.push(callback)
+		}
+		return new Promise<Echarts>((resolve) => {
+			initializationQueue.push(resolve)
+			processInitializationQueue()
+		})
+	}
+	// #endif
+	// #ifndef APP 
+	// #ifndef WEB 
+	let use2dCanvas = canIUseCanvas2d()
+	const getContext = async () => {
+		return new Promise((resolve, reject)=>{
+			uni.createCanvasContextAsync({
+				id: canvasid,
+				component: instance.proxy!,
+				success: (context : CanvasContext) => {
+					canvasNode = context
+					const canvasContext = context.getContext('2d')!;
+					const canvas = canvasContext.canvas;
+					let uniCanvas;
+					const width = canvas.offsetWidth
+					const height = canvas.offsetHeight
+					// 处理高清屏逻辑
+					const dpr = uni.getDeviceInfo().devicePixelRatio ?? 1;
+					canvas.width = canvas.offsetWidth * dpr;
+					canvas.height = canvas.offsetHeight * dpr;
+					canvasContext.scale(dpr, dpr); // 仅需调用一次,当调用 reset 方法后需要再次 scale
+					if(use2dCanvas) {
+						uniCanvas = new Canvas(canvasContext, instance.proxy, true, context);
+					} else {
+						uniCanvas =  new Canvas(canvasContext, instance.proxy, false);
 					}
+					resolve({ canvas: uniCanvas, width, height, devicePixelRatio: 1, node: context});
+				},
+				fail(err) {
+					reject(err)
+					console.log('err', err)
 				}
-			},
-			init() : Promise<Echarts> {
-				return new Promise((resolve) => {
-					this.map.push(resolve)
-					this.trigger()
-				})
-			},
-			init(callback : (chart : Echarts) => void) : Promise<Echarts> {
-				if (this.chart !== null) {
-					callback(this.chart!)
-				} else {
-					console.warn('echarts 未加载完成,您可以延时一下')
-				}
-				return new Promise((resolve) => {
-					this.map.push(resolve)
-					this.trigger()
-				})
+			})
+		})
+	}
+	// #endif
+	const getTouch = (e) => {
+		const touches = e.touches[0]
+		// #ifdef WEB
+		const rect = chart!.getZr().dom.getBoundingClientRect();
+		const touch = {
+			x: touches.clientX - rect.left,
+			y: touches.clientY - rect.top
+		}
+		// #endif
+		// #ifndef WEB
+		const touch = {
+			x: touches.x,
+			y: touches.y
+		}
+		// #endif
+		return touch
+	}
+	const touchstart = (e) => {
+		if (chartInstance == null) return
+		const handler = chartInstance.getZr().handler;
+		const touch = getTouch(e)
+		dispatch.call(handler, 'mousedown', touch)
+		dispatch.call(handler, 'click', touch)
+	}
+	const touchmove = (e) => {
+		if (chartInstance == null) return
+		const handler = chartInstance.getZr().handler;
+		const touch = getTouch(e)
+		dispatch.call(handler, 'mousemove', touch)
+	}
+	const touchend = (e) => {
+		if (chartInstance == null || !props.autoHideTooltip) return
+		const handler = chartInstance.getZr().handler;
+
+		const touch = {
+			x: 999999999,
+			y: 999999999
+		}
+
+		dispatch.call(handler, 'mousemove', touch)
+		dispatch.call(handler, 'touchend', touch)
+
+	}
+	async function init(echarts : any, ...args : any[]) : Promise<Echarts> {
+		const library = echarts || echartsLibrary
+		if (library == null) {
+			console.error('请确保已经引入了 ECharts 库');
+			return Promise.reject('请确保已经引入了 ECharts 库');
+		}
+		let theme : string | null = null
+		let opts = {}
+		let callback : Function | null = null;
+
+		args.forEach(item => {
+			if (typeof item === 'function') {
+				callback = item
+			} else if (['string'].includes(typeof item)) {
+				theme = item
+			} else if (typeof item === 'object') {
+				opts = item
 			}
+		})
+
+		// #ifdef WEB
+		library.env.domSupported = true
+		library.env.hasGlobalWindow = true
+		library.env.node = false
+		library.env.pointerEventsSupported = false
+		library.env.svgSupported = true
+		library.env.touchEventsSupported = true
+		library.env.transform3dSupported = true
+		library.env.transformSupported = true
+		library.env.worker = false
+		library.env.wxa = false
+		chartInstance = library.init(chartRef.value, theme, opts)
+		// window.addEventListener('touchstart', touchstart)
+		// window.addEventListener('touchmove', touchmove)
+		// window.addEventListener('touchend', touchend)
+		// #endif
+
+		// #ifndef WEB
+		let config = await getContext();
+		setCanvasCreator(library, config)
+		chartInstance = library.init(config.canvas, theme, Object.assign({}, config, opts))
+		// #endif
+		if (callback != null && typeof callback == 'function') {
+			callbackQueue.push(callback)
 		}
-	};
+		return new Promise<Echarts>((resolve) => {
+			initializationQueue.push(resolve)
+			processInitializationQueue()
+		})
+	}
+	onMounted(() => {
+		nextTick(() => {
+			finished.value = true
+			processInitializationQueue()
+			emits('finished')
+		})
+	})
+	onUnmounted(() => {
+		// #ifdef WEB
+		// window.removeEventListener('touchstart', touchstart)
+		// window.removeEventListener('touchmove', touchmove)
+		// window.removeEventListener('touchend', touchend)
+		// #endif
+	})
+	// #endif
+
+	defineExpose({
+		init,
+		setOption,
+		showLoading,
+		hideLoading,
+		clear,
+		dispose,
+		resize,
+		canvasToTempFilePath
+	})
 </script>
 <style lang="scss">
 	.lime-echart {
 		flex: 1;
+		width: 100%;
 	}
 </style>

+ 434 - 456
src/uni_modules/lime-echart/components/l-echart/l-echart.vue

@@ -1,506 +1,484 @@
 <template>
-	<view class="lime-echart" :style="customStyle" v-if="canvasId" ref="limeEchart" :aria-label="ariaLabel">
-		<!-- #ifndef APP-NVUE -->
-		<canvas
-			class="lime-echart__canvas"
-			v-if="use2dCanvas"
-			type="2d"
-			:id="canvasId"
-			:style="canvasStyle"
+	<!-- #ifndef APP-NVUE || WEB -->
+	<view class="lime-echart" 
+		:style="[lStyle]" 
+		v-if="canvasId" 
+		ref="chartContainer" 
+		:aria-label="'图表'">
+		<canvas class="lime-echart__canvas" 
+			type="2d" 
+			:style="[styles]"
+			:id="canvasId" 
 			:disable-scroll="isDisableScroll"
-			@touchstart="touchStart"
-			@touchmove="touchMove"
-			@touchend="touchEnd"
-		/>
-		<!-- <canvas
-			class="lime-echart__canvas"
-			v-else-if="isPC"
-			:style="canvasStyle"
-			:id="canvasId"
 			:canvas-id="canvasId"
-			:disable-scroll="isDisableScroll"
-			@mousedown="touchStart"
-			@mousemove="touchMove"
-			@mouseup="touchEnd"
-		/> -->
-		<canvas
-			class="lime-echart__canvas"
-			v-else
-			:width="nodeWidth"
-			:height="nodeHeight"
-			:style="canvasStyle"
-			:canvas-id="canvasId"
-			:id="canvasId"
-			:disable-scroll="isDisableScroll"
-			@touchstart="touchStart"
-			@touchmove="touchMove"
-			@touchend="touchEnd"
-		/>
-		<view class="lime-echart__mask"
-			v-if="isPC"
-			@mousedown="touchStart"
-			@mousemove="touchMove"
-			@mouseup="touchEnd"
-			@touchstart="touchStart"
-			@touchmove="touchMove"
-			@touchend="touchEnd">
-		</view>
-		<canvas v-if="isOffscreenCanvas" :style="offscreenStyle" :canvas-id="offscreenCanvasId"></canvas>
-		<!-- #endif -->
-		<!-- #ifdef APP-NVUE -->
-		<web-view
-			class="lime-echart__canvas"
-			:id="canvasId"
-			:style="canvasStyle"
-			:webview-styles="webviewStyles"
-			ref="webview"
-			src="/uni_modules/lime-echart/static/nvue.html?v=1"
-			@pagefinish="finished = true"
-			@onPostMessage="onMessage"
-		></web-view>
-		<!-- #endif -->
+			@touchstart="handleTouchStart" 
+			@touchmove="handleTouchMove"
+			@touchend="handleTouchEnd">
+		</canvas>
 	</view>
+	<!-- #endif -->
+	<!-- #ifdef WEB -->
+	<div class="lime-echart" ref="chartContainer" :style="[styles, lStyle]"></div>
+	<!-- #endif -->
+	<!-- #ifdef APP-NVUE -->
+	<view class="lime-echart" :style="[lStyle]">
+		<web-view class="lime-echart__canvas" 
+			:webview-styles="webviewStyles" 
+			:style="[styles]"
+			ref="chartContainer"
+			src="/uni_modules/lime-echart/static/app/uvue.html?v=1" 
+			@pagefinish="isInitialized = true"
+			@onPostMessage="handleWebviewMessage"></web-view>
+	</view>
+	<!-- #endif -->
 </template>
 
-<script>
-// #ifdef VUE3
-// #ifdef APP-PLUS
-global = {}
-// #endif
-// #endif
-// #ifndef APP-NVUE
-import {Canvas, setCanvasCreator, dispatch} from './canvas';
-import {wrapTouch, convertTouchesToArray, devicePixelRatio ,sleep, canIUseCanvas2d, getRect} from './utils';
-// #endif
-// #ifdef APP-NVUE
-import { base64ToPath, sleep } from './utils';
-import {Echarts} from './nvue'
-// #endif
-const charts = {}
-const echartsObj = {}
-export default {
-	name: 'lime-echart',
-	props: {
-		// #ifdef MP-WEIXIN || MP-TOUTIAO
-		type: {
-			type: String,
-			default: '2d'
-		},
-		// #endif
-		// #ifdef APP-NVUE
-		webviewStyles: Object,
-		// hybrid: Boolean,
-		// #endif
-		customStyle: String,
-		isDisableScroll: Boolean,
-		isClickable: {
-			type: Boolean,
-			default: true
-		},
-		enableHover: Boolean,
-		beforeDelay: {
-			type: Number,
-			default: 30
-		}
-	},
-	data() {
-		return {
-			// #ifdef MP-WEIXIN || MP-TOUTIAO || MP-ALIPAY
-			use2dCanvas: true,
-			// #endif
-			// #ifndef MP-WEIXIN || MP-TOUTIAO || MP-ALIPAY
-			use2dCanvas: false,
-			// #endif
-			ariaLabel: '图表',
-			width: null,
-			height: null,
-			nodeWidth: null,
-			nodeHeight: null,
-			// canvasNode: null,
-			config: {},
-			inited: false,
-			finished: false,
-			file: '',
-			platform: '',
-			isPC: false,
-			isDown: false,
-			isOffscreenCanvas: false,
-			offscreenWidth: 0,
-			offscreenHeight: 0
-		};
-	},
-	computed: {
-		canvasId() {
-			return `lime-echart${this._ && this._.uid || this._uid}`
-		},
-		offscreenCanvasId() {
-			return `${this.canvasId}_offscreen`
-		},
-		offscreenStyle() {
-			return `width:${this.offscreenWidth}px;height: ${this.offscreenHeight}px; position: fixed; left: 99999px; background: red`
-		},
-		canvasStyle() {
-			return  this.width && this.height ? ('width:' + this.width + 'px;height:' + this.height + 'px') : ''
-		}
-	},
-	// #ifndef VUE3
-	beforeDestroy() {
-		this.clear()
-		this.dispose()
-		// #ifdef H5
-		if(this.isPC) {
-			document.removeEventListener('mousewheel', this.mousewheel)
-		}
-		// #endif
-	},
+<script lang="ts">
+	// @ts-nocheck
+	import { defineComponent, getCurrentInstance, ref, onMounted, nextTick, onBeforeUnmount, watch, computed } from './vue'
+	import echartProps from './props'
+	
+	// #ifndef APP-NVUE || WEB
+	import { Canvas, setCanvasCreator, dispatch } from './canvas';
+	import { wrapTouch, convertTouchesToArray, devicePixelRatio ,sleep, canIUseCanvas2d, getRect, getDeviceInfo } from './utils';
 	// #endif
-	// #ifdef VUE3
-	beforeUnmount() {
-		this.clear()
-		this.dispose()
-		// #ifdef H5
-		if(this.isPC) {
-			document.removeEventListener('mousewheel', this.mousewheel)
-		}
-		// #endif
-	},
+	// #ifdef APP-NVUE
+	import { base64ToPath, sleep } from './utils';
+	import { Echarts } from './nvue'
 	// #endif
-	created() {
-		// #ifdef H5
-		if(!('ontouchstart' in window)) {
-			this.isPC = true
-			document.addEventListener('mousewheel', this.mousewheel)
-		}
-		// #endif
-		// #ifdef MP-WEIXIN || MP-TOUTIAO || MP-ALIPAY
-		const { platform } = uni.getSystemInfoSync();
-		this.isPC = /windows/i.test(platform)
-		// #endif
-		this.use2dCanvas = this.type === '2d' && canIUseCanvas2d()
-	},
-	mounted() {
-		this.$nextTick(() => {
-			this.$emit('finished')
-		})
-	},
-	methods: {
-		// #ifdef APP-NVUE
-		onMessage(e) {
-			const res = e?.detail?.data[0] || null;
-			 if (res?.event) {
-				 const data = JSON.parse(res.data)
-				if(res.event === 'inited') {
-					this.inited = true
-				} else if(res.event.startsWith('@')){
-					this.chart.dispatchAction(res.event.split('@')[1], data.options)
+	// #ifdef WEB
+	import * as echartsLibrary from '@/uni_modules/lime-echart/static/web/echarts.esm.min.js';
+	// #endif
+	
+	// #ifdef APP-VUE
+	import '@/uni_modules/lime-echart/static/app/echarts.min.js';
+	const echartsLibrary = globalThis.echarts
+	// #endif
+	
+	
+	export default defineComponent({
+		props: echartProps,
+		emits: ['finished'],
+		setup(props, { emit, expose }) {
+			// #ifndef APP-NVUE || WEB || APP-VUE
+			let echartsLibrary = null
+			// #endif
+			
+			const instance = getCurrentInstance()!;
+			const canvasId = `lime-echart-${instance.uid}`
+			const isInitialized = ref(false)
+			const chartContainer = ref(null)
+			
+			type ChartOptions = Record<string, any>
+			type EChartsInstance = typeof echartsLibrary
+			type EChartsResolveCallback = (value: EChartsInstance) => void
+			
+			const initializationQueue = [] as EChartsResolveCallback[]
+			const callbackQueue = [] as EChartsResolveCallback[]
+			
+			let chartInstance: null | EChartsInstance = null
+			
+			const styles = computed(()=> {
+				if(props.landscape) {
+					return {
+						transform: 'translate(-50%,-50%) rotate(90deg)', 
+						top: '50%',
+						left: '50%',
+					}
 				}
-				
-				this.$emit(res.event, data);
-			} else if(res?.file){
-				this.file = res.data
-			} else if(!res[0] && JSON.stringify(res[0]) != '{}'){
-				console.error(res);
-			} else {
-				console.log(...res)
-			}
-		},
-		// #endif
-		setChart(callback) {
-			if(!this.chart) {
+				return {}
+			})
+			
+			const checkInitialization = (): boolean => {
+				if(chartInstance) return false
 				console.warn(`组件还未初始化,请先使用 init`)
-				return
-			}
-			if(typeof callback === 'function' && this.chart) {
-				callback(this.chart);
+				return true
 			}
-			// #ifdef APP-NVUE
-			if(typeof callback === 'function') {
-				this.$refs.webview.evalJs(`setChart(${JSON.stringify(callback.toString())}, ${JSON.stringify(this.chart.options)})`);
-			}
-			// #endif
-		},
-		setOption() {
-			if (!this.chart || !this.chart.setOption) {
-				console.warn(`组件还未初始化,请先使用 init`)
-				return
+			
+			const setOption = (options: ChartOptions) => {
+				if (checkInitialization()) return
+				chartInstance!.setOption(options);
 			}
-			this.chart.setOption(...arguments);
-		},
-		showLoading() {
-			if(this.chart) {
-				this.chart.showLoading(...arguments)
+			
+			const hideLoading = () => {
+				if (checkInitialization()) return
+				chartInstance!.showLoading();
 			}
-		},
-		hideLoading() {
-			if(this.chart) {
-				this.chart.hideLoading()
+			
+			const showLoading = () => {
+				if (checkInitialization()) return
+				chartInstance!.hideLoading();
 			}
-		},
-		clear() {
-			if(this.chart) {
-				this.chart.clear()
+			
+			const clear = () => {
+				if (checkInitialization()) return
+				chartInstance!.clear();
 			}
-		},
-		dispose() {
-			if(this.chart) {
-				this.chart.dispose()
+			
+			const dispose = () => {
+				if (checkInitialization()) return
+				chartInstance!.dispose();
 			}
-		},
-		resize(size) {
-			if(size && size.width && size.height) {
-				this.height = size.height
-				this.width = size.width
-				if(this.chart) {this.chart.resize(size)}
-			} else {
-				this.$nextTick(() => {
-					uni.createSelectorQuery()
-						.in(this)
-						.select(`.lime-echart`)
-						.boundingClientRect()
-						.exec(res => {
-							if (res) {
-								let { width, height } = res[0];
-								this.width = width = width || 300;
-								this.height = height = height || 300;
-								this.chart.resize({width, height})
-							}
-						});
-				})
+			const processInitializationQueue = () => {
+				while (initializationQueue.length > 0) {
+					if (chartInstance != null) {
+						const resolve = initializationQueue.pop() as EChartsResolveCallback
+						resolve(chartInstance!)
+					}
+				}
 				
+				if (chartInstance != null) {
+					while (callbackQueue.length > 0) {
+						const callback = callbackQueue.pop() as EChartsResolveCallback
+						callback(chartInstance!)
+					}
+				}
 			}
 			
-		},
-		canvasToTempFilePath(args = {}) {
-			// #ifndef APP-NVUE
-			const { use2dCanvas, canvasId } = this;
-			return new Promise((resolve, reject) => {
-				const copyArgs = Object.assign({
-					canvasId,
-					success: resolve,
-					fail: reject
-				}, args);
-				if (use2dCanvas) {
-					delete copyArgs.canvasId;
-					copyArgs.canvas = this.canvasNode;
-				}
-				uni.canvasToTempFilePath(copyArgs, this);
-			});
-			// #endif
-			// #ifdef APP-NVUE
-			this.file = ''
-			this.$refs.webview.evalJs(`canvasToTempFilePath()`);
-			return new Promise((resolve, reject) => {
-				this.$watch('file', async (file) => {
-					if(file) {
-						const tempFilePath = await base64ToPath(file)
-						resolve(args.success({tempFilePath}))
-					} else {
-						reject(args.fail({error: ``}))
-					}
+			const resize = (dimensions?: { width?: number; height?: number }) => {
+				if (checkInitialization()) return
+				// #ifdef APP-NVUE || WEB
+				chartInstance!.resize(dimensions);
+				// #endif
+				// #ifndef APP-NVUE || WEB
+				getRect(`#${canvasId}`, instance.proxy).then(res => {
+					chartInstance!.resize({width: res.width, height: res.height});
 				})
-			})
-			// #endif
-		},
-		async init(echarts, ...args) {
-			// #ifndef APP-NVUE
-			if(arguments && arguments.length < 1) {
-				console.error('缺少参数:init(echarts, theme?:string, opts?: object, callback?: function)')
-				return
+				// #endif
 			}
-			// #endif
-			let theme=null,opts={},callback;
 			
-			Array.from(arguments).forEach(item => {
-				if(typeof item === 'function') {
-					callback = item
+			// #ifdef APP-NVUE
+			let chartFile = ref(null);
+			const handleWebviewMessage = (e) => {
+				const detail = e?.detail?.data[0] || null;
+				const data = detail?.data
+				const key = detail?.event
+				const options = data?.options
+				const event = data?.event
+				const file = detail?.file
+				if (key == 'log' && data) {
+					console.log(data)
 				}
-				if(['string'].includes(typeof item)) {
-					theme = item
+				if(event) {
+					chartInstance.dispatchAction(event.replace(/"/g,''), options)
 				}
-				if(typeof item === 'object') {
-					opts = item
+				if(file) {
+					chartFile.value = file
 				}
-			})
-			
-			if(this.beforeDelay) {
-				await sleep(this.beforeDelay)
 			}
-			let config = await this.getContext();
-			// #ifndef APP-NVUE
-			setCanvasCreator(echarts, config)
-			this.chart = echarts.init(config.canvas, theme, Object.assign({}, config, opts))
-			if(typeof callback === 'function') {
-				callback(this.chart)
-			} else {
-				return this.chart
-			}
-			// #endif
-			// #ifdef APP-NVUE
-			this.chart = new Echarts(this.$refs.webview)
-			this.$refs.webview.evalJs(`init(null, null, ${JSON.stringify(opts)}, ${theme})`)
-			if(callback) {
-				callback(this.chart)
-			} else {
-				return this.chart
+			
+			const canvasToTempFilePath = (options: ChartOptions) => {
+				if (checkInitialization()) return
+				chartContainer.value.evalJs(`canvasToTempFilePath()`);
+				watch(chartFile, async (file) =>{
+					if(!file) return
+					const tempFilePath = await base64ToPath(file)
+					options.success({tempFilePath})
+				})
 			}
-			// #endif
-		},
-		getContext() {
-			// #ifdef APP-NVUE
-			if(this.finished) {
-				return Promise.resolve(this.finished)
+			
+			const getContext = () => {
+				if(isInitialized.value) {
+					return Promise.resolve(isInitialized.value)
+				}
+				return new Promise(resolve => {
+					watch(isInitialized, (val) =>{
+						if(!val) return
+						resolve(val)
+					})
+				})
 			}
-			return new Promise(resolve => {
-				this.$watch('finished', (val) => {
-					if(val) {
-						resolve(this.finished)
+			const init = async (echarts, ...args) => {
+				let theme: string | null = null
+				let config:Record<string, any> = {}
+				let callback: Function | null = null;
+							
+				args.forEach(item => {
+					if (typeof item === 'function') {
+						callback = item
+					} else if (typeof item === 'string') {
+						theme = item
+					} else if (typeof item === 'object') {
+						config = item
 					}
 				})
-			})
+				if(props.beforeDelay) {
+					await sleep(props.beforeDelay)
+				}
+				await getContext();
+				chartInstance = new Echarts(chartContainer.value)
+				chartContainer.value.evalJs(`init(null, null, ${JSON.stringify(config)}, ${theme})`)
+				if (callback && typeof callback === 'function') {
+					callbackQueue.push(callback)
+				}
+				
+				return new Promise<EChartsInstance>((resolve) => {
+					nextTick(()=>{
+						initializationQueue.push(resolve)
+						processInitializationQueue()
+					})
+				})
+			}
+			
 			// #endif
-			// #ifndef APP-NVUE
-			return getRect(`#${this.canvasId}`, {context: this, type: this.use2dCanvas ? 'fields': 'boundingClientRect'}).then(res => {
-				if(res) {
+			
+			
+			// #ifndef APP-NVUE || WEB
+			let canvasNode;
+			const canvasToTempFilePath = (options: ChartOptions) => {
+				if (checkInitialization()) return
+				if(canvasNode) {
+					options.success?.({
+						tempFilePath: canvasNode.toDataURL()
+					}) 
+				} else {
+					uni.canvasToTempFilePath({
+						...options,
+						canvasId
+					}, instance.proxy);
+				}
+			}
+			
+			const getContext = () => {
+				return getRect(`#${canvasId}`, instance.proxy).then(res => {
 					let dpr = devicePixelRatio
 					let {width, height, node} = res
-					let canvas;
-					this.width = width = width || 300;
-					this.height = height = height || 300;
-					if(node) {
+					let canvas: Canvas | null = null;
+					if(!(width || height)) {
+						return Promise.reject('no rect')
+					}
+					if(node && node.getContext) {
 						const ctx = node.getContext('2d');
-						canvas = new Canvas(ctx, this, true, node);
-						this.canvasNode = node
+						canvas = new Canvas(ctx, instance.proxy, true, node);
+						canvasNode = node
 					} else {
-						// #ifdef MP-TOUTIAO
-						dpr = !this.isPC ? devicePixelRatio : 1// 1.25
-						// #endif
-						// #ifndef MP-ALIPAY || MP-TOUTIAO
-						dpr = this.isPC ? devicePixelRatio : 1
-						// #endif
-						// #ifdef MP-ALIPAY || MP-LARK
-						dpr = devicePixelRatio
-						// #endif
-						this.rect = res
-						this.nodeWidth = width * dpr;
-						this.nodeHeight = height * dpr;
-						const ctx = uni.createCanvasContext(this.canvasId, this);
-						canvas =  new Canvas(ctx, this, false);
+						dpr = 1
+						const ctx = uni.createCanvasContext(canvasId, instance.proxy);
+						canvas = new Canvas(ctx, instance.proxy, false);
 					}
-					return { canvas, width, height, devicePixelRatio: dpr, node };
-				} else {
-					return {}
-				}
-			})
-			// #endif
-		},
-		// #ifndef APP-NVUE
-		getRelative(e, touches) {
-			let { clientX, clientY } = e
-			if(!(clientX && clientY) && touches && touches[0]) {
-				clientX = touches[0].clientX
-				clientY = touches[0].clientY
+					return { canvas, width, height, devicePixelRatio: dpr, node }
+				})
 			}
-			return {x: clientX - this.rect.left, y: clientY - this.rect.top, wheelDelta: e.wheelDelta || 0}
-		},
-		getTouch(e, touches) {
-			const {x} = touches && touches[0] || {}
-			return x ? touches[0] : this.getRelative(e, touches);
-		},
-		touchStart(e) {
-			this.isDown = true
-			const next = () => {
-				const touches = convertTouchesToArray(e.touches)
-				if(this.chart) {
-					const touch = this.getTouch(e, touches)
-					this.startX = touch.x
-					this.startY = touch.y
-					this.startT = new Date()
-					const handler = this.chart.getZr().handler;
-					dispatch.call(handler, 'mousedown', touch)
-					dispatch.call(handler, 'mousemove', touch)
-					handler.processGesture(wrapTouch(e), 'start');
-					clearTimeout(this.endTimer);
+			const getTouch = (e) => {
+				const touches = e.touches[0]
+				const touch = props.landscape 
+					? 	{
+							x: touches.y,
+							y: touches.x
+						}
+					:  {
+							x: touches.x,
+							y: touches.y
+						}
+				return touch
+			}
+			const handleTouchStart = (e) => {
+				if (chartInstance == null) return
+				const handler = chartInstance.getZr().handler;
+				const touch = getTouch(e)
+				dispatch.call(handler, 'mousedown', touch)
+				dispatch.call(handler, 'click', touch)
+			}
+			const handleTouchMove = (e) => {
+				if (chartInstance == null) return
+				const handler = chartInstance.getZr().handler;
+				const touch = getTouch(e)
+				dispatch.call(handler, 'mousemove', touch)
+			}
+			const handleTouchEnd = (e) => {
+				if (chartInstance == null || !props.autoHideTooltip) return
+				const handler = chartInstance.getZr().handler;
+			
+				const touch = {
+					x: 999999999,
+					y: 999999999
 				}
-				
+			
+				dispatch.call(handler, 'mousemove', touch)
+				dispatch.call(handler, 'touchend', touch)
+			
 			}
-			if(this.isPC) {
-				getRect(`#${this.canvasId}`, {context: this}).then(res => {
-					this.rect = res
-					next()
+			const init = async (echartsLib: EChartsInstance = echartsLibrary, ...args: any[]): Promise<EChartsInstance> => {
+				const library = echartsLib || echartsLibrary
+				if (!library) {
+					console.error('ECharts library is required');
+					return Promise.reject('ECharts library is required');
+				}
+				let theme: string | null = null
+				let config:Record<string, any> = {}
+				let callback: Function | null = null;
+			
+				args.forEach(item => {
+					if (typeof item === 'function') {
+						callback = item
+					} else if (typeof item === 'string') {
+						theme = item
+					} else if (typeof item === 'object') {
+						config = item
+					}
+				})
+				if(props.beforeDelay) {
+					await sleep(props.beforeDelay)
+				}
+				let options = await getContext();
+				setCanvasCreator(library, options)
+				chartInstance = library.init(options.canvas, theme, Object.assign({}, options, config))
+				if (callback && typeof callback === 'function') {
+					callbackQueue.push(callback)
+				}
+				return new Promise<EChartsInstance>((resolve) => {
+					initializationQueue.push(resolve)
+					processInitializationQueue()
 				})
-				return
 			}
-			next()
-		},
-		touchMove(e) {
-			if(this.isPC && this.enableHover && !this.isDown) {this.isDown = true}
-			const touches = convertTouchesToArray(e.touches)
-			if (this.chart && this.isDown) {
-				const handler = this.chart.getZr().handler;
-				dispatch.call(handler, 'mousemove', this.getTouch(e, touches))
-				handler.processGesture(wrapTouch(e), 'change');
+			
+			// #endif
+			
+			
+			// #ifdef WEB
+			const canvasToTempFilePath = (options: ChartOptions) => {
+				if (checkInitialization()) return
+				options.success?.({
+					tempFilePath: chartInstance._api.getDataURL()
+				}) 
 			}
 			
-		},
-		touchEnd(e) {
-			this.isDown = false
-			if (this.chart) {
-				const touches = convertTouchesToArray(e.changedTouches)
-				const {x} = touches && touches[0] || {}
-				const touch = (x ? touches[0] : this.getRelative(e, touches)) || {};
-				const handler = this.chart.getZr().handler;
-				const isClick = Math.abs(touch.x - this.startX) < 10 && new Date() - this.startT < 200;
-				dispatch.call(handler, 'mouseup', touch)
-				handler.processGesture(wrapTouch(e), 'end');
-				if(isClick) {
-					dispatch.call(handler, 'click', touch)
-				} else {
-					this.endTimer = setTimeout(() => {
-						dispatch.call(handler, 'mousemove', {x: 999999999,y: 999999999});
-						dispatch.call(handler, 'mouseup', {x: 999999999,y: 999999999});
-					},50)
+			const init = async (echarts: EChartsInstance = echartsLibrary, ...args: any[]): Promise<EChartsInstance> => {
+				const library = echarts || echartsLibrary
+				if (!library) {
+					console.error('ECharts library is required');
+					return Promise.reject('ECharts library is required');
+				}
+				
+				let theme: string | null = null
+				let config = {}
+				let callback: Function | null = null;
+
+				args.forEach(item => {
+					if (typeof item === 'function') {
+						callback = item
+					} else if (typeof item === 'string') {
+						theme = item
+					} else if (typeof item === 'object') {
+						config = item
+					}
+				})
+				
+				// Configure ECharts environment
+				library.env.domSupported = true
+				library.env.hasGlobalWindow = true
+				library.env.node = false
+				library.env.pointerEventsSupported = false
+				library.env.svgSupported = true
+				library.env.touchEventsSupported = true
+				library.env.transform3dSupported = true
+				library.env.transformSupported = true
+				library.env.worker = false
+				library.env.wxa = false
+				
+				chartInstance = library.init(chartContainer.value, theme, config)
+				
+				if (callback != null && typeof callback === 'function') {
+					callbackQueue.push(callback)
 				}
+				
+				return new Promise<EChartsInstance>((resolve) => {
+					initializationQueue.push(resolve)
+					processInitializationQueue()
+				})
 			}
-		},
-		// #endif
-		// #ifdef H5
-		mousewheel(e){
-			if(this.chart) {
-				dispatch.call(this.chart.getZr().handler, 'mousewheel', this.getTouch(e))
+			// #endif
+			
+			
+			
+			
+			onMounted(() => {
+				nextTick(() => {
+					// #ifndef APP-NVUE
+					isInitialized.value = true
+					// #endif
+					emit('finished')
+					processInitializationQueue()
+				})
+			})
+			onBeforeUnmount(()=> {
+				clear()
+				dispose()
+			})
+			
+			// #ifdef VUE3
+			expose({
+				init,
+				setOption,
+				hideLoading,
+				showLoading,
+				clear,
+				dispose,
+				resize,
+				canvasToTempFilePath
+			})
+			// #endif
+
+			return {
+				canvasId,
+				chartContainer,
+				styles,
+				// #ifndef WEB || APP-NVUE
+				handleTouchStart,
+				handleTouchMove,
+				handleTouchEnd,
+				// #endif
+				
+				// #ifdef APP-NVUE
+				handleWebviewMessage,
+				isInitialized,
+				// #endif
+				
+				// #ifdef VUE2
+				init,
+				setOption,
+				hideLoading,
+				showLoading,
+				clear,
+				dispose,
+				resize,
+				canvasToTempFilePath,
+				// #endif
 			}
 		}
-		// #endif
-	}
-};
+	})
 </script>
-<style>	
-.lime-echart {
-	position: relative;
-	/* #ifndef APP-NVUE */
-	width: 100%;
-	height: 100%;
-	/* #endif */
-	/* #ifdef APP-NVUE */
-	flex: 1;
-	/* #endif */
-}
-.lime-echart__canvas {
+
+<style>
+	.lime-echart {
+		position: relative;
+		/* #ifndef APP-NVUE */
+		width: 100%;
+		height: 100%;
+		/* #endif */
+		/* #ifdef APP-NVUE */
+		flex: 1;
+		/* #endif */
+	}
+
+	.lime-echart__canvas {
+		/* #ifndef APP-NVUE */
+		width: 100%;
+		height: 100%;
+		/* #endif */
+		/* #ifdef APP-NVUE */
+		flex: 1;
+		/* #endif */
+	}
+
 	/* #ifndef APP-NVUE */
-	width: 100%;
-	height: 100%;
-	/* #endif */
-	/* #ifdef APP-NVUE */
-	flex: 1;
+	.lime-echart__mask {
+		position: absolute;
+		width: 100%;
+		height: 100%;
+		left: 0;
+		top: 0;
+		z-index: 1;
+	}
 	/* #endif */
-}
-/* #ifndef APP-NVUE */
-.lime-echart__mask {
-	position: absolute;
-	width: 100%;
-	height: 100%;
-	left: 0;
-	top: 0;
-	z-index: 1;
-}
-/* #endif */
-</style>
+</style>

+ 515 - 0
src/uni_modules/lime-echart/components/l-echart/l-echart_old.vue

@@ -0,0 +1,515 @@
+<template>
+	<view class="lime-echart" :style="[customStyle]" v-if="canvasId" ref="limeEchart" :aria-label="ariaLabel">
+		<!-- #ifndef APP-NVUE -->
+		<canvas
+			class="lime-echart__canvas"
+			v-if="use2dCanvas"
+			type="2d"
+			:id="canvasId"
+			:style="canvasStyle"
+			:disable-scroll="isDisableScroll"
+			@touchstart="touchStart"
+			@touchmove="touchMove"
+			@touchend="touchEnd"
+		/>
+		<canvas
+			class="lime-echart__canvas"
+			v-else
+			:width="nodeWidth"
+			:height="nodeHeight"
+			:style="canvasStyle"
+			:canvas-id="canvasId"
+			:id="canvasId"
+			:disable-scroll="isDisableScroll"
+			@touchstart="touchStart"
+			@touchmove="touchMove"
+			@touchend="touchEnd"
+		/>
+		<view class="lime-echart__mask"
+			v-if="isPC"
+			@mousedown="touchStart"
+			@mousemove="touchMove"
+			@mouseup="touchEnd"
+			@touchstart="touchStart"
+			@touchmove="touchMove"
+			@touchend="touchEnd">
+		</view>
+		<canvas v-if="isOffscreenCanvas" :style="offscreenStyle" :canvas-id="offscreenCanvasId"></canvas>
+		<!-- #endif -->
+		<!-- #ifdef APP-NVUE -->
+		<web-view
+			class="lime-echart__canvas"
+			:id="canvasId"
+			:style="canvasStyle"
+			:webview-styles="webviewStyles"
+			ref="webview"
+			src="/uni_modules/lime-echart/static/uvue.html?v=1"
+			@pagefinish="finished = true"
+			@onPostMessage="onMessage"
+		></web-view>
+		<!-- #endif -->
+	</view>
+</template>
+
+<script>
+// @ts-nocheck
+// #ifndef APP-NVUE
+import {Canvas, setCanvasCreator, dispatch} from './canvas';
+import {wrapTouch, convertTouchesToArray, devicePixelRatio ,sleep, canIUseCanvas2d, getRect, getDeviceInfo} from './utils';
+// #endif
+// #ifdef APP-NVUE
+import { base64ToPath, sleep } from './utils';
+import {Echarts} from './nvue'
+// #endif
+
+/**
+ * LimeChart 图表
+ * @description 全端兼容的eCharts
+ * @tutorial https://ext.dcloud.net.cn/plugin?id=4899
+
+ * @property {String} customStyle 自定义样式
+ * @property {String} type 指定 canvas 类型
+ * @value 2d 使用canvas 2d,部分小程序支持
+ * @value '' 使用原生canvas,会有层级问题
+ * @value bottom right	不缩放图片,只显示图片的右下边区域
+ * @property {Boolean} isDisableScroll	 
+ * @property {number} beforeDelay = [30]  延迟初始化 (毫秒)
+ * @property {Boolean} enableHover PC端使用鼠标悬浮
+
+ * @event {Function} finished 加载完成触发
+ */
+export default {
+	name: 'lime-echart',
+	props: {
+		// #ifdef MP-WEIXIN || MP-TOUTIAO
+		type: {
+			type: String,
+			default: '2d'
+		},
+		// #endif
+		// #ifdef APP-NVUE
+		webviewStyles: Object,
+		// hybrid: Boolean,
+		// #endif
+		customStyle: String,
+		isDisableScroll: Boolean,
+		isClickable: {
+			type: Boolean,
+			default: true
+		},
+		enableHover: Boolean,
+		beforeDelay: {
+			type: Number,
+			default: 30
+		},
+		landscape: Boolean
+	},
+	data() {
+		return {
+			// #ifdef MP-WEIXIN || MP-TOUTIAO || MP-ALIPAY
+			use2dCanvas: true,
+			// #endif
+			// #ifndef MP-WEIXIN || MP-TOUTIAO || MP-ALIPAY
+			use2dCanvas: false,
+			// #endif
+			ariaLabel: '图表',
+			width: null,
+			height: null,
+			nodeWidth: null,
+			nodeHeight: null,
+			// canvasNode: null,
+			config: {},
+			inited: false,
+			finished: false,
+			file: '',
+			platform: '',
+			isPC: false,
+			isDown: false,
+			isOffscreenCanvas: false,
+			offscreenWidth: 0,
+			offscreenHeight: 0,
+		};
+	},
+	computed: {
+		rootStyle() {
+			if(this.landscape) {
+				return `transform: translate(-50%,-50%) rotate(90deg); top:50%; left:50%;`
+			}
+		},
+		canvasId() {
+			return `lime-echart${this._ && this._.uid || this._uid}`
+		},
+		offscreenCanvasId() {
+			return `${this.canvasId}_offscreen`
+		},
+		offscreenStyle() {
+			return `width:${this.offscreenWidth}px;height: ${this.offscreenHeight}px; position: fixed; left: 99999px; background: red`
+		},
+		canvasStyle() {
+			return this.rootStyle + (this.width && this.height ? ('width:' + this.width + 'px;height:' + this.height + 'px') : '')
+		}
+	},
+	// #ifndef VUE3
+	beforeDestroy() {
+		this.clear()
+		this.dispose()
+		// #ifdef H5
+		if(this.isPC) {
+			document.removeEventListener('mousewheel', this.mousewheel)
+		}
+		// #endif
+	},
+	// #endif
+	// #ifdef VUE3
+	beforeUnmount() {
+		this.clear()
+		this.dispose()
+		// #ifdef H5
+		if(this.isPC) {
+			document.removeEventListener('mousewheel', this.mousewheel)
+		}
+		// #endif
+	},
+	// #endif
+	created() {
+		// #ifdef H5
+		if(!('ontouchstart' in window)) {
+			this.isPC = true
+			document.addEventListener('mousewheel', this.mousewheel)
+		}
+		// #endif
+		// #ifdef MP-WEIXIN || MP-TOUTIAO || MP-ALIPAY
+		const { platform } = getDeviceInfo();
+		this.isPC = /windows/i.test(platform)
+		// #endif
+		this.use2dCanvas = this.type === '2d' && canIUseCanvas2d()
+	},
+	mounted() {
+		this.$nextTick(() => {
+			this.$emit('finished')
+		})
+	},
+	methods: {
+		// #ifdef APP-NVUE
+		onMessage(e) {
+			const detail = e?.detail?.data[0] || null;
+			const data = detail?.data
+			const key = detail?.event
+			const options = data?.options
+			const event = data?.event
+			const file = detail?.file
+			if (key == 'log' && data) {
+				console.log(data)
+			}
+			if(event) {
+				this.chart.dispatchAction(event.replace(/"/g,''), options)
+			}
+			if(file) {
+				thie.file = file
+			}
+		},
+		// #endif
+		setChart(callback) {
+			if(!this.chart) {
+				console.warn(`组件还未初始化,请先使用 init`)
+				return
+			}
+			if(typeof callback === 'function' && this.chart) {
+				callback(this.chart);
+			}
+			// #ifdef APP-NVUE
+			if(typeof callback === 'function') {
+				this.$refs.webview.evalJs(`setChart(${JSON.stringify(callback.toString())}, ${JSON.stringify(this.chart.options)})`);
+			}
+			// #endif
+		},
+		setOption() {
+			if (!this.chart || !this.chart.setOption) {
+				console.warn(`组件还未初始化,请先使用 init`)
+				return
+			}
+			this.chart.setOption(...arguments);
+		},
+		showLoading() {
+			if(this.chart) {
+				this.chart.showLoading(...arguments)
+			}
+		},
+		hideLoading() {
+			if(this.chart) {
+				this.chart.hideLoading()
+			}
+		},
+		clear() {
+			if(this.chart && !this.chart.isDisposed()) {
+				this.chart.clear()
+			}
+		},
+		dispose() {
+			if(this.chart && !this.chart.isDisposed()) {
+				this.chart.dispose()
+			}
+		},
+		resize(size) {
+			if(size && size.width && size.height) {
+				this.height = size.height
+				this.width = size.width
+				if(this.chart) {this.chart.resize(size)}
+			} else {
+				this.$nextTick(() => {
+					getRect('.lime-echart', this).then(res =>{
+						if (res) {
+							let { width, height } = res;
+							this.width = width = width || 300;
+							this.height = height = height || 300;
+							this.chart.resize({width, height})
+						}
+					})
+				})
+			}
+			
+		},
+		canvasToTempFilePath(args = {}) {
+			// #ifndef APP-NVUE
+			const { use2dCanvas, canvasId } = this;
+			return new Promise((resolve, reject) => {
+				const copyArgs = Object.assign({
+					canvasId,
+					success: resolve,
+					fail: reject
+				}, args);
+				if (use2dCanvas) {
+					delete copyArgs.canvasId;
+					copyArgs.canvas = this.canvasNode;
+				}
+				uni.canvasToTempFilePath(copyArgs, this);
+			});
+			// #endif
+			// #ifdef APP-NVUE
+			this.file = ''
+			this.$refs.webview.evalJs(`canvasToTempFilePath()`);
+			return new Promise((resolve, reject) => {
+				this.$watch('file', async (file) => {
+					if(file) {
+						const tempFilePath = await base64ToPath(file)
+						resolve(args.success({tempFilePath}))
+					} else {
+						reject(args.fail({error: ``}))
+					}
+				})
+			})
+			// #endif
+		},
+		async init(echarts, ...args) {
+			// #ifndef APP-NVUE
+			if(args && args.length == 0 && !echarts) {
+				console.error('缺少参数:init(echarts, theme?:string, opts?: object, callback?: function)')
+				return
+			}
+			// #endif
+			let theme=null,opts={},callback;
+			// Array.from(arguments)
+			args.forEach(item => {
+				if(typeof item === 'function') {
+					callback = item
+				}
+				if(['string'].includes(typeof item)) {
+					theme = item
+				}
+				if(typeof item === 'object') {
+					opts = item
+				}
+			})
+			if(this.beforeDelay) {
+				await sleep(this.beforeDelay)
+			}
+			let config = await this.getContext();
+			// #ifndef APP-NVUE
+			setCanvasCreator(echarts, config)
+			try {
+				this.chart = echarts.init(config.canvas, theme, Object.assign({}, config, opts || {}))
+				
+				callback?.(this.chart)
+				return this.chart
+			} catch(e) {
+				console.error("【lime-echarts】:", e)
+				return null
+			}
+			// #endif
+			// #ifdef APP-NVUE
+			this.chart = new Echarts(this.$refs.webview)
+			this.$refs.webview.evalJs(`init(null, null, ${JSON.stringify(opts)}, ${theme})`)
+			callback?.(this.chart)
+			return this.chart
+			// #endif
+		},
+		getContext() {
+			// #ifdef APP-NVUE
+			if(this.finished) {
+				return Promise.resolve(this.finished)
+			}
+			return new Promise(resolve => {
+				this.$watch('finished', (val) => {
+					if(val) {
+						resolve(this.finished)
+					}
+				})
+			})
+			// #endif
+			// #ifndef APP-NVUE
+			return getRect(`#${this.canvasId}`, this, this.use2dCanvas).then(res => {
+				if(res) {
+					let dpr = devicePixelRatio
+					let {width, height, node} = res
+					let canvas;
+					this.width = width = width || 300;
+					this.height = height = height || 300;
+					if(node) {
+						const ctx = node.getContext('2d');
+						canvas = new Canvas(ctx, this, true, node);
+						this.canvasNode = node
+					} else {
+						// #ifdef MP-TOUTIAO
+						dpr = !this.isPC ? devicePixelRatio : 1// 1.25
+						// #endif
+						// #ifndef MP-ALIPAY || MP-TOUTIAO
+						dpr = this.isPC ? devicePixelRatio : 1
+						// #endif
+						// #ifdef MP-ALIPAY || MP-LARK
+						dpr = devicePixelRatio
+						// #endif
+						// #ifdef WEB
+						dpr = 1
+						// #endif
+						this.rect = res
+						this.nodeWidth = width * dpr;
+						this.nodeHeight = height * dpr;
+						const ctx = uni.createCanvasContext(this.canvasId, this);
+						canvas =  new Canvas(ctx, this, false);
+					}
+					
+					return { canvas, width, height, devicePixelRatio: dpr, node };
+				} else {
+					return {}
+				}
+			})
+			// #endif
+		},
+		// #ifndef APP-NVUE
+		getRelative(e, touches) {
+			let { clientX, clientY } = e
+			if(!(clientX && clientY) && touches && touches[0]) {
+				clientX = touches[0].clientX
+				clientY = touches[0].clientY
+			}
+			return {x: clientX - this.rect.left, y: clientY - this.rect.top, wheelDelta: e.wheelDelta || 0}
+		},
+		getTouch(e, touches) {
+			const {x} = touches && touches[0] || {}
+			const touch = x ? touches[0] : this.getRelative(e, touches);
+			if(this.landscape) {
+				[touch.x, touch.y] = [touch.y, this.height - touch.x]
+			}
+			return touch;
+		},
+		touchStart(e) {
+			this.isDown = true
+			const next = () => {
+				const touches = convertTouchesToArray(e.touches)
+				if(this.chart) {
+					const touch = this.getTouch(e, touches)
+					this.startX = touch.x
+					this.startY = touch.y
+					this.startT = new Date()
+					const handler = this.chart.getZr().handler;
+					dispatch.call(handler, 'mousedown', touch)
+					dispatch.call(handler, 'mousemove', touch)
+					handler.processGesture(wrapTouch(e), 'start');
+					clearTimeout(this.endTimer);
+				}
+				
+			}
+			if(this.isPC) {
+				getRect(`#${this.canvasId}`, {context: this}).then(res => {
+					this.rect = res
+					next()
+				})
+				return
+			}
+			next()
+		},
+		touchMove(e) {
+			if(this.isPC && this.enableHover && !this.isDown) {this.isDown = true}
+			const touches = convertTouchesToArray(e.touches)
+			if (this.chart && this.isDown) {
+				const handler = this.chart.getZr().handler;
+				dispatch.call(handler, 'mousemove', this.getTouch(e, touches))
+				handler.processGesture(wrapTouch(e), 'change');
+			}
+			
+		},
+		touchEnd(e) {
+			this.isDown = false
+			if (this.chart) {
+				const touches = convertTouchesToArray(e.changedTouches)
+				const {x} = touches && touches[0] || {}
+				const touch = (x ? touches[0] : this.getRelative(e, touches)) || {};
+				if(this.landscape) {
+					[touch.x, touch.y] = [touch.y,  this.height - touch.x]
+				}
+				const handler = this.chart.getZr().handler;
+				const isClick = Math.abs(touch.x - this.startX) < 10 && new Date() - this.startT < 200;
+				dispatch.call(handler, 'mouseup', touch)
+				handler.processGesture(wrapTouch(e), 'end');
+				if(isClick) {
+					dispatch.call(handler, 'click', touch)
+				} else {
+					this.endTimer = setTimeout(() => {
+						dispatch.call(handler, 'mousemove', {x: 999999999,y: 999999999});
+						dispatch.call(handler, 'mouseup', {x: 999999999,y: 999999999});
+					},50)
+				}
+			}
+		},
+		// #endif
+		// #ifdef H5
+		mousewheel(e){
+			if(this.chart) {
+				dispatch.call(this.chart.getZr().handler, 'mousewheel', this.getTouch(e))
+			}
+		}
+		// #endif
+	}
+};
+</script>
+<style>	
+.lime-echart {
+	position: relative;
+	/* #ifndef APP-NVUE */
+	width: 100%;
+	height: 100%;
+	/* #endif */
+	/* #ifdef APP-NVUE */
+	flex: 1;
+	/* #endif */
+}
+.lime-echart__canvas {
+	/* #ifndef APP-NVUE */
+	width: 100%;
+	height: 100%;
+	/* #endif */
+	/* #ifdef APP-NVUE */
+	flex: 1;
+	/* #endif */
+}
+/* #ifndef APP-NVUE */
+.lime-echart__mask {
+	position: absolute;
+	width: 100%;
+	height: 100%;
+	left: 0;
+	top: 0;
+	z-index: 1;
+}
+/* #endif */
+</style>

+ 6 - 1
src/uni_modules/lime-echart/components/l-echart/nvue.js

@@ -6,6 +6,7 @@ export class Echarts {
 	}
 	setOption() {
 		this.options = arguments
+		console.log('setOption1')
 		this.webview.evalJs(`setOption(${JSON.stringify(arguments)})`);
 	}
 	getOption() {
@@ -25,7 +26,7 @@ export class Echarts {
 	}
 	resize(size) {
 		if(size) {
-			this.webview.evalJs(`resize(${size})`);
+			this.webview.evalJs(`resize(${JSON.stringify(size)})`);
 		} else {
 			this.webview.evalJs(`resize()`);
 		}
@@ -48,4 +49,8 @@ export class Echarts {
 			handler(options)
 		}
 	}
+	// 不让报错 无实际作用
+	isDisposed() {
+		return !!this.webview
+	}
 }

+ 27 - 0
src/uni_modules/lime-echart/components/l-echart/props.ts

@@ -0,0 +1,27 @@
+export default {
+	// #ifdef MP-WEIXIN || MP-TOUTIAO
+	type: {
+		type: String,
+		default: '2d'
+	},
+	// #endif
+	// #ifdef APP-NVUE
+	webviewStyles: Object,
+	// #endif
+	lStyle: String,
+	isDisableScroll: Boolean,
+	isClickable: {
+		type: Boolean,
+		default: true
+	},
+	enableHover: Boolean,
+	beforeDelay: {
+		type: Number,
+		default: 30
+	},
+	landscape: Boolean,
+	autoHideTooltip: {
+		type: Boolean,
+		default: false
+	}
+}

+ 11 - 0
src/uni_modules/lime-echart/components/l-echart/type.ts

@@ -0,0 +1,11 @@
+// @ts-nocheck
+export interface echartsProps {
+	webviewStyles?: UTSJSONObject,
+	lStyle?: string | UTSJSONObject
+	isDisableScroll: boolean;
+	isClickable: boolean;
+	enableHover: boolean;
+	beforeDelay: number;
+	landscape: boolean;
+	autoHideTooltip: boolean;
+}

+ 57 - 21
src/uni_modules/lime-echart/components/l-echart/utils.js

@@ -1,3 +1,44 @@
+// @ts-nocheck
+/**
+ * 获取设备基础信息
+ *
+ * @see [uni.getDeviceInfo](https://uniapp.dcloud.net.cn/api/system/getDeviceInfo.html)
+ */
+export function getDeviceInfo() {
+	if (uni.getDeviceInfo || uni.canIUse('getDeviceInfo')) {
+		return uni.getDeviceInfo();
+	} else {
+		return uni.getSystemInfoSync();
+	}
+}
+
+/**
+ * 获取窗口信息
+ *
+ * @see [uni.getWindowInfo](https://uniapp.dcloud.net.cn/api/system/getWindowInfo.html)
+ */
+export function getWindowInfo() {
+	if (uni.getWindowInfo || uni.canIUse('getWindowInfo')) {
+		return uni.getWindowInfo();
+	} else {
+		return uni.getSystemInfoSync();
+	}
+}
+
+/**
+ * 获取APP基础信息
+ *
+ * @see [uni.getAppBaseInfo](https://uniapp.dcloud.net.cn/api/system/getAppBaseInfo.html)
+ */
+export function getAppBaseInfo() {
+	if (uni.getAppBaseInfo || uni.canIUse('getAppBaseInfo')) {
+		return uni.getAppBaseInfo();
+	} else {
+		return uni.getSystemInfoSync();
+	}
+}
+
+
 // #ifndef APP-NVUE
 // 计算版本
 export function compareVersion(v1, v2) {
@@ -22,14 +63,16 @@ export function compareVersion(v1, v2) {
 	}
 	return 0
 }
-const systemInfo = uni.getSystemInfoSync();
+// const systemInfo = uni.getSystemInfoSync();
 
 function gte(version) {
 	// 截止 2023-03-22 mac pc小程序不支持 canvas 2d
-	let {
-		SDKVersion,
-		platform
-	} = systemInfo;
+	// let {
+	// 	SDKVersion,
+	// 	platform
+	// } = systemInfo;
+	const { platform } = getDeviceInfo();
+	let { SDKVersion } = getAppBaseInfo();
 	// #ifdef MP-ALIPAY
 	SDKVersion = my.SDKVersion
 	// #endif
@@ -67,6 +110,7 @@ export function convertTouchesToArray(touches) {
 }
 
 export function wrapTouch(event) {
+	event.touches = convertTouchesToArray(event.touches)
 	for (let i = 0; i < event.touches.length; ++i) {
 		const touch = event.touches[i];
 		touch.offsetX = touch.x;
@@ -74,7 +118,8 @@ export function wrapTouch(event) {
 	}
 	return event;
 }
-export const devicePixelRatio = uni.getSystemInfoSync().pixelRatio
+// export const devicePixelRatio = uni.getSystemInfoSync().pixelRatio
+export const devicePixelRatio = getWindowInfo().pixelRatio;
 // #endif
 // #ifdef APP-NVUE
 export function base64ToPath(base64) {
@@ -117,12 +162,7 @@ export function sleep(time) {
 }
 
 
-export function getRect(selector, options = {}) {
-	const typeDefault = 'boundingClientRect'
-	const {
-		context,
-		type = typeDefault
-	} = options
+export function getRect(selector, context) {
 	return new Promise((resolve, reject) => {
 		const dom = uni.createSelectorQuery().in(context).select(selector);
 		const result = (rect) => {
@@ -132,14 +172,10 @@ export function getRect(selector, options = {}) {
 				reject()
 			}
 		}
-		if (type == typeDefault) {
-			dom[type](result).exec()
-		} else {
-			dom[type]({
-				node: true,
-				size: true,
-				rect: true
-			}, result).exec()
-		}
+		dom.fields({
+			node: true,
+			size: true,
+			rect: true
+		}, result).exec()
 	});
 };

+ 44 - 13
src/uni_modules/lime-echart/components/l-echart/uvue.uts

@@ -1,4 +1,5 @@
-
+// @ts-nocheck
+// #ifdef APP
 type EchartsEventHandler = (event: UTSJSONObject)=>void
 // type EchartsTempResolve = (obj : UTSJSONObject) => void
 // type EchartsTempOptions = UTSJSONObject
@@ -14,18 +15,21 @@ export class Echarts {
 	init(){
 		this.context.evalJS(`init(null, null, ${JSON.stringify({})})`)
 		
-		this.context.addEventListener('message', (e : WebViewMessageEvent) => {
+		this.context.addEventListener('message', (e : UniWebViewMessageEvent) => {
 			// event.stopPropagation()
 			// event.preventDefault()
-			const log = e.detail.data!.get('log')
-			const event = e.detail.data!.get('event')
-			const options = e.detail.data!.get('options')
-			const file = e.detail.data!.get('file')
-			if (log != null) {
-				console.log(log)
+			
+			const detail = e.detail.data[0]
+			const file = detail.getString('file')
+			const data = detail.get('data')
+			const key = detail.getString('event')
+			const options = typeof data == 'object' ? (data as UTSJSONObject).getJSON('options'): null
+			const event = typeof data == 'object' ? (data as UTSJSONObject).getString('event'): null
+			if (key == 'log' && data != null) {
+				console.log(data)
 			}
 			if (event != null && options != null) {
-				this.dispatchAction(event as string, options as UTSJSONObject)
+				this.dispatchAction(event.replace(/"/g,''), options)
 			}
 			if(file != null){
 				while (this.temp.length > 0) {
@@ -71,10 +75,15 @@ export class Echarts {
 		this.context.evalJS(`dispose()`);
 	}
 	resize(size:UTSJSONObject){
-		this.context.evalJS(`resize(${JSON.stringify(size)})`);
+		setTimeout(()=>{
+			this.context.evalJS(`resize(${JSON.stringify(size)})`);
+		},0)
 	}
 	resize(){
-		this.context.evalJS(`resize()`);
+		setTimeout(()=>{
+			this.context.evalJS(`resize()`);
+		},10)
+		
 	}
 	on(type:string, query: any, callback: EchartsEventHandler) {
 		const key = `${type}${JSON.stringify(query)}`
@@ -99,7 +108,29 @@ export class Echarts {
 		}
 	}
 	canvasToTempFilePath(opt: UTSJSONObject){
-		this.context.evalJS(`on(${JSON.stringify(opt)})`);
+		// this.context.evalJS(`on(${JSON.stringify(opt)})`);
+		this.context.evalJS(`canvasToTempFilePath(${JSON.stringify(opt)})`);
 		this.temp.push(opt)
 	}
-}
+	isDisposed():boolean {
+		return false
+	}
+}
+
+// #endif
+// #ifndef APP
+export class Echarts {
+	constructor() {}
+	setOption(option: UTSJSONObject): void
+	isDisposed(): boolean;
+	clear(): void;
+	resize(size:UTSJSONObject): void;
+	resize(): void;
+	canvasToTempFilePath(opt : UTSJSONObject): void;
+	dispose(): void;
+	showLoading(cfg?: UTSJSONObject): void;
+	showLoading(name?: string, cfg?: UTSJSONObject): void;
+	hideLoading(): void;
+	getZr(): any
+}
+// #endif

+ 16 - 0
src/uni_modules/lime-echart/components/l-echart/vue.ts

@@ -0,0 +1,16 @@
+// @ts-nocheck
+
+// #ifdef VUE3
+export * from 'vue';
+// #endif
+
+// #ifndef VUE3
+export * from '@vue/composition-api';
+
+// #ifdef APP-NVUE
+import Vue from 'vue'
+import VueCompositionAPI from '@vue/composition-api'
+Vue.use(VueCompositionAPI)
+// #endif
+
+// #endif

+ 227 - 0
src/uni_modules/lime-echart/components/lime-echart/lime-echart-old.vue

@@ -0,0 +1,227 @@
+<template>
+  <view>
+    <view style="height: 750rpx; position: relative">
+      <l-echart ref="chart" @finished="init"></l-echart>
+      <view
+        class="customTooltips"
+        :style="{ left: position[0] + 'px', top: position[1] + 'px' }"
+        v-if="params.length && position.length && showTip"
+      >
+        <view>这是个自定的tooltips</view>
+        <view>{{ params[0]['axisValue'] }}</view>
+        <view v-for="item in params">
+          <view>
+            <text>{{ item.seriesName }}</text>
+            <text>{{ item.value }}</text>
+          </view>
+        </view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script>
+// nvue 不需要引入
+// #ifdef VUE2
+import * as echarts from '@/uni_modules/lime-echart/static/echarts.min'
+// #endif
+// #ifdef VUE3
+// #ifdef MP
+// 由于vue3 使用vite 不支持umd格式的包,小程序依然可以使用,但需要使用require
+const echarts = require('../../static/echarts.min')
+// #endif
+// #ifndef MP
+// 由于 vue3 使用vite 不支持umd格式的包,故引入npm的包
+import * as echarts from 'echarts/dist/echarts.esm'
+// #endif
+// #endif
+export default {
+  data() {
+    return {
+      showTip: false,
+      position: [],
+      params: [],
+      option: {
+        tooltip: {
+          trigger: 'axis',
+          // shadowBlur: 0,
+          textStyle: {
+            textShadowBlur: 0,
+          },
+          renderMode: 'richText',
+          position: (point, params, dom, rect, size) => {
+            // 假设自定义的tooltips尺寸
+            const box = [170, 170]
+            // 偏移
+            const offsetX = point[0] < size.viewSize[0] / 2 ? 20 : -box[0] - 20
+            const offsetY = point[1] < size.viewSize[1] / 2 ? 20 : -box[1] - 20
+            const x = point[0] + offsetX
+            const y = point[1] + offsetY
+
+            this.position = [x, y]
+            this.params = params
+          },
+          formatter: (params, ticket, callback) => {},
+        },
+        legend: {
+          data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎'],
+        },
+        grid: {
+          left: '3%',
+          right: '4%',
+          bottom: '3%',
+          containLabel: true,
+        },
+        xAxis: {
+          type: 'category',
+          boundaryGap: false,
+          data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
+        },
+        yAxis: {
+          type: 'value',
+        },
+        series: [
+          {
+            name: '邮件营销',
+            type: 'line',
+            stack: '总量',
+            data: [120, 132, 101, 134, 90, 230, 210],
+          },
+          {
+            name: '联盟广告',
+            type: 'line',
+            stack: '总量',
+            data: [220, 182, 191, 234, 290, 330, 310],
+          },
+          {
+            name: '视频广告',
+            type: 'line',
+            stack: '总量',
+            data: [150, 232, 201, 154, 190, 330, 410],
+          },
+          {
+            name: '直接访问',
+            type: 'line',
+            stack: '总量',
+            data: [320, 332, 301, 334, 390, 330, 320],
+          },
+          {
+            name: '搜索引擎',
+            type: 'line',
+            stack: '总量',
+            data: [820, 932, 901, 934, 1290, 1330, 1320],
+          },
+        ],
+      },
+    }
+  },
+
+  methods: {
+    init() {
+      // init(echarts, theme?:string, opts?:{}, chart => {})
+      // echarts 必填, 非nvue必填,nvue不用填
+      // theme 可选,应用的主题,目前只支持名称,如:'dark'
+      // opts = { // 可选
+      //	locale?: string  // 从 `5.0.0` 开始支持
+      // }
+      // chart => {} , callback 返回图表实例
+      // setTimeout(()=>{
+      // 	this.$refs.chart.init(echarts, chart => {
+      // 		chart.setOption(this.option);
+      // 	});
+      // },300)
+      this.$refs.chart.init(echarts, (chart) => {
+        chart.setOption(this.option)
+
+        // 监听tooltip显示事件
+        chart.on('showTip', (params) => {
+          this.showTip = true
+          console.log('showTip::')
+        })
+        chart.on('hideTip', (params) => {
+          setTimeout(() => {
+            this.showTip = false
+          }, 300)
+        })
+
+        setTimeout(() => {
+          const option = {
+            tooltip: {
+              trigger: 'axis',
+              // shadowBlur: 0,
+              textStyle: {
+                textShadowBlur: 0,
+              },
+              renderMode: 'richText',
+            },
+            legend: {
+              data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎'],
+            },
+            grid: {
+              left: '3%',
+              right: '4%',
+              bottom: '3%',
+              containLabel: true,
+            },
+            xAxis: {
+              type: 'category',
+              boundaryGap: false,
+              data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
+            },
+            yAxis: {
+              type: 'value',
+            },
+            series: [
+              {
+                name: '邮件营销',
+                type: 'line',
+                stack: '总量',
+                data: [1120, 132, 101, 134, 90, 230, 210],
+              },
+              {
+                name: '联盟广告',
+                type: 'line',
+                stack: '总量',
+                data: [220, 182, 191, 234, 290, 330, 310],
+              },
+              {
+                name: '视频广告',
+                type: 'line',
+                stack: '总量',
+                data: [150, 632, 201, 154, 190, 330, 410],
+              },
+              {
+                name: '直接访问',
+                type: 'line',
+                stack: '总量',
+                data: [820, 332, 301, 334, 390, 330, 320],
+              },
+              {
+                name: '搜索引擎',
+                type: 'line',
+                stack: '总量',
+                data: [820, 932, 901, 934, 1290, 1330, 1320],
+              },
+            ],
+          }
+          chart.setOption(option)
+        }, 1000)
+      })
+    },
+    save() {
+      this.$refs.chart.canvasToTempFilePath({
+        success(res) {
+          console.log('res::::', res)
+        },
+      })
+    },
+  },
+}
+</script>
+<style>
+.customTooltips {
+  position: absolute;
+  background-color: rgba(255, 255, 255, 0.8);
+  padding: 20rpx;
+}
+</style>

+ 64 - 0
src/uni_modules/lime-echart/components/lime-echart/lime-echart.nvue

@@ -78,6 +78,70 @@
 				const chartRef = this.$refs['chartRef']
 				chartRef.init(chart => {
 					chart.setOption(this.option);
+					
+					
+					setTimeout(()=>{
+						const option = {
+							tooltip: {
+								trigger: 'axis',
+								// shadowBlur: 0,
+								textStyle: {
+									textShadowBlur: 0
+								},
+								renderMode: 'richText',
+							},
+							legend: {
+								data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎']
+							},
+							grid: {
+								left: '3%',
+								right: '4%',
+								bottom: '3%',
+								containLabel: true
+							},
+							xAxis: {
+								type: 'category',
+								boundaryGap: false,
+								data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
+							},
+							yAxis: {
+								type: 'value'
+							},
+							series: [
+								{
+									name: '邮件营销',
+									type: 'line',
+									stack: '总量',
+									data: [120, 132, 101, 134, 90, 230, 210]
+								},
+								{
+									name: '联盟广告',
+									type: 'line',
+									stack: '总量',
+									data: [220, 182, 191, 234, 290, 330, 310]
+								},
+								{
+									name: '视频广告',
+									type: 'line',
+									stack: '总量',
+									data: [150, 232, 201, 154, 190, 330, 410]
+								},
+								{
+									name: '直接访问',
+									type: 'line',
+									stack: '总量',
+									data: [320, 332, 301, 334, 390, 330, 320]
+								},
+								{
+									name: '搜索引擎',
+									type: 'line',
+									stack: '总量',
+									data: [820, 932, 901, 934, 1290, 1330, 1320]
+								}
+							]
+						}
+						chart.setOption(option);
+					},1000)
 				})
 			},
 			save() {

+ 143 - 81
src/uni_modules/lime-echart/components/lime-echart/lime-echart.uvue

@@ -4,92 +4,154 @@
 	</view>
 </template>
 
-<script lang="uts">
-	export default {
-		data() {
-			return {
-				showTip: false,
-				option: {
-					tooltip: {
-						trigger: 'axis',
-						// shadowBlur: 0,
-						textStyle: {
-							textShadowBlur: 0
-						},
-						renderMode: 'richText',
-					},
-					legend: {
-						data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎']
-					},
-					grid: {
-						left: '3%',
-						right: '4%',
-						bottom: '3%',
-						containLabel: true
-					},
-					xAxis: {
-						type: 'category',
-						boundaryGap: false,
-						data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
-					},
-					yAxis: {
-						type: 'value'
-					},
-					series: [
-						{
-							name: '邮件营销',
-							type: 'line',
-							stack: '总量',
-							data: [120, 132, 101, 134, 90, 230, 210]
-						},
-						{
-							name: '联盟广告',
-							type: 'line',
-							stack: '总量',
-							data: [220, 182, 191, 234, 290, 330, 310]
-						},
-						{
-							name: '视频广告',
-							type: 'line',
-							stack: '总量',
-							data: [150, 232, 201, 154, 190, 330, 410]
-						},
-						{
-							name: '直接访问',
-							type: 'line',
-							stack: '总量',
-							data: [320, 332, 301, 334, 390, 330, 320]
-						},
-						{
-							name: '搜索引擎',
-							type: 'line',
-							stack: '总量',
-							data: [820, 932, 901, 934, 1290, 1330, 1320]
-						}
-					]
-				}
-			}
+<script lang="uts" setup>
+	// #ifdef MP
+	// 引入小程序依赖包,require只能是当前文件的相对路径
+	const echarts = require('../../../../static/echarts.min.js')
+	// #endif
+	// #ifndef MP
+	// 非小程序不需要引入
+	const echarts = null
+	// #endif
+	const chartRef = ref<LEchartComponentPublicInstance|null>(null)
+	const option = {
+		tooltip: {
+			trigger: 'axis',
+			// shadowBlur: 0,
+			textStyle: {
+				textShadowBlur: 0
+			},
+			renderMode: 'richText',
+		},
+		// formatter: async (params: any) => {
+		// 	console.log('params', params)
+		// 	return 1
+		// },
+		legend: {
+			data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎']
 		},
-		mounted() {
-			console.log('lime echarts uvue')
+		// grid: {
+		// 	left: '3%',
+		// 	right: '4%',
+		// 	bottom: '3%',
+		// 	containLabel: true
+		// },
+		xAxis: {
+			type: 'category',
+			boundaryGap: false,
+			data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
 		},
-		methods: {
-			init() {
-				const chartRef = this.$refs['chartRef'] as LEchartComponentPublicInstance
-				chartRef.init(chart => {
-					chart.setOption(this.option);
-					
-				})
+		yAxis: {
+			type: 'value'
+		},
+		series: [
+			{
+				name: '邮件营销',
+				type: 'line',
+				stack: '总量',
+				data: [120, 132, 101, 134, 90, 230, 210]
+			},
+			{
+				name: '联盟广告',
+				type: 'line',
+				stack: '总量',
+				data: [220, 182, 191, 234, 290, 330, 310]
 			},
-			save() {
-				// this.$refs.chart.canvasToTempFilePath({
-				// 	success(res) {
-				// 		console.log('res::::', res)
-				// 	}
-				// })
+			{
+				name: '视频广告',
+				type: 'line',
+				stack: '总量',
+				data: [150, 232, 201, 154, 190, 330, 410]
+			},
+			{
+				name: '直接访问',
+				type: 'line',
+				stack: '总量',
+				data: [320, 332, 301, 334, 390, 330, 320]
+			},
+			{
+				name: '搜索引擎',
+				type: 'line',
+				stack: '总量',
+				data: [820, 932, 901, 934, 1290, 1330, 1320]
 			}
-		}
+		]
 	}
+
+	const init = async () =>{
+		if(chartRef.value== null) return
+		const chart = await chartRef.value!.init(echarts)
+		chart.setOption(option)
+		// chart.on('mouseover', function (params) {
+		//     console.log('params', params);
+		// });
+		
+		
+		// setTimeout(()=> {
+		// 	const option1 = {
+		// 		tooltip: {
+		// 			trigger: 'axis',
+		// 			// shadowBlur: 0,
+		// 			textStyle: {
+		// 				textShadowBlur: 0
+		// 			},
+		// 			renderMode: 'richText',
+		// 		},
+		// 		legend: {
+		// 			data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎']
+		// 		},
+		// 		grid: {
+		// 			left: '3%',
+		// 			right: '4%',
+		// 			bottom: '3%',
+		// 			containLabel: true
+		// 		},
+		// 		xAxis: {
+		// 			type: 'category',
+		// 			boundaryGap: false,
+		// 			data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
+		// 		},
+		// 		yAxis: {
+		// 			type: 'value'
+		// 		},
+		// 		series: [
+		// 			{
+		// 				name: '邮件营销',
+		// 				type: 'line',
+		// 				stack: '总量',
+		// 				data: [820, 132, 101, 134, 90, 230, 210]
+		// 			},
+		// 			{
+		// 				name: '联盟广告',
+		// 				type: 'line',
+		// 				stack: '总量',
+		// 				data: [220, 182, 191, 234, 290, 330, 310]
+		// 			},
+		// 			{
+		// 				name: '视频广告',
+		// 				type: 'line',
+		// 				stack: '总量',
+		// 				data: [950, 232, 201, 154, 190, 330, 410]
+		// 			},
+		// 			{
+		// 				name: '直接访问',
+		// 				type: 'line',
+		// 				stack: '总量',
+		// 				data: [320, 332, 301, 334, 390, 330, 320]
+		// 			},
+		// 			{
+		// 				name: '搜索引擎',
+		// 				type: 'line',
+		// 				stack: '总量',
+		// 				data: [820, 932, 901, 934, 1290, 1330, 1320]
+		// 			}
+		// 		]
+		// 	}
+		// 	chart.setOption(option1)
+		// },1000)
+	}
+	
+
 </script>
 <style>
 

+ 54 - 65
src/uni_modules/lime-echart/components/lime-echart/lime-echart.vue

@@ -1,35 +1,30 @@
 <template>
-	<view >
+	<view>
 		<view style="height: 750rpx; position: relative">
 			<l-echart ref="chart" @finished="init"></l-echart>
-			<view class="customTooltips" :style="{left: position[0] + 'px',top: position[1] + 'px'}" v-if="params.length && position.length && showTip">
+			<view class="customTooltips" :style="{ left: position[0] + 'px', top: position[1] + 'px' }"
+				v-if="params.length && position.length && showTip">
 				<view>这是个自定的tooltips</view>
-				<view>{{params[0]['axisValue']}}</view>
+				<view>{{ params[0]['axisValue'] }}</view>
 				<view v-for="item in params">
 					<view>
-						<text>{{item.seriesName}}</text>
-						<text>{{item.value}}</text>
+						<text>{{ item.seriesName }}</text>
+						<text>{{ item.value }}</text>
 					</view>
 				</view>
 			</view>
 		</view>
-	</view>		
+	</view>
 </template>
 
 <script>
-	// nvue 不需要引入
-	// #ifdef VUE2
-	import * as echarts from '@/uni_modules/lime-echart/static/echarts.min';
-	// #endif
-	// #ifdef VUE3
 	// #ifdef MP
-	// 由于vue3 使用vite 不支持umd格式的包,小程序依然可以使用,但需要使用require
-	const echarts = require('../../static/echarts.min');
+	// 引入小程序依赖包,require只能是当前文件的相对路径
+	const echarts = require('../../../../static/echarts.min.js');
 	// #endif
 	// #ifndef MP
-	// 由于 vue3 使用vite 不支持umd格式的包,故引入npm的包
-	import * as echarts from 'echarts/dist/echarts.esm';
-	// #endif
+	// 非小程序不需要引入
+	const echarts = null
 	// #endif
 	export default {
 		data() {
@@ -37,85 +32,82 @@
 				showTip: false,
 				position: [],
 				params: [],
-				option:  {
+				option: {
 					tooltip: {
 						trigger: 'axis',
 						// shadowBlur: 0,
 						textStyle: {
-							textShadowBlur : 0
+							textShadowBlur: 0,
 						},
 						renderMode: 'richText',
 						position: (point, params, dom, rect, size) => {
 							// 假设自定义的tooltips尺寸
 							const box = [170, 170]
 							// 偏移
-							const offsetX = point[0] < size.viewSize[0] / 2 ? 20 : -box[0] - 20;
-							const offsetY = point[1] < size.viewSize[1] / 2 ? 20 : -box[1] - 20;
-							const x = point[0] + offsetX;
-							const y = point[1] + offsetY;
-							
+							const offsetX = point[0] < size.viewSize[0] / 2 ? 20 : -box[0] - 20
+							const offsetY = point[1] < size.viewSize[1] / 2 ? 20 : -box[1] - 20
+							const x = point[0] + offsetX
+							const y = point[1] + offsetY
+
 							this.position = [x, y]
 							this.params = params
 						},
-						formatter: (params, ticket, callback) => {
-							
-						}
+						formatter: (params, ticket, callback) => {},
 					},
 					legend: {
-						data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎']
-					},
-					grid: {
-						left: '3%',
-						right: '4%',
-						bottom: '3%',
-						containLabel: true
+						data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎'],
 					},
+					// grid: {
+					// 	left: '3%',
+					// 	right: '4%',
+					// 	bottom: '3%',
+					// 	containLabel: true,
+					// },
 					xAxis: {
 						type: 'category',
 						boundaryGap: false,
-						data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
+						data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
 					},
 					yAxis: {
-						type: 'value'
+						type: 'value',
 					},
-					series: [
-						{
+					series: [{
 							name: '邮件营销',
 							type: 'line',
 							stack: '总量',
-							data: [120, 132, 101, 134, 90, 230, 210]
+							data: [120, 132, 101, 134, 90, 230, 210],
 						},
 						{
 							name: '联盟广告',
 							type: 'line',
 							stack: '总量',
-							data: [220, 182, 191, 234, 290, 330, 310]
+							data: [220, 182, 191, 234, 290, 330, 310],
 						},
 						{
 							name: '视频广告',
 							type: 'line',
 							stack: '总量',
-							data: [150, 232, 201, 154, 190, 330, 410]
+							data: [150, 232, 201, 154, 190, 330, 410],
 						},
 						{
 							name: '直接访问',
 							type: 'line',
 							stack: '总量',
-							data: [320, 332, 301, 334, 390, 330, 320]
+							data: [320, 332, 301, 334, 390, 330, 320],
 						},
 						{
 							name: '搜索引擎',
 							type: 'line',
 							stack: '总量',
-							data: [820, 932, 901, 934, 1290, 1330, 1320]
-						}
-					]
-				}
+							data: [820, 932, 901, 934, 1290, 1330, 1320],
+						},
+					],
+				},
 			}
 		},
-		
+
 		methods: {
-			init() {
+			async init() {
 				// init(echarts, theme?:string, opts?:{}, chart => {})
 				// echarts 必填, 非nvue必填,nvue不用填
 				// theme 可选,应用的主题,目前只支持名称,如:'dark'
@@ -128,30 +120,27 @@
 				// 		chart.setOption(this.option);
 				// 	});
 				// },300)
-				this.$refs.chart.init(echarts, chart => {
-					chart.setOption(this.option);
-					
-					// 监听tooltip显示事件
-					chart.on('showTip', (params) => {
-					  this.showTip = true
-					  console.log('showTip::')
-					});
-					chart.on('hideTip', (params) => {
-						setTimeout(() => {
-							 this.showTip = false
-						},300)
-					});
-					
-				});
+				const chart = await this.$refs.chart.init(echarts)
+				chart.setOption(this.option)
+				// 监听tooltip显示事件
+				chart.on('showTip', (params) => {
+					this.showTip = true
+					console.log('showTip::')
+				})
+				chart.on('hideTip', (params) => {
+					setTimeout(() => {
+						this.showTip = false
+					}, 300)
+				})
 			},
 			save() {
 				this.$refs.chart.canvasToTempFilePath({
 					success(res) {
 						console.log('res::::', res)
-					}
+					},
 				})
-			}
-		}
+			},
+		},
 	}
 </script>
 <style>

+ 63 - 42
src/uni_modules/lime-echart/package.json

@@ -1,8 +1,8 @@
 {
   "id": "lime-echart",
-  "displayName": "echarts",
-  "version": "0.8.4",
-  "description": "echarts 全端兼容,一款使echarts图表能跑在uniapp各端中的插件",
+  "displayName": "lime-echart echarts图表",
+  "version": "2.0.3",
+  "description": "lime-echart 为 UniApp 和 UniAppX 提供 ECharts 图表兼容支持, 使 ECharts 图表能在H5、小程序、App中运行",
   "keywords": [
     "echarts",
     "canvas",
@@ -11,7 +11,9 @@
 ],
   "repository": "https://gitee.com/liangei/lime-echart",
   "engines": {
-    "HBuilderX": "^3.6.4"
+    "HBuilderX": "^3.6.4",
+    "uni-app": "^4.65",
+    "uni-app-x": "^4.71"
   },
   "dcloudext": {
     "sale": {
@@ -31,53 +33,72 @@
       "permissions": "无"
     },
     "npmurl": "",
-    "type": "component-vue"
+    "type": "component-vue",
+    "darkmode": "x",
+    "i18n": "x",
+    "widescreen": "x"
   },
   "uni_modules": {
     "dependencies": [],
     "encrypt": [],
     "platforms": {
       "cloud": {
-        "tcb": "y",
-        "aliyun": "y"
+        "tcb": "√",
+        "aliyun": "√",
+        "alipay": "x"
       },
       "client": {
-        "App": {
-          "app-vue": "y",
-          "app-nvue": "y",
-          "app-uvue": "y"
+        "uni-app": {
+          "vue": {
+            "vue2": "√",
+            "vue3": "√"
+          },
+          "web": {
+            "safari": "√",
+            "chrome": "√"
+          },
+          "app": {
+            "vue": "√",
+            "nvue": "√",
+            "android": {
+                "extVersion": "",
+                "minVersion": "21"
+            },
+            "ios": "√",
+            "harmony": "√"
+          },
+          "mp": {
+            "weixin": "√",
+            "alipay": "√",
+            "toutiao": "√",
+            "baidu": "√",
+            "kuaishou": "√",
+            "jd": "√",
+            "harmony": "-",
+            "qq": "√",
+            "lark": "√"
+          },
+          "quickapp": {
+            "huawei": "-",
+            "union": "-"
+          }
         },
-        "H5-mobile": {
-          "Safari": "y",
-          "Android Browser": "y",
-          "微信浏览器(Android)": "y",
-          "QQ浏览器(Android)": "y"
-        },
-        "H5-pc": {
-          "Chrome": "u",
-          "IE": "u",
-          "Edge": "u",
-          "Firefox": "u",
-          "Safari": "u"
-        },
-        "小程序": {
-          "微信": "y",
-          "阿里": "y",
-          "百度": "y",
-          "字节跳动": "y",
-          "QQ": "y",
-          "钉钉": "u",
-          "快手": "u",
-          "飞书": "u",
-          "京东": "u"
-        },
-        "快应用": {
-          "华为": "u",
-          "联盟": "u"
-        },
-        "Vue": {
-          "vue2": "y",
-          "vue3": "y"
+        "uni-app-x": {
+          "web": {
+            "safari": "√",
+            "chrome": "√"
+          },
+          "app": {
+            "android": {
+                "extVersion": "",
+                "minVersion": "21"
+            },
+            "ios": "√",
+            "harmony": "√"
+          },
+          "mp": {
+            "weixin": "√"
+          }
         }
       }
     }

+ 427 - 341
src/uni_modules/lime-echart/readme.md

@@ -1,413 +1,499 @@
-# echarts 图表 <span style="font-size:16px;">👑👑👑👑👑 <span style="background:#ff9d00;padding:2px 4px;color:#fff;font-size:10px;border-radius: 3px;">全端</span></span>
-> 一个基于 JavaScript 的开源可视化图表库   [查看更多 站点1](https://limeui.qcoon.cn/#/echart) |  [查看更多 站点2](http://liangei.gitee.io/limeui/#/echart)  <br>
-> 基于 echarts 做了兼容处理,更多示例请访问  [uni示例 站点1](https://limeui.qcoon.cn/#/echart-example) | [uni示例 站点2](http://liangei.gitee.io/limeui/#/echart-example) | [官方示例](https://echarts.apache.org/examples/zh/index.html)     <br>
-> Q群:1046793420 <br>
+# lime-echart 📊
 
-## 平台兼容
+为 UniApp 和 UniAppX 提供 ECharts 图表兼容支持,使 ECharts 图表能在 H5、小程序、App 等多端环境中正常运行。
 
-| H5  | 微信小程序 | 支付宝小程序 | 百度小程序 | 头条小程序 | QQ 小程序 | App  |
-| --- | ---------- | ------------ | ---------- | ---------- | --------- | ---- |
-| √   | √          | √         | √      | √       | √      | √ |
+## 特性 ✨
 
+- 📱 **跨平台兼容**:支持 H5、微信小程序、支付宝小程序、App 等多端
+- 🎯 **简单易用**:统一 API,使用方式与原生 ECharts 基本一致
+- ⚡ **性能优化**:针对不同平台进行了渲染优化
+- 🔄 **双框架支持**:同时支持 uni-app 和 uni-app-x
 
-## 安装
-- 第一步:在市场导入 [百度图表](https://ext.dcloud.net.cn/plugin?id=4899) 
-- 第二步:选择插件依赖:
-  1、可以选插件内的`echarts`包或自定义包,自定义包[下载地址](https://echarts.apache.org/zh/builder.html)<br>
-  2、或者使用`npm`安装`echarts`	
+## 文档与示例 📚
 
-**注意** 
-* 🔔 echarts 5.3.0及以上
-* 🔔 如果是 `cli` 项目请下载插件到`src`目录下的`uni_modules`,没有这个目录就创建一个
+更多详细文档与示例:
+- [lime-echart 组件文档](https://limeui.qcoon.cn/#/echart)
+- [在线示例](https://limeui.qcoon.cn/#/echart-example)
+- [ECharts 官方示例](https://echarts.apache.org/examples/zh/index.html)
+- [lime-echart 组件文档2](https://limex.qcoon.cn/components/echart.html) (将来用到,目前未上线)
 
+## 安装方法 📦
 
-## 代码演示
+### 插件市场安装
 
-### Vue2
-```html
-<view style="width:750rpx; height:750rpx"><l-echart ref="chartRef" @finished="init"></l-echart></view>
+1. 在uni-app插件市场中搜索并导入`lime-echart`
+2. 导入后重新编译项目
+3. 在页面中直接使用 `l-echart` 组件
+
+### CLI 项目安装
+
+```bash
+# 下载插件到项目的 src/uni_modules 目录
+mkdir -p src/uni_modules
+# 将插件解压到上述目录
 ```
 
-####  插件依赖 方式一:引入插件内的或自定义包
-- 引入插件内提供或自己下载的[自定义包](https://echarts.apache.org/zh/builder.html)
+## 前置依赖 ⚙️
+
+### 小程序平台(重点说明)
+
+小程序平台必须下载并引入 ECharts 自定义构建包:
+
+1. 小程序中引入ECharts有两种方式:
+   - **本地构建文件**
+     - 访问 [ECharts 在线构建](https://echarts.apache.org/zh/builder.html) 下载所需图表类型的精简版
+     - 注意:在线构建工具**仅支持生成UMD格式**(默认,`echarts.min.js`),通过 `require` 引入
+   - 建议只勾选项目所需的图表类型和组件,以减小文件体积
+
+2. **文件放置位置**:
+   - 📁 **主包**:将文件放入项目根目录的 `static` 文件夹
+   - 📁 **分包**:将文件放入对应分包的 `static` 文件夹(如 `pagesB/static/`)
+
+3. **相对路径引用示例**:
+   ```js
+   // UMD格式 - 页面位于主包根目录 - 相对路径引用示例(仅在线构建或本地文件使用)
+   // ├─pages
+   // │  └─index
+   // │     └─index.vue
+   // └─static
+   const echarts = require('../../static/echarts.min.js')
+   
+   // UMD格式 - 页面位于主包三层目录 - 相对路径引用示例(仅在线构建或本地文件使用)
+   // ├─pages
+   // │  └─user
+   // │     └─settings
+   // │        └─profile.vue
+   // └─static
+   const echarts = require('../../../static/echarts.min.js')
+   
+   // UMD格式 - 页面位于分包中 - 相对路径引用示例(仅在线构建或本地文件使用)
+   // ├─pagesB (分包)
+   // │  ├─static
+   // │  └─detail
+   // │     └─detail.vue
+   const echarts = require('../static/echarts.min.js')
+   
+   // ES模块格式 
+   import * as echarts from 'echarts'
+   ```
+
+   > 注意:
+   > - `require` 是小程序平台特有的API,仅在小程序环境下使用
+   > - 路径是相对于当前页面文件的路径,请根据实际项目结构调整路径
+
+
+## 使用示例 🎯
+
+### 图表配置项示例
+
+以下是一个柱状图的配置项示例,在后续使用示例中将引用此配置:
+
 ```js
-// 插件内的 二选一
-import * as echarts from '@/uni_modules/lime-echart/static/echarts.min'
-// 自定义的 二选一 下载后放入项目的路径
-import * as echarts from 'xxx/echarts.min'
+// 图表配置项示例 - 柱状图
+const chartOption = {
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: {
+      type: 'shadow'
+    },
+    confine: true
+  },
+  legend: {
+    data: ['热度', '正面', '负面']
+  },
+  xAxis: [
+    {
+      type: 'value',
+      axisLine: {
+        lineStyle: {
+          color: '#999999'
+        }
+      },
+      axisLabel: {
+        color: '#666666'
+      }
+    }
+  ],
+  yAxis: [
+    {
+      type: 'category',
+      axisTick: { show: false },
+      data: ['汽车之家', '今日头条', '百度贴吧', '一点资讯', '微信', '微博', '知乎'],
+      axisLine: {
+        lineStyle: {
+          color: '#999999'
+        }
+      },
+      axisLabel: {
+        color: '#666666'
+      }
+    }
+  ],
+  series: [
+    {
+      name: '热度',
+      type: 'bar',
+      label: {
+        show: true,
+        position: 'inside'
+      },
+      data: [300, 270, 340, 344, 300, 320, 310]
+    },
+    {
+      name: '正面',
+      type: 'bar',
+      stack: '总量',
+      label: {
+        show: true
+      },
+      data: [120, 102, 141, 174, 190, 250, 220]
+    },
+    {
+      name: '负面',
+      type: 'bar',
+      stack: '总量',
+      label: {
+        show: true,
+        position: 'left'
+      },
+      data: [-20, -32, -21, -34, -90, -130, -110]
+    }
+  ]
+}
 ```
 
-####  插件依赖 方式二:npm包
-- 自行安装 `echarts`
-- 可根据自己的需要全量引入或按需引入
+> **说明**:在实际项目中,可以根据需求修改上述配置项。
+> - 更多配置选项请参考 [ECharts 官方文档](https://echarts.apache.org/zh/option.html)
+> - 查看更多图表样式请访问 [ECharts 官方示例](https://echarts.apache.org/examples/zh/index.html)
 
-```cmd
-pnpm add echarts
- -or-
-npm install echarts
-```
+### uni-app 使用方式
 
-```js
-// 全量包  二选一
-import * as echarts from 'echarts'
-
-// 按需引入 二选一
-import * as echarts from 'echarts/core';
-import {LineChart, BarChart} from 'echarts/charts';
-import {TitleComponent,TooltipComponent,GridComponent, DatasetComponent, TransformComponent, LegendComponent } from 'echarts/components';
-// 标签自动布局,全局过渡动画等特性
-import {LabelLayout,UniversalTransition} from 'echarts/features';
-// 引入 Canvas 渲染器,注意引入 CanvasRenderer 是必须的一步
-import {CanvasRenderer} from 'echarts/renderers';
-
-// 按需引入 注册必须的组件
-echarts.use([
-	LegendComponent,
-	TitleComponent,
-	TooltipComponent,
-	GridComponent,
-	DatasetComponent,
-	TransformComponent,
-	LineChart,
-	BarChart,
-	LabelLayout,
-	UniversalTransition,
-	CanvasRenderer
-]);
+#### 组合式 API 方式
+
+```html
+<template>
+  <view style="width: 750rpx; height: 750rpx;">
+    <l-echart ref="chartRef" @finished="initChart"></l-echart>
+  </view>
+</template>
 ```
 
 ```js
-export default {
-	data() {
-		return {
-			option: {
-				tooltip: {
-					trigger: 'axis',
-					axisPointer: {
-						type: 'shadow' 
-					},
-					confine: true
-				},
-				legend: {
-					data: ['热度', '正面', '负面']
-				},
-				grid: {
-					left: 20,
-					right: 20,
-					bottom: 15,
-					top: 40,
-					containLabel: true
-				},
-				xAxis: [
-					{
-						type: 'value',
-						axisLine: {
-							lineStyle: {
-								color: '#999999'
-							}
-						},
-						axisLabel: {
-							color: '#666666'
-						}
-					}
-				],
-				yAxis: [
-					{
-						type: 'category',
-						axisTick: { show: false },
-						data: ['汽车之家', '今日头条', '百度贴吧', '一点资讯', '微信', '微博', '知乎'],
-						axisLine: {
-							lineStyle: {
-								color: '#999999'
-							}
-						},
-						axisLabel: {
-							color: '#666666'
-						}
-					}
-				],
-				series: [
-					{
-						name: '热度',
-						type: 'bar',
-						label: {
-							normal: {
-								show: true,
-								position: 'inside'
-							}
-						},
-						data: [300, 270, 340, 344, 300, 320, 310],
-					},
-					{
-						name: '正面',
-						type: 'bar',
-						stack: '总量',
-						label: {
-							normal: {
-								show: true
-							}
-						},
-						data: [120, 102, 141, 174, 190, 250, 220]
-					},
-					{
-						name: '负面',
-						type: 'bar',
-						stack: '总量',
-						label: {
-							normal: {
-								show: true,
-								position: 'left'
-							}
-						},
-						data: [-20, -32, -21, -34, -90, -130, -110]
-					}
-				]
-			},
-		};
-	},
-	// 组件能被调用必须是组件的节点已经被渲染到页面上
-	methods: {
-		async init() {
-			// chart 图表实例不能存在data里
-			const chart = await this.$refs.chartRef.init(echarts);
-			chart.setOption(this.option)
-		}
-	}
+import { ref } from 'vue';
+
+const chartRef = ref(null)
+
+// 仅在小程序环境下引入 ECharts
+// #ifdef MP
+const echarts = require('../../static/echarts.min.js') // 根据实际路径调整
+// #endif
+// #ifndef MP
+const echarts = null // H5 和 App 环境不需要手动引入
+// #endif
+
+// 使用上面定义的图表配置项
+const option = chartOption
+
+// 初始化图表
+const initChart = async () => {
+  if (!chartRef.value) return
+  
+  try {
+    const chart = await chartRef.value.init(echarts)
+    chart.setOption(option)
+  } catch (error) {
+    console.error('图表初始化失败:', error)
+  }
 }
 ```
 
-### Vue3
+#### 选项式 API 方式
 
 ```html
-<view style="width:750rpx; height:750rpx"><l-echart ref="chart" @finished="init"></l-echart></view>
+<template>
+  <view style="width: 750rpx; height: 750rpx;">
+    <l-echart ref="chartRef" @finished="initChart"></l-echart>
+  </view>
+</template>
 ```
 
-####  插件依赖 小程序引入插件内的包或自定义包
-- 引入插件内提供或自己下载的[自定义包](https://echarts.apache.org/zh/builder.html)
-- `require`仅支持相对路径,不支持路径别名
-
 ```js
-// 插件内的 二选一 
-const echarts = require('../../uni_modules/lime-echart/static/echarts.min');
-// 自定义的 二选一 下载后放入项目的路径
-const echarts = require('xxx/xxx/echarts');
-```
+// 仅在小程序环境下引入 ECharts
+// #ifdef MP
+const echarts = require('../../static/echarts.min.js') // 根据实际路径调整
+// #endif
+// #ifndef MP
+const echarts = null // H5 和 App 环境不需要手动引入
+// #endif
 
-#### 非小程序端不支持引入插件内的包
-- 由于vue3使用的是vite 不支持非`esm`格式,故不支持引入插件内的包
-- 可使用`npm`包
+export default {
+  data() {
+    return {
+      // 使用上面定义的图表配置项
+      option: chartOption,
+      // 图表实例,用于后续操作
+      chartInstance: null,
+    }
+  },
+  methods: {
+    // 初始化图表
+    async initChart() {
+      if (!this.$refs.chartRef) return
+      
+      try {
+        this.chartInstance = await this.$refs.chartRef.init(echarts)
+        this.chartInstance.setOption(this.option)
+      } catch (error) {
+        console.error('图表初始化失败:', error)
+      }
+    },
+    // 更新图表数据
+    updateChart(newOption) {
+      if (this.chartInstance) {
+        this.chartInstance.setOption(newOption)
+      } else if (this.$refs.chartRef) {
+        this.$refs.chartRef.setOption(newOption)
+      }
+    },
+    // 调整图表大小
+    resizeChart() {
+      if (this.$refs.chartRef) {
+        this.$refs.chartRef.resize()
+      }
+    }
+  },
+  // 页面卸载时销毁图表实例
+  beforeUnmount() {
+    if (this.$refs.chartRef) {
+      this.$refs.chartRef.dispose()
+    }
+  }
+}
+```
 
-#### 插件依赖 方式二:npm包
-- 可自行安装 `echarts`
-- 可根据自己的需要全量引入或按需引入
+### uni-app-x 使用方式
 
-```cmd
-pnpm add echarts
- -or-
-npm install echarts
+```html
+<template>
+  <view style="width: 100%; height: 408px;">
+    <l-echart ref="chartRef" @finished="initChart"></l-echart>
+  </view>
+</template>
 ```
 
-```js
-// 全量包  二选一
-import * as echarts from 'echarts'
-
-// 按需引入 二选一
-import * as echarts from 'echarts/core';
-import {LineChart, BarChart} from 'echarts/charts';
-import {TitleComponent,TooltipComponent,GridComponent, DatasetComponent, TransformComponent, LegendComponent } from 'echarts/components';
-// 标签自动布局,全局过渡动画等特性
-import {LabelLayout,UniversalTransition} from 'echarts/features';
-// 引入 Canvas 渲染器,注意引入 CanvasRenderer 是必须的一步
-import {CanvasRenderer} from 'echarts/renderers';
-
-// 按需引入 注册必须的组件
-echarts.use([
-	LegendComponent,
-	TitleComponent,
-	TooltipComponent,
-	GridComponent,
-	DatasetComponent,
-	TransformComponent,
-	LineChart,
-	BarChart,
-	LabelLayout,
-	UniversalTransition,
-	CanvasRenderer
-]);
+```ts
+const chartRef = ref<LEchartComponentPublicInstance | null>(null)
+
+// 仅在小程序环境下引入 ECharts
+// #ifdef MP
+const echarts = require('../../static/echarts.min.js') // 根据实际路径调整
+// #endif
+// #ifndef MP
+const echarts = null
+// #endif
+
+// 使用上面定义的图表配置项
+const option = chartOption
+
+// 初始化图表
+const initChart = async () => {
+  if (chartRef.value === null) return
+  
+  try {
+    const chart = await chartRef.value.init(echarts, null)
+    chart.setOption(option)
+  } catch (error) {
+    console.error('图表初始化失败:', error)
+  }
+}
 ```
 
-```js
 
-const chartRef = ref(null)
+## 高级功能 💪
 
-onMounted( ()=>{
-	// 组件能被调用必须是组件的节点已经被渲染到页面上
-	setTimeout(async()=>{
-		if(!chartRef.value) return
-		const myChart = await chartRef.value.init(echarts)
-		myChart.setOption(data)
-	},300)
-})
+### 数据更新 🔄
 
-```
+图表支持动态更新数据,有两种常用方式:
+
+#### 方式一:通过组件引用更新
 
+```js
+// Vue 3 Composition API
+chartRef.value?.setOption(newOption)
+
+// Vue 2 Options API
+this.$refs.chart.setOption(newOption)
+```
 
-### Uvue
-- Uvue和Nvue不需要引入`echarts`,因为它们的实现方式是`webview`
+#### 方式二:通过图表实例更新
 
 ```js
-methods: {
-	async init() {
-		const chartRef = this.$refs['chartRef'] as LEchartComponentPublicInstance
-		const myChart = await chartRef.init()
-		myChart.setOption(this.option)
-	}
+// 在初始化时保存图表实例
+let chartInstance = null
+
+const initChart = async () => {
+  if (!chartRef.value) return
+  chartInstance = await chartRef.value.init(echarts)
+  chartInstance.setOption(option)
+}
+
+// 后续更新数据
+const updateChart = () => {
+  if (chartInstance) {
+    chartInstance.setOption(newData)
+  }
 }
 ```
 
+### 图表大小调整 📏
 
-## 数据更新
-- 1、使用 `ref` 可获取`setOption`设置更新
-- 2、也可以拿到图表实例`chart`设置`myChart.setOption(data)`
+当容器大小改变时,可以调用 `resize` 方法重新调整图表尺寸:
 
 ```js
-// ref
-this.$refs.chart.setOption(data)
+// 自动适应容器大小
+chartRef.value?.resize()
 
-// 图表实例
-myChart.setOption(data)
+// 手动指定尺寸
+chartRef.value?.resize({
+  width: 375,  // 像素值
+  height: 375  // 像素值
+})
 ```
 
-## 图表大小
-- 在有些场景下,我们希望当容器大小改变时,图表的大小也相应地改变。
+**💡 提示**:在窗口大小变化或屏幕旋转时,可以监听相应事件并调用 `resize` 方法。
+
+### Vue 2 兼容配置 🔄
+
+如果您的项目使用 Vue 2,需要先安装并引入 Vue Composition API:
 
 ```js
-// 默认获取容器尺寸
-this.$refs.chart.resize()
-// 指定尺寸
-this.$refs.chart.resize({width: 375, height: 375})
+// main.js
+import Vue from 'vue'
+import VueCompositionAPI from '@vue/composition-api'
+Vue.use(VueCompositionAPI)
 ```
 
-## 自定义Tooltips
-- uvue\nvue 不支持
-由于除H5之外都不存在dom,但又有tooltips个性化的需求,代码就不贴了,看示例吧
-```
-代码位于/uni_modules/lime-echart/component/lime-echart
-```
+详细配置请参考:[Vue Composition API 官方文档](https://uniapp.dcloud.net.cn/tutorial/vue-composition-api.html)
+
+### 组件标签说明 🏷️
+
+| 标签名 | 说明 |
+|-------|------|
+| `l-echart` | 正式使用的组件标签 |
+| `lime-echart` | 演示用组件标签 |
+
+### 快速预览 🚀
 
+导入插件后,可以直接使用演示标签查看效果:
 
-## 插件标签
-- 默认 l-echart 为 component
-- 默认 lime-echart 为 demo
 ```html
- // 在任意地方使用可查看domo, 代码位于/uni_modules/lime-echart/component/lime-echart
-<lime-echart></lime-echart>
+<template>
+  <view style="width: 100%; height: 400px;">
+    <!-- 演示组件 -->
+    <lime-echart />
+  </view>
+</template>
 ```
 
+## 常见问题与解决方案 🐛
 
-## 常见问题
-- 钉钉小程序 由于没有`measureText`,模拟的`measureText`又无法得到当前字体的`fontWeight`,故可能存在估计不精细的问题
-- 微信小程序 `2d` 只支持 真机调试2.0
-- 微信开发工具会出现 `canvas` 不跟随页面的情况,真机不影响
-- 微信开发工具会出现 `canvas` 层级过高的问题,真机一般不受影响,可以先测只有两个元素的页面看是否会有层级问题。
-- toolbox 不支持 `saveImage`
-- echarts 5.3.0 的 lines 不支持 trailLength,故需设置为 `0`
-- dataZoom H5不要设置 `showDetail` 
-- 如果微信小程序的`tooltip`文字有阴影,可能是微信的锅,临时解决方法是`tooltip.shadowBlur = 0`
-- 如果钉钉小程序上传时报安全问题`Uint8Clamped`,可以向钉钉反馈是安全代码扫描把Uint8Clamped数组错误识别了,也可以在 echarts 文件修改`Uint8Clamped`
-```js
-// 找到这段代码把代码中`Uint8Clamped`改成`Uint8_Clamped`,再把下划线去掉,不过直接去掉`Uint8Clamped`也是可行的
-// ["Int8","Uint8","Uint8Clamped","Int16","Uint16","Int32","Uint32","Float32","Float64"],(function(t,e){return t["[object "+e+"Array]"]
-// 改成如下
-["Int8","Uint8","Uint8_Clamped","Int16","Uint16","Int32","Uint32","Float32","Float64"],(function(t,e){return t["[object "+e.replace('_','')+"Array]"]
-```
+### 平台特殊问题
 
-### vue3
-如果您是使用 **vite + vue3** 非微信小程序可能会遇到`echarts`文件缺少`wx`判断导致无法使用或缺少`tooltip`<br>
+#### 微信小程序
+- **画布层级问题**:微信开发工具中 canvas 可能出现层级过高或不跟随页面滚动的情况,真机环境下通常不受影响
+- **Tooltip 阴影**:如需去除文字阴影,可添加配置:`tooltip.shadowBlur = 0`
 
-方式一:可以在`echarts.min.js`文件开头增加以下内容,参考插件内的echart.min.js的做法
+#### 钉钉小程序
+- **文字测量精度**:由于钉钉小程序没有原生 `measureText`,字体粗细测量可能不够精确
+- **安全扫描警告**:如遇到 `Uint8Clamped` 安全问题,可按以下方式修改 ECharts 文件:
+  ```js
+  // 查找类似代码并修改
+  // 原代码
+  ["Int8","Uint8","Uint8Clamped","Int16","Uint16","Int32","Uint32","Float32","Float64"],(function(t,e){return t["[object "+e+"Array]"]
+  // 修改为
+  ["Int8","Uint8","Uint8_Clamped","Int16","Uint16","Int32","Uint32","Float32","Float64"],(function(t,e){return t["[object "+e.replace('_','')+"Array]"]
+  ```
 
-```js
-var prefix = () => {
-	var UNDEFINED = 'undefined'
-	if(typeof wx !== UNDEFINED) return wx // 微信
-	if(typeof tt !== UNDEFINED) return tt // 字节 飞书
-	if(typeof swan !== UNDEFINED) return swan // 百度
-	if(typeof my !== UNDEFINED) return my // 支付宝
-	if(typeof dd !== UNDEFINED) return dd // 钉钉
-	if(typeof ks !== UNDEFINED) return ks // 快手
-	if(typeof jd !== UNDEFINED) return jd // 京东
-	if(typeof qa !== UNDEFINED) return qa // 快应用
-	if(typeof qq !== UNDEFINED) return qq // qq
-	if(typeof qh !== UNDEFINED) return qh // 360
-	if(typeof uni !== UNDEFINED) return uni
-	return null
-}
-//在 !function(t,e){"object"==typeof 下面加入 可能是第36行
-var wx = prefix();
-/*! *****************************************************************************
-    Copyright (c) Microsoft Corporation.
-```
+### 功能限制 ⚠️
+- **Toolbox**:不支持 `saveImage` 功能
+- **Lines 图表**:不支持 `trailLength` 属性,请设置为 `0`
+- **DataZoom**:H5 平台不建议设置 `showDetail` 属性
+- **自定义 Tooltips**:uvue 和 vue 中不支持 DOM 操作相关的自定义 Tooltips
 
-方式二:在`vite.config.js`的`define`设置环境
+## API 参考 📝
 
-```js
-//  或者在`vite.config.js`的`define`设置环境
-import { defineConfig } from 'vite';
-import uni from '@dcloudio/vite-plugin-uni';
-
-const UNI_PLATFORM = {
-	"app": "uni",
-	"web": "uni",
-	"mp-weixin": "wx",
-	"mp-baidu": "swan",
-	"mp-alipay": "my",
-	"mp-toutiao": "tt",
-	"mp-lark": "tt",
-	"mp-qq": "qq",
-	"mp-kuaishou": "ks",
-	"mp-jd": "jd",
-	"mp-360": "qh",
-	"quickapp-webview-union": "qa",
-	"quickapp-webview-huawei": "qa",
-	"quickapp-webview": "qa",
-}
+### Props
 
-export default defineConfig({
-	plugins: [uni()],
-	define: { 
-		global: UNI_PLATFORM[process.env.UNI_PLATFORM],
-		wx: UNI_PLATFORM[process.env.UNI_PLATFORM]
-	}
-});
-```
+| 参数 | 说明 | 类型 | 默认值 | 版本 |
+|------|------|------|--------|------|
+| l-style | 自定义样式 | string | - | - |
+| type | 指定 canvas 类型(废除) | string | "2d" | - |
+| is-disable-scroll | 触摸图表时是否禁止页面滚动 | boolean | false | - |
+| beforeDelay | 延迟初始化时间(毫秒) | number | 30 | - |
+| enableHover | PC端是否启用鼠标悬浮效果(废除) | boolean | false | - |
+| landscape | 是否旋转90度,模拟横屏效果 | boolean | false | - |
+| autoHideTooltip | 是否自动隐藏Tooltip | boolean | false | - |
+
+### 组件方法
+
+| 方法名 | 参数 | 返回值 | 说明 |
+|--------|------|--------|------|
+| init | `echarts: Object, config?: Object` | `Promise<ChartInstance>` | 初始化图表实例 |
+| setOption | `option: Object` | `void` | 设置或更新图表配置项 |
+| resize | `size?: {width: number, height: number}` | `void` | 调整图表尺寸 |
+| clear | `-` | `void` | 清空图表内容 |
+| dispose | `-` | `void` | 销毁图表实例 |
+| showLoading | `-` | `void` | 显示加载动画 |
+| hideLoading | `-` | `void` | 隐藏加载动画 |
+| canvasToTempFilePath | `options: Object` | `Promise<Object>` | 生成图表图片,与 uni-app 官方 API 类似,但无需传入 canvasId |
+
+### 事件
+
+| 事件名 | 参数 | 说明 |
+|--------|------|------|
+| finished | 无 | 图表准备就绪时触发,此时可调用 init 方法 |
+
+## 其他平台依赖说明 🌐
+
+### uni-app 非 nvue 端
+
+- **推荐使用 `npm` 安装**
+- 通过 npm 安装可以获得完整的 ES 模块格式支持
+  ```bash
+  npm install echarts --save
+  ```
+- 安装后可直接在代码中通过 `import` 引入
+  ```js
+  import * as echarts from 'echarts'
+  ```
+
+### uni-app-x 非 App 端
+
+- **推荐使用 npm 安装**获取 ES 模块格式
+  ```bash
+  npm install echarts --save
+  ```
+- ES 模块格式具有更好的性能和构建优化支持
+- 通过 `import` 引入使用
+  ```js
+  import * as echarts from 'echarts'
+  ```
 
+> 💡 注意:H5 和 App 原生环境通常不需要手动引入 ECharts,组件会自动处理。只有在需要自定义 ECharts 版本或配置时才需要手动引入。
 
-## Props
+## 技术支持 🆘
 
-| 参数             | 说明                                                            | 类型             | 默认值        | 版本 	|
-| ---------------  | --------                                                        | -------         | ------------ | ----- 	|
-| custom-style     | 自定义样式                                                      |   `string`       | -            | -     	|
-| type             | 指定 canvas 类型                                				 |    `string`      | `2d`         |   	    |
-| is-disable-scroll | 触摸图表时是否禁止页面滚动                                       |    `boolean`     | `false`     |   	    |
-| beforeDelay       |  延迟初始化 (毫秒)                       						|    `number`     | `30`     |   	    |
-| enableHover       |  PC端使用鼠标悬浮                       						|    `boolean`     | `false`     |   	    |
+如果您在使用过程中遇到问题,可以通过以下方式获取帮助:
 
-## 事件
+1. 查看 [在线文档](https://limeui.qcoon.cn/#/echart) 获取详细使用说明
+2. 检查 [常见问题](#常见问题与解决方案) 章节查找解决方案
 
-| 参数                    | 说明                                                                                                             |
-| ---------------        | ---------------                                                                                                  |
-| init(echarts, chart => {})  | 初始化调用函数,第一个参数是传入`echarts`,第二个参数是回调函数,回调函数的参数是 `chart` 实例                                           |  
-| setChart(chart => {})        | 已经初始化后,请使用这个方法,是个回调函数,参数是 `chart` 实例                  |  
-| setOption(data)        | [图表配置项](https://echarts.apache.org/zh/option.html#title),用于更新 ,传递是数据 `option`  |  
-| clear()                | 清空当前实例,会移除实例中所有的组件和图表。  |  
-| dispose()              | 销毁实例  |  
-| showLoading()          | 显示加载  |  
-| hideLoading()          | 隐藏加载  |  
-| [canvasToTempFilePath](https://uniapp.dcloud.io/api/canvas/canvasToTempFilePath.html#canvastotempfilepath)(opt)  | 用于生成图片,与官方使用方法一致,但不需要传`canvasId`  |  
+## 贡献与支持 💙
 
+如果您觉得本插件对您有帮助,欢迎给作者点个赞或提供支持:
 
-## 打赏
-如果你觉得本插件,解决了你的问题,赠人玫瑰,手留余香。  
-![](https://testingcf.jsdelivr.net/gh/liangei/image@1.9/alipay.png)
-![](https://testingcf.jsdelivr.net/gh/liangei/image@1.9/wpay.png)
+| 支付宝 | 微信 |
+|--------|------|
+| ![支付宝](https://testingcf.jsdelivr.net/gh/liangei/image@1.9/alipay.png) | ![微信](https://testingcf.jsdelivr.net/gh/liangei/image@1.9/wpay.png) |
+
+您的支持是作者持续开发和维护的动力! 🌟

+ 408 - 0
src/uni_modules/lime-echart/readme.old.md

@@ -0,0 +1,408 @@
+# lime-echart
+> 一个基于 JavaScript 的开源可视化图表库   [查看更多](https://limeui.qcoon.cn/#/echart) <br>
+> 基于 echarts 做了兼容处理,更多示例请访问  [uni示例](https://limeui.qcoon.cn/#/echart-example) | [官方示例](https://echarts.apache.org/examples/zh/index.html)  <br>
+
+
+## 文档链接
+📚 组件详细文档请访问以下站点:
+- [echart组件文档 - 站点1](https://limex.qcoon.cn/components/echart.html)
+- [echart组件文档 - 站点1](https://limeui.qcoon.cn/#/echart)
+- [echart组件文档 - uni示例](https://limeui.qcoon.cn/#/echart-example)
+- [echart组件文档 - 官方示例](https://echarts.apache.org/examples/zh/index.html)
+
+
+
+## 安装
+- 第一步:在市场导入 [百度图表](https://ext.dcloud.net.cn/plugin?id=4899) 
+- 第二步:选择插件依赖:<br>
+  1、可以选插件内的`echarts`包或自定义包,自定义包[下载地址](https://echarts.apache.org/zh/builder.html)<br>
+
+**注意** 
+* 🔔 如果是 `cli` 项目请下载插件到`src`目录下的`uni_modules`,没有这个目录就创建一个
+
+
+## 代码演示
+
+### Vue2
+- 引入依赖,可以是插件内提供或自己下载的[自定义包](https://echarts.apache.org/zh/builder.html),也可以是`npm`包
+
+```html
+<view style="width:750rpx; height:750rpx"><l-echart ref="chartRef" @finished="init"></l-echart></view>
+```
+
+```js
+// 插件内的 三选一
+import * as echarts from '@/uni_modules/lime-echart/static/echarts.min'
+// 自定义的 三选一 下载后放入项目的路径
+import * as echarts from 'xxx/echarts.min'
+// npm包 三选一 需要在控制台 输入命令:npm install echarts
+import * as echarts from 'echarts'
+```
+
+```js
+export default {
+	data() {
+		return {
+			option: {
+				tooltip: {
+					trigger: 'axis',
+					axisPointer: {
+						type: 'shadow' 
+					},
+					confine: true
+				},
+				legend: {
+					data: ['热度', '正面', '负面']
+				},
+				grid: {
+					left: 20,
+					right: 20,
+					bottom: 15,
+					top: 40,
+					containLabel: true
+				},
+				xAxis: [
+					{
+						type: 'value',
+						axisLine: {
+							lineStyle: {
+								color: '#999999'
+							}
+						},
+						axisLabel: {
+							color: '#666666'
+						}
+					}
+				],
+				yAxis: [
+					{
+						type: 'category',
+						axisTick: { show: false },
+						data: ['汽车之家', '今日头条', '百度贴吧', '一点资讯', '微信', '微博', '知乎'],
+						axisLine: {
+							lineStyle: {
+								color: '#999999'
+							}
+						},
+						axisLabel: {
+							color: '#666666'
+						}
+					}
+				],
+				series: [
+					{
+						name: '热度',
+						type: 'bar',
+						label: {
+							normal: {
+								show: true,
+								position: 'inside'
+							}
+						},
+						data: [300, 270, 340, 344, 300, 320, 310],
+					},
+					{
+						name: '正面',
+						type: 'bar',
+						stack: '总量',
+						label: {
+							normal: {
+								show: true
+							}
+						},
+						data: [120, 102, 141, 174, 190, 250, 220]
+					},
+					{
+						name: '负面',
+						type: 'bar',
+						stack: '总量',
+						label: {
+							normal: {
+								show: true,
+								position: 'left'
+							}
+						},
+						data: [-20, -32, -21, -34, -90, -130, -110]
+					}
+				]
+			},
+		};
+	},
+	// 组件能被调用必须是组件的节点已经被渲染到页面上
+	methods: {
+		async init() {
+			// chart 图表实例不能存在data里
+			const chart = await this.$refs.chartRef.init(echarts);
+			chart.setOption(this.option)
+		}
+	}
+}
+```
+
+### Vue3
+- 小程序可以使用`require`引入插件内提供或自己下载的[自定义包](https://echarts.apache.org/zh/builder.html)
+- `require`仅支持相对路径,不支持路径别名
+- 非小程序使用 `npm` 包
+
+
+```html
+<view style="width:750rpx; height:750rpx"><l-echart ref="chartRef"></l-echart></view>
+```
+
+```js
+// 小程序 二选一 
+// 插件内的 二选一 
+const echarts = require('../../uni_modules/lime-echart/static/echarts.min');
+// 自定义的 二选一 下载后放入项目的路径
+const echarts = require('xxx/xxx/echarts');
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 非小程序 
+// 需要在控制台 输入命令:npm install echarts
+import * as echarts from 'echarts'
+```
+
+```js
+
+const chartRef = ref(null)
+const option = {
+	tooltip: {
+		trigger: 'axis',
+		axisPointer: {
+			type: 'shadow' 
+		},
+		confine: true
+	},
+	legend: {
+		data: ['热度', '正面', '负面']
+	},
+	grid: {
+		left: 20,
+		right: 20,
+		bottom: 15,
+		top: 40,
+		containLabel: true
+	},
+	xAxis: [
+		{
+			type: 'value',
+			axisLine: {
+				lineStyle: {
+					color: '#999999'
+				}
+			},
+			axisLabel: {
+				color: '#666666'
+			}
+		}
+	],
+	yAxis: [
+		{
+			type: 'category',
+			axisTick: { show: false },
+			data: ['汽车之家', '今日头条', '百度贴吧', '一点资讯', '微信', '微博', '知乎'],
+			axisLine: {
+				lineStyle: {
+					color: '#999999'
+				}
+			},
+			axisLabel: {
+				color: '#666666'
+			}
+		}
+	],
+	series: [
+		{
+			name: '热度',
+			type: 'bar',
+			label: {
+				normal: {
+					show: true,
+					position: 'inside'
+				}
+			},
+			data: [300, 270, 340, 344, 300, 320, 310],
+		},
+		{
+			name: '正面',
+			type: 'bar',
+			stack: '总量',
+			label: {
+				normal: {
+					show: true
+				}
+			},
+			data: [120, 102, 141, 174, 190, 250, 220]
+		},
+		{
+			name: '负面',
+			type: 'bar',
+			stack: '总量',
+			label: {
+				normal: {
+					show: true,
+					position: 'left'
+				}
+			},
+			data: [-20, -32, -21, -34, -90, -130, -110]
+		}
+	]
+};
+
+
+onMounted( ()=>{
+	// 组件能被调用必须是组件的节点已经被渲染到页面上
+	setTimeout(async()=>{
+		if(!chartRef.value) return
+		const myChart = await chartRef.value.init(echarts)
+		myChart.setOption(option)
+	},300)
+})
+
+```
+
+
+### Uvue
+- Uvue和Nvue不需要引入`echarts`,因为它们的实现方式是`webview`
+- uniapp x需要HBX 4.13以上
+
+```html
+<view style="width: 100%; height: 408px;">
+	<l-echart ref="chartRef" @finished="init"></l-echart>
+</view>
+```
+
+```js
+// @ts-nocheck
+// #ifdef H5
+import * as echarts from 'echarts/dist/echarts.esm.js'
+// #endif
+const chartRef = ref<LEchartComponentPublicInstance|null>(null);
+const init = async () => {
+	if(chartRef.value== null) return
+	// #ifdef APP
+	const chart = await chartRef.value!.init(null)
+	// #endif
+	// #ifdef H5
+	const chart = await chartRef.value!.init(echarts, null)
+	// #endif
+	chart.setOption(option)
+}
+```
+
+
+## 数据更新
+- 1、使用 `ref` 可获取`setOption`设置更新
+- 2、也可以拿到图表实例`chart`设置`myChart.setOption(data)`
+
+```js
+// ref
+this.$refs.chart.setOption(data)
+
+// 图表实例
+myChart.setOption(data)
+```
+
+## 图表大小
+- 在有些场景下,我们希望当容器大小改变时,图表的大小也相应地改变。
+
+```js
+// 默认获取容器尺寸
+this.$refs.chart.resize()
+// 指定尺寸
+this.$refs.chart.resize({width: 375, height: 375})
+```
+
+## 自定义Tooltips
+- uvue\nvue 不支持
+由于除H5之外都不存在dom,但又有tooltips个性化的需求,代码就不贴了,看示例吧
+```
+代码位于/uni_modules/lime-echart/component/lime-echart
+```
+
+
+## 插件标签
+- 默认 l-echart 为 component
+- 默认 lime-echart 为 demo
+```html
+ // 在任意地方使用可查看domo, 代码位于/uni_modules/lime-echart/component/lime-echart
+<lime-echart></lime-echart>
+```
+
+
+## 常见问题
+- 钉钉小程序 由于没有`measureText`,模拟的`measureText`又无法得到当前字体的`fontWeight`,故可能存在估计不精细的问题
+- 微信小程序 `2d` 只支持 真机调试2.0
+- 微信开发工具会出现 `canvas` 不跟随页面的情况,真机不影响
+- 微信开发工具会出现 `canvas` 层级过高的问题,真机一般不受影响,可以先测只有两个元素的页面看是否会有层级问题。
+- toolbox 不支持 `saveImage`
+- echarts 5.3.0 的 lines 不支持 trailLength,故需设置为 `0`
+- dataZoom H5不要设置 `showDetail` 
+- 如果微信小程序的`tooltip`文字有阴影,可能是微信的锅,临时解决方法是`tooltip.shadowBlur = 0`
+- 如果钉钉小程序上传时报安全问题`Uint8Clamped`,可以向钉钉反馈是安全代码扫描把Uint8Clamped数组错误识别了,也可以在 echarts 文件修改`Uint8Clamped`
+```js
+// 找到这段代码把代码中`Uint8Clamped`改成`Uint8_Clamped`,再把下划线去掉,不过直接去掉`Uint8Clamped`也是可行的
+// ["Int8","Uint8","Uint8Clamped","Int16","Uint16","Int32","Uint32","Float32","Float64"],(function(t,e){return t["[object "+e+"Array]"]
+// 改成如下
+["Int8","Uint8","Uint8_Clamped","Int16","Uint16","Int32","Uint32","Float32","Float64"],(function(t,e){return t["[object "+e.replace('_','')+"Array]"]
+```
+
+### vue3
+如果您是使用 **vite + vue3** 非微信小程序可能会遇到`echarts`文件缺少`wx`判断导致无法使用或缺少`tooltip`<br>
+
+方式一:可以在`echarts.min.js`文件开头增加以下内容,参考插件内的echart.min.js的做法
+
+```js
+// 某些echarts版本下 uniapp app 需要global,不然会报__ECHARTS__DEFAULT__RENDERER__
+let global = null
+let wx = uni
+```
+
+方式二:在`vite.config.js`的`define`设置环境
+
+```js
+//  或者在`vite.config.js`的`define`设置环境
+import { defineConfig } from 'vite';
+import uni from '@dcloudio/vite-plugin-uni';
+
+const define = {}
+if(!["mp-weixin", "h5", "web"].includes(process.env.UNI_PLATFORM)) {
+	define['global'] =  null
+	define['wx'] =  'uni'
+}
+export default defineConfig({
+	plugins: [uni()],
+	define
+});
+```
+
+
+## Props
+
+| 参数             | 说明                                                            | 类型             | 默认值        | 版本 	|
+| ---------------  | --------                                                        | -------         | ------------ | ----- 	|
+| custom-style     | 自定义样式                                                      |   `string`       | -            | -     	|
+| type             | 指定 canvas 类型                                				 |    `string`      | `2d`         |   	    |
+| is-disable-scroll | 触摸图表时是否禁止页面滚动                                       |    `boolean`     | `false`     |   	    |
+| beforeDelay       |  延迟初始化 (毫秒)                       						|    `number`     | `30`     |   	    |
+| enableHover       |  PC端使用鼠标悬浮                       						|    `boolean`     | `false`     |   	    |
+| landscape       |  是否旋转90deg,模拟横屏效果                       						|    `boolean`     | `false`     |   	    |
+
+## 事件
+
+| 参数                    | 说明                                                                                                             |
+| ---------------        | ---------------                                                                                                  |
+| init(echarts, chart => {})  | 初始化调用函数,第一个参数是传入`echarts`,第二个参数是回调函数,回调函数的参数是 `chart` 实例                                           |  
+| setChart(chart => {})        | 已经初始化后,请使用这个方法,是个回调函数,参数是 `chart` 实例                  |  
+| setOption(data)        | [图表配置项](https://echarts.apache.org/zh/option.html#title),用于更新 ,传递是数据 `option`  |  
+| clear()                | 清空当前实例,会移除实例中所有的组件和图表。  |  
+| dispose()              | 销毁实例  |  
+| showLoading()          | 显示加载  |  
+| hideLoading()          | 隐藏加载  |  
+| [canvasToTempFilePath](https://uniapp.dcloud.io/api/canvas/canvasToTempFilePath.html#canvastotempfilepath)(opt)  | 用于生成图片,与官方使用方法一致,但不需要传`canvasId`  |  
+
+
+## 打赏
+如果你觉得本插件,解决了你的问题,赠人玫瑰,手留余香。  
+![](https://testingcf.jsdelivr.net/gh/liangei/image@1.9/alipay.png)
+![](https://testingcf.jsdelivr.net/gh/liangei/image@1.9/wpay.png)

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
src/uni_modules/lime-echart/static/app/ecStat.min.js


Разница между файлами не показана из-за своего большого размера
+ 34 - 0
src/uni_modules/lime-echart/static/app/echarts.min.js


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
src/uni_modules/lime-echart/static/app/uni.webview.1.5.5.js


+ 184 - 0
src/uni_modules/lime-echart/static/app/uvue.html

@@ -0,0 +1,184 @@
+<!DOCTYPE html>
+<html lang="zh">
+	<head>
+		<meta charset="UTF-8">
+		<meta name="viewport"
+			content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
+		<meta http-equiv="X-UA-Compatible" content="ie=edge">
+		<title></title>
+		<style type="text/css">
+			html,
+			body {
+				overflow: hidden;
+				/* 隐藏滚动条 */
+				overscroll-behavior: none;
+				/* 禁止橡皮筋效果 */
+			}
+			html,
+			body,
+			.canvas {
+				padding: 0;
+				margin: 0;
+				overflow-y: hidden;
+				background-color: transparent;
+				width: 100%;
+				height: 100%;
+			}
+		</style>
+	</head>
+	<body>
+		<div class="canvas" id="limeChart"></div>
+		<script type="text/javascript" src="./uni.webview.1.5.5.js"></script>
+		<script type="text/javascript" src="./echarts.min.js"></script>
+		<script type="text/javascript" src="./ecStat.min.js"></script>
+		<!-- <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts-liquidfill@latest/dist/echarts-liquidfill.min.js"></script> -->
+		<script>
+			let chart = null;
+			let cache = [];
+			console.log = function() {
+				emit('log', {
+					log: arguments,
+				})
+			}
+
+			function emit(event, data) {
+				postMessage({
+					event,
+					data
+				})
+				cache = []
+			}
+
+			function postMessage(data) {
+				uni.webView.postMessage({
+					data
+				})
+				// window.__uniapp_x_.postMessage(JSON.stringify(data))
+			};
+
+			function stringify(key, value) {
+				if (typeof value === 'object' && value !== null) {
+					if (cache.indexOf(value) !== -1) {
+						return;
+					}
+					cache.push(value);
+				}
+				return value;
+			}
+
+			function parse(name, callback, options) {
+				const optionNameReg = /[\w]+\.setOption\(([\w]+\.)?([\w]+)\)/
+				if (optionNameReg.test(callback)) {
+					const optionNames = callback.match(optionNameReg)
+					if (optionNames[1]) {
+						const _this = optionNames[1].split('.')[0]
+						window[_this] = {}
+						window[_this][optionNames[2]] = options
+						return optionNames[2]
+					} else {
+						return null
+					}
+				}
+				return null
+			}
+
+			function init(callback, options, opts, theme) {
+				if (!chart) {
+					chart = echarts.init(document.getElementById('limeChart'), theme, opts)
+
+					if (options) {
+						chart.setOption(options)
+					}
+				}
+			}
+
+			function on(data) {
+				if (chart && data.length > 0) {
+					const [type, query] = data
+					const key = `${type}${JSON.stringify(query||'')}`
+					if (query) {
+						chart.on(type, query, function(options) {
+							var obj = {};
+							Object.keys(options).forEach(function(key) {
+								if (key != 'event') {
+									obj[key] = options[key];
+								}
+							});
+							emit(key, {
+								event: key,
+								options: obj,
+							});
+						});
+					} else {
+						chart.on(type, function(options) {
+							var obj = {};
+							Object.keys(options).forEach(function(key) {
+								if (key != 'event') {
+									obj[key] = options[key];
+								}
+							});
+							emit(key, {
+								event: key,
+								options: obj,
+							});
+						});
+					}
+				}
+
+			}
+
+			function setChart(callback, options) {
+				if (!callback) return
+				if (chart && callback && options) {
+					var r = null
+					const name = parse('r', callback, options)
+					if (name) this[name] = options
+					eval(`r = ${callback};`)
+					if (r) {
+						r(chart)
+					}
+				}
+			}
+
+			function setOption(data) {
+				if (chart) chart.setOption(data[0], data[1])
+			}
+
+			function showLoading(data) {
+				if (chart) chart.showLoading(data[0], data[1])
+			}
+
+			function hideLoading() {
+				if (chart) chart.hideLoading()
+			}
+
+			function clear() {
+				if (chart) chart.clear()
+
+			}
+
+			function dispose() {
+				if (chart) chart.dispose()
+			}
+
+			function resize(size) {
+				if (chart) chart.resize(size)
+			}
+
+			function canvasToTempFilePath(opt) {
+				if (chart) {
+					delete opt.success
+					const src = chart.getDataURL(opt)
+					postMessage({
+						// event: 'file',
+						file: src
+					})
+				}
+			}
+
+			document.addEventListener('touchmove', () => {
+
+			})
+		</script>
+	</body>
+</html>

Разница между файлами не показана из-за своего большого размера
+ 34 - 0
src/uni_modules/lime-echart/static/web/echarts.esm.min.js


+ 2 - 0
src/uni_modules/uni-calendar/changelog.md

@@ -1,3 +1,5 @@
+## 1.4.12(2024-09-21)
+- 修复 calendar在选择日期范围后重新选择日期需要点两次的Bug
 ## 1.4.11(2024-01-10)
 - 修复 回到今天时,月份显示不一致问题
 ## 1.4.10(2023-04-10)

+ 0 - 2
src/uni_modules/uni-calendar/components/uni-calendar/calendar.js

@@ -351,10 +351,8 @@ var calendar = {
         s = '\u521d\u5341'; break
       case 20:
         s = '\u4e8c\u5341'; break
-        break
       case 30:
         s = '\u4e09\u5341'; break
-        break
       default :
         s = this.nStr2[Math.floor(d / 10)]
         s += this.nStr1[d % 10]

+ 1 - 1
src/uni_modules/uni-calendar/components/uni-calendar/util.js

@@ -296,7 +296,7 @@ class Calendar {
 
 		if (!this.range) return
 		if (before && after) {
-			this.multipleStatus.before = ''
+			this.multipleStatus.before = fullDate
 			this.multipleStatus.after = ''
 			this.multipleStatus.data = []
 		} else {

+ 4 - 3
src/uni_modules/uni-calendar/package.json

@@ -1,7 +1,7 @@
 {
   "id": "uni-calendar",
   "displayName": "uni-calendar 日历",
-  "version": "1.4.11",
+  "version": "1.4.12",
   "description": "日历组件",
   "keywords": [
     "uni-ui",
@@ -44,7 +44,8 @@
     "platforms": {
       "cloud": {
         "tcb": "y",
-        "aliyun": "y"
+        "aliyun": "y",
+        "alipay": "n"
       },
       "client": {
         "App": {
@@ -82,4 +83,4 @@
       }
     }
   }
-}
+}

+ 12 - 0
src/uni_modules/uni-collapse/changelog.md

@@ -1,3 +1,15 @@
+## 1.4.8(2025-09-16)
+- 修复 modelValue 修改会两次触发 change 事件的 Bug
+## 1.4.7(2025-09-11)
+- 修复 modelValue 修改不会触发更新的 Bug
+## 1.4.6(2025-09-02)
+- 修复 modelValue 修改不会触发 change 事件的 Bug
+
+## 1.4.5(2025-09-02)
+- 修复 非手风琴模式 不能设置 modeValue 为 [] 的 Bug (question/205130)
+
+## 1.4.4(2024-03-20)
+- 修复 titleBorder类型修正
 ## 1.4.3(2022-01-25)
 - 修复 初始化的时候 ,open 属性失效的bug
 ## 1.4.2(2022-01-21)

+ 1 - 1
src/uni_modules/uni-collapse/components/uni-collapse-item/uni-collapse-item.vue

@@ -40,7 +40,7 @@
 	 * @property {String} name 唯一标志符
 	 * @property {Boolean} open = [true|false] 是否展开组件
 	 * @property {Boolean} titleBorder = [true|false] 是否显示标题分隔线
-	 * @property {Boolean} border = [true|false] 是否显示分隔线
+	 * @property {String} border = ['auto'|'show'|'none'] 是否显示分隔线
 	 * @property {Boolean} disabled = [true|false] 是否展开面板
 	 * @property {Boolean} showAnimation = [true|false] 开启动画
 	 * @property {Boolean} showArrow = [true|false] 是否显示右侧箭头

+ 14 - 14
src/uni_modules/uni-collapse/components/uni-collapse/uni-collapse.vue

@@ -51,8 +51,11 @@
 			}
 		},
 		watch: {
-			dataValue(val) {
-				this.setOpen(val)
+			dataValue: {
+				handler(newVal) {
+					this.setOpen(newVal)
+				},
+				deep: true
 			}
 		},
 		created() {
@@ -66,9 +69,9 @@
 		},
 		methods: {
 			setOpen(val) {
-				let str = typeof val === 'string'
-				let arr = Array.isArray(val)
-				this.childrens.forEach((vm, index) => {
+				const str = typeof val === 'string'
+				const arr = Array.isArray(val)
+				this.childrens.forEach((vm) => {
 					if (str) {
 						if (val === vm.nameSync) {
 							if (!this.accordion) {
@@ -79,15 +82,12 @@
 						}
 					}
 					if (arr) {
-						val.forEach(v => {
-							if (v === vm.nameSync) {
-								if (this.accordion) {
-									console.warn('accordion 属性为 true ,v-model 类型应该为 string')
-									return
-								}
-								vm.isOpen = true
-							}
-						})
+						const isOpen = val.findIndex(v => v === vm.nameSync) !== -1
+						if (this.accordion && isOpen) {
+							console.warn('accordion 属性为 true ,v-model 类型应该为 string')
+							return
+						}
+						vm.isOpen = isOpen
 					}
 				})
 				this.emit(val)

+ 58 - 41
src/uni_modules/uni-collapse/package.json

@@ -1,7 +1,7 @@
 {
   "id": "uni-collapse",
   "displayName": "uni-collapse 折叠面板",
-  "version": "1.4.3",
+  "version": "1.4.8",
   "description": "Collapse 组件,可以折叠 / 展开的内容区域。",
   "keywords": [
     "uni-ui",
@@ -11,16 +11,14 @@
 ],
   "repository": "https://github.com/dcloudio/uni-ui",
   "engines": {
-    "HBuilderX": ""
+    "HBuilderX": "",
+    "uni-app": "^4.07",
+    "uni-app-x": ""
   },
   "directories": {
     "example": "../../temps/example_temps"
   },
   "dcloudext": {
-    "category": [
-      "前端组件",
-      "通用组件"
-    ],
     "sale": {
       "regular": {
         "price": "0.00"
@@ -37,53 +35,72 @@
       "data": "无",
       "permissions": "无"
     },
-    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
+    "type": "component-vue",
+    "darkmode": "x",
+    "i18n": "x",
+    "widescreen": "x"
   },
   "uni_modules": {
     "dependencies": [
-			"uni-scss",
+      "uni-scss",
       "uni-icons"
     ],
     "encrypt": [],
     "platforms": {
       "cloud": {
-        "tcb": "y",
-        "aliyun": "y"
+        "tcb": "x",
+        "aliyun": "x",
+        "alipay": "x"
       },
       "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": "y",
-          "Edge": "y",
-          "Firefox": "y",
-          "Safari": "y"
-        },
-        "小程序": {
-          "微信": "y",
-          "阿里": "y",
-          "百度": "y",
-          "字节跳动": "y",
-          "QQ": "y"
-        },
-        "快应用": {
-          "华为": "u",
-          "联盟": "u"
+        "uni-app": {
+          "vue": {
+            "vue2": "√",
+            "vue3": "√"
+          },
+          "web": {
+            "safari": "√",
+            "chrome": "√"
+          },
+          "app": {
+            "vue": "√",
+            "nvue": "√",
+            "android": "√",
+            "ios": "√",
+            "harmony": "√"
+          },
+          "mp": {
+            "weixin": "√",
+            "alipay": "√",
+            "toutiao": "√",
+            "baidu": "√",
+            "kuaishou": "-",
+            "jd": "-",
+            "harmony": "-",
+            "qq": "√",
+            "lark": "-"
+          },
+          "quickapp": {
+            "huawei": "√",
+            "union": "√"
+          }
         },
-        "Vue": {
-            "vue2": "y",
-            "vue3": "y"
+        "uni-app-x": {
+          "web": {
+            "safari": "-",
+            "chrome": "-"
+          },
+          "app": {
+            "android": "-",
+            "ios": "-",
+            "harmony": "-"
+          },
+          "mp": {
+            "weixin": "-"
+          }
         }
       }
     }
   }
-}
+}

+ 2 - 0
src/uni_modules/uni-combox/changelog.md

@@ -1,3 +1,5 @@
+## 1.0.2(2024-09-21)
+- 新增 clearAble属性
 ## 1.0.1(2021-11-23)
 - 优化 label、label-width 属性
 ## 1.0.0(2021-11-19)

+ 16 - 7
src/uni_modules/uni-combox/components/uni-combox/uni-combox.vue

@@ -4,10 +4,11 @@
 			<text>{{label}}</text>
 		</view>
 		<view class="uni-combox__input-box">
-			<input class="uni-combox__input" type="text" :placeholder="placeholder" 
-			placeholder-class="uni-combox__input-plac" v-model="inputVal" @input="onInput" @focus="onFocus" 
-@blur="onBlur" />
-			<uni-icons :type="showSelector? 'top' : 'bottom'" size="14" color="#999" @click="toggleSelector">
+			<input class="uni-combox__input" type="text" :placeholder="placeholder" placeholder-class="uni-combox__input-plac"
+				v-model="inputVal" @input="onInput" @focus="onFocus" @blur="onBlur" />
+			<uni-icons v-if="!inputVal || !clearAble" :type="showSelector? 'top' : 'bottom'" size="14" color="#999" @click="toggleSelector">
+			</uni-icons>
+			<uni-icons v-if="inputVal && clearAble" type="clear" size="24" color="#999" @click="clean">
 			</uni-icons>
 		</view>
 		<view class="uni-combox__selector" v-if="showSelector">
@@ -16,8 +17,8 @@
 				<view class="uni-combox__selector-empty" v-if="filterCandidatesLength === 0">
 					<text>{{emptyTips}}</text>
 				</view>
-				<view class="uni-combox__selector-item" v-for="(item,index) in filterCandidates" :key="index" 
-				@click="onSelectorClick(index)">
+				<view class="uni-combox__selector-item" v-for="(item,index) in filterCandidates" :key="index"
+					@click="onSelectorClick(index)">
 					<text>{{item}}</text>
 				</view>
 			</scroll-view>
@@ -41,6 +42,10 @@
 		name: 'uniCombox',
 		emits: ['input', 'update:modelValue'],
 		props: {
+			clearAble: {
+				type: Boolean,
+				default: false
+			},
 			border: {
 				type: Boolean,
 				default: true
@@ -143,12 +148,16 @@
 					this.$emit('input', this.inputVal)
 					this.$emit('update:modelValue', this.inputVal)
 				})
+			},
+			clean() {
+				this.inputVal = ''
+				this.onInput()
 			}
 		}
 	}
 </script>
 
-<style lang="scss" >
+<style lang="scss" scoped>
 	.uni-combox {
 		font-size: 14px;
 		border: 1px solid #DCDFE6;

+ 7 - 9
src/uni_modules/uni-combox/package.json

@@ -1,7 +1,7 @@
 {
   "id": "uni-combox",
   "displayName": "uni-combox 组合框",
-  "version": "1.0.1",
+  "version": "1.0.2",
   "description": "可以选择也可以输入的表单项 ",
   "keywords": [
     "uni-ui",
@@ -17,11 +17,7 @@
   "directories": {
     "example": "../../temps/example_temps"
   },
-  "dcloudext": {
-    "category": [
-      "前端组件",
-      "通用组件"
-    ],
+"dcloudext": {
     "sale": {
       "regular": {
         "price": "0.00"
@@ -38,7 +34,8 @@
       "data": "无",
       "permissions": "无"
     },
-    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
+    "type": "component-vue"
   },
   "uni_modules": {
     "dependencies": [
@@ -49,7 +46,8 @@
     "platforms": {
       "cloud": {
         "tcb": "y",
-        "aliyun": "y"
+        "aliyun": "y",
+        "alipay": "n"
       },
       "client": {
         "App": {
@@ -87,4 +85,4 @@
       }
     }
   }
-}
+}

+ 11 - 7
src/uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/package.json

@@ -1,9 +1,13 @@
 {
-  "name": "uni-config-center",
-  "version": "0.0.3",
-  "description": "配置中心",
-  "main": "index.js",
-  "keywords": [],
-  "author": "DCloud",
-  "license": "Apache-2.0"
+    "name": "uni-config-center",
+    "version": "0.0.3",
+    "description": "配置中心",
+    "main": "index.js",
+    "keywords": [],
+    "author": "DCloud",
+    "license": "Apache-2.0",
+    "origin-plugin-dev-name": "uni-config-center",
+    "origin-plugin-version": "0.0.3",
+    "plugin-dev-name": "uni-config-center",
+    "plugin-version": "0.0.3"
 }

+ 6 - 0
src/uni_modules/uni-countdown/changelog.md

@@ -1,3 +1,9 @@
+## 1.2.5(2025-04-14)
+- 修复 filterShow 导致的运行报错
+## 1.2.4(2024-09-21)
+- 新增 支持控制显示位数 默认显示2位
+## 1.2.3(2024-02-20)
+- 新增 支持控制小时,分钟的显隐:showHour showMinute
 ## 1.2.2(2022-01-19)
 - 修复 在微信小程序中样式不生效的bug
 ## 1.2.1(2022-01-18)

+ 27 - 20
src/uni_modules/uni-countdown/components/uni-countdown/uni-countdown.vue

@@ -2,10 +2,10 @@
 	<view class="uni-countdown">
 		<text v-if="showDay" :style="[timeStyle]" class="uni-countdown__number">{{ d }}</text>
 		<text v-if="showDay" :style="[splitorStyle]" class="uni-countdown__splitor">{{dayText}}</text>
-		<text :style="[timeStyle]" class="uni-countdown__number">{{ h }}</text>
-		<text :style="[splitorStyle]" class="uni-countdown__splitor">{{ showColon ? ':' : hourText }}</text>
-		<text :style="[timeStyle]" class="uni-countdown__number">{{ i }}</text>
-		<text :style="[splitorStyle]" class="uni-countdown__splitor">{{ showColon ? ':' : minuteText }}</text>
+		<text v-if="showHour" :style="[timeStyle]" class="uni-countdown__number">{{ h }}</text>
+		<text v-if="showHour" :style="[splitorStyle]" class="uni-countdown__splitor">{{ showColon ? ':' : hourText }}</text>
+		<text v-if="showMinute" :style="[timeStyle]" class="uni-countdown__number">{{ i }}</text>
+		<text v-if="showMinute" :style="[splitorStyle]" class="uni-countdown__splitor">{{ showColon ? ':' : minuteText }}</text>
 		<text :style="[timeStyle]" class="uni-countdown__number">{{ s }}</text>
 		<text v-if="!showColon" :style="[splitorStyle]" class="uni-countdown__splitor">{{secondText}}</text>
 	</view>
@@ -30,6 +30,8 @@
 	 * @property {Number} second 秒
 	 * @property {Number} timestamp 时间戳
 	 * @property {Boolean} showDay = [true|false] 是否显示天数
+	 * @property {Boolean} showHour = [true|false] 是否显示小时
+	 * @property {Boolean} showMinute = [true|false] 是否显示分钟
 	 * @property {Boolean} show-colon = [true|false] 是否以冒号为分隔符
 	 * @property {String} splitorColor 分割符号颜色
 	 * @event {Function} timeup 倒计时时间到触发事件
@@ -43,6 +45,14 @@
 				type: Boolean,
 				default: true
 			},
+			showHour: {
+				type: Boolean,
+				default: true
+			},
+			showMinute: {
+				type: Boolean,
+				default: true
+			},
 			showColon: {
 				type: Boolean,
 				default: true
@@ -86,6 +96,12 @@
 			timestamp: {
 				type: Number,
 				default: 0
+			},
+			filterShow : {
+				type:Object,
+				default () {
+					return {}
+				}
 			}
 		},
 		data() {
@@ -199,22 +215,13 @@
 				} else {
 					this.timeUp()
 				}
-				if (day < 10) {
-					day = '0' + day
-				}
-				if (hour < 10) {
-					hour = '0' + hour
-				}
-				if (minute < 10) {
-					minute = '0' + minute
-				}
-				if (second < 10) {
-					second = '0' + second
-				}
-				this.d = day
-				this.h = hour
-				this.i = minute
-				this.s = second
+				this.d  = String(day).padStart(this.validFilterShow(this.filterShow.d), '0')
+				this.h = String(hour).padStart(this.validFilterShow(this.filterShow.h), '0')
+				this.i = String(minute).padStart(this.validFilterShow(this.filterShow.m), '0')
+				this.s = String(second).padStart(this.validFilterShow(this.filterShow.s), '0')
+			},
+			validFilterShow(filter){
+				return (filter && filter > 0) ? filter : 2;
 			},
 			startData() {
 				this.seconds = this.toSeconds(this.timestamp, this.day, this.hour, this.minute, this.second)

+ 11 - 11
src/uni_modules/uni-countdown/package.json

@@ -1,7 +1,7 @@
 {
   "id": "uni-countdown",
   "displayName": "uni-countdown 倒计时",
-  "version": "1.2.2",
+  "version": "1.2.5",
   "description": "CountDown 倒计时组件",
   "keywords": [
     "uni-ui",
@@ -16,11 +16,7 @@
   "directories": {
     "example": "../../temps/example_temps"
   },
-  "dcloudext": {
-    "category": [
-      "前端组件",
-      "通用组件"
-    ],
+"dcloudext": {
     "sale": {
       "regular": {
         "price": "0.00"
@@ -37,7 +33,8 @@
       "data": "无",
       "permissions": "无"
     },
-    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
+    "type": "component-vue"
   },
   "uni_modules": {
     "dependencies": ["uni-scss"],
@@ -45,12 +42,15 @@
     "platforms": {
       "cloud": {
         "tcb": "y",
-        "aliyun": "y"
+        "aliyun": "y",
+        "alipay": "n"
       },
       "client": {
         "App": {
-          "app-vue": "y",
-          "app-nvue": "y"
+            "app-vue": "y",
+            "app-nvue": "y",
+            "app-harmony": "u",
+            "app-uvue": "u"
         },
         "H5-mobile": {
           "Safari": "y",
@@ -83,4 +83,4 @@
       }
     }
   }
-}
+}

+ 4 - 0
src/uni_modules/uni-data-checkbox/changelog.md

@@ -1,3 +1,7 @@
+## 1.0.6(2024-10-22)
+- 新增 当 multiple 为 false 且传递的 value 为 数组时,使用数组第一项用作反显
+## 1.0.5(2024-03-20)
+- 修复 单选模式下选中样式不生效的bug
 ## 1.0.4(2024-01-27)
 - 修复 修复错别字chagne为change
 ## 1.0.3(2022-09-16)

+ 316 - 0
src/uni_modules/uni-data-checkbox/components/uni-data-checkbox/clientdb.js

@@ -0,0 +1,316 @@
+
+const events = {
+	load: 'load',
+	error: 'error'
+}
+const pageMode = {
+	add: 'add',
+	replace: 'replace'
+}
+
+const attrs = [
+	'pageCurrent',
+	'pageSize',
+	'collection',
+	'action',
+	'field',
+	'getcount',
+	'orderby',
+	'where'
+]
+
+export default {
+	data() {
+		return {
+			loading: false,
+			listData: this.getone ? {} : [],
+			paginationInternal: {
+				current: this.pageCurrent,
+				size: this.pageSize,
+				count: 0
+			},
+			errorMessage: ''
+		}
+	},
+	created() {
+		let db = null;
+		let dbCmd = null;
+
+		if(this.collection){
+			this.db = uniCloud.database();
+			this.dbCmd = this.db.command;
+		}
+
+		this._isEnded = false
+
+		this.$watch(() => {
+			let al = []
+			attrs.forEach(key => {
+				al.push(this[key])
+			})
+			return al
+		}, (newValue, oldValue) => {
+			this.paginationInternal.pageSize = this.pageSize
+
+			let needReset = false
+			for (let i = 2; i < newValue.length; i++) {
+				if (newValue[i] != oldValue[i]) {
+					needReset = true
+					break
+				}
+			}
+			if (needReset) {
+				this.clear()
+				this.reset()
+			}
+			if (newValue[0] != oldValue[0]) {
+				this.paginationInternal.current = this.pageCurrent
+			}
+
+			this._execLoadData()
+		})
+
+		// #ifdef H5
+		if (process.env.NODE_ENV === 'development') {
+			this._debugDataList = []
+			if (!window.unidev) {
+				window.unidev = {
+					clientDB: {
+						data: []
+					}
+				}
+			}
+			unidev.clientDB.data.push(this._debugDataList)
+		}
+		// #endif
+
+		// #ifdef MP-TOUTIAO
+		let changeName
+		let events = this.$scope.dataset.eventOpts
+		for (let i = 0; i < events.length; i++) {
+			let event = events[i]
+			if (event[0].includes('^load')) {
+				changeName = event[1][0][0]
+			}
+		}
+		if (changeName) {
+			let parent = this.$parent
+			let maxDepth = 16
+			this._changeDataFunction = null
+			while (parent && maxDepth > 0) {
+				let fun = parent[changeName]
+				if (fun && typeof fun === 'function') {
+					this._changeDataFunction = fun
+					maxDepth = 0
+					break
+				}
+				parent = parent.$parent
+				maxDepth--;
+			}
+		}
+		// #endif
+
+		// if (!this.manual) {
+		// 	this.loadData()
+		// }
+	},
+	// #ifdef H5
+	beforeDestroy() {
+		if (process.env.NODE_ENV === 'development' && window.unidev) {
+			let cd = this._debugDataList
+			let dl = unidev.clientDB.data
+			for (let i = dl.length - 1; i >= 0; i--) {
+				if (dl[i] === cd) {
+					dl.splice(i, 1)
+					break
+				}
+			}
+		}
+	},
+	// #endif
+	methods: {
+		loadData(args1, args2) {
+			let callback = null
+			if (typeof args1 === 'object') {
+				if (args1.clear) {
+					this.clear()
+					this.reset()
+				}
+				if (args1.current !== undefined) {
+					this.paginationInternal.current = args1.current
+				}
+				if (typeof args2 === 'function') {
+					callback = args2
+				}
+			} else if (typeof args1 === 'function') {
+				callback = args1
+			}
+
+			this._execLoadData(callback)
+		},
+		loadMore() {
+			if (this._isEnded) {
+				return
+			}
+			this._execLoadData()
+		},
+		refresh() {
+			this.clear()
+			this._execLoadData()
+		},
+		clear() {
+			this._isEnded = false
+			this.listData = []
+		},
+		reset() {
+			this.paginationInternal.current = 1
+		},
+		remove(id, {
+			action,
+			callback,
+			confirmTitle,
+			confirmContent
+		} = {}) {
+			if (!id || !id.length) {
+				return
+			}
+			uni.showModal({
+				title: confirmTitle || '提示',
+				content: confirmContent || '是否删除该数据',
+				showCancel: true,
+				success: (res) => {
+					if (!res.confirm) {
+						return
+					}
+					this._execRemove(id, action, callback)
+				}
+			})
+		},
+		_execLoadData(callback) {
+			if (this.loading) {
+				return
+			}
+			this.loading = true
+			this.errorMessage = ''
+
+			this._getExec().then((res) => {
+				this.loading = false
+				const {
+					data,
+					count
+				} = res.result
+				this._isEnded = data.length < this.pageSize
+
+				callback && callback(data, this._isEnded)
+				this._dispatchEvent(events.load, data)
+
+				if (this.getone) {
+					this.listData = data.length ? data[0] : undefined
+				} else if (this.pageData === pageMode.add) {
+					this.listData.push(...data)
+					if (this.listData.length) {
+						this.paginationInternal.current++
+					}
+				} else if (this.pageData === pageMode.replace) {
+					this.listData = data
+					this.paginationInternal.count = count
+				}
+
+				// #ifdef H5
+				if (process.env.NODE_ENV === 'development') {
+					this._debugDataList.length = 0
+					this._debugDataList.push(...JSON.parse(JSON.stringify(this.listData)))
+				}
+				// #endif
+			}).catch((err) => {
+				this.loading = false
+				this.errorMessage = err
+				callback && callback()
+				this.$emit(events.error, err)
+			})
+		},
+		_getExec() {
+			let exec = this.db
+			if (this.action) {
+				exec = exec.action(this.action)
+			}
+
+			exec = exec.collection(this.collection)
+
+			if (!(!this.where || !Object.keys(this.where).length)) {
+				exec = exec.where(this.where)
+			}
+			if (this.field) {
+				exec = exec.field(this.field)
+			}
+			if (this.orderby) {
+				exec = exec.orderBy(this.orderby)
+			}
+
+			const {
+				current,
+				size
+			} = this.paginationInternal
+			exec = exec.skip(size * (current - 1)).limit(size).get({
+				getCount: this.getcount
+			})
+
+			return exec
+		},
+		_execRemove(id, action, callback) {
+			if (!this.collection || !id) {
+				return
+			}
+
+			const ids = Array.isArray(id) ? id : [id]
+			if (!ids.length) {
+				return
+			}
+
+			uni.showLoading({
+				mask: true
+			})
+
+			let exec = this.db
+			if (action) {
+				exec = exec.action(action)
+			}
+
+			exec.collection(this.collection).where({
+				_id: dbCmd.in(ids)
+			}).remove().then((res) => {
+				callback && callback(res.result)
+				if (this.pageData === pageMode.replace) {
+					this.refresh()
+				} else {
+					this.removeData(ids)
+				}
+			}).catch((err) => {
+				uni.showModal({
+					content: err.message,
+					showCancel: false
+				})
+			}).finally(() => {
+				uni.hideLoading()
+			})
+		},
+		removeData(ids) {
+			let il = ids.slice(0)
+			let dl = this.listData
+			for (let i = dl.length - 1; i >= 0; i--) {
+				let index = il.indexOf(dl[i]._id)
+				if (index >= 0) {
+					dl.splice(i, 1)
+					il.splice(index, 1)
+				}
+			}
+		},
+		_dispatchEvent(type, data) {
+			if (this._changeDataFunction) {
+				this._changeDataFunction(data, this._isEnded)
+			} else {
+				this.$emit(type, data, this._isEnded)
+			}
+		}
+	}
+}

+ 78 - 46
src/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue

@@ -2,16 +2,21 @@
 	<view class="uni-data-checklist" :style="{'margin-top':isTop+'px'}">
 		<template v-if="!isLocal">
 			<view class="uni-data-loading">
-				<uni-load-more v-if="!mixinDatacomErrorMessage" status="loading" iconType="snow" :iconSize="18" :content-text="contentText"></uni-load-more>
+				<uni-load-more v-if="!mixinDatacomErrorMessage" status="loading" iconType="snow" :iconSize="18"
+					:content-text="contentText"></uni-load-more>
 				<text v-else>{{mixinDatacomErrorMessage}}</text>
 			</view>
 		</template>
 		<template v-else>
-			<checkbox-group v-if="multiple" class="checklist-group" :class="{'is-list':mode==='list' || wrap}" @change="change">
-				<label class="checklist-box" :class="['is--'+mode,item.selected?'is-checked':'',(disabled || !!item.disabled)?'is-disable':'',index!==0&&mode==='list'?'is-list-border':'']"
-				 :style="item.styleBackgroud" v-for="(item,index) in dataList" :key="index">
-					<checkbox class="hidden" hidden :disabled="disabled || !!item.disabled" :value="item[map.value]+''" :checked="item.selected" />
-					<view v-if="(mode !=='tag' && mode !== 'list') || ( mode === 'list' && icon === 'left')" class="checkbox__inner"  :style="item.styleIcon">
+			<checkbox-group v-if="multiple" class="checklist-group" :class="{'is-list':mode==='list' || wrap}"
+				@change="change">
+				<label class="checklist-box"
+					:class="['is--'+mode,item.selected?'is-checked':'',(disabled || !!item.disabled)?'is-disable':'',index!==0&&mode==='list'?'is-list-border':'']"
+					:style="item.styleBackgroud" v-for="(item,index) in dataList" :key="index">
+					<checkbox class="hidden" hidden :disabled="disabled || !!item.disabled" :value="item[map.value]+''"
+						:checked="item.selected" />
+					<view v-if="(mode !=='tag' && mode !== 'list') || ( mode === 'list' && icon === 'left')"
+						class="checkbox__inner" :style="item.styleIcon">
 						<view class="checkbox__inner-icon"></view>
 					</view>
 					<view class="checklist-content" :class="{'list-content':mode === 'list' && icon ==='left'}">
@@ -21,12 +26,13 @@
 				</label>
 			</checkbox-group>
 			<radio-group v-else class="checklist-group" :class="{'is-list':mode==='list','is-wrap':wrap}" @change="change">
-				<!-- -->
-				<label class="checklist-box" :class="['is--'+mode,item.selected?'is-checked':'',(disabled || !!item.disabled)?'is-disable':'',index!==0&&mode==='list'?'is-list-border':'']"
-				 :style="item.styleBackgroud" v-for="(item,index) in dataList" :key="index">
-					<radio class="hidden" hidden :disabled="disabled || item.disabled" :value="item[map.value]+''" :checked="item.selected" />
+				<label class="checklist-box"
+					:class="['is--'+mode,item.selected?'is-checked':'',(disabled || !!item.disabled)?'is-disable':'',index!==0&&mode==='list'?'is-list-border':'']"
+					:style="item.styleBackgroud" v-for="(item,index) in dataList" :key="index">
+					<radio class="hidden" hidden :disabled="disabled || item.disabled" :value="item[map.value]+''"
+						:checked="item.selected" />
 					<view v-if="(mode !=='tag' && mode !== 'list') || ( mode === 'list' && icon === 'left')" class="radio__inner"
-					 :style="item.styleBackgroud">
+						:style="item.styleBackgroud">
 						<view class="radio__inner-icon" :style="item.styleIcon"></view>
 					</view>
 					<view class="checklist-content" :class="{'list-content':mode === 'list' && icon ==='left'}">
@@ -68,7 +74,7 @@
 	export default {
 		name: 'uniDataChecklist',
 		mixins: [uniCloud.mixinDatacom || {}],
-		emits:['input','update:modelValue','change'],
+		emits: ['input', 'update:modelValue', 'change'],
 		props: {
 			mode: {
 				type: String,
@@ -88,7 +94,7 @@
 			// TODO vue3
 			modelValue: {
 				type: [Array, String, Number],
-				default() {
+				default () {
 					return '';
 				}
 			},
@@ -122,20 +128,20 @@
 				type: String,
 				default: ''
 			},
-			emptyText:{
+			emptyText: {
 				type: String,
 				default: '暂无数据'
 			},
-			disabled:{
+			disabled: {
 				type: Boolean,
 				default: false
 			},
-			map:{
+			map: {
 				type: Object,
-				default(){
+				default () {
 					return {
-						text:'text',
-						value:'value'
+						text: 'text',
+						value: 'value'
 					}
 				}
 			}
@@ -177,18 +183,18 @@
 					contentrefresh: '加载中',
 					contentnomore: '没有更多'
 				},
-				isLocal:true,
+				isLocal: true,
 				styles: {
 					selectedColor: '#2979ff',
 					selectedTextColor: '#666',
 				},
-				isTop:0
+				isTop: 0
 			};
 		},
-		computed:{
-			dataValue(){
-				if(this.value === '')return this.modelValue
-				if(this.modelValue === '') return this.value
+		computed: {
+			dataValue() {
+				if (this.value === '') return this.modelValue
+				if (this.modelValue === '') return this.value
 				return this.value
 			}
 		},
@@ -223,15 +229,15 @@
 		},
 		methods: {
 			loadData() {
-				this.mixinDatacomGet().then(res=>{
+				this.mixinDatacomGet().then(res => {
 					this.mixinDatacomResData = res.result.data
-					if(this.mixinDatacomResData.length === 0){
+					if (this.mixinDatacomResData.length === 0) {
 						this.isLocal = false
 						this.mixinDatacomErrorMessage = this.emptyText
-					}else{
+					} else {
 						this.isLocal = true
 					}
-				}).catch(err=>{
+				}).catch(err => {
 					this.mixinDatacomErrorMessage = err.message
 				})
 			},
@@ -303,6 +309,10 @@
 					if (!Array.isArray(value)) {
 						value = []
 					}
+				} else {
+					if (Array.isArray(value) && value.length) {
+						value = value[0]
+					}
 				}
 				dataList.forEach((item, index) => {
 					item.disabled = item.disable || item.disabled || false
@@ -383,13 +393,13 @@
 			 */
 			setStyleBackgroud(item) {
 				let styles = {}
-				let selectedColor = this.selectedColor?this.selectedColor:'#2979ff'
+				let selectedColor = this.selectedColor ? this.selectedColor : '#2979ff'
 				if (this.selectedColor) {
 					if (this.mode !== 'list') {
-						styles['border-color'] = item.selected?selectedColor:'#DCDFE6'
+						styles['border-color'] = item.selected ? selectedColor : '#DCDFE6'
 					}
 					if (this.mode === 'tag') {
-						styles['background-color'] = item.selected? selectedColor:'#f5f5f5'
+						styles['background-color'] = item.selected ? selectedColor : '#f5f5f5'
 					}
 				}
 				let classles = ''
@@ -402,13 +412,13 @@
 				let styles = {}
 				let classles = ''
 				if (this.selectedColor) {
-					let selectedColor = this.selectedColor?this.selectedColor:'#2979ff'
-					styles['background-color'] = item.selected?selectedColor:'#fff'
-					styles['border-color'] = item.selected?selectedColor:'#DCDFE6'
-					
-					if(!item.selected && item.disabled){
+					let selectedColor = this.selectedColor ? this.selectedColor : '#2979ff'
+					styles['background-color'] = item.selected ? selectedColor : '#fff'
+					styles['border-color'] = item.selected ? selectedColor : '#DCDFE6'
+
+					if (!item.selected && item.disabled) {
 						styles['background-color'] = '#F2F6FC'
-						styles['border-color'] = item.selected?selectedColor:'#DCDFE6'
+						styles['border-color'] = item.selected ? selectedColor : '#DCDFE6'
 					}
 				}
 				for (let i in styles) {
@@ -420,13 +430,13 @@
 				let styles = {}
 				let classles = ''
 				if (this.selectedColor) {
-					let selectedColor = this.selectedColor?this.selectedColor:'#2979ff'
+					let selectedColor = this.selectedColor ? this.selectedColor : '#2979ff'
 					if (this.mode === 'tag') {
-						styles.color = item.selected?(this.selectedTextColor?this.selectedTextColor:'#fff'):'#666'
+						styles.color = item.selected ? (this.selectedTextColor ? this.selectedTextColor : '#fff') : '#666'
 					} else {
-						styles.color = item.selected?(this.selectedTextColor?this.selectedTextColor:selectedColor):'#666'
+						styles.color = item.selected ? (this.selectedTextColor ? this.selectedTextColor : selectedColor) : '#666'
 					}
-					if(!item.selected && item.disabled){
+					if (!item.selected && item.disabled) {
 						styles.color = '#999'
 					}
 				}
@@ -439,7 +449,7 @@
 				let styles = {}
 				let classles = ''
 				if (this.mode === 'list') {
-					styles['border-color'] = item.selected?this.styles.selectedColor:'#DCDFE6'
+					styles['border-color'] = item.selected ? this.styles.selectedColor : '#DCDFE6'
 				}
 				for (let i in styles) {
 					classles += `${i}:${styles[i]};`
@@ -454,7 +464,7 @@
 <style lang="scss">
 	$uni-primary: #2979ff !default;
 	$border-color: #DCDFE6;
-	$disable:0.4;
+	$disable: 0.4;
 
 	@mixin flex {
 		/* #ifndef APP-NVUE */
@@ -476,6 +486,7 @@
 		position: relative;
 		z-index: 0;
 		flex: 1;
+
 		// 多选样式
 		.checklist-group {
 			@include flex;
@@ -506,6 +517,7 @@
 					flex-direction: row;
 					align-items: center;
 					justify-content: space-between;
+
 					.checklist-text {
 						font-size: 14px;
 						color: #666;
@@ -517,7 +529,7 @@
 						border-right-width: 1px;
 						border-right-color: #007aff;
 						border-right-style: solid;
-						border-bottom-width:1px;
+						border-bottom-width: 1px;
 						border-bottom-color: #007aff;
 						border-bottom-style: solid;
 						height: 12px;
@@ -542,6 +554,7 @@
 					border-radius: 4px;
 					background-color: #fff;
 					z-index: 1;
+
 					.checkbox__inner-icon {
 						position: absolute;
 						/* #ifdef APP-NVUE */
@@ -556,7 +569,7 @@
 						border-right-width: 1px;
 						border-right-color: #fff;
 						border-right-style: solid;
-						border-bottom-width:1px ;
+						border-bottom-width: 1px;
 						border-bottom-color: #fff;
 						border-bottom-style: solid;
 						opacity: 0;
@@ -597,6 +610,7 @@
 					&.is-disable {
 						/* #ifdef H5 */
 						cursor: not-allowed;
+
 						/* #endif */
 						.checkbox__inner {
 							background-color: #F2F6FC;
@@ -610,6 +624,7 @@
 							background-color: #F2F6FC;
 							border-color: $border-color;
 						}
+
 						.checklist-text {
 							color: #999;
 						}
@@ -626,16 +641,20 @@
 								transform: rotate(45deg);
 							}
 						}
+
 						.radio__inner {
 							border-color: $uni-primary;
+
 							.radio__inner-icon {
 								opacity: 1;
 								background-color: $uni-primary;
 							}
 						}
+
 						.checklist-text {
 							color: $uni-primary;
 						}
+
 						// 选中禁用
 						&.is-disable {
 							.checkbox__inner {
@@ -645,6 +664,7 @@
 							.checklist-text {
 								opacity: $disable;
 							}
+
 							.radio__inner {
 								opacity: $disable;
 							}
@@ -667,6 +687,7 @@
 						/* #endif */
 						border: 1px #eee solid;
 						opacity: $disable;
+
 						.checkbox__inner {
 							background-color: #F2F6FC;
 							border-color: $border-color;
@@ -674,6 +695,7 @@
 							cursor: not-allowed;
 							/* #endif */
 						}
+
 						.radio__inner {
 							background-color: #F2F6FC;
 							border-color: $border-color;
@@ -681,6 +703,7 @@
 							cursor: not-allowed;
 							/* #endif */
 						}
+
 						.checklist-text {
 							color: #999;
 						}
@@ -688,9 +711,11 @@
 
 					&.is-checked {
 						border-color: $uni-primary;
+
 						.checkbox__inner {
 							border-color: $uni-primary;
 							background-color: $uni-primary;
+
 							.checkbox__inner-icon {
 								opacity: 1;
 								transform: rotate(45deg);
@@ -747,6 +772,7 @@
 						}
 					}
 				}
+
 				// 列表样式
 				&.is--list {
 					/* #ifndef APP-NVUE */
@@ -764,6 +790,7 @@
 					&.is-disable {
 						/* #ifdef H5 */
 						cursor: not-allowed;
+
 						/* #endif */
 						.checkbox__inner {
 							background-color: #F2F6FC;
@@ -772,6 +799,7 @@
 							cursor: not-allowed;
 							/* #endif */
 						}
+
 						.checklist-text {
 							color: #999;
 						}
@@ -787,11 +815,15 @@
 								transform: rotate(45deg);
 							}
 						}
+
 						.radio__inner {
+							border-color: $uni-primary;
 							.radio__inner-icon {
 								opacity: 1;
+								background-color: $uni-primary;
 							}
 						}
+
 						.checklist-text {
 							color: $uni-primary;
 						}

+ 7 - 4
src/uni_modules/uni-data-checkbox/package.json

@@ -1,7 +1,7 @@
 {
   "id": "uni-data-checkbox",
   "displayName": "uni-data-checkbox 数据选择器",
-  "version": "1.0.4",
+  "version": "1.0.6",
   "description": "通过数据驱动的单选框和复选框",
   "keywords": [
     "uni-ui",
@@ -43,12 +43,15 @@
     "platforms": {
       "cloud": {
         "tcb": "y",
-        "aliyun": "y"
+        "aliyun": "y",
+        "alipay": "n"
       },
       "client": {
         "App": {
-          "app-vue": "y",
-          "app-nvue": "y"
+            "app-vue": "y",
+            "app-nvue": "y",
+            "app-harmony": "u",
+            "app-uvue": "u"
         },
         "H5-mobile": {
           "Safari": "y",

+ 2 - 0
src/uni_modules/uni-data-picker/changelog.md

@@ -1,3 +1,5 @@
+## 2.0.2(2025-04-14)
+- 修复 在readonly属性为true时选项匹配错误的问题
 ## 2.0.0(2023-12-14)
 - 新增 支持 uni-app-x
 ## 1.1.2(2023-04-11)

+ 18 - 9
src/uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.vue

@@ -232,15 +232,24 @@
         }
 
         let result = []
-        for (let i = 0; i < value.length; i++) {
-          var val = value[i]
-          var item = dataList.find((v) => {
-            return v.value == val
-          })
-          if (item) {
-            result.push(item)
-          }
-        }
+				if (Array.isArray(value)) {
+					for (let i = 0; i < value.length; i++) {
+						var val = value[i]
+						var item = dataList.find((v) => {
+							return v.value == val
+						})
+						if (item) {
+							result.push(item)
+						}
+					}
+				} else {
+					let item = dataList.find((v) => {
+						return v.value == value;
+					});
+					if (item) {
+						result.push(item);
+					}
+				}
         if (result.length) {
           this.inputSelected = result
         }

+ 7 - 5
src/uni_modules/uni-data-picker/package.json

@@ -1,7 +1,7 @@
 {
   "id": "uni-data-picker",
   "displayName": "uni-data-picker 数据驱动的picker选择器",
-  "version": "2.0.0",
+  "version": "2.0.2",
   "description": "单列、多列级联选择器,常用于省市区城市选择、公司部门选择、多级分类等场景",
   "keywords": [
     "uni-ui",
@@ -48,13 +48,15 @@
     "platforms": {
       "cloud": {
         "tcb": "y",
-        "aliyun": "y"
+        "aliyun": "y",
+        "alipay": "n"
       },
       "client": {
         "App": {
-          "app-vue": "y",
-          "app-nvue": "y",
-          "app-uvue": "y"
+            "app-vue": "y",
+            "app-nvue": "y",
+            "app-uvue": "y",
+            "app-harmony": "u"
         },
         "H5-mobile": {
           "Safari": "y",

+ 14 - 0
src/uni_modules/uni-data-select/changelog.md

@@ -1,3 +1,17 @@
+## 1.1.0(2025-08-19)
+- 新增 插槽 selected empty option
+- 新增 mutiple 属性,支持多选功能
+- 新增 wrap 属性,支持选中的文字超过一行显示
+- 新增 align 属性,支持修改选中的文字显示的位置
+- 新增 hideRight 属性,支持隐藏右侧所有按钮
+- 新增 mode 属性,支持修改边框样式
+- 新增 事件 open close clear
+## 1.0.10(2025-04-14)
+- 修复 清除按钮不展示问题
+## 1.0.9(2025-03-26)
+- 优化 默认背景为白色与整体组件保持风格统一
+## 1.0.8(2024-03-28)
+- 修复 在vue2下:style动态绑定导致编译失败的bug
 ## 1.0.7(2024-01-20)
 - 修复 长文本回显超过容器的bug,超过容器部分显示省略号
 ## 1.0.6(2023-04-12)

+ 391 - 81
src/uni_modules/uni-data-select/components/uni-data-select/uni-data-select.vue

@@ -2,30 +2,59 @@
 	<view class="uni-stat__select">
 		<span v-if="label" class="uni-label-text hide-on-phone">{{label + ':'}}</span>
 		<view class="uni-stat-box" :class="{'uni-stat__actived': current}">
-			<view class="uni-select" :class="{'uni-select--disabled':disabled}">
-				<view class="uni-select__input-box" @click="toggleSelector">
-					<view v-if="current" class="uni-select__input-text">{{textShow}}</view>
-					<view v-else class="uni-select__input-text uni-select__input-placeholder">{{typePlaceholder}}</view>
-					<view v-if="current && clear && !disabled" @click.stop="clearVal" >
-						<uni-icons type="clear" color="#c0c4cc" size="24"/>
+			<view class="uni-select" :class="{'uni-select--disabled':disabled, 'uni-select--wrap': shouldWrap , 'border-default': mode == 'default','border-bottom': mode == 'underline'}">
+				<view class="uni-select__input-box" @click="toggleSelector" :class="{'uni-select__input-box--wrap': shouldWrap}">
+          <view v-if="slotSelected" class="slot-content padding-top-bottom" :class="{'uni-select__input-text--wrap': shouldWrap}">
+            <slot name="selected" :selectedItems="getSelectedItems()"></slot>
+          </view>
+          <template v-else>
+            <view v-if="textShow" class="uni-select__input-text" :class="{'uni-select__input-text--wrap': shouldWrap}">
+              <view class="padding-top-bottom" :class="'align-'+align">{{textShow}}</view>
+            </view>
+            <view v-else class="uni-select__input-text uni-select__input-placeholder" :class="'align-'+align">{{typePlaceholder}}</view>
+          </template>
+					<view key="clear-button" v-if="!hideRight && shouldShowClear && clear && !disabled" @click.stop="clearVal">
+						<uni-icons type="clear" color="#c0c4cc" size="24" />
 					</view>
-					<view v-else>
+					<view key="arrow-button" v-else-if="!hideRight">
 						<uni-icons :type="showSelector? 'top' : 'bottom'" size="14" color="#999" />
 					</view>
 				</view>
 				<view class="uni-select--mask" v-if="showSelector" @click="toggleSelector" />
-				<view class="uni-select__selector" v-if="showSelector">
-					<view class="uni-popper__arrow"></view>
-					<scroll-view scroll-y="true" class="uni-select__selector-scroll">
-						<view class="uni-select__selector-empty" v-if="mixinDatacomResData.length === 0">
-							<text>{{emptyTips}}</text>
-						</view>
-						<view v-else class="uni-select__selector-item" v-for="(item,index) in mixinDatacomResData" :key="index"
-							@click="change(item)">
-							<text :class="{'uni-select__selector__disabled': item.disable}">{{formatItemName(item)}}</text>
-						</view>
-					</scroll-view>
-				</view>
+					<view class="uni-select__selector" :style="getOffsetByPlacement" v-if="showSelector">
+						<view :class="placement=='bottom'?'uni-popper__arrow_bottom':'uni-popper__arrow_top'"></view>
+						<scroll-view scroll-y="true" class="uni-select__selector-scroll">
+							<template v-if="slotEmpty && mixinDatacomResData.length === 0">
+								<view class="uni-select__selector-empty">
+									<slot name="empty" :empty="emptyTips"></slot>
+								</view>
+							</template>
+							<template v-else>
+								<view v-if="mixinDatacomResData.length === 0" class="uni-select__selector-empty">
+									<text>{{emptyTips}}</text>
+								</view>
+							</template>
+							<template v-if="slotOption">
+								<view v-for="(itemData,index) in mixinDatacomResData" :key="index" @click="change(itemData)">
+									<slot name="option" :item="itemData" :itemSelected="multiple? getCurrentValues().includes(itemData.value):getCurrentValues() == itemData.value"></slot>
+								</view>
+							</template>
+							<template v-else>
+								<view v-if="!multiple && mixinDatacomResData.length > 0" class="uni-select__selector-item" v-for="(item,index) in mixinDatacomResData" :key="index"
+									@click="change(item)">
+									<text :class="{'uni-select__selector__disabled': item.disable}">{{formatItemName(item)}}</text>
+								</view>
+								<view v-if="multiple && mixinDatacomResData.length > 0" >
+									<checkbox-group @change="checkBoxChange">
+										<label class="uni-select__selector-item" v-for="(item,index) in mixinDatacomResData" :key="index" >
+											<checkbox :value="index+''" :checked="getCurrentValues().includes(item.value)" :disabled="item.disable"></checkbox>
+											<view :class="{'uni-select__selector__disabled': item.disable}">{{formatItemName(item)}}</view>
+										</label>
+									</checkbox-group>
+								</view>
+							</template>
+						</scroll-view>
+					</view>
 			</view>
 		</view>
 	</view>
@@ -36,19 +65,56 @@
 	 * DataChecklist 数据选择器
 	 * @description 通过数据渲染的下拉框组件
 	 * @tutorial https://uniapp.dcloud.io/component/uniui/uni-data-select
-	 * @property {String} value 默认值
+	 * @property {String|Array} value 默认值,多选时为数组
 	 * @property {Array} localdata 本地数据 ,格式 [{text:'',value:''}]
 	 * @property {Boolean} clear 是否可以清空已选项
 	 * @property {Boolean} emptyText 没有数据时显示的文字 ,本地数据无效
 	 * @property {String} label 左侧标题
 	 * @property {String} placeholder 输入框的提示文字
 	 * @property {Boolean} disabled 是否禁用
+	 * @property {Boolean} multiple 是否多选模式
+	 * @property {Boolean} wrap 是否允许选中文本换行显示
+	 * @property {String} placement 弹出位置
+	 * 	@value top   		顶部弹出
+	 * 	@value bottom		底部弹出(default)
+	 * @property {String} align 选择文字的位置
+	 *  @value left 显示左侧
+	 *  @value center 显示中间
+	 *  @value right 显示 右侧
+	 * @property {Boolean} hideRight 是否隐藏右侧按钮
+	 * @property {String} mode 边框样式
+	 *  @value default 四周边框
+	 *  @value underline 下边框
+	 *  @value none 无边框
 	 * @event {Function} change  选中发生变化触发
+	 * @event {Function} open  选择框开启时触发
+	 * @event {Function} close  选择框关闭时触发
+	 * @event {Function} clear  点击清除按钮之后触发
 	 */
 
 	export default {
 		name: "uni-data-select",
 		mixins: [uniCloud.mixinDatacom || {}],
+		emits: [
+			'open',
+			'close',
+			'update:modelValue',
+			'input',
+			'clear',
+			'change'
+		],
+		model: {
+			prop: 'modelValue',
+			event: 'update:modelValue'
+		},
+		options: {
+			// #ifdef MP-TOUTIAO
+			virtualHost: false,
+			// #endif
+			// #ifndef MP-TOUTIAO
+			virtualHost: true
+			// #endif
+		},
 		props: {
 			localdata: {
 				type: Array,
@@ -57,11 +123,11 @@
 				}
 			},
 			value: {
-				type: [String, Number],
+				type: [String, Number, Array],
 				default: ''
 			},
 			modelValue: {
-				type: [String, Number],
+				type: [String, Number, Array],
 				default: ''
 			},
 			label: {
@@ -93,6 +159,30 @@
 				type: String,
 				default: ''
 			},
+			placement: {
+				type: String,
+				default: 'bottom'
+			},
+      multiple: {
+				type: Boolean,
+				default: false
+			},
+			wrap: {
+				type: Boolean,
+				default: false
+			},
+			align:{
+				type: String,
+				default: "left"
+			},
+			hideRight: {
+				type: Boolean,
+				default: false
+			},
+      mode:{
+        type: String,
+        default: 'default'
+      }
 		},
 		data() {
 			return {
@@ -125,25 +215,76 @@
 					common + placeholder :
 					common
 			},
-			valueCom(){
-				// #ifdef VUE3
-				return this.modelValue;
-				// #endif
-				// #ifndef VUE3
-				return this.value;
-				// #endif
+			valueCom() {
+        if (this.value === '') return this.modelValue
+				if (this.modelValue === '') return this.value
+				return this.value
 			},
-			textShow(){
+			textShow() {
 				// 长文本显示
-				let text = this.current;
-				if (text.length > 10) {
-					return text.slice(0, 25) + '...';
+				if (this.multiple) {
+					const currentValues = this.getCurrentValues();
+					if (Array.isArray(currentValues) && currentValues.length > 0) {
+						const selectedItems = this.mixinDatacomResData.filter(item => currentValues.includes(item.value));
+						return selectedItems.map(item => this.formatItemName(item)).join(', ');
+					} else {
+						return ''; // 空数组时返回空字符串,显示占位符
+					}
+				} else {
+					return this.current;
+				}
+			},
+			shouldShowClear() {
+				if (this.multiple) {
+					const currentValues = this.getCurrentValues();
+					return Array.isArray(currentValues) && currentValues.length > 0;
+				} else {
+					return !!this.current;
 				}
-				return text;
+			},
+			shouldWrap() {
+				// 只有在多选模式、开启换行、且有内容时才应用换行样式
+				return this.multiple && this.wrap && !!this.textShow;
+			},
+			getOffsetByPlacement() {
+				switch (this.placement) {
+					case 'top':
+						return "bottom:calc(100% + 12px);";
+					case 'bottom':
+						return "top:calc(100% + 12px);";
+				}
+			},
+      slotSelected(){
+        // #ifdef VUE2
+        return this.$scopedSlots ? this.$scopedSlots.selected : false
+        // #endif
+        // #ifdef VUE3
+        return this.$slots ? this.$slots.selected : false
+        // #endif
+      },
+      slotEmpty(){
+        // #ifdef VUE2
+        return this.$scopedSlots ? this.$scopedSlots.empty : false
+        // #endif
+        // #ifdef VUE3
+        return this.$slots ? this.$slots.empty : false
+        // #endif
+      },
+			slotOption(){
+				// #ifdef VUE2
+				return this.$scopedSlots ? this.$scopedSlots.option : false
+				// #endif
+				// #ifdef VUE3
+				return this.$slots ? this.$slots.option : false
+				// #endif
 			}
 		},
-
 		watch: {
+			showSelector:{
+				handler(val,old){
+					val ? this.$emit('open') : this.$emit('close')
+				}
+			},
 			localdata: {
 				immediate: true,
 				handler(val, old) {
@@ -163,10 +304,21 @@
 					}
 				}
 			},
-
 		},
 		methods: {
-			debounce(fn, time = 100){
+			getSelectedItems() {
+				const currentValues = this.getCurrentValues();
+				let _minxData = this.mixinDatacomResData
+				// #ifdef MP-WEIXIN || MP-TOUTIAO
+				_minxData = JSON.parse(JSON.stringify(this.mixinDatacomResData))
+				// #endif
+				if (this.multiple) {
+					return _minxData.filter(item => currentValues.includes(item.value)) || [];
+				} else {
+					return _minxData.filter(item => item.value === currentValues) || [];
+				}
+			},
+			debounce(fn, time = 100) {
 				let timer = null
 				return function(...args) {
 					if (timer) clearTimeout(timer)
@@ -175,18 +327,35 @@
 					}, time)
 				}
 			},
+			// 检查项目是否已选中
+			isSelected(item) {
+				if (this.multiple) {
+					const currentValues = this.getCurrentValues();
+					return Array.isArray(currentValues) && currentValues.includes(item.value);
+				} else {
+					return this.getCurrentValues() === item.value;
+				}
+			},
+			// 获取当前选中的值
+			getCurrentValues() {
+				if (this.multiple) {
+					return Array.isArray(this.valueCom) ? this.valueCom : (this.valueCom ? [this.valueCom] : []);
+				} else {
+					return this.valueCom;
+				}
+			},
 			// 执行数据库查询
-			query(){
+			query() {
 				this.mixinDatacomEasyGet();
 			},
 			// 监听查询条件变更事件
-			onMixinDatacomPropsChange(){
+			onMixinDatacomPropsChange() {
 				if (this.collection) {
 					this.debounceGet();
 				}
 			},
 			initDefVal() {
-				let defValue = ''
+				let defValue = this.multiple ? [] : ''
 				if ((this.valueCom || this.valueCom === 0) && !this.isDisabled(this.valueCom)) {
 					defValue = this.valueCom
 				} else {
@@ -197,47 +366,105 @@
 					if (strogeValue || strogeValue === 0) {
 						defValue = strogeValue
 					} else {
-						let defItem = ''
+						let defItem = this.multiple ? [] : ''
 						if (this.defItem > 0 && this.defItem <= this.mixinDatacomResData.length) {
-							defItem = this.mixinDatacomResData[this.defItem - 1].value
+							defItem = this.multiple ? [this.mixinDatacomResData[this.defItem - 1].value] : this.mixinDatacomResData[this.defItem - 1].value
 						}
 						defValue = defItem
 					}
-          if (defValue || defValue === 0) {
-					  this.emit(defValue)
-          }
+					if (defValue || defValue === 0 || (this.multiple && Array.isArray(defValue) && defValue.length > 0)) {
+						this.emit(defValue)
+					}
+				}
+
+				if (this.multiple) {
+					const selectedValues = Array.isArray(defValue) ? defValue : (defValue ? [defValue] : []);
+					const selectedItems = this.mixinDatacomResData.filter(item => selectedValues.includes(item.value));
+					this.current = selectedItems.map(item => this.formatItemName(item));
+				} else {
+					const def = this.mixinDatacomResData.find(item => item.value === defValue)
+					this.current = def ? this.formatItemName(def) : ''
 				}
-				const def = this.mixinDatacomResData.find(item => item.value === defValue)
-				this.current = def ? this.formatItemName(def) : ''
 			},
 
 			/**
-			 * @param {[String, Number]} value
+			 * @param {[String, Number, Array]} value
 			 * 判断用户给的 value 是否同时为禁用状态
 			 */
 			isDisabled(value) {
-				let isDisabled = false;
-
-				this.mixinDatacomResData.forEach(item => {
-					if (item.value === value) {
-						isDisabled = item.disable
-					}
-				})
-
-				return isDisabled;
+				if (Array.isArray(value)) {
+					// 对于数组,如果任意一个值被禁用,则认为整体被禁用
+					return value.some(val => {
+						return this.mixinDatacomResData.some(item => item.value === val && item.disable);
+					});
+				} else {
+					let isDisabled = false;
+					this.mixinDatacomResData.forEach(item => {
+						if (item.value === value) {
+							isDisabled = item.disable
+						}
+					})
+					return isDisabled;
+				}
 			},
-
 			clearVal() {
-				this.emit('')
+				const emptyValue = this.multiple ? [] : '';
+				this.emit(emptyValue)
+				this.current = this.multiple ? [] : ''
 				if (this.collection) {
 					this.removeCache()
 				}
+				this.$emit('clear')
+			},
+			checkBoxChange(res){
+				let range = res.detail.value
+
+				let currentValues = range && range.length > 0? range.map((item)=>{
+					const index = parseInt(item, 10);
+
+					if (isNaN(index)) {
+						console.error(`无效索引: ${item}`);
+					}
+
+					if (index < 0 || index >= this.mixinDatacomResData.length) {
+						console.error(`索引越界: ${index}`);
+					}
+
+					return this.mixinDatacomResData[index].value;
+				}) : []
+				const selectedItems = this.mixinDatacomResData.filter(dataItem => currentValues.includes(dataItem.value));
+				this.current = selectedItems.map(dataItem => this.formatItemName(dataItem));
+
+				this.emit(currentValues);
 			},
 			change(item) {
 				if (!item.disable) {
-					this.showSelector = false
-					this.current = this.formatItemName(item)
-					this.emit(item.value)
+					if (this.multiple) {
+						// 多选模式
+						let currentValues = this.getCurrentValues();
+						if (!Array.isArray(currentValues)) {
+							currentValues = currentValues ? [currentValues] : [];
+						}
+
+						const itemValue = item.value;
+						const index = currentValues.indexOf(itemValue);
+
+						if (index > -1) {
+							currentValues.splice(index, 1);
+						} else {
+							currentValues.push(itemValue);
+						}
+
+						const selectedItems = this.mixinDatacomResData.filter(dataItem => currentValues.includes(dataItem.value));
+						this.current = selectedItems.map(dataItem => this.formatItemName(dataItem));
+
+						this.emit(currentValues);
+					} else {
+						// 单选模式
+						this.showSelector = false
+						this.current = this.formatItemName(item)
+						this.emit(item.value)
+					}
 				}
 			},
 			emit(val) {
@@ -268,7 +495,7 @@
 					let str = "";
 					str = this.format;
 					for (let key in item) {
-						str = str.replace(new RegExp(`{${key}}`,"g"),item[key]);
+						str = str.replace(new RegExp(`{${key}}`, "g"), item[key]);
 					}
 					return str;
 				} else {
@@ -282,26 +509,26 @@
 				}
 			},
 			// 获取当前加载的数据
-			getLoadData(){
+			getLoadData() {
 				return this.mixinDatacomResData;
 			},
 			// 获取当前缓存key
-			getCurrentCacheKey(){
+			getCurrentCacheKey() {
 				return this.collection;
 			},
 			// 获取缓存
-			getCache(name=this.getCurrentCacheKey()){
+			getCache(name = this.getCurrentCacheKey()) {
 				let cacheData = uni.getStorageSync(this.cacheKey) || {};
 				return cacheData[name];
 			},
 			// 设置缓存
-			setCache(value, name=this.getCurrentCacheKey()){
+			setCache(value, name = this.getCurrentCacheKey()) {
 				let cacheData = uni.getStorageSync(this.cacheKey) || {};
 				cacheData[name] = value;
 				uni.setStorageSync(this.cacheKey, cacheData);
 			},
 			// 删除缓存
-			removeCache(name=this.getCurrentCacheKey()){
+			removeCache(name = this.getCurrentCacheKey()) {
 				let cacheData = uni.getStorageSync(this.cacheKey) || {};
 				delete cacheData[name];
 				uni.setStorageSync(this.cacheKey, cacheData);
@@ -315,7 +542,11 @@
 	$uni-main-color: #333 !default;
 	$uni-secondary-color: #909399 !default;
 	$uni-border-3: #e5e5e5;
-
+  $uni-primary: #2979ff !default;
+	$uni-success: #4cd964 !default;
+	$uni-warning: #f0ad4e !default;
+	$uni-error: #dd524d !default;
+	$uni-info: #909399 !default;
 
 	/* #ifndef APP-NVUE */
 	@media screen and (max-width: 500px) {
@@ -338,6 +569,7 @@
 	}
 
 	.uni-stat-box {
+		background-color: #fff;
 		width: 100%;
 		flex: 1;
 	}
@@ -356,9 +588,16 @@
 		margin-right: 5px;
 	}
 
+  .border-bottom {
+    border-bottom: solid 1px $uni-border-3;
+  }
+
+  .border-default {
+    border: 1px solid $uni-border-3;
+  }
+
 	.uni-select {
 		font-size: 14px;
-		border: 1px solid $uni-border-3;
 		box-sizing: border-box;
 		border-radius: 4px;
 		padding: 0 5px;
@@ -370,15 +609,20 @@
 		/* #endif */
 		flex-direction: row;
 		align-items: center;
-		border-bottom: solid 1px $uni-border-3;
 		width: 100%;
 		flex: 1;
-		height: 35px;
+		min-height: 35px;
 
 		&--disabled {
 			background-color: #f5f7fa;
 			cursor: not-allowed;
 		}
+
+		&--wrap {
+			height: auto;
+			min-height: 35px;
+			// align-items: flex-start;
+		}
 	}
 
 	.uni-select__label {
@@ -390,7 +634,8 @@
 	}
 
 	.uni-select__input-box {
-		height: 35px;
+		// height: 35px;
+		width: 0px;
 		position: relative;
 		/* #ifndef APP-NVUE */
 		display: flex;
@@ -398,6 +643,24 @@
 		flex: 1;
 		flex-direction: row;
 		align-items: center;
+
+		&--wrap {
+			.uni-select__input-text {
+				margin-right: 8px;
+			}
+		}
+
+    .padding-top-bottom {
+      padding-top: 5px;
+      padding-bottom: 5px;
+    }
+
+    .slot-content {
+      width: 100%;
+      display: flex;
+      flex-direction: row;
+			flex-wrap: wrap;
+    }
 	}
 
 	.uni-select__input {
@@ -417,7 +680,6 @@
 		box-sizing: border-box;
 		/* #endif */
 		position: absolute;
-		top: calc(100% + 12px);
 		left: 0;
 		width: 100%;
 		background-color: #FFFFFF;
@@ -441,6 +703,7 @@
 			max-height: 600px;
 		}
 	}
+
 	/* #endif */
 
 	.uni-select__selector-empty,
@@ -449,15 +712,18 @@
 		display: flex;
 		cursor: pointer;
 		/* #endif */
+		flex-direction: row;
+		align-items: center;
 		line-height: 35px;
 		font-size: 14px;
-		text-align: center;
 		/* border-bottom: solid 1px $uni-border-3; */
 		padding: 0px 10px;
 	}
 
-	.uni-select__selector-item:hover {
-		background-color: #f9f9f9;
+
+
+	.uni-select__selector-item-check {
+		margin-left: auto;
 	}
 
 	.uni-select__selector-empty:last-child,
@@ -473,8 +739,10 @@
 	}
 
 	/* picker 弹出层通用的指示小三角 */
-	.uni-popper__arrow,
-	.uni-popper__arrow::after {
+	.uni-popper__arrow_bottom,
+	.uni-popper__arrow_bottom::after,
+	.uni-popper__arrow_top,
+	.uni-popper__arrow_top::after {
 		position: absolute;
 		display: block;
 		width: 0;
@@ -484,7 +752,7 @@
 		border-width: 6px;
 	}
 
-	.uni-popper__arrow {
+	.uni-popper__arrow_bottom {
 		filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
 		top: -6px;
 		left: 10%;
@@ -493,7 +761,7 @@
 		border-bottom-color: #EBEEF5;
 	}
 
-	.uni-popper__arrow::after {
+	.uni-popper__arrow_bottom::after {
 		content: " ";
 		top: 1px;
 		margin-left: -6px;
@@ -501,6 +769,24 @@
 		border-bottom-color: #fff;
 	}
 
+	.uni-popper__arrow_top {
+		filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
+		bottom: -6px;
+		left: 10%;
+		margin-right: 3px;
+		border-bottom-width: 0;
+		border-top-color: #EBEEF5;
+	}
+
+	.uni-popper__arrow_top::after {
+		content: " ";
+		bottom: 1px;
+		margin-left: -6px;
+		border-bottom-width: 0;
+		border-top-color: #fff;
+	}
+
+
 	.uni-select__input-text {
 		// width: 280px;
 		width: 100%;
@@ -509,11 +795,22 @@
 		text-overflow: ellipsis;
 		-o-text-overflow: ellipsis;
 		overflow: hidden;
+
+		&--wrap {
+			white-space: normal;
+			text-overflow: initial;
+			-o-text-overflow: initial;
+			overflow: visible;
+			word-wrap: break-word;
+			word-break: break-all;
+			// line-height: 1.5;
+		}
 	}
 
 	.uni-select__input-placeholder {
 		color: $uni-base-color;
 		font-size: 12px;
+    margin: 1px 0;
 	}
 
 	.uni-select--mask {
@@ -524,4 +821,17 @@
 		left: 0;
 		z-index: 2;
 	}
+
+  .align-left {
+    text-align: left;
+  }
+
+  .align-center {
+    text-align: center;
+  }
+
+  .align-right {
+    text-align: right;
+  }
+
 </style>

+ 60 - 39
src/uni_modules/uni-data-select/package.json

@@ -1,7 +1,7 @@
 {
   "id": "uni-data-select",
   "displayName": "uni-data-select 下拉框选择器",
-  "version": "1.0.7",
+  "version": "1.1.0",
   "description": "通过数据驱动的下拉框选择器",
   "keywords": [
     "uni-ui",
@@ -12,12 +12,14 @@
 ],
   "repository": "https://github.com/dcloudio/uni-ui",
   "engines": {
-    "HBuilderX": "^3.1.1"
+    "HBuilderX": "^3.1.1",
+    "uni-app": "^4.45",
+    "uni-app-x": ""
   },
   "directories": {
     "example": "../../temps/example_temps"
   },
-"dcloudext": {
+  "dcloudext": {
     "sale": {
       "regular": {
         "price": "0.00"
@@ -35,51 +37,70 @@
       "permissions": "无"
     },
     "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
-    "type": "component-vue"
+    "type": "component-vue",
+    "darkmode": "x",
+    "i18n": "x",
+    "widescreen": "x"
   },
   "uni_modules": {
-    "dependencies": ["uni-load-more"],
+    "dependencies": [
+      "uni-load-more"
+    ],
     "encrypt": [],
     "platforms": {
       "cloud": {
-        "tcb": "y",
-        "aliyun": "y"
+        "tcb": "√",
+        "aliyun": "√",
+        "alipay": "√"
       },
       "client": {
-        "App": {
-          "app-vue": "u",
-          "app-nvue": "n"
+        "uni-app": {
+          "vue": {
+            "vue2": "√",
+            "vue3": "√"
+          },
+          "web": {
+            "safari": "√",
+            "chrome": "√"
+          },
+          "app": {
+            "vue": "√",
+            "nvue": "-",
+            "android": "√",
+            "ios": "√",
+            "harmony": "√"
+          },
+          "mp": {
+            "weixin": "√",
+            "alipay": "√",
+            "toutiao": "√",
+            "baidu": "-",
+            "kuaishou": "-",
+            "jd": "-",
+            "harmony": "-",
+            "qq": "-",
+            "lark": "-"
+          },
+          "quickapp": {
+            "huawei": "-",
+            "union": "-"
+          }
         },
-        "H5-mobile": {
-          "Safari": "y",
-          "Android Browser": "y",
-          "微信浏览器(Android)": "y",
-          "QQ浏览器(Android)": "y"
-        },
-        "H5-pc": {
-          "Chrome": "y",
-          "IE": "y",
-          "Edge": "y",
-          "Firefox": "y",
-          "Safari": "y"
-        },
-        "小程序": {
-          "微信": "y",
-          "阿里": "u",
-          "百度": "u",
-          "字节跳动": "u",
-        "QQ": "u",
-        "京东": "u"
-        },
-        "快应用": {
-          "华为": "u",
-          "联盟": "u"
-        },
-        "Vue": {
-            "vue2": "y",
-            "vue3": "y"
+        "uni-app-x": {
+          "web": {
+            "safari": "-",
+            "chrome": "-"
+          },
+          "app": {
+            "android": "-",
+            "ios": "-",
+            "harmony": "-"
+          },
+          "mp": {
+            "weixin": "-"
+          }
         }
       }
     }
   }
-}
+}

+ 21 - 0
src/uni_modules/uni-datetime-picker/changelog.md

@@ -1,3 +1,24 @@
+## 2.2.42(2025-08-20)
+- 修复 datetime-picker 小程序样式警告
+## 2.2.41(2025-08-20)
+- 修复 uni-datetime-picker组件时间对比报错问题
+## 2.2.40(2025-04-14)
+- 修复 绑定字符串值的时,日历面板选中状态未重置到默认值的问题
+## 2.2.39(2025-04-14)
+- 修复 在 iOS 微信小程序上type='daterange'时,传入'YYYY-MM-DD'格式不生效的问题
+
+## 2.2.38(2024-10-15)
+- 修复 微信小程序中的getSystemInfo警告
+## 2.2.35(2024-09-21)
+- 修复 没有选中日期时点击确定直接报错的Bug [详情](https://ask.dcloud.net.cn/question/198168)
+## 2.2.34(2024-04-24)
+- 新增 日期点击事件,在点击日期时会触发该事件。
+## 2.2.33(2024-04-15)
+- 修复 抖音小程序事件传递失效bug
+## 2.2.32(2024-02-20)
+- 修复 日历的close事件触发异常的bug [详情](https://github.com/dcloudio/uni-ui/issues/844)
+## 2.2.31(2024-02-20)
+- 修复 h5平台 右边日历的月份默认+1的bug [详情](https://github.com/dcloudio/uni-ui/issues/841)
 ## 2.2.30(2024-01-31)
 - 修复 隐藏“秒”时,在IOS15及以下版本时出现 结束时间在开始时间之前 的bug [详情](https://github.com/dcloudio/uni-ui/issues/788)
 ## 2.2.29(2024-01-20)

+ 91 - 72
src/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.vue

@@ -21,7 +21,7 @@
 					<view class="uni-calendar__header-btn uni-calendar--right"></view>
 				</view>
 
-				<view v-if="!insert" class="dialog-close" @click="close">
+				<view v-if="!insert" class="dialog-close" @click="maskClick">
 					<view class="dialog-close-plus" data-id="close"></view>
 					<view class="dialog-close-plus dialog-close-rotate" data-id="close"></view>
 				</view>
@@ -58,9 +58,8 @@
 
 				<view class="uni-calendar__weeks" v-for="(item,weekIndex) in weeks" :key="weekIndex">
 					<view class="uni-calendar__weeks-item" v-for="(weeks,weeksIndex) in item" :key="weeksIndex">
-						<calendar-item class="uni-calendar-item--hook" :weeks="weeks" :calendar="calendar"
-							:selected="selected" :checkHover="range" @change="choiceDate"
-							@handleMouse="handleMouse">
+						<calendar-item class="uni-calendar-item--hook" :weeks="weeks" :calendar="calendar" :selected="selected"
+							:checkHover="range" @change="choiceDate" @handleMouse="handleMouse">
 						</calendar-item>
 					</view>
 				</view>
@@ -101,13 +100,21 @@
 </template>
 
 <script>
-	import { Calendar, getDate, getTime } from './util.js';
+	import {
+		Calendar,
+		getDate,
+		getTime
+	} from './util.js';
 	import calendarItem from './calendar-item.vue'
 	import timePicker from './time-picker.vue'
 
-	import { initVueI18n } from '@dcloudio/uni-i18n'
+	import {
+		initVueI18n
+	} from '@dcloudio/uni-i18n'
 	import i18nMessages from './i18n/index.js'
-	const { t } = initVueI18n(i18nMessages)
+	const {
+		t
+	} = initVueI18n(i18nMessages)
 
 	/**
 	 * Calendar 日历
@@ -134,6 +141,15 @@
 			calendarItem,
 			timePicker
 		},
+
+		options: {
+			// #ifdef MP-TOUTIAO
+			virtualHost: false,
+			// #endif
+			// #ifndef MP-TOUTIAO
+			virtualHost: true
+			// #endif
+		},
 		props: {
 			date: {
 				type: String,
@@ -163,8 +179,8 @@
 				type: String,
 				default: ''
 			},
-      startPlaceholder: {
-        type: String,
+			startPlaceholder: {
+				type: String,
 				default: ''
 			},
 			endPlaceholder: {
@@ -210,10 +226,10 @@
 					}
 				}
 			},
-      defaultValue: {
-        type: [String, Object, Array],
-        default: ''
-      }
+			defaultValue: {
+				type: [String, Object, Array],
+				default: ''
+			}
 		},
 		data() {
 			return {
@@ -260,7 +276,7 @@
 			},
 			startDate(val) {
 				// 字节小程序 watch 早于 created
-				if(!this.cale){
+				if (!this.cale) {
 					return
 				}
 				this.cale.setStartDate(val)
@@ -269,7 +285,7 @@
 			},
 			endDate(val) {
 				// 字节小程序 watch 早于 created
-				if(!this.cale){
+				if (!this.cale) {
 					return
 				}
 				this.cale.setEndDate(val)
@@ -278,7 +294,7 @@
 			},
 			selected(newVal) {
 				// 字节小程序 watch 早于 created
-				if(!this.cale){
+				if (!this.cale) {
 					return
 				}
 				this.cale.setSelectInfo(this.nowDate.fullDate, newVal)
@@ -309,16 +325,16 @@
 								this.cale.lastHover = false
 							}
 						} else {
-              // 字节小程序 watch 早于 created
-              if(!this.cale){
-                return
-              }
+							// 字节小程序 watch 早于 created
+							if (!this.cale) {
+								return
+							}
 
 							this.cale.setDefaultMultiple(before, after)
 							if (which === 'left' && before) {
 								this.setDate(before)
 								this.weeks = this.cale.weeks
-							} else if(after) {
+							} else if (after) {
 								this.setDate(after)
 								this.weeks = this.cale.weeks
 							}
@@ -423,7 +439,7 @@
 			},
 			// 蒙版点击事件
 			maskClick() {
-        this.close()
+				this.close()
 				this.$emit('maskClose')
 			},
 
@@ -454,36 +470,38 @@
 			 * @param {Object} date
 			 */
 			init(date) {
-        // 字节小程序 watch 早于 created
-				if(!this.cale){
+				// 字节小程序 watch 早于 created
+				if (!this.cale) {
 					return
 				}
 				this.cale.setDate(date || new Date())
 				this.weeks = this.cale.weeks
 				this.nowDate = this.cale.getInfo(date)
-        this.calendar = {...this.nowDate}
-        if(!date){
-          // 优化date为空默认不选中今天
-          this.calendar.fullDate = ''
-          if(this.defaultValue && !this.range){
-            // 暂时只支持移动端非范围选择
-            const defaultDate = new Date(this.defaultValue)
-            const fullDate = getDate(defaultDate)
-            const year = defaultDate.getFullYear()
-            const month = defaultDate.getMonth()+1
-            const date = defaultDate.getDate()
-            const day = defaultDate.getDay()
-            this.calendar = {
-              fullDate,
-              year,
-              month,
-              date,
-              day
-            },
-            this.tempSingleDate = fullDate
-            this.time = getTime(defaultDate, this.hideSecond)
-          }
-        }
+				this.calendar = {
+					...this.nowDate
+				}
+				if (!date) {
+					// 优化date为空默认不选中今天
+					this.calendar.fullDate = ''
+					if (this.defaultValue && !this.range) {
+						// 暂时只支持移动端非范围选择
+						const defaultDate = new Date(this.defaultValue)
+						const fullDate = getDate(defaultDate)
+						const year = defaultDate.getFullYear()
+						const month = defaultDate.getMonth() + 1
+						const date = defaultDate.getDate()
+						const day = defaultDate.getDay()
+						this.calendar = {
+								fullDate,
+								year,
+								month,
+								date,
+								day
+							},
+							this.tempSingleDate = fullDate
+						this.time = getTime(defaultDate, this.hideSecond)
+					}
+				}
 			},
 			/**
 			 * 打开日历弹窗
@@ -523,8 +541,8 @@
 			/**
 			 * 变化触发
 			 */
-			change() {
-				if (!this.insert) return
+			change(isSingleChange) {
+				if (!this.insert && !isSingleChange) return
 				this.setEmit('change')
 			},
 			/**
@@ -545,13 +563,13 @@
 			 * @param {Object} name
 			 */
 			setEmit(name) {
-        if(!this.range){
-					if(!this.calendar.fullDate){
-					  this.calendar = this.cale.getInfo(new Date())
-					  this.tempSingleDate = this.calendar.fullDate
+				if (!this.range) {
+					if (!this.calendar.fullDate) {
+						this.calendar = this.cale.getInfo(new Date())
+						this.tempSingleDate = this.calendar.fullDate
 					}
-					if(this.hasTime && !this.time) {
-					  this.time = getTime(new Date(), this.hideSecond)
+					if (this.hasTime && !this.time) {
+						this.time = getTime(new Date(), this.hideSecond)
 					}
 				}
 				let {
@@ -593,19 +611,19 @@
 					this.tempRange.before = this.cale.multipleStatus.before
 					this.tempRange.after = this.cale.multipleStatus.after
 				}
-				this.change()
-			},
-      changeMonth(type) {
-        let newDate
-        if(type === 'pre') {
-          newDate = this.cale.getPreMonthObj(this.nowDate.fullDate).fullDate
-        } else if(type === 'next') {
-          newDate = this.cale.getNextMonthObj(this.nowDate.fullDate).fullDate
-        }
+				this.change(true)
+			},
+			changeMonth(type) {
+				let newDate
+				if (type === 'pre') {
+					newDate = this.cale.getPreMonthObj(this.nowDate.fullDate).fullDate
+				} else if (type === 'next') {
+					newDate = this.cale.getNextMonthObj(this.nowDate.fullDate).fullDate
+				}
 
-        this.setDate(newDate)
+				this.setDate(newDate)
 				this.monthSwitch()
-      },
+			},
 			/**
 			 * 设置日期
 			 * @param {Object} date
@@ -619,7 +637,7 @@
 	}
 </script>
 
-<style lang="scss" >
+<style lang="scss">
 	$uni-primary: #007aff !default;
 
 	.uni-calendar {
@@ -855,17 +873,17 @@
 
 	.uni-date-changed--time-end {
 		/* #ifndef APP-NVUE */
-    display: flex;
+		display: flex;
 		/* #endif */
 		align-items: center;
 	}
 
 	.uni-date-changed--time-date {
-    color: #999;
+		color: #999;
 		line-height: 50px;
-    /* #ifdef MP-TOUTIAO */
-    font-size: 16px;
-    /* #endif */
+		/* #ifdef MP-TOUTIAO */
+		font-size: 16px;
+		/* #endif */
 		margin-right: 5px;
 		// opacity: 0.6;
 	}
@@ -924,5 +942,6 @@
 	.uni-datetime-picker--btn:active {
 		opacity: 0.7;
 	}
+
 	/* #endif */
 </style>

+ 22 - 8
src/uni_modules/uni-datetime-picker/components/uni-datetime-picker/time-picker.vue

@@ -81,10 +81,16 @@
 </template>
 
 <script>
-	import { initVueI18n } from '@dcloudio/uni-i18n'
+	import {
+		initVueI18n
+	} from '@dcloudio/uni-i18n'
 	import i18nMessages from './i18n/index.js'
-	const {	t	} = initVueI18n(i18nMessages)
-  import { fixIosDateFormat } from './util'
+	const {
+		t
+	} = initVueI18n(i18nMessages)
+	import {
+		fixIosDateFormat
+	} from './util'
 
 	/**
 	 * DatetimePicker 时间选择器
@@ -134,6 +140,14 @@
 				endSecond: 59,
 			}
 		},
+		options: {
+			// #ifdef MP-TOUTIAO
+			virtualHost: false,
+			// #endif
+			// #ifndef MP-TOUTIAO
+			virtualHost: true
+			// #endif
+		},
 		props: {
 			type: {
 				type: String,
@@ -176,11 +190,11 @@
 			// #ifndef VUE3
 			value: {
 				handler(newVal) {
-          if (newVal) {
-            this.parseValue(fixIosDateFormat(newVal))
+					if (newVal) {
+						this.parseValue(fixIosDateFormat(newVal))
 						this.initTime(false)
 					} else {
-            this.time = ''
+						this.time = ''
 						this.parseValue(Date.now())
 					}
 				},
@@ -189,8 +203,8 @@
 			// #endif
 			// #ifdef VUE3
 			modelValue: {
-        handler(newVal) {
-          if (newVal) {
+				handler(newVal) {
+					if (newVal) {
 						this.parseValue(fixIosDateFormat(newVal))
 						this.initTime(false)
 					} else {

+ 36 - 13
src/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue

@@ -81,7 +81,7 @@
 				<view class="popup-x-body">
 					<Calendar ref="left" :showMonth="false" :start-date="calendarRange.startDate"
 						:end-date="calendarRange.endDate" :range="true" :pleStatus="endMultipleStatus" @change="leftChange"
-						@firstEnterCale="updateRightCale" style="padding: 0 8px;" />
+						@firstEnterCale="updateRightCale" style="padding: 0 8px;"/>
 					<Calendar ref="right" :showMonth="false" :start-date="calendarRange.startDate"
 						:end-date="calendarRange.endDate" :range="true" @change="rightChange" :pleStatus="startMultipleStatus"
 						@firstEnterCale="updateLeftCale" style="padding: 0 8px;border-left: 1px solid #F1F1F1;" />
@@ -98,7 +98,7 @@
 			:start-date="calendarRange.startDate" :end-date="calendarRange.endDate" :selectableTimes="mobSelectableTime"
 			:startPlaceholder="startPlaceholder" :endPlaceholder="endPlaceholder" :default-value="defaultValue"
 			:pleStatus="endMultipleStatus" :showMonth="false" :range="isRange" :hasTime="hasTime" :insert="false"
-			:hideSecond="hideSecond" @confirm="mobileChange" @maskClose="close" />
+			:hideSecond="hideSecond" @confirm="mobileChange" @maskClose="close" @change="calendarClick"/>
 	</view>
 </template>
 <script>
@@ -142,8 +142,14 @@
 
 	export default {
 		name: 'UniDatetimePicker',
+
 		options: {
+			// #ifdef MP-TOUTIAO
+			virtualHost: false,
+			// #endif
+			// #ifndef MP-TOUTIAO
 			virtualHost: true
+			// #endif
 		},
 		components: {
 			Calendar,
@@ -458,9 +464,16 @@
 					this.isPhone = navigator.userAgent.toLowerCase().indexOf('mobile') !== -1
 					return
 				}
+				// #ifdef MP-WEIXIN
+				const {
+					windowWidth
+				} = uni.getWindowInfo()
+				// #endif
+				// #ifndef MP-WEIXIN
 				const {
 					windowWidth
 				} = uni.getSystemInfoSync()
+				// #endif
 				this.isPhone = windowWidth <= 500
 				this.windowWidth = windowWidth
 			},
@@ -498,7 +511,7 @@
 								this.$refs.right.changeMonth('pre')
 							}
 						} else {
-							this.$refs.right.changeMonth('next')
+							// this.$refs.right.changeMonth('next')
 							if (this.isPhone) {
 								this.$refs.right.cale.lastHover = false;
 							}
@@ -616,6 +629,7 @@
 					fulldate: e.fulldate
 				}
 				this.startMultipleStatus = Object.assign({}, this.startMultipleStatus, obj)
+				this.$emit('calendarClick', e)
 			},
 			rightChange(e) {
 				const {
@@ -630,6 +644,7 @@
 					fulldate: e.fulldate
 				}
 				this.endMultipleStatus = Object.assign({}, this.endMultipleStatus, obj)
+				this.$emit('calendarClick', e)
 			},
 			mobileChange(e) {
 				if (this.isRange) {
@@ -658,6 +673,7 @@
 						this.displayValue = e.fulldate
 					}
 					this.setEmit(this.displayValue)
+					this.calendarDate = this.displayValue;
 				}
 				this.$refs.mobile.close()
 			},
@@ -684,17 +700,25 @@
 				let startDateLaterRangeStartDate = false
 				let startDateLaterRangeEndDate = false
 				let startDate, startTime
+
+				let compareStartDateString = this.tempRange.startDate
+				let compareEndDateString = this.tempRange.endDate
+				if (this.hasTime) {
+					compareStartDateString = `${this.tempRange.startDate} ${this.tempRange.startTime}`
+					compareEndDateString = `${this.tempRange.endDate} ${this.tempRange.endTime}`
+				}
+
 				if (this.start) {
 					let startString = this.start
 					if (typeof this.start === 'number') {
 						startString = getDateTime(this.start, this.hideSecond)
 					}
 					[startDate, startTime] = startString.split(' ')
-					if (this.start && !dateCompare(this.start, this.tempRange.startDate)) {
+					if (this.start && !dateCompare(this.start, compareStartDateString)) {
 						startDateLaterRangeStartDate = true
 						this.tempRange.startDate = startDate
 					}
-					if (this.start && !dateCompare(this.start, this.tempRange.endDate)) {
+					if (this.start && !dateCompare(this.start, compareEndDateString)) {
 						startDateLaterRangeEndDate = true
 						this.tempRange.endDate = startDate
 					}
@@ -709,11 +733,11 @@
 					}
 					[endDate, endTime] = endString.split(' ')
 
-					if (this.end && !dateCompare(this.tempRange.startDate, this.end)) {
+					if (this.end && !dateCompare(compareStartDateString, this.end)) {
 						endDateEarlierRangeStartDate = true
 						this.tempRange.startDate = endDate
 					}
-					if (this.end && !dateCompare(this.tempRange.endDate, this.end)) {
+					if (this.end && !dateCompare(compareEndDateString, this.end)) {
 						endDateEarlierRangeEndDate = true
 						this.tempRange.endDate = endDate
 					}
@@ -753,7 +777,7 @@
 			},
 			handleStartAndEnd(before, after, temp = false) {
 				if (!before) return
-				if(!after)after = before;
+				if (!after) after = before;
 				const type = temp ? 'tempRange' : 'range'
 				const isStartEarlierEnd = dateCompare(before, after)
 				this[type].startDate = isStartEarlierEnd ? before : after
@@ -817,6 +841,10 @@
 						this.$emit('update:modelValue', [])
 					}
 				}
+			},
+
+			calendarClick(e) {
+				this.$emit('calendarClick', e)
 			}
 		}
 	}
@@ -999,11 +1027,6 @@
 		border-bottom-width: 1px;
 	}
 
-	.uni-date-changed--time text {
-		height: 50px;
-		line-height: 50px;
-	}
-
 	.uni-date-changed .uni-date-changed--time {
 		flex: 1;
 	}

+ 4 - 4
src/uni_modules/uni-datetime-picker/components/uni-datetime-picker/util.js

@@ -182,8 +182,8 @@ class Calendar {
 		if (!date) {
 			date = new Date()
 		}
-
-		return this.calendar.find(item => item.fullDate === this.getDateObj(date).fullDate)
+		const res = this.calendar.find(item => item.fullDate === this.getDateObj(date).fullDate)
+		return res ? res : this.getDateObj(date)
 	}
 
 	/**
@@ -389,8 +389,8 @@ function getDefaultSecond(hideSecond) {
 }
 
 function dateCompare(startDate, endDate) {
-	startDate = new Date(fixIosDateFormat(startDate))
-	endDate = new Date(fixIosDateFormat(endDate))
+	startDate = new Date(fixIosDateFormat(typeof startDate === 'string' ? startDate.trim() : startDate))
+	endDate = new Date(fixIosDateFormat(typeof endDate === 'string' ? endDate.trim() : endDate))
 	return startDate <= endDate
 }
 

+ 60 - 40
src/uni_modules/uni-datetime-picker/package.json

@@ -1,7 +1,7 @@
 {
   "id": "uni-datetime-picker",
   "displayName": "uni-datetime-picker 日期选择器",
-  "version": "2.2.30",
+  "version": "2.2.42",
   "description": "uni-datetime-picker 日期时间选择器,支持日历,支持范围选择",
   "keywords": [
     "uni-datetime-picker",
@@ -12,12 +12,14 @@
 ],
   "repository": "https://github.com/dcloudio/uni-ui",
   "engines": {
-    "HBuilderX": ""
+    "HBuilderX": "",
+    "uni-app": "^4.07",
+    "uni-app-x": ""
   },
   "directories": {
     "example": "../../temps/example_temps"
   },
-"dcloudext": {
+  "dcloudext": {
     "sale": {
       "regular": {
         "price": "0.00"
@@ -35,53 +37,71 @@
       "permissions": "无"
     },
     "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
-    "type": "component-vue"
+    "type": "component-vue",
+    "darkmode": "x",
+    "i18n": "x",
+    "widescreen": "x"
   },
   "uni_modules": {
     "dependencies": [
-			"uni-scss",
-			"uni-icons"
-		],
+      "uni-scss",
+      "uni-icons"
+    ],
     "encrypt": [],
     "platforms": {
       "cloud": {
-        "tcb": "y",
-        "aliyun": "y"
+        "tcb": "x",
+        "aliyun": "x",
+        "alipay": "x"
       },
       "client": {
-        "App": {
-          "app-vue": "y",
-          "app-nvue": "n"
+        "uni-app": {
+          "vue": {
+            "vue2": "√",
+            "vue3": "√"
+          },
+          "web": {
+            "safari": "√",
+            "chrome": "√"
+          },
+          "app": {
+            "vue": "√",
+            "nvue": "√",
+            "android": "√",
+            "ios": "√",
+            "harmony": "√"
+          },
+          "mp": {
+            "weixin": "√",
+            "alipay": "√",
+            "toutiao": "√",
+            "baidu": "√",
+            "kuaishou": "-",
+            "jd": "-",
+            "harmony": "-",
+            "qq": "√",
+            "lark": "-"
+          },
+          "quickapp": {
+            "huawei": "√",
+            "union": "√"
+          }
         },
-        "H5-mobile": {
-          "Safari": "y",
-          "Android Browser": "y",
-          "微信浏览器(Android)": "y",
-          "QQ浏览器(Android)": "y"
-        },
-        "H5-pc": {
-          "Chrome": "y",
-          "IE": "y",
-          "Edge": "y",
-          "Firefox": "y",
-          "Safari": "y"
-        },
-        "小程序": {
-          "微信": "y",
-          "阿里": "y",
-          "百度": "y",
-          "字节跳动": "y",
-          "QQ": "y"
-        },
-        "快应用": {
-          "华为": "u",
-          "联盟": "u"
-        },
-        "Vue": {
-            "vue2": "y",
-            "vue3": "y"
+        "uni-app-x": {
+          "web": {
+            "safari": "-",
+            "chrome": "-"
+          },
+          "app": {
+            "android": "-",
+            "ios": "-",
+            "harmony": "-"
+          },
+          "mp": {
+            "weixin": "-"
+          }
         }
       }
     }
   }
-}
+}

+ 18 - 0
src/uni_modules/uni-easyinput/changelog.md

@@ -1,3 +1,21 @@
+## 1.1.22(2025-09-19)
+- 修复 禁用状态下背景不生效的问题
+## 1.1.21(2025-08-26)
+- 修复 在 @input 中修改 v-model 不生效的问题
+## 1.1.20(2025-08-19)
+- 修复 微信小程序平台样式警告问题
+## 1.1.19(2024-07-18)
+- 修复 初始值传入 null 导致input报错的bug
+## 1.1.18(2024-04-11)
+- 修复 easyinput组件双向绑定问题
+## 1.1.17(2024-03-28)
+- 修复 在头条小程序下丢失事件绑定的问题
+## 1.1.16(2024-03-20)
+- 修复 在密码输入情况下 清除和小眼睛覆盖bug 在edge浏览器下显示双眼睛bug
+## 1.1.15(2024-02-21)
+- 新增 左侧插槽:left
+## 1.1.14(2024-02-19)
+- 修复 onBlur的emit传值错误
 ## 1.1.12(2024-01-29)
 - 补充 adjust-position文档属性补充
 ## 1.1.11(2024-01-29)

+ 613 - 615
src/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue

@@ -2,75 +2,26 @@
 	<view class="uni-easyinput" :class="{ 'uni-easyinput-error': msg }" :style="boxStyle">
 		<view class="uni-easyinput__content" :class="inputContentClass" :style="inputContentStyle">
 			<uni-icons v-if="prefixIcon" class="content-clear-icon" :type="prefixIcon" color="#c0c4cc" @click="onClickIcon('prefix')" size="22"></uni-icons>
-			<textarea
-				v-if="type === 'textarea'"
-				class="uni-easyinput__content-textarea"
-				:class="{ 'input-padding': inputBorder }"
-				:name="name"
-				:value="val"
-				:placeholder="placeholder"
-				:placeholderStyle="placeholderStyle"
-				:disabled="disabled"
-				placeholder-class="uni-easyinput__placeholder-class"
-				:maxlength="inputMaxlength"
-				:focus="focused"
-				:autoHeight="autoHeight"
-				:cursor-spacing="cursorSpacing"
-				:adjust-position="adjustPosition"
-				@input="onInput"
-				@blur="_Blur"
-				@focus="_Focus"
-				@confirm="onConfirm"
-        @keyboardheightchange="onkeyboardheightchange"
-			></textarea>
-			<input
-				v-else
-				:type="type === 'password' ? 'text' : type"
-				class="uni-easyinput__content-input"
-				:style="inputStyle"
-				:name="name"
-				:value="val"
-				:password="!showPassword && type === 'password'"
-				:placeholder="placeholder"
-				:placeholderStyle="placeholderStyle"
-				placeholder-class="uni-easyinput__placeholder-class"
-				:disabled="disabled"
-				:maxlength="inputMaxlength"
-				:focus="focused"
-				:confirmType="confirmType"
-				:cursor-spacing="cursorSpacing"
-				:adjust-position="adjustPosition"
-				@focus="_Focus"
-				@blur="_Blur"
-				@input="onInput"
-				@confirm="onConfirm"
-        @keyboardheightchange="onkeyboardheightchange"
-			/>
+			<slot name="left">
+			</slot>
+			<!-- #ifdef MP-ALIPAY -->
+			<textarea :enableNative="enableNative" v-if="type === 'textarea'" class="uni-easyinput__content-textarea" :class="{ 'input-padding': inputBorder }" :name="name" :value="val" :placeholder="placeholder" :placeholderStyle="placeholderStyle" :disabled="disabled" placeholder-class="uni-easyinput__placeholder-class" :maxlength="inputMaxlength" :focus="focused" :autoHeight="autoHeight" :cursor-spacing="cursorSpacing" :adjust-position="adjustPosition" @input="onInput" @blur="_Blur" @focus="_Focus" @confirm="onConfirm" @keyboardheightchange="onkeyboardheightchange"></textarea>
+			<input :enableNative="enableNative" v-else :type="type === 'password' ? 'text' : type" class="uni-easyinput__content-input" :style="inputStyle" :name="name" :value="val" :password="!showPassword && type === 'password'" :placeholder="placeholder" :placeholderStyle="placeholderStyle" placeholder-class="uni-easyinput__placeholder-class" :disabled="disabled" :maxlength="inputMaxlength" :focus="focused" :confirmType="confirmType" :cursor-spacing="cursorSpacing" :adjust-position="adjustPosition" @focus="_Focus" @blur="_Blur" @input="onInput" @confirm="onConfirm" @keyboardheightchange="onkeyboardheightchange" />
+			<!-- #endif -->
+			<!-- #ifndef MP-ALIPAY -->
+			<textarea v-if="type === 'textarea'" class="uni-easyinput__content-textarea" :class="{ 'input-padding': inputBorder }" :name="name" :value="val" :placeholder="placeholder" :placeholderStyle="placeholderStyle" :disabled="disabled" placeholder-class="uni-easyinput__placeholder-class" :maxlength="inputMaxlength" :focus="focused" :autoHeight="autoHeight" :cursor-spacing="cursorSpacing" :adjust-position="adjustPosition" @input="onInput" @blur="_Blur" @focus="_Focus" @confirm="onConfirm" @keyboardheightchange="onkeyboardheightchange"></textarea>
+			<input v-else :type="type === 'password' ? 'text' : type" class="uni-easyinput__content-input" :style="inputStyle" :name="name" :value="val" :password="!showPassword && type === 'password'" :placeholder="placeholder" :placeholderStyle="placeholderStyle" placeholder-class="uni-easyinput__placeholder-class" :disabled="disabled" :maxlength="inputMaxlength" :focus="focused" :confirmType="confirmType" :cursor-spacing="cursorSpacing" :adjust-position="adjustPosition" @focus="_Focus" @blur="_Blur" @input="onInput" @confirm="onConfirm" @keyboardheightchange="onkeyboardheightchange" />
+			<!-- #endif -->
+
 			<template v-if="type === 'password' && passwordIcon">
 				<!-- 开启密码时显示小眼睛 -->
-				<uni-icons
-					v-if="isVal"
-					class="content-clear-icon"
-					:class="{ 'is-textarea-icon': type === 'textarea' }"
-					:type="showPassword ? 'eye-slash-filled' : 'eye-filled'"
-					:size="22"
-					:color="focusShow ? primaryColor : '#c0c4cc'"
-					@click="onEyes"
-				></uni-icons>
+				<uni-icons v-if="isVal" class="content-clear-icon" :class="{ 'is-textarea-icon': type === 'textarea' }" :type="showPassword ? 'eye-slash-filled' : 'eye-filled'" :size="22" :color="focusShow ? primaryColor : '#c0c4cc'" @click="onEyes"></uni-icons>
 			</template>
-			<template v-else-if="suffixIcon">
+			<template v-if="suffixIcon">
 				<uni-icons v-if="suffixIcon" class="content-clear-icon" :type="suffixIcon" color="#c0c4cc" @click="onClickIcon('suffix')" size="22"></uni-icons>
 			</template>
 			<template v-else>
-				<uni-icons
-					v-if="clearable && isVal && !disabled && type !== 'textarea'"
-					class="content-clear-icon"
-					:class="{ 'is-textarea-icon': type === 'textarea' }"
-					type="clear"
-					:size="clearSize"
-					:color="msg ? '#dd524d' : focusShow ? primaryColor : '#c0c4cc'"
-					@click="onClear"
-				></uni-icons>
+				<uni-icons v-if="clearable && isVal && !disabled && type !== 'textarea'" class="content-clear-icon" :class="{ 'is-textarea-icon': type === 'textarea' }" type="clear" :size="clearSize" :color="msg ? '#dd524d' : focusShow ? primaryColor : '#c0c4cc'" @click="onClear"></uni-icons>
 			</template>
 			<slot name="right"></slot>
 		</view>
@@ -78,587 +29,634 @@
 </template>
 
 <script>
-/**
- * Easyinput 输入框
- * @description 此组件可以实现表单的输入与校验,包括 "text" 和 "textarea" 类型。
- * @tutorial https://ext.dcloud.net.cn/plugin?id=3455
- * @property {String}	value	输入内容
- * @property {String }	type	输入框的类型(默认text) password/text/textarea/..
- * 	@value text			文本输入键盘
- * 	@value textarea	多行文本输入键盘
- * 	@value password	密码输入键盘
- * 	@value number		数字输入键盘,注意iOS上app-vue弹出的数字键盘并非9宫格方式
- * 	@value idcard		身份证输入键盘,信、支付宝、百度、QQ小程序
- * 	@value digit		带小数点的数字键盘	,App的nvue页面、微信、支付宝、百度、头条、QQ小程序支持
- * @property {Boolean}	clearable	是否显示右侧清空内容的图标控件,点击可清空输入框内容(默认true)
- * @property {Boolean}	autoHeight	是否自动增高输入区域,type为textarea时有效(默认true)
- * @property {String }	placeholder	输入框的提示文字
- * @property {String }	placeholderStyle	placeholder的样式(内联样式,字符串),如"color: #ddd"
- * @property {Boolean}	focus	是否自动获得焦点(默认false)
- * @property {Boolean}	disabled	是否禁用(默认false)
- * @property {Number }	maxlength	最大输入长度,设置为 -1 的时候不限制最大长度(默认140)
- * @property {String }	confirmType	设置键盘右下角按钮的文字,仅在type="text"时生效(默认done)
- * @property {Number }	clearSize	清除图标的大小,单位px(默认15)
- * @property {String}	prefixIcon	输入框头部图标
- * @property {String}	suffixIcon	输入框尾部图标
- * @property {String}	primaryColor	设置主题色(默认#2979ff)
- * @property {Boolean}	trim	是否自动去除两端的空格
- * @property {Boolean}	cursorSpacing	指定光标与键盘的距离,单位 px
- * @property {Boolean}  ajust-position 当键盘弹起时,是否上推内容,默认值:true
- * @value both	去除两端空格
- * @value left	去除左侧空格
- * @value right	去除右侧空格
- * @value start	去除左侧空格
- * @value end		去除右侧空格
- * @value all		去除全部空格
- * @value none	不去除空格
- * @property {Boolean}	inputBorder	是否显示input输入框的边框(默认true)
- * @property {Boolean}	passwordIcon	type=password时是否显示小眼睛图标
- * @property {Object}	styles	自定义颜色
- * @event {Function}	input	输入框内容发生变化时触发
- * @event {Function}	focus	输入框获得焦点时触发
- * @event {Function}	blur	输入框失去焦点时触发
- * @event {Function}	confirm	点击完成按钮时触发
- * @event {Function}	iconClick	点击图标时触发
- * @example <uni-easyinput v-model="mobile"></uni-easyinput>
- */
-function obj2strClass(obj) {
-	let classess = '';
-	for (let key in obj) {
-		const val = obj[key];
-		if (val) {
-			classess += `${key} `;
+	/**
+	 * Easyinput 输入框
+	 * @description 此组件可以实现表单的输入与校验,包括 "text" 和 "textarea" 类型。
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=3455
+	 * @property {String}	value	输入内容
+	 * @property {String }	type	输入框的类型(默认text) password/text/textarea/..
+	 * 	@value text			文本输入键盘
+	 * 	@value textarea	多行文本输入键盘
+	 * 	@value password	密码输入键盘
+	 * 	@value number		数字输入键盘,注意iOS上app-vue弹出的数字键盘并非9宫格方式
+	 * 	@value idcard		身份证输入键盘,信、支付宝、百度、QQ小程序
+	 * 	@value digit		带小数点的数字键盘	,App的nvue页面、微信、支付宝、百度、头条、QQ小程序支持
+	 * @property {Boolean}	clearable	是否显示右侧清空内容的图标控件,点击可清空输入框内容(默认true)
+	 * @property {Boolean}	autoHeight	是否自动增高输入区域,type为textarea时有效(默认true)
+	 * @property {String }	placeholder	输入框的提示文字
+	 * @property {String }	placeholderStyle	placeholder的样式(内联样式,字符串),如"color: #ddd"
+	 * @property {Boolean}	focus	是否自动获得焦点(默认false)
+	 * @property {Boolean}	disabled	是否禁用(默认false)
+	 * @property {Number }	maxlength	最大输入长度,设置为 -1 的时候不限制最大长度(默认140)
+	 * @property {String }	confirmType	设置键盘右下角按钮的文字,仅在type="text"时生效(默认done)
+	 * @property {Number }	clearSize	清除图标的大小,单位px(默认15)
+	 * @property {String}	prefixIcon	输入框头部图标
+	 * @property {String}	suffixIcon	输入框尾部图标
+	 * @property {String}	primaryColor	设置主题色(默认#2979ff)
+	 * @property {Boolean}	trim	是否自动去除两端的空格
+	 * @property {Boolean}	cursorSpacing	指定光标与键盘的距离,单位 px
+	 * @property {Boolean}  ajust-position 当键盘弹起时,是否上推内容,默认值:true
+	 * @value both	去除两端空格
+	 * @value left	去除左侧空格
+	 * @value right	去除右侧空格
+	 * @value start	去除左侧空格
+	 * @value end		去除右侧空格
+	 * @value all		去除全部空格
+	 * @value none	不去除空格
+	 * @property {Boolean}	inputBorder	是否显示input输入框的边框(默认true)
+	 * @property {Boolean}	passwordIcon	type=password时是否显示小眼睛图标
+	 * @property {Object}	styles	自定义颜色
+	 * @event {Function}	input	输入框内容发生变化时触发
+	 * @event {Function}	focus	输入框获得焦点时触发
+	 * @event {Function}	blur	输入框失去焦点时触发
+	 * @event {Function}	confirm	点击完成按钮时触发
+	 * @event {Function}	iconClick	点击图标时触发
+	 * @example <uni-easyinput v-model="mobile"></uni-easyinput>
+	 */
+	function obj2strClass(obj) {
+		let classess = '';
+		for (let key in obj) {
+			const val = obj[key];
+			if (val) {
+				classess += `${key} `;
+			}
 		}
+		return classess;
 	}
-	return classess;
-}
-
-function obj2strStyle(obj) {
-	let style = '';
-	for (let key in obj) {
-		const val = obj[key];
-		style += `${key}:${val};`;
-	}
-	return style;
-}
-export default {
-	name: 'uni-easyinput',
-	emits: ['click', 'iconClick', 'update:modelValue', 'input', 'focus', 'blur', 'confirm', 'clear', 'eyes', 'change', 'keyboardheightchange'],
-	model: {
-		prop: 'modelValue',
-		event: 'update:modelValue'
-	},
-	options: {
-		virtualHost: true
-	},
-	inject: {
-		form: {
-			from: 'uniForm',
-			default: null
-		},
-		formItem: {
-			from: 'uniFormItem',
-			default: null
+
+	function obj2strStyle(obj) {
+		let style = '';
+		for (let key in obj) {
+			const val = obj[key];
+			style += `${key}:${val};`;
 		}
-	},
-	props: {
-		name: String,
-		value: [Number, String],
-		modelValue: [Number, String],
-		type: {
-			type: String,
-			default: 'text'
-		},
-		clearable: {
-			type: Boolean,
-			default: true
-		},
-		autoHeight: {
-			type: Boolean,
-			default: false
-		},
-		placeholder: {
-			type: String,
-			default: ' '
-		},
-		placeholderStyle: String,
-		focus: {
-			type: Boolean,
-			default: false
-		},
-		disabled: {
-			type: Boolean,
-			default: false
-		},
-		maxlength: {
-			type: [Number, String],
-			default: 140
-		},
-		confirmType: {
-			type: String,
-			default: 'done'
-		},
-		clearSize: {
-			type: [Number, String],
-			default: 24
-		},
-		inputBorder: {
-			type: Boolean,
-			default: true
-		},
-		prefixIcon: {
-			type: String,
-			default: ''
-		},
-		suffixIcon: {
-			type: String,
-			default: ''
-		},
-		trim: {
-			type: [Boolean, String],
-			default: false
-		},
-		cursorSpacing: {
-			type: Number,
-			default: 0
-		},
-		passwordIcon: {
-			type: Boolean,
-			default: true
-		},
-		adjustPosition:{
-			type: Boolean,
-			default: true
-		},
-		primaryColor: {
-			type: String,
-			default: '#2979ff'
-		},
-		styles: {
-			type: Object,
-			default() {
-				return {
-					color: '#333',
-					backgroundColor: '#fff',
-					disableColor: '#F7F6F6',
-					borderColor: '#e5e5e5'
-				};
+		return style;
+	}
+	export default {
+		name: 'uni-easyinput',
+		emits: [
+			'click',
+			'iconClick',
+			'update:modelValue',
+			'input',
+			'focus',
+			'blur',
+			'confirm',
+			'clear',
+			'eyes',
+			'change',
+			'keyboardheightchange'
+		],
+		model: {
+			prop: 'modelValue',
+			event: 'update:modelValue'
+		},
+		options: {
+			// #ifdef MP-TOUTIAO
+			virtualHost: false,
+			// #endif
+			// #ifndef MP-TOUTIAO
+			virtualHost: true
+			// #endif
+		},
+		inject: {
+			form: {
+				from: 'uniForm',
+				default: null
+			},
+			formItem: {
+				from: 'uniFormItem',
+				default: null
 			}
 		},
-		errorMessage: {
-			type: [String, Boolean],
-			default: ''
-		}
-	},
-	data() {
-		return {
-			focused: false,
-			val: '',
-			showMsg: '',
-			border: false,
-			isFirstBorder: false,
-			showClearIcon: false,
-			showPassword: false,
-			focusShow: false,
-			localMsg: '',
-			isEnter: false // 用于判断当前是否是使用回车操作
-		};
-	},
-	computed: {
-		// 输入框内是否有值
-		isVal() {
-			const val = this.val;
-			// fixed by mehaotian 处理值为0的情况,字符串0不在处理范围
-			if (val || val === 0) {
-				return true;
+		props: {
+			name: String,
+			value: [Number, String],
+			modelValue: [Number, String],
+			type: {
+				type: String,
+				default: 'text'
+			},
+			clearable: {
+				type: Boolean,
+				default: true
+			},
+			autoHeight: {
+				type: Boolean,
+				default: false
+			},
+			placeholder: {
+				type: String,
+				default: ' '
+			},
+			placeholderStyle: String,
+			focus: {
+				type: Boolean,
+				default: false
+			},
+			disabled: {
+				type: Boolean,
+				default: false
+			},
+			maxlength: {
+				type: [Number, String],
+				default: 140
+			},
+			confirmType: {
+				type: String,
+				default: 'done'
+			},
+			clearSize: {
+				type: [Number, String],
+				default: 24
+			},
+			inputBorder: {
+				type: Boolean,
+				default: true
+			},
+			prefixIcon: {
+				type: String,
+				default: ''
+			},
+			suffixIcon: {
+				type: String,
+				default: ''
+			},
+			trim: {
+				type: [Boolean, String],
+				default: false
+			},
+			cursorSpacing: {
+				type: Number,
+				default: 0
+			},
+			passwordIcon: {
+				type: Boolean,
+				default: true
+			},
+			adjustPosition: {
+				type: Boolean,
+				default: true
+			},
+			primaryColor: {
+				type: String,
+				default: '#2979ff'
+			},
+			styles: {
+				type: Object,
+				default () {
+					return {
+						color: '#333',
+						backgroundColor: '#fff',
+						disableColor: '#F7F6F6',
+						borderColor: '#e5e5e5'
+					};
+				}
+			},
+			errorMessage: {
+				type: [String, Boolean],
+				default: ''
+			},
+			// #ifdef MP-ALIPAY
+			enableNative: {
+				type: Boolean,
+				default: false
+			}
+			// #endif
+		},
+		data() {
+			return {
+				focused: false,
+				val: '',
+				showMsg: '',
+				border: false,
+				isFirstBorder: false,
+				showClearIcon: false,
+				showPassword: false,
+				focusShow: false,
+				localMsg: '',
+				isEnter: false // 用于判断当前是否是使用回车操作
+			};
+		},
+		computed: {
+			// 输入框内是否有值
+			isVal() {
+				const val = this.val;
+				// fixed by mehaotian 处理值为0的情况,字符串0不在处理范围
+				if (val || val === 0) {
+					return true;
+				}
+				return false;
+			},
+
+			msg() {
+				// console.log('computed', this.form, this.formItem);
+				// if (this.form) {
+				// 	return this.errorMessage || this.formItem.errMsg;
+				// }
+				// TODO 处理头条 formItem 中 errMsg 不更新的问题
+				return this.localMsg || this.errorMessage;
+			},
+			// 因为uniapp的input组件的maxlength组件必须要数值,这里转为数值,用户可以传入字符串数值
+			inputMaxlength() {
+				return Number(this.maxlength);
+			},
+
+			// 处理外层样式的style
+			boxStyle() {
+				return `color:${
+					this.inputBorder && this.msg ? '#e43d33' : this.styles.color
+				};`;
+			},
+			// input 内容的类和样式处理
+			inputContentClass() {
+				return obj2strClass({
+					'is-input-border': this.inputBorder,
+					'is-input-error-border': this.inputBorder && this.msg,
+					'is-textarea': this.type === 'textarea',
+					'is-disabled': this.disabled,
+					'is-focused': this.focusShow
+				});
+			},
+			inputContentStyle() {
+				const focusColor = this.focusShow ?
+					this.primaryColor :
+					this.styles.borderColor;
+				const borderColor =
+					this.inputBorder && this.msg ? '#dd524d' : focusColor;
+				return obj2strStyle({
+					'border-color': borderColor || '#e5e5e5',
+					'background-color': this.disabled ?
+						this.styles.disableColor : this.styles.backgroundColor
+				});
+			},
+			// input右侧样式
+			inputStyle() {
+				const paddingRight =
+					this.type === 'password' || this.clearable || this.prefixIcon ?
+					'' :
+					'10px';
+				return obj2strStyle({
+					'padding-right': paddingRight,
+					'padding-left': this.prefixIcon ? '' : '10px'
+				});
 			}
-			return false;
-		},
-
-		msg() {
-			// console.log('computed', this.form, this.formItem);
-			// if (this.form) {
-			// 	return this.errorMessage || this.formItem.errMsg;
-			// }
-			// TODO 处理头条 formItem 中 errMsg 不更新的问题
-			return this.localMsg || this.errorMessage;
-		},
-		// 因为uniapp的input组件的maxlength组件必须要数值,这里转为数值,用户可以传入字符串数值
-		inputMaxlength() {
-			return Number(this.maxlength);
-		},
-
-		// 处理外层样式的style
-		boxStyle() {
-			return `color:${this.inputBorder && this.msg ? '#e43d33' : this.styles.color};`;
-		},
-		// input 内容的类和样式处理
-		inputContentClass() {
-			return obj2strClass({
-				'is-input-border': this.inputBorder,
-				'is-input-error-border': this.inputBorder && this.msg,
-				'is-textarea': this.type === 'textarea',
-				'is-disabled': this.disabled,
-				'is-focused': this.focusShow
-			});
-		},
-		inputContentStyle() {
-			const focusColor = this.focusShow ? this.primaryColor : this.styles.borderColor;
-			const borderColor = this.inputBorder && this.msg ? '#dd524d' : focusColor;
-			return obj2strStyle({
-				'border-color': borderColor || '#e5e5e5',
-				'background-color': this.disabled ? this.styles.disableColor : this.styles.backgroundColor
-			});
 		},
-		// input右侧样式
-		inputStyle() {
-			const paddingRight = this.type === 'password' || this.clearable || this.prefixIcon ? '' : '10px';
-			return obj2strStyle({
-				'padding-right': paddingRight,
-				'padding-left': this.prefixIcon ? '' : '10px'
-			});
-		}
-	},
-	watch: {
-		value(newVal) {
-			this.val = newVal;
+		watch: {
+			value(newVal) {
+				// fix by mehaotian 解决 值为null的情况下,input报错的bug
+				if (newVal === null) {
+					this.val = '';
+					return
+				}
+				this.val = newVal;
+			},
+			modelValue(newVal) {
+				if (newVal === null) {
+					this.val = '';
+					return
+				}
+				this.val = newVal;
+			},
+			focus(newVal) {
+				this.$nextTick(() => {
+					this.focused = this.focus;
+					this.focusShow = this.focus;
+				});
+			}
 		},
-		modelValue(newVal) {
-			this.val = newVal;
+		created() {
+			this.init();
+			// TODO 处理头条vue3 computed 不监听 inject 更改的问题(formItem.errMsg)
+			if (this.form && this.formItem) {
+				this.$watch('formItem.errMsg', newVal => {
+					this.localMsg = newVal;
+				});
+			}
 		},
-		focus(newVal) {
+		mounted() {
 			this.$nextTick(() => {
 				this.focused = this.focus;
 				this.focusShow = this.focus;
 			});
-		}
-	},
-	created() {
-		this.init();
-		// TODO 处理头条vue3 computed 不监听 inject 更改的问题(formItem.errMsg)
-		if (this.form && this.formItem) {
-			this.$watch('formItem.errMsg', newVal => {
-				this.localMsg = newVal;
-			});
-		}
-	},
-	mounted() {
-		this.$nextTick(() => {
-			this.focused = this.focus;
-			this.focusShow = this.focus;
-		});
-	},
-	methods: {
-		/**
-		 * 初始化变量值
-		 */
-		init() {
-			if (this.value || this.value === 0) {
-				this.val = this.value;
-			} else if (this.modelValue || this.modelValue === 0 || this.modelValue === '') {
-				this.val = this.modelValue;
-			} else {
-				this.val = null;
-			}
-		},
-
-		/**
-		 * 点击图标时触发
-		 * @param {Object} type
-		 */
-		onClickIcon(type) {
-			this.$emit('iconClick', type);
-		},
-
-		/**
-		 * 显示隐藏内容,密码框时生效
-		 */
-		onEyes() {
-			this.showPassword = !this.showPassword;
-			this.$emit('eyes', this.showPassword);
 		},
-
-		/**
-		 * 输入时触发
-		 * @param {Object} event
-		 */
-		onInput(event) {
-			let value = event.detail.value;
-			// 判断是否去除空格
-			if (this.trim) {
-				if (typeof this.trim === 'boolean' && this.trim) {
-					value = this.trimStr(value);
+		methods: {
+			/**
+			 * 初始化变量值
+			 */
+			init() {
+				if (this.value || this.value === 0) {
+					this.val = this.value;
+				} else if (
+					this.modelValue ||
+					this.modelValue === 0 ||
+					this.modelValue === ''
+				) {
+					this.val = this.modelValue;
+				} else {
+					// fix by ht 如果初始值为null,则input报错,待框架修复
+					this.val = '';
+				}
+			},
+
+			/**
+			 * 点击图标时触发
+			 * @param {Object} type
+			 */
+			onClickIcon(type) {
+				this.$emit('iconClick', type);
+			},
+
+			/**
+			 * 显示隐藏内容,密码框时生效
+			 */
+			onEyes() {
+				this.showPassword = !this.showPassword;
+				this.$emit('eyes', this.showPassword);
+			},
+
+			/**
+			 * 输入时触发
+			 * @param {Object} event
+			 */
+			onInput(event) {
+				let value = event.detail.value;
+				// 判断是否去除空格
+				if (this.trim) {
+					if (typeof this.trim === 'boolean' && this.trim) {
+						value = this.trimStr(value);
+					}
+					if (typeof this.trim === 'string') {
+						value = this.trimStr(value, this.trim);
+					}
+				}
+				if (this.errMsg) this.errMsg = '';
+				this.val = value;
+				// TODO 兼容 vue3
+				this.$emit('update:modelValue', value);
+
+				// fix by ht input 修改一定要放在 update:modelvalue 后面,避免在input中修改值,导致 v-model 不生效
+				// TODO 兼容 vue2
+				this.$emit('input', value);
+			},
+
+			/**
+			 * 外部调用方法
+			 * 获取焦点时触发
+			 * @param {Object} event
+			 */
+			onFocus() {
+				this.$nextTick(() => {
+					this.focused = true;
+				});
+				this.$emit('focus', null);
+			},
+
+			_Focus(event) {
+				this.focusShow = true;
+				this.$emit('focus', event);
+			},
+
+			/**
+			 * 外部调用方法
+			 * 失去焦点时触发
+			 * @param {Object} event
+			 */
+			onBlur() {
+				this.focused = false;
+				this.$emit('blur', null);
+			},
+			_Blur(event) {
+				let value = event.detail.value;
+				this.focusShow = false;
+				this.$emit('blur', event);
+				// 根据类型返回值,在event中获取的值理论上讲都是string
+				if (this.isEnter === false) {
+					this.$emit('change', this.val);
 				}
-				if (typeof this.trim === 'string') {
-					value = this.trimStr(value, this.trim);
+				// 失去焦点时参与表单校验
+				if (this.form && this.formItem) {
+					const { validateTrigger } = this.form;
+					if (validateTrigger === 'blur') {
+						this.formItem.onFieldChange();
+					}
 				}
+			},
+
+			/**
+			 * 按下键盘的发送键
+			 * @param {Object} e
+			 */
+			onConfirm(e) {
+				this.$emit('confirm', this.val);
+				this.isEnter = true;
+				this.$emit('change', this.val);
+				this.$nextTick(() => {
+					this.isEnter = false;
+				});
+			},
+
+			/**
+			 * 清理内容
+			 * @param {Object} event
+			 */
+			onClear(event) {
+				this.val = '';
+				// TODO 兼容 vue2
+				this.$emit('input', '');
+				// TODO 兼容 vue2
+				// TODO 兼容 vue3
+				this.$emit('update:modelValue', '');
+				// 点击叉号触发
+				this.$emit('clear');
+			},
+
+			/**
+			 * 键盘高度发生变化的时候触发此事件
+			 * 兼容性:微信小程序2.7.0+、App 3.1.0+
+			 * @param {Object} event
+			 */
+			onkeyboardheightchange(event) {
+				this.$emit('keyboardheightchange', event);
+			},
+
+			/**
+			 * 去除空格
+			 */
+			trimStr(str, pos = 'both') {
+				if (pos === 'both') {
+					return str.trim();
+				} else if (pos === 'left') {
+					return str.trimLeft();
+				} else if (pos === 'right') {
+					return str.trimRight();
+				} else if (pos === 'start') {
+					return str.trimStart();
+				} else if (pos === 'end') {
+					return str.trimEnd();
+				} else if (pos === 'all') {
+					return str.replace(/\s+/g, '');
+				} else if (pos === 'none') {
+					return str;
+				}
+				return str;
 			}
-			if (this.errMsg) this.errMsg = '';
-			this.val = value;
-			// TODO 兼容 vue2
-			this.$emit('input', value);
-			// TODO 兼容 vue3
-			this.$emit('update:modelValue', value);
-		},
+		}
+	};
+</script>
 
-		/**
-		 * 外部调用方法
-		 * 获取焦点时触发
-		 * @param {Object} event
-		 */
-		onFocus() {
-			this.$nextTick(() => {
-				this.focused = true;
-			});
-			this.$emit('focus', null);
-		},
+<style lang="scss">
+	$uni-error: #e43d33;
+	$uni-border-1: #dcdfe6 !default;
+
+	.uni-easyinput {
+		/* #ifndef APP-NVUE */
+		width: 100%;
+		/* #endif */
+		flex: 1;
+		position: relative;
+		text-align: left;
+		color: #333;
+		font-size: 14px;
+	}
 
-		_Focus(event) {
-			this.focusShow = true;
-			this.$emit('focus', event);
-		},
+	.uni-easyinput__content {
+		flex: 1;
+		/* #ifndef APP-NVUE */
+		width: 100%;
+		display: flex;
+		box-sizing: border-box;
+		// min-height: 36px;
+		/* #endif */
+		flex-direction: row;
+		align-items: center;
+		// 处理border动画刚开始显示黑色的问题
+		border-color: #fff;
+		transition-property: border-color;
+		transition-duration: 0.3s;
+	}
 
-		/**
-		 * 外部调用方法
-		 * 失去焦点时触发
-		 * @param {Object} event
-		 */
-		onBlur() {
-			this.focused = false;
-			this.$emit('focus', null);
-		},
-		_Blur(event) {
-			let value = event.detail.value;
-			this.focusShow = false;
-			this.$emit('blur', event);
-			// 根据类型返回值,在event中获取的值理论上讲都是string
-			if (this.isEnter === false) {
-				this.$emit('change', this.val);
-			}
-			// 失去焦点时参与表单校验
-			if (this.form && this.formItem) {
-				const { validateTrigger } = this.form;
-				if (validateTrigger === 'blur') {
-					this.formItem.onFieldChange();
-				}
-			}
-		},
+	.uni-easyinput__content-input {
+		/* #ifndef APP-NVUE */
+		width: auto;
+		/* #endif */
+		position: relative;
+		overflow: hidden;
+		flex: 1;
+		line-height: 1;
+		font-size: 14px;
+		height: 35px;
+	}
 
-		/**
-		 * 按下键盘的发送键
-		 * @param {Object} e
-		 */
-		onConfirm(e) {
-			this.$emit('confirm', this.val);
-			this.isEnter = true;
-			this.$emit('change', this.val);
-			this.$nextTick(() => {
-				this.isEnter = false;
-			});
-		},
+	.uni-easyinput__placeholder-class {
+		color: #999;
+		font-size: 12px;
+		// font-weight: 200;
+	}
 
-		/**
-		 * 清理内容
-		 * @param {Object} event
-		 */
-		onClear(event) {
-			this.val = '';
-			// TODO 兼容 vue2
-			this.$emit('input', '');
-			// TODO 兼容 vue2
-			// TODO 兼容 vue3
-			this.$emit('update:modelValue', '');
-			// 点击叉号触发
-			this.$emit('clear');
-		},
+	.is-textarea {
+		align-items: flex-start;
+	}
 
-    /**
-     * 键盘高度发生变化的时候触发此事件
-     * 兼容性:微信小程序2.7.0+、App 3.1.0+
-     * @param {Object} event
-     */
-    onkeyboardheightchange(event) {
-      this.$emit("keyboardheightchange",event);
-    },
-
-		/**
-		 * 去除空格
-		 */
-		trimStr(str, pos = 'both') {
-			if (pos === 'both') {
-				return str.trim();
-			} else if (pos === 'left') {
-				return str.trimLeft();
-			} else if (pos === 'right') {
-				return str.trimRight();
-			} else if (pos === 'start') {
-				return str.trimStart();
-			} else if (pos === 'end') {
-				return str.trimEnd();
-			} else if (pos === 'all') {
-				return str.replace(/\s+/g, '');
-			} else if (pos === 'none') {
-				return str;
-			}
-			return str;
+	.is-textarea-icon {
+		margin-top: 5px;
+	}
+
+	.uni-easyinput__content-textarea {
+		position: relative;
+		overflow: hidden;
+		flex: 1;
+		line-height: 1.5;
+		font-size: 14px;
+		margin: 6px;
+		margin-left: 0;
+		height: 80px;
+		min-height: 80px;
+		/* #ifndef APP-NVUE */
+		min-height: 80px;
+		width: auto;
+		/* #endif */
+	}
+
+	.input-padding {
+		padding-left: 10px;
+	}
+
+	.content-clear-icon {
+		padding: 0 5px;
+	}
+
+	.label-icon {
+		margin-right: 5px;
+		margin-top: -1px;
+	}
+
+	// 显示边框
+	.is-input-border {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		box-sizing: border-box;
+		/* #endif */
+		flex-direction: row;
+		align-items: center;
+		border: 1px solid $uni-border-1;
+		border-radius: 4px;
+		/* #ifdef MP-ALIPAY */
+		overflow: hidden;
+		/* #endif */
+	}
+
+	.uni-error-message {
+		position: absolute;
+		bottom: -17px;
+		left: 0;
+		line-height: 12px;
+		color: $uni-error;
+		font-size: 12px;
+		text-align: left;
+	}
+
+	.uni-error-msg--boeder {
+		position: relative;
+		bottom: 0;
+		line-height: 22px;
+	}
+
+	.is-input-error-border {
+		border-color: $uni-error;
+
+		.uni-easyinput__placeholder-class {
+			color: mix(#fff, $uni-error, 50%);
 		}
 	}
-};
-</script>
 
-<style lang="scss">
-$uni-error: #e43d33;
-$uni-border-1: #dcdfe6 !default;
-
-.uni-easyinput {
-	/* #ifndef APP-NVUE */
-	width: 100%;
-	/* #endif */
-	flex: 1;
-	position: relative;
-	text-align: left;
-	color: #333;
-	font-size: 14px;
-}
-
-.uni-easyinput__content {
-	flex: 1;
-	/* #ifndef APP-NVUE */
-	width: 100%;
-	display: flex;
-	box-sizing: border-box;
-	// min-height: 36px;
-	/* #endif */
-	flex-direction: row;
-	align-items: center;
-	// 处理border动画刚开始显示黑色的问题
-	border-color: #fff;
-	transition-property: border-color;
-	transition-duration: 0.3s;
-}
-
-.uni-easyinput__content-input {
-	/* #ifndef APP-NVUE */
-	width: auto;
-	/* #endif */
-	position: relative;
-	overflow: hidden;
-	flex: 1;
-	line-height: 1;
-	font-size: 14px;
-	height: 35px;
-	// min-height: 36px;
-}
-
-.uni-easyinput__placeholder-class {
-	color: #999;
-	font-size: 12px;
-	// font-weight: 200;
-}
-
-.is-textarea {
-	align-items: flex-start;
-}
-
-.is-textarea-icon {
-	margin-top: 5px;
-}
-
-.uni-easyinput__content-textarea {
-	position: relative;
-	overflow: hidden;
-	flex: 1;
-	line-height: 1.5;
-	font-size: 14px;
-	margin: 6px;
-	margin-left: 0;
-	height: 80px;
-	min-height: 80px;
-	/* #ifndef APP-NVUE */
-	min-height: 80px;
-	width: auto;
-	/* #endif */
-}
-
-.input-padding {
-	padding-left: 10px;
-}
-
-.content-clear-icon {
-	padding: 0 5px;
-}
-
-.label-icon {
-	margin-right: 5px;
-	margin-top: -1px;
-}
-
-// 显示边框
-.is-input-border {
-	/* #ifndef APP-NVUE */
-	display: flex;
-	box-sizing: border-box;
-	/* #endif */
-	flex-direction: row;
-	align-items: center;
-	border: 1px solid $uni-border-1;
-	border-radius: 4px;
-	/* #ifdef MP-ALIPAY */
-	overflow: hidden;
-	/* #endif */
-}
-
-.uni-error-message {
-	position: absolute;
-	bottom: -17px;
-	left: 0;
-	line-height: 12px;
-	color: $uni-error;
-	font-size: 12px;
-	text-align: left;
-}
-
-.uni-error-msg--boeder {
-	position: relative;
-	bottom: 0;
-	line-height: 22px;
-}
-
-.is-input-error-border {
-	border-color: $uni-error;
+	.uni-easyinput--border {
+		margin-bottom: 0;
+		padding: 10px 15px;
+		// padding-bottom: 0;
+		border-top: 1px #eee solid;
+	}
 
-	.uni-easyinput__placeholder-class {
-		color: mix(#fff, $uni-error, 50%);
+	.uni-easyinput-error {
+		padding-bottom: 0;
 	}
-}
-
-.uni-easyinput--border {
-	margin-bottom: 0;
-	padding: 10px 15px;
-	// padding-bottom: 0;
-	border-top: 1px #eee solid;
-}
-
-.uni-easyinput-error {
-	padding-bottom: 0;
-}
-
-.is-first-border {
-	/* #ifndef APP-NVUE */
-	border: none;
-	/* #endif */
-	/* #ifdef APP-NVUE */
-	border-width: 0;
-	/* #endif */
-}
-
-.is-disabled {
-	background-color: #f7f6f6;
-	color: #d5d5d5;
 
-	.uni-easyinput__placeholder-class {
+	.is-first-border {
+		/* #ifndef APP-NVUE */
+		border: none;
+		/* #endif */
+		/* #ifdef APP-NVUE */
+		border-width: 0;
+		/* #endif */
+	}
+
+	.is-disabled {
+		background-color: #f7f6f6;
 		color: #d5d5d5;
-		font-size: 12px;
+
+		.uni-easyinput__placeholder-class {
+			color: #d5d5d5;
+			font-size: 12px;
+		}
 	}
-}
 </style>

+ 57 - 37
src/uni_modules/uni-easyinput/package.json

@@ -1,7 +1,7 @@
 {
   "id": "uni-easyinput",
   "displayName": "uni-easyinput 增强输入框",
-  "version": "1.1.12",
+  "version": "1.1.22",
   "description": "Easyinput 组件是对原生input组件的增强",
   "keywords": [
     "uni-ui",
@@ -12,12 +12,14 @@
 ],
   "repository": "https://github.com/dcloudio/uni-ui",
   "engines": {
-    "HBuilderX": ""
+    "HBuilderX": "",
+    "uni-app": "^4.07",
+    "uni-app-x": ""
   },
   "directories": {
     "example": "../../temps/example_temps"
   },
-"dcloudext": {
+  "dcloudext": {
     "sale": {
       "regular": {
         "price": "0.00"
@@ -35,51 +37,69 @@
       "permissions": "无"
     },
     "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
-    "type": "component-vue"
+    "type": "component-vue",
+    "darkmode": "x",
+    "i18n": "x",
+    "widescreen": "x"
   },
   "uni_modules": {
     "dependencies": [
-			"uni-scss",
+      "uni-scss",
       "uni-icons"
     ],
     "encrypt": [],
     "platforms": {
       "cloud": {
-        "tcb": "y",
-        "aliyun": "y"
+        "tcb": "x",
+        "aliyun": "x",
+        "alipay": "x"
       },
       "client": {
-        "App": {
-          "app-vue": "y",
-          "app-nvue": "y"
+        "uni-app": {
+          "vue": {
+            "vue2": "√",
+            "vue3": "√"
+          },
+          "web": {
+            "safari": "√",
+            "chrome": "√"
+          },
+          "app": {
+            "vue": "√",
+            "nvue": "-",
+            "android": "√",
+            "ios": "√",
+            "harmony": "√"
+          },
+          "mp": {
+            "weixin": "√",
+            "alipay": "√",
+            "toutiao": "√",
+            "baidu": "√",
+            "kuaishou": "√",
+            "jd": "√",
+            "harmony": "√",
+            "qq": "√",
+            "lark": "-"
+          },
+          "quickapp": {
+            "huawei": "-",
+            "union": "-"
+          }
         },
-        "H5-mobile": {
-          "Safari": "y",
-          "Android Browser": "y",
-          "微信浏览器(Android)": "y",
-          "QQ浏览器(Android)": "y"
-        },
-        "H5-pc": {
-          "Chrome": "y",
-          "IE": "y",
-          "Edge": "y",
-          "Firefox": "y",
-          "Safari": "y"
-        },
-        "小程序": {
-          "微信": "y",
-          "阿里": "y",
-          "百度": "y",
-          "字节跳动": "y",
-          "QQ": "y"
-        },
-        "快应用": {
-          "华为": "u",
-          "联盟": "u"
-        },
-        "Vue": {
-            "vue2": "y",
-            "vue3": "y"
+        "uni-app-x": {
+          "web": {
+            "safari": "-",
+            "chrome": "-"
+          },
+          "app": {
+            "android": "-",
+            "ios": "-",
+            "harmony": "-"
+          },
+          "mp": {
+            "weixin": "-"
+          }
         }
       }
     }

+ 2 - 0
src/uni_modules/uni-fab/changelog.md

@@ -1,3 +1,5 @@
+## 1.2.6(2024-10-12)
+- 修复 微信小程序中的getSystemInfo警告
 ## 1.2.5(2023-03-29)
 - 新增 pattern.icon 属性,可自定义图标
 ## 1.2.4(2022-09-07)

+ 1 - 1
src/uni_modules/uni-fab/components/uni-fab/uni-fab.vue

@@ -164,8 +164,8 @@
 			},
 			// 计算 nvue bottom
 			nvueBottom() {
-				const safeBottom = uni.getSystemInfoSync().windowBottom;
 				// #ifdef APP-NVUE
+				const safeBottom = uni.getSystemInfoSync().windowBottom;
 				return 30 + safeBottom
 				// #endif
 				// #ifndef APP-NVUE

+ 3 - 2
src/uni_modules/uni-fab/package.json

@@ -1,7 +1,7 @@
 {
   "id": "uni-fab",
   "displayName": "uni-fab 悬浮按钮",
-  "version": "1.2.5",
+  "version": "1.2.6",
   "description": "悬浮按钮 fab button ,点击可展开一个图标按钮菜单。",
   "keywords": [
     "uni-ui",
@@ -43,7 +43,8 @@
     "platforms": {
       "cloud": {
         "tcb": "y",
-        "aliyun": "y"
+        "aliyun": "y",
+        "alipay": "n"
       },
       "client": {
         "App": {

+ 20 - 0
src/uni_modules/uni-file-picker/changelog.md

@@ -1,3 +1,23 @@
+## 1.1.3(2025-12-03)
+- 修复: 腾讯云目录错误导致的上传错误问题
+## 1.1.2(2025-09-17)
+- 修复 设置readonly属性后内容插槽失效的问题。
+## 1.1.1(2025-09-03)
+- 修复 动态dir目录,不生效的问题
+## 1.1.0(2025-09-02)
+- 新增 dir 属性,可以选择上传目录
+## 1.0.13(2025-08-18)
+- 修复 删除文件后,返回信息不包含file对象的问题
+## 1.0.12(2025-04-14)
+- 修复 支付宝小程序 上传样式问题
+## 1.0.10(2024-07-09)
+- 优化 vue3兼容性
+## 1.0.9(2024-07-09)
+- 修复 value 属性不兼容vue3的bug
+## 1.0.8(2024-03-20)
+- 补充 删除文件时返回文件下标
+## 1.0.7(2024-02-21)
+- 新增 微信小程序选择视频时改用chooseMedia,并返回视频缩略图
 ## 1.0.6(2024-01-06)
 - 新增 微信小程序不再调用chooseImage,而是调用chooseMedia
 ## 1.0.5(2024-01-03)

+ 44 - 4
src/uni_modules/uni-file-picker/components/uni-file-picker/choose-and-upload-file.js

@@ -11,6 +11,7 @@ function chooseImage(opts) {
 		extension
 	} = opts
 	return new Promise((resolve, reject) => {
+		// 微信由于旧接口不再维护,针对微信小程序平台改用chooseMedia接口
 		// #ifdef MP-WEIXIN
 		uni.chooseMedia({
 			count,
@@ -53,6 +54,7 @@ function chooseImage(opts) {
 
 function chooseVideo(opts) {
 	const {
+		count,
 		camera,
 		compressed,
 		maxDuration,
@@ -60,6 +62,45 @@ function chooseVideo(opts) {
 		extension
 	} = opts;
 	return new Promise((resolve, reject) => {
+		// 微信由于旧接口不再维护,针对微信小程序平台改用chooseMedia接口
+		// #ifdef MP-WEIXIN
+		uni.chooseMedia({
+			count,
+			compressed,
+			maxDuration,
+			sourceType,
+			extension,
+			mediaType: ['video'],
+			success(res) {
+				const {
+					tempFiles,
+				} = res;
+				resolve(normalizeChooseAndUploadFileRes({
+					errMsg: 'chooseVideo:ok',
+					tempFiles: tempFiles.map(item => {
+						return {
+							name: item.name || '',
+							path: item.tempFilePath,
+							thumbTempFilePath: item.thumbTempFilePath,
+							size:item.size,
+							type: (res.tempFile && res.tempFile.type) || '',
+							width:item.width,
+							height:item.height,
+							duration:item.duration,
+							fileType: 'video',
+							cloudPath: '',
+						}
+					}),
+				}, 'video'));
+			},
+			fail(res) {
+				reject({
+					errMsg: res.errMsg.replace('chooseVideo:fail', ERR_MSG_FAIL),
+				});
+			},
+		})
+		// #endif
+		// #ifndef MP-WEIXIN
 		uni.chooseVideo({
 			camera,
 			compressed,
@@ -77,8 +118,7 @@ function chooseVideo(opts) {
 				resolve(normalizeChooseAndUploadFileRes({
 					errMsg: 'chooseVideo:ok',
 					tempFilePaths: [tempFilePath],
-					tempFiles: [
-					{
+					tempFiles: [{
 						name: (res.tempFile && res.tempFile.name) || '',
 						path: tempFilePath,
 						size,
@@ -97,6 +137,7 @@ function chooseVideo(opts) {
 				});
 			},
 		});
+		// #endif
 	});
 }
 
@@ -234,8 +275,7 @@ function chooseAndUploadFile(opts = {
 }) {
 	if (opts.type === 'image') {
 		return uploadFiles(chooseImage(opts), opts);
-	}
-	else if (opts.type === 'video') {
+	} else if (opts.type === 'video') {
 		return uploadFiles(chooseVideo(opts), opts);
 	}
 	return uploadFiles(chooseAll(opts), opts);

+ 50 - 47
src/uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue

@@ -4,19 +4,13 @@
 			<text class="file-title">{{ title }}</text>
 			<text class="file-count">{{ filesList.length }}/{{ limitLength }}</text>
 		</view>
-		<upload-image v-if="fileMediatype === 'image' && showType === 'grid'" :readonly="readonly"
-			:image-styles="imageStyles" :files-list="filesList" :limit="limitLength" :disablePreview="disablePreview"
-			:delIcon="delIcon" @uploadFiles="uploadFiles" @choose="choose" @delFile="delFile">
+		<upload-image v-if="fileMediatype === 'image' && showType === 'grid'" :readonly="readonly" :image-styles="imageStyles" :files-list="filesList" :limit="limitLength" :disablePreview="disablePreview" :delIcon="delIcon" @uploadFiles="uploadFiles" @choose="choose" @delFile="delFile">
 			<slot>
-				<view class="is-add">
-					<view class="icon-add"></view>
-					<view class="icon-add rotate"></view>
-				</view>
+				<view class="icon-add"></view>
+				<view class="icon-add rotate"></view>
 			</slot>
 		</upload-image>
-		<upload-file v-if="fileMediatype !== 'image' || showType !== 'grid'" :readonly="readonly"
-			:list-styles="listStyles" :files-list="filesList" :showType="showType" :delIcon="delIcon"
-			@uploadFiles="uploadFiles" @choose="choose" @delFile="delFile">
+		<upload-file v-if="fileMediatype !== 'image' || showType !== 'grid'" :readonly="readonly" :list-styles="listStyles" :files-list="filesList" :showType="showType" :delIcon="delIcon" @uploadFiles="uploadFiles" @choose="choose" @delFile="delFile">
 			<slot><button type="primary" size="mini">选择文件</button></slot>
 		</upload-file>
 	</view>
@@ -89,24 +83,18 @@
 		},
 		emits: ['select', 'success', 'fail', 'progress', 'delete', 'update:modelValue', 'input'],
 		props: {
-			// #ifdef VUE3
 			modelValue: {
 				type: [Array, Object],
 				default () {
 					return []
 				}
 			},
-			// #endif
-
-			// #ifndef VUE3
 			value: {
 				type: [Array, Object],
 				default () {
 					return []
 				}
 			},
-			// #endif
-
 			disabled: {
 				type: Boolean,
 				default: false
@@ -189,37 +177,44 @@
 			sourceType: {
 				type: Array,
 				default () {
-					return  ['album', 'camera']
+					return ['album', 'camera']
 				}
 			},
 			provider: {
 				type: String,
 				default: '' // 默认上传到 unicloud 内置存储 extStorage 扩展存储
+			},
+			dir: {
+				type: String,
+				default: ''
 			}
 		},
 		data() {
 			return {
 				files: [],
-				localValue: []
+				localValue: [],
+				dirPath: ''
 			}
 		},
 		watch: {
-			// #ifndef VUE3
 			value: {
 				handler(newVal, oldVal) {
 					this.setValue(newVal, oldVal)
 				},
 				immediate: true
 			},
-			// #endif
-			// #ifdef VUE3
 			modelValue: {
 				handler(newVal, oldVal) {
 					this.setValue(newVal, oldVal)
 				},
 				immediate: true
 			},
-			// #endif
+			dir: {
+				handler(newVal) {
+					this.dirPath = newVal
+				},
+				immediate: true
+			},
 		},
 		computed: {
 			filesList() {
@@ -294,19 +289,19 @@
 				return this.uploadFiles(files)
 			},
 			async setValue(newVal, oldVal) {
-				const newData =  async (v) => {
+				const newData = async (v) => {
 					const reg = /cloud:\/\/([\w.]+\/?)\S*/
 					let url = ''
-					if(v.fileID){
+					if (v.fileID) {
 						url = v.fileID
-					}else{
+					} else {
 						url = v.url
 					}
 					if (reg.test(url)) {
 						v.fileID = url
 						v.url = await this.getTempFileURL(url)
 					}
-					if(v.url) v.path = v.url
+					if (v.url) v.path = v.url
 					return v
 				}
 				if (this.returnType === 'object') {
@@ -317,13 +312,13 @@
 					}
 				} else {
 					if (!newVal) newVal = []
-					for(let i =0 ;i < newVal.length ;i++){
+					for (let i = 0; i < newVal.length; i++) {
 						let v = newVal[i]
 						await newData(v)
 					}
 				}
 				this.localValue = newVal
-				if (this.form && this.formItem &&!this.is_reset) {
+				if (this.form && this.formItem && !this.is_reset) {
 					this.is_reset = false
 					this.formItem.setValue(this.localValue)
 				}
@@ -380,7 +375,9 @@
 			 * @param {Object} res
 			 */
 			async chooseFileCallback(res) {
+
 				const _extname = get_extname(this.fileExtname)
+
 				const is_one = (Number(this.limitLength) === 1 &&
 						this.disablePreview &&
 						!this.disabled) ||
@@ -406,11 +403,13 @@
 					let filedata = await get_file_data(files[i], this.fileMediatype)
 					filedata.progress = 0
 					filedata.status = 'ready'
-					this.files.push(filedata)
-					currentData.push({
+					// fix by mehaotian ,统一返回,删除也包含file对象
+					let fileTempData = {
 						...filedata,
 						file: files[i]
-					})
+					}
+					this.files.push(fileTempData)
+					currentData.push(fileTempData)
 				}
 				this.$emit('select', {
 					tempFiles: currentData,
@@ -421,13 +420,24 @@
 				if (!this.autoUpload || this.noSpace) {
 					res.tempFiles = []
 				}
-				res.tempFiles.forEach((fileItem, index) => {
+				res.tempFiles.map((fileItem, index) => {
 					this.provider && (fileItem.provider = this.provider);
 					const fileNameSplit = fileItem.name.split('.')
 					const ext = fileNameSplit.pop()
 					const fileName = fileNameSplit.join('.').replace(/[\s\/\?<>\\:\*\|":]/g, '_')
-					fileItem.cloudPath = fileName + '_' + Date.now() + '_' + index + '.' + ext
+					// 选择文件目录上传
+					let dir = this.dirPath || ''; // 防止用户传入的 dir 不正常
+					// 检查最后一个字符是否为 '/'(同时处理空字符串情况)
+					if (dir && dir[dir.length - 1] !== '/') {
+						dir += '/';
+					}
+
+					fileItem.cloudPath = dir + fileName + '_' + Date.now() + '_' + index + '.' + ext
+					fileItem.cloudPathAsRealPath = true
+
+					return fileItem
 				})
+				return res
 			},
 
 			/**
@@ -474,7 +484,7 @@
 						const reg = /cloud:\/\/([\w.]+\/?)\S*/
 						if (reg.test(item.url)) {
 							this.files[index].url = await this.getTempFileURL(item.url)
-						}else{
+						} else {
 							this.files[index].url = item.url
 						}
 
@@ -533,6 +543,7 @@
 			 */
 			delFile(index) {
 				this.$emit('delete', {
+					index,
 					tempFile: this.files[index],
 					tempFilePath: this.files[index].url
 				})
@@ -562,7 +573,7 @@
 				let data = []
 				if (this.returnType === 'object') {
 					data = this.backObject(this.files)[0]
-					this.localValue = data?data:null
+					this.localValue = data ? data : null
 				} else {
 					data = this.backObject(this.files)
 					if (!this.localValue) {
@@ -592,12 +603,12 @@
 						name: v.name,
 						path: v.path,
 						size: v.size,
-						fileID:v.fileID,
+						fileID: v.fileID,
 						url: v.url,
 						// 修改删除一个文件后不能再上传的bug, #694
-            uuid: v.uuid,
-            status: v.status,
-            cloudPath: v.cloudPath
+						uuid: v.uuid,
+						status: v.status,
+						cloudPath: v.cloudPath
 					})
 				})
 				return newFilesData
@@ -655,14 +666,6 @@
 		color: #999;
 	}
 
-	.is-add {
-		/* #ifndef APP-NVUE */
-		display: flex;
-		/* #endif */
-		align-items: center;
-		justify-content: center;
-	}
-
 	.icon-add {
 		width: 50px;
 		height: 5px;

+ 7 - 9
src/uni_modules/uni-file-picker/components/uni-file-picker/upload-file.vue

@@ -8,8 +8,7 @@
 			<!-- ,'is-list-card':showType === 'list-card' -->
 
 			<view class="uni-file-picker__lists-box" v-for="(item ,index) in list" :key="index" :class="{
-				'files-border':index !== 0 && styles.dividline}"
-			 :style="index !== 0 && styles.dividline &&borderLineStyle">
+				'files-border':index !== 0 && styles.dividline}" :style="index !== 0 && styles.dividline &&borderLineStyle">
 				<view class="uni-file-picker__item">
 					<!-- :class="{'is-text-image':showType === 'list'}" -->
 					<!-- 	<view class="files__image is-text-image">
@@ -22,8 +21,7 @@
 					</view>
 				</view>
 				<view v-if="(item.progress && item.progress !== 100) ||item.progress===0 " class="file-picker__progress">
-					<progress class="file-picker__progress-item" :percent="item.progress === -1?0:item.progress" stroke-width="4"
-					 :backgroundColor="item.errMsg?'#ff5a5f':'#EBEBEB'" />
+					<progress class="file-picker__progress-item" :percent="item.progress === -1?0:item.progress" stroke-width="4" :backgroundColor="item.errMsg?'#ff5a5f':'#EBEBEB'" />
 				</view>
 				<view v-if="item.status === 'error'" class="file-picker__mask" @click.stop="uploadFiles(item,index)">
 					点击重试
@@ -37,7 +35,7 @@
 <script>
 	export default {
 		name: "uploadFile",
-		emits:['uploadFiles','choose','delFile'],
+		emits: ['uploadFiles', 'choose', 'delFile'],
 		props: {
 			filesList: {
 				type: Array,
@@ -70,9 +68,9 @@
 					}
 				}
 			},
-			readonly:{
-				type:Boolean,
-				default:false
+			readonly: {
+				type: Boolean,
+				default: false
 			}
 		},
 		computed: {
@@ -322,4 +320,4 @@
 	}
 
 	/* #endif */
-</style>
+</style>

+ 5 - 12
src/uni_modules/uni-file-picker/components/uni-file-picker/upload-image.vue

@@ -16,12 +16,9 @@
 				</view>
 			</view>
 		</view>
-		<view v-if="filesList.length < limit && !readonly" class="file-picker__box" :style="boxStyle">
+		<view v-if="filesList.length < limit" class="file-picker__box" :style="boxStyle">
 			<view class="file-picker__box-content is-add" :style="borderStyle" @click="choose">
-				<slot>
-					<view class="icon-add"></view>
-					<view class="icon-add rotate"></view>
-				</slot>
+				<slot></slot>
 			</view>
 		</view>
 	</view>
@@ -145,12 +142,15 @@
 				this.$emit("uploadFiles", item)
 			},
 			choose() {
+				if(this.readonly) return
 				this.$emit("choose")
 			},
 			delFile(index) {
+				if(this.readonly) return
 				this.$emit('delFile', index)
 			},
 			prviewImage(img, index) {
+				if(this.readonly) return
 				let urls = []
 				if(Number(this.limit) === 1&&this.disablePreview&&!this.disabled){
 					this.$emit("choose")
@@ -254,13 +254,6 @@
 		justify-content: center;
 	}
 
-	.icon-add {
-		width: 50px;
-		height: 5px;
-		background-color: #f1f1f1;
-		border-radius: 2px;
-	}
-
 	.rotate {
 		position: absolute;
 		transform: rotate(90deg);

+ 1 - 0
src/uni_modules/uni-file-picker/components/uni-file-picker/utils.js

@@ -90,6 +90,7 @@ export const get_file_data = async (files, type = 'image') => {
 		extname: extname || '',
 		cloudPath: files.cloudPath,
 		fileType: files.fileType,
+		thumbTempFilePath: files.thumbTempFilePath,
 		url: files.path || files.path,
 		size: files.size, //单位是字节
 		image: {},

+ 60 - 38
src/uni_modules/uni-file-picker/package.json

@@ -1,7 +1,7 @@
 {
   "id": "uni-file-picker",
   "displayName": "uni-file-picker 文件选择上传",
-  "version": "1.0.6",
+  "version": "1.1.3",
   "description": "文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间",
   "keywords": [
     "uni-ui",
@@ -11,12 +11,14 @@
 ],
   "repository": "https://github.com/dcloudio/uni-ui",
   "engines": {
-    "HBuilderX": ""
+    "HBuilderX": "",
+    "uni-app": "^4.33",
+    "uni-app-x": ""
   },
   "directories": {
     "example": "../../temps/example_temps"
   },
-"dcloudext": {
+  "dcloudext": {
     "sale": {
       "regular": {
         "price": "0.00"
@@ -34,50 +36,70 @@
       "permissions": "无"
     },
     "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
-    "type": "component-vue"
+    "type": "component-vue",
+    "darkmode": "x",
+    "i18n": "x",
+    "widescreen": "x"
   },
   "uni_modules": {
-    "dependencies": ["uni-scss"],
+    "dependencies": [
+      "uni-scss"
+    ],
     "encrypt": [],
     "platforms": {
       "cloud": {
-        "tcb": "y",
-        "aliyun": "y"
+        "tcb": "√",
+        "aliyun": "√",
+        "alipay": "√"
       },
       "client": {
-        "App": {
-          "app-vue": "y",
-          "app-nvue": "n"
+        "uni-app": {
+          "vue": {
+            "vue2": "√",
+            "vue3": "√"
+          },
+          "web": {
+            "safari": "√",
+            "chrome": "√"
+          },
+          "app": {
+            "vue": "√",
+            "nvue": "-",
+            "android": "√",
+            "ios": "√",
+            "harmony": "√"
+          },
+          "mp": {
+            "weixin": "√",
+            "alipay": "√",
+            "toutiao": "√",
+            "baidu": "√",
+            "kuaishou": "√",
+            "jd": "-",
+            "harmony": "-",
+            "qq": "√",
+            "lark": "-"
+          },
+          "quickapp": {
+            "huawei": "√",
+            "union": "√"
+          }
         },
-        "H5-mobile": {
-          "Safari": "y",
-          "Android Browser": "y",
-          "微信浏览器(Android)": "y",
-          "QQ浏览器(Android)": "y"
-        },
-        "H5-pc": {
-          "Chrome": "y",
-          "IE": "y",
-          "Edge": "y",
-          "Firefox": "y",
-          "Safari": "y"
-        },
-        "小程序": {
-          "微信": "y",
-          "阿里": "y",
-          "百度": "y",
-          "字节跳动": "y",
-          "QQ": "y"
-        },
-        "快应用": {
-          "华为": "u",
-          "联盟": "u"
-        },
-        "Vue": {
-            "vue2": "y",
-            "vue3": "y"
+        "uni-app-x": {
+          "web": {
+            "safari": "-",
+            "chrome": "-"
+          },
+          "app": {
+            "android": "-",
+            "ios": "-",
+            "harmony": "-"
+          },
+          "mp": {
+            "weixin": "-"
+          }
         }
       }
     }
   }
-}
+}

+ 1 - 2
src/uni_modules/uni-file-picker/readme.md

@@ -7,5 +7,4 @@
 
 文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间
 
-### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-file-picker)
-#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-file-picker)

+ 6 - 0
src/uni_modules/uni-forms/changelog.md

@@ -1,3 +1,9 @@
+## 1.4.13(2024-10-08)
+- 修复 校验规则在抖音开发者工具上不生效的bug,详见:[https://ask.dcloud.net.cn/question/191933](https://ask.dcloud.net.cn/question/191933)
+## 1.4.12 (2024-9-21)
+- 修复 form上次修改的问题
+## 1.4.11 (2024-9-14)
+- 修复 binddata的兼容性问题
 ## 1.4.10(2023-11-03)
 - 优化 labelWidth 描述错误
 ## 1.4.9(2023-02-10)

+ 5 - 0
src/uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue

@@ -57,7 +57,12 @@
 	export default {
 		name: 'uniFormsItem',
 		options: {
+			// #ifdef MP-TOUTIAO
+			virtualHost: false,
+			// #endif
+			// #ifndef MP-TOUTIAO
 			virtualHost: true
+			// #endif
 		},
 		provide() {
 			return {

+ 8 - 1
src/uni_modules/uni-forms/components/uni-forms/uni-forms.vue

@@ -68,7 +68,12 @@
 		name: 'uniForms',
 		emits: ['validate', 'submit'],
 		options: {
+			// #ifdef MP-TOUTIAO
+			virtualHost: false,
+			// #endif
+			// #ifndef MP-TOUTIAO
 			virtualHost: true
+			// #endif
 		},
 		props: {
 			// 即将弃用
@@ -180,7 +185,9 @@
 							}
 						}
 						if (!formVm) return console.error('当前 uni-froms 组件缺少 ref 属性');
-						formVm.setValue(name, value);
+						if(formVm.model)formVm.model[name] = value
+						if(formVm.modelValue)formVm.modelValue[name] = value
+						if(formVm.value)formVm.value[name] = value
 					}
 				}
 			}

+ 3 - 2
src/uni_modules/uni-forms/package.json

@@ -1,7 +1,7 @@
 {
   "id": "uni-forms",
   "displayName": "uni-forms 表单",
-  "version": "1.4.10",
+  "version": "1.4.13",
   "description": "由输入框、选择器、单选框、多选框等控件组成,用以收集、校验、提交数据",
   "keywords": [
     "uni-ui",
@@ -46,7 +46,8 @@
     "platforms": {
       "cloud": {
         "tcb": "y",
-        "aliyun": "y"
+        "aliyun": "y",
+        "alipay": "n"
       },
       "client": {
         "App": {

+ 4 - 0
src/uni_modules/uni-icons/changelog.md

@@ -1,3 +1,7 @@
+## 2.0.12(2025-08-26)
+- 优化 uni-app x 下 size 类型问题
+## 2.0.11(2025-08-18)
+- 修复 图标点击事件返回
 ## 2.0.9(2024-01-12)
 fix: 修复图标大小默认值错误的问题
 ## 2.0.8(2023-12-14)

+ 5 - 5
src/uni_modules/uni-icons/components/uni-icons/uni-icons.uvue

@@ -29,8 +29,8 @@
 				default: '#333333'
 			},
 			size: {
-				type: Object,
-				default: 16
+        type: [Number, String],
+        default: 16
 			},
 			fontFamily: {
 				type: String,
@@ -51,9 +51,9 @@
 			iconSize() : string {
 				const size = this.size
 				if (typeof size == 'string') {
-					const reg = /^[0-9]*$/g
-					return reg.test(size as string) ? '' + size + 'px' : '' + size;
-					// return '' + this.size
+				  const reg = /^[0-9]*$/g
+				  return reg.test(size as string) ? '' + size + 'px' : '' + size;
+				  // return '' + this.size
 				}
 				return this.getFontSize(size as number)
 			},

+ 3 - 3
src/uni_modules/uni-icons/components/uni-icons/uni-icons.vue

@@ -85,8 +85,8 @@
 			}
 		},
 		methods: {
-			_onClick() {
-				this.$emit('click')
+			_onClick(e) {
+				this.$emit('click', e)
 			}
 		}
 	}
@@ -107,4 +107,4 @@
 		text-decoration: none;
 		text-align: center;
 	}
-</style>
+</style>

+ 66 - 43
src/uni_modules/uni-icons/package.json

@@ -1,7 +1,7 @@
 {
   "id": "uni-icons",
   "displayName": "uni-icons 图标",
-  "version": "2.0.9",
+  "version": "2.0.12",
   "description": "图标组件,用于展示移动端常见的图标,可自定义颜色、大小。",
   "keywords": [
     "uni-ui",
@@ -11,12 +11,14 @@
 ],
   "repository": "https://github.com/dcloudio/uni-ui",
   "engines": {
-    "HBuilderX": "^3.2.14"
+    "HBuilderX": "^3.2.14",
+    "uni-app": "^4.08",
+    "uni-app-x": "^4.61"
   },
   "directories": {
     "example": "../../temps/example_temps"
   },
-"dcloudext": {
+  "dcloudext": {
     "sale": {
       "regular": {
         "price": "0.00"
@@ -34,55 +36,76 @@
       "permissions": "无"
     },
     "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
-    "type": "component-vue"
+    "type": "component-vue",
+    "darkmode": "x",
+    "i18n": "x",
+    "widescreen": "x"
   },
   "uni_modules": {
-    "dependencies": ["uni-scss"],
+    "dependencies": [
+      "uni-scss"
+    ],
     "encrypt": [],
     "platforms": {
       "cloud": {
-        "tcb": "y",
-        "aliyun": "y"
+        "tcb": "x",
+        "aliyun": "x",
+        "alipay": "x"
       },
       "client": {
-        "App": {
-          "app-vue": "y",
-          "app-nvue": "y",
-          "app-uvue": "y"
+        "uni-app": {
+          "vue": {
+            "vue2": "√",
+            "vue3": "√"
+          },
+          "web": {
+            "safari": "√",
+            "chrome": "√"
+          },
+          "app": {
+            "vue": "√",
+            "nvue": "-",
+            "android": {
+                "extVersion": "",
+                "minVersion": "29"
+            },
+            "ios": "√",
+            "harmony": "√"
+          },
+          "mp": {
+            "weixin": "√",
+            "alipay": "√",
+            "toutiao": "√",
+            "baidu": "√",
+            "kuaishou": "-",
+            "jd": "-",
+            "harmony": "-",
+            "qq": "√",
+            "lark": "-"
+          },
+          "quickapp": {
+            "huawei": "√",
+            "union": "√"
+          }
         },
-        "H5-mobile": {
-          "Safari": "y",
-          "Android Browser": "y",
-          "微信浏览器(Android)": "y",
-          "QQ浏览器(Android)": "y"
-        },
-        "H5-pc": {
-          "Chrome": "y",
-          "IE": "y",
-          "Edge": "y",
-          "Firefox": "y",
-          "Safari": "y"
-        },
-        "小程序": {
-          "微信": "y",
-          "阿里": "y",
-          "百度": "y",
-          "字节跳动": "y",
-          "QQ": "y",
-					"钉钉": "y",
-					"快手": "y",
-					"飞书": "y",
-					"京东": "y"
-        },
-        "快应用": {
-          "华为": "y",
-          "联盟": "y"
-        },
-        "Vue": {
-            "vue2": "y",
-            "vue3": "y"
+        "uni-app-x": {
+          "web": {
+            "safari": "√",
+            "chrome": "√"
+          },
+          "app": {
+            "android": {
+                "extVersion": "",
+                "minVersion": "29"
+            },
+            "ios": "√",
+            "harmony": "√"
+          },
+          "mp": {
+            "weixin": "√"
+          }
         }
       }
     }
   }
-}
+}

+ 4 - 0
src/uni_modules/uni-id-common/changelog.md

@@ -1,3 +1,7 @@
+## 1.0.18(2024-07-08)
+- checkToken时如果传入的token为空则返回uni-id-check-token-failed错误码以便uniIdRouter能正常跳转
+## 1.0.17(2024-04-26)
+- 兼容uni-app-x对客户端uniPlatform的调整(uni-app-x内uniPlatform区分app-android、app-ios)
 ## 1.0.16(2023-04-25)
 - 新增maxTokenLength配置,用于限制数据库用户记录token数组的最大长度
 ## 1.0.15(2023-04-06)

+ 6 - 6
src/uni_modules/uni-id-common/package.json

@@ -1,7 +1,7 @@
 {
 	"id": "uni-id-common",
 	"displayName": "uni-id-common",
-	"version": "1.0.16",
+	"version": "1.0.18",
 	"description": "包含uni-id token生成、校验、刷新功能的云函数公共模块",
 	"keywords": [
         "uni-id-common",
@@ -10,16 +10,15 @@
         "权限"
     ],
 	"repository": "https://gitcode.net/dcloud/uni-id-common",
-	"engines": {
-		"HBuilderX": "^3.1.0"
+    "engines": {
 	},
     "dcloudext": {
         "sale": {
 			"regular": {
-				"price": "0.00"
+				"price": 0
 			},
 			"sourcecode": {
-				"price": "0.00"
+				"price": 0
 			}
 		},
 		"contact": {
@@ -39,7 +38,8 @@
 		"platforms": {
 			"cloud": {
 				"tcb": "y",
-				"aliyun": "y"
+                "aliyun": "y",
+                "alipay": "n"
 			},
 			"client": {
 				"Vue": {

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
src/uni_modules/uni-id-common/uniCloud/cloudfunctions/common/uni-id-common/index.js


+ 18 - 14
src/uni_modules/uni-id-common/uniCloud/cloudfunctions/common/uni-id-common/package.json

@@ -1,16 +1,20 @@
 {
-  "name": "uni-id-common",
-  "version": "1.0.16",
-  "description": "uni-id token生成、校验、刷新",
-  "main": "index.js",
-  "homepage": "https://uniapp.dcloud.io/uniCloud/uni-id-common.html",
-  "repository": {
-    "type": "git",
-    "url": "git+https://gitee.com/dcloud/uni-id-common.git"
-  },
-  "author": "DCloud",
-  "license": "Apache-2.0",
-  "dependencies": {
-    "uni-config-center": "file:../../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center"
-  }
+    "name": "uni-id-common",
+    "version": "1.0.18",
+    "description": "uni-id token生成、校验、刷新",
+    "main": "index.js",
+    "homepage": "https:\/\/uniapp.dcloud.io\/uniCloud\/uni-id-common.html",
+    "repository": {
+        "type": "git",
+        "url": "git+https:\/\/gitee.com\/dcloud\/uni-id-common.git"
+    },
+    "author": "DCloud",
+    "license": "Apache-2.0",
+    "dependencies": {
+        "uni-config-center": "file:..\/..\/..\/..\/..\/uni-config-center\/uniCloud\/cloudfunctions\/common\/uni-config-center"
+    },
+    "origin-plugin-dev-name": "uni-id-common",
+    "origin-plugin-version": "1.0.18",
+    "plugin-dev-name": "uni-id-common",
+    "plugin-version": "1.0.18"
 }

+ 6 - 0
src/uni_modules/uni-list/changelog.md

@@ -1,3 +1,9 @@
+## 1.2.17(2025-08-20)
+- 修复 右侧箭头类型错误的问题
+## 1.2.16(2025-04-14)
+- 修复 可触发点击反馈的 uni-list-item 没有hover效果的问题
+## 1.2.15(2025-01-08)
+- 修复 示例中过期图片地址
 ## 1.2.14(2023-04-14)
 - 优化 uni-list-chat 具名插槽`header` 非app端套一层元素,方便使用时通过外层元素定位实现样式修改
 ## 1.2.13(2023-03-03)

+ 17 - 9
src/uni_modules/uni-list/components/uni-list-item/uni-list-item.vue

@@ -37,7 +37,7 @@
 					</view>
 				</slot>
 			</view>
-			<uni-icons v-if="showArrow || link" :size="16" class="uni-icon-wrapper" color="#bbb" type="arrowright" />
+			<uni-icons v-if="showArrow || link" :size="16" class="uni-icon-wrapper" color="#bbb" type="right" />
 		</view>
 		<!-- #ifdef APP-NVUE -->
 	</cell>
@@ -213,14 +213,22 @@
 							"bottom": verticalPadding,
 							"left": horizontalPadding
 						}
+					} else if(paddingArr.length === 3) {
+						const [topPadding, horizontalPadding, bottomPadding] = paddingArr;
+						this.padding = {
+							"top": topPadding,
+							"right": horizontalPadding,
+							"bottom": bottomPadding,
+							"left": horizontalPadding
+						}
 					} else if (paddingArr.length === 4) {
-							const [topPadding, rightPadding, bottomPadding, leftPadding] = paddingArr;
-							this.padding = {
-								"top": topPadding,
-								"right": rightPadding,
-								"bottom": bottomPadding,
-								"left": leftPadding
-							}
+						const [topPadding, rightPadding, bottomPadding, leftPadding] = paddingArr;
+						this.padding = {
+							"top": topPadding,
+							"right": rightPadding,
+							"bottom": bottomPadding,
+							"left": leftPadding
+						}
 					}
 				},
 				immediate: true
@@ -531,4 +539,4 @@
 		text-overflow: ellipsis;
 		/* #endif */
 	}
-</style>
+</style>

+ 56 - 36
src/uni_modules/uni-list/package.json

@@ -1,7 +1,7 @@
 {
   "id": "uni-list",
   "displayName": "uni-list 列表",
-  "version": "1.2.14",
+  "version": "1.2.17",
   "description": "List 组件 ,帮助使用者快速构建列表。",
   "keywords": [
     "",
@@ -13,12 +13,14 @@
 ],
   "repository": "https://github.com/dcloudio/uni-ui",
   "engines": {
-    "HBuilderX": ""
+    "HBuilderX": "",
+    "uni-app": "^4.08",
+    "uni-app-x": ""
   },
   "directories": {
     "example": "../../temps/example_temps"
   },
-"dcloudext": {
+  "dcloudext": {
     "sale": {
       "regular": {
         "price": "0.00"
@@ -36,7 +38,10 @@
       "permissions": "无"
     },
     "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
-    "type": "component-vue"
+    "type": "component-vue",
+    "darkmode": "x",
+    "i18n": "x",
+    "widescreen": "x"
   },
   "uni_modules": {
     "dependencies": [
@@ -46,41 +51,56 @@
     "encrypt": [],
     "platforms": {
       "cloud": {
-        "tcb": "y",
-        "aliyun": "y"
+        "tcb": "x",
+        "aliyun": "x",
+        "alipay": "x"
       },
       "client": {
-        "App": {
-          "app-vue": "y",
-          "app-nvue": "y"
+        "uni-app": {
+          "vue": {
+            "vue2": "√",
+            "vue3": "√"
+          },
+          "web": {
+            "safari": "√",
+            "chrome": "√"
+          },
+          "app": {
+            "vue": "√",
+            "nvue": "-",
+            "android": "√",
+            "ios": "√",
+            "harmony": "√"
+          },
+          "mp": {
+            "weixin": "√",
+            "alipay": "√",
+            "toutiao": "√",
+            "baidu": "√",
+            "kuaishou": "-",
+            "jd": "-",
+            "harmony": "-",
+            "qq": "√",
+            "lark": "-"
+          },
+          "quickapp": {
+            "huawei": "√",
+            "union": "√"
+          }
         },
-        "H5-mobile": {
-          "Safari": "y",
-          "Android Browser": "y",
-          "微信浏览器(Android)": "y",
-          "QQ浏览器(Android)": "y"
-        },
-        "H5-pc": {
-          "Chrome": "y",
-          "IE": "y",
-          "Edge": "y",
-          "Firefox": "y",
-          "Safari": "y"
-        },
-        "小程序": {
-          "微信": "y",
-          "阿里": "y",
-          "百度": "y",
-          "字节跳动": "y",
-          "QQ": "y"
-        },
-        "快应用": {
-          "华为": "u",
-          "联盟": "u"
-        },
-        "Vue": {
-            "vue2": "y",
-            "vue3": "y"
+        "uni-app-x": {
+          "web": {
+            "safari": "-",
+            "chrome": "-"
+          },
+          "app": {
+            "android": "-",
+            "ios": "-",
+            "harmony": "-"
+          },
+          "mp": {
+            "weixin": "-"
+          }
         }
       }
     }

+ 3 - 303
src/uni_modules/uni-list/readme.md

@@ -20,304 +20,8 @@ uni-list-item有很多风格,uni-list-item组件通过内置的属性,满足
 
 uni-list不包含下拉刷新和上拉翻页。上拉翻页另见组件:[uni-load-more](https://ext.dcloud.net.cn/plugin?id=29)
 
-
-### 安装方式
-
-本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
-
-如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
-
-> **注意事项**
-> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。
-> - 组件需要依赖 `sass` 插件 ,请自行手动安装
-> - 组件内部依赖 `'uni-icons'` 、`uni-badge` 组件
-> - `uni-list` 和 `uni-list-item` 需要配套使用,暂不支持单独使用 `uni-list-item`
-> - 只有开启点击反馈后,会有点击选中效果
-> - 使用插槽时,可以完全自定义内容
-> - note 、rightText 属性暂时没做限制,不支持文字溢出隐藏,使用时应该控制长度显示或通过默认插槽自行扩展
-> - 支付宝小程序平台需要在支付宝小程序开发者工具里开启 component2 编译模式,开启方式: 详情 --> 项目配置 --> 启用 component2 编译
-> - 如果需要修改 `switch`、`badge` 样式,请使用插槽自定义
-> - 在 `HBuilderX` 低版本中,可能会出现组件显示 `undefined` 的问题,请升级最新的 `HBuilderX` 或者 `cli`
-> - 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
- 
-
-### 基本用法 
-
-- 设置 `title` 属性,可以显示列表标题
-- 设置 `disabled` 属性,可以禁用当前项
-
-```html
-<uni-list>
-	<uni-list-item  title="列表文字" ></uni-list-item>
-	<uni-list-item :disabled="true" title="列表禁用状态" ></uni-list-item>
-</uni-list>
-			 
-```
-
-### 多行内容显示
-
-- 设置 `note` 属性 ,可以在第二行显示描述文本信息
-
-```html
-<uni-list>
-	<uni-list-item title="列表文字" note="列表描述信息"></uni-list-item>
-	<uni-list-item :disabled="true" title="列表文字" note="列表禁用状态"></uni-list-item>
-</uni-list>
-
-```
-
-### 右侧显示角标、switch
-
-- 设置 `show-badge` 属性 ,可以显示角标内容
-- 设置 `show-switch` 属性,可以显示 switch 开关
-
-```html
-<uni-list>
-	<uni-list-item  title="列表右侧显示角标" :show-badge="true" badge-text="12" ></uni-list-item>
-	<uni-list-item title="列表右侧显示 switch"  :show-switch="true"  @switchChange="switchChange" ></uni-list-item>
-</uni-list>
-
-```
-
-### 左侧显示略缩图、图标  
-
-- 设置 `thumb` 属性 ,可以在列表左侧显示略缩图
-- 设置 `show-extra-icon` 属性,并指定 `extra-icon` 可以在左侧显示图标
-
-```html
- <uni-list>
- 	<uni-list-item title="列表左侧带略缩图" note="列表描述信息" thumb="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png"
- 	 thumb-size="lg" rightText="右侧文字"></uni-list-item>
- 	<uni-list-item :show-extra-icon="true" :extra-icon="extraIcon1" title="列表左侧带扩展图标" ></uni-list-item>
-</uni-list>
-```
-
-### 开启点击反馈和右侧箭头
-- 设置 `clickable` 为 `true` ,则表示这是一个可点击的列表,会默认给一个点击效果,并可以监听 `click` 事件
-- 设置 `link` 属性,会自动开启点击反馈,并给列表右侧添加一个箭头
-- 设置 `to` 属性,可以跳转页面,`link` 的值表示跳转方式,如果不指定,默认为 `navigateTo`
-
-```html
-
-<uni-list>
-	<uni-list-item title="开启点击反馈" clickable  @click="onClick" ></uni-list-item>
-	<uni-list-item title="默认 navigateTo 方式跳转页面" link to="/pages/vue/index/index" @click="onClick($event,1)" ></uni-list-item>
-	<uni-list-item title="reLaunch 方式跳转页面" link="reLaunch" to="/pages/vue/index/index" @click="onClick($event,1)" ></uni-list-item>
-</uni-list>
-
-```
-
-
-### 聊天列表示例
-- 设置 `clickable` 为 `true` ,则表示这是一个可点击的列表,会默认给一个点击效果,并可以监听 `click` 事件
-- 设置 `link` 属性,会自动开启点击反馈,`link` 的值表示跳转方式,如果不指定,默认为 `navigateTo`
-- 设置 `to` 属性,可以跳转页面
-- `time` 属性,通常会设置成时间显示,但是这个属性不仅仅可以设置时间,你可以传入任何文本,注意文本长度可能会影响显示
-- `avatar` 和 `avatarList` 属性同时只会有一个生效,同时设置的话,`avatarList` 属性的长度大于1 ,`avatar` 属性将失效
-- 可以通过默认插槽自定义列表右侧内容
-
-```html
-
-<uni-list>
-	<uni-list :border="true">
-		<!-- 显示圆形头像 -->
-		<uni-list-chat :avatar-circle="true" title="uni-app" avatar="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png" note="您收到一条新的消息" time="2020-02-02 20:20" ></uni-list-chat>
-		<!-- 右侧带角标 -->
-		<uni-list-chat title="uni-app" avatar="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png" note="您收到一条新的消息" time="2020-02-02 20:20" badge-text="12" :badge-style="{backgroundColor:'#FF80AB'}"></uni-list-chat>
-		<!-- 头像显示圆点 -->
-		<uni-list-chat title="uni-app" avatar="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png" note="您收到一条新的消息" time="2020-02-02 20:20" badge-positon="left" badge-text="dot"></uni-list-chat>
-		<!-- 头像显示角标 -->
-		<uni-list-chat title="uni-app" avatar="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png" note="您收到一条新的消息" time="2020-02-02 20:20" badge-positon="left" badge-text="99"></uni-list-chat>
-		<!-- 显示多头像 -->
-		<uni-list-chat title="uni-app" :avatar-list="avatarList" note="您收到一条新的消息" time="2020-02-02 20:20" badge-positon="left" badge-text="dot"></uni-list-chat>
-		<!-- 自定义右侧内容 -->
-		<uni-list-chat title="uni-app" :avatar-list="avatarList" note="您收到一条新的消息" time="2020-02-02 20:20" badge-positon="left" badge-text="dot">
-			<view class="chat-custom-right">
-				<text class="chat-custom-text">刚刚</text>
-				<!-- 需要使用 uni-icons 请自行引入 -->
-				<uni-icons type="star-filled" color="#999" size="18"></uni-icons>
-			</view>
-		</uni-list-chat>
-	</uni-list>
-</uni-list>
-
-```
-
-```javascript
-
-export default {
-	components: {},
-	data() {
-		return {
-			avatarList: [{
-				url: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png'
-			}, {
-				url: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png'
-			}, {
-				url: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png'
-			}]
-		}
-	}
-}
-
-```
-
-
-```css
-
-.chat-custom-right {
-	flex: 1;
-	/* #ifndef APP-NVUE */
-	display: flex;
-	/* #endif */
-	flex-direction: column;
-	justify-content: space-between;
-	align-items: flex-end;
-}
-
-.chat-custom-text {
-	font-size: 12px;
-	color: #999;
-}
-
-```
-
-## API
-
-### List Props
-
-属性名			|类型		|默认值		|	说明																									
-:-:				|:-:		|:-:		|	:-:	
-border			|Boolean	|true		|	是否显示边框
-
-
-### ListItem Props
-
-属性名			|类型		|默认值		|	说明																					
-:-:				|:-:		|:-:		|	:-:	
-title			|String		|-			|	标题
-note			|String		|-			|	描述
-ellipsis		|Number		|0			|	title 是否溢出隐藏,可选值,0:默认;  1:显示一行;	2:显示两行;【nvue 暂不支持】
-thumb			|String		|-			|	左侧缩略图,若thumb有值,则不会显示扩展图标
-thumbSize		|String 	|medium 	|	略缩图尺寸,可选值,lg:大图;  medium:一般;	sm:小图;
-showBadge		|Boolean	|false		|	是否显示数字角标	
-badgeText		|String		|-			|	数字角标内容
-badgeType		|String		|-			|	数字角标类型,参考[uni-icons](https://ext.dcloud.net.cn/plugin?id=21)	
-badgeStyle  |Object   |-      | 数字角标样式,使用uni-badge的custom-style参数
-rightText		|String		|-			|	右侧文字内容
-disabled		|Boolean	|false		|	是否禁用	
-showArrow 		|Boolean	|true		|	是否显示箭头图标			
-link			|String 	|navigateTo	|	新页面跳转方式,可选值见下表
-to				|String		|-			|	新页面跳转地址,如填写此属性,click 会返回页面是否跳转成功			
-clickable		|Boolean	|false		|	是否开启点击反馈
-showSwitch	    |Boolean	|false		|	是否显示Switch																			
-switchChecked	|Boolean	|false		|	Switch是否被选中																			
-showExtraIcon   |Boolean	|false		|	左侧是否显示扩展图标																		
-extraIcon		|Object		|-			|	扩展图标参数,格式为 ``{color: '#4cd964',size: '22',type: 'spinner'}``,参考 [uni-icons](https://ext.dcloud.net.cn/plugin?id=28)	
-direction		| String	|row		|	排版方向,可选值,row:水平排列;  column:垂直排列; 3个插槽是水平排还是垂直排,也受此属性控制
-
-
-#### Link Options
-
-属性名				|	说明
-:-:					|	:-:
-navigateTo 	| 	同 uni.navigateTo()
-redirectTo 	|	同 uni.reLaunch()
-reLaunch		|	同 uni.reLaunch()
-switchTab  	|	同 uni.switchTab()
-
-### ListItem Events
-
-事件称名			|说明									|返回参数			
-:-:				|:-:									|:-:				
-click			|点击 uniListItem 触发事件,需开启点击反馈	|-					
-switchChange	|点击切换 Switch 时触发,需显示 switch		|e={value:checked}	
-
-
-
-### ListItem Slots
-
-名称	 	|	说明					
-:-:		|	:-:						
-header	|	左/上内容插槽,可完全自定义默认显示
-body	|	中间内容插槽,可完全自定义中间内容				
-footer	|	右/下内容插槽,可完全自定义右侧内容		
-
-
-> **通过插槽扩展**
-> 需要注意的是当使用插槽时,内置样式将会失效,只保留排版样式,此时的样式需要开发者自己实现
-> 如果	`uni-list-item` 组件内置属性样式无法满足需求,可以使用插槽来自定义uni-list-item里的内容。
-> uni-list-item提供了3个可扩展的插槽:`header`、`body`、`footer`
-> - 当 `direction` 属性为 `row` 时表示水平排列,此时 `header` 表示列表的左边部分,`body` 表示列表的中间部分,`footer` 表示列表的右边部分
-> - 当 `direction` 属性为 `column` 时表示垂直排列,此时 `header` 表示列表的上边部分,`body` 表示列表的中间部分,`footer` 表示列表的下边部分
-> 开发者可以只用1个插槽,也可以3个一起使用。在插槽中可自主编写view标签,实现自己所需的效果。
-
-	
-**示例**
-
-```html
-<uni-list>
-	<uni-list-item title="自定义右侧插槽" note="列表描述信息" link>
-		<template slot="header">
-			<image class="slot-image" src="/static/logo.png" mode="widthFix"></image>
-		</template>
-	</uni-list-item>
-	<uni-list-item>
-		<!-- 自定义 header -->
-		<view slot="header" class="slot-box"><image class="slot-image" src="/static/logo.png" mode="widthFix"></image></view>
-		<!-- 自定义 body -->
-		<text slot="body" class="slot-box slot-text">自定义插槽</text>
-		<!-- 自定义 footer-->
-		<template slot="footer">
-			<image class="slot-image" src="/static/logo.png" mode="widthFix"></image>
-		</template>
-	</uni-list-item>
-</uni-list>
-```
-
-
-
-
-
-### ListItemChat Props
-
-属性名			|类型		|默认值		|	说明																		
-:-:				|:-:		|:-:		|	:-:	
-title 			|String		|-			|	标题
-note 			|String		|-			|	描述
-clickable		|Boolean	|false		|	是否开启点击反馈
-badgeText		|String		|-			|	数字角标内容,设置为 `dot` 将显示圆点
-badgePositon 	|String		|right		|	角标位置
-link			|String 	|navigateTo	|	是否展示右侧箭头并开启点击反馈,可选值见下表
-clickable		|Boolean	|false		|	是否开启点击反馈
-to				|String		|-			|	跳转页面地址,如填写此属性,click 会返回页面是否跳转成功	
-time			|String 	|-			|	右侧时间显示
-avatarCircle 	|Boolean 	|false		|	是否显示圆形头像
-avatar			|String 	|-			|	头像地址,avatarCircle 不填时生效
-avatarList 		|Array	 	|-			|	头像组,格式为 [{url:''}]
-
-#### Link Options
-
-属性名		|	说明
-:-:			|	:-:
-navigateTo 	| 	同 uni.navigateTo()
-redirectTo 	|	同 uni.reLaunch()
-reLaunch	|	同 uni.reLaunch()
-switchTab  	|	同 uni.switchTab()
-
-### ListItemChat Slots
-
-名称	 	|	说明					
-:-		|	:-						
-default	|	自定义列表右侧内容(包括时间和角标显示)
-
-### ListItemChat Events
-事件称名			|	说明						|	返回参数			
-:-:				|	:-:						|	:-:	
-@click			|	点击 uniListChat 触发事件	|	{data:{}}	,如有 to 属性,会返回页面跳转信息	
-
-
-
+### [点击查看详细文档](https://uniapp.dcloud.io/component/uniui/uni-indexed-list)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 
 
 
 
@@ -339,8 +43,4 @@ default	|	自定义列表右侧内容(包括时间和角标显示)
 
 1. 云端一体列表/宫格视图互切:[https://ext.dcloud.net.cn/plugin?id=2651](https://ext.dcloud.net.cn/plugin?id=2651)
 2. 云端一体列表(宫格模式):[https://ext.dcloud.net.cn/plugin?id=2671](https://ext.dcloud.net.cn/plugin?id=2671)
-3. 云端一体列表(列表模式):[https://ext.dcloud.net.cn/plugin?id=2672](https://ext.dcloud.net.cn/plugin?id=2672)
-
-## 组件示例
-
-点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/list/list](https://hellouniapp.dcloud.net.cn/pages/extUI/list/list)
+3. 云端一体列表(列表模式):[https://ext.dcloud.net.cn/plugin?id=2672](https://ext.dcloud.net.cn/plugin?id=2672)

+ 4 - 0
src/uni_modules/uni-load-more/changelog.md

@@ -1,3 +1,7 @@
+## 1.3.7(2025-08-20)
+- 修复 微信小程序css警告问题
+## 1.3.6(2024-10-15)
+- 修复 微信小程序中的getSystemInfo警告
 ## 1.3.3(2022-01-20)
 - 新增 showText属性 ,是否显示文本
 ## 1.3.2(2022-01-19)

+ 7 - 2
src/uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue

@@ -26,7 +26,7 @@
 		<!-- #ifndef APP-NVUE -->
 		<view v-else-if="!webviewHide && status === 'loading' && showIcon"
 			:style="{width:iconSize+'px',height:iconSize+'px'}" class="uni-load-more__img uni-load-more__img--ios-H5">
-			<image :src="imgBase64" mode="widthFix"></image>
+			<image class="image" :src="imgBase64" mode="widthFix"></image>
 		</view>
 		<!-- #endif -->
 		<text v-if="showText" class="uni-load-more__text"
@@ -37,7 +37,12 @@
 <script>
 	let platform
 	setTimeout(() => {
+		// #ifdef MP-WEIXIN
+		platform = uni.getDeviceInfo().platform
+		// #endif
+		// #ifndef MP-WEIXIN
 		platform = uni.getSystemInfoSync().platform
+		// #endif
 	}, 16)
 
 	import {
@@ -205,7 +210,7 @@
 		animation: loading-ios-H5 1s 0s step-end infinite;
 	}
 
-	.uni-load-more__img--ios-H5 image {
+	.uni-load-more__img--ios-H5 .image {
 		position: absolute;
 		width: 100%;
 		height: 100%;

+ 59 - 40
src/uni_modules/uni-load-more/package.json

@@ -1,7 +1,7 @@
 {
   "id": "uni-load-more",
   "displayName": "uni-load-more 加载更多",
-  "version": "1.3.3",
+  "version": "1.3.7",
   "description": "LoadMore 组件,常用在列表里面,做滚动加载使用。",
   "keywords": [
     "uni-ui",
@@ -11,16 +11,14 @@
 ],
   "repository": "https://github.com/dcloudio/uni-ui",
   "engines": {
-    "HBuilderX": ""
+    "HBuilderX": "",
+    "uni-app": "^4.07",
+    "uni-app-x": ""
   },
   "directories": {
     "example": "../../temps/example_temps"
   },
   "dcloudext": {
-    "category": [
-      "前端组件",
-      "通用组件"
-    ],
     "sale": {
       "regular": {
         "price": "0.00"
@@ -37,48 +35,69 @@
       "data": "无",
       "permissions": "无"
     },
-    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
+    "type": "component-vue",
+    "darkmode": "x",
+    "i18n": "x",
+    "widescreen": "x"
   },
   "uni_modules": {
-    "dependencies": ["uni-scss"],
+    "dependencies": [
+      "uni-scss"
+    ],
     "encrypt": [],
     "platforms": {
       "cloud": {
-        "tcb": "y",
-        "aliyun": "y"
+        "tcb": "x",
+        "aliyun": "x",
+        "alipay": "x"
       },
       "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": "y",
-          "Edge": "y",
-          "Firefox": "y",
-          "Safari": "y"
-        },
-        "小程序": {
-          "微信": "y",
-          "阿里": "y",
-          "百度": "y",
-          "字节跳动": "y",
-          "QQ": "y"
-        },
-        "快应用": {
-          "华为": "u",
-          "联盟": "u"
+        "uni-app": {
+          "vue": {
+            "vue2": "√",
+            "vue3": "√"
+          },
+          "web": {
+            "safari": "√",
+            "chrome": "√"
+          },
+          "app": {
+            "vue": "√",
+            "nvue": "-",
+            "android": "√",
+            "ios": "√",
+            "harmony": "√"
+          },
+          "mp": {
+            "weixin": "√",
+            "alipay": "√",
+            "toutiao": "√",
+            "baidu": "√",
+            "kuaishou": "-",
+            "jd": "-",
+            "harmony": "-",
+            "qq": "√",
+            "lark": "-"
+          },
+          "quickapp": {
+            "huawei": "√",
+            "union": "√"
+          }
         },
-        "Vue": {
-            "vue2": "y",
-            "vue3": "y"
+        "uni-app-x": {
+          "web": {
+            "safari": "-",
+            "chrome": "-"
+          },
+          "app": {
+            "android": "-",
+            "ios": "-",
+            "harmony": "-"
+          },
+          "mp": {
+            "weixin": "-"
+          }
         }
       }
     }

+ 9 - 0
src/uni_modules/uni-nav-bar/changelog.md

@@ -1,3 +1,12 @@
+## 1.3.17(2025-09-03)
+- 修复 内部样式问题
+## 1.3.16(2025-08-18)
+- 修复 微信小程序 fixed 下避让胶囊,优化标题居中,默认showMenuButtonWidth 不开启下,右侧插槽会被 胶囊覆盖
+- 新增 showMenuButtonWidth 右侧是否避让胶囊,即 显示区域为胶囊左侧,默认不开启,开启后会导致标题不在页面水平居中
+## 1.3.15(2025-06-24)
+- 适配微信小程序固定导航栏时,右侧插槽避让胶囊按钮
+## 1.3.14(2024-10-15)
+- 修复 微信小程序中的getSystemInfo警告
 ## 1.3.11(2023-03-29)
 - 修复 自定义状态栏高度闪动BUG
 ## 1.3.10(2023-03-29)

+ 44 - 18
src/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-nav-bar.vue

@@ -1,18 +1,14 @@
 <template>
 	<view class="uni-navbar" :class="{'uni-dark':dark, 'uni-nvue-fixed': fixed}">
-		<view class="uni-navbar__content" :class="{ 'uni-navbar--fixed': fixed, 'uni-navbar--shadow': shadow, 'uni-navbar--border': border }"
-			:style="{ 'background-color': themeBgColor, 'border-bottom-color':themeColor }" >
+		<view class="uni-navbar__content" :class="{ 'uni-navbar--fixed': fixed, 'uni-navbar--shadow': shadow, 'uni-navbar--border': border }" :style="{ 'background-color': themeBgColor }">
 			<status-bar v-if="statusBar" />
-			<view :style="{ color: themeColor,backgroundColor: themeBgColor ,height:navbarHeight}"
-				class="uni-navbar__header">
-				<view @tap="onClickLeft" class="uni-navbar__header-btns uni-navbar__header-btns-left"
-					:style="{width:leftIconWidth}">
+			<view :style="{ color: themeColor,backgroundColor: themeBgColor ,height:navbarHeight,width:showMenuButtonWidth?navWidth+'px':'100%'}" class="uni-navbar__header">
+				<view @tap="onClickLeft" class="uni-navbar__header-btns uni-navbar__header-btns-left" :style="{width:leftIconWidth}">
 					<slot name="left">
 						<view class="uni-navbar__content_view" v-if="leftIcon.length > 0">
 							<uni-icons :color="themeColor" :type="leftIcon" size="20" />
 						</view>
-						<view :class="{ 'uni-navbar-btn-icon-left': !leftIcon.length > 0 }" class="uni-navbar-btn-text"
-							v-if="leftText.length">
+						<view :class="{ 'uni-navbar-btn-icon-left': !leftIcon.length > 0 }" class="uni-navbar-btn-text" v-if="leftText.length">
 							<text :style="{ color: themeColor, fontSize: '12px' }">{{ leftText }}</text>
 						</view>
 					</slot>
@@ -20,13 +16,11 @@
 				<view class="uni-navbar__header-container " @tap="onClickTitle">
 					<slot>
 						<view class="uni-navbar__header-container-inner" v-if="title.length>0">
-							<text class="uni-nav-bar-text uni-ellipsis-1"
-								:style="{color: themeColor }">{{ title }}</text>
+							<text class="uni-nav-bar-text uni-ellipsis-1" :style="{color: themeColor }">{{ title }}</text>
 						</view>
 					</slot>
 				</view>
-				<view @click="onClickRight" class="uni-navbar__header-btns uni-navbar__header-btns-right"
-					:style="{width:rightIconWidth}">
+				<view @click="onClickRight" class="uni-navbar__header-btns uni-navbar__header-btns-right" :style="{width:rightIconWidth}">
 					<slot name="right">
 						<view v-if="rightIcon.length">
 							<uni-icons :color="themeColor" :type="rightIcon" size="22" />
@@ -38,12 +32,10 @@
 				</view>
 			</view>
 		</view>
-		<!-- #ifndef APP-NVUE -->
 		<view class="uni-navbar__placeholder" v-if="fixed">
 			<status-bar v-if="statusBar" />
 			<view class="uni-navbar__placeholder-view" :style="{ height:navbarHeight}" />
 		</view>
-		<!-- #endif -->
 	</view>
 </template>
 
@@ -52,8 +44,8 @@
 	const getVal = (val) => typeof val === 'number' ? val + 'px' : val;
 
 	/**
-	 * 
-	 * 
+	 *
+	 *
 	 * NavBar 自定义导航栏
 	 * @description 导航栏组件,主要用于头部导航
 	 * @tutorial https://ext.dcloud.net.cn/plugin?id=52
@@ -140,11 +132,20 @@
 				type: [Number, String],
 				default: 60
 			},
+			showMenuButtonWidth: {
+				type: Boolean,
+				default: false
+			},
 			stat: {
 				type: [Boolean, String],
 				default: ''
 			}
 		},
+		data() {
+			return {
+				navWidth: 'auto'
+			}
+		},
 		computed: {
 			themeBgColor() {
 				if (this.dark) {
@@ -169,6 +170,21 @@
 				return this.color || '#333'
 			},
 			navbarHeight() {
+				// #ifdef MP-WEIXIN
+				if (this.fixed && this.height === 0) {
+					const menuBtnInfo = uni.getMenuButtonBoundingClientRect()
+					const winInfo = uni.getWindowInfo()
+					const statusHeight = winInfo.statusBarHeight
+					const spaceHeight = menuBtnInfo.top - statusHeight
+					return getVal(menuBtnInfo.height + spaceHeight * 2)
+				}
+				// #endif
+				// #ifndef MP-WEIXIN
+				if (this.fixed && this.height === 0) {
+					return getVal(44)
+				}
+				// #endif
+
 				return getVal(this.height)
 			},
 			leftIconWidth() {
@@ -178,6 +194,15 @@
 				return getVal(this.rightWidth)
 			}
 		},
+		created() {
+			// #ifdef MP-WEIXIN
+			if (this.fixed) {
+				const menuBtnInfo = uni.getMenuButtonBoundingClientRect()
+				this.navWidth = menuBtnInfo.left
+			}
+			// #endif
+
+		},
 		mounted() {
 			if (uni.report && this.stat && this.title !== '') {
 				uni.report('title', this.title)
@@ -205,6 +230,7 @@
 		position: sticky;
 		/* #endif */
 	}
+
 	.uni-navbar {
 		// box-sizing: border-box;
 	}
@@ -244,13 +270,14 @@
 	}
 
 	.uni-navbar__header {
+		padding: 0 10px;
 		/* #ifndef APP-NVUE */
 		display: flex;
 		/* #endif */
-		padding: 0 10px;
 		flex-direction: row;
 		height: $nav-height;
 		font-size: 12px;
+		box-sizing: border-box;
 	}
 
 	.uni-navbar__header-btns {
@@ -311,7 +338,6 @@
 		// box-sizing: border-box;
 	}
 
-
 	.uni-navbar__placeholder-view {
 		height: $nav-height;
 	}

+ 7 - 1
src/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-status-bar.vue

@@ -9,7 +9,13 @@
 		name: 'UniStatusBar',
 		data() {
 			return {
-				statusBarHeight: uni.getSystemInfoSync().statusBarHeight + 'px'
+				// #ifdef MP-WEIXIN
+				statusBarHeight: uni.getWindowInfo().statusBarHeight + 'px',
+				// #endif
+				// #ifndef MP-WEIXIN
+				statusBarHeight: uni.getSystemInfoSync().statusBarHeight + 'px',
+				// #endif
+
 			}
 		}
 	}

+ 59 - 39
src/uni_modules/uni-nav-bar/package.json

@@ -1,7 +1,7 @@
 {
   "id": "uni-nav-bar",
   "displayName": "uni-nav-bar 自定义导航栏",
-  "version": "1.3.11",
+  "version": "1.3.17",
   "description": "自定义导航栏组件,主要用于头部导航。",
   "keywords": [
     "uni-ui",
@@ -11,12 +11,14 @@
 ],
   "repository": "https://github.com/dcloudio/uni-ui",
   "engines": {
-    "HBuilderX": ""
+    "HBuilderX": "",
+    "uni-app": "^4.07",
+    "uni-app-x": ""
   },
   "directories": {
     "example": "../../temps/example_temps"
   },
-"dcloudext": {
+  "dcloudext": {
     "sale": {
       "regular": {
         "price": "0.00"
@@ -34,51 +36,69 @@
       "permissions": "无"
     },
     "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
-    "type": "component-vue"
+    "type": "component-vue",
+    "darkmode": "x",
+    "i18n": "x",
+    "widescreen": "x"
   },
   "uni_modules": {
     "dependencies": [
-			"uni-scss",
-			"uni-icons"
-		],
+      "uni-scss",
+      "uni-icons"
+    ],
     "encrypt": [],
     "platforms": {
       "cloud": {
-        "tcb": "y",
-        "aliyun": "y"
+        "tcb": "x",
+        "aliyun": "x",
+        "alipay": "x"
       },
       "client": {
-        "App": {
-          "app-vue": "y",
-          "app-nvue": "y"
+        "uni-app": {
+          "vue": {
+            "vue2": "√",
+            "vue3": "√"
+          },
+          "web": {
+            "safari": "√",
+            "chrome": "√"
+          },
+          "app": {
+            "vue": "√",
+            "nvue": "√",
+            "android": "√",
+            "ios": "√",
+            "harmony": "√"
+          },
+          "mp": {
+            "weixin": "√",
+            "alipay": "√",
+            "toutiao": "√",
+            "baidu": "√",
+            "kuaishou": "-",
+            "jd": "-",
+            "harmony": "-",
+            "qq": "√",
+            "lark": "-"
+          },
+          "quickapp": {
+            "huawei": "√",
+            "union": "√"
+          }
         },
-        "H5-mobile": {
-          "Safari": "y",
-          "Android Browser": "y",
-          "微信浏览器(Android)": "y",
-          "QQ浏览器(Android)": "y"
-        },
-        "H5-pc": {
-          "Chrome": "y",
-          "IE": "y",
-          "Edge": "y",
-          "Firefox": "y",
-          "Safari": "y"
-        },
-        "小程序": {
-          "微信": "y",
-          "阿里": "y",
-          "百度": "y",
-          "字节跳动": "y",
-          "QQ": "y"
-        },
-        "快应用": {
-          "华为": "u",
-          "联盟": "u"
-        },
-        "Vue": {
-            "vue2": "y",
-            "vue3": "y"
+        "uni-app-x": {
+          "web": {
+            "safari": "-",
+            "chrome": "-"
+          },
+          "app": {
+            "android": "-",
+            "ios": "-",
+            "harmony": "-"
+          },
+          "mp": {
+            "weixin": "-"
+          }
         }
       }
     }

+ 2 - 0
src/uni_modules/uni-notice-bar/changelog.md

@@ -1,3 +1,5 @@
+## 1.2.3(2025-04-14)
+- 新增 左侧自定义插槽,可自定义文字或图标
 ## 1.2.2(2023-12-20)
 - 修复动态绑定title时,滚动速度不一致的问题
 ## 1.2.1(2022-09-05)

+ 15 - 23
src/uni_modules/uni-notice-bar/components/uni-notice-bar/uni-notice-bar.vue

@@ -1,26 +1,20 @@
 <template>
 	<view v-if="show" class="uni-noticebar" :style="{ backgroundColor }" @click="onClick">
-		<uni-icons v-if="showIcon === true || showIcon === 'true'" class="uni-noticebar-icon" type="sound"
-			:color="color" :size="fontSize * 1.5" />
-		<view ref="textBox" class="uni-noticebar__content-wrapper"
-			:class="{
+		<slot v-if="showIcon === true || showIcon === 'true'" name="noticebarIcon">
+			<uni-icons class="uni-noticebar-icon" type="sound" :color="color" :size="fontSize * 1.5" />
+		</slot>
+		<view ref="textBox" class="uni-noticebar__content-wrapper" :class="{
 				'uni-noticebar__content-wrapper--scrollable': scrollable,
 				'uni-noticebar__content-wrapper--single': !scrollable && (single || moreText)
-			}"
-			:style="{ height: scrollable ? fontSize * 1.5 + 'px' : 'auto' }"
-		>
-			<view :id="elIdBox" class="uni-noticebar__content"
-				:class="{
+			}" :style="{ height: scrollable ? fontSize * 1.5 + 'px' : 'auto' }">
+			<view :id="elIdBox" class="uni-noticebar__content" :class="{
 					'uni-noticebar__content--scrollable': scrollable,
 					'uni-noticebar__content--single': !scrollable && (single || moreText)
-				}"
-			>
-				<text :id="elId" ref="animationEle" class="uni-noticebar__content-text" 
-					:class="{
+				}">
+				<text :id="elId" ref="animationEle" class="uni-noticebar__content-text" :class="{
 						'uni-noticebar__content-text--scrollable': scrollable,
 						'uni-noticebar__content-text--single': !scrollable && (single || showGetMore)
-					}" 
-					:style="{
+					}" :style="{
 						color: color,
 						fontSize: fontSize + 'px',
 						lineHeight: fontSize * 1.5 + 'px',
@@ -31,12 +25,10 @@
 						'-webkit-animationPlayState': webviewHide ? 'paused' : animationPlayState,
 						animationDelay: animationDelay,
 						'-webkit-animationDelay': animationDelay
-					}"
-				>{{text}}</text>
+					}">{{text}}</text>
 			</view>
 		</view>
-		<view v-if="isShowGetMore" class="uni-noticebar__more uni-cursor-point"
-			@click="clickMore">
+		<view v-if="isShowGetMore" class="uni-noticebar__more uni-cursor-point" @click="clickMore">
 			<text v-if="moreText.length > 0" :style="{ color: moreColor, fontSize: fontSize + 'px' }">{{ moreText }}</text>
 			<uni-icons v-else type="right" :color="moreColor" :size="fontSize * 1.1" />
 		</view>
@@ -150,8 +142,8 @@
 				animationDelay: '0s'
 			}
 		},
-		watch:{
-			text:function(newValue,oldValue){
+		watch: {
+			text(newValue, oldValue) {
 				this.initSize();
 			}
 		},
@@ -160,8 +152,8 @@
 				return this.showGetMore === true || this.showGetMore === 'true'
 			},
 			isShowClose() {
-				return (this.showClose === true || this.showClose === 'true') 
-					&& (this.showGetMore === false || this.showGetMore === 'false')
+				return (this.showClose === true || this.showClose === 'true') &&
+					(this.showGetMore === false || this.showGetMore === 'false')
 			}
 		},
 		mounted() {

+ 7 - 4
src/uni_modules/uni-notice-bar/package.json

@@ -1,7 +1,7 @@
 {
   "id": "uni-notice-bar",
   "displayName": "uni-notice-bar 通告栏",
-  "version": "1.2.2",
+  "version": "1.2.3",
   "description": "NoticeBar 通告栏组件,常用于展示公告信息,可设为滚动公告",
   "keywords": [
     "uni-ui",
@@ -46,12 +46,15 @@
     "platforms": {
       "cloud": {
         "tcb": "y",
-        "aliyun": "y"
+        "aliyun": "y",
+        "alipay": "n"
       },
       "client": {
         "App": {
-          "app-vue": "y",
-          "app-nvue": "y"
+            "app-vue": "y",
+            "app-nvue": "y",
+            "app-harmony": "u",
+            "app-uvue": "u"
         },
         "H5-mobile": {
           "Safari": "y",

+ 8 - 0
src/uni_modules/uni-number-box/changelog.md

@@ -1,3 +1,11 @@
+## 1.2.8(2024-04-26)
+- 修复 在vue2下H5黑边的bug
+## 1.2.7(2024-04-26)
+- 修复 在vue2手动输入后失焦导致清空数值的严重bug
+## 1.2.6(2024-02-22)
+- 新增 设置宽度属性width(单位:px)
+## 1.2.5(2024-02-21)
+- 修复 step步长小于1时,键盘类型为number的bug
 ## 1.2.4(2024-02-02)
 - 修复 加减号垂直位置偏移样式问题
 ## 1.2.3(2023-05-23)

+ 19 - 8
src/uni_modules/uni-number-box/components/uni-number-box/uni-number-box.vue

@@ -1,12 +1,14 @@
 <template>
 	<view class="uni-numbox">
 		<view @click="_calcValue('minus')" class="uni-numbox__minus uni-numbox-btns" :style="{background}">
-			<text class="uni-numbox--text" :class="{ 'uni-numbox--disabled': inputValue <= min || disabled }" :style="{color}">-</text>
+			<text class="uni-numbox--text" :class="{ 'uni-numbox--disabled': inputValue <= min || disabled }"
+				:style="{color}">-</text>
 		</view>
-		<input :disabled="disabled" @focus="_onFocus" @blur="_onBlur" class="uni-numbox__value" type="number"
-			v-model="inputValue" :style="{background, color}" />
+		<input :disabled="disabled" @focus="_onFocus" @blur="_onBlur" class="uni-numbox__value"
+			:type="step<1?'digit':'number'" v-model="inputValue" :style="{background, color, width:widthWithPx}" />
 		<view @click="_calcValue('plus')" class="uni-numbox__plus uni-numbox-btns" :style="{background}">
-			<text class="uni-numbox--text" :class="{ 'uni-numbox--disabled': inputValue >= max || disabled }" :style="{color}">+</text>
+			<text class="uni-numbox--text" :class="{ 'uni-numbox--disabled': inputValue >= max || disabled }"
+				:style="{color}">+</text>
 		</view>
 	</view>
 </template>
@@ -21,6 +23,7 @@
 	 * @property {Number} step 每次点击改变的间隔大小
 	 * @property {String} background 背景色
 	 * @property {String} color 字体颜色(前景色)
+	 * @property {Number} width 输入框宽度(单位:px)
 	 * @property {Boolean} disabled = [true|false] 是否为禁用状态
 	 * @event {Function} change 输入框值改变时触发的事件,参数为输入框当前的 value
 	 * @event {Function} focus 输入框聚焦时触发的事件,参数为 event 对象
@@ -62,6 +65,10 @@
 			disabled: {
 				type: Boolean,
 				default: false
+			},
+			width: {
+				type: Number,
+				default: 40,
 			}
 		},
 		data() {
@@ -77,6 +84,11 @@
 				this.inputValue = +val;
 			}
 		},
+		computed: {
+			widthWithPx() {
+				return this.width + 'px';
+			}
+		},
 		created() {
 			if (this.value === 1) {
 				this.inputValue = +this.modelValue;
@@ -133,7 +145,7 @@
 				this.$emit('blur', event)
 				let value = event.detail.value;
 				if (isNaN(value)) {
-					this.inputValue = this.min;
+					this.inputValue = this.value;
 					return;
 				}
 				value = +value;
@@ -154,7 +166,7 @@
 		}
 	};
 </script>
-<style lang="scss" >
+<style lang="scss">
 	$box-height: 26px;
 	$bg: #f5f5f5;
 	$br: 2px;
@@ -188,8 +200,7 @@
 		height: $box-height;
 		text-align: center;
 		font-size: 14px;
-		border-left-width: 0;
-		border-right-width: 0;
+		border-width: 0;
 		color: $color;
 	}
 

+ 3 - 2
src/uni_modules/uni-number-box/package.json

@@ -1,7 +1,7 @@
 {
   "id": "uni-number-box",
   "displayName": "uni-number-box 数字输入框",
-  "version": "1.2.4",
+  "version": "1.2.8",
   "description": "NumberBox 带加减按钮的数字输入框组件,用户可以控制每次点击增加的数值,支持小数。",
   "keywords": [
     "uni-ui",
@@ -41,7 +41,8 @@
     "platforms": {
       "cloud": {
         "tcb": "y",
-        "aliyun": "y"
+        "aliyun": "y",
+        "alipay": "n"
       },
       "client": {
         "App": {

+ 26 - 0
src/uni_modules/uni-popup/changelog.md

@@ -1,3 +1,29 @@
+## 1.9.11(2025-08-20)
+- 修复 uni-popup-dialog组件设置 borderRadius 不生效的 Bug
+## 1.9.10(2025-07-18)
+- 修复 nvue 下弹窗样式错乱的问题 ,更新依赖 uni-transition 组件
+- 更新 示例取消 borderRadius 属性 ,如需内容圆角,用户应该直接在内容插槽中实现
+## 1.9.9(2025-06-11)
+- 修复 uni-popup-dialog 中 setVal 方法报错的问题
+- 修复 uni-popup-dialog 数据双向绑定问题。
+## 1.9.8(2025-04-16)
+- 修复 更新组件示例 ,解决更新数据或保存项目导致弹窗消失的问题
+## 1.9.7(2025-04-14)
+- 修复 uni-popup-dialog 弹出框在vue3中双向绑定问题
+## 1.9.6(2025-01-08)
+- 修复 示例中过期图片地址
+## 1.9.5(2024-10-15)
+- 修复 微信小程序中的getSystemInfo警告
+## 1.9.2(2024-09-21)
+- 修复 uni-popup在android上的重复点击弹出位置不正确的bug
+## 1.9.1(2024-04-02)
+- 修复 uni-popup-dialog vue3下使用value无法进行绑定的bug(双向绑定兼容旧写法)
+## 1.9.0(2024-03-28)
+- 修复 uni-popup-dialog 双向绑定时初始化逻辑修正
+## 1.8.9(2024-03-20)
+- 修复 uni-popup-dialog 数据输入时修正为双向绑定
+## 1.8.8(2024-02-20)
+- 修复 uni-popup 在微信小程序下出现文字向上闪动的bug
 ## 1.8.7(2024-02-02)
 - 新增 uni-popup-dialog 新增属性focus:input模式下,是否自动自动聚焦
 ## 1.8.6(2024-01-30)

+ 48 - 12
src/uni_modules/uni-popup/components/uni-popup-dialog/uni-popup-dialog.vue

@@ -1,5 +1,5 @@
 <template>
-	<view class="uni-popup-dialog">
+	<view class="uni-popup-dialog" :style="{ borderRadius }">
 		<view class="uni-dialog-title">
 			<text class="uni-dialog-title-text" :class="['uni-popup__'+dialogType]">{{titleText}}</text>
 		</view>
@@ -18,7 +18,7 @@
 			<view class="uni-dialog-button" v-if="showClose" @click="closeDialog">
 				<text class="uni-dialog-button-text">{{closeText}}</text>
 			</view>
-			<view class="uni-dialog-button uni-border-left" @click="onOk">
+			<view class="uni-dialog-button" :class="showClose?'uni-border-left':''" @click="onOk">
 				<text class="uni-dialog-button-text uni-button-color">{{okText}}</text>
 			</view>
 		</view>
@@ -61,7 +61,7 @@
 	export default {
 		name: "uniPopupDialog",
 		mixins: [popup],
-		emits: ['confirm', 'close'],
+		emits: ['confirm', 'close', 'update:modelValue', 'input'],
 		props: {
 			inputType: {
 				type: String,
@@ -71,10 +71,20 @@
 				type: Boolean,
 				default: true
 			},
+			// #ifdef VUE2
 			value: {
 				type: [String, Number],
 				default: ''
 			},
+			// #endif
+			// #ifdef VUE3
+			modelValue: {
+				type: [Number, String],
+				default: ''
+			},
+			// #endif
+
+
 			placeholder: {
 				type: [String, Number],
 				default: ''
@@ -111,9 +121,13 @@
 				type: Number,
 				default: -1,
 			},
-			focus:{
+			focus: {
 				type: Boolean,
 				default: true,
+			},
+		    borderRadius: {
+				type: String,
+				default: '11px',
 			}
 		},
 		data() {
@@ -146,11 +160,22 @@
 				}
 			},
 			value(val) {
-				if (this.maxlength != -1 && this.mode === 'input') {
-					this.val = val.slice(0, this.maxlength);
-				} else {
-					this.val = val
-				}
+				this.setVal(val)
+			},
+			// #ifdef VUE3
+			modelValue(val) {
+				this.setVal(val)
+			},
+			// #endif
+			val(val) {
+				// #ifdef VUE2
+				// TODO 兼容 vue2
+				this.$emit('input', val);
+				// #endif
+				// #ifdef VUE3
+				// TODO 兼容 vue3
+				this.$emit('update:modelValue', val);
+				// #endif
 			}
 		},
 		created() {
@@ -159,12 +184,25 @@
 			// this.popup.closeMask()
 			if (this.mode === 'input') {
 				this.dialogType = 'info'
-				this.val = this.value
+				this.val = this.value;
+				// #ifdef VUE3
+				this.val = this.modelValue;
+				// #endif
 			} else {
 				this.dialogType = this.type
 			}
 		},
 		methods: {
+			/**
+			 * 给val属性赋值
+			 */
+			setVal(val) {
+				if (this.maxlength != -1 && this.mode === 'input') {
+					this.val = val.slice(0, this.maxlength);
+				} else {
+					this.val = val
+				}
+			},
 			/**
 			 * 点击确认按钮
 			 */
@@ -174,7 +212,6 @@
 				} else {
 					this.$emit('confirm')
 				}
-				this.$emit("input",this.val);
 				if (this.beforeClose) return
 				this.popup.close()
 			},
@@ -196,7 +233,6 @@
 <style lang="scss">
 	.uni-popup-dialog {
 		width: 300px;
-		border-radius: 11px;
 		background-color: #fff;
 	}
 

+ 5 - 4
src/uni_modules/uni-popup/components/uni-popup-share/uni-popup-share.vue

@@ -39,24 +39,25 @@
 		},
 		data() {
 			return {
+				// TODO 替换为自己的图标
 				bottomData: [{
 						text: '微信',
-						icon: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/c2b17470-50be-11eb-b680-7980c8a877b8.png',
+						icon: 'https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/unicloudlogo.png',
 						name: 'wx'
 					},
 					{
 						text: '支付宝',
-						icon: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/d684ae40-50be-11eb-8ff1-d5dcf8779628.png',
+						icon: 'https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/unicloudlogo.png',
 						name: 'ali'
 					},
 					{
 						text: 'QQ',
-						icon: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/e7a79520-50be-11eb-b997-9918a5dda011.png',
+						icon: 'https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/unicloudlogo.png',
 						name: 'qq'
 					},
 					{
 						text: '新浪',
-						icon: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/0dacdbe0-50bf-11eb-8ff1-d5dcf8779628.png',
+						icon: 'https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/unicloudlogo.png',
 						name: 'sina'
 					},
 					// {

Некоторые файлы не были показаны из-за большого количества измененных файлов