From 6017f46b762663b9393cdae8422e0de1ed3db218 Mon Sep 17 00:00:00 2001
From: guifei zhu <guifeizhu@guifeideiMac.local>
Date: 星期三, 27 十一月 2024 13:30:06 +0800
Subject: [PATCH] 添加mqtt数据接口

---
 uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/index.js           |    8 
 uni_modules/uni-datetime-picker/components/uni-datetime-picker/time-picker.vue         |  940 +++++++++
 uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.vue            |  947 +++++++++
 mqtt/MqttView.vue                                                                      |  116 +
 uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hans.json       |   22 
 uni_modules/uni-datetime-picker/readme.md                                              |   21 
 uni_modules/uni-datetime-picker/changelog.md                                           |  168 +
 App.vue                                                                                |  106 
 colorui/main.css                                                                       |    7 
 common/constant.js                                                                     |   20 
 static/push/push_small_24.png                                                          |    0 
 store/index.js                                                                         |   28 
 uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hant.json       |   22 
 components/drop-down-menu/index.vue                                                    |  299 ++
 colorui/components/cu-custom.vue                                                       |   13 
 pages/tabBar/general.vue                                                               |   63 
 uni_modules/uni-datetime-picker/package.json                                           |   88 
 main.js                                                                                |   17 
 components/drop-down-menu/readme.txt                                                   |   12 
 dryuniapp.keystore                                                                     |    0 
 pages/me/analy.vue                                                                     |    2 
 static/image/pic_gzj.jpg                                                               |    0 
 pages/tabBar/me.vue                                                                    |   13 
 static/push/push_small_48.png                                                          |    0 
 uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar-item.vue       |  177 +
 pages/login/login.vue                                                                  |   41 
 pages.json                                                                             |   17 
 static/push/push_small_18.png                                                          |    0 
 pages/tabBar/device.vue                                                                |    7 
 static/push/push_small_72.png                                                          |    0 
 pages/tabBar/warning.vue                                                               |  755 +++++++
 uni_modules/uni-datetime-picker/components/uni-datetime-picker/util.js                 |  421 ++++
 common/loadshget.js                                                                    |    4 
 static/image/pic_gz.jpg                                                                |    0 
 uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/en.json            |   22 
 lib/mqttTool.js                                                                        |   22 
 manifest.json                                                                          |   74 
 package.json                                                                           |    3 
 components/drop-down-menu/dy-Date/dy-Date.vue                                          |  427 ++++
 mqtt/mqttTool.js                                                                       |  119 +
 components/drop-down-menu/dy-Date/用法示例.vue                                             |  160 +
 static/push/push_small_36.png                                                          |    0 
 uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue | 1064 ++++++++++
 43 files changed, 6,102 insertions(+), 123 deletions(-)

diff --git a/App.vue b/App.vue
index 93ab3b0..87c3ab4 100644
--- a/App.vue
+++ b/App.vue
@@ -1,10 +1,46 @@
 <script>
-	import Vue from 'vue'
+	import Vue from 'vue'
+
 	export default {
 		globalData: {
 			token: ""
 		},
 		onLaunch: function() {
+			 
+
+
+			//姝ゅ涓簎nipush2.0鐨勬帹閫佹柟娉�
+			// uni-app瀹㈡埛绔幏鍙杙ush瀹㈡埛绔爣璁�
+			// uni.getPushClientId({
+			// 	success: (res) => {
+			// 		let push_clientid = res.cid
+			// 		console.log('瀹㈡埛绔帹閫佹爣璇�:', push_clientid)
+			// 	},
+			// 	fail(err) {
+			// 		console.log(err)
+			// 	}
+			// })
+			// uni.onPushMessage((res) => {
+			// 	console.log("鏀跺埌鎺ㄩ�佹秷鎭細", res) //鐩戝惉鎺ㄩ�佹秷鎭�
+			// })
+
+
+			//鎺ㄩ�佷粎鏀寔Android ios鍘熺敓骞冲彴
+			// #ifdef APP-PLUS
+			console.log('APP-PLUS:')
+			// 姝ゅ涓簎nipush1.0鐨勬帹閫佹柟娉�
+			plus.push.getClientInfoAsync((info) => {
+				let cid = info["clientid"];
+				console.log('瀹㈡埛绔帹閫佹爣璇�:', cid)
+				this.$store.dispatch('setCid', cid); // 浣跨敤 action 鏇存柊 cid
+			});
+			// #endif
+			uni.onPushMessage((res) => {
+				console.log("鏀跺埌鎺ㄩ�佹秷鎭細", res) //鐩戝惉鎺ㄩ�佹秷鎭�
+			})
+
+
+
 			uni.getSystemInfo({
 				success: function(e) {
 					// #ifndef MP
@@ -32,42 +68,42 @@
 			console.log('App Launch')
 		},
 		onShow: function() {
-			 console.log('App Show')
-			 // this.conn()
-			 
+			console.log('App Show')
+			// this.conn()
+
 
 		},
 		onHide: function() {
-			 console.log('App Hide')
-			 // this.disconn()
-		},
-		methods:{
-			//澶勭悊鎺夌嚎閲嶈繛
-			conn(){
-				console.log(this.$mqttTool.client)
-				if(this.$mqttTool.client){
-					console.log(this.$mqttTool.client.connected)
-				}
-				if(this.$mqttTool.client && !this.$mqttTool.client.connected){
-					console.info("寮�濮嬮噸杩�")
-					this.$mqttTool.reconnect()
-				}else {
-					
-				}
-			},
-			disconn(){
-				console.log(this.$mqttTool.client)
-				if(this.$mqttTool.client){
-					console.log(this.$mqttTool.client.connected)
-				}
-				// if(this.$mqttTool.client){
-				// 	this.$mqttTool.end().then(res =>{
-				// 		console.log('缁堟锛�')
-				// 	})
-				
-				// }
-			}
-			
+			console.log('App Hide')
+			// this.disconn()
+		},
+		methods: {
+			//澶勭悊鎺夌嚎閲嶈繛
+			conn() {
+				console.log(this.$mqttTool.client)
+				if (this.$mqttTool.client) {
+					console.log(this.$mqttTool.client.connected)
+				}
+				if (this.$mqttTool.client && !this.$mqttTool.client.connected) {
+					console.info("寮�濮嬮噸杩�")
+					this.$mqttTool.reconnect()
+				} else {
+
+				}
+			},
+			disconn() {
+				console.log(this.$mqttTool.client)
+				if (this.$mqttTool.client) {
+					console.log(this.$mqttTool.client.connected)
+				}
+				// if(this.$mqttTool.client){
+				// 	this.$mqttTool.end().then(res =>{
+				// 		console.log('缁堟锛�')
+				// 	})
+
+				// }
+			}
+
 		},
 		mounted() {
 
@@ -80,4 +116,4 @@
 	@import "colorui/main.css";
 	@import "colorui/icon.css";
 	@import "uview-ui/index.scss";
-</style>
+</style>
\ No newline at end of file
diff --git a/colorui/components/cu-custom.vue b/colorui/components/cu-custom.vue
index b09f70d..c4c36cf 100644
--- a/colorui/components/cu-custom.vue
+++ b/colorui/components/cu-custom.vue
@@ -9,7 +9,11 @@
 				<view class="content" :style="[{top:StatusBar + 'px'}]">
 					<slot name="content"></slot>
 				</view>
-				<slot name="right"></slot>
+				<!-- <slot name="right"></slot> -->
+				<view class="right" @tap="HandleRight" v-if="isRight">
+					<text class="cuIcon-discover"></text>
+					<slot name="rihjtText"></slot>
+				</view>
 			</view>
 		</view>
 	</view>
@@ -44,6 +48,10 @@
 			isBack: {
 				type: [Boolean, String],
 				default: false
+			},
+			isRight: {
+				type: [Boolean, String],
+				default: false
 			},
 			bgImage: {
 				type: String,
@@ -55,6 +63,9 @@
 				uni.navigateBack({
 					delta: 1
 				});
+			},
+			HandleRight(){
+				 this.$emit('rightclick'); // 瑙﹀彂鑷畾涔変簨浠�
 			}
 		}
 	}
diff --git a/colorui/main.css b/colorui/main.css
index 838117d..f37eb4d 100644
--- a/colorui/main.css
+++ b/colorui/main.css
@@ -1494,7 +1494,12 @@
 	height: 100%;
 	justify-content: center;
 	max-width: 100%;
-}
+}
+	.cu-bar .right {
+		position: absolute;
+		 right: 30upx;
+		 font-size: 36upx;
+	}
 
 .cu-bar .action.border-title {
 	position: relative;
diff --git a/common/constant.js b/common/constant.js
index 5c7525c..7208477 100644
--- a/common/constant.js
+++ b/common/constant.js
@@ -22,6 +22,22 @@
 const DEVICE_ID = "device_id"
 
 
+/***********************鏈嶅姟绔箍鎾�********************************/
+//骞挎挱涓嶅湪涔庡鎴风id锛屽悜鏈夋墍鍦ㄧ嚎瀹㈡埛绔彂閫�
+//骞挎挱鍓嶇紑
+const SERVICE_BROADCAST = "service/broadcast"
+//  //鏈嶅姟绔悜鍚勭鎴峰鎴风鍙戦�佸疄鏃舵晠闅滃箍鎾�
+const SERVICE_BROADCAST_TENANT_REAL_FAULT = SERVICE_BROADCAST + "/real/fault/%s"
+
+
+
+
+/***********************EventBus function********************************/
+
+ const  MQTT_TOPIC_MESSAGE = "mqtt_topic_message"
+
+
+
 export default {
 	MOBILE_QUERY_EQU_STATU,
 	SERVICE_RES_EQU_STATU,
@@ -29,7 +45,9 @@
 	MOBILE_REQ_EQU_CMD,
 	SERVICE_RES_EQU_CMD,
 
-
+	SERVICE_BROADCAST_TENANT_REAL_FAULT,
+	
+	MQTT_TOPIC_MESSAGE,
 
 	DEVICE_ID
 }
\ No newline at end of file
diff --git a/common/loadshget.js b/common/loadshget.js
index 316ae41..cdd514c 100644
--- a/common/loadshget.js
+++ b/common/loadshget.js
@@ -1,6 +1,8 @@
 import get from 'lodash.get'
 
-export default function lget(data, item) {
+export default function lget(data, item) {
+	if(!data || data == null) return "--";
+	if(data & (!item || item == null)) return data;
 	let res  =  get(data, item)
 	return res == null ? "--" :res 
 
diff --git a/components/drop-down-menu/dy-Date/dy-Date.vue b/components/drop-down-menu/dy-Date/dy-Date.vue
new file mode 100644
index 0000000..e7f703d
--- /dev/null
+++ b/components/drop-down-menu/dy-Date/dy-Date.vue
@@ -0,0 +1,427 @@
+<template>
+	<view>
+		<picker :title="index" @change="bindTimeChange" @columnchange="columnchange" mode="multiSelector" :disabled="disabled" :class="{disabled:disabled}"
+		 :value="index" :range="array">
+			<view :style="{'line-height':inputHeight+'rpx','font-size':inputFont+'rpx'}" v-if="showTime">{{showTime}}
+			</view>
+			<view v-else class="placeholder" :style="{'line-height':inputHeight+'rpx','font-size':inputFont+'rpx'}">{{placeholder}}</view>
+		</picker>
+	</view>
+	<!-- 鍙 -->
+</template>
+
+<script>
+	export default {
+		name: 'dy-Date-Picker',
+		props: {
+			timeType: {
+				type: String,
+				default: () => 'day'
+			},
+			// 杈撳叆妗嗛珮搴�/琛岄珮
+			inputHeight:{
+				type: Number,
+				default:56
+			},
+			// 杈撳叆妗嗛珮搴�/鎻愮ず璇瓧浣撳ぇ灏�
+			inputFont:{
+				type: Number,
+				default:24
+			},
+			disabled: {
+				type: Boolean,
+				default: () => false
+			},
+			// 鏄惁鏄剧ず鍥炬爣
+			iconshow: {
+				type: Boolean,
+				default: () => true
+			},
+			placeholder: {
+				type: String,
+				default () {
+					return '璇烽�夋嫨'
+				}
+			},
+			childValue: {
+				default () {
+					return ''
+				}
+			},
+			minSelect: {
+				type: String,
+				default: () => '1900/01/01'
+			},
+			maxSelect: {
+				type: String,
+				default: () => '2050/12/31'
+			}
+		},
+		data() {
+			return {
+				index: [0],
+				array: [],
+				yearArr: [], // 骞翠唤鏁扮粍
+				monthArr: [], // 鏈堜唤鏁扮粍
+				yearIndex: 0, // 骞翠唤閫変腑涓嬫爣
+				showTime: this.moment(this.childValue)
+			}
+		},
+
+		methods: {
+			clear(){
+				this.showTime = ''
+				this.$emit('getData', '')
+			},
+			moment(strTime) {
+				let type = this.timeType
+				if (!strTime) {
+					return
+				}
+				let time = new Date(strTime)
+				let y = time.getFullYear()
+				let m = time.getMonth() + 1
+				m = m < 10 ? `0${m}` : m
+				let d = time.getDate()
+				d = d < 10 ? `0${d}` : d
+				let hh = time.getHours()
+				hh = hh < 10 ? `0${hh}` : hh
+				let mm = time.getMinutes()
+				mm = mm < 10 ? `0${mm}` : mm
+				let ss = time.getSeconds()
+				ss = ss < 10 ? `0${ss}` : ss
+				let value = `${y}/${m}/${d} ${hh}:${mm}:${ss}`
+				if (type === 'year') {
+					value = `${y}`
+				}
+				if (type === 'month') {
+					value = `${y}-${m}`
+				}
+				if (type === 'day') {
+					value = `${y}-${m}-${d}`
+				}
+				return value
+			},
+			/**
+			 * [setDefaultValue 璁剧疆榛樿鍊糫
+			 */
+			setDefaultValue() {
+				let date = this.moment(new Date().getTime())
+				this.valueEchoed(date)
+			},
+			bindDateChange(e) {
+				this.childValue = e.target.value
+			},
+			dateInit() {
+				this.array = []
+				this.yearArr = []
+				this.monthArr = []
+				let minDate = this.moment(this.minSelect) || []
+				let maxDate = this.moment(this.maxSelect) || []
+				minDate = minDate ? minDate.split(' ') : ''
+				maxDate = maxDate ? maxDate.split(' ') : ''
+				minDate = minDate[0] ? minDate[0].split('-') : 1900
+				maxDate = maxDate[0] ? maxDate[0].split('-') : 2050
+				let type = this.timeType
+				let {
+					monthStar,
+					monthEnd
+				} = ''
+				let yearStar = minDate[0] ? parseInt(minDate[0]) : 1900
+				let yearEnd = maxDate[0] ? parseInt(maxDate[0]) : 2050
+				if (type === 'day') {
+					let dateStar = minDate[2] ? parseInt(minDate[2]) : 1
+					let dateEnd = maxDate[2] ? parseInt(maxDate[2]) : 31
+				}
+				if (type === 'month' || type === 'day') {
+					monthStar = minDate[1] ? parseInt(minDate[1]) : 1
+					monthEnd = maxDate[1] ? parseInt(maxDate[1]) : 12
+				}
+
+				for (let y = yearStar; y <= yearEnd; y++) {
+					let ytext = y < 10 ? `0${y}` : y
+					this.yearArr.push(`${ytext}骞碻)
+					if (type === 'month' || type === 'day') {
+						let mGroup = this.getMonthArr(
+							y,
+							yearStar,
+							yearEnd,
+							monthStar,
+							monthEnd,
+							type
+						)
+						mGroup.length && this.monthArr.push(mGroup)
+					}
+				}
+
+				this.array[0] = this.yearArr
+				
+				if (type === 'month' || type === 'day') {
+					this.array[1] = this.monthArr.length && this.monthArr[0]
+				}
+				if (type === 'day') {
+					this.array[2] = this.getDateArr(
+						parseInt(this.yearArr[0]),
+						parseInt(this.monthArr[0])
+					)
+				}
+			},
+
+			getMonthArr(y, yearStar, yearEnd, monthStar, monthEnd, type) {
+				let mGroup = []
+				let dateGroup = []
+				if (y === yearStar && y !== yearEnd) {
+					for (let m = monthStar; m <= 12; m++) {
+						let mtext = m < 10 ? `0${m}` : m
+						mGroup.push(`${mtext}鏈坄)
+					}
+				}
+
+				if (y === yearEnd && y !== yearStar) {
+
+					for (let m = 1; m <= monthEnd; m++) {
+						let mtext = m < 10 ? `0${m}` : m
+						mGroup.push(`${mtext}鏈坄)
+					}
+
+				}
+
+				if (y !== yearStar && y !== yearEnd) {
+					for (let m = 1; m <= 12; m++) {
+						let mtext = m < 10 ? `0${m}` : m
+						mGroup.push(`${mtext}鏈坄)
+					}
+				}
+
+				if (y === yearStar && y === yearEnd) {
+					for (let m = monthStar; m <= monthEnd; m++) {
+						let mtext = m < 10 ? `0${m}` : m
+						mGroup.push(`${mtext}鏈坄)
+					}
+				}
+				return mGroup
+			},
+			getDateArr(y, m) {
+				let minDate = this.moment(this.minSelect) || []
+				let maxDate = this.moment(this.maxSelect) || []
+				minDate = minDate.length && minDate.split('-')
+				maxDate = maxDate.length && maxDate.split('-')
+				let yearStar = minDate[0] ? parseInt(minDate[0]) : 1900
+				let yearEnd = maxDate[0] ? parseInt(maxDate[0]) : 2050
+				let monthStar = minDate[1] ? parseInt(minDate[1]) : 1
+				let monthEnd = maxDate[1] ? parseInt(maxDate[1]) : 12
+				let datearr = []
+				let maxnum = 30
+				let date31 = [1, 3, 5, 7, 8, 10, 12]
+				if (date31.includes(m)) {
+					maxnum = 31
+				}
+				// 鍒ゆ柇鏄钩骞磋繕鏄棸骞寸殑2鏈堜唤
+				if (m === 2) {
+					if (y % 400 == 0 || (y % 4 == 0 && y % 100 != 0)) {
+						maxnum = 29
+					} else {
+						maxnum = 28
+					}
+				}
+				let dateStar = minDate[2] ? parseInt(minDate[2]) : 1
+				let dateEnd = maxDate[2] ? parseInt(maxDate[2]) : maxnum
+				if (
+					(y !== yearEnd && y !== yearStar) ||
+					(y === yearStar && m !== monthStar && m !== monthEnd) ||
+					(y === yearEnd && m !== monthEnd && m !== monthStar) ||
+					(yearStar === yearEnd && m !== monthStar && m !== monthEnd) ||
+					(yearStar !== yearEnd && y === yearEnd && m !== monthEnd) ||
+					(y === yearStar && m !== monthStar && y < yearEnd)
+				) {
+
+					for (let d = 1; d <= maxnum; d++) {
+						let dtext = d < 10 ? `0${d}` : d
+						datearr.push(`${dtext}鏃)
+					}
+				}
+
+				if ((yearStar === yearEnd && y === yearStar && m === monthStar && m !== monthEnd) || (yearStar !== yearEnd && y ===
+						yearStar && m === monthStar)) {
+
+					for (let d = dateStar; d <= maxnum; d++) {
+						let dtext = d < 10 ? `0${d}` : d
+						datearr.push(`${dtext}鏃)
+					}
+				}
+
+				if ((y === yearEnd && m === monthEnd && m !== monthStar && yearStar === yearEnd) || (y === yearEnd && yearStar !==
+						yearEnd && m === monthEnd)) {
+
+					for (let d = 1; d <= dateEnd; d++) {
+						let dtext = d < 10 ? `0${d}` : d
+						datearr.push(`${dtext}鏃)
+					}
+				}
+
+				if (
+					y === yearStar &&
+					yearStar === yearEnd &&
+					m === monthStar &&
+					monthStar === monthEnd
+				) {
+
+					for (let d = dateStar; d <= dateEnd; d++) {
+						let dtext = d < 10 ? `0${d}` : d
+						datearr.push(`${dtext}鏃)
+					}
+				}
+				return datearr
+			},
+
+			bindTimeChange(e) {
+				let timeValue = ''
+				let indexArr = e.detail.value
+				let type = this.timeType
+				let year = parseInt(this.array[0][parseInt(indexArr[0]) || 0])
+				let month = ''
+				timeValue = year + ''
+				if (type === 'month' || type === 'day') {
+					let index = parseInt(indexArr[1]) || 0
+					index = index < 0 ? 0 : index
+					month = parseInt(this.array[1][index])
+					month = month < 10 ? `0${month}` : month
+					timeValue = `${timeValue}-${month}`
+				}
+				if (type === 'day') {
+					let dateindex = parseInt(indexArr[2]) || 0
+					dateindex = dateindex < 0 ? 0 : dateindex
+					let date = parseInt(this.array[2][dateindex])
+					date = date < 10 ? `0${date}` : date
+					timeValue = `${timeValue}-${date}`
+				}
+				this.showTime = timeValue
+				this.$emit('getData', timeValue)
+			},
+			// 褰撴椂鍙戠敓鏀瑰彉鏃� 鍔犺浇瀵瑰簲鐨勫垎閽熸暟缁�
+			columnchange(e) {
+				const minIndex = e.detail.value
+				const column = e.detail.column
+				let type = this.timeType
+				this.$set(this.index, column, minIndex)
+
+				if (column === 0) {
+					this.yearIndex = minIndex
+					if (type === 'month' || type === 'day') {
+						this.$set(this.array, 1, this.monthArr[minIndex])
+					}
+					if (type === 'day') {
+						let monthindex = this.index[1] || 0
+
+						let newDateArr = this.getDateArr(
+							parseInt(this.yearArr[minIndex]),
+							parseInt(this.monthArr[this.yearIndex][monthindex])
+						)
+						this.$set(this.array, 2, newDateArr)
+					}
+				}
+				if (column === 1 && type === 'day') {
+					let newDateArr = this.getDateArr(
+						parseInt(this.yearArr[this.yearIndex]),
+						parseInt(this.monthArr[this.yearIndex][minIndex])
+					)
+					this.$set(this.array, 2, newDateArr)
+				}
+			},
+			valueEchoed(defaultTime) {
+				this.index = [0]
+				if (this.childValue || defaultTime) {
+					let value = this.childValue || defaultTime
+					value = this.moment(value)
+					value = value.split('-')
+					let index =
+						this.array[0].findIndex(
+							item => parseInt(item) === parseInt(value[0])
+						) || 0
+						index = index === -1 ? 0 : index
+					this.index[0] = index
+					this.yearIndex = index
+					
+					let type = this.timeType
+					if (type === 'month' || type === 'day') {
+						this.array[1] = this.monthArr.length && this.monthArr[index]
+						const monthindex =
+							(this.array[1] && this.array[1].length &&
+								this.array[1].findIndex(
+									item => parseInt(item) === parseInt(value[1])
+								)) ||
+							0
+						this.index[1] = monthindex
+					}
+					if (type === 'day') {
+						let index0 = this.index[0] || 0
+						let index1 = this.index[1] || 0
+						index0 = index0 === -1 ? 0 : index0
+						index1 = index1 === -1 ? 0 : index1
+						let newDay = this.getDateArr(
+							parseInt(this.yearArr[index0]),
+							parseInt(this.monthArr[index0][index1])
+						)
+						this.getDateIndex(newDay)
+					}
+				}
+			},
+			getDateIndex(newDay) {
+				let defaultTime = this.moment(new Date().getTime())
+				let value = this.childValue || defaultTime
+				value = this.moment(value)
+				value = value.split('-')
+				this.array[2] = newDay
+				let dateindex =
+					this.array[2].findIndex(
+						item => parseInt(item) === parseInt(value[2])
+					) || 0
+				this.index[2] = dateindex
+			}
+		},
+
+		watch: {
+			// 鐩戞祴缁勪欢鏈�灏忛�夋嫨鑼冨洿鍙戠敓鏀瑰彉 鍒濆鍖栨棩鏈熸暟鎹�
+			minSelect() {
+				this.dateInit()
+				this.setDefaultValue()
+			},
+			// 鐩戞祴缁勪欢鏈�澶у彲閫夎寖鍥村彂鐢熸敼鍙� 鍒濆鍖栨棩鏈熸暟鎹�
+			maxSelect() {
+				this.dateInit()
+				this.setDefaultValue()
+			},
+			childValue() {
+				this.showTime = ''
+				this.showTime = this.moment(this.childValue)
+				this.dateInit()
+				this.setDefaultValue()
+			}
+		},
+		created() {
+			this.dateInit()
+			this.valueEchoed()
+			if (!this.childValue) {
+				this.setDefaultValue()
+			}
+		}
+	}
+</script>
+
+<style lang="less">
+	.tx_r {
+		line-height: 48px;
+		font-size: 15px;
+		font-weight: normal;
+		color: #848b9a;
+	}
+
+	.placeholder {
+		color: #b5b8c2;
+	}
+
+	.fa-angle-right {
+		font-size: 36rpx;
+		padding-left: 12rpx;
+	}
+</style>
diff --git "a/components/drop-down-menu/dy-Date/\347\224\250\346\263\225\347\244\272\344\276\213.vue" "b/components/drop-down-menu/dy-Date/\347\224\250\346\263\225\347\244\272\344\276\213.vue"
new file mode 100644
index 0000000..9528f24
--- /dev/null
+++ "b/components/drop-down-menu/dy-Date/\347\224\250\346\263\225\347\244\272\344\276\213.vue"
@@ -0,0 +1,160 @@
+<template>
+	<view class="content">
+		<div class="item filter_input">
+			<div class="lable">鏃ユ湡鏈熼棿锛�</div>
+			<view class="date_item">
+				<dyDatePicker placeholder="璧峰鏃ユ湡" :childValue="from" :minSelect="from_minSelect" :maxSelect="from_maxSelect"
+				 :iconshow="false" @getData="getFromData"></dyDatePicker>
+			</view>
+			<view class="filter_inputline"></view>
+			<view class="date_item">
+
+				<dyDatePicker placeholder="缁撴潫鏃ユ湡" :minSelect="to_minSelect" :childValue="to" :maxSelect="to_maxSelect" :iconshow="false"
+				 @getData="getToData"></dyDatePicker>
+			</view>
+		</div>
+		<div class="item">
+			<div class="lable">绂佹閫夋嫨锛�</div>
+			<dyDatePicker childValue="2019/08/08" :disabled="true" @getData="getData" placeholder="璇烽�夋嫨鏃ユ湡"></dyDatePicker>
+		</div>
+		<div class="item">
+			<div class="lable">鎸囧畾寮�濮嬨�佺粨鏉熸椂闂达細</div>
+			<dyDatePicker @getData="getData" placeholder="璇烽�夋嫨鏃ユ湡" minSelect="2018/08/23" maxSelect="2019/08/28"></dyDatePicker>
+		</div>
+		<div class="item">
+			<div class="lable">鎸囧畾鍊硷細</div>
+			<dyDatePicker @getData="getData" childValue="2019/08/08" placeholder="璇烽�夋嫨鏃ユ湡" minSelect="2000/01/01" maxSelect="2025/12/31"></dyDatePicker>
+		</div>
+		
+		<div class="item">
+			<div class="lable">閫夋嫨鏈堜唤锛�</div>
+			<dyDatePicker timeType="month" @getData="getData" placeholder="璇烽�夋嫨鏃ユ湡" minSelect="2000/01/01" maxSelect="2025/12/31"></dyDatePicker>
+		</div>
+		<div class="item">
+			<div class="lable">閫夋嫨骞翠唤锛�</div>
+			<dyDatePicker timeType="year" @getData="getData" placeholder="璇烽�夋嫨鏃ユ湡" minSelect="2000/01/01" maxSelect="2025/12/31"></dyDatePicker>
+		</div>
+	</view>
+</template>
+
+<script>
+	import dyDatePicker from '../../components/dy-Date/dy-Date.vue'
+	export default {
+		components: {
+			dyDatePicker
+		},
+		data() {
+			return {
+				from_minSelect: '1900/01/01',
+				from_maxSelect: '2050/12/31',
+				to_minSelect: '1900/01/01',
+				to_maxSelect: '2050/12/31',
+				from: '',
+				to: '',
+			}
+		},
+		onLoad() {
+
+		},
+		methods: {
+			/**
+			 * @param {to_minSelect|from}  to_minSelect缁撴潫鏃堕棿鐨勬渶灏忛�夋嫨鑼冨洿 from=>寮�濮嬫棩鏈�
+			 */
+			getFromData(time) {
+				this.to_minSelect = time
+				this.from = time
+			},
+			/**
+			 * @param {from_maxSelect|to} from_maxSelect=>寮�濮嬫棩鏈熷彲閫夋渶澶у彲閫夊�� to=> 缁撴潫鏃ユ湡
+			 */
+			getToData(time) {
+				this.from_maxSelect = time
+				this.to = time
+			},
+			getData() {
+				// 
+			}
+		}
+	}
+</script>
+
+<style lang="less" scoped>
+	* {
+		padding: 0px;
+		margin: 0 auto;
+		box-sizing: border-box;
+	}
+
+
+	.content {
+		text-align: center;
+
+		margin-top: 20px;
+		font-size: 24rpx;
+
+	}
+
+	.item {
+		box-sizing: border-box;
+		width: 100%;
+		height: 40px;
+		line-height: 40px;
+		background-color: #ffffff;
+		position: relative;
+		padding: 0px 10px 0px 100px;
+		margin-bottom: 10px;
+		text-align: right;
+	}
+
+	.item .lable {
+		position: absolute;
+		left: 10px;
+		top: 0px;
+		color: #333333;
+	}
+
+	uni-picker-view-column {
+		font-size: 24rpx;
+	}
+
+	.filter_input {
+		height: 92rpx;
+		padding-top: 10rpx;
+	}
+
+	.date_item {
+		float: left;
+		width: 240upx;
+		overflow: hidden;
+		display: inline-block;
+		text-align: center;
+		border: 1px solid #ececec;
+		height: 72rpx;
+		line-height: 72rpx;
+
+		// font-size: 28rpx;
+		&:last-child {
+			// float: right;
+		}
+
+		input {
+			height: 72rpx;
+
+			.uni-input-placeholder {
+				color: #b5b8c2;
+			}
+		}
+	}
+
+	.filter_inputline {
+		float: left;
+		margin: 0 4rpx;
+		line-height: 72rpx;
+
+		&:after {
+			content: '鈥�';
+			font-size: 28rpx;
+			color: #848b9a;
+		}
+	}
+</style>
diff --git a/components/drop-down-menu/index.vue b/components/drop-down-menu/index.vue
new file mode 100644
index 0000000..c5103e2
--- /dev/null
+++ b/components/drop-down-menu/index.vue
@@ -0,0 +1,299 @@
+<template>
+	<view class="dropdown">
+		<view class="item">
+			<view class="item-title">璁惧</view>
+			<view class="item-box">
+				<view v-for="(item,index) in menuList" :key="item.code" :class="['item-menu',item.ck?'active':'']"
+					@click="changeMenu(index)">{{item.name}}
+				</view>
+			</view>
+
+			<view class="item-title">鏃堕棿</view>
+			<view class="item-box">
+				<view v-for="(item,index) in dateList" :key="item.code"
+					:class="['item-menu',currentDate==index?'active':'']" @click="changeDate(index)">{{item.name}}
+				</view>
+			</view>
+			<view class="custom-date" v-if="currentDate==3">
+				<view class="custom-date-ipute">
+					<dyDatePicker placeholder="寮�濮嬫棩鏈�" :minSelect="from_minSelect" :maxSelect="from_maxSelect"
+						:iconshow="false" @getData="starteDate" ref="startDatePickerRef"></dyDatePicker>
+				</view>
+				<view class="custom-date-line"></view>
+				<view class="custom-date-ipute">
+					<dyDatePicker placeholder="缁撴潫鏃ユ湡" :minSelect="to_minSelect" 
+						:maxSelect="to_maxSelect" :iconshow="false" @getData="endDate" ref="endDatePickerRef">
+					</dyDatePicker>
+				</view>
+			</view>
+		</view>
+
+		<view class="dropdown-footer">
+			<view class="dropdown-footer-btn reset" @click="resetDropdown">閲嶇疆</view>
+			<view class="dropdown-footer-btn submit" @click="submitSelect">纭畾</view>
+		</view>
+	</view>
+</template>
+<script>
+	import dyDatePicker from '@/components/drop-down-menu/dy-Date/dy-Date.vue';
+	import dayjs from 'dayjs'
+	export default {
+		components: {
+			dyDatePicker
+		},
+		props: {
+			list: {
+				type: Array,
+				default: () => []
+			}
+		},
+		data() {
+			return {
+				menuList: [],
+				dateList: [{
+						code: 1,
+						name: '浠婂ぉ',
+						subDay: 0
+					},
+					{
+						code: 2,
+						name: '鏄ㄥぉ',
+						subDay: 1
+					},
+					{
+						code: 3,
+						name: '杩戜竴鍛�',
+						subDay: 7
+					},
+					{
+						code: 4,
+						name: '鑷畾涔夋椂闂�',
+						subDay: ''
+					}
+				],
+				from_minSelect: '1900/01/01',
+				from_maxSelect: '2050/12/31',
+				to_minSelect: '1900/01/01',
+				to_maxSelect: '2050/12/31',
+				currentDate: undefined,
+				selectData: {
+					menu: [],
+					startTime: undefined,
+					endTime: undefined
+				},
+
+			}
+		},
+		watch: {
+			list: {
+				handler(newVal, oldVal) {
+					this.init()
+				},
+				deep: true,
+				immediate: true
+			}
+		},
+	
+		methods: {
+			init() {
+				const menuList = JSON.parse(JSON.stringify(this.list));
+				menuList.forEach(item => item.ck = false);
+				this.menuList = menuList
+				const todayDate = dayjs().format('YYYY-MM-DD');
+				const beforeDate = dayjs().subtract(5, 'year').format('YYYY-MM-DD')
+				this.from_minSelect = beforeDate;
+				this.from_maxSelect = todayDate;
+				this.to_minSelect = beforeDate;
+				this.to_maxSelect = todayDate;
+				this.resetDropdown(false)
+			},
+			// change涓篺alse鏃朵笉鍙戦�� change浜嬩欢  浠呬粎閲嶇疆
+			resetDropdown(change=true) {
+				this.menuList.forEach(item => item.ck = false);
+				if (this.currentDate == 3) {
+					this.$refs.startDatePickerRef.clear();
+					this.$refs.endDatePickerRef.clear();
+				}
+				this.currentDate = 999;
+				this.initDate();
+				this.selectData.menu = [];
+				this.selectData.startTime = undefined;
+				this.selectData.endTime = undefined;
+				if(change){
+					this.$emit('reset', this.selectData);
+				}
+			},
+			submitSelect() {
+				if (this.currentDate == 3) {
+					if (!this.selectData.startTime || !this.selectData.endTime) {
+						uni.showToast({
+							icon: "none",
+							title: "寮�濮嬫棩鏈熷拰缁撴潫鏃ユ湡閮戒笉鑳戒负绌猴紒",
+							duration: 3000
+						})
+						return
+					};
+				};
+				this.$emit('change', this.selectData);
+			},
+			initDate() {
+				const todayDate = dayjs().format('YYYY-MM-DD');
+				const beforeDate = dayjs().subtract(5, 'year').format('YYYY-MM-DD')
+				this.from_minSelect = beforeDate;
+				this.from_maxSelect = todayDate;
+				this.to_minSelect = beforeDate;
+				this.to_maxSelect = todayDate
+			},
+			changeMenu(index) {
+				const handelItem = this.menuList[index].ck;
+				this.menuList[index].ck = !handelItem;
+				const checkList = [];
+				this.menuList.forEach(item => {
+					if (item.ck) {
+						checkList.push(item.code)
+					}
+				})
+				this.selectData.menu = checkList;
+			},
+			changeDate(index) {
+				this.currentDate = index;
+				if (index == 3) {
+					this.selectData.startTime = undefined;
+					this.selectData.endTime = undefined;
+					return
+				}
+				const todayDate = dayjs().format('YYYY-MM-DD');
+				const beforeDate = dayjs().subtract(this.dateList[index].subDay, 'day').format('YYYY-MM-DD')
+				this.selectData.startTime = beforeDate;
+				this.selectData.endTime = todayDate;
+			},
+			starteDate(val) {
+				if (this.selectData.endTime) {
+					const diffDate = dayjs(this.selectData.endTime).diff(val, 'day');
+					if (diffDate < 0) {
+						uni.showToast({
+							icon: "none",
+							title: "寮�濮嬫棩鏈熶笉鑳藉ぇ浜庣粨鏉熸棩鏈�",
+							duration: 3000
+						})
+						this.$refs.startDatePickerRef.clear();
+						return
+					}
+				}
+				this.selectData.startTime = val;
+			},
+			endDate(val) {
+				if (this.selectData.startTime) {
+					const diffDate = dayjs(val).diff(this.selectData.startTime, 'day');
+					if (diffDate < 0) {
+						uni.showToast({
+							icon: "none",
+							title: "缁撴潫鏃ユ湡涓嶈兘灏忎簬寮�濮嬫棩鏈�",
+							duration: 3000
+						})
+						this.$refs.endDatePickerRef.clear()
+						return
+					}
+				}
+				this.selectData.endTime = val;
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.dropdown {
+		;
+		padding: 32rpx 28rpx 48rpx 28rpx;
+		box-sizing: border-box;
+		background: #FFFFFF;
+		box-shadow: 0rpx 4rpx 12rpx 0rpx rgba(0, 0, 0, 0.15);
+		border-radius: 16rpx;
+
+		.item {
+			&-title {
+				font-size: 24rpx;
+				font-family: PingFangTC-Medium, PingFangTC;
+				font-weight: 600;
+				color: #000000;
+			}
+
+			&-box {
+				width: 100%;
+				display: flex;
+				flex-wrap: wrap;
+				 
+				margin-bottom: 32rpx;
+			}
+
+			&-menu {
+				box-sizing: border-box;
+				flex: 0 0 calc(33.33% - 32rpx);  
+				height: 56rpx;
+				background: #ECEDF3;
+				border-radius: 8rpx;
+				text-align: center;
+				line-height: 56rpx;
+		        margin:  24rpx 10rpx 0 20rpx;
+				font-size: 24rpx;
+				font-weight: 400;
+				color: #000000;
+			}
+
+			.active {
+				background: #0064FF;
+				color: #fff;
+
+			}
+		}
+
+		.custom-date {
+			display: flex;
+			align-items: center;
+
+			.custom-date-line {
+				width: 30rpx;
+				height: 2px;
+				background: #eee;
+				margin: 0 10rpx;
+			}
+
+			.custom-date-ipute {
+				border: 1px solid #0064FF;
+				width: 50%;
+				text-align: center;
+				height: 56rpx;
+				color: #0064FF;
+				border-radius: 8rpx;
+			}
+		}
+
+		&-footer {
+			display: flex;
+			justify-content: space-around;
+			align-items: center;
+			margin-top: 32rpx;
+
+			&-btn {
+				width: 298rpx;
+				height: 82rpx;
+				text-align: center;
+				border-radius: 12rpx;
+				font-weight: 500;
+				line-height: 82rpx;
+				font-size: 32rpx;
+			}
+
+			.reset {
+				border: 2rpx solid #0064FF;
+				color: #0064FF;
+			}
+
+			.submit {
+				color: #fff;
+				background: #0064FF;
+				border: 2rpx solid #0064FF;
+			}
+		}
+	}
+</style>
\ No newline at end of file
diff --git a/components/drop-down-menu/readme.txt b/components/drop-down-menu/readme.txt
new file mode 100644
index 0000000..9440bcb
--- /dev/null
+++ b/components/drop-down-menu/readme.txt
@@ -0,0 +1,12 @@
+鎻掍欢ID锛歡x-drop-down-menu
+淇敼鑷猽niapp 鎻掍欢甯傚満 銆奷rop-down-menu涓嬫媺鑿滃崟銆佸閫夛紝鑷畾涔夋棩鏈熻寖鍥撮�夋嫨銆�
+**渚濊禆dayjs锛岃npm  install  dayjs 銆�"dayjs": "^1.11.10"銆�
+
+Vue2	Vue3
+鈭�	     脳
+App	蹇簲鐢�	寰俊灏忕▼搴�	鏀粯瀹濆皬绋嬪簭	鐧惧害灏忕▼搴�	瀛楄妭灏忕▼搴�	QQ灏忕▼搴�
+app-vue app-nvue	鈭�	鈭�	鈭�	鈭�	鈭�	鈭�
+閽夐拤灏忕▼搴�	蹇墜灏忕▼搴�	椋炰功灏忕▼搴�	浜笢灏忕▼搴�
+鈭�	鈭�	鈭�	鈭�
+H5-Safari	Android Browser	寰俊娴忚鍣�(Android)	QQ娴忚鍣�(Android)	Chrome	IE	Edge	Firefox	PC-Safari
+鈭�	鈭�	鈭�	鈭�	鈭�	鈭�	鈭�	鈭�
\ No newline at end of file
diff --git a/dryuniapp.keystore b/dryuniapp.keystore
new file mode 100644
index 0000000..d106ac7
--- /dev/null
+++ b/dryuniapp.keystore
Binary files differ
diff --git a/lib/mqttTool.js b/lib/mqttTool.js
index 0dba4b4..bfc9cc9 100644
--- a/lib/mqttTool.js
+++ b/lib/mqttTool.js
@@ -113,28 +113,6 @@
 	})
 }
 
-//娑堟伅澶勭悊
-mqttTool.message = function(){
-	return new Promise((resolve, reject) => {
-		if(mqttTool.client == null){
-			resolve('鏈繛鎺�')
-			console.log('App_text' + ":unconnect 鏈繛鎺�")
-			return;
-		}
-		if(mqttTool.client != null && ! mqttTool.client.connected){
-			mqttTool.client.reconnect()
-		}
-		 
-		mqttTool.client.on('message', function(topic, message, buffer) {
-			console.info(topic)
-			console.info(message)
-			 setTimeout(() => {
-			      resolve({topic, message, buffer })
-			    }, 300)
-		})
-	 
-	})
-}
 
 
 
diff --git a/main.js b/main.js
index f1d37dd..00b379f 100644
--- a/main.js
+++ b/main.js
@@ -1,11 +1,16 @@
 import App from './App'
-import Vue from 'vue'
+import Vue from 'vue'
+
+import store from './store'; // 寮曞叆 Vuex store
 
 // 姝ゅ涓哄紩鐢ㄨ嚜瀹氫箟椤堕儴
 import cuCustom from './colorui/components/cu-custom.vue'
 Vue.component('cu-custom',cuCustom);
 import TnCustom from './components/TnCustom/TnCustom.vue'
 Vue.component('tn-custom', TnCustom)
+
+import MqttView from './mqtt/MqttView.vue'
+Vue.component('mqtt-view', MqttView)
 
 import uView from "uview-ui";
 Vue.use(uView);
@@ -26,8 +31,11 @@
 Vue.prototype.$lget = lget
 
 import mqttTool from './lib/mqttTool.js'
-Vue.prototype.$mqttTool = mqttTool
-
+Vue.prototype.$mqttTool = mqttTool
+
+
+const EventBus = new Vue();
+Vue.prototype.$eventBus = EventBus
  
 
 //鍏ㄥ眬鐩戞帶瀹氭椂鍣紙鍦ㄩ〉闈娇鐢ㄥ眬閮ㄥ畾鏃跺櫒浼氬嚭鐜版棤娉曞叧闂棶棰橈級
@@ -38,7 +46,8 @@
 Vue.config.productionTip = false
 App.mpType = 'app'
 
-const app = new Vue({
+const app = new Vue({
+	store, // 娉ㄥ叆 store
   ...App
 })
 app.$mount()
diff --git a/manifest.json b/manifest.json
index 69c265d..363f7d0 100644
--- a/manifest.json
+++ b/manifest.json
@@ -1,5 +1,5 @@
 {
-    "name" : "lbdry-uniapp",
+    "name" : "鏅鸿兘涓崏鑽共鐕ユ満",
     "appid" : "__UNI__1E83F66",
     "description" : "",
     "versionName" : "1.0.0",
@@ -17,7 +17,9 @@
             "delay" : 0
         },
         /* 妯″潡閰嶇疆 */
-        "modules" : {},
+        "modules" : {
+            "Push" : {}
+        },
         /* 搴旂敤鍙戝竷淇℃伅 */
         "distribute" : {
             /* android鎵撳寘閰嶇疆 */
@@ -38,41 +40,59 @@
                     "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
                     "<uses-feature android:name=\"android.hardware.camera\"/>",
                     "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
-                ]
+                ],
+                "targetSdkVersion" : 30,
+                "minSdkVersion" : 23
             },
             /* ios鎵撳寘閰嶇疆 */
-            "ios" : {},
+            "ios" : {
+                "dSYMs" : false
+            },
             /* SDK閰嶇疆 */
-            "sdkConfigs" : {},
+            "sdkConfigs" : {
+                "push" : {
+                    "unipush" : {
+                        "icons" : {
+                            "small" : {
+                                "ldpi" : "static/push/push_small_18.png",
+                                "mdpi" : "static/push/push_small_24.png",
+                                "hdpi" : "static/push/push_small_36.png",
+                                "xhdpi" : "static/push/push_small_48.png",
+                                "xxhdpi" : "static/push/push_small_72.png"
+                            }
+                        }
+                    }
+                }
+            },
             "icons" : {
                 "android" : {
-                    "hdpi" : "",
-                    "xhdpi" : "",
-                    "xxhdpi" : "",
-                    "xxxhdpi" : ""
+                    "hdpi" : "unpackage/res/icons/72x72.png",
+                    "xhdpi" : "unpackage/res/icons/96x96.png",
+                    "xxhdpi" : "unpackage/res/icons/144x144.png",
+                    "xxxhdpi" : "unpackage/res/icons/192x192.png"
                 },
                 "ios" : {
-                    "appstore" : "",
+                    "appstore" : "unpackage/res/icons/1024x1024.png",
                     "ipad" : {
-                        "app" : "",
-                        "app@2x" : "",
-                        "notification" : "",
-                        "notification@2x" : "",
-                        "proapp@2x" : "",
-                        "settings" : "",
-                        "settings@2x" : "",
-                        "spotlight" : "",
-                        "spotlight@2x" : ""
+                        "app" : "unpackage/res/icons/76x76.png",
+                        "app@2x" : "unpackage/res/icons/152x152.png",
+                        "notification" : "unpackage/res/icons/20x20.png",
+                        "notification@2x" : "unpackage/res/icons/40x40.png",
+                        "proapp@2x" : "unpackage/res/icons/167x167.png",
+                        "settings" : "unpackage/res/icons/29x29.png",
+                        "settings@2x" : "unpackage/res/icons/58x58.png",
+                        "spotlight" : "unpackage/res/icons/40x40.png",
+                        "spotlight@2x" : "unpackage/res/icons/80x80.png"
                     },
                     "iphone" : {
-                        "app@2x" : "",
-                        "app@3x" : "",
-                        "notification@2x" : "",
-                        "notification@3x" : "",
-                        "settings@2x" : "",
-                        "settings@3x" : "",
-                        "spotlight@2x" : "",
-                        "spotlight@3x" : ""
+                        "app@2x" : "unpackage/res/icons/120x120.png",
+                        "app@3x" : "unpackage/res/icons/180x180.png",
+                        "notification@2x" : "unpackage/res/icons/40x40.png",
+                        "notification@3x" : "unpackage/res/icons/60x60.png",
+                        "settings@2x" : "unpackage/res/icons/58x58.png",
+                        "settings@3x" : "unpackage/res/icons/87x87.png",
+                        "spotlight@2x" : "unpackage/res/icons/80x80.png",
+                        "spotlight@3x" : "unpackage/res/icons/120x120.png"
                     }
                 }
             },
diff --git a/mqtt/MqttView.vue b/mqtt/MqttView.vue
new file mode 100644
index 0000000..412d8bf
--- /dev/null
+++ b/mqtt/MqttView.vue
@@ -0,0 +1,116 @@
+<template>
+	<view>
+	</view>
+</template>
+
+<script>
+ 
+	export default {
+		name: 'MqttView',
+		data() {
+			return {
+
+			}
+		},
+		onReady() {
+			 
+		},
+		methods: {
+			initMqtt(){
+				uni.getSystemInfo({
+					success: (res) => {
+						let deviceId = res.deviceId
+						if (!deviceId) {
+							deviceId = 'mobile-' + this.tenantId + '-' + Date.parse(new Date())
+						}
+						uni.setStorageSync(this.$constant.DEVICE_ID, 'mobile-' + this.tenantId + '-' + res.deviceId);
+					}
+				})
+					this.startConnect();
+			},
+			 /* 杩炴帴MQTT */
+			 async startConnect() {
+			 	var _this = this
+			 	const account = uni.getStorageSync('account');
+			 	const deviceid = uni.getStorageSync(this.$constant.DEVICE_ID);
+			 
+			 	if (!account) {
+			 
+			 		return false
+			 	}
+			 	let opts = {
+			 		// #ifdef H5
+			 		url: 'ws://' + this.$api.mqttBaseUrl + ':8083/mqtt',
+			 		// #endif
+			 		// #ifdef APP-PLUS
+			 		url: 'wx://' + this.$api.mqttBaseUrl + ':8083/mqtt',
+			 		// #endif
+			 		clientId: deviceid,
+			 		username: account.username,
+			 		password: account.password
+			 	}
+			 	if (!this.$mqttTool.client) {
+			 		var client = await this.$mqttTool.connect(opts);
+			 	}
+			 	//璁㈤槄鏌ヨ璁惧鐘舵�佽繑鍥炴暟鎹�
+			 	this.$mqttTool.subscribe({
+			 		topic: this.$constant.SERVICE_DOWN + '/' + deviceid + '/#',
+			 		qos: 0
+			 	}).then(res => {
+			 		console.error(res)
+			 	})
+			  
+			 	//璁㈤槄璁惧鏁呴殰骞挎挱锛堝箍鎾笉鍦ㄤ箮瀹㈡埛绔痠d锛屽彂閫佺粰绉熸埛涓嬫墍鏈夊湪绾跨殑璁惧锛�
+			 	this.$mqttTool.subscribe({
+			 		topic: this.$constant.SERVICE_BROADCAST_TENANT_REAL_FAULT.replace('%s', this.tenantId),
+			 		qos: 0
+			 	}).then(res => {
+			 		console.error(res)
+			 	})
+			 	//璁㈤槄鍙戦�佹寚浠よ繑鍥炵粨鏋�
+			 	// this.$mqttTool.subscribe({
+			 	// 	topic: this.$constant.SERVICE_RES_EQU_CMD,
+			 	// 	qos: 0
+			 	// }).then(res => {
+			 	// 	console.error(res)
+			 	// })
+			 	// if (!client) {
+			 	// 	return false
+			 	// }
+				let that = this
+			 
+			 	client.on('connect', function(res) {
+			 		console.error('杩炴帴鎴愬姛')
+			 	})
+			 	client.on('reconnect', function(res) {
+			 		console.error('閲嶆柊杩炴帴')
+			 	})
+			 	client.on('error', function(res) {
+			 		console.info('杩炴帴閿欒')
+			 	})
+			 	client.on('close', function(res) {
+			 
+			 		console.error('鍏抽棴鎴愬姛')
+			 
+			 	})
+			 	client.on('message', function(topic, message, buffer) {
+					that.$eventBus.$emit(that.$constant.MQTT_TOPIC_MESSAGE, message);
+			 		console.info(message)
+				
+			 	})
+			 },
+		},
+		computed: {
+			tenantId() {
+				const userinfo = uni.getStorageSync('userinfo');
+				const tenantid = userinfo.loginTenantId
+				return tenantid;
+			}
+
+		}
+	}
+</script>
+
+<style>
+
+</style>
\ No newline at end of file
diff --git a/mqtt/mqttTool.js b/mqtt/mqttTool.js
new file mode 100644
index 0000000..bfc9cc9
--- /dev/null
+++ b/mqtt/mqttTool.js
@@ -0,0 +1,119 @@
+/* main.js 椤圭洰涓诲叆鍙f敞鍏ュ疄渚� */
+// import mqttTool from './lib/mqttTool.js'
+// Vue.prototype.$mqttTool = mqttTool
+
+/* 浣跨敤鑼冧緥瑙� /pages/index/index.vue */
+// mqtt鍗忚锛欻5浣跨敤ws/wss APP-PLUS浣跨敤wx/wxs
+
+var mqtt = require('mqtt/dist/mqtt.js')
+
+//瀹㈡埛绔�
+let mqttTool = {
+	client: null
+}
+
+//杩炴帴鎭�
+mqttTool.connect = function(params){
+	let options = {
+		clientId: params.clientId,
+		username: params.username,
+		password: params.password,
+		clean: true,
+		keepalive:10,  //蹇冭烦 鍗曚綅锛歴
+		connectTimeout: 10*1000, //杩炴帴瓒呮椂 鍗曚綅锛歮s
+		cleanSession: true
+	}
+	let client = mqtt.connect(params.url, options);
+	mqttTool.client = client
+	return client;
+}
+
+mqttTool.end = function(){
+	return new Promise((resolve, reject) => {
+		if(mqttTool.client == null){
+			resolve('鏈繛鎺�')
+			console.log('App_text' + ":end 鏈繛鎺�")
+			return;
+		}
+		mqttTool.client.end()
+		mqttTool.client = null
+		resolve('杩炴帴缁堟')
+	})
+}
+
+mqttTool.reconnect = function(){
+	return new Promise((resolve, reject) => {
+		if(mqttTool.client == null){
+			resolve('鏈繛鎺�')
+			console.log('App_text' + ":reconnect 鏈繛鎺�")
+			return;
+		}
+		mqttTool.client.reconnect()
+	})
+}
+
+mqttTool.subscribe = function(params){
+	return new Promise((resolve, reject) => {
+		if(mqttTool.client == null){
+			resolve('鏈繛鎺�')
+			console.log('App_text' + ":unconnect 鏈繛鎺�")
+			return;
+		}
+		mqttTool.client.subscribe(params.topic, {qos:params.qos}, function(err,res) {
+			console.log(err,res)
+			if (!err && res.length>0) {
+				resolve('璁㈤槄鎴愬姛')
+				console.log('App_text' + ":subscribe success 璁㈤槄鎴愬姛")
+			}else{
+				resolve('璁㈤槄澶辫触')
+				console.log('App_text' + ":subscribe failed 璁㈤槄澶辫触")
+				return;
+			} 
+		})  
+	})
+}
+
+mqttTool.unsubscribe = function(params){
+	return new Promise((resolve, reject) => {
+		if(mqttTool.client == null){
+			resolve('鏈繛鎺�')
+			console.log('App_text' + ":unconnect 鏈繛鎺�")
+			return;
+		}
+		mqttTool.client.unsubscribe(params.topic, function(err) {
+			if (!err) {
+				resolve('鍙栨秷璁㈤槄鎴愬姛')
+				console.log('App_text' + ":unsubscribe success 鍙栨秷璁㈤槄鎴愬姛")
+			}else{
+				resolve('鍙栨秷璁㈤槄澶辫触')
+				console.log('App_text' + ":unsubscribe failed 鍙栨秷璁㈤槄澶辫触")
+				return;
+			} 
+		})  
+	})
+}
+
+mqttTool.publish = function(params){
+	return new Promise((resolve, reject) => {
+		if(mqttTool.client == null){
+			resolve('鏈繛鎺�')
+			console.log('App_text' + ":unconnect 鏈繛鎺�")
+			return;
+		}
+		mqttTool.client.publish(params.topic, params.message, function(err){
+			if (!err) {
+				resolve(params.topic + '-' + params.message + '-鍙戦�佹垚鍔�')
+				console.log('App_text' + ":publish success 鍙戦�佹垚鍔�")
+			}else{
+				resolve(params.topic + '-' + params.message + '-鍙戦�佸け璐�')
+				console.log('App_text' + ":publish failed 鍙戦�佸け璐�")
+				return;
+			} 
+		})
+	})
+}
+
+
+
+
+export default mqttTool
diff --git a/package.json b/package.json
index 28b8caf..2a9c5c5 100644
--- a/package.json
+++ b/package.json
@@ -12,6 +12,7 @@
 	"dependencies": {
 		"ezuikit-js": "^0.7.2",
 		"lodash.get": "^4.4.2",
-		"mqtt": "^3.0.0"
+		"mqtt": "^3.0.0",
+		"dayjs": "^1.11.10"
 	}
 }
diff --git a/pages.json b/pages.json
index 557c06b..611c480 100644
--- a/pages.json
+++ b/pages.json
@@ -76,7 +76,7 @@
 			}
 
 		}, {
-			"path": "pages/tabBar/analy",
+			"path": "pages/me/analy",
 			"style": {
 				"navigationStyle": "custom"
 			}
@@ -123,6 +123,16 @@
 					"titleNView": false
 				}
 			}
+		},
+		{
+			"path" : "pages/tabBar/warning",
+			"style" : 
+			{
+				"navigationStyle": "custom",
+				"app-plus": {
+					"titleNView": false
+				}
+			}
 		},
 		{
 			"path" : "pages/device/control",
@@ -134,6 +144,7 @@
 				}
 			}
 		}
+		 
 	],
 	"globalStyle": {
 		"navigationBarTextStyle": "white",
@@ -158,10 +169,10 @@
 			"selectedIconPath": "static/tabBar/shop_cur.png",
 			"text": "鐩戞帶"
 		}, {
-			"pagePath": "pages/tabBar/analy",
+			"pagePath": "pages/tabBar/warning",
 			"iconPath": "static/tabBar/analy.png",
 			"selectedIconPath": "static/tabBar/analy_cur.png",
-			"text": "鍒嗘瀽"
+			"text": "鎶ヨ"
 		}, {
 			"pagePath": "pages/tabBar/formula",
 			"iconPath": "static/tabBar/order.png",
diff --git a/pages/login/login.vue b/pages/login/login.vue
index d1539e1..c12de54 100644
--- a/pages/login/login.vue
+++ b/pages/login/login.vue
@@ -51,7 +51,7 @@
 						trigger: ['blur', 'change']
 					},
 				},
-				 
+
 			};
 		},
 		onLoad() {
@@ -59,17 +59,41 @@
 			if (account) {
 				this.model = account
 			}
+			let _that = this
+			// uni-app瀹㈡埛绔幏鍙杙ush瀹㈡埛绔爣璁�
+			// uni.getPushClientId({
+			// 	success: (res) => {
+			// 		let push_clientid = res.cid
+			// 		_that.model.username  = push_clientid
+			// 		console.log('瀹㈡埛绔帹閫佹爣璇�:', push_clientid)
+			// 	},
+			// 	fail(err) {
+			// 		_that.model.username  = err
+			// 		console.log(err)
+			// 	}
+			// })
+
+			// uni.onPushMessage((res) => {
+			// 	_that.model.username  = JSON.stringify(res)
+			// 	console.log("鏀跺埌鎺ㄩ�佹秷鎭細", res) //鐩戝惉鎺ㄩ�佹秷鎭�
+			// })
+
+
 
 		},
+		computed: {
+			cid() {
+				return this.$store.getters.getCid; // 浣跨敤 getter 鑾峰彇 cid
+			},
+		},
+		methods: {
 
-		methods: {
-		 
 			forget() {
 				uni.navigateTo({
 					url: "/pages/tabBar/demo"
 				})
 			},
-			submit() {
+			submit() {
 				if (this.model.username.startsWith("http")) {
 					uni.setStorageSync('baseurl', this.model.username);
 					this.model.username = null
@@ -86,8 +110,8 @@
 			},
 			login() {
 				this.$api.login(this.model).then((res) => {
-					if (res.success) {
-						 
+					if (res.success) {
+
 
 						console.log('request success', res)
 						uni.showToast({
@@ -98,8 +122,9 @@
 
 						uni.setStorageSync('account', this.model);
 						uni.setStorageSync('userinfo', res.result.userInfo);
-						uni.setStorageSync('token', res.result.token);
-				 
+						uni.setStorageSync('token', res.result.token);
+
+
 
 						uni.switchTab({
 							url: '/pages/tabBar/general'
diff --git a/pages/tabBar/analy.vue b/pages/me/analy.vue
similarity index 97%
rename from pages/tabBar/analy.vue
rename to pages/me/analy.vue
index 34dda6a..b1033a6 100644
--- a/pages/tabBar/analy.vue
+++ b/pages/me/analy.vue
@@ -1,6 +1,6 @@
 <template>
 	<view>
-		<cu-custom bgColor="bg-gradual-blue" :isBack="false">
+		<cu-custom bgColor="bg-gradual-blue" :isBack="true">
 			<block slot="content">鐢熶骇璁板綍鍒嗘瀽</block>
 		</cu-custom>
 
diff --git a/pages/tabBar/device.vue b/pages/tabBar/device.vue
index faff43c..90fe27e 100644
--- a/pages/tabBar/device.vue
+++ b/pages/tabBar/device.vue
@@ -19,7 +19,7 @@
 							</view>
 							<view>
 								<text
-									class="text-gray margin-right-lg">{{new Date().toLocaleDateString().replace(/\//g, '-')}}</text>
+									class="text-gray margin-right-lg">{{curDate}}</text>
 							</view>
 
 						</view>
@@ -72,7 +72,9 @@
 							<view class="title text-cut">{{$lget(item,'name')}}</view>
 							<view class="flex title text-green text-sm">
 								<u-tag v-if="item.online" size="mini" text="鍦ㄧ嚎" type="success" plain plainFill></u-tag>
-								<u-tag v-else class="" size="mini" text="鍋滄満" type="error" plain plainFill></u-tag>
+								<u-tag v-else  size="mini" text="绂荤嚎" type="warning" plain plainFill></u-tag>
+								<u-tag v-if="item.online" class="margin-left-sm" size="mini" text="鍦ㄧ嚎" type="success" plain plainFill></u-tag>
+								<u-tag  v-else class="margin-left-sm" size="mini" text="鍋滄満" type="error" plain plainFill></u-tag>
 							</view>
 						</view>
 						<view class="right" style="min-width: 240rpx;">
@@ -128,6 +130,7 @@
 				loading: true,
 				// v-model缁戝畾鐨勮繖涓彉閲忎笉瑕佸湪鍒嗛〉璇锋眰缁撴潫涓嚜宸辫祴鍊硷紒锛侊紒
 				dataList: [],
+				curDate:uni.$u.timeFormat(new Date(), 'yyyy-mm-dd'),
 			}
 		},
 		methods: {
diff --git a/pages/tabBar/general.vue b/pages/tabBar/general.vue
index ae71ad0..4dd41df 100644
--- a/pages/tabBar/general.vue
+++ b/pages/tabBar/general.vue
@@ -11,9 +11,10 @@
 		 </view>
 		 
 		 -->
-		<cu-custom bgColor="bg-gradual-blue" :isBack="false">
-			<block slot="content">鏅鸿兘涓崏鑽共鐕ヨ澶囬厤濂楃郴缁�</block>
+		<cu-custom  bgColor="bg-gradual-blue" :isBack="false">
+			<block slot="content">鏅鸿兘涓崏鑽�</block>
 		</cu-custom>
+		<mqtt-view  ref="mqttView"></mqtt-view>
 		<u-toast ref="uToast"></u-toast>
 		<!-- 		<view class="card-box dynamic shadow cu-list menu">
 			<view class="title-box">
@@ -232,7 +233,7 @@
 				</view>
 				<u-line color="#f1f1f1" margin="15rpx 0 15rpx 0"></u-line>
 			</view>
-
+		
 		</view>
 		<!-- 
 		<view class="page-box" v-show="false">
@@ -277,11 +278,15 @@
 				</view>
 			</view>
 		</view> -->
+		
 	</view>
 </template>
 
 <script>
+ 
+
 	export default {
+	 
 		data() {
 			return {
 				list: [{
@@ -353,22 +358,30 @@
 		},
 		onShow() {
 			console.info('onShow')
+			uni.showTabBarRedDot({
+			    index: 2 // 鏄剧ず绗�2涓猼abbar椤癸紙绱㈠紩浠�0寮�濮嬶級鐨勭孩鐐�
+			});
 
 
 		},
+		mounted() {
+			 
+			 
+
+		},
 		onReady() {
-			const userinfo = uni.getStorageSync('userinfo');
-			const tenantid = userinfo.loginTenantId
-			uni.getSystemInfo({
-				success: (res) => {
-					let deviceId = res.deviceId
-					if (!deviceId) {
-						deviceId = 'mobile-' + tenantid + '-' + Date.parse(new Date())
-					}
-					uni.setStorageSync(this.$constant.DEVICE_ID, 'mobile-' + tenantid + '-' + res.deviceId);
-				}
-			})
-			this.startConnect();
+			this.$refs.mqttView.initMqtt()
+			
+			// uni.getSystemInfo({
+			// 	success: (res) => {
+			// 		let deviceId = res.deviceId
+			// 		if (!deviceId) {
+			// 			deviceId = 'mobile-' + this.tenantId + '-' + Date.parse(new Date())
+			// 		}
+			// 		uni.setStorageSync(this.$constant.DEVICE_ID, 'mobile-' + this.tenantId + '-' + res.deviceId);
+			// 	}
+			// })
+			// this.startConnect();
 
 
 
@@ -380,7 +393,11 @@
 
 
 		},
+		onLoad() {
+		
+		},
 		methods: {
+			 
 			/* 杩炴帴MQTT */
 			async startConnect() {
 				var _this = this
@@ -408,6 +425,14 @@
 				//璁㈤槄鏌ヨ璁惧鐘舵�佽繑鍥炴暟鎹�
 				this.$mqttTool.subscribe({
 					topic: this.$constant.SERVICE_DOWN + '/' + deviceid + '/#',
+					qos: 0
+				}).then(res => {
+					console.error(res)
+				})
+ 
+				//璁㈤槄璁惧鏁呴殰骞挎挱锛堝箍鎾笉鍦ㄤ箮瀹㈡埛绔痠d锛屽彂閫佺粰绉熸埛涓嬫墍鏈夊湪绾跨殑璁惧锛�
+				this.$mqttTool.subscribe({
+					topic: this.$constant.SERVICE_BROADCAST_TENANT_REAL_FAULT.replace('%s', this.tenantId),
 					qos: 0
 				}).then(res => {
 					console.error(res)
@@ -571,6 +596,14 @@
 
 
 
+		},
+		computed:{
+			tenantId(){
+				const userinfo = uni.getStorageSync('userinfo');
+				const tenantid = userinfo.loginTenantId
+				return   tenantid;
+			}
+			
 		}
 
 	}
diff --git a/pages/tabBar/me.vue b/pages/tabBar/me.vue
index 5b5377b..ec5bda3 100644
--- a/pages/tabBar/me.vue
+++ b/pages/tabBar/me.vue
@@ -130,7 +130,14 @@
 						<image src='../../static/me/icon/diannao.png' class='png' mode='aspectFit'></image>
 						<text class='text-lg margin-sm'>杩滅▼鎺у埗</text>
 					</button>
-				</view> -->
+				</view> -->
+				
+				<view class="cu-item">
+					<button class='content cu-btn' @click="itemClick('analy')">
+						<image src='../../static/me/icon/diannao.png' class='png' mode='aspectFit'></image>
+						<text class='text-lg margin-sm'>鍒嗘瀽</text>
+					</button>
+				</view> 
 				
 				
 				<view class="cu-item">
@@ -222,6 +229,10 @@
 					uni.navigateTo({
 						url:"/pages/me/video"
 					})
+				}else if(mode == 'analy'){
+					uni.navigateTo({
+						url:"/pages/me/analy"
+					})
 				}else if(mode == 'other'){
 					uni.navigateTo({
 						url:"/pages/tabBar/monitor"
diff --git a/pages/tabBar/warning.vue b/pages/tabBar/warning.vue
new file mode 100644
index 0000000..71ced45
--- /dev/null
+++ b/pages/tabBar/warning.vue
@@ -0,0 +1,755 @@
+<template>
+	<view class="app">
+		<cu-custom bgColor="bg-gradual-blue" :isBack="false" :isRight="true" @rightclick="rclick">
+			<block slot="content">鎶ヨ</block>
+
+		</cu-custom>
+		<u-notice-bar text="12:20:10 1杞﹂棿GM001鏈哄彴鐢垫満杩囨祦(鐢垫皵)鎶ヨ" mode="closable"></u-notice-bar>
+
+		<!--寮瑰嚭灞俿tart-->
+		<view style="width: 100%; position: absolute;z-index: 1000;top:300rpx;padding: 20rpx;" @touchmove.prevent >
+			<dropdown-menu v-show="filterMenuShow"@reset='resetMenu'  @change='changeMenu' :list='equList' ref='dropdownMenuRef'/>
+			
+		</view>
+		<view class="lock-page dropdown-mask" @touchmove.prevent @click.stop="1==1" v-if="filterMenuShow"></view>
+		
+		<!--寮瑰嚭灞俥nd-->
+
+		<view class="card-box dynamic shadow">
+			<view class="title-box margin-bottom-sm">
+				<view style="width: 100vw;" class="left justify-between">
+					<view class="flex align-center">
+						<uni-text class="cuIcon-titles text-blue"></uni-text>
+						<view class="title">鎬昏</view>
+					</view>
+					<view>
+						<text class="text-gray text-sm">2024-10-01 鑷� 2024-12-01</text>
+					</view>
+
+				</view>
+
+			</view>
+			<view class="flex flex-direction padding-xs">
+				<view class="flex">
+					<view class="flex-sub flex flex-direction">
+						<text class="text-df">鎶ヨ鎬绘暟</text>
+						<text class="text-bold text-sl margin-top-xs text-red margin-top-sm">10
+							<text class="text-gray text-sm margin-left-xs">娆�</text></text>
+
+					</view>
+					<view class="flex-twice flex flex-direction justify-between">
+						<view class="flex-sub flex">
+							<view class="flex flex-direction flex-sub">
+								<text class="text-gray text-xs">鎶ヨ淇℃伅</text>
+								<text class="text-black">
+									<text class="text-black">鏈烘鏁呴殰:</text>
+									<text class="margin-lr-xs text-orange">0</text>
+									<text class="text-gray text-xs">娆�</text>
+								</text>
+
+							</view>
+							<view class="flex flex-direction flex-sub">
+								<text class="text-white text-xs">鐢垫皵鏁呴殰</text>
+								<text class="text-black">
+									<text class="text-black">鐢垫皵鏁呴殰:</text>
+									<text class="margin-lr-xs text-orange">1</text>
+									<text class="text-gray text-xs">娆�</text>
+								</text>
+
+							</view>
+
+						</view>
+						<view class="flex-sub flex margin-top-sm">
+							<view class="flex flex-direction flex-sub">
+								<text class="text-gray text-xs">鎶ヨ淇℃伅</text>
+								<text>
+									<text class="text-black">閫氫俊鏁呴殰:</text>
+									<text class="margin-lr-xs text-orange">4</text>
+									<text class="text-gray text-xs">娆�</text>
+								</text>
+
+							</view>
+							<view class="flex flex-direction flex-sub">
+								<text class="text-white text-xs">鍏朵粬鏁呴殰</text>
+								<text class="text-cyan">
+									<text class="text-black">鍏朵粬鏁呴殰:</text>
+									<text class="margin-lr-xs text-orange">5</text>
+									<text class="text-gray text-xs">娆�</text>
+								</text>
+							</view>
+
+						</view>
+
+					</view>
+
+				</view>
+				<view class="margin-top">
+					<u-scroll-list>
+
+					</u-scroll-list>
+
+				</view>
+
+			</view>
+
+
+
+		</view>
+
+		<u-sticky>
+			<view class="tab-box card-box top dynamic shadow">
+				<z-tabs ref="tabs" :active-style="{'font-size':'30rpx','font-weight':'bold'}" :current="tabCurrent"
+					:list="tabList" @change="tabsChange">
+					<!-- 鑷畾涔夊彸渚ф彃妲� -->
+					<!-- <template v-slot:right>
+						<u-icon name="setting"  ></u-icon>
+					</template> -->
+				</z-tabs>
+			</view>
+		</u-sticky>
+		<!-- 鍙�氳繃璁剧疆bar-animate-mode="worm"寮�鍚瘺姣涜櫕妯″紡-->
+		<swiper :style="'height:' + swiperItemHeight[tabCurrent] + 'rpx;'" :current="tabCurrent"
+			@transition="swiperTransition" @animationfinish="swiperAnimationfinish">
+			<swiper-item :key="0">
+				<view :style="'height:' + swiperItemHeight[0] + 'rpx;'">
+
+					<view class="card-box center dynamic shadow">
+						<view class="title-box margin-bottom-sm">
+							<view style="width: 100vw;" class="left justify-between">
+								<view class="flex align-center">
+									<uni-text class="cuIcon-titles text-blue"></uni-text>
+									<view class="title">璁惧 </view>
+								</view>
+								<view>
+									<!-- <text class="text-blue text-sm">鏇村></text> -->
+								</view>
+
+							</view>
+
+						</view>
+						<view class="borderTop">
+							<image style="width: 100%;border-radius: 20rpx; " src="../../static/image/pic_gz.jpg"
+								mode="aspectFit"></image>
+						</view>
+
+					</view>
+
+					<view class="card-box center dynamic shadow">
+						<view class="title-box margin-bottom-sm">
+							<view style="width: 100vw;" class="left justify-between">
+								<view class="flex align-center">
+									<uni-text class="cuIcon-titles text-blue"></uni-text>
+									<view class="title">瀹炴椂鎶ヨ </view>
+								</view>
+								<view>
+									<!-- <text class="text-blue text-sm">鏇村></text> -->
+								</view>
+
+							</view>
+
+						</view>
+						<view class="borderTop"  v-for="i in 10">
+							<view style="height: 180rpx;display: flex;align-items: center;">
+								<view>
+									<image style="width: 80rpx;height: 80rpx;margin:20rpx;border-radius: 20rpx; "
+										src="../../static/image/pic_gz.jpg"></image>
+								</view>
+								<view
+									style="display: flex;flex: 1;flex-direction: column; justify-content: space-between;  ;height: 100%;padding: 20rpx;">
+									<view class="text-bold">
+										婊氱瓛鐢垫満杩囨祦鎶ヨ
+									</view>
+									<view class="text-gray text-sm">
+										璁惧:1鍙峰共鐕ユ満
+									</view>
+
+									<view class="text-gray text-sm">
+										鎻忚堪:鍚屾祹鍫�1鍙锋粴绛掔數鏈鸿繃娴佹姤璀︼紝闇�瑕亁xxx澶勭悊锛屼笢鏂硅埅绌虹殑鎭㈠寰堝揩鐨勫洖澶�
+									</view>
+
+								</view>
+								<view style="width: 100rpx;">{{i}}</view>
+
+							</view>
+						</view>
+
+					</view>
+
+					<view class="card-box bot dynamic shadow">
+						<view style="height: 20rpx;"></view>
+					</view>
+				</view>
+			</swiper-item>
+			<swiper-item :key="1">
+				<view :style="'height:' + swiperItemHeight[1] + 'rpx;'">
+					<view class="card-box center dynamic shadow">
+						<view class="title-box margin-bottom-sm">
+							<view style="width: 100vw;" class="left justify-between">
+								<view class="flex align-center">
+									<uni-text class="cuIcon-titles text-blue"></uni-text>
+									<view class="title">鏈�杩戞姤璀�</view>
+								</view>
+								<view>
+									<text class="text-blue text-sm">鏇村></text>
+								</view>
+
+							</view>
+
+						</view>
+
+
+						<view class="borderTop">
+							<view class="h-table">
+								<view class="h-tr h-tr-2 ">
+									<view class="h-td">杞﹂棿</view>
+									<view class="h-td">鏈哄彴</view>
+									<view class="h-td">鏃堕棿</view>
+									<view class="h-td">绫诲瀷</view>
+									<view class="h-td">绛夌骇</view>
+
+
+								</view>
+								<view class="h-tr h-tr-2">
+									<view class="h-td">001</view>
+									<view class="h-td">GM001</view>
+									<view class="h-td">12:00:00</view>
+									<view class="h-td">鏈烘</view>
+									<view class="h-td">楂�</view>
+
+								</view>
+								<view class="h-tr h-tr-2">
+									<view class="h-td">001</view>
+									<view class="h-td">GM001</view>
+									<view class="h-td">12:00:00</view>
+									<view class="h-td">閫氫俊</view>
+									<view class="h-td">涓�</view>
+
+								</view>
+								<view class="h-tr h-tr-2">
+									<view class="h-td">001</view>
+									<view class="h-td">GM001</view>
+									<view class="h-td">12:00:00</view>
+									<view class="h-td">鐢垫皵</view>
+									<view class="h-td">楂�</view>
+
+								</view>
+							</view>
+
+						</view>
+
+
+					</view>
+
+					<view class="card-box center dynamic shadow">
+						<view class="title-box margin-bottom-sm">
+							<view style="width: 100vw;" class="left justify-between">
+								<view class="flex align-center">
+									<uni-text class="cuIcon-titles text-blue"></uni-text>
+									<view class="title">鎶ヨ缁熻</view>
+								</view>
+								<view>
+									<text class="text-gray text-sm"></text>
+								</view>
+
+							</view>
+
+						</view>
+
+
+						<view class="chartsMain">
+							<qiun-data-charts type="mount" :opts="opts" :animation="true" :chartData="Mount" />
+						</view>
+					</view>
+
+
+					<view class="card-box center dynamic shadow">
+						<view class="title-box margin-bottom-sm">
+							<view style="width: 100vw;" class="left justify-between">
+								<view class="flex align-center">
+									<uni-text class="cuIcon-titles text-blue"></uni-text>
+									<view class="title">鎶ヨ瀵规瘮</view>
+								</view>
+								<view>
+									<text class="text-gray text-sm"></text>
+								</view>
+
+							</view>
+
+						</view>
+
+						<view class="chartsMain">
+
+							<qiun-data-charts type="pie" :opts="optsPie" :chartData="PieA" />
+
+						</view>
+					</view>
+
+
+
+					<view class="card-box center dynamic shadow">
+						<view class="title-box margin-bottom-sm">
+							<view style="width: 100vw;" class="left justify-between">
+								<view class="flex align-center">
+									<uni-text class="cuIcon-titles text-blue"></uni-text>
+									<view class="title">鎶ヨ棰戠巼</view>
+								</view>
+								<view>
+									<text class="text-gray text-sm"></text>
+								</view>
+
+							</view>
+
+						</view>
+
+
+						<view class="chartsMain">
+							<!-- <qiun-data-charts type="mount" :opts="{extra:{mount:{type:'mount',widthRatio:1.5}}}"
+					:chartData="Mount" /> -->
+							<qiun-data-charts type="word" :chartData="Word" />
+						</view>
+					</view>
+
+					<view class="card-box bot dynamic shadow">
+						<view class="title-box margin-bottom-sm">
+							<view style="width: 100vw;" class="left justify-between">
+								<view class="flex align-center">
+									<uni-text class="cuIcon-titles text-blue"></uni-text>
+									<view class="title">鎶ヨ鍒嗘瀽</view>
+								</view>
+								<view>
+									<text class="text-gray text-sm"></text>
+								</view>
+
+							</view>
+
+						</view>
+
+
+						<view class="chartsMain">
+
+							<qiun-data-charts type="radar" :opts="optsRadar" :chartData="dataRadar" />
+						</view>
+					</view>
+
+
+				</view>
+			</swiper-item>
+		</swiper>
+
+
+	</view>
+</template>
+
+<script>
+	import dropdownMenu from '@/components/drop-down-menu/index.vue'
+	export default {
+		components: {
+			dropdownMenu
+		},
+		data() {
+			return {
+				equList: [{
+						code: 1,
+						name: '1#骞茬嚗鏈�'
+					},
+					{
+						code: 2,
+						name: '2#骞茬嚗鏈�'
+					} 
+				],
+				model: {},
+				filterMenuShow: false,
+				tabCurrent: 0,
+				swiperItemHeight: [2800, 2140],
+				tabList: [{
+					name: '瀹炴椂鎶ヨ',
+					badge: {
+						count: 6
+					}
+				}, {
+					name: '鎶ヨ缁熻',
+				}],
+				PieA: {
+					"series": [{
+						"data": [{
+							"name": "鏈烘",
+							"value": 50,
+							"labelText": "鏈烘:50娆�"
+						}, {
+							"name": "鐢垫皵",
+							"value": 30,
+							"labelText": "鐢垫皵:30娆�"
+						}, {
+							"name": "閫氫俊",
+							"value": 20,
+							"labelText": "閫氫俊:20娆�"
+						}, {
+							"name": "鍏朵粬",
+							"value": 18,
+							"labelText": "鍏朵粬:18娆�"
+						}]
+					}]
+				},
+				dataRadar: {
+
+					categories: ["鏈烘", "鐢垫皵", "閫氫俊", "鍏朵粬"],
+					series: [{
+						name: "鎶ヨ鍗犳瘮",
+						data: [99, 30, 18, 73]
+					}]
+
+				},
+
+				Mount: {
+					"series": [{
+
+						"data": [{
+							"name": "鏈烘",
+							"value": 82
+						}, {
+							"name": "鐢垫皵",
+							"value": 63
+						}, {
+							"name": "閫氫俊",
+							"value": 86
+						}, {
+							"name": "鍏朵粬",
+							"value": 65
+						}]
+					}]
+				},
+				Word: {
+					"series": [{
+						"name": "椋庢満杩囨祦",
+						"textSize": 25
+					}, {
+						"name": "鍚庨棬鏈叧闂�",
+						"textSize": 20
+					}, {
+						"name": "椋庣鍗囧紓甯�",
+						"textSize": 20
+					}, {
+						"name": "鐢垫満杩囨祦",
+						"textSize": 20
+					}, {
+						"name": "鍔犵儹浣嶄紶鎰熷櫒",
+						"textSize": 20
+					}, {
+						"name": "鍔犵儹鏃堕棿寮傚父",
+						"textSize": 20
+					}, {
+						"name": "婊氱瓛鍗囧紓甯�",
+						"textSize": 20
+					}, {
+						"name": "椋庣涓嶅湪鍔犵儹浣�",
+						"textSize": 20
+					}, {
+						"name": "婊氱瓛涓嶅湪鍔犵儹浣�",
+						"textSize": 10
+					}]
+				},
+				opts: {
+					color: ["#1890FF", "#91CB74", "#FAC858", "#EE6666", "#73C0DE", "#3CA272", "#FC8452", "#9A60B4",
+						"#ea7ccc"
+					],
+					padding: [15, 15, 0, 5],
+					enableScroll: false,
+					legend: {
+						show: true
+					},
+
+					xAxis: {
+						disableGrid: true
+					},
+					yAxis: {
+						gridColor: "rgba(230,230,230,0.6)",
+
+						data: [
+
+							{
+								min: 0
+							}
+						]
+					},
+					extra: {
+						mount: {
+							type: "bar",
+							widthRatio: 0.3,
+							borderWidth: 0,
+							barBorderRadius: [
+								50,
+								50,
+								50,
+								50
+							],
+							linearType: "custom"
+						}
+					}
+				},
+				optsPie: {
+					color: ["#1890FF", "#91CB74", "#FAC858", "#EE6666", "#73C0DE", "#3CA272", "#FC8452", "#9A60B4",
+						"#ea7ccc"
+					],
+					padding: [5, 5, 5, 5],
+					enableScroll: false,
+					extra: {
+						pie: {
+							activeOpacity: 0.5,
+							activeRadius: 10,
+							offsetAngle: 0,
+							labelWidth: 1,
+							border: true,
+							borderWidth: 3,
+							borderColor: "#FFFFFF",
+							linearType: "custom"
+						}
+					}
+				},
+				optsRadar: {
+					color: ["#1890FF", "#91CB74", "#FAC858", "#EE6666", "#73C0DE", "#3CA272", "#FC8452", "#9A60B4",
+						"#ea7ccc"
+					],
+					padding: [5, 5, 5, 5],
+					dataLabel: true,
+					dataPointShape: false,
+					enableScroll: false,
+					legend: {
+						show: false,
+						position: "right",
+						lineHeight: 25
+					},
+					extra: {
+						radar: {
+							gridType: "circle",
+							gridColor: "#CCCCCC",
+							gridCount: 3,
+							opacity: 1,
+							max: 100,
+							labelShow: true,
+							linearType: "custom",
+							border: false
+						}
+					}
+				},
+
+
+
+
+			}
+		},
+		computed: {
+
+
+		},
+		created() {
+			
+		},
+		beforeDestroy() {
+			
+		},
+		methods: {
+			mqttTopicMessage(){
+			//澶勭悊娑堟伅閫昏緫
+			switch(topic){
+				case _this.$constant.SERVICE_BROADCAST_TENANT_REAL_FAULT.replace('%s', that.tenantId):
+				   console.error(that.$constant.SERVICE_BROADCAST_TENANT_REAL_FAULT.replace('%s', that.tenantId))
+				   console.error("鏀跺埌骞挎挱")
+				   
+				break
+			}	
+			},
+			changeMenu(selectData){
+				console.info(selectData)
+				this.filterMenuShow = false
+				
+			 
+			},
+			resetMenu(selectData){
+				console.info(selectData)
+				 
+			},
+			rclick() {
+				this.filterMenuShow=!this.filterMenuShow
+			},
+			//tabs閫氱煡swiper鍒囨崲
+			tabsChange(index) {
+				this.tabCurrent = index;
+			},
+			//swiper婊戝姩涓�
+			swiperTransition(e) {
+				this.$refs.tabs.setDx(e.detail.dx);
+			},
+			//swiper婊戝姩缁撴潫
+			swiperAnimationfinish(e) {
+				this.tabCurrent = e.detail.current;
+				this.$refs.tabs.unlockDx();
+			},
+
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	@import "components/table/helang-table";
+
+	.app {
+		position: relative;
+	}
+
+	.card-box {
+		margin: 20rpx;
+		padding: 20rpx;
+		box-sizing: border-box;
+		background-color: white;
+		border-radius: 20rpx;
+		font-family: Helvetica Neue, Helvetica, sans-serif;
+
+	}
+
+
+	.top {
+		margin: 0 20rpx;
+		border-radius: 0;
+		border-top-left-radius: 20rpx;
+		border-top-right-radius: 20rpx;
+		border-bot-left-radius: 0;
+		border-bot-right-radius: 0;
+
+	}
+
+	.center {
+		margin: 0 20rpx;
+		border-radius: 0;
+
+	}
+
+	.bot {
+		margin: 0 20rpx 20rpx 20rpx;
+		border-top-left-radius: 0;
+		border-top-right-radius: 0;
+		border-bot-left-radius: 20rpx;
+		border-bot-right-radius: 20rpx;
+	}
+
+
+	.title-box {
+		display: flex;
+		flex-direction: row;
+		align-items: center;
+
+		.left {
+			display: flex;
+			align-items: center;
+
+			.title {
+				margin: 0 10rpx;
+				font-weight: bold;
+			}
+		}
+
+		.right {
+			display: flex;
+			align-items: center;
+
+			.title {
+				margin: 0 10rpx;
+				font-weight: bold;
+			}
+		}
+	}
+
+	.info-box {
+		margin-top: 20rpx;
+		display: flex;
+		flex-direction: row;
+		align-items: center;
+
+		.left {
+			display: flex;
+			align-items: center;
+
+			.title {
+				margin: 0 10rpx;
+			}
+		}
+
+		.right {
+			display: flex;
+			align-items: center;
+
+			.title {
+				margin: 0 10rpx;
+			}
+		}
+	}
+
+
+	.chartsMain {
+		width: 100%;
+		height: 320rpx;
+		padding-top: 15rpx;
+		background: #fff;
+		margin-bottom: 24rpx;
+		border-top: 2rpx solid #f2f2f2;
+
+		.charts {
+			width: 50%;
+			height: 450rpx;
+			box-sizing: border-box;
+		}
+	}
+
+	.tab-box {
+		display: flex;
+		justify-content: center;
+		/* 寮哄埗姘村钩灞呬腑 */
+	}
+
+	.swiper {
+		height: 2116rpx;
+	}
+
+	.swiper-item-view {
+		height: 2116rpx;
+
+
+	}
+
+
+
+
+
+
+
+	.picBox {
+		margin: 0 20rpx;
+		background-color: white;
+
+		image {
+			border-radius: 8rpx;
+			width: 100%;
+
+		}
+	}
+
+	.borderTop {
+		border-top: 2rpx solid #f2f2f2;
+		padding-top: 20rpx;
+	}
+
+	// 寮瑰嚭灞傝儗鏅伄缃﹕tart
+	.dropdown-mask {
+		background: rgba(0, 0, 0, 0.5);
+	}
+	.lock-page {
+		height: 100vh;
+		width: 100vw;
+		position: fixed;
+		top: 0;
+		left: 0;
+		right: 0;
+		bottom: 0;
+		z-index: 998;
+	}
+	// 寮瑰嚭灞傝儗鏅伄缃〆nd
+</style>
\ No newline at end of file
diff --git a/static/image/pic_gz.jpg b/static/image/pic_gz.jpg
new file mode 100644
index 0000000..ee8e04c
--- /dev/null
+++ b/static/image/pic_gz.jpg
Binary files differ
diff --git a/static/image/pic_gzj.jpg b/static/image/pic_gzj.jpg
new file mode 100644
index 0000000..e5ef9bb
--- /dev/null
+++ b/static/image/pic_gzj.jpg
Binary files differ
diff --git a/static/push/push_small_18.png b/static/push/push_small_18.png
new file mode 100644
index 0000000..d8723eb
--- /dev/null
+++ b/static/push/push_small_18.png
Binary files differ
diff --git a/static/push/push_small_24.png b/static/push/push_small_24.png
new file mode 100644
index 0000000..e9d9c81
--- /dev/null
+++ b/static/push/push_small_24.png
Binary files differ
diff --git a/static/push/push_small_36.png b/static/push/push_small_36.png
new file mode 100644
index 0000000..df0f698
--- /dev/null
+++ b/static/push/push_small_36.png
Binary files differ
diff --git a/static/push/push_small_48.png b/static/push/push_small_48.png
new file mode 100644
index 0000000..c1bab63
--- /dev/null
+++ b/static/push/push_small_48.png
Binary files differ
diff --git a/static/push/push_small_72.png b/static/push/push_small_72.png
new file mode 100644
index 0000000..1e7b7a8
--- /dev/null
+++ b/static/push/push_small_72.png
Binary files differ
diff --git a/store/index.js b/store/index.js
new file mode 100644
index 0000000..ef969c7
--- /dev/null
+++ b/store/index.js
@@ -0,0 +1,28 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+Vue.use(Vuex);
+ 
+const store = new Vuex.Store({
+  state: {
+	// 瀹氫箟cid榛樿鍊�
+    cid: null
+  },
+  mutations: {
+    setCid(state, cid) {
+          state.cid = cid;
+    },
+  },
+  actions: {
+    setCid({ commit }, cid) {
+         commit('setCid', cid);
+       },
+  },
+  getters: {
+   getCid(state) {  
+         return state.cid;  
+       }  
+  }
+});
+ 
+export default store;
+
diff --git a/uni_modules/uni-datetime-picker/changelog.md b/uni_modules/uni-datetime-picker/changelog.md
new file mode 100644
index 0000000..102ddb1
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/changelog.md
@@ -0,0 +1,168 @@
+## 2.2.38锛�2024-10-15锛�
+- 淇 寰俊灏忕▼搴忎腑鐨刧etSystemInfo璀﹀憡
+## 2.2.37锛�2024-10-12锛�
+- 淇 寰俊灏忕▼搴忎腑鐨刧etSystemInfo璀﹀憡
+## 2.2.36锛�2024-10-12锛�
+- 淇 寰俊灏忕▼搴忎腑鐨刧etSystemInfo璀﹀憡
+## 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锛�
+- 淇 鎶栭煶灏忕▼搴忎簨浠朵紶閫掑け鏁坆ug
+## 2.2.32锛�2024-02-20锛�
+- 淇 鏃ュ巻鐨刢lose浜嬩欢瑙﹀彂寮傚父鐨刡ug [璇︽儏](https://github.com/dcloudio/uni-ui/issues/844)
+## 2.2.31锛�2024-02-20锛�
+- 淇 h5骞冲彴 鍙宠竟鏃ュ巻鐨勬湀浠介粯璁�+1鐨刡ug [璇︽儏](https://github.com/dcloudio/uni-ui/issues/841)
+## 2.2.30锛�2024-01-31锛�
+- 淇 闅愯棌鈥滅鈥濇椂锛屽湪IOS15鍙婁互涓嬬増鏈椂鍑虹幇 缁撴潫鏃堕棿鍦ㄥ紑濮嬫椂闂翠箣鍓� 鐨刡ug [璇︽儏](https://github.com/dcloudio/uni-ui/issues/788)
+## 2.2.29锛�2024-01-20锛�
+- 鏂板 show浜嬩欢锛屽脊绐楀脊鍑烘椂瑙﹀彂璇ヤ簨浠� [璇︽儏](https://github.com/dcloudio/uni-app/issues/4694)
+## 2.2.28锛�2024-01-18锛�
+- 鍘婚櫎 noChange浜嬩欢锛屽綋杩涜鏃ユ湡鑼冨洿閫夋嫨鏃讹紝鑻ュ彧閫変簡涓�澶╋紝鍒欏紑濮嬬粨鏉熸棩鏈熼兘涓哄悓涓�澶� [璇︽儏](https://github.com/dcloudio/uni-ui/issues/815)
+## 2.2.27锛�2024-01-10锛�
+- 浼樺寲 澧炲姞noChange浜嬩欢锛屽綋杩涜鏃ユ湡鑼冨洿閫夋嫨鏃讹紝鑻ユ湁绌哄�硷紝鍒欒Е鍙戣浜嬩欢 [璇︽儏](https://github.com/dcloudio/uni-ui/issues/815)
+## 2.2.26锛�2024-01-08锛�
+- 淇 瀛楄妭灏忕▼搴忔椂闂撮�夋嫨鑼冨洿鍣ㄥけ鏁堥棶棰� [璇︽儏](https://github.com/dcloudio/uni-ui/issues/834)
+## 2.2.25锛�2023-10-18锛�
+- 淇 PC绔垵娆′慨鏀规椂闂达紝寮�濮嬫椂闂存湭鏇存柊鐨凚ug [璇︽儏](https://github.com/dcloudio/uni-ui/issues/737)
+## 2.2.24锛�2023-06-02锛�
+- 淇 閮ㄥ垎鎯呭喌淇敼鏃堕棿锛屽紑濮嬨�佺粨鏉熸椂闂存樉绀哄紓甯哥殑Bug [璇︽儏](https://ask.dcloud.net.cn/question/171146)
+- 浼樺寲 褰撳墠鏈堝彲浠ラ�夋嫨涓婃湀銆佷笅鏈堢殑鏃ユ湡鐨凚ug
+## 2.2.23锛�2023-05-02锛�
+- 淇 閮ㄥ垎鎯呭喌淇敼鏃堕棿锛屽紑濮嬫椂闂存湭鏇存柊鐨凚ug [璇︽儏](https://github.com/dcloudio/uni-ui/issues/737)
+- 淇 閮ㄥ垎骞冲彴鍙婅澶囩涓�娆$偣鍑绘棤娉曟樉绀哄脊妗嗙殑Bug
+- 淇 ios 鏃ユ湡鏍煎紡鏈ˉ闆舵樉绀哄強浣跨敤寮傚父鐨凚ug [璇︽儏](https://ask.dcloud.net.cn/question/162979)
+## 2.2.22锛�2023-03-30锛�
+- 淇 鏃ュ巻 picker 淇敼骞存湀鍚庯紝鑷姩閫変腑褰撴湀1鏃ョ殑Bug [璇︽儏](https://ask.dcloud.net.cn/question/165937)
+- 淇 灏忕▼搴忕 浣庣増鏈� ios NaN鐨凚ug [璇︽儏](https://ask.dcloud.net.cn/question/162979)
+## 2.2.21锛�2023-02-20锛�
+- 淇 firefox 娴忚鍣ㄦ樉绀哄尯鍩熺偣鍑绘棤娉曟媺璧锋棩鍘嗗脊妗嗙殑Bug [璇︽儏](https://ask.dcloud.net.cn/question/163362)
+## 2.2.20锛�2023-02-17锛�
+- 浼樺寲 鍊间负绌轰緷鐒堕�変腑褰撳ぉ闂
+- 浼樺寲 鎻愪緵 default-value 灞炴�ф敮鎸侀厤缃�夋嫨鍣ㄦ墦寮�鏃堕粯璁ゆ樉绀虹殑鏃堕棿
+- 浼樺寲 闈炶寖鍥撮�夋嫨鏈�夋嫨鏃ユ湡鏃堕棿锛岀偣鍑荤‘璁ゆ寜閽�変腑褰撳墠鏃ユ湡鏃堕棿
+- 浼樺寲 瀛楄妭灏忕▼搴忔棩鏈熸椂闂磋寖鍥撮�夋嫨锛屽簳閮ㄦ棩鏈熸崲琛岀殑Bug
+## 2.2.19锛�2023-02-09锛�
+- 淇 2.2.18 寮曡捣鑼冨洿閫夋嫨閰嶇疆 end 閫夋嫨鏃犳晥鐨凚ug [璇︽儏](https://github.com/dcloudio/uni-ui/issues/686)
+## 2.2.18锛�2023-02-08锛�
+- 淇 绉诲姩绔寖鍥撮�夋嫨change浜嬩欢瑙﹀彂寮傚父鐨凚ug [璇︽儏](https://github.com/dcloudio/uni-ui/issues/684)
+- 浼樺寲 PC绔緭鍏ユ棩鏈熸牸寮忛敊璇椂杩斿洖褰撳墠鏃ユ湡鏃堕棿
+- 浼樺寲 PC绔緭鍏ユ棩鏈熸椂闂磋秴鍑� start銆乪nd 闄愬埗鐨凚ug
+- 浼樺寲 绉诲姩绔棩鏈熸椂闂磋寖鍥寸敤娉曟椂闂村睍绀轰笉瀹屾暣闂
+## 2.2.17锛�2023-02-04锛�
+- 淇 灏忕▼搴忕缁戝畾 Date 绫诲瀷鎶ラ敊鐨凚ug [璇︽儏](https://github.com/dcloudio/uni-ui/issues/679)
+- 淇 vue3 time-picker 鏃犳硶鏄剧ず缁戝畾鏃跺垎绉掔殑Bug
+## 2.2.16锛�2023-02-02锛�
+- 淇 瀛楄妭灏忕▼搴忔姤閿欑殑Bug
+## 2.2.15锛�2023-02-02锛�
+- 淇 鏌愪簺鎯呭喌鍒囨崲鏈堜唤閿欒鐨凚ug
+## 2.2.14锛�2023-01-30锛�
+- 淇 鏌愪簺鎯呭喌鍒囨崲鏈堜唤閿欒鐨凚ug [璇︽儏](https://ask.dcloud.net.cn/question/162033)
+## 2.2.13锛�2023-01-10锛�
+- 淇 澶氭鍔犺浇缁勪欢閫犳垚鍐呭瓨鍗犵敤鐨凚ug
+## 2.2.12锛�2022-12-01锛�
+- 淇 vue3 涓� i18n 鍥介檯鍖栧垵濮嬪�间笉姝g‘鐨凚ug
+## 2.2.11锛�2022-09-19锛�
+- 淇 鏀粯瀹濆皬绋嬪簭鏍峰紡閿欎贡鐨凚ug [璇︽儏](https://github.com/dcloudio/uni-app/issues/3861)
+## 2.2.10锛�2022-09-19锛�
+- 淇 鍙嶅悜閫夋嫨鏃ユ湡鑼冨洿锛屾棩鏈熸樉绀哄紓甯哥殑Bug [璇︽儏](https://ask.dcloud.net.cn/question/153401?item_id=212892&rf=false)
+## 2.2.9锛�2022-09-16锛�
+- 鍙互浣跨敤 uni-scss 鎺у埗涓婚鑹�
+## 2.2.8锛�2022-09-08锛�
+- 淇 close浜嬩欢鏃犳晥鐨凚ug
+## 2.2.7锛�2022-09-05锛�
+- 淇 绉诲姩绔� maskClick 鏃犳晥鐨凚ug [璇︽儏](https://ask.dcloud.net.cn/question/140824)
+## 2.2.6锛�2022-06-30锛�
+- 浼樺寲 缁勪欢鏍峰紡锛岃皟鏁翠簡缁勪欢鍥炬爣澶у皬銆侀珮搴︺�侀鑹茬瓑锛屼笌uni-ui椋庢牸淇濇寔涓�鑷�
+## 2.2.5锛�2022-06-24锛�
+- 淇 鏃ュ巻椤堕儴骞存湀鍙婂簳閮ㄧ‘璁ゆ湭鍥介檯鍖栫殑Bug
+## 2.2.4锛�2022-03-31锛�
+- 淇 Vue3 涓嬪姩鎬佽祴鍊�,鍗曢�夌被鍨嬫湭鍝嶅簲鐨凚ug
+## 2.2.3锛�2022-03-28锛�
+- 淇 Vue3 涓嬪姩鎬佽祴鍊兼湭鍝嶅簲鐨凚ug
+## 2.2.2锛�2021-12-10锛�
+- 淇 clear-icon 灞炴�у湪灏忕▼搴忓钩鍙颁笉鐢熸晥鐨凚ug
+## 2.2.1锛�2021-12-10锛�
+- 淇 鏃ユ湡鑼冨洿閫夊湪灏忕▼搴忓钩鍙帮紝蹇呴』澶氱偣鍑讳竴娆℃墠鑳藉彇娑堥�変腑鐘舵�佺殑Bug
+## 2.2.0锛�2021-11-19锛�
+- 浼樺寲 缁勪欢UI锛屽苟鎻愪緵璁捐璧勬簮 [璇︽儏](https://uniapp.dcloud.io/component/uniui/resource)
+- 鏂囨。杩佺Щ [https://uniapp.dcloud.io/component/uniui/uni-datetime-picker](https://uniapp.dcloud.io/component/uniui/uni-datetime-picker)
+## 2.1.5锛�2021-11-09锛�
+- 鏂板 鎻愪緵缁勪欢璁捐璧勬簮锛岀粍浠舵牱寮忚皟鏁�
+## 2.1.4锛�2021-09-10锛�
+- 淇 hide-second 鍦ㄧЩ鍔ㄧ鐨凚ug
+- 淇 鍗曢�夎祴榛樿鍊兼椂锛岃祴鍊兼棩鏈熸湭楂樹寒鐨凚ug
+- 淇 璧嬮粯璁ゅ�兼椂锛岀Щ鍔ㄧ鏈纭樉绀烘椂闂寸殑Bug
+## 2.1.3锛�2021-09-09锛�
+- 鏂板 hide-second 灞炴�э紝鏀寔鍙娇鐢ㄦ椂鍒嗭紝闅愯棌绉�
+## 2.1.2锛�2021-09-03锛�
+- 浼樺寲 鍙栨秷閫変腑鏃讹紙鑼冨洿閫夛級鐩存帴寮�濮嬩笅涓�娆¢�夋嫨, 閬垮厤澶氱偣涓�娆�
+- 浼樺寲 绉诲姩绔敮鎸佹竻闄ゆ寜閽紝鍚屾椂鏀寔閫氳繃 ref 璋冪敤缁勪欢鐨� clear 鏂规硶
+- 浼樺寲 璋冩暣瀛楀彿澶у皬锛岀編鍖栨棩鍘嗙晫闈�
+- 淇 鍥犲浗闄呭寲瀵艰嚧鐨� placeholder 澶辨晥鐨凚ug
+## 2.1.1锛�2021-08-24锛�
+- 鏂板 鏀寔鍥介檯鍖�
+- 浼樺寲 鑼冨洿閫夋嫨鍣ㄥ湪 pc 绔繃瀹界殑闂
+## 2.1.0锛�2021-08-09锛�
+- 鏂板 閫傞厤 vue3
+## 2.0.19锛�2021-08-09锛�
+- 鏂板 鏀寔浣滀负 uni-forms 瀛愮粍浠剁浉鍏冲姛鑳�
+- 淇 鍦� uni-forms 涓娇鐢ㄦ椂锛岄�夋嫨鏃堕棿鎶� NAN 閿欒鐨凚ug
+## 2.0.18锛�2021-08-05锛�
+- 淇 type 灞炴�у姩鎬佽祴鍊兼棤鏁堢殑Bug
+- 淇 鈥樼‘璁も�欐寜閽 tabbar 閬洊 bug
+- 淇 缁勪欢鏈祴鍊兼椂鑼冨洿閫夊乏銆佸彸鏃ュ巻鐩稿悓鐨凚ug
+## 2.0.17锛�2021-08-04锛�
+- 淇 鑼冨洿閫夋湭姝g‘鏄剧ず褰撳墠鍊肩殑Bug
+- 淇 h5 骞冲彴锛堢Щ鍔ㄧ锛夋姤閿� 'cale' of undefined 鐨凚ug
+## 2.0.16锛�2021-07-21锛�
+- 鏂板 return-type 灞炴�ф敮鎸佽繑鍥� date 鏃ユ湡瀵硅薄
+## 2.0.15锛�2021-07-14锛�
+- 淇 鍗曢�夋棩鏈熺被鍨嬶紝鍒濆璧嬪�煎悗涓嶅湪褰撳墠鏃ュ巻鐨凚ug
+- 鏂板 clearIcon 灞炴�э紝鏄剧ず妗嗙殑娓呯┖鎸夐挳鍙厤缃樉绀洪殣钘忥紙浠� pc 鏈夋晥锛�
+- 浼樺寲 绉诲姩绔Щ闄ゆ樉绀烘鐨勬竻绌烘寜閽紝鏃犲疄闄呯敤閫�
+## 2.0.14锛�2021-07-14锛�
+- 淇 缁勪欢璧嬪�间负绌猴紝鐣岄潰鏈洿鏂扮殑Bug
+- 淇 start 鍜� end 涓嶈兘鍔ㄦ�佽祴鍊肩殑Bug
+- 淇 鑼冨洿閫夌被鍨嬶紝鐢ㄦ埛閫夋嫨鍚庡啀娆¢�夋嫨鍙充晶鏃ュ巻锛堢粨鏉熸棩鏈燂級鏄剧ず涓嶆纭殑Bug
+## 2.0.13锛�2021-07-08锛�
+- 淇 鑼冨洿閫夋嫨涓嶈兘鍔ㄦ�佽祴鍊肩殑Bug
+## 2.0.12锛�2021-07-08锛�
+- 淇 鑼冨洿閫夋嫨鐨勫垵濮嬫椂闂村湪涓�涓湀鍐呮椂锛岄�犳垚鏃犳硶閫夋嫨鐨刡ug
+## 2.0.11锛�2021-07-08锛�
+- 浼樺寲 寮瑰嚭灞傚湪瓒呭嚭瑙嗙獥杈圭紭瀹氫綅涓嶅噯纭殑闂
+## 2.0.10锛�2021-07-08锛�
+- 淇 鑼冨洿璧峰鐐规牱寮忕殑鑳屾櫙鑹蹭笌浠婃棩鏍峰紡鐨勫瓧浣撳墠鏅壊铻嶅悎锛屽鑷存棩鏈熷瓧浣撶湅涓嶆竻鐨凚ug
+- 浼樺寲 寮瑰嚭灞傚湪瓒呭嚭瑙嗙獥杈圭紭琚伄鐩栫殑闂
+## 2.0.9锛�2021-07-07锛�
+- 鏂板 maskClick 浜嬩欢
+- 淇 鐗规畩鎯呭喌鏃ュ巻 rpx 甯冨眬閿欒鐨凚ug锛宺px -> px
+- 淇 鑼冨洿閫夋嫨鏃舵竻绌鸿繑鍥炲�间笉鍚堢悊鐨刡ug锛孾'', ''] -> []
+## 2.0.8锛�2021-07-07锛�
+- 鏂板 鏃ユ湡鏃堕棿鏄剧ず妗嗘敮鎸佹彃妲�
+## 2.0.7锛�2021-07-01锛�
+- 浼樺寲 娣诲姞 uni-icons 渚濊禆
+## 2.0.6锛�2021-05-22锛�
+- 淇 鍥炬爣鍦ㄥ皬绋嬪簭涓婁笉鏄剧ず鐨凚ug
+- 浼樺寲 閲嶅懡鍚嶅紩鐢ㄧ粍浠讹紝閬垮厤娼滃湪缁勪欢鍛藉悕鍐茬獊
+## 2.0.5锛�2021-05-20锛�
+- 浼樺寲 浠g爜鐩綍鎵佸钩鍖�
+## 2.0.4锛�2021-05-12锛�
+- 鏂板 缁勪欢绀轰緥鍦板潃
+## 2.0.3锛�2021-05-10锛�
+- 淇 ios 涓嬩笉璇嗗埆 '-' 鏃ユ湡鏍煎紡鐨凚ug
+- 浼樺寲 pc 涓嬪脊鍑哄眰娣诲姞杈规鍜岄槾褰�
+## 2.0.2锛�2021-05-08锛�
+- 淇 鍦� admin 涓幏鍙栧脊鍑哄眰瀹氫綅閿欒鐨刡ug
+## 2.0.1锛�2021-05-08锛�
+- 淇 type 灞炴�у悜涓嬪吋瀹癸紝榛樿鍊间粠 date 鍙樻洿涓� datetime
+## 2.0.0锛�2021-04-30锛�
+- 鏀寔鏃ュ巻褰㈠紡鐨勬棩鏈�+鏃堕棿鐨勮寖鍥撮�夋嫨
+ > 娉ㄦ剰锛氭鐗堟湰涓嶅悜鍚庡吋瀹癸紝涓嶅啀鏀寔鍗曠嫭鏃堕棿閫夋嫨锛坱ype=time锛夊強鐩稿叧鐨� hide-second 灞炴�э紙鏃堕棿閫夊彲浣跨敤鍐呯疆缁勪欢 picker锛�
+## 1.0.6锛�2021-03-18锛�
+- 鏂板 hide-second 灞炴�э紝鏃堕棿鏀寔浠呴�夋嫨鏃躲�佸垎
+- 淇 閫夋嫨璺熸樉绀虹殑鏃ユ湡涓嶄竴鏍风殑Bug
+- 淇 chang浜嬩欢瑙﹀彂2娆$殑Bug
+- 淇 鍒嗐�佺 end 鑼冨洿閿欒鐨凚ug
+- 浼樺寲 鏇村ソ鐨� nvue 閫傞厤
diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar-item.vue b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar-item.vue
new file mode 100644
index 0000000..8f3c461
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar-item.vue
@@ -0,0 +1,177 @@
+<template>
+	<view class="uni-calendar-item__weeks-box" :class="{
+		'uni-calendar-item--disable':weeks.disable,
+		'uni-calendar-item--before-checked-x':weeks.beforeMultiple,
+		'uni-calendar-item--multiple': weeks.multiple,
+		'uni-calendar-item--after-checked-x':weeks.afterMultiple,
+		}" @click="choiceDate(weeks)" @mouseenter="handleMousemove(weeks)">
+		<view class="uni-calendar-item__weeks-box-item" :class="{
+				'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && (calendar.userChecked || !checkHover),
+				'uni-calendar-item--checked-range-text': checkHover,
+				'uni-calendar-item--before-checked':weeks.beforeMultiple,
+				'uni-calendar-item--multiple': weeks.multiple,
+				'uni-calendar-item--after-checked':weeks.afterMultiple,
+				'uni-calendar-item--disable':weeks.disable,
+				}">
+			<text v-if="selected && weeks.extraInfo" class="uni-calendar-item__weeks-box-circle"></text>
+			<text class="uni-calendar-item__weeks-box-text uni-calendar-item__weeks-box-text-disable uni-calendar-item--checked-text">{{weeks.date}}</text>
+		</view>
+		<view :class="{'uni-calendar-item--today': weeks.isToday}"></view>
+	</view>
+</template>
+
+<script>
+	export default {
+		props: {
+			weeks: {
+				type: Object,
+				default () {
+					return {}
+				}
+			},
+			calendar: {
+				type: Object,
+				default: () => {
+					return {}
+				}
+			},
+			selected: {
+				type: Array,
+				default: () => {
+					return []
+				}
+			},
+			checkHover: {
+				type: Boolean,
+				default: false
+			}
+		},
+		methods: {
+			choiceDate(weeks) {
+				this.$emit('change', weeks)
+			},
+			handleMousemove(weeks) {
+				this.$emit('handleMouse', weeks)
+			}
+		}
+	}
+</script>
+
+<style lang="scss" >
+	$uni-primary: #007aff !default;
+
+	.uni-calendar-item__weeks-box {
+		flex: 1;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: column;
+		justify-content: center;
+		align-items: center;
+		margin: 1px 0;
+		position: relative;
+	}
+
+	.uni-calendar-item__weeks-box-text {
+		font-size: 14px;
+		// font-family: Lato-Bold, Lato;
+		font-weight: bold;
+		color: darken($color: $uni-primary, $amount: 40%);
+	}
+
+	.uni-calendar-item__weeks-box-item {
+		position: relative;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: column;
+		justify-content: center;
+		align-items: center;
+		width: 40px;
+		height: 40px;
+		/* #ifdef H5 */
+		cursor: pointer;
+		/* #endif */
+	}
+
+
+	.uni-calendar-item__weeks-box-circle {
+		position: absolute;
+		top: 5px;
+		right: 5px;
+		width: 8px;
+		height: 8px;
+		border-radius: 8px;
+		background-color: #dd524d;
+
+	}
+
+	.uni-calendar-item__weeks-box .uni-calendar-item--disable {
+		cursor: default;
+	}
+
+	.uni-calendar-item--disable .uni-calendar-item__weeks-box-text-disable {
+		color: #D1D1D1;
+	}
+
+	.uni-calendar-item--today {
+		position: absolute;
+		top: 10px;
+		right: 17%;
+		background-color: #dd524d;
+		width:6px;
+		height: 6px;
+		border-radius: 50%;
+	}
+
+	.uni-calendar-item--extra {
+		color: #dd524d;
+		opacity: 0.8;
+	}
+
+	.uni-calendar-item__weeks-box .uni-calendar-item--checked {
+		background-color: $uni-primary;
+		border-radius: 50%;
+		box-sizing: border-box;
+		border: 3px solid #fff;
+	}
+
+	.uni-calendar-item--checked .uni-calendar-item--checked-text {
+		color: #fff;
+	}
+
+	.uni-calendar-item--multiple .uni-calendar-item--checked-range-text {
+		color: #333;
+	}
+
+	.uni-calendar-item--multiple {
+		background-color:  #F6F7FC;
+		// color: #fff;
+	}
+
+	.uni-calendar-item--multiple .uni-calendar-item--before-checked,
+	.uni-calendar-item--multiple .uni-calendar-item--after-checked {
+		background-color: $uni-primary;
+		border-radius: 50%;
+		box-sizing: border-box;
+		border: 3px solid #F6F7FC;
+	}
+
+	.uni-calendar-item--before-checked .uni-calendar-item--checked-text,
+	.uni-calendar-item--after-checked .uni-calendar-item--checked-text {
+		color: #fff;
+	}
+
+	.uni-calendar-item--before-checked-x {
+		border-top-left-radius: 50px;
+		border-bottom-left-radius: 50px;
+		box-sizing: border-box;
+		background-color: #F6F7FC;
+	}
+
+	.uni-calendar-item--after-checked-x {
+		border-top-right-radius: 50px;
+		border-bottom-right-radius: 50px;
+		background-color: #F6F7FC;
+	}
+</style>
diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.vue b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.vue
new file mode 100644
index 0000000..e6fe594
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.vue
@@ -0,0 +1,947 @@
+<template>
+	<view class="uni-calendar" @mouseleave="leaveCale">
+
+		<view v-if="!insert && show" class="uni-calendar__mask" :class="{'uni-calendar--mask-show':aniMaskShow}"
+			@click="maskClick"></view>
+
+		<view v-if="insert || show" class="uni-calendar__content"
+			:class="{'uni-calendar--fixed':!insert,'uni-calendar--ani-show':aniMaskShow, 'uni-calendar__content-mobile': aniMaskShow}">
+			<view class="uni-calendar__header" :class="{'uni-calendar__header-mobile' :!insert}">
+
+				<view class="uni-calendar__header-btn-box" @click.stop="changeMonth('pre')">
+					<view class="uni-calendar__header-btn uni-calendar--left"></view>
+				</view>
+
+				<picker mode="date" :value="date" fields="month" @change="bindDateChange">
+					<text
+						class="uni-calendar__header-text">{{ (nowDate.year||'') + yearText + ( nowDate.month||'') + monthText}}</text>
+				</picker>
+
+				<view class="uni-calendar__header-btn-box" @click.stop="changeMonth('next')">
+					<view class="uni-calendar__header-btn uni-calendar--right"></view>
+				</view>
+
+				<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>
+			</view>
+			<view class="uni-calendar__box">
+
+				<view v-if="showMonth" class="uni-calendar__box-bg">
+					<text class="uni-calendar__box-bg-text">{{nowDate.month}}</text>
+				</view>
+
+				<view class="uni-calendar__weeks" style="padding-bottom: 7px;">
+					<view class="uni-calendar__weeks-day">
+						<text class="uni-calendar__weeks-day-text">{{SUNText}}</text>
+					</view>
+					<view class="uni-calendar__weeks-day">
+						<text class="uni-calendar__weeks-day-text">{{MONText}}</text>
+					</view>
+					<view class="uni-calendar__weeks-day">
+						<text class="uni-calendar__weeks-day-text">{{TUEText}}</text>
+					</view>
+					<view class="uni-calendar__weeks-day">
+						<text class="uni-calendar__weeks-day-text">{{WEDText}}</text>
+					</view>
+					<view class="uni-calendar__weeks-day">
+						<text class="uni-calendar__weeks-day-text">{{THUText}}</text>
+					</view>
+					<view class="uni-calendar__weeks-day">
+						<text class="uni-calendar__weeks-day-text">{{FRIText}}</text>
+					</view>
+					<view class="uni-calendar__weeks-day">
+						<text class="uni-calendar__weeks-day-text">{{SATText}}</text>
+					</view>
+				</view>
+
+				<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>
+					</view>
+				</view>
+			</view>
+
+			<view v-if="!insert && !range && hasTime" class="uni-date-changed uni-calendar--fixed-top"
+				style="padding: 0 80px;">
+				<view class="uni-date-changed--time-date">{{tempSingleDate ? tempSingleDate : selectDateText}}</view>
+				<time-picker type="time" :start="timepickerStartTime" :end="timepickerEndTime" v-model="time"
+					:disabled="!tempSingleDate" :border="false" :hide-second="hideSecond" class="time-picker-style">
+				</time-picker>
+			</view>
+
+			<view v-if="!insert && range && hasTime" class="uni-date-changed uni-calendar--fixed-top">
+				<view class="uni-date-changed--time-start">
+					<view class="uni-date-changed--time-date">{{tempRange.before ? tempRange.before : startDateText}}
+					</view>
+					<time-picker type="time" :start="timepickerStartTime" v-model="timeRange.startTime" :border="false"
+						:hide-second="hideSecond" :disabled="!tempRange.before" class="time-picker-style">
+					</time-picker>
+				</view>
+				<view style="line-height: 50px;">
+					<uni-icons type="arrowthinright" color="#999"></uni-icons>
+				</view>
+				<view class="uni-date-changed--time-end">
+					<view class="uni-date-changed--time-date">{{tempRange.after ? tempRange.after : endDateText}}</view>
+					<time-picker type="time" :end="timepickerEndTime" v-model="timeRange.endTime" :border="false"
+						:hide-second="hideSecond" :disabled="!tempRange.after" class="time-picker-style">
+					</time-picker>
+				</view>
+			</view>
+
+			<view v-if="!insert" class="uni-date-changed uni-date-btn--ok">
+				<view class="uni-datetime-picker--btn" @click="confirm">{{confirmText}}</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	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 i18nMessages from './i18n/index.js'
+	const {
+		t
+	} = initVueI18n(i18nMessages)
+
+	/**
+	 * Calendar 鏃ュ巻
+	 * @description 鏃ュ巻缁勪欢鍙互鏌ョ湅鏃ユ湡锛岄�夋嫨浠绘剰鑼冨洿鍐呯殑鏃ユ湡锛屾墦鐐规搷浣溿�傚父鐢ㄥ満鏅锛氶厭搴楁棩鏈熼璁€�佺伀杞︽満绁ㄩ�夋嫨璐拱鏃ユ湡銆佷笂涓嬬彮鎵撳崱绛�
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=56
+	 * @property {String} date 鑷畾涔夊綋鍓嶆椂闂达紝榛樿涓轰粖澶�
+	 * @property {String} startDate 鏃ユ湡閫夋嫨鑼冨洿-寮�濮嬫棩鏈�
+	 * @property {String} endDate 鏃ユ湡閫夋嫨鑼冨洿-缁撴潫鏃ユ湡
+	 * @property {Boolean} range 鑼冨洿閫夋嫨
+	 * @property {Boolean} insert = [true|false] 鎻掑叆妯″紡,榛樿涓篺alse
+	 * 	@value true 寮圭獥妯″紡
+	 * 	@value false 鎻掑叆妯″紡
+	 * @property {Boolean} clearDate = [true|false] 寮圭獥妯″紡鏄惁娓呯┖涓婃閫夋嫨鍐呭
+	 * @property {Array} selected 鎵撶偣锛屾湡寰呮牸寮廩{date: '2019-06-27', info: '绛惧埌', data: { custom: '鑷畾涔変俊鎭�', name: '鑷畾涔夋秷鎭ご',xxx:xxx... }}]
+	 * @property {Boolean} showMonth 鏄惁閫夋嫨鏈堜唤涓鸿儗鏅�
+	 * @property {[String} defaultValue 閫夋嫨鍣ㄦ墦寮�鏃堕粯璁ゆ樉绀虹殑鏃堕棿
+	 * @event {Function} change 鏃ユ湡鏀瑰彉锛宍insert :ture` 鏃剁敓鏁�
+	 * @event {Function} confirm 纭閫夋嫨`insert :false` 鏃剁敓鏁�
+	 * @event {Function} monthSwitch 鍒囨崲鏈堜唤鏃惰Е鍙�
+	 * @example <uni-calendar :insert="true" :start-date="'2019-3-2'":end-date="'2019-5-20'"@change="change" />
+	 */
+	export default {
+		components: {
+			calendarItem,
+			timePicker
+		},
+
+		options: {
+			// #ifdef MP-TOUTIAO
+			virtualHost: false,
+			// #endif
+			// #ifndef MP-TOUTIAO
+			virtualHost: true
+			// #endif
+		},
+		props: {
+			date: {
+				type: String,
+				default: ''
+			},
+			defTime: {
+				type: [String, Object],
+				default: ''
+			},
+			selectableTimes: {
+				type: [Object],
+				default () {
+					return {}
+				}
+			},
+			selected: {
+				type: Array,
+				default () {
+					return []
+				}
+			},
+			startDate: {
+				type: String,
+				default: ''
+			},
+			endDate: {
+				type: String,
+				default: ''
+			},
+			startPlaceholder: {
+				type: String,
+				default: ''
+			},
+			endPlaceholder: {
+				type: String,
+				default: ''
+			},
+			range: {
+				type: Boolean,
+				default: false
+			},
+			hasTime: {
+				type: Boolean,
+				default: false
+			},
+			insert: {
+				type: Boolean,
+				default: true
+			},
+			showMonth: {
+				type: Boolean,
+				default: true
+			},
+			clearDate: {
+				type: Boolean,
+				default: true
+			},
+			checkHover: {
+				type: Boolean,
+				default: true
+			},
+			hideSecond: {
+				type: [Boolean],
+				default: false
+			},
+			pleStatus: {
+				type: Object,
+				default () {
+					return {
+						before: '',
+						after: '',
+						data: [],
+						fulldate: ''
+					}
+				}
+			},
+			defaultValue: {
+				type: [String, Object, Array],
+				default: ''
+			}
+		},
+		data() {
+			return {
+				show: false,
+				weeks: [],
+				calendar: {},
+				nowDate: {},
+				aniMaskShow: false,
+				firstEnter: true,
+				time: '',
+				timeRange: {
+					startTime: '',
+					endTime: ''
+				},
+				tempSingleDate: '',
+				tempRange: {
+					before: '',
+					after: ''
+				}
+			}
+		},
+		watch: {
+			date: {
+				immediate: true,
+				handler(newVal) {
+					if (!this.range) {
+						this.tempSingleDate = newVal
+						setTimeout(() => {
+							this.init(newVal)
+						}, 100)
+					}
+				}
+			},
+			defTime: {
+				immediate: true,
+				handler(newVal) {
+					if (!this.range) {
+						this.time = newVal
+					} else {
+						this.timeRange.startTime = newVal.start
+						this.timeRange.endTime = newVal.end
+					}
+				}
+			},
+			startDate(val) {
+				// 瀛楄妭灏忕▼搴� watch 鏃╀簬 created
+				if (!this.cale) {
+					return
+				}
+				this.cale.setStartDate(val)
+				this.cale.setDate(this.nowDate.fullDate)
+				this.weeks = this.cale.weeks
+			},
+			endDate(val) {
+				// 瀛楄妭灏忕▼搴� watch 鏃╀簬 created
+				if (!this.cale) {
+					return
+				}
+				this.cale.setEndDate(val)
+				this.cale.setDate(this.nowDate.fullDate)
+				this.weeks = this.cale.weeks
+			},
+			selected(newVal) {
+				// 瀛楄妭灏忕▼搴� watch 鏃╀簬 created
+				if (!this.cale) {
+					return
+				}
+				this.cale.setSelectInfo(this.nowDate.fullDate, newVal)
+				this.weeks = this.cale.weeks
+			},
+			pleStatus: {
+				immediate: true,
+				handler(newVal) {
+					const {
+						before,
+						after,
+						fulldate,
+						which
+					} = newVal
+					this.tempRange.before = before
+					this.tempRange.after = after
+					setTimeout(() => {
+						if (fulldate) {
+							this.cale.setHoverMultiple(fulldate)
+							if (before && after) {
+								this.cale.lastHover = true
+								if (this.rangeWithinMonth(after, before)) return
+								this.setDate(before)
+							} else {
+								this.cale.setMultiple(fulldate)
+								this.setDate(this.nowDate.fullDate)
+								this.calendar.fullDate = ''
+								this.cale.lastHover = false
+							}
+						} else {
+							// 瀛楄妭灏忕▼搴� 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) {
+								this.setDate(after)
+								this.weeks = this.cale.weeks
+							}
+							this.cale.lastHover = true
+						}
+					}, 16)
+				}
+			}
+		},
+		computed: {
+			timepickerStartTime() {
+				const activeDate = this.range ? this.tempRange.before : this.calendar.fullDate
+				return activeDate === this.startDate ? this.selectableTimes.start : ''
+			},
+			timepickerEndTime() {
+				const activeDate = this.range ? this.tempRange.after : this.calendar.fullDate
+				return activeDate === this.endDate ? this.selectableTimes.end : ''
+			},
+			/**
+			 * for i18n
+			 */
+			selectDateText() {
+				return t("uni-datetime-picker.selectDate")
+			},
+			startDateText() {
+				return this.startPlaceholder || t("uni-datetime-picker.startDate")
+			},
+			endDateText() {
+				return this.endPlaceholder || t("uni-datetime-picker.endDate")
+			},
+			okText() {
+				return t("uni-datetime-picker.ok")
+			},
+			yearText() {
+				return t("uni-datetime-picker.year")
+			},
+			monthText() {
+				return t("uni-datetime-picker.month")
+			},
+			MONText() {
+				return t("uni-calender.MON")
+			},
+			TUEText() {
+				return t("uni-calender.TUE")
+			},
+			WEDText() {
+				return t("uni-calender.WED")
+			},
+			THUText() {
+				return t("uni-calender.THU")
+			},
+			FRIText() {
+				return t("uni-calender.FRI")
+			},
+			SATText() {
+				return t("uni-calender.SAT")
+			},
+			SUNText() {
+				return t("uni-calender.SUN")
+			},
+			confirmText() {
+				return t("uni-calender.confirm")
+			},
+		},
+		created() {
+			// 鑾峰彇鏃ュ巻鏂规硶瀹炰緥
+			this.cale = new Calendar({
+				selected: this.selected,
+				startDate: this.startDate,
+				endDate: this.endDate,
+				range: this.range,
+			})
+			// 閫変腑鏌愪竴澶�
+			this.init(this.date)
+		},
+		methods: {
+			leaveCale() {
+				this.firstEnter = true
+			},
+			handleMouse(weeks) {
+				if (weeks.disable) return
+				if (this.cale.lastHover) return
+				let {
+					before,
+					after
+				} = this.cale.multipleStatus
+				if (!before) return
+				this.calendar = weeks
+				// 璁剧疆鑼冨洿閫�
+				this.cale.setHoverMultiple(this.calendar.fullDate)
+				this.weeks = this.cale.weeks
+				// hover鏃讹紝杩涘叆涓�涓棩鍘嗭紝鏇存柊鍙︿竴涓�
+				if (this.firstEnter) {
+					this.$emit('firstEnterCale', this.cale.multipleStatus)
+					this.firstEnter = false
+				}
+			},
+			rangeWithinMonth(A, B) {
+				const [yearA, monthA] = A.split('-')
+				const [yearB, monthB] = B.split('-')
+				return yearA === yearB && monthA === monthB
+			},
+			// 钂欑増鐐瑰嚮浜嬩欢
+			maskClick() {
+				this.close()
+				this.$emit('maskClose')
+			},
+
+			clearCalender() {
+				if (this.range) {
+					this.timeRange.startTime = ''
+					this.timeRange.endTime = ''
+					this.tempRange.before = ''
+					this.tempRange.after = ''
+					this.cale.multipleStatus.before = ''
+					this.cale.multipleStatus.after = ''
+					this.cale.multipleStatus.data = []
+					this.cale.lastHover = false
+				} else {
+					this.time = ''
+					this.tempSingleDate = ''
+				}
+				this.calendar.fullDate = ''
+				this.setDate(new Date())
+			},
+
+			bindDateChange(e) {
+				const value = e.detail.value + '-1'
+				this.setDate(value)
+			},
+			/**
+			 * 鍒濆鍖栨棩鏈熸樉绀�
+			 * @param {Object} date
+			 */
+			init(date) {
+				// 瀛楄妭灏忕▼搴� 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)
+					}
+				}
+			},
+			/**
+			 * 鎵撳紑鏃ュ巻寮圭獥
+			 */
+			open() {
+				// 寮圭獥妯″紡骞朵笖娓呯悊鏁版嵁
+				if (this.clearDate && !this.insert) {
+					this.cale.cleanMultipleStatus()
+					this.init(this.date)
+				}
+				this.show = true
+				this.$nextTick(() => {
+					setTimeout(() => {
+						this.aniMaskShow = true
+					}, 50)
+				})
+			},
+			/**
+			 * 鍏抽棴鏃ュ巻寮圭獥
+			 */
+			close() {
+				this.aniMaskShow = false
+				this.$nextTick(() => {
+					setTimeout(() => {
+						this.show = false
+						this.$emit('close')
+					}, 300)
+				})
+			},
+			/**
+			 * 纭鎸夐挳
+			 */
+			confirm() {
+				this.setEmit('confirm')
+				this.close()
+			},
+			/**
+			 * 鍙樺寲瑙﹀彂
+			 */
+			change(isSingleChange) {
+				if (!this.insert && !isSingleChange) return
+				this.setEmit('change')
+			},
+			/**
+			 * 閫夋嫨鏈堜唤瑙﹀彂
+			 */
+			monthSwitch() {
+				let {
+					year,
+					month
+				} = this.nowDate
+				this.$emit('monthSwitch', {
+					year,
+					month: Number(month)
+				})
+			},
+			/**
+			 * 娲惧彂浜嬩欢
+			 * @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.hasTime && !this.time) {
+						this.time = getTime(new Date(), this.hideSecond)
+					}
+				}
+				let {
+					year,
+					month,
+					date,
+					fullDate,
+					extraInfo
+				} = this.calendar
+				this.$emit(name, {
+					range: this.cale.multipleStatus,
+					year,
+					month,
+					date,
+					time: this.time,
+					timeRange: this.timeRange,
+					fulldate: fullDate,
+					extraInfo: extraInfo || {}
+				})
+			},
+			/**
+			 * 閫夋嫨澶╄Е鍙�
+			 * @param {Object} weeks
+			 */
+			choiceDate(weeks) {
+				if (weeks.disable) return
+				this.calendar = weeks
+				this.calendar.userChecked = true
+				// 璁剧疆澶氶��
+				this.cale.setMultiple(this.calendar.fullDate, true)
+				this.weeks = this.cale.weeks
+				this.tempSingleDate = this.calendar.fullDate
+				const beforeDate = new Date(this.cale.multipleStatus.before).getTime()
+				const afterDate = new Date(this.cale.multipleStatus.after).getTime()
+				if (beforeDate > afterDate && afterDate) {
+					this.tempRange.before = this.cale.multipleStatus.after
+					this.tempRange.after = this.cale.multipleStatus.before
+				} else {
+					this.tempRange.before = this.cale.multipleStatus.before
+					this.tempRange.after = this.cale.multipleStatus.after
+				}
+				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.monthSwitch()
+			},
+			/**
+			 * 璁剧疆鏃ユ湡
+			 * @param {Object} date
+			 */
+			setDate(date) {
+				this.cale.setDate(date)
+				this.weeks = this.cale.weeks
+				this.nowDate = this.cale.getInfo(date)
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	$uni-primary: #007aff !default;
+
+	.uni-calendar {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: column;
+	}
+
+	.uni-calendar__mask {
+		position: fixed;
+		bottom: 0;
+		top: 0;
+		left: 0;
+		right: 0;
+		background-color: rgba(0, 0, 0, 0.4);
+		transition-property: opacity;
+		transition-duration: 0.3s;
+		opacity: 0;
+		/* #ifndef APP-NVUE */
+		z-index: 99;
+		/* #endif */
+	}
+
+	.uni-calendar--mask-show {
+		opacity: 1
+	}
+
+	.uni-calendar--fixed {
+		position: fixed;
+		bottom: calc(var(--window-bottom));
+		left: 0;
+		right: 0;
+		transition-property: transform;
+		transition-duration: 0.3s;
+		transform: translateY(460px);
+		/* #ifndef APP-NVUE */
+		z-index: 99;
+		/* #endif */
+	}
+
+	.uni-calendar--ani-show {
+		transform: translateY(0);
+	}
+
+	.uni-calendar__content {
+		background-color: #fff;
+	}
+
+	.uni-calendar__content-mobile {
+		border-top-left-radius: 10px;
+		border-top-right-radius: 10px;
+		box-shadow: 0px 0px 5px 3px rgba(0, 0, 0, 0.1);
+	}
+
+	.uni-calendar__header {
+		position: relative;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		justify-content: center;
+		align-items: center;
+		height: 50px;
+	}
+
+	.uni-calendar__header-mobile {
+		padding: 10px;
+		padding-bottom: 0;
+	}
+
+	.uni-calendar--fixed-top {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		justify-content: space-between;
+		border-top-color: rgba(0, 0, 0, 0.4);
+		border-top-style: solid;
+		border-top-width: 1px;
+	}
+
+	.uni-calendar--fixed-width {
+		width: 50px;
+	}
+
+	.uni-calendar__backtoday {
+		position: absolute;
+		right: 0;
+		top: 25rpx;
+		padding: 0 5px;
+		padding-left: 10px;
+		height: 25px;
+		line-height: 25px;
+		font-size: 12px;
+		border-top-left-radius: 25px;
+		border-bottom-left-radius: 25px;
+		color: #fff;
+		background-color: #f1f1f1;
+	}
+
+	.uni-calendar__header-text {
+		text-align: center;
+		width: 100px;
+		font-size: 15px;
+		color: #666;
+	}
+
+	.uni-calendar__button-text {
+		text-align: center;
+		width: 100px;
+		font-size: 14px;
+		color: $uni-primary;
+		/* #ifndef APP-NVUE */
+		letter-spacing: 3px;
+		/* #endif */
+	}
+
+	.uni-calendar__header-btn-box {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		align-items: center;
+		justify-content: center;
+		width: 50px;
+		height: 50px;
+	}
+
+	.uni-calendar__header-btn {
+		width: 9px;
+		height: 9px;
+		border-left-color: #808080;
+		border-left-style: solid;
+		border-left-width: 1px;
+		border-top-color: #555555;
+		border-top-style: solid;
+		border-top-width: 1px;
+	}
+
+	.uni-calendar--left {
+		transform: rotate(-45deg);
+	}
+
+	.uni-calendar--right {
+		transform: rotate(135deg);
+	}
+
+
+	.uni-calendar__weeks {
+		position: relative;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+	}
+
+	.uni-calendar__weeks-item {
+		flex: 1;
+	}
+
+	.uni-calendar__weeks-day {
+		flex: 1;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: column;
+		justify-content: center;
+		align-items: center;
+		height: 40px;
+		border-bottom-color: #F5F5F5;
+		border-bottom-style: solid;
+		border-bottom-width: 1px;
+	}
+
+	.uni-calendar__weeks-day-text {
+		font-size: 12px;
+		color: #B2B2B2;
+	}
+
+	.uni-calendar__box {
+		position: relative;
+		// padding: 0 10px;
+		padding-bottom: 7px;
+	}
+
+	.uni-calendar__box-bg {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		justify-content: center;
+		align-items: center;
+		position: absolute;
+		top: 0;
+		left: 0;
+		right: 0;
+		bottom: 0;
+	}
+
+	.uni-calendar__box-bg-text {
+		font-size: 200px;
+		font-weight: bold;
+		color: #999;
+		opacity: 0.1;
+		text-align: center;
+		/* #ifndef APP-NVUE */
+		line-height: 1;
+		/* #endif */
+	}
+
+	.uni-date-changed {
+		padding: 0 10px;
+		// line-height: 50px;
+		text-align: center;
+		color: #333;
+		border-top-color: #DCDCDC;
+		;
+		border-top-style: solid;
+		border-top-width: 1px;
+		flex: 1;
+	}
+
+	.uni-date-btn--ok {
+		padding: 20px 15px;
+	}
+
+	.uni-date-changed--time-start {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		align-items: center;
+	}
+
+	.uni-date-changed--time-end {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		align-items: center;
+	}
+
+	.uni-date-changed--time-date {
+		color: #999;
+		line-height: 50px;
+		/* #ifdef MP-TOUTIAO */
+		font-size: 16px;
+		/* #endif */
+		margin-right: 5px;
+		// opacity: 0.6;
+	}
+
+	.time-picker-style {
+		// width: 62px;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		justify-content: center;
+		align-items: center
+	}
+
+	.mr-10 {
+		margin-right: 10px;
+	}
+
+	.dialog-close {
+		position: absolute;
+		top: 0;
+		right: 0;
+		bottom: 0;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		align-items: center;
+		padding: 0 25px;
+		margin-top: 10px;
+	}
+
+	.dialog-close-plus {
+		width: 16px;
+		height: 2px;
+		background-color: #737987;
+		border-radius: 2px;
+		transform: rotate(45deg);
+	}
+
+	.dialog-close-rotate {
+		position: absolute;
+		transform: rotate(-45deg);
+	}
+
+	.uni-datetime-picker--btn {
+		border-radius: 100px;
+		height: 40px;
+		line-height: 40px;
+		background-color: $uni-primary;
+		color: #fff;
+		font-size: 16px;
+		letter-spacing: 2px;
+	}
+
+	/* #ifndef APP-NVUE */
+	.uni-datetime-picker--btn:active {
+		opacity: 0.7;
+	}
+
+	/* #endif */
+</style>
diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/en.json b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/en.json
new file mode 100644
index 0000000..56cd0a6
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/en.json
@@ -0,0 +1,22 @@
+{
+	"uni-datetime-picker.selectDate": "select date",
+	"uni-datetime-picker.selectTime": "select time",
+	"uni-datetime-picker.selectDateTime": "select date and time",
+	"uni-datetime-picker.startDate": "start date",
+	"uni-datetime-picker.endDate": "end date",
+	"uni-datetime-picker.startTime": "start time",
+	"uni-datetime-picker.endTime": "end time",
+	"uni-datetime-picker.ok": "ok",
+	"uni-datetime-picker.clear": "clear",
+	"uni-datetime-picker.cancel": "cancel",
+	"uni-datetime-picker.year": "-",
+	"uni-datetime-picker.month": "",
+	"uni-calender.MON": "MON",
+	"uni-calender.TUE": "TUE",
+	"uni-calender.WED": "WED",
+	"uni-calender.THU": "THU",
+	"uni-calender.FRI": "FRI",
+	"uni-calender.SAT": "SAT",
+	"uni-calender.SUN": "SUN",
+	"uni-calender.confirm": "confirm"
+}
diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/index.js b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/index.js
new file mode 100644
index 0000000..fa8f0f3
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/index.js
@@ -0,0 +1,8 @@
+import en from './en.json'
+import zhHans from './zh-Hans.json'
+import zhHant from './zh-Hant.json'
+export default {
+	en,
+	'zh-Hans': zhHans,
+	'zh-Hant': zhHant
+}
diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hans.json b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hans.json
new file mode 100644
index 0000000..d2df5e7
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hans.json
@@ -0,0 +1,22 @@
+{
+	"uni-datetime-picker.selectDate": "閫夋嫨鏃ユ湡",
+	"uni-datetime-picker.selectTime": "閫夋嫨鏃堕棿",
+	"uni-datetime-picker.selectDateTime": "閫夋嫨鏃ユ湡鏃堕棿",
+	"uni-datetime-picker.startDate": "寮�濮嬫棩鏈�",
+	"uni-datetime-picker.endDate": "缁撴潫鏃ユ湡",
+	"uni-datetime-picker.startTime": "寮�濮嬫椂闂�",
+	"uni-datetime-picker.endTime": "缁撴潫鏃堕棿",
+	"uni-datetime-picker.ok": "纭畾",
+	"uni-datetime-picker.clear": "娓呴櫎",
+	"uni-datetime-picker.cancel": "鍙栨秷",
+	"uni-datetime-picker.year": "骞�",
+	"uni-datetime-picker.month": "鏈�",
+	"uni-calender.SUN": "鏃�",
+	"uni-calender.MON": "涓�",
+	"uni-calender.TUE": "浜�",
+	"uni-calender.WED": "涓�",
+	"uni-calender.THU": "鍥�",
+	"uni-calender.FRI": "浜�",
+	"uni-calender.SAT": "鍏�",
+	"uni-calender.confirm": "纭"
+}
\ No newline at end of file
diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hant.json b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hant.json
new file mode 100644
index 0000000..d23fa3c
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hant.json
@@ -0,0 +1,22 @@
+{
+  "uni-datetime-picker.selectDate": "閬告搰鏃ユ湡",
+  "uni-datetime-picker.selectTime": "閬告搰鏅傞枔",
+  "uni-datetime-picker.selectDateTime": "閬告搰鏃ユ湡鏅傞枔",
+  "uni-datetime-picker.startDate": "闁嬪鏃ユ湡",
+  "uni-datetime-picker.endDate": "绲愭潫鏃ユ湡",
+  "uni-datetime-picker.startTime": "闁嬪鏃堕棿",
+  "uni-datetime-picker.endTime": "绲愭潫鏃堕棿",
+  "uni-datetime-picker.ok": "纰哄畾",
+  "uni-datetime-picker.clear": "娓呴櫎",
+  "uni-datetime-picker.cancel": "鍙栨秷",
+  "uni-datetime-picker.year": "骞�",
+  "uni-datetime-picker.month": "鏈�",
+  "uni-calender.SUN": "鏃�",
+  "uni-calender.MON": "涓�",
+  "uni-calender.TUE": "浜�",
+  "uni-calender.WED": "涓�",
+  "uni-calender.THU": "鍥�",
+  "uni-calender.FRI": "浜�",
+  "uni-calender.SAT": "鍏�",
+  "uni-calender.confirm": "纰鸿獚"
+}
\ No newline at end of file
diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/time-picker.vue b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/time-picker.vue
new file mode 100644
index 0000000..8716d42
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/time-picker.vue
@@ -0,0 +1,940 @@
+<template>
+	<view class="uni-datetime-picker">
+		<view @click="initTimePicker">
+			<slot>
+				<view class="uni-datetime-picker-timebox-pointer"
+					:class="{'uni-datetime-picker-disabled': disabled, 'uni-datetime-picker-timebox': border}">
+					<text class="uni-datetime-picker-text">{{time}}</text>
+					<view v-if="!time" class="uni-datetime-picker-time">
+						<text class="uni-datetime-picker-text">{{selectTimeText}}</text>
+					</view>
+				</view>
+			</slot>
+		</view>
+		<view v-if="visible" id="mask" class="uni-datetime-picker-mask" @click="tiggerTimePicker"></view>
+		<view v-if="visible" class="uni-datetime-picker-popup" :class="[dateShow && timeShow ? '' : 'fix-nvue-height']"
+			:style="fixNvueBug">
+			<view class="uni-title">
+				<text class="uni-datetime-picker-text">{{selectTimeText}}</text>
+			</view>
+			<view v-if="dateShow" class="uni-datetime-picker__container-box">
+				<picker-view class="uni-datetime-picker-view" :indicator-style="indicatorStyle" :value="ymd"
+					@change="bindDateChange">
+					<picker-view-column>
+						<view class="uni-datetime-picker-item" v-for="(item,index) in years" :key="index">
+							<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
+						</view>
+					</picker-view-column>
+					<picker-view-column>
+						<view class="uni-datetime-picker-item" v-for="(item,index) in months" :key="index">
+							<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
+						</view>
+					</picker-view-column>
+					<picker-view-column>
+						<view class="uni-datetime-picker-item" v-for="(item,index) in days" :key="index">
+							<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
+						</view>
+					</picker-view-column>
+				</picker-view>
+				<!-- 鍏煎 nvue 涓嶆敮鎸佷吉绫� -->
+				<text class="uni-datetime-picker-sign sign-left">-</text>
+				<text class="uni-datetime-picker-sign sign-right">-</text>
+			</view>
+			<view v-if="timeShow" class="uni-datetime-picker__container-box">
+				<picker-view class="uni-datetime-picker-view" :class="[hideSecond ? 'time-hide-second' : '']"
+					:indicator-style="indicatorStyle" :value="hms" @change="bindTimeChange">
+					<picker-view-column>
+						<view class="uni-datetime-picker-item" v-for="(item,index) in hours" :key="index">
+							<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
+						</view>
+					</picker-view-column>
+					<picker-view-column>
+						<view class="uni-datetime-picker-item" v-for="(item,index) in minutes" :key="index">
+							<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
+						</view>
+					</picker-view-column>
+					<picker-view-column v-if="!hideSecond">
+						<view class="uni-datetime-picker-item" v-for="(item,index) in seconds" :key="index">
+							<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
+						</view>
+					</picker-view-column>
+				</picker-view>
+				<!-- 鍏煎 nvue 涓嶆敮鎸佷吉绫� -->
+				<text class="uni-datetime-picker-sign" :class="[hideSecond ? 'sign-center' : 'sign-left']">:</text>
+				<text v-if="!hideSecond" class="uni-datetime-picker-sign sign-right">:</text>
+			</view>
+			<view class="uni-datetime-picker-btn">
+				<view @click="clearTime">
+					<text class="uni-datetime-picker-btn-text">{{clearText}}</text>
+				</view>
+				<view class="uni-datetime-picker-btn-group">
+					<view class="uni-datetime-picker-cancel" @click="tiggerTimePicker">
+						<text class="uni-datetime-picker-btn-text">{{cancelText}}</text>
+					</view>
+					<view @click="setTime">
+						<text class="uni-datetime-picker-btn-text">{{okText}}</text>
+					</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		initVueI18n
+	} from '@dcloudio/uni-i18n'
+	import i18nMessages from './i18n/index.js'
+	const {
+		t
+	} = initVueI18n(i18nMessages)
+	import {
+		fixIosDateFormat
+	} from './util'
+
+	/**
+	 * DatetimePicker 鏃堕棿閫夋嫨鍣�
+	 * @description 鍙互鍚屾椂閫夋嫨鏃ユ湡鍜屾椂闂寸殑閫夋嫨鍣�
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=xxx
+	 * @property {String} type = [datetime | date | time] 鏄剧ず妯″紡
+	 * @property {Boolean} multiple = [true|false] 鏄惁澶氶��
+	 * @property {String|Number} value 榛樿鍊�
+	 * @property {String|Number} start 璧峰鏃ユ湡鎴栨椂闂�
+	 * @property {String|Number} end 璧峰鏃ユ湡鎴栨椂闂�
+	 * @property {String} return-type = [timestamp | string]
+	 * @event {Function} change  閫変腑鍙戠敓鍙樺寲瑙﹀彂
+	 */
+
+	export default {
+		name: 'UniDatetimePicker',
+		data() {
+			return {
+				indicatorStyle: `height: 50px;`,
+				visible: false,
+				fixNvueBug: {},
+				dateShow: true,
+				timeShow: true,
+				title: '鏃ユ湡鍜屾椂闂�',
+				// 杈撳叆妗嗗綋鍓嶆椂闂�
+				time: '',
+				// 褰撳墠鐨勫勾鏈堟棩鏃跺垎绉�
+				year: 1920,
+				month: 0,
+				day: 0,
+				hour: 0,
+				minute: 0,
+				second: 0,
+				// 璧峰鏃堕棿
+				startYear: 1920,
+				startMonth: 1,
+				startDay: 1,
+				startHour: 0,
+				startMinute: 0,
+				startSecond: 0,
+				// 缁撴潫鏃堕棿
+				endYear: 2120,
+				endMonth: 12,
+				endDay: 31,
+				endHour: 23,
+				endMinute: 59,
+				endSecond: 59,
+			}
+		},
+		options: {
+			// #ifdef MP-TOUTIAO
+			virtualHost: false,
+			// #endif
+			// #ifndef MP-TOUTIAO
+			virtualHost: true
+			// #endif
+		},
+		props: {
+			type: {
+				type: String,
+				default: 'datetime'
+			},
+			value: {
+				type: [String, Number],
+				default: ''
+			},
+			modelValue: {
+				type: [String, Number],
+				default: ''
+			},
+			start: {
+				type: [Number, String],
+				default: ''
+			},
+			end: {
+				type: [Number, String],
+				default: ''
+			},
+			returnType: {
+				type: String,
+				default: 'string'
+			},
+			disabled: {
+				type: [Boolean, String],
+				default: false
+			},
+			border: {
+				type: [Boolean, String],
+				default: true
+			},
+			hideSecond: {
+				type: [Boolean, String],
+				default: false
+			}
+		},
+		watch: {
+			// #ifndef VUE3
+			value: {
+				handler(newVal) {
+					if (newVal) {
+						this.parseValue(fixIosDateFormat(newVal))
+						this.initTime(false)
+					} else {
+						this.time = ''
+						this.parseValue(Date.now())
+					}
+				},
+				immediate: true
+			},
+			// #endif
+			// #ifdef VUE3
+			modelValue: {
+				handler(newVal) {
+					if (newVal) {
+						this.parseValue(fixIosDateFormat(newVal))
+						this.initTime(false)
+					} else {
+						this.time = ''
+						this.parseValue(Date.now())
+					}
+				},
+				immediate: true
+			},
+			// #endif
+			type: {
+				handler(newValue) {
+					if (newValue === 'date') {
+						this.dateShow = true
+						this.timeShow = false
+						this.title = '鏃ユ湡'
+					} else if (newValue === 'time') {
+						this.dateShow = false
+						this.timeShow = true
+						this.title = '鏃堕棿'
+					} else {
+						this.dateShow = true
+						this.timeShow = true
+						this.title = '鏃ユ湡鍜屾椂闂�'
+					}
+				},
+				immediate: true
+			},
+			start: {
+				handler(newVal) {
+					this.parseDatetimeRange(fixIosDateFormat(newVal), 'start')
+				},
+				immediate: true
+			},
+			end: {
+				handler(newVal) {
+					this.parseDatetimeRange(fixIosDateFormat(newVal), 'end')
+				},
+				immediate: true
+			},
+
+			// 鏈堛�佹棩銆佹椂銆佸垎銆佺鍙�夎寖鍥村彉鍖栧悗锛屾鏌ュ綋鍓嶅�兼槸鍚﹀湪鑼冨洿鍐咃紝涓嶅湪鍒欏綋鍓嶅�奸噸缃负鍙�夎寖鍥寸涓�椤�
+			months(newVal) {
+				this.checkValue('month', this.month, newVal)
+			},
+			days(newVal) {
+				this.checkValue('day', this.day, newVal)
+			},
+			hours(newVal) {
+				this.checkValue('hour', this.hour, newVal)
+			},
+			minutes(newVal) {
+				this.checkValue('minute', this.minute, newVal)
+			},
+			seconds(newVal) {
+				this.checkValue('second', this.second, newVal)
+			}
+		},
+		computed: {
+			// 褰撳墠骞淬�佹湀銆佹棩銆佹椂銆佸垎銆佺閫夋嫨鑼冨洿
+			years() {
+				return this.getCurrentRange('year')
+			},
+
+			months() {
+				return this.getCurrentRange('month')
+			},
+
+			days() {
+				return this.getCurrentRange('day')
+			},
+
+			hours() {
+				return this.getCurrentRange('hour')
+			},
+
+			minutes() {
+				return this.getCurrentRange('minute')
+			},
+
+			seconds() {
+				return this.getCurrentRange('second')
+			},
+
+			// picker 褰撳墠鍊兼暟缁�
+			ymd() {
+				return [this.year - this.minYear, this.month - this.minMonth, this.day - this.minDay]
+			},
+			hms() {
+				return [this.hour - this.minHour, this.minute - this.minMinute, this.second - this.minSecond]
+			},
+
+			// 褰撳墠 date 鏄� start
+			currentDateIsStart() {
+				return this.year === this.startYear && this.month === this.startMonth && this.day === this.startDay
+			},
+
+			// 褰撳墠 date 鏄� end
+			currentDateIsEnd() {
+				return this.year === this.endYear && this.month === this.endMonth && this.day === this.endDay
+			},
+
+			// 褰撳墠骞淬�佹湀銆佹棩銆佹椂銆佸垎銆佺鐨勬渶灏忓�煎拰鏈�澶у��
+			minYear() {
+				return this.startYear
+			},
+			maxYear() {
+				return this.endYear
+			},
+			minMonth() {
+				if (this.year === this.startYear) {
+					return this.startMonth
+				} else {
+					return 1
+				}
+			},
+			maxMonth() {
+				if (this.year === this.endYear) {
+					return this.endMonth
+				} else {
+					return 12
+				}
+			},
+			minDay() {
+				if (this.year === this.startYear && this.month === this.startMonth) {
+					return this.startDay
+				} else {
+					return 1
+				}
+			},
+			maxDay() {
+				if (this.year === this.endYear && this.month === this.endMonth) {
+					return this.endDay
+				} else {
+					return this.daysInMonth(this.year, this.month)
+				}
+			},
+			minHour() {
+				if (this.type === 'datetime') {
+					if (this.currentDateIsStart) {
+						return this.startHour
+					} else {
+						return 0
+					}
+				}
+				if (this.type === 'time') {
+					return this.startHour
+				}
+			},
+			maxHour() {
+				if (this.type === 'datetime') {
+					if (this.currentDateIsEnd) {
+						return this.endHour
+					} else {
+						return 23
+					}
+				}
+				if (this.type === 'time') {
+					return this.endHour
+				}
+			},
+			minMinute() {
+				if (this.type === 'datetime') {
+					if (this.currentDateIsStart && this.hour === this.startHour) {
+						return this.startMinute
+					} else {
+						return 0
+					}
+				}
+				if (this.type === 'time') {
+					if (this.hour === this.startHour) {
+						return this.startMinute
+					} else {
+						return 0
+					}
+				}
+			},
+			maxMinute() {
+				if (this.type === 'datetime') {
+					if (this.currentDateIsEnd && this.hour === this.endHour) {
+						return this.endMinute
+					} else {
+						return 59
+					}
+				}
+				if (this.type === 'time') {
+					if (this.hour === this.endHour) {
+						return this.endMinute
+					} else {
+						return 59
+					}
+				}
+			},
+			minSecond() {
+				if (this.type === 'datetime') {
+					if (this.currentDateIsStart && this.hour === this.startHour && this.minute === this.startMinute) {
+						return this.startSecond
+					} else {
+						return 0
+					}
+				}
+				if (this.type === 'time') {
+					if (this.hour === this.startHour && this.minute === this.startMinute) {
+						return this.startSecond
+					} else {
+						return 0
+					}
+				}
+			},
+			maxSecond() {
+				if (this.type === 'datetime') {
+					if (this.currentDateIsEnd && this.hour === this.endHour && this.minute === this.endMinute) {
+						return this.endSecond
+					} else {
+						return 59
+					}
+				}
+				if (this.type === 'time') {
+					if (this.hour === this.endHour && this.minute === this.endMinute) {
+						return this.endSecond
+					} else {
+						return 59
+					}
+				}
+			},
+
+			/**
+			 * for i18n
+			 */
+			selectTimeText() {
+				return t("uni-datetime-picker.selectTime")
+			},
+			okText() {
+				return t("uni-datetime-picker.ok")
+			},
+			clearText() {
+				return t("uni-datetime-picker.clear")
+			},
+			cancelText() {
+				return t("uni-datetime-picker.cancel")
+			}
+		},
+
+		mounted() {
+			// #ifdef APP-NVUE
+			const res = uni.getSystemInfoSync();
+			this.fixNvueBug = {
+				top: res.windowHeight / 2,
+				left: res.windowWidth / 2
+			}
+			// #endif
+		},
+
+		methods: {
+			/**
+			 * @param {Object} item
+			 * 灏忎簬 10 鍦ㄥ墠闈㈠姞涓� 0
+			 */
+
+			lessThanTen(item) {
+				return item < 10 ? '0' + item : item
+			},
+
+			/**
+			 * 瑙f瀽鏃跺垎绉掑瓧绗︿覆锛屼緥濡傦細00:00:00
+			 * @param {String} timeString
+			 */
+			parseTimeType(timeString) {
+				if (timeString) {
+					let timeArr = timeString.split(':')
+					this.hour = Number(timeArr[0])
+					this.minute = Number(timeArr[1])
+					this.second = Number(timeArr[2])
+				}
+			},
+
+			/**
+			 * 瑙f瀽閫夋嫨鍣ㄥ垵濮嬪�硷紝绫诲瀷鍙互鏄瓧绗︿覆銆佹椂闂存埑锛屼緥濡傦細2000-10-02銆�'08:30:00'銆� 1610695109000
+			 * @param {String | Number} datetime
+			 */
+			initPickerValue(datetime) {
+				let defaultValue = null
+				if (datetime) {
+					defaultValue = this.compareValueWithStartAndEnd(datetime, this.start, this.end)
+				} else {
+					defaultValue = Date.now()
+					defaultValue = this.compareValueWithStartAndEnd(defaultValue, this.start, this.end)
+				}
+				this.parseValue(defaultValue)
+			},
+
+			/**
+			 * 鍒濆鍊艰鍒欙細
+			 * - 鐢ㄦ埛璁剧疆鍒濆鍊� value
+			 * 	- 璁剧疆浜嗚捣濮嬫椂闂� start銆佺粓姝㈡椂闂� end锛屽苟 start < value < end锛屽垵濮嬪�间负 value锛� 鍚﹀垯鍒濆鍊间负 start
+			 * 	- 鍙缃簡璧峰鏃堕棿 start锛屽苟 start < value锛屽垵濮嬪�间负 value锛屽惁鍒欏垵濮嬪�间负 start
+			 * 	- 鍙缃簡缁堟鏃堕棿 end锛屽苟 value < end锛屽垵濮嬪�间负 value锛屽惁鍒欏垵濮嬪�间负 end
+			 * 	- 鏃犺捣濮嬬粓姝㈡椂闂达紝鍒欏垵濮嬪�间负 value
+			 * - 鏃犲垵濮嬪�� value锛屽垯鍒濆鍊间负褰撳墠鏈湴鏃堕棿 Date.now()
+			 * @param {Object} value
+			 * @param {Object} dateBase
+			 */
+			compareValueWithStartAndEnd(value, start, end) {
+				let winner = null
+				value = this.superTimeStamp(value)
+				start = this.superTimeStamp(start)
+				end = this.superTimeStamp(end)
+
+				if (start && end) {
+					if (value < start) {
+						winner = new Date(start)
+					} else if (value > end) {
+						winner = new Date(end)
+					} else {
+						winner = new Date(value)
+					}
+				} else if (start && !end) {
+					winner = start <= value ? new Date(value) : new Date(start)
+				} else if (!start && end) {
+					winner = value <= end ? new Date(value) : new Date(end)
+				} else {
+					winner = new Date(value)
+				}
+
+				return winner
+			},
+
+			/**
+			 * 杞崲涓哄彲姣旇緝鐨勬椂闂存埑锛屾帴鍙楁棩鏈熴�佹椂鍒嗙銆佹椂闂存埑
+			 * @param {Object} value
+			 */
+			superTimeStamp(value) {
+				let dateBase = ''
+				if (this.type === 'time' && value && typeof value === 'string') {
+					const now = new Date()
+					const year = now.getFullYear()
+					const month = now.getMonth() + 1
+					const day = now.getDate()
+					dateBase = year + '/' + month + '/' + day + ' '
+				}
+				if (Number(value)) {
+					value = parseInt(value)
+					dateBase = 0
+				}
+				return this.createTimeStamp(dateBase + value)
+			},
+
+			/**
+			 * 瑙f瀽榛樿鍊� value锛屽瓧绗︿覆銆佹椂闂存埑
+			 * @param {Object} defaultTime
+			 */
+			parseValue(value) {
+				if (!value) {
+					return
+				}
+				if (this.type === 'time' && typeof value === "string") {
+					this.parseTimeType(value)
+				} else {
+					let defaultDate = null
+					defaultDate = new Date(value)
+					if (this.type !== 'time') {
+						this.year = defaultDate.getFullYear()
+						this.month = defaultDate.getMonth() + 1
+						this.day = defaultDate.getDate()
+					}
+					if (this.type !== 'date') {
+						this.hour = defaultDate.getHours()
+						this.minute = defaultDate.getMinutes()
+						this.second = defaultDate.getSeconds()
+					}
+				}
+				if (this.hideSecond) {
+					this.second = 0
+				}
+			},
+
+			/**
+			 * 瑙f瀽鍙�夋嫨鏃堕棿鑼冨洿 start銆乪nd锛屽勾鏈堟棩瀛楃涓层�佹椂闂存埑
+			 * @param {Object} defaultTime
+			 */
+			parseDatetimeRange(point, pointType) {
+				// 鏃堕棿涓虹┖锛屽垯閲嶇疆涓哄垵濮嬪��
+				if (!point) {
+					if (pointType === 'start') {
+						this.startYear = 1920
+						this.startMonth = 1
+						this.startDay = 1
+						this.startHour = 0
+						this.startMinute = 0
+						this.startSecond = 0
+					}
+					if (pointType === 'end') {
+						this.endYear = 2120
+						this.endMonth = 12
+						this.endDay = 31
+						this.endHour = 23
+						this.endMinute = 59
+						this.endSecond = 59
+					}
+					return
+				}
+				if (this.type === 'time') {
+					const pointArr = point.split(':')
+					this[pointType + 'Hour'] = Number(pointArr[0])
+					this[pointType + 'Minute'] = Number(pointArr[1])
+					this[pointType + 'Second'] = Number(pointArr[2])
+				} else {
+					if (!point) {
+						pointType === 'start' ? this.startYear = this.year - 60 : this.endYear = this.year + 60
+						return
+					}
+					if (Number(point)) {
+						point = parseInt(point)
+					}
+					// datetime 鐨� end 娌℃湁鏃跺垎绉�, 鍒欎笉闄愬埗
+					const hasTime = /[0-9]:[0-9]/
+					if (this.type === 'datetime' && pointType === 'end' && typeof point === 'string' && !hasTime.test(
+							point)) {
+						point = point + ' 23:59:59'
+					}
+					const pointDate = new Date(point)
+					this[pointType + 'Year'] = pointDate.getFullYear()
+					this[pointType + 'Month'] = pointDate.getMonth() + 1
+					this[pointType + 'Day'] = pointDate.getDate()
+					if (this.type === 'datetime') {
+						this[pointType + 'Hour'] = pointDate.getHours()
+						this[pointType + 'Minute'] = pointDate.getMinutes()
+						this[pointType + 'Second'] = pointDate.getSeconds()
+					}
+				}
+			},
+
+			// 鑾峰彇 骞淬�佹湀銆佹棩銆佹椂銆佸垎銆佺 褰撳墠鍙�夎寖鍥�
+			getCurrentRange(value) {
+				const range = []
+				for (let i = this['min' + this.capitalize(value)]; i <= this['max' + this.capitalize(value)]; i++) {
+					range.push(i)
+				}
+				return range
+			},
+
+			// 瀛楃涓查瀛楁瘝澶у啓
+			capitalize(str) {
+				return str.charAt(0).toUpperCase() + str.slice(1)
+			},
+
+			// 妫�鏌ュ綋鍓嶅�兼槸鍚﹀湪鑼冨洿鍐咃紝涓嶅湪鍒欏綋鍓嶅�奸噸缃负鍙�夎寖鍥寸涓�椤�
+			checkValue(name, value, values) {
+				if (values.indexOf(value) === -1) {
+					this[name] = values[0]
+				}
+			},
+
+			// 姣忎釜鏈堢殑瀹為檯澶╂暟
+			daysInMonth(year, month) { // Use 1 for January, 2 for February, etc.
+				return new Date(year, month, 0).getDate();
+			},
+
+			/**
+			 * 鐢熸垚鏃堕棿鎴�
+			 * @param {Object} time
+			 */
+			createTimeStamp(time) {
+				if (!time) return
+				if (typeof time === "number") {
+					return time
+				} else {
+					time = time.replace(/-/g, '/')
+					if (this.type === 'date') {
+						time = time + ' ' + '00:00:00'
+					}
+					return Date.parse(time)
+				}
+			},
+
+			/**
+			 * 鐢熸垚鏃ユ湡鎴栨椂闂寸殑瀛楃涓�
+			 */
+			createDomSting() {
+				const yymmdd = this.year +
+					'-' +
+					this.lessThanTen(this.month) +
+					'-' +
+					this.lessThanTen(this.day)
+
+				let hhmmss = this.lessThanTen(this.hour) +
+					':' +
+					this.lessThanTen(this.minute)
+
+				if (!this.hideSecond) {
+					hhmmss = hhmmss + ':' + this.lessThanTen(this.second)
+				}
+
+				if (this.type === 'date') {
+					return yymmdd
+				} else if (this.type === 'time') {
+					return hhmmss
+				} else {
+					return yymmdd + ' ' + hhmmss
+				}
+			},
+
+			/**
+			 * 鍒濆鍖栬繑鍥炲�硷紝骞舵姏鍑� change 浜嬩欢
+			 */
+			initTime(emit = true) {
+				this.time = this.createDomSting()
+				if (!emit) return
+				if (this.returnType === 'timestamp' && this.type !== 'time') {
+					this.$emit('change', this.createTimeStamp(this.time))
+					this.$emit('input', this.createTimeStamp(this.time))
+					this.$emit('update:modelValue', this.createTimeStamp(this.time))
+				} else {
+					this.$emit('change', this.time)
+					this.$emit('input', this.time)
+					this.$emit('update:modelValue', this.time)
+				}
+			},
+
+			/**
+			 * 鐢ㄦ埛閫夋嫨鏃ユ湡鎴栨椂闂存洿鏂� data
+			 * @param {Object} e
+			 */
+			bindDateChange(e) {
+				const val = e.detail.value
+				this.year = this.years[val[0]]
+				this.month = this.months[val[1]]
+				this.day = this.days[val[2]]
+			},
+			bindTimeChange(e) {
+				const val = e.detail.value
+				this.hour = this.hours[val[0]]
+				this.minute = this.minutes[val[1]]
+				this.second = this.seconds[val[2]]
+			},
+
+			/**
+			 * 鍒濆鍖栧脊鍑哄眰
+			 */
+			initTimePicker() {
+				if (this.disabled) return
+				const value = fixIosDateFormat(this.time)
+				this.initPickerValue(value)
+				this.visible = !this.visible
+			},
+
+			/**
+			 * 瑙﹀彂鎴栧叧闂脊妗�
+			 */
+			tiggerTimePicker(e) {
+				this.visible = !this.visible
+			},
+
+			/**
+			 * 鐢ㄦ埛鐐瑰嚮鈥滄竻绌衡�濇寜閽紝娓呯┖褰撳墠鍊�
+			 */
+			clearTime() {
+				this.time = ''
+				this.$emit('change', this.time)
+				this.$emit('input', this.time)
+				this.$emit('update:modelValue', this.time)
+				this.tiggerTimePicker()
+			},
+
+			/**
+			 * 鐢ㄦ埛鐐瑰嚮鈥滅‘瀹氣�濇寜閽�
+			 */
+			setTime() {
+				this.initTime()
+				this.tiggerTimePicker()
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	$uni-primary: #007aff !default;
+
+	.uni-datetime-picker {
+		/* #ifndef APP-NVUE */
+		/* width: 100%; */
+		/* #endif */
+	}
+
+	.uni-datetime-picker-view {
+		height: 130px;
+		width: 270px;
+		/* #ifndef APP-NVUE */
+		cursor: pointer;
+		/* #endif */
+	}
+
+	.uni-datetime-picker-item {
+		height: 50px;
+		line-height: 50px;
+		text-align: center;
+		font-size: 14px;
+	}
+
+	.uni-datetime-picker-btn {
+		margin-top: 60px;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		cursor: pointer;
+		/* #endif */
+		flex-direction: row;
+		justify-content: space-between;
+	}
+
+	.uni-datetime-picker-btn-text {
+		font-size: 14px;
+		color: $uni-primary;
+	}
+
+	.uni-datetime-picker-btn-group {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+	}
+
+	.uni-datetime-picker-cancel {
+		margin-right: 30px;
+	}
+
+	.uni-datetime-picker-mask {
+		position: fixed;
+		bottom: 0px;
+		top: 0px;
+		left: 0px;
+		right: 0px;
+		background-color: rgba(0, 0, 0, 0.4);
+		transition-duration: 0.3s;
+		z-index: 998;
+	}
+
+	.uni-datetime-picker-popup {
+		border-radius: 8px;
+		padding: 30px;
+		width: 270px;
+		/* #ifdef APP-NVUE */
+		height: 500px;
+		/* #endif */
+		/* #ifdef APP-NVUE */
+		width: 330px;
+		/* #endif */
+		background-color: #fff;
+		position: fixed;
+		top: 50%;
+		left: 50%;
+		transform: translate(-50%, -50%);
+		transition-duration: 0.3s;
+		z-index: 999;
+	}
+
+	.fix-nvue-height {
+		/* #ifdef APP-NVUE */
+		height: 330px;
+		/* #endif */
+	}
+
+	.uni-datetime-picker-time {
+		color: grey;
+	}
+
+	.uni-datetime-picker-column {
+		height: 50px;
+	}
+
+	.uni-datetime-picker-timebox {
+
+		border: 1px solid #E5E5E5;
+		border-radius: 5px;
+		padding: 7px 10px;
+		/* #ifndef APP-NVUE */
+		box-sizing: border-box;
+		cursor: pointer;
+		/* #endif */
+	}
+
+	.uni-datetime-picker-timebox-pointer {
+		/* #ifndef APP-NVUE */
+		cursor: pointer;
+		/* #endif */
+	}
+
+
+	.uni-datetime-picker-disabled {
+		opacity: 0.4;
+		/* #ifdef H5 */
+		cursor: not-allowed !important;
+		/* #endif */
+	}
+
+	.uni-datetime-picker-text {
+		font-size: 14px;
+		line-height: 50px
+	}
+
+	.uni-datetime-picker-sign {
+		position: absolute;
+		top: 53px;
+		/* 鍑忔帀 10px 鐨勫厓绱犻珮搴︼紝鍏煎nvue */
+		color: #999;
+		/* #ifdef APP-NVUE */
+		font-size: 16px;
+		/* #endif */
+	}
+
+	.sign-left {
+		left: 86px;
+	}
+
+	.sign-right {
+		right: 86px;
+	}
+
+	.sign-center {
+		left: 135px;
+	}
+
+	.uni-datetime-picker__container-box {
+		position: relative;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		margin-top: 40px;
+	}
+
+	.time-hide-second {
+		width: 180px;
+	}
+</style>
diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue
new file mode 100644
index 0000000..6843e80
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue
@@ -0,0 +1,1064 @@
+<template>
+	<view class="uni-date">
+		<view class="uni-date-editor" @click="show">
+			<slot>
+				<view class="uni-date-editor--x"
+					:class="{'uni-date-editor--x__disabled': disabled,'uni-date-x--border': border}">
+					<view v-if="!isRange" class="uni-date-x uni-date-single">
+						<uni-icons class="icon-calendar" type="calendar" color="#c0c4cc" size="22"></uni-icons>
+						<view class="uni-date__x-input">{{ displayValue || singlePlaceholderText }}</view>
+					</view>
+
+					<view v-else class="uni-date-x uni-date-range">
+						<uni-icons class="icon-calendar" type="calendar" color="#c0c4cc" size="22"></uni-icons>
+						<view class="uni-date__x-input text-center">{{ displayRangeValue.startDate || startPlaceholderText }}</view>
+
+						<view class="range-separator">{{rangeSeparator}}</view>
+
+						<view class="uni-date__x-input text-center">{{ displayRangeValue.endDate || endPlaceholderText }}</view>
+					</view>
+
+					<view v-if="showClearIcon" class="uni-date__icon-clear" @click.stop="clear">
+						<uni-icons type="clear" color="#c0c4cc" size="22"></uni-icons>
+					</view>
+				</view>
+			</slot>
+		</view>
+
+		<view v-show="pickerVisible" class="uni-date-mask--pc" @click="close"></view>
+
+		<view v-if="!isPhone" v-show="pickerVisible" ref="datePicker" class="uni-date-picker__container">
+			<view v-if="!isRange" class="uni-date-single--x" :style="pickerPositionStyle">
+				<view class="uni-popper__arrow"></view>
+
+				<view v-if="hasTime" class="uni-date-changed popup-x-header">
+					<input class="uni-date__input text-center" type="text" v-model="inputDate" :placeholder="selectDateText" />
+
+					<time-picker type="time" v-model="pickerTime" :border="false" :disabled="!inputDate"
+						:start="timepickerStartTime" :end="timepickerEndTime" :hideSecond="hideSecond" style="width: 100%;">
+						<input class="uni-date__input text-center" type="text" v-model="pickerTime" :placeholder="selectTimeText"
+							:disabled="!inputDate" />
+					</time-picker>
+				</view>
+
+				<Calendar ref="pcSingle" :showMonth="false" :start-date="calendarRange.startDate"
+					:end-date="calendarRange.endDate" :date="calendarDate" @change="singleChange" :default-value="defaultValue"
+					style="padding: 0 8px;" />
+
+				<view v-if="hasTime" class="popup-x-footer">
+					<text class="confirm-text" @click="confirmSingleChange">{{okText}}</text>
+				</view>
+			</view>
+
+			<view v-else class="uni-date-range--x" :style="pickerPositionStyle">
+				<view class="uni-popper__arrow"></view>
+				<view v-if="hasTime" class="popup-x-header uni-date-changed">
+					<view class="popup-x-header--datetime">
+						<input class="uni-date__input uni-date-range__input" type="text" v-model="tempRange.startDate"
+							:placeholder="startDateText" />
+
+						<time-picker type="time" v-model="tempRange.startTime" :start="timepickerStartTime" :border="false"
+							:disabled="!tempRange.startDate" :hideSecond="hideSecond">
+							<input class="uni-date__input uni-date-range__input" type="text" v-model="tempRange.startTime"
+								:placeholder="startTimeText" :disabled="!tempRange.startDate" />
+						</time-picker>
+					</view>
+
+					<uni-icons type="arrowthinright" color="#999" style="line-height: 40px;"></uni-icons>
+
+					<view class="popup-x-header--datetime">
+						<input class="uni-date__input uni-date-range__input" type="text" v-model="tempRange.endDate"
+							:placeholder="endDateText" />
+
+						<time-picker type="time" v-model="tempRange.endTime" :end="timepickerEndTime" :border="false"
+							:disabled="!tempRange.endDate" :hideSecond="hideSecond">
+							<input class="uni-date__input uni-date-range__input" type="text" v-model="tempRange.endTime"
+								:placeholder="endTimeText" :disabled="!tempRange.endDate" />
+						</time-picker>
+					</view>
+				</view>
+
+				<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;"/>
+					<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;" />
+				</view>
+
+				<view v-if="hasTime" class="popup-x-footer">
+					<text @click="clear">{{clearText}}</text>
+					<text class="confirm-text" @click="confirmRangeChange">{{okText}}</text>
+				</view>
+			</view>
+		</view>
+
+		<Calendar v-if="isPhone" ref="mobile" :clearDate="false" :date="calendarDate" :defTime="mobileCalendarTime"
+			: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" @change="calendarClick"/>
+	</view>
+</template>
+<script>
+	/**
+	 * DatetimePicker 鏃堕棿閫夋嫨鍣�
+	 * @description 鍚屾椂鏀寔 PC 鍜岀Щ鍔ㄧ浣跨敤鏃ュ巻閫夋嫨鏃ユ湡鍜屾棩鏈熻寖鍥�
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=3962
+	 * @property {String} type 閫夋嫨鍣ㄧ被鍨�
+	 * @property {String|Number|Array|Date} value 缁戝畾鍊�
+	 * @property {String} placeholder 鍗曢�夋嫨鏃剁殑鍗犱綅鍐呭
+	 * @property {String} start 璧峰鏃堕棿
+	 * @property {String} end 缁堟鏃堕棿
+	 * @property {String} start-placeholder 鑼冨洿閫夋嫨鏃跺紑濮嬫棩鏈熺殑鍗犱綅鍐呭
+	 * @property {String} end-placeholder 鑼冨洿閫夋嫨鏃剁粨鏉熸棩鏈熺殑鍗犱綅鍐呭
+	 * @property {String} range-separator 閫夋嫨鑼冨洿鏃剁殑鍒嗛殧绗�
+	 * @property {Boolean} border = [true|false] 鏄惁鏈夎竟妗�
+	 * @property {Boolean} disabled = [true|false] 鏄惁绂佺敤
+	 * @property {Boolean} clearIcon = [true|false] 鏄惁鏄剧ず娓呴櫎鎸夐挳锛堜粎PC绔�傜敤锛�
+	 * @property {[String} defaultValue 閫夋嫨鍣ㄦ墦寮�鏃堕粯璁ゆ樉绀虹殑鏃堕棿
+	 * @event {Function} change 纭畾鏃ユ湡鏃惰Е鍙戠殑浜嬩欢
+	 * @event {Function} maskClick 鐐瑰嚮閬僵灞傝Е鍙戠殑浜嬩欢
+	 * @event {Function} show 鎵撳紑寮瑰嚭灞�
+	 * @event {Function} close 鍏抽棴寮瑰嚭灞�
+	 * @event {Function} clear 娓呴櫎涓婃閫変腑鐨勭姸鎬佸拰鍊�
+	 **/
+	import Calendar from './calendar.vue'
+	import TimePicker from './time-picker.vue'
+	import {
+		initVueI18n
+	} from '@dcloudio/uni-i18n'
+	import i18nMessages from './i18n/index.js'
+	import {
+		getDateTime,
+		getDate,
+		getTime,
+		getDefaultSecond,
+		dateCompare,
+		checkDate,
+		fixIosDateFormat
+	} from './util'
+
+	export default {
+		name: 'UniDatetimePicker',
+
+		options: {
+			// #ifdef MP-TOUTIAO
+			virtualHost: false,
+			// #endif
+			// #ifndef MP-TOUTIAO
+			virtualHost: true
+			// #endif
+		},
+		components: {
+			Calendar,
+			TimePicker
+		},
+		data() {
+			return {
+				isRange: false,
+				hasTime: false,
+				displayValue: '',
+				inputDate: '',
+				calendarDate: '',
+				pickerTime: '',
+				calendarRange: {
+					startDate: '',
+					startTime: '',
+					endDate: '',
+					endTime: ''
+				},
+				displayRangeValue: {
+					startDate: '',
+					endDate: '',
+				},
+				tempRange: {
+					startDate: '',
+					startTime: '',
+					endDate: '',
+					endTime: ''
+				},
+				// 宸﹀彸鏃ュ巻鍚屾鏁版嵁
+				startMultipleStatus: {
+					before: '',
+					after: '',
+					data: [],
+					fulldate: ''
+				},
+				endMultipleStatus: {
+					before: '',
+					after: '',
+					data: [],
+					fulldate: ''
+				},
+				pickerVisible: false,
+				pickerPositionStyle: null,
+				isEmitValue: false,
+				isPhone: false,
+				isFirstShow: true,
+				i18nT: () => {}
+			}
+		},
+		props: {
+			type: {
+				type: String,
+				default: 'datetime'
+			},
+			value: {
+				type: [String, Number, Array, Date],
+				default: ''
+			},
+			modelValue: {
+				type: [String, Number, Array, Date],
+				default: ''
+			},
+			start: {
+				type: [Number, String],
+				default: ''
+			},
+			end: {
+				type: [Number, String],
+				default: ''
+			},
+			returnType: {
+				type: String,
+				default: 'string'
+			},
+			placeholder: {
+				type: String,
+				default: ''
+			},
+			startPlaceholder: {
+				type: String,
+				default: ''
+			},
+			endPlaceholder: {
+				type: String,
+				default: ''
+			},
+			rangeSeparator: {
+				type: String,
+				default: '-'
+			},
+			border: {
+				type: [Boolean],
+				default: true
+			},
+			disabled: {
+				type: [Boolean],
+				default: false
+			},
+			clearIcon: {
+				type: [Boolean],
+				default: true
+			},
+			hideSecond: {
+				type: [Boolean],
+				default: false
+			},
+			defaultValue: {
+				type: [String, Object, Array],
+				default: ''
+			}
+		},
+		watch: {
+			type: {
+				immediate: true,
+				handler(newVal) {
+					this.hasTime = newVal.indexOf('time') !== -1
+					this.isRange = newVal.indexOf('range') !== -1
+				}
+			},
+			// #ifndef VUE3
+			value: {
+				immediate: true,
+				handler(newVal) {
+					if (this.isEmitValue) {
+						this.isEmitValue = false
+						return
+					}
+					this.initPicker(newVal)
+				}
+			},
+			// #endif
+			// #ifdef VUE3
+			modelValue: {
+				immediate: true,
+				handler(newVal) {
+					if (this.isEmitValue) {
+						this.isEmitValue = false
+						return
+					}
+					this.initPicker(newVal)
+				}
+			},
+			// #endif
+			start: {
+				immediate: true,
+				handler(newVal) {
+					if (!newVal) return
+					this.calendarRange.startDate = getDate(newVal)
+					if (this.hasTime) {
+						this.calendarRange.startTime = getTime(newVal)
+					}
+				}
+			},
+			end: {
+				immediate: true,
+				handler(newVal) {
+					if (!newVal) return
+					this.calendarRange.endDate = getDate(newVal)
+					if (this.hasTime) {
+						this.calendarRange.endTime = getTime(newVal, this.hideSecond)
+					}
+				}
+			},
+		},
+		computed: {
+			timepickerStartTime() {
+				const activeDate = this.isRange ? this.tempRange.startDate : this.inputDate
+				return activeDate === this.calendarRange.startDate ? this.calendarRange.startTime : ''
+			},
+			timepickerEndTime() {
+				const activeDate = this.isRange ? this.tempRange.endDate : this.inputDate
+				return activeDate === this.calendarRange.endDate ? this.calendarRange.endTime : ''
+			},
+			mobileCalendarTime() {
+				const timeRange = {
+					start: this.tempRange.startTime,
+					end: this.tempRange.endTime
+				}
+				return this.isRange ? timeRange : this.pickerTime
+			},
+			mobSelectableTime() {
+				return {
+					start: this.calendarRange.startTime,
+					end: this.calendarRange.endTime
+				}
+			},
+			datePopupWidth() {
+				// todo
+				return this.isRange ? 653 : 301
+			},
+
+			/**
+			 * for i18n
+			 */
+			singlePlaceholderText() {
+				return this.placeholder || (this.type === 'date' ? this.selectDateText : this.selectDateTimeText)
+			},
+			startPlaceholderText() {
+				return this.startPlaceholder || this.startDateText
+			},
+			endPlaceholderText() {
+				return this.endPlaceholder || this.endDateText
+			},
+			selectDateText() {
+				return this.i18nT("uni-datetime-picker.selectDate")
+			},
+			selectDateTimeText() {
+				return this.i18nT("uni-datetime-picker.selectDateTime")
+			},
+			selectTimeText() {
+				return this.i18nT("uni-datetime-picker.selectTime")
+			},
+			startDateText() {
+				return this.startPlaceholder || this.i18nT("uni-datetime-picker.startDate")
+			},
+			startTimeText() {
+				return this.i18nT("uni-datetime-picker.startTime")
+			},
+			endDateText() {
+				return this.endPlaceholder || this.i18nT("uni-datetime-picker.endDate")
+			},
+			endTimeText() {
+				return this.i18nT("uni-datetime-picker.endTime")
+			},
+			okText() {
+				return this.i18nT("uni-datetime-picker.ok")
+			},
+			clearText() {
+				return this.i18nT("uni-datetime-picker.clear")
+			},
+			showClearIcon() {
+				return this.clearIcon && !this.disabled && (this.displayValue || (this.displayRangeValue.startDate && this
+					.displayRangeValue.endDate))
+			}
+		},
+		created() {
+			this.initI18nT()
+			this.platform()
+		},
+		methods: {
+			initI18nT() {
+				const vueI18n = initVueI18n(i18nMessages)
+				this.i18nT = vueI18n.t
+			},
+			initPicker(newVal) {
+				if ((!newVal && !this.defaultValue) || Array.isArray(newVal) && !newVal.length) {
+					this.$nextTick(() => {
+						this.clear(false)
+					})
+					return
+				}
+
+				if (!Array.isArray(newVal) && !this.isRange) {
+					if (newVal) {
+						this.displayValue = this.inputDate = this.calendarDate = getDate(newVal)
+						if (this.hasTime) {
+							this.pickerTime = getTime(newVal, this.hideSecond)
+							this.displayValue = `${this.displayValue} ${this.pickerTime}`
+						}
+					} else if (this.defaultValue) {
+						this.inputDate = this.calendarDate = getDate(this.defaultValue)
+						if (this.hasTime) {
+							this.pickerTime = getTime(this.defaultValue, this.hideSecond)
+						}
+					}
+				} else {
+					const [before, after] = newVal
+					if (!before && !after) return
+					const beforeDate = getDate(before)
+					const beforeTime = getTime(before, this.hideSecond)
+
+					const afterDate = getDate(after)
+					const afterTime = getTime(after, this.hideSecond)
+					const startDate = beforeDate
+					const endDate = afterDate
+					this.displayRangeValue.startDate = this.tempRange.startDate = startDate
+					this.displayRangeValue.endDate = this.tempRange.endDate = endDate
+
+					if (this.hasTime) {
+						this.displayRangeValue.startDate = `${beforeDate} ${beforeTime}`
+						this.displayRangeValue.endDate = `${afterDate} ${afterTime}`
+						this.tempRange.startTime = beforeTime
+						this.tempRange.endTime = afterTime
+					}
+					const defaultRange = {
+						before: beforeDate,
+						after: afterDate
+					}
+					this.startMultipleStatus = Object.assign({}, this.startMultipleStatus, defaultRange, {
+						which: 'right'
+					})
+					this.endMultipleStatus = Object.assign({}, this.endMultipleStatus, defaultRange, {
+						which: 'left'
+					})
+				}
+			},
+			updateLeftCale(e) {
+				const left = this.$refs.left
+				// 璁剧疆鑼冨洿閫�
+				left.cale.setHoverMultiple(e.after)
+				left.setDate(this.$refs.left.nowDate.fullDate)
+			},
+			updateRightCale(e) {
+				const right = this.$refs.right
+				// 璁剧疆鑼冨洿閫�
+				right.cale.setHoverMultiple(e.after)
+				right.setDate(this.$refs.right.nowDate.fullDate)
+			},
+			platform() {
+				if (typeof navigator !== "undefined") {
+					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
+			},
+			show() {
+				this.$emit("show")
+				if (this.disabled) {
+					return
+				}
+				this.platform()
+				if (this.isPhone) {
+					setTimeout(() => {
+						this.$refs.mobile.open()
+					}, 0);
+					return
+				}
+				this.pickerPositionStyle = {
+					top: '10px'
+				}
+				const dateEditor = uni.createSelectorQuery().in(this).select(".uni-date-editor")
+				dateEditor.boundingClientRect(rect => {
+					if (this.windowWidth - rect.left < this.datePopupWidth) {
+						this.pickerPositionStyle.right = 0
+					}
+				}).exec()
+				setTimeout(() => {
+					this.pickerVisible = !this.pickerVisible
+					if (!this.isPhone && this.isRange && this.isFirstShow) {
+						this.isFirstShow = false
+						const {
+							startDate,
+							endDate
+						} = this.calendarRange
+						if (startDate && endDate) {
+							if (this.diffDate(startDate, endDate) < 30) {
+								this.$refs.right.changeMonth('pre')
+							}
+						} else {
+							// this.$refs.right.changeMonth('next')
+							if (this.isPhone) {
+								this.$refs.right.cale.lastHover = false;
+							}
+						}
+					}
+
+				}, 50)
+			},
+			close() {
+				setTimeout(() => {
+					this.pickerVisible = false
+					this.$emit('maskClick', this.value)
+					this.$refs.mobile && this.$refs.mobile.close()
+				}, 20)
+			},
+			setEmit(value) {
+				if (this.returnType === "timestamp" || this.returnType === "date") {
+					if (!Array.isArray(value)) {
+						if (!this.hasTime) {
+							value = value + ' ' + '00:00:00'
+						}
+						value = this.createTimestamp(value)
+						if (this.returnType === "date") {
+							value = new Date(value)
+						}
+					} else {
+						if (!this.hasTime) {
+							value[0] = value[0] + ' ' + '00:00:00'
+							value[1] = value[1] + ' ' + '00:00:00'
+						}
+						value[0] = this.createTimestamp(value[0])
+						value[1] = this.createTimestamp(value[1])
+						if (this.returnType === "date") {
+							value[0] = new Date(value[0])
+							value[1] = new Date(value[1])
+						}
+					}
+				}
+
+				this.$emit('update:modelValue', value)
+				this.$emit('input', value)
+				this.$emit('change', value)
+				this.isEmitValue = true
+			},
+			createTimestamp(date) {
+				date = fixIosDateFormat(date)
+				return Date.parse(new Date(date))
+			},
+			singleChange(e) {
+				this.calendarDate = this.inputDate = e.fulldate
+				if (this.hasTime) return
+				this.confirmSingleChange()
+			},
+			confirmSingleChange() {
+				if (!checkDate(this.inputDate)) {
+					const now = new Date()
+					this.calendarDate = this.inputDate = getDate(now)
+					this.pickerTime = getTime(now, this.hideSecond)
+				}
+
+				let startLaterInputDate = false
+				let startDate, startTime
+				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(startDate, this.inputDate)) {
+						startLaterInputDate = true
+						this.inputDate = startDate
+					}
+				}
+
+				let endEarlierInputDate = false
+				let endDate, endTime
+				if (this.end) {
+					let endString = this.end
+					if (typeof this.end === 'number') {
+						endString = getDateTime(this.end, this.hideSecond)
+					}
+					[endDate, endTime] = endString.split(' ')
+					if (this.end && !dateCompare(this.inputDate, endDate)) {
+						endEarlierInputDate = true
+						this.inputDate = endDate
+					}
+				}
+				if (this.hasTime) {
+					if (startLaterInputDate) {
+						this.pickerTime = startTime || getDefaultSecond(this.hideSecond)
+					}
+					if (endEarlierInputDate) {
+						this.pickerTime = endTime || getDefaultSecond(this.hideSecond)
+					}
+					if (!this.pickerTime) {
+						this.pickerTime = getTime(Date.now(), this.hideSecond)
+					}
+					this.displayValue = `${this.inputDate} ${this.pickerTime}`
+				} else {
+					this.displayValue = this.inputDate
+				}
+				this.setEmit(this.displayValue)
+				this.pickerVisible = false
+			},
+			leftChange(e) {
+				const {
+					before,
+					after
+				} = e.range
+				this.rangeChange(before, after)
+				const obj = {
+					before: e.range.before,
+					after: e.range.after,
+					data: e.range.data,
+					fulldate: e.fulldate
+				}
+				this.startMultipleStatus = Object.assign({}, this.startMultipleStatus, obj)
+				this.$emit('calendarClick', e)
+			},
+			rightChange(e) {
+				const {
+					before,
+					after
+				} = e.range
+				this.rangeChange(before, after)
+				const obj = {
+					before: e.range.before,
+					after: e.range.after,
+					data: e.range.data,
+					fulldate: e.fulldate
+				}
+				this.endMultipleStatus = Object.assign({}, this.endMultipleStatus, obj)
+				this.$emit('calendarClick', e)
+			},
+			mobileChange(e) {
+				if (this.isRange) {
+					const {
+						before,
+						after
+					} = e.range
+					if (!before) {
+						return;
+					}
+
+					this.handleStartAndEnd(before, after, true)
+					if (this.hasTime) {
+						const {
+							startTime,
+							endTime
+						} = e.timeRange
+						this.tempRange.startTime = startTime
+						this.tempRange.endTime = endTime
+					}
+					this.confirmRangeChange()
+				} else {
+					if (this.hasTime) {
+						this.displayValue = e.fulldate + ' ' + e.time
+					} else {
+						this.displayValue = e.fulldate
+					}
+					this.setEmit(this.displayValue)
+				}
+				this.$refs.mobile.close()
+			},
+			rangeChange(before, after) {
+				if (!(before && after)) return
+				this.handleStartAndEnd(before, after, true)
+				if (this.hasTime) return
+				this.confirmRangeChange()
+			},
+			confirmRangeChange() {
+				if (!this.tempRange.startDate || !this.tempRange.endDate) {
+					this.pickerVisible = false
+					return
+				}
+				if (!checkDate(this.tempRange.startDate)) {
+					this.tempRange.startDate = getDate(Date.now())
+				}
+				if (!checkDate(this.tempRange.endDate)) {
+					this.tempRange.endDate = getDate(Date.now())
+				}
+
+				let start, end
+
+				let startDateLaterRangeStartDate = false
+				let startDateLaterRangeEndDate = false
+				let startDate, startTime
+				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} ${this.tempRange.startTime}`)) {
+						startDateLaterRangeStartDate = true
+						this.tempRange.startDate = startDate
+					}
+					if (this.start && !dateCompare(this.start, `${this.tempRange.endDate} ${this.tempRange.endTime}`)) {
+						startDateLaterRangeEndDate = true
+						this.tempRange.endDate = startDate
+					}
+				}
+				let endDateEarlierRangeStartDate = false
+				let endDateEarlierRangeEndDate = false
+				let endDate, endTime
+				if (this.end) {
+					let endString = this.end
+					if (typeof this.end === 'number') {
+						endString = getDateTime(this.end, this.hideSecond)
+					}
+					[endDate, endTime] = endString.split(' ')
+
+					if (this.end && !dateCompare(`${this.tempRange.startDate} ${this.tempRange.startTime}`, this.end)) {
+						endDateEarlierRangeStartDate = true
+						this.tempRange.startDate = endDate
+					}
+					if (this.end && !dateCompare(`${this.tempRange.endDate} ${this.tempRange.endTime}`, this.end)) {
+						endDateEarlierRangeEndDate = true
+						this.tempRange.endDate = endDate
+					}
+				}
+				if (!this.hasTime) {
+					start = this.displayRangeValue.startDate = this.tempRange.startDate
+					end = this.displayRangeValue.endDate = this.tempRange.endDate
+				} else {
+					if (startDateLaterRangeStartDate) {
+						this.tempRange.startTime = startTime || getDefaultSecond(this.hideSecond)
+					} else if (endDateEarlierRangeStartDate) {
+						this.tempRange.startTime = endTime || getDefaultSecond(this.hideSecond)
+					}
+					if (!this.tempRange.startTime) {
+						this.tempRange.startTime = getTime(Date.now(), this.hideSecond)
+					}
+
+					if (startDateLaterRangeEndDate) {
+						this.tempRange.endTime = startTime || getDefaultSecond(this.hideSecond)
+					} else if (endDateEarlierRangeEndDate) {
+						this.tempRange.endTime = endTime || getDefaultSecond(this.hideSecond)
+					}
+					if (!this.tempRange.endTime) {
+						this.tempRange.endTime = getTime(Date.now(), this.hideSecond)
+					}
+					start = this.displayRangeValue.startDate = `${this.tempRange.startDate} ${this.tempRange.startTime}`
+					end = this.displayRangeValue.endDate = `${this.tempRange.endDate} ${this.tempRange.endTime}`
+				}
+				if (!dateCompare(start, end)) {
+					[start, end] = [end, start]
+				}
+				this.displayRangeValue.startDate = start
+				this.displayRangeValue.endDate = end
+				const displayRange = [start, end]
+				this.setEmit(displayRange)
+				this.pickerVisible = false
+			},
+			handleStartAndEnd(before, after, temp = false) {
+				if (!before) return
+				if (!after) after = before;
+				const type = temp ? 'tempRange' : 'range'
+				const isStartEarlierEnd = dateCompare(before, after)
+				this[type].startDate = isStartEarlierEnd ? before : after
+				this[type].endDate = isStartEarlierEnd ? after : before
+			},
+			/**
+			 * 姣旇緝鏃堕棿澶у皬
+			 */
+			dateCompare(startDate, endDate) {
+				// 璁$畻鎴鏃堕棿
+				startDate = new Date(startDate.replace('-', '/').replace('-', '/'))
+				// 璁$畻璇︾粏椤圭殑鎴鏃堕棿
+				endDate = new Date(endDate.replace('-', '/').replace('-', '/'))
+				return startDate <= endDate
+			},
+
+			/**
+			 * 姣旇緝鏃堕棿宸�
+			 */
+			diffDate(startDate, endDate) {
+				// 璁$畻鎴鏃堕棿
+				startDate = new Date(startDate.replace('-', '/').replace('-', '/'))
+				// 璁$畻璇︾粏椤圭殑鎴鏃堕棿
+				endDate = new Date(endDate.replace('-', '/').replace('-', '/'))
+				const diff = (endDate - startDate) / (24 * 60 * 60 * 1000)
+				return Math.abs(diff)
+			},
+
+			clear(needEmit = true) {
+				if (!this.isRange) {
+					this.displayValue = ''
+					this.inputDate = ''
+					this.pickerTime = ''
+					if (this.isPhone) {
+						this.$refs.mobile && this.$refs.mobile.clearCalender()
+					} else {
+						this.$refs.pcSingle && this.$refs.pcSingle.clearCalender()
+					}
+					if (needEmit) {
+						this.$emit('change', '')
+						this.$emit('input', '')
+						this.$emit('update:modelValue', '')
+					}
+				} else {
+					this.displayRangeValue.startDate = ''
+					this.displayRangeValue.endDate = ''
+					this.tempRange.startDate = ''
+					this.tempRange.startTime = ''
+					this.tempRange.endDate = ''
+					this.tempRange.endTime = ''
+					if (this.isPhone) {
+						this.$refs.mobile && this.$refs.mobile.clearCalender()
+					} else {
+						this.$refs.left && this.$refs.left.clearCalender()
+						this.$refs.right && this.$refs.right.clearCalender()
+						this.$refs.right && this.$refs.right.changeMonth('next')
+					}
+					if (needEmit) {
+						this.$emit('change', [])
+						this.$emit('input', [])
+						this.$emit('update:modelValue', [])
+					}
+				}
+			},
+
+			calendarClick(e) {
+				this.$emit('calendarClick', e)
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	$uni-primary: #007aff !default;
+
+	.uni-date {
+		width: 100%;
+		flex: 1;
+	}
+
+	.uni-date-x {
+		display: flex;
+		flex-direction: row;
+		align-items: center;
+		justify-content: center;
+		border-radius: 4px;
+		background-color: #fff;
+		color: #666;
+		font-size: 14px;
+		flex: 1;
+
+		.icon-calendar {
+			padding-left: 3px;
+		}
+
+		.range-separator {
+			height: 35px;
+			/* #ifndef MP */
+			padding: 0 2px;
+			/* #endif */
+			line-height: 35px;
+		}
+	}
+
+	.uni-date-x--border {
+		box-sizing: border-box;
+		border-radius: 4px;
+		border: 1px solid #e5e5e5;
+	}
+
+	.uni-date-editor--x {
+		display: flex;
+		align-items: center;
+		position: relative;
+	}
+
+	.uni-date-editor--x .uni-date__icon-clear {
+		padding-right: 3px;
+		display: flex;
+		align-items: center;
+		/* #ifdef H5 */
+		cursor: pointer;
+		/* #endif */
+	}
+
+	.uni-date__x-input {
+		width: auto;
+		height: 35px;
+		/* #ifndef MP */
+		padding-left: 5px;
+		/* #endif */
+		position: relative;
+		flex: 1;
+		line-height: 35px;
+		font-size: 14px;
+		overflow: hidden;
+	}
+
+	.text-center {
+		text-align: center;
+	}
+
+	.uni-date__input {
+		height: 40px;
+		width: 100%;
+		line-height: 40px;
+		font-size: 14px;
+	}
+
+	.uni-date-range__input {
+		text-align: center;
+		max-width: 142px;
+	}
+
+	.uni-date-picker__container {
+		position: relative;
+	}
+
+	.uni-date-mask--pc {
+		position: fixed;
+		bottom: 0px;
+		top: 0px;
+		left: 0px;
+		right: 0px;
+		background-color: rgba(0, 0, 0, 0);
+		transition-duration: 0.3s;
+		z-index: 996;
+	}
+
+	.uni-date-single--x {
+		background-color: #fff;
+		position: absolute;
+		top: 0;
+		z-index: 999;
+		border: 1px solid #EBEEF5;
+		box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+		border-radius: 4px;
+	}
+
+	.uni-date-range--x {
+		background-color: #fff;
+		position: absolute;
+		top: 0;
+		z-index: 999;
+		border: 1px solid #EBEEF5;
+		box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+		border-radius: 4px;
+	}
+
+	.uni-date-editor--x__disabled {
+		opacity: 0.4;
+		cursor: default;
+	}
+
+	.uni-date-editor--logo {
+		width: 16px;
+		height: 16px;
+		vertical-align: middle;
+	}
+
+	/* 娣诲姞鏃堕棿 */
+	.popup-x-header {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+	}
+
+	.popup-x-header--datetime {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		flex: 1;
+	}
+
+	.popup-x-body {
+		display: flex;
+	}
+
+	.popup-x-footer {
+		padding: 0 15px;
+		border-top-color: #F1F1F1;
+		border-top-style: solid;
+		border-top-width: 1px;
+		line-height: 40px;
+		text-align: right;
+		color: #666;
+	}
+
+	.popup-x-footer text:hover {
+		color: $uni-primary;
+		cursor: pointer;
+		opacity: 0.8;
+	}
+
+	.popup-x-footer .confirm-text {
+		margin-left: 20px;
+		color: $uni-primary;
+	}
+
+	.uni-date-changed {
+		text-align: center;
+		color: #333;
+		border-bottom-color: #F1F1F1;
+		border-bottom-style: solid;
+		border-bottom-width: 1px;
+	}
+
+	.uni-date-changed--time text {
+		height: 50px;
+		line-height: 50px;
+	}
+
+	.uni-date-changed .uni-date-changed--time {
+		flex: 1;
+	}
+
+	.uni-date-changed--time-date {
+		color: #333;
+		opacity: 0.6;
+	}
+
+	.mr-50 {
+		margin-right: 50px;
+	}
+
+	/* picker 寮瑰嚭灞傞�氱敤鐨勬寚绀哄皬涓夎, todo锛氭墿灞曡嚦涓婁笅宸﹀彸鏂瑰悜瀹氫綅 */
+	.uni-popper__arrow,
+	.uni-popper__arrow::after {
+		position: absolute;
+		display: block;
+		width: 0;
+		height: 0;
+		border: 6px solid transparent;
+		border-top-width: 0;
+	}
+
+	.uni-popper__arrow {
+		filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
+		top: -6px;
+		left: 10%;
+		margin-right: 3px;
+		border-bottom-color: #EBEEF5;
+	}
+
+	.uni-popper__arrow::after {
+		content: " ";
+		top: 1px;
+		margin-left: -6px;
+		border-bottom-color: #fff;
+	}
+</style>
diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/util.js b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/util.js
new file mode 100644
index 0000000..bc9d481
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/util.js
@@ -0,0 +1,421 @@
+class Calendar {
+	constructor({
+		selected,
+		startDate,
+		endDate,
+		range,
+	} = {}) {
+		// 褰撳墠鏃ユ湡
+		this.date = this.getDateObj(new Date()) // 褰撳墠鍒濆叆鏃ユ湡
+		// 鎵撶偣淇℃伅
+		this.selected = selected || [];
+		// 璧峰鏃堕棿
+		this.startDate = startDate
+		// 缁堟鏃堕棿
+		this.endDate = endDate
+		// 鏄惁鑼冨洿閫夋嫨
+		this.range = range
+		// 澶氶�夌姸鎬�
+		this.cleanMultipleStatus()
+		// 姣忓懆鏃ユ湡
+		this.weeks = {}
+		this.lastHover = false
+	}
+	/**
+	 * 璁剧疆鏃ユ湡
+	 * @param {Object} date
+	 */
+	setDate(date) {
+		const selectDate = this.getDateObj(date)
+		this.getWeeks(selectDate.fullDate)
+	}
+
+	/**
+	 * 娓呯悊澶氶�夌姸鎬�
+	 */
+	cleanMultipleStatus() {
+		this.multipleStatus = {
+			before: '',
+			after: '',
+			data: []
+		}
+	}
+
+	setStartDate(startDate) {
+		this.startDate = startDate
+	}
+
+	setEndDate(endDate) {
+		this.endDate = endDate
+	}
+
+	getPreMonthObj(date) {
+		date = fixIosDateFormat(date)
+		date = new Date(date)
+
+		const oldMonth = date.getMonth()
+		date.setMonth(oldMonth - 1)
+		const newMonth = date.getMonth()
+		if (oldMonth !== 0 && newMonth - oldMonth === 0) {
+			date.setMonth(newMonth - 1)
+		}
+		return this.getDateObj(date)
+	}
+	getNextMonthObj(date) {
+		date = fixIosDateFormat(date)
+		date = new Date(date)
+
+		const oldMonth = date.getMonth()
+		date.setMonth(oldMonth + 1)
+		const newMonth = date.getMonth()
+		if (newMonth - oldMonth > 1) {
+			date.setMonth(newMonth - 1)
+		}
+		return this.getDateObj(date)
+	}
+
+	/**
+	 * 鑾峰彇鎸囧畾鏍煎紡Date瀵硅薄
+	 */
+	getDateObj(date) {
+		date = fixIosDateFormat(date)
+		date = new Date(date)
+
+		return {
+			fullDate: getDate(date),
+			year: date.getFullYear(),
+			month: addZero(date.getMonth() + 1),
+			date: addZero(date.getDate()),
+			day: date.getDay()
+		}
+	}
+
+	/**
+	 * 鑾峰彇涓婁竴涓湀鏃ユ湡闆嗗悎
+	 */
+	getPreMonthDays(amount, dateObj) {
+		const result = []
+		for (let i = amount - 1; i >= 0; i--) {
+			const month = dateObj.month - 1
+			result.push({
+				date: new Date(dateObj.year, month, -i).getDate(),
+				month,
+				disable: true
+			})
+		}
+		return result
+	}
+	/**
+	 * 鑾峰彇鏈湀鏃ユ湡闆嗗悎
+	 */
+	getCurrentMonthDays(amount, dateObj) {
+		const result = []
+		const fullDate = this.date.fullDate
+		for (let i = 1; i <= amount; i++) {
+			const currentDate = `${dateObj.year}-${dateObj.month}-${addZero(i)}`
+			const isToday = fullDate === currentDate
+			// 鑾峰彇鎵撶偣淇℃伅
+			const info = this.selected && this.selected.find((item) => {
+				if (this.dateEqual(currentDate, item.date)) {
+					return item
+				}
+			})
+
+			// 鏃ユ湡绂佺敤
+			let disableBefore = true
+			let disableAfter = true
+			if (this.startDate) {
+				disableBefore = dateCompare(this.startDate, currentDate)
+			}
+
+			if (this.endDate) {
+				disableAfter = dateCompare(currentDate, this.endDate)
+			}
+
+			let multiples = this.multipleStatus.data
+			let multiplesStatus = -1
+			if (this.range && multiples) {
+				multiplesStatus = multiples.findIndex((item) => {
+					return this.dateEqual(item, currentDate)
+				})
+			}
+			const checked = multiplesStatus !== -1
+
+			result.push({
+				fullDate: currentDate,
+				year: dateObj.year,
+				date: i,
+				multiple: this.range ? checked : false,
+				beforeMultiple: this.isLogicBefore(currentDate, this.multipleStatus.before, this.multipleStatus.after),
+				afterMultiple: this.isLogicAfter(currentDate, this.multipleStatus.before, this.multipleStatus.after),
+				month: dateObj.month,
+				disable: (this.startDate && !dateCompare(this.startDate, currentDate)) || (this.endDate && !dateCompare(
+					currentDate, this.endDate)),
+				isToday,
+				userChecked: false,
+				extraInfo: info
+			})
+		}
+		return result
+	}
+	/**
+	 * 鑾峰彇涓嬩竴涓湀鏃ユ湡闆嗗悎
+	 */
+	_getNextMonthDays(amount, dateObj) {
+		const result = []
+		const month = dateObj.month + 1
+		for (let i = 1; i <= amount; i++) {
+			result.push({
+				date: i,
+				month,
+				disable: true
+			})
+		}
+		return result
+	}
+
+	/**
+	 * 鑾峰彇褰撳墠鏃ユ湡璇︽儏
+	 * @param {Object} date
+	 */
+	getInfo(date) {
+		if (!date) {
+			date = new Date()
+		}
+		const res = this.calendar.find(item => item.fullDate === this.getDateObj(date).fullDate)
+		return res ? res : this.getDateObj(date)
+	}
+
+	/**
+	 * 姣旇緝鏃堕棿鏄惁鐩哥瓑
+	 */
+	dateEqual(before, after) {
+		before = new Date(fixIosDateFormat(before))
+		after = new Date(fixIosDateFormat(after))
+		return before.valueOf() === after.valueOf()
+	}
+
+	/**
+	 *  姣旇緝鐪熷疄璧峰鏃ユ湡
+	 */
+
+	isLogicBefore(currentDate, before, after) {
+		let logicBefore = before
+		if (before && after) {
+			logicBefore = dateCompare(before, after) ? before : after
+		}
+		return this.dateEqual(logicBefore, currentDate)
+	}
+
+	isLogicAfter(currentDate, before, after) {
+		let logicAfter = after
+		if (before && after) {
+			logicAfter = dateCompare(before, after) ? after : before
+		}
+		return this.dateEqual(logicAfter, currentDate)
+	}
+
+	/**
+	 * 鑾峰彇鏃ユ湡鑼冨洿鍐呮墍鏈夋棩鏈�
+	 * @param {Object} begin
+	 * @param {Object} end
+	 */
+	geDateAll(begin, end) {
+		var arr = []
+		var ab = begin.split('-')
+		var ae = end.split('-')
+		var db = new Date()
+		db.setFullYear(ab[0], ab[1] - 1, ab[2])
+		var de = new Date()
+		de.setFullYear(ae[0], ae[1] - 1, ae[2])
+		var unixDb = db.getTime() - 24 * 60 * 60 * 1000
+		var unixDe = de.getTime() - 24 * 60 * 60 * 1000
+		for (var k = unixDb; k <= unixDe;) {
+			k = k + 24 * 60 * 60 * 1000
+			arr.push(this.getDateObj(new Date(parseInt(k))).fullDate)
+		}
+		return arr
+	}
+
+	/**
+	 *  鑾峰彇澶氶�夌姸鎬�
+	 */
+	setMultiple(fullDate) {
+		if (!this.range) return
+
+		let {
+			before,
+			after
+		} = this.multipleStatus
+		if (before && after) {
+			if (!this.lastHover) {
+				this.lastHover = true
+				return
+			}
+			this.multipleStatus.before = fullDate
+			this.multipleStatus.after = ''
+			this.multipleStatus.data = []
+			this.multipleStatus.fulldate = ''
+			this.lastHover = false
+		} else {
+			if (!before) {
+				this.multipleStatus.before = fullDate
+				this.multipleStatus.after = undefined;
+				this.lastHover = false
+			} else {
+				this.multipleStatus.after = fullDate
+				if (dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
+					this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus
+						.after);
+				} else {
+					this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus
+						.before);
+				}
+				this.lastHover = true
+			}
+		}
+		this.getWeeks(fullDate)
+	}
+
+	/**
+	 *  榧犳爣 hover 鏇存柊澶氶�夌姸鎬�
+	 */
+	setHoverMultiple(fullDate) {
+		//鎶栭煶灏忕▼搴忕偣鍑讳細瑙﹀彂hover浜嬩欢锛岄渶瑕侀伩鍏嶄竴涓�
+		// #ifndef MP-TOUTIAO
+		if (!this.range || this.lastHover) return
+		const {
+			before
+		} = this.multipleStatus
+
+		if (!before) {
+			this.multipleStatus.before = fullDate
+		} else {
+			this.multipleStatus.after = fullDate
+			if (dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
+				this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus.after);
+			} else {
+				this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus.before);
+			}
+		}
+		this.getWeeks(fullDate)
+		// #endif
+
+	}
+
+	/**
+	 * 鏇存柊榛樿鍊煎閫夌姸鎬�
+	 */
+	setDefaultMultiple(before, after) {
+		this.multipleStatus.before = before
+		this.multipleStatus.after = after
+		if (before && after) {
+			if (dateCompare(before, after)) {
+				this.multipleStatus.data = this.geDateAll(before, after);
+				this.getWeeks(after)
+			} else {
+				this.multipleStatus.data = this.geDateAll(after, before);
+				this.getWeeks(before)
+			}
+		}
+	}
+
+	/**
+	 * 鑾峰彇姣忓懆鏁版嵁
+	 * @param {Object} dateData
+	 */
+	getWeeks(dateData) {
+		const {
+			year,
+			month,
+		} = this.getDateObj(dateData)
+
+		const preMonthDayAmount = new Date(year, month - 1, 1).getDay()
+		const preMonthDays = this.getPreMonthDays(preMonthDayAmount, this.getDateObj(dateData))
+
+		const currentMonthDayAmount = new Date(year, month, 0).getDate()
+		const currentMonthDays = this.getCurrentMonthDays(currentMonthDayAmount, this.getDateObj(dateData))
+
+		const nextMonthDayAmount = 42 - preMonthDayAmount - currentMonthDayAmount
+		const nextMonthDays = this._getNextMonthDays(nextMonthDayAmount, this.getDateObj(dateData))
+
+		const calendarDays = [...preMonthDays, ...currentMonthDays, ...nextMonthDays]
+
+		const weeks = new Array(6)
+		for (let i = 0; i < calendarDays.length; i++) {
+			const index = Math.floor(i / 7)
+			if (!weeks[index]) {
+				weeks[index] = new Array(7)
+			}
+			weeks[index][i % 7] = calendarDays[i]
+		}
+
+		this.calendar = calendarDays
+		this.weeks = weeks
+	}
+}
+
+function getDateTime(date, hideSecond) {
+	return `${getDate(date)} ${getTime(date, hideSecond)}`
+}
+
+function getDate(date) {
+	date = fixIosDateFormat(date)
+	date = new Date(date)
+	const year = date.getFullYear()
+	const month = date.getMonth() + 1
+	const day = date.getDate()
+	return `${year}-${addZero(month)}-${addZero(day)}`
+}
+
+function getTime(date, hideSecond) {
+	date = fixIosDateFormat(date)
+	date = new Date(date)
+	const hour = date.getHours()
+	const minute = date.getMinutes()
+	const second = date.getSeconds()
+	return hideSecond ? `${addZero(hour)}:${addZero(minute)}` : `${addZero(hour)}:${addZero(minute)}:${addZero(second)}`
+}
+
+function addZero(num) {
+	if (num < 10) {
+		num = `0${num}`
+	}
+	return num
+}
+
+function getDefaultSecond(hideSecond) {
+	return hideSecond ? '00:00' : '00:00:00'
+}
+
+function dateCompare(startDate, endDate) {
+	startDate = new Date(fixIosDateFormat(startDate))
+	endDate = new Date(fixIosDateFormat(endDate))
+	return startDate <= endDate
+}
+
+function checkDate(date) {
+	const dateReg = /((19|20)\d{2})(-|\/)\d{1,2}(-|\/)\d{1,2}/g
+	return date.match(dateReg)
+}
+//ios浣庣増鏈�15鍙婁互涓嬶紝鏃犳硶鍖归厤 娌℃湁 鈥欑鈥� 鏃剁殑鎯呭喌锛屾墍浠ラ渶瑕佸湪鏈熬 绉� 鍔犱笂 闂彿
+const dateTimeReg = /^\d{4}-(0?[1-9]|1[012])-(0?[1-9]|[12][0-9]|3[01])( [0-5]?[0-9]:[0-5]?[0-9](:[0-5]?[0-9])?)?$/;
+
+function fixIosDateFormat(value) {
+	if (typeof value === 'string' && dateTimeReg.test(value)) {
+		value = value.replace(/-/g, '/')
+	}
+	return value
+}
+
+export {
+	Calendar,
+	getDateTime,
+	getDate,
+	getTime,
+	addZero,
+	getDefaultSecond,
+	dateCompare,
+	checkDate,
+	fixIosDateFormat
+}
diff --git a/uni_modules/uni-datetime-picker/package.json b/uni_modules/uni-datetime-picker/package.json
new file mode 100644
index 0000000..a886f1b
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/package.json
@@ -0,0 +1,88 @@
+{
+  "id": "uni-datetime-picker",
+  "displayName": "uni-datetime-picker 鏃ユ湡閫夋嫨鍣�",
+  "version": "2.2.38",
+  "description": "uni-datetime-picker 鏃ユ湡鏃堕棿閫夋嫨鍣紝鏀寔鏃ュ巻锛屾敮鎸佽寖鍥撮�夋嫨",
+  "keywords": [
+    "uni-datetime-picker",
+    "uni-ui",
+    "uniui",
+    "鏃ユ湡鏃堕棿閫夋嫨鍣�",
+    "鏃ユ湡鏃堕棿"
+],
+  "repository": "https://github.com/dcloudio/uni-ui",
+  "engines": {
+    "HBuilderX": ""
+  },
+  "directories": {
+    "example": "../../temps/example_temps"
+  },
+"dcloudext": {
+    "sale": {
+      "regular": {
+        "price": "0.00"
+      },
+      "sourcecode": {
+        "price": "0.00"
+      }
+    },
+    "contact": {
+      "qq": ""
+    },
+    "declaration": {
+      "ads": "鏃�",
+      "data": "鏃�",
+      "permissions": "鏃�"
+    },
+    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
+    "type": "component-vue"
+  },
+  "uni_modules": {
+    "dependencies": [
+			"uni-scss",
+			"uni-icons"
+		],
+    "encrypt": [],
+    "platforms": {
+      "cloud": {
+        "tcb": "y",
+        "aliyun": "y",
+        "alipay": "n"
+      },
+      "client": {
+        "App": {
+          "app-vue": "y",
+          "app-nvue": "n"
+        },
+        "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"
+        }
+      }
+    }
+  }
+}
diff --git a/uni_modules/uni-datetime-picker/readme.md b/uni_modules/uni-datetime-picker/readme.md
new file mode 100644
index 0000000..162fbef
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/readme.md
@@ -0,0 +1,21 @@
+
+
+> `閲嶈閫氱煡锛氱粍浠跺崌绾ф洿鏂� 2.0.0 鍚庯紝鏀寔鏃ユ湡+鏃堕棿鑼冨洿閫夋嫨锛岀粍浠� ui 灏嗕娇鐢ㄦ棩鍘嗛�夋嫨鏃ユ湡锛寀i 鍙樺寲杈冨ぇ锛屽悓鏃舵敮鎸� PC 鍜� 绉诲姩绔�傛鐗堟湰涓嶅悜鍚庡吋瀹癸紝涓嶅啀鏀寔鍗曠嫭鐨勬椂闂撮�夋嫨锛坱ype=time锛夊強鐩稿叧鐨� hide-second 灞炴�э紙鏃堕棿閫夊彲浣跨敤鍐呯疆缁勪欢 picker锛夈�傝嫢浠嶉渶浣跨敤鏃х増鏈紝鍙湪鎻掍欢甯傚満涓嬭浇*闈瀠ni_modules鐗堟湰*锛屾棫鐗堟湰灏嗕笉鍐嶇淮鎶
+
+## DatetimePicker 鏃堕棿閫夋嫨鍣�
+
+> **缁勪欢鍚嶏細uni-datetime-picker**
+> 浠g爜鍧楋細 `uDatetimePicker`
+
+
+璇ョ粍浠剁殑浼樺娍鏄紝鏀寔**鏃堕棿鎴�**杈撳叆鍜岃緭鍑猴紙璧峰鏃堕棿銆佺粓姝㈡椂闂翠篃鏀寔鏃堕棿鎴筹級锛屽彲**鍚屾椂閫夋嫨**鏃ユ湡鍜屾椂闂淬��
+
+鑻ュ彧鏄渶瑕佸崟鐙�夋嫨鏃ユ湡鍜屾椂闂达紝涓嶉渶瑕佹椂闂存埑杈撳叆鍜岃緭鍑猴紝鍙娇鐢ㄥ師鐢熺殑 picker 缁勪欢銆�
+
+**_鐐瑰嚮 picker 榛樿鍊艰鍒欙細_**
+
+- 鑻ヨ缃垵濮嬪�� value, 浼氭樉绀哄湪 picker 鏄剧ず妗嗕腑
+- 鑻ユ棤鍒濆鍊� value锛屽垯鍒濆鍊� value 涓哄綋鍓嶆湰鍦版椂闂� Date.now()锛� 浣嗕笉浼氭樉绀哄湪 picker 鏄剧ず妗嗕腑
+
+### [鏌ョ湅鏂囨。](https://uniapp.dcloud.io/component/uniui/uni-datetime-picker)
+#### 濡備娇鐢ㄨ繃绋嬩腑鏈変换浣曢棶棰橈紝鎴栬�呮偍瀵箄ni-ui鏈変竴浜涘ソ鐨勫缓璁紝娆㈣繋鍔犲叆 uni-ui 浜ゆ祦缇わ細871950839 
\ No newline at end of file

--
Gitblit v1.9.3