Kaynağa Gözat

1. 采用了分包处理;
2. 共享空调完成部分界面。

程志平 4 yıl önce
ebeveyn
işleme
e5447460b7
100 değiştirilmiş dosya ile 12323 ekleme ve 2167 silme
  1. 95 89
      manifest.json
  2. 78 29
      pages.json
  3. 7 3
      pages/index/index.vue
  4. 149 120
      pages/reshui/reshui.vue
  5. 544 0
      pagesAir/addAir/addAir.vue
  6. 571 0
      pagesAir/shareAir/shareAir.vue
  7. BIN
      pagesAir/static/images/air-pic.png
  8. BIN
      pagesAir/static/images/power-off.png
  9. BIN
      pagesAir/static/images/power-on.png
  10. BIN
      pagesAir/static/images/qidong.png
  11. BIN
      pagesAir/static/images/tzgl.png
  12. BIN
      pagesAir/static/images/yhye.png
  13. 353 0
      pagesElectric/dfxq/dfxq.vue
  14. 0 0
      pagesElectric/jiaofei/ad_dianfei.vue
  15. 22 0
      pages/jiaofei/jiaofei.css
  16. 59 16
      pages/jiaofei/jiaofei.vue
  17. 0 0
      pagesElectric/select/select.css
  18. 8 8
      pages/select/select.vue
  19. 360 0
      pagesElectric/sfxq/sfxq.vue
  20. 0 0
      pagesElectric/show/show.css
  21. 62 30
      pages/show/show.vue
  22. 0 0
      pagesElectric/static/images/ad_dianfei.png
  23. 0 0
      pagesElectric/static/images/building.png
  24. BIN
      pagesElectric/static/images/dfxq.png
  25. 0 0
      pagesElectric/static/images/elec.png
  26. 0 0
      pagesElectric/static/images/floor.png
  27. 0 0
      pagesElectric/static/images/money.png
  28. 0 0
      pagesElectric/static/images/record.png
  29. 0 0
      pagesElectric/static/images/right.png
  30. 0 0
      pagesElectric/static/images/room.png
  31. 0 0
      pagesElectric/static/images/school.png
  32. BIN
      pagesElectric/static/images/sfxq.png
  33. 0 0
      pagesElectric/static/images/show.png
  34. 239 0
      pagesWater/reshuiDetails/reshuiDetails.vue
  35. 0 1
      static/api.js
  36. BIN
      static/image/banner2x.png
  37. BIN
      static/image/recharge2x.png
  38. BIN
      static/image/shower2x.png
  39. BIN
      static/image/sjx.png
  40. 0 0
      static/images/ad_reshui.png
  41. BIN
      static/images/air.png
  42. 77 0
      uni_modules/qiun-data-charts/changelog.md
  43. 131 65
      uni_modules/qiun-data-charts/components/qiun-data-charts/qiun-data-charts.vue
  44. 4 2
      uni_modules/qiun-data-charts/js_sdk/u-charts/config-echarts.js
  45. 290 325
      uni_modules/qiun-data-charts/js_sdk/u-charts/config-ucharts.js
  46. 3 10
      uni_modules/qiun-data-charts/js_sdk/u-charts/readme.md
  47. 822 301
      uni_modules/qiun-data-charts/js_sdk/u-charts/u-charts.js
  48. 18 0
      uni_modules/qiun-data-charts/js_sdk/u-charts/u-charts.min.js
  49. 8 4
      uni_modules/qiun-data-charts/package.json
  50. 74 423
      uni_modules/qiun-data-charts/readme.md
  51. 29 0
      uni_modules/uni-badge/changelog.md
  52. 268 0
      uni_modules/uni-badge/components/uni-badge/uni-badge.vue
  53. 88 0
      uni_modules/uni-badge/package.json
  54. 10 0
      uni_modules/uni-badge/readme.md
  55. 83 0
      uni_modules/uni-datetime-picker/changelog.md
  56. 185 0
      uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar-item.vue
  57. 898 0
      uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.vue
  58. 19 0
      uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/en.json
  59. 8 0
      uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/index.js
  60. 19 0
      uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hans.json
  61. 19 0
      uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hant.json
  62. 927 0
      uni_modules/uni-datetime-picker/components/uni-datetime-picker/time-picker.vue
  63. 780 686
      uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue
  64. 410 0
      uni_modules/uni-datetime-picker/components/uni-datetime-picker/util.js
  65. 14 6
      uni_modules/uni-datetime-picker/package.json
  66. 9 49
      uni_modules/uni-datetime-picker/readme.md
  67. 22 0
      uni_modules/uni-icons/changelog.md
  68. 1169 0
      uni_modules/uni-icons/components/uni-icons/icons.js
  69. 96 0
      uni_modules/uni-icons/components/uni-icons/uni-icons.vue
  70. 663 0
      uni_modules/uni-icons/components/uni-icons/uniicons.css
  71. BIN
      uni_modules/uni-icons/components/uni-icons/uniicons.ttf
  72. 86 0
      uni_modules/uni-icons/package.json
  73. 8 0
      uni_modules/uni-icons/readme.md
  74. 20 0
      uni_modules/uni-list/changelog.md
  75. 107 0
      uni_modules/uni-list/components/uni-list-ad/uni-list-ad.vue
  76. 58 0
      uni_modules/uni-list/components/uni-list-chat/uni-list-chat.scss
  77. 538 0
      uni_modules/uni-list/components/uni-list-chat/uni-list-chat.vue
  78. 454 0
      uni_modules/uni-list/components/uni-list-item/uni-list-item.vue
  79. 108 0
      uni_modules/uni-list/components/uni-list/uni-list.vue
  80. 65 0
      uni_modules/uni-list/components/uni-list/uni-refresh.vue
  81. 87 0
      uni_modules/uni-list/components/uni-list/uni-refresh.wxs
  82. 91 0
      uni_modules/uni-list/package.json
  83. 346 0
      uni_modules/uni-list/readme.md
  84. 20 0
      uni_modules/uni-pagination/changelog.md
  85. 4 0
      uni_modules/uni-pagination/components/uni-pagination/i18n/en.json
  86. 4 0
      uni_modules/uni-pagination/components/uni-pagination/i18n/es.json
  87. 4 0
      uni_modules/uni-pagination/components/uni-pagination/i18n/fr.json
  88. 12 0
      uni_modules/uni-pagination/components/uni-pagination/i18n/index.js
  89. 4 0
      uni_modules/uni-pagination/components/uni-pagination/i18n/zh-Hans.json
  90. 4 0
      uni_modules/uni-pagination/components/uni-pagination/i18n/zh-Hant.json
  91. 409 0
      uni_modules/uni-pagination/components/uni-pagination/uni-pagination.vue
  92. 86 0
      uni_modules/uni-pagination/package.json
  93. 13 0
      uni_modules/uni-pagination/readme.md
  94. 8 0
      uni_modules/uni-scss/changelog.md
  95. 1 0
      uni_modules/uni-scss/index.scss
  96. 82 0
      uni_modules/uni-scss/package.json
  97. 4 0
      uni_modules/uni-scss/readme.md
  98. 7 0
      uni_modules/uni-scss/styles/index.scss
  99. 3 0
      uni_modules/uni-scss/styles/setting/_border.scss
  100. 0 0
      uni_modules/uni-scss/styles/setting/_color.scss

+ 95 - 89
manifest.json

@@ -1,92 +1,98 @@
 {
 {
-    "name" : "智慧校园水电",
-    "appid" : "__UNI__D7AE6E0",
-    "description" : "",
-    "versionName" : "1.0.0",
-    "versionCode" : "100",
-    "transformPx" : false,
-    /* 5+App特有相关 */
-    "app-plus" : {
-        "usingComponents" : true,
-        "nvueStyleCompiler" : "uni-app",
-        "compilerVersion" : 3,
-        "splashscreen" : {
-            "alwaysShowBeforeRender" : true,
-            "waiting" : true,
-            "autoclose" : true,
-            "delay" : 0
-        },
-        /* 模块配置 */
-        "modules" : {},
-        /* 应用发布信息 */
-        "distribute" : {
-            /* android打包配置 */
-            "android" : {
-                "permissions" : [
-                    "<uses-feature android:name=\"android.hardware.camera\"/>",
-                    "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
-                    "<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
-                    "<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
-                    "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
-                    "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
-                    "<uses-permission android:name=\"android.permission.BLUETOOTH\"/>",
-                    "<uses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\"/>",
-                    "<uses-permission android:name=\"android.permission.CAMERA\"/>",
-                    "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
-                    "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
-                    "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
-                    "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
-                    "<uses-permission android:name=\"android.permission.INTERNET\"/>",
-                    "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
-                    "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
-                    "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
-                    "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
-                    "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
-                    "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>",
-                    "<uses-permission android:name=\"android.permission.BLUETOOTH\"/>",
-                    "<uses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\"/>"
-                ]
-            },
-            /* ios打包配置 */
-            "ios" : {},
-            /* SDK配置 */
-            "sdkConfigs" : {
-                "payment" : {}
-            }
-        }
-    },
-    /* 快应用特有相关 */
-    "quickapp" : {},
-    /* 小程序特有相关 */
-    "mp-weixin" : {
-        "appid" : "wxd6f090391d410534",
-        "setting" : {
-            "urlCheck" : false
-        },
-        "usingComponents" : true,
-        "plugins" : {
-            "myPlugin" : {
-                "provider" : "wx1549b963bbae9931",
-                "version" : "4.0.0"
-            }
-        },
-        "permission" : {
-            "scope.userLocation" : {
-                "desc" : "您的位置信息将用于连接热水表蓝牙"
-            }
-        },
+	"name": "智慧校园水电",
+	"appid": "__UNI__D7AE6E0",
+	"description": "",
+	"versionName": "1.0.0",
+	"versionCode": "100",
+	"transformPx": false,
+	/* 5+App特有相关 */
+	"app-plus": {
+		"usingComponents": true,
+		"nvueStyleCompiler": "uni-app",
+		"compilerVersion": 3,
+		"splashscreen": {
+			"alwaysShowBeforeRender": true,
+			"waiting": true,
+			"autoclose": true,
+			"delay": 0
+		},
+		/* 模块配置 */
+		"modules": {},
+		/* 应用发布信息 */
+		"distribute": {
+			/* android打包配置 */
+			"android": {
+				"permissions": [
+					"<uses-feature android:name=\"android.hardware.camera\"/>",
+					"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
+					"<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
+					"<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
+					"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
+					"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
+					"<uses-permission android:name=\"android.permission.BLUETOOTH\"/>",
+					"<uses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\"/>",
+					"<uses-permission android:name=\"android.permission.CAMERA\"/>",
+					"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
+					"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
+					"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
+					"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
+					"<uses-permission android:name=\"android.permission.INTERNET\"/>",
+					"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
+					"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
+					"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
+					"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
+					"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
+					"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>",
+					"<uses-permission android:name=\"android.permission.BLUETOOTH\"/>",
+					"<uses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\"/>"
+				]
+			},
+			/* ios打包配置 */
+			"ios": {},
+			/* SDK配置 */
+			"sdkConfigs": {
+				"payment": {}
+			}
+		},
+		// ====================支持分包==================
+		"optimization": {
+			"subPackages": true
+		},
+		"runmode": "liberate" // 开启分包优化后,必须配置资源释放模式
+		// ====================支持分包==================
+	},
+	/* 快应用特有相关 */
+	"quickapp": {},
+	/* 小程序特有相关 */
+	"mp-weixin": {
+		"appid": "wxd6f090391d410534",
+		"setting": {
+			"urlCheck": false
+		},
+		"usingComponents": true,
+		"plugins": {
+			"myPlugin": {
+				"provider": "wx1549b963bbae9931",
+				"version": "4.0.0"
+			}
+		},
+		"permission": {
+			"scope.userLocation": {
+				"desc": "您的位置信息将用于连接热水表蓝牙"
+			}
+		},
 		"lazyCodeLoading": "requiredComponents"
 		"lazyCodeLoading": "requiredComponents"
-    },
-    "mp-alipay" : {
-        "usingComponents" : true
-    },
-    "mp-baidu" : {
-        "usingComponents" : true
-    },
-    "mp-toutiao" : {
-        "usingComponents" : true
-    },
-    "uniStatistics" : {
-        "enable" : false
-    }
+	},
+	"mp-alipay": {
+		"usingComponents": true
+	},
+	"mp-baidu": {
+		"usingComponents": true
+	},
+	"mp-toutiao": {
+		"usingComponents": true
+	},
+	"uniStatistics": {
+		"enable": false
+	}
 }
 }

+ 78 - 29
pages.json

@@ -6,8 +6,13 @@
 				"navigationBarTitleText": "校园",
 				"navigationBarTitleText": "校园",
 				"enablePullDownRefresh": false
 				"enablePullDownRefresh": false
 			}
 			}
-		},
-		{
+		}, {
+			"path": "pages/qr_code/qr_code",
+			"style": {
+				"navigationBarTitleText": "校园卡二维码",
+				"enablePullDownRefresh": false
+			}
+		}, {
 			"path": "pages/reshui/reshui",
 			"path": "pages/reshui/reshui",
 			"style": {
 			"style": {
 				"navigationBarTitleText": "热水",
 				"navigationBarTitleText": "热水",
@@ -27,44 +32,88 @@
 				"navigationBarTitleText": "热水钱包充值",
 				"navigationBarTitleText": "热水钱包充值",
 				"enablePullDownRefresh": false
 				"enablePullDownRefresh": false
 			}
 			}
-		}, 
-		{
-			"path": "pages/jiaofei/jiaofei",
-			"style": {
-				"navigationBarTitleText": "水电充值",
-				"enablePullDownRefresh": false
-			}
-		},
-		{
-			"path": "pages/jiaofei/ad_dianfei",
-			"style": {
-				"navigationBarTitleText": "",
-				"enablePullDownRefresh": false
+		}
+	],
+	"subPackages": [{
+		"root": "pagesElectric",
+		"pages": [{
+				"path": "dfxq/dfxq",
+				"style": {
+					"navigationBarTitleText": "电费详情",
+					"enablePullDownRefresh": false
+				}
+			},
+			{
+				"path": "sfxq/sfxq",
+				"style": {
+					"navigationBarTitleText": "水费详情",
+					"enablePullDownRefresh": false
+				}
+			},
+			{
+				"path": "jiaofei/jiaofei",
+				"style": {
+					"navigationBarTitleText": "水电充值",
+					"enablePullDownRefresh": false
+				}
+			},
+			{
+				"path": "jiaofei/ad_dianfei",
+				"style": {
+					"navigationBarTitleText": "",
+					"enablePullDownRefresh": false
+				}
+			},
+			{
+				"path": "show/show",
+				"style": {
+					"navigationBarTitleText": "台账管理",
+					"enablePullDownRefresh": false
+				}
+			},
+			{
+				"path": "select/select",
+				"style": {
+					"navigationBarTitleText": "缴水电费_选宿舍号",
+					"enablePullDownRefresh": false
+				}
 			}
 			}
-		},
-		{
-			"path": "pages/show/show",
+		]
+	}, {
+		"root": "pagesWater",
+		"pages": [{
+			"path": "reshuiDetails/reshuiDetails",
 			"style": {
 			"style": {
-				"navigationBarTitleText": "台账管理",
+				"navigationBarTitleText": "热水充值详情",
 				"enablePullDownRefresh": false
 				"enablePullDownRefresh": false
 			}
 			}
-
-		},
-		{
-			"path": "pages/select/select",
+		}]
+	}, {
+		"root": "pagesAir",
+		"pages": [{
+			"path": "shareAir/shareAir",
 			"style": {
 			"style": {
-				"navigationBarTitleText": "缴水电费",
+				"navigationBarTitleText": "共享空调",
 				"enablePullDownRefresh": false
 				"enablePullDownRefresh": false
 			}
 			}
-
 		}, {
 		}, {
-			"path": "pages/qr_code/qr_code",
+			"path": "addAir/addAir",
 			"style": {
 			"style": {
-				"navigationBarTitleText": "校园卡二维码",
+				"navigationBarTitleText": "添加空调",
 				"enablePullDownRefresh": false
 				"enablePullDownRefresh": false
 			}
 			}
-		}
-	],
+		}]
+	}],
+	// "preloadRule": {
+	// 	"pagesA/list/list": {
+	// 		"network": "all",
+	// 		"packages": ["__APP__"]
+	// 	},
+	// 	"pagesB/detail/detail": {
+	// 		"network": "all",
+	// 		"packages": ["pagesA"]
+	// 	}
+	// },
 	"globalStyle": {
 	"globalStyle": {
 		"navigationBarTextStyle": "black",
 		"navigationBarTextStyle": "black",
 		"navigationBarTitleText": "uni-app",
 		"navigationBarTitleText": "uni-app",

+ 7 - 3
pages/index/index.vue

@@ -5,14 +5,18 @@
 		</view>
 		</view>
 		<view class="nav">
 		<view class="nav">
 			<view class="menu">
 			<view class="menu">
-				<navigator :url="'/pages/reshui/reshui'" open-type="redirect" class="menu_item">
+				<navigator :url="'/pages/reshui/reshui'" open-type="navigate" class="menu_item">
 					<image src="../../static/images/shower2x.png" mode=""></image>
 					<image src="../../static/images/shower2x.png" mode=""></image>
 					<text>洗 浴</text>
 					<text>洗 浴</text>
 				</navigator>
 				</navigator>
-				<navigator :url="'/pages/jiaofei/jiaofei?o=index'" open-type="redirect" class="menu_item">
+				<navigator :url="'/pagesElectric/jiaofei/jiaofei?o=index'" open-type="navigate" class="menu_item">
 					<image src="../../static/images/recharge2x.png" mode=""></image>
 					<image src="../../static/images/recharge2x.png" mode=""></image>
 					<text>水电充值</text>
 					<text>水电充值</text>
 				</navigator>
 				</navigator>
+				<navigator :url="'/pagesAir/shareAir/shareAir'" open-type="navigate" class="menu_item">
+					<image src="../../static/images/air.png" mode=""></image>
+					<text>共享空调</text>
+				</navigator>
 			</view>
 			</view>
 		</view>
 		</view>
 		<view class="qr_code" v-if="showQR_code">
 		<view class="qr_code" v-if="showQR_code">
@@ -225,7 +229,7 @@
 				} = detail
 				} = detail
 
 
 				this.validation_failed = false
 				this.validation_failed = false
-				
+
 				// 屏蔽用户操作
 				// 屏蔽用户操作
 				uni.showLoading({
 				uni.showLoading({
 					title: '获取数据中…',
 					title: '获取数据中…',

+ 149 - 120
pages/reshui/reshui.vue

@@ -24,7 +24,7 @@
 				<view class="start_mid">
 				<view class="start_mid">
 					<view class="item_left">
 					<view class="item_left">
 						<text class="iconfont icon-qian"></text>
 						<text class="iconfont icon-qian"></text>
-						<text class="start_mid_txt">¥{{amount}}</text>
+						<navigator url="/pagesWater/reshuiDetails/reshuiDetails" open-type="navigate" class="start_mid_txt">¥{{amount}}</navigator>
 					</view>
 					</view>
 					<view class="start_payamount" @tap="chongzhi_yemian()" hover-class="scan_hover">
 					<view class="start_payamount" @tap="chongzhi_yemian()" hover-class="scan_hover">
 						<text>点击充值</text>
 						<text>点击充值</text>
@@ -46,7 +46,7 @@
 				<uni-steps :options="list1" :active-color="colorPrimary" :active="active" />
 				<uni-steps :options="list1" :active-color="colorPrimary" :active="active" />
 			</view>
 			</view>
 			<view class="ad">
 			<view class="ad">
-				<image src="../../static/image/ad_reshui.png" mode="aspectFit" class="ad_img" @tap="ad_redirect">
+				<image src="../../static/images/ad_reshui.png" mode="aspectFit" class="ad_img" @tap="ad_redirect">
 				</image>
 				</image>
 			</view>
 			</view>
 			<view class="title">
 			<view class="title">
@@ -197,19 +197,23 @@
 			 * 单击连接热水表
 			 * 单击连接热水表
 			 */
 			 */
 			clickRoom(e) {
 			clickRoom(e) {
-				if (this.judgeBalance('clickRoom') === false) {
-					return
-				} else {
-					this.device_code = 'K' + e
+				try {
+					if (this.judgeBalance('clickRoom') === false) {
+						return
+					} else {
+						this.device_code = 'K' + e
 
 
-					for (var i = 0, len = this.devices.length; i < len; i++) {
-						if (this.devices[i].dname == e) {
-							this.deviceId = this.devices[i].did
-							break
+						for (var i = 0, len = this.devices.length; i < len; i++) {
+							if (this.devices[i].dname == e) {
+								this.deviceId = this.devices[i].did
+								break
+							}
 						}
 						}
+						// 开始连接匹配的蓝牙设备
+						this.createBLEConnection();
 					}
 					}
-					// 开始连接匹配的蓝牙设备
-					this.createBLEConnection();
+				} catch (e) {
+					console.log('单击连接热水表:' + e.message);
 				}
 				}
 			},
 			},
 			/**
 			/**
@@ -283,7 +287,7 @@
 						}
 						}
 					}
 					}
 				} catch (e) {
 				} catch (e) {
-					// console.log(e);
+					console.log('获取基本信息:' + e.message);
 				}
 				}
 
 
 				if (param == 'onShow') {
 				if (param == 'onShow') {
@@ -416,55 +420,59 @@
 						uni.removeStorageSync("instruction_noshow")
 						uni.removeStorageSync("instruction_noshow")
 					}
 					}
 				} catch (e) {
 				} catch (e) {
-					// console.log(e);
+					console.log('使用说明组件不再出现:' + e.message);
 				}
 				}
 			},
 			},
 			/**
 			/**
 			 * 请求选定的月份消费记录
 			 * 请求选定的月份消费记录
 			 */
 			 */
 			async request_consumption_records() {
 			async request_consumption_records() {
-				if (this.stu_number != '' && typeof(this.stu_number) != 'undefined') {
-					const res = await this.$myRequest({
-						host: this.ceshi,
-						url: '/HotWaters/wpqueryConsume.action',
-						method: 'POST',
-						header: {
-							'content-type': 'application/x-www-form-urlencoded'
-						},
-						data: {
-							stu_number: this.stu_number,
-							begin_time: this.date
-						}
-					});
+				try {
+					if (this.stu_number != '' && typeof(this.stu_number) != 'undefined') {
+						const res = await this.$myRequest({
+							host: this.ceshi,
+							url: '/HotWaters/wpqueryConsume.action',
+							method: 'POST',
+							header: {
+								'content-type': 'application/x-www-form-urlencoded'
+							},
+							data: {
+								stu_number: this.stu_number,
+								begin_time: this.date
+							}
+						});
 
 
-					// console.log(res);
-					if (res.data.mess == '返回成功') {
-						this.xiaofei_items = []
-						// 消费记录
-						let items = res.data.data
-						for (var i = 0; i < items.length; i++) {
-							this.xiaofei_items.push(items[i])
-						}
-					} else {
-						if (this.changeDate) {
-							uni.showToast({
-								icon: 'success',
-								title: res.data.mess,
-								success: () => {
-									this.changeDate = false
-								}
-							})
+						// console.log(res);
+						if (res.data.mess == '返回成功') {
+							this.xiaofei_items = []
+							// 消费记录
+							let items = res.data.data
+							for (var i = 0; i < items.length; i++) {
+								this.xiaofei_items.push(items[i])
+							}
+						} else {
+							if (this.changeDate) {
+								uni.showToast({
+									icon: 'success',
+									title: res.data.mess,
+									success: () => {
+										this.changeDate = false
+									}
+								})
 
 
-							if (res.data.mess == '本月无消费记录') {
-								this.xiaofei_items = []
+								if (res.data.mess == '本月无消费记录') {
+									this.xiaofei_items = []
+								}
 							}
 							}
 						}
 						}
+					} else {
+						uni.showToast({
+							icon: 'success',
+							title: '未获得学号'
+						})
 					}
 					}
-				} else {
-					uni.showToast({
-						icon: 'success',
-						title: '未获得学号'
-					})
+				} catch (e) {
+					console.log('请求选定的月份消费记录:' + e.message);
 				}
 				}
 			},
 			},
 			/**
 			/**
@@ -472,8 +480,12 @@
 			 * @param {Object} active_value
 			 * @param {Object} active_value
 			 */
 			 */
 			process_control(active_value) {
 			process_control(active_value) {
-				if (active_value <= this.list1.length - 1) {
-					this.active = active_value
+				try {
+					if (active_value <= this.list1.length - 1) {
+						this.active = active_value
+					}
+				} catch (e) {
+					console.log('控制进度条显示:' + e.message);
 				}
 				}
 			},
 			},
 
 
@@ -809,91 +821,105 @@
 				uni.onBluetoothDeviceFound((res) => {
 				uni.onBluetoothDeviceFound((res) => {
 					let dname = ''
 					let dname = ''
 					res.devices.forEach(device => { // 筛选找到的蓝牙中对名称匹配
 					res.devices.forEach(device => { // 筛选找到的蓝牙中对名称匹配
-						// 过滤掉没有名字的设备
-						if (!device.name && !device.localName) {
-							return
-						}
-						// 把搜索到的设备存储起来,如有需要可以在页面上展示
-						dname = device.name.substr(1)
-						let d = {
-							did: device.deviceId,
-							dname: dname
-						}
-						if (dname.length == 10 && JSON.stringify(this.devices).indexOf(JSON.stringify(
-								d)) === -1) {
-							this.devices.push(d)
-						}
+						try {
+							// 过滤掉没有名字的设备
+							if (!device.name && !device.localName) {
+								return
+							}
+							// 把搜索到的设备存储起来,如有需要可以在页面上展示
+							dname = device.name.substr(1)
+							let d = {
+								did: device.deviceId,
+								dname: dname
+							}
 
 
-						if (device.name == this.device_code) {
-							this.process_control(0);
+							if (dname.length == 10 && JSON.stringify(this.devices).indexOf(JSON.stringify(
+									d)) === -1) {
+								this.devices.push(d)
+							}
 
 
-							//data里面建立一个deviceId、device_code,存储起来
-							// this.device_code = device.name;
-							this.deviceId = device.deviceId
+							if (device.name == this.device_code) {
+								this.process_control(0);
 
 
-							// 放此位置,苹果手机兼容
-							this.stopBluetoothDevicesDiscovery()
+								//data里面建立一个deviceId、device_code,存储起来
+								// this.device_code = device.name;
+								this.deviceId = device.deviceId
 
 
-							return
-						}
+								// 放此位置,苹果手机兼容
+								this.stopBluetoothDevicesDiscovery()
 
 
-						setTimeout(() => {
-							this.stopBluetoothDevicesDiscovery()
-						}, 2000)
+								return
+							}
+
+							setTimeout(() => {
+								this.stopBluetoothDevicesDiscovery()
+							}, 2000)
+						} catch (e) {
+							console.log('发现外围设备:' + e.message);
+						}
 					})
 					})
 				});
 				});
 			},
 			},
 			// 获取水表对应的宿舍号
 			// 获取水表对应的宿舍号
 			async get_room() {
 			async get_room() {
-				if (this.devices.length > 0) {
-					let devices_str = []
-
-					for (var i = 0, len = this.devices.length; i < len; i++) {
-						devices_str.push(this.devices[i].dname)
-					}
+				try {
+					if (this.devices.length > 0) {
+						let devices_str = []
 
 
-					const res = await this.$myRequest({
-						host: this.ceshi,
-						url: '/HotWaters/waterqueryDom.action',
-						method: 'POST',
-						header: {
-							'content-type': 'application/x-www-form-urlencoded'
-						},
-						data: {
-							user_id: devices_str.join(',')
+						for (var i = 0, len = this.devices.length; i < len; i++) {
+							devices_str.push(this.devices[i].dname)
 						}
 						}
-					});
 
 
-					if (res.data.msg == '获取成功') {
-						// 消费记录
-						let items = res.data.data
-						if (items == 'undefined') {
-							return
-						}
-						for (var i = 0; i < items.length; i++) {
-							let item = {
-								id: items[i].user_id,
-								room: items[i].dom
+						const res = await this.$myRequest({
+							host: this.ceshi,
+							url: '/HotWaters/waterqueryDom.action',
+							method: 'POST',
+							header: {
+								'content-type': 'application/x-www-form-urlencoded'
+							},
+							data: {
+								user_id: devices_str.join(',')
 							}
 							}
-							if (JSON.stringify(this.rooms).indexOf(JSON.stringify(item)) === -1) {
-								this.rooms.push(item); // 进行动态的操作
+						});
+
+						if (res.data.msg == '获取成功') {
+							// 消费记录
+							let items = res.data.data
+							if (typeof items === 'undefined') {
+								uni.showToast({
+									title: '获取宿舍号为空',
+									duration: 2000
+								})
+								return
 							}
 							}
-						}
-					} else {
-						if (this.changeDate) {
-							uni.showToast({
-								icon: 'success',
-								title: res.data.mess,
-								success: () => {
-									this.changeDate = false
+							
+							for (var i = 0; i < items.length; i++) {
+								let item = {
+									id: items[i].user_id,
+									room: items[i].dom
 								}
 								}
-							})
+								if (JSON.stringify(this.rooms).indexOf(JSON.stringify(item)) === -1) {
+									this.rooms.push(item); // 进行动态的操作
+								}
+							}
+						} else {
+							if (this.changeDate) {
+								uni.showToast({
+									icon: 'success',
+									title: res.data.mess,
+									success: () => {
+										this.changeDate = false
+									}
+								})
 
 
-							if (res.data.mess == '本月无消费记录') {
-								this.xiaofei_items = []
+								if (res.data.mess == '本月无消费记录') {
+									this.xiaofei_items = []
+								}
 							}
 							}
 						}
 						}
 					}
 					}
+				} catch (e) {
+					console.log('获取水表对应的宿舍号:' + e.message);
 				}
 				}
 			},
 			},
 
 
@@ -1278,7 +1304,7 @@
 						}
 						}
 					},
 					},
 					fail: (err) => {
 					fail: (err) => {
-						console.log(err)
+						// console.log(err)
 						if (err.errCode == 10006) {
 						if (err.errCode == 10006) {
 							setTimeout(() => {
 							setTimeout(() => {
 								this.setInit()
 								this.setInit()
@@ -1509,8 +1535,11 @@
 					}
 					}
 
 
 					.start_mid_txt {
 					.start_mid_txt {
+						padding: 16rpx;
+						border-radius: 10rpx;
+						font-size: 36rpx;
+						font-weight: bold;
 						color: #333;
 						color: #333;
-						font-size: 30rpx;
 					}
 					}
 
 
 					.iconfont {
 					.iconfont {

+ 544 - 0
pagesAir/addAir/addAir.vue

@@ -0,0 +1,544 @@
+<template>
+	<view class="container">
+		<view class="line"></view>
+		<view class="show-selected">
+			<view class="title-selected">已选择:</view>
+			<view class="air-selected-name">{{show_airs}}</view>
+		</view>
+		<view class="btn">
+			<view class="btn-bg" @tap="confirm_selection">确认选择</view>
+		</view>
+		<view class="line"></view>
+		<view class="title-tip">请选择</view>
+		<view class="line"></view>
+		<view class="tree-box">
+			<scroll-view scroll-y="true" class="tree-scroll" :style="{height: screenHeight}">
+				<view class="item-loudong" v-for="(item1, index1) in treeData" :key="index1">
+					<view class="loudong" :id="item1.id" @tap="handle_toggle_items">
+						<view class="title-loudong">
+							<uni-icons type="plus-filled" size="22" color="#2979ff"
+								:style="{display: item1.isShow ? 'none' : ''}"></uni-icons>
+							<uni-icons type="minus-filled" size="22" color="#2979ff"
+								:style="{display: item1.isShow ? '' : 'none'}"></uni-icons>
+							<view class="txt-loudong">{{item1.label}}</view>
+						</view>
+						<uni-icons type="bottom" size="22" color="#2979ff"
+							:style="{display: item1.isShow ? '' : 'none'}"></uni-icons>
+						<uni-icons type="top" size="22" color="#2979ff" :style="{display: item1.isShow ? 'none' : ''}">
+						</uni-icons>
+					</view>
+					<view class="item-loucheng" v-for="(item2, index2) in item1.children" :key="index2"
+						:style="{display: item1.isShow ? '' : 'none'}">
+						<view class="loucheng" :id="item2.id" @tap="handle_toggle_items">
+							<view class="title-loucheng">
+								<uni-icons type="plus-filled" size="22" color="#2979ff"
+									:style="{display: item2.isShow ? 'none' : ''}"></uni-icons>
+								<uni-icons type="minus-filled" size="22" color="#2979ff"
+									:style="{display: item2.isShow ? '' : 'none'}"></uni-icons>
+								<view class="txt-loucheng">{{item2.label}}</view>
+							</view>
+							<uni-icons type="bottom" size="22" color="#2979ff"
+								:style="{display: item2.isShow ? '' : 'none'}"></uni-icons>
+							<uni-icons type="top" size="22" color="#2979ff"
+								:style="{display: item2.isShow ? 'none' : ''}"></uni-icons>
+						</view>
+						<view class="item-jiaoshi" v-for="(item3, index3) in item2.children" :key="index3"
+							:style="{display: item2.isShow ? '' : 'none'}">
+							<view class="jiaoshi" :id="item3.id" @tap="handle_toggle_items">
+								<view class="title-jiaoshi">
+									<uni-icons type="plus-filled" size="22" color="#2979ff"
+										:style="{display: item3.isShow ? 'none' : ''}"></uni-icons>
+									<uni-icons type="minus-filled" size="22" color="#2979ff"
+										:style="{display: item3.isShow ? '' : 'none'}"></uni-icons>
+									<view class="txt-jiaoshi">{{item3.label}}</view>
+								</view>
+								<uni-icons type="bottom" size="22" color="#2979ff"
+									:style="{display: item3.isShow ? '' : 'none'}"></uni-icons>
+								<uni-icons type="top" size="22" color="#2979ff"
+									:style="{display: item3.isShow ? 'none' : ''}"></uni-icons>
+							</view>
+							<view v-for="(item4, index4) in item3.children" :key="index4"
+								:style="{display: item3.isShow ? '' : 'none'}">
+								<view class="item-kongtiao" v-if="item4.isUsering">
+									<view :style="{color: item4.isUsering ? '#747578' : '#2979ff'}">
+										{{item4.label}}(使用中)
+									</view>
+									<checkbox :id="item4.id" :checked="true" :disabled="true" />
+								</view>
+								<view class="item-kongtiao" v-else>
+									<view :style="{color: item4.isUsering ? '#747578' : '#2979ff'}">
+										{{item4.label}}
+									</view>
+									<checkbox :value="index4" :id="item4.id" :checked="item4.isChecked"
+										@tap="handle_kongtiao" />
+								</view>
+							</view>
+						</view>
+					</view>
+				</view>
+			</scroll-view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				// 用于返回到上一页面的结果变量
+				airs_selected: '',
+				show_airs: '', // 用于显示已经选择的空调
+				screenHeight: '', // 屏幕的高度
+				// tree
+				treeData: [] // 树形选择器的数据
+			};
+		},
+		onLoad() {
+			uni.showLoading({
+				title: '加载中'
+			})
+
+			// 模拟异步请求
+			setTimeout(() => {
+				this.treeData = [{
+					id: 1,
+					label: '科技楼',
+					isShow: false,
+					children: [{
+						id: 11,
+						label: '5F',
+						isShow: false,
+						children: [{
+							id: 111,
+							label: '501',
+							isShow: false,
+							children: [{
+								id: 1111,
+								label: '空调-01',
+								isChecked: false,
+								isUsering: false
+							}, {
+								id: 1112,
+								label: '空调-02',
+								isChecked: true,
+								isUsering: true
+							}]
+						}, {
+							id: 112,
+							label: '502',
+							isShow: false,
+							children: [{
+								id: 1121,
+								label: '空调-01',
+								isChecked: false,
+								isUsering: false
+							}]
+						}]
+					}]
+				}, {
+					id: 2,
+					label: '志胜楼',
+					isShow: false,
+					children: [{
+						id: 21,
+						label: '1F',
+						isShow: false,
+						children: [{
+							id: 211,
+							label: '101',
+							isShow: false,
+							children: [{
+								id: 2111,
+								label: '空调-01',
+								isChecked: false,
+								isUsering: false
+							}, {
+								id: 2112,
+								label: '空调-02',
+								isChecked: false,
+								isUsering: false
+							}]
+						}, {
+							id: 212,
+							label: '102',
+							isShow: false,
+							children: [{
+								id: 2121,
+								label: '空调-01',
+								isChecked: false,
+								isUsering: false
+							}, {
+								id: 2122,
+								label: '空调-02',
+								isChecked: false,
+								isUsering: false
+							}]
+						}]
+					}]
+				}];
+
+				setTimeout(() => {
+					uni.hideLoading();
+				}, 500);
+			}, 500);
+		},
+		onShow() {
+			// 从新计算高度
+			this.calc_screen_height()
+		},
+		methods: {
+			/**
+			 * 获取空调的全称,勾选返回空调全称,不勾返回-空调全称,递归调用
+			 * @param {Object} obj
+			 * @param {Object} id
+			 * @param {Object} parentName
+			 */
+			get_airs_full_name(obj, id, parentName) {
+				for (var i = 0; i < obj.length; i++) {
+					if (obj[i].id == id) {
+						if (parentName == '') {
+							return obj[i].label
+						}
+
+						if (obj[i].isChecked) {
+							obj[i].isChecked = false
+							return '-' + parentName + ' ' + obj[i].label
+						} else {
+							obj[i].isChecked = true
+							return parentName + ' ' + obj[i].label
+						}
+					}
+
+					let selfName = ''
+					if (typeof obj[i].children != 'undefined' && obj[i].children.length > 0) {
+						if (parentName == '') {
+							selfName = this.get_airs_full_name(obj[i].children, id, obj[i].label)
+						} else {
+							selfName = this.get_airs_full_name(obj[i].children, id, parentName + '-' + obj[i].label)
+						}
+
+						if (typeof selfName != 'undefined') {
+							return selfName
+						}
+					}
+				}
+			},
+			/**
+			 * 更新airs_selected中的数据
+			 * @param {Object} param
+			 */
+			update_airs_selected(param) {
+				let tmp_airs_selected = ''
+				if (param.indexOf('-') == 0) { // 删除airs_selected中的数据
+					// 把前面的'-'去除
+					let del_val = param.substring(1)
+					// 需要删除的值进行拆分成:【楼栋-楼层-房间,空调】
+					let room = del_val.split(' ')
+					if (this.airs_selected.trim() != '') {
+						let arrAirs = this.airs_selected.trim().split(',')
+						let airs = ''
+						for (var i = 0; i < arrAirs.length; i++) {
+							airs = arrAirs[i].trim() // 删除空格后,赋给临时变量
+							// 如果找到指定的房间,则删除
+							if (airs.indexOf(room[0]) == 0) {
+								// 删除 楼栋-楼层-房间 中的空调
+								airs = airs.replace(' ' + room[1], '')
+								// 如果只剩下 楼栋-楼层-房间,没有了空调,则置为空
+								if (airs == room[0]) {
+									airs = ''
+								}
+							}
+
+							if (airs != '') {
+								// 保存到临时变量tmp_airs_selected中
+								tmp_airs_selected += airs + ','
+							}
+						}
+					}
+				} else { // 添加、合并到airs_selected中
+					// 如果为空,直接加入
+					if (this.airs_selected.trim() == '') {
+						tmp_airs_selected = param + ','
+					} else {
+						let arrAirs = this.airs_selected.trim().split(',')
+						let num = 0
+						// 需要添加的数据
+						let room = param.split(' ')
+						for (var i = 0; i < arrAirs.length; i++) {
+							let airs = arrAirs[i].trim().split(' ')
+							// 如果找到指定的房间,则合并
+							if (airs[0] == room[0]) {
+								// 临时数组, 为排序做准备
+								let tmp_arr = []
+								// 数组转字符串, 即拼接
+								tmp_arr.push(room[1])
+								for (var j = 1; j < airs.length; j++) {
+									tmp_arr.push(airs[j])
+								}
+								// 数组排序
+								tmp_arr.sort()
+								// 生成字符串
+								tmp_airs_selected += room[0]
+								for (var k = 0; k < tmp_arr.length; k++) {
+									tmp_airs_selected += ' ' + tmp_arr[k]
+								}
+								// 加入分隔符
+								tmp_airs_selected += ','
+							} else {
+								num++ // 计数
+								tmp_airs_selected += arrAirs[i] + ','
+							}
+						}
+						// 如果没有找到同一房间的,则直接拼接要添加的数据
+						if (num == arrAirs.length) {
+							tmp_airs_selected += param + ','
+						}
+					}
+				}
+				// 更新变量airs_selected
+				this.airs_selected = tmp_airs_selected.substring(0, tmp_airs_selected.length - 1)
+				// 更新显示框的内容
+				this.show_selected_airs()
+			},
+			/**
+			 * 选择空调
+			 * @param {Object} e
+			 */
+			handle_kongtiao(e) {
+				// console.log(e.currentTarget.id);
+				// 获取id
+				let id = e.currentTarget.id
+				// 获取勾选的值
+				let airsFullName = this.get_airs_full_name(this.treeData, id, '')
+				if (typeof airsFullName != 'undefined') {
+					// 更新airs_selected中的数据
+					this.update_airs_selected(airsFullName)
+				} else {
+					uni.showToast({
+						title: '选取无效!',
+						duration: 1500
+					})
+				}
+			},
+			/**
+			 * 选项的展开与收起,进行切换,递归调用
+			 * @param {Object} obj
+			 * @param {Object} id
+			 */
+			toggle_item(obj, id) {
+				for (var i = 0; i < obj.length; i++) {
+					if (obj[i].id == id) {
+						if (obj[i].isShow) {
+							obj[i].isShow = false
+						} else {
+							obj[i].isShow = true
+						}
+						return
+					}
+
+					if (typeof obj[i].children != 'undefined' && obj[i].children.length > 0) {
+						this.toggle_item(obj[i].children, id)
+					}
+				}
+			},
+			/**
+			 * 选项的展开与收起,进行切换
+			 * @param {Object} e
+			 */
+			handle_toggle_items(e) {
+				// console.log(e.currentTarget.id);
+				// 获取id
+				let id = e.currentTarget.id
+				this.toggle_item(this.treeData, id)
+			},
+			/**
+			 * 确认选择,将结果返回到前一页面显示
+			 */
+			confirm_selection() {
+				// 触发全局的自定义事件,附加参数都会传给监听器回调函数。
+				if (this.airs_selected != '') {
+					uni.$emit('selectAirs', {
+						airs: this.airs_selected
+					})
+				}
+
+				// 返回空调列表页面
+				uni.navigateBack({
+					delta: -1
+				})
+			},
+			/**
+			 * 超出左边显示...
+			 */
+			show_selected_airs() {
+				// 显示到上方
+				this.show_airs = this.airs_selected.split('').reverse().join('')
+			},
+			/**
+			 * 计算屏幕的高度
+			 */
+			calc_screen_height() {
+				uni.getSystemInfo({
+					success: res => {
+						let h = ((res.screenHeight * (750 / res.windowWidth)) - 480) //将px 转换rpx
+						this.screenHeight = Math.floor(h) + 'rpx'
+					}
+				});
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.container {
+		display: flex;
+		flex-direction: column;
+		font-size: 28rpx;
+		font-family: "Microsoft YaHei-3970(82674968)";
+		width: 730rpx;
+		padding: 10rpx;
+
+		.line {
+			height: 20rpx;
+		}
+
+		.show-selected {
+			display: flex;
+			padding: 20rpx;
+			border-radius: 10rpx;
+			border: 1px solid #c7c9ce;
+			font-size: 32rpx;
+
+			.title-selected {
+				color: #686b71;
+				white-space: nowrap;
+			}
+
+			.air-selected-name {
+				width: 600rpx;
+				font-weight: bold;
+				white-space: nowrap;
+				text-overflow: ellipsis;
+				direction: rtl;
+				unicode-bidi: bidi-override;
+				overflow: hidden;
+			}
+		}
+
+		.btn {
+			display: flex;
+			justify-content: flex-end;
+
+			.btn-bg {
+				margin-top: 30rpx;
+				padding: 20rpx 40rpx;
+				border-radius: 10rpx;
+				font-size: 32rpx;
+				color: #ffffff;
+				background-color: #2979ff;
+			}
+		}
+
+		.title-tip {
+			font-size: 36rpx;
+		}
+
+		.tree-box {
+			border-radius: 10rpx;
+			border: 1px solid #c7c9ce;
+			color: #2979ff;
+
+			.tree-scroll {
+				border-radius: 10rpx;
+				overflow: scroll;
+			}
+
+			.item-loudong {
+				display: flex;
+				flex-direction: column;
+				padding: 10rpx 0 0 10rpx;
+
+				.loudong {
+					display: flex;
+					align-items: center;
+					justify-content: space-between;
+					border: 1rpx solid #c7c9ce;
+					padding: 10rpx;
+					height: 60rpx;
+					width: 636rpx;
+					font-size: 30rpx;
+
+					.title-loudong {
+						display: flex;
+					}
+
+					.txt-loudong {
+						padding-left: 5rpx;
+					}
+				}
+
+				.item-loucheng {
+					display: flex;
+					flex-direction: column;
+					margin-left: 60rpx;
+
+					.loucheng {
+						display: flex;
+						align-items: center;
+						justify-content: space-between;
+						border: 1rpx solid #c7c9ce;
+						padding: 10rpx;
+						height: 60rpx;
+						width: 578rpx;
+						font-size: 30rpx;
+
+						.title-loucheng {
+							display: flex;
+						}
+
+						.txt-loucheng {
+							padding-left: 5rpx;
+						}
+					}
+
+					.item-jiaoshi {
+						display: flex;
+						flex-direction: column;
+						margin-left: 60rpx;
+
+						.jiaoshi {
+							display: flex;
+							align-items: center;
+							justify-content: space-between;
+							border: 1rpx solid #c7c9ce;
+							padding: 10rpx;
+							height: 60rpx;
+							width: 520rpx;
+							font-size: 30rpx;
+
+							.title-jiaoshi {
+								display: flex;
+							}
+
+							.txt-jiaoshi {
+								padding-left: 5rpx;
+							}
+						}
+
+						.item-kongtiao {
+							display: flex;
+							justify-content: space-between;
+							align-items: center;
+							border: 1rpx solid #c7c9ce;
+							margin-left: 60rpx;
+							padding: 10rpx 10rpx 10rpx 30rpx;
+							height: 60rpx;
+							width: 442rpx;
+							font-size: 32rpx;
+						}
+					}
+				}
+			}
+		}
+	}
+</style>

+ 571 - 0
pagesAir/shareAir/shareAir.vue

@@ -0,0 +1,571 @@
+<template>
+	<view class="container">
+		<uni-swiper-dot :info="info" :current="current" field="content" :mode="dotMode">
+			<swiper class="swiper-box" @change="swiper_change" autoplay :interval="3000" :duration="500">
+				<swiper-item v-for="(item ,index) in info" :key="index">
+					<image :src="item.url" mode="aspectFill"></image>
+				</swiper-item>
+			</swiper>
+		</uni-swiper-dot>
+		<view class="line"></view>
+		<view class="nav">
+			<navigator class="btn" url="" hover-class="navigator-hover">
+				<view class="btn-icon-tzgl">
+					<image src="../static/images/tzgl.png" mode=""></image>
+					<text>台账管理</text>
+				</view>
+				<view class="txt-right">
+					<text> </text>
+					<uni-icons type="forward" color="#c7c9ce" size="26"></uni-icons>
+				</view>
+			</navigator>
+			<navigator class="btn" url="" hover-class="navigator-hover">
+				<view class="btn-icon">
+					<image src="../static/images/yhye.png" mode=""></image>
+					<text>用户余额</text>
+				</view>
+				<view class="txt-right">
+					<text>{{balance}}</text>
+					<uni-icons type="forward" color="#c7c9ce" size="26"></uni-icons>
+				</view>
+			</navigator>
+		</view>
+		<view class="line"></view>
+		<view class="add-air" v-if="isList === false" :style="{height: screenHeight}">
+			<view class="add-content">
+				<view class="add-left">
+					<navigator url="../addAir/addAir" class="add-btn">
+						<uni-icons type="plus" color="white" size="30"></uni-icons>
+						<view>添加</view>
+					</navigator>
+					<view class="add-tip">
+						<view class="txt-add-air">添加空调</view>
+						<view class="txt-tip">点击添加设备</view>
+						<view class="txt-tip">可添加多个设备</view>
+					</view>
+				</view>
+				<view class="add-right">
+					<image src="../static/images/air-pic.png" mode="aspectFit"></image>
+				</view>
+			</view>
+			<view class="add-bg">
+				<image src="../static/images/qidong.png" mode="aspectFit"></image>
+			</view>
+		</view>
+		<view class="list-air" v-else>
+			<scroll-view scroll-y="true" :style="{height: screenHeight}" @scrolltoupper="scroll_to_upper"
+				@scrolltolower="scroll_to_lower">
+				<view class="list-items" v-for="(item, index) in airs" :key="index">
+					<view v-if="item.on" class="item-air" @longpress="itemLongPress($event, 1)">
+						<view class="item-left">
+							<view class="item-icon">
+								<view class="circle1"></view>
+								<view class="circle2"></view>
+								<view class="circle3"></view>
+							</view>
+							<view class="item-title">{{item.name}}</view>
+							<view class="item-info">
+								<text class="item-info-left">{{item.info}}</text>
+								<text>启用时长:</text><text>{{item.time}}</text>
+							</view>
+						</view>
+						<view class="item-right" @tap="btn_click" :ref="index">
+							<view class="item-btn">
+								<image src="../static/images/power-off.png" mode="aspectFit"></image>
+								<view class="item-txt-off">
+									关闭
+								</view>
+							</view>
+						</view>
+					</view>
+					<view v-else class="item-air" @longpress="itemLongPress($event, 0)" :ref="index">
+						<view class="item-left">
+							<view class="item-icon">
+								<view class="circle1"></view>
+								<view class="circle2"></view>
+								<view class="circle3"></view>
+							</view>
+							<view class="item-title">{{item.name}}</view>
+							<view class="item-info">
+								<text class="item-info-left">{{item.info}}</text>
+								<image src="../static/images/power-off.png" mode="" class="item-info-icon"></image>
+								<text>未启用</text>
+							</view>
+						</view>
+						<view class="item-right" @tap="btn_click" :ref="index">
+							<view class="item-btn">
+								<image src="../static/images/power-on.png" mode="aspectFit"></image>
+								<view class="item-txt-on">
+									启动
+								</view>
+							</view>
+						</view>
+					</view>
+				</view>
+				<navigator url="../addAir/addAir" class="add-air-bottom">
+					<uni-icons type="plus" size="30" color="#4B8DFB"></uni-icons>
+					<view class="add-btn-bottom">添加</view>
+				</navigator>
+			</scroll-view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				// 滚动横幅的数据
+				info: [{
+						url: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/094a9dc0-50c0-11eb-b680-7980c8a877b8.jpg'
+					},
+					{
+						url: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/094a9dc0-50c0-11eb-b680-7980c8a877b8.jpg'
+					},
+					{
+						url: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/094a9dc0-50c0-11eb-b680-7980c8a877b8.jpg'
+					}
+				],
+				current: 0, // 开始显示第几个
+				dotMode: 'round', // 显示控制点样式
+				balance: 18.88, // 余额
+				isList: false, // 是否显示添加的空调列表
+				airs: [], // 已经添加的空调列表数据
+				screenHeight: '' // 屏幕的高度
+			};
+		},
+		onLoad() {
+			let airs_selected = uni.getStorageSync('airs_selected')
+			if (airs_selected.length > 0) {
+				// 使用存储的列表
+				this.airs = airs_selected
+				// 显示添加的空调列表
+				this.isList = true
+			}
+		},
+		onShow() {
+			// 从新计算高度
+			this.calc_screen_height()
+			// 监听全局的自定义事件,事件由 uni.$emit 触发,但仅触发一次,在第一次触发之后移除该监听器。
+			uni.$once('selectAirs', data => {
+				// console.log('监听到事件来自 selectAirs ,携带参数 airs 为:' + data.airs);
+				// this.airs = []
+				let arrAirs = data.airs.trim().split(',').sort()
+				let airs = []
+				let room = '' // 房间名
+				let temp = true // 没有同名的空调
+				for (var i = 0; i < arrAirs.length; i++) {
+					airs = arrAirs[i].trim().split(' ')
+					// room = airs[0].replaceAll('-', '')
+					room = airs[0]
+					for (var j = 1; j < airs.length; j++) {
+						if (airs[j].trim().length > 0) {
+							temp = true
+							for (var k = 0; k < this.airs.length; k++) {
+								if (this.airs[k].name == room + ' ' + airs[j]) {
+									temp = false
+									break
+								}
+							}
+							// 没有同名的
+							if (temp) {
+								this.airs.push({
+									name: room + ' ' + airs[j],
+									info: '2P空调',
+									time: '01:25:21',
+									on: false
+								})
+							}
+						}
+					}
+				}
+				// 如果选的空调不为空,则显示添加的空调列表
+				if (this.airs.length > 0) {
+					// 显示添加的空调列表
+					this.isList = true
+				}
+				// 存储空调列表
+				uni.setStorageSync('airs_selected', this.airs)
+				// 移除全局自定义事件监听器。
+				uni.$off('selectAirs')
+			})
+		},
+		methods: {
+			// 长按事件
+			itemLongPress(e, val) {
+				// console.log(e, val);
+				if (val == 0) {
+					let index = e.currentTarget.dataset.ref
+					uni.showModal({
+						title: '提示',
+						content: '是否删除该空调?',
+						success: (res) => {
+							if (res.confirm) {
+								// 删除指定下标的元素
+								this.airs.splice(index, 1)
+								// 更新存储
+								uni.setStorageSync('airs_selected', this.airs)
+							}
+						}
+					})
+				} else {
+					uni.showToast({
+						title: '使用中不能删除',
+						icon: 'error',
+						duration: 1000
+					})
+				}
+			},
+			/**
+			 * 单击了启动或关闭按钮
+			 */
+			btn_click(e) {
+				// console.log(e.currentTarget.dataset.ref);
+				let index_btn = e.currentTarget.dataset.ref
+				// 未获取到索引
+				if (typeof index_btn === 'undefined') {
+					return
+				}
+
+				if (this.airs[index_btn].on) {
+					uni.showModal({
+						title: '提示',
+						content: '确认【关闭】空调吗?',
+						success: (res) => {
+							if (res.confirm) {
+								// 操作【关闭】空调
+
+								this.airs[index_btn].on = false
+							}
+						}
+					});
+				} else {
+					uni.showModal({
+						title: '提示',
+						content: '确认【启动】空调吗?',
+						success: (res) => {
+							if (res.confirm) {
+								// 操作【启动】空调
+
+								this.airs[index_btn].on = true
+							}
+						}
+					});
+				}
+			},
+			/**
+			 * 滚动到顶部提示
+			 */
+			scroll_to_upper() {
+				uni.showToast({
+					title: '到顶了!',
+					icon: 'none',
+					duration: 500
+				})
+			},
+			/**
+			 * 滚动到底部提示
+			 */
+			scroll_to_lower() {
+				uni.showToast({
+					title: '到底了!',
+					icon: 'none',
+					duration: 500
+				})
+			},
+			/**
+			 * 轮播图发生改变
+			 * @param {Object} e
+			 */
+			swiper_change(e) {
+				this.current = e.detail.current;
+			},
+			/**
+			 * 计算屏幕的高度
+			 */
+			calc_screen_height() {
+				uni.getSystemInfo({
+					success: res => {
+						let h = 0;
+						if (this.isList === true) {
+							h = ((res.screenHeight * (750 / res.windowWidth)) - 640) //将px 转换rpx
+						} else {
+							h = ((res.screenHeight * (750 / res.windowWidth)) - 740) //将px 转换rpx
+						}
+						this.screenHeight = Math.floor(h) + 'rpx'
+					}
+				});
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.container {
+		display: flex;
+		flex-direction: column;
+		font-size: 28rpx;
+		font-family: "Microsoft YaHei-3970(82674968)";
+		width: 730rpx;
+		padding: 10rpx;
+
+		.swiper-box {
+			height: 150px;
+			width: 100%;
+		}
+
+		swiper-item {
+			/* #ifndef APP-NVUE */
+			display: flex;
+			/* #endif */
+			flex-direction: column;
+			justify-content: center;
+			align-items: center;
+			height: 100%;
+
+			image {
+				height: 100%;
+				width: 100%;
+				border-radius: 8rpx;
+			}
+		}
+
+		.line {
+			height: 20rpx;
+		}
+
+		.nav {
+			display: flex;
+			justify-content: space-between;
+
+			.btn {
+				display: flex;
+				justify-content: space-between;
+				align-items: center;
+				width: 338rpx;
+				height: 100rpx;
+				padding: 5rpx 10rpx;
+				border-radius: 8rpx;
+				background-color: #eaefff;
+
+				.btn-icon-tzgl {
+					display: flex;
+					align-items: center;
+
+					image {
+						width: 40rpx;
+						height: 40rpx;
+						padding: 10rpx;
+					}
+				}
+
+				.btn-icon {
+					display: flex;
+					align-items: center;
+
+					image {
+						width: 60rpx;
+						height: 60rpx;
+					}
+				}
+
+				.txt-right {
+					display: flex;
+					align-items: center;
+				}
+			}
+		}
+
+		.add-air {
+			border-radius: 8rpx;
+			padding: 60rpx 10rpx;
+			background-color: #F1F1F1;
+
+			.add-content {
+				display: flex;
+				justify-content: space-around;
+				align-items: center;
+				margin-bottom: 20rpx;
+
+				.add-left {
+					display: flex;
+
+					.add-btn {
+						display: flex;
+						flex-direction: column;
+						justify-content: center;
+						align-items: center;
+						margin-right: 20rpx;
+						width: 120rpx;
+						height: 120rpx;
+						border-radius: 20rpx;
+						background-color: #2979ff;
+						color: #ffffff;
+					}
+
+					.add-tip {
+						display: flex;
+						flex-direction: column;
+						justify-content: space-around;
+
+						.txt-add-air {
+							font-size: 40rpx;
+							font-weight: bold;
+						}
+
+						.txt-tip {
+							font-size: 20rpx;
+							color: #8f939c;
+						}
+					}
+				}
+
+				.add-right {
+					width: 300rpx;
+					height: 100rpx;
+					border-radius: 10rpx;
+
+					image {
+						width: 300rpx;
+						height: 100rpx;
+					}
+				}
+			}
+
+			.add-bg {
+				display: flex;
+				justify-content: center;
+				align-items: center;
+				padding-top: 90rpx;
+
+				image {
+					width: 400rpx;
+					height: 400rpx;
+				}
+			}
+		}
+
+		.list-air {
+			border-radius: 8rpx;
+			padding: 10rpx 10rpx;
+			background-color: #e9e9eb;
+
+			.list-items {
+				display: flex;
+				flex-direction: column;
+
+				.item-air {
+					display: flex;
+					justify-content: space-between;
+					padding: 30rpx 20rpx;
+					border-bottom: 1px solid #c3c8d4;
+
+					.item-left {
+						display: flex;
+						flex-direction: column;
+						justify-content: space-around;
+
+						.item-icon {
+							display: flex;
+							align-items: center;
+
+							.circle1 {
+								width: 16rpx;
+								height: 16rpx;
+								border-radius: 8rpx;
+								background-color: #18bc37;
+							}
+
+							.circle2 {
+								width: 12rpx;
+								height: 12rpx;
+								border-radius: 6rpx;
+								background-color: #18bc37;
+								margin: 0 10rpx;
+							}
+
+							.circle3 {
+								display: inline-block;
+								width: 8rpx;
+								height: 8rpx;
+								border-radius: 4rpx;
+								background-color: #18bc37;
+							}
+						}
+
+
+
+						.item-title {
+							font-size: 32rpx;
+							font-weight: bold;
+							padding-bottom: 12rpx;
+						}
+
+						.item-info {
+							display: flex;
+							color: #8f939c;
+
+							.item-info-left {
+								padding-right: 20rpx;
+							}
+
+							.item-info-icon {
+								width: 40rpx;
+								height: 40rpx;
+								margin-right: 8rpx;
+							}
+						}
+					}
+
+					.item-right {
+
+						.item-btn {
+							display: flex;
+							flex-direction: column;
+							justify-content: center;
+							align-items: center;
+							width: 100rpx;
+							height: 100rpx;
+							border: 1px solid #d9deeb;
+							border-radius: 50rpx;
+							box-shadow: 4rpx 4rpx 5rpx #c8cdd8;
+							background-image: linear-gradient(-45deg, #F2F4F2, #DFDFDF);
+
+							image {
+								width: 50rpx;
+								height: 50rpx;
+							}
+
+							.item-txt-on {
+								font-size: 24rpx;
+								font-weight: bold;
+								color: #4B8DFB;
+							}
+
+							.item-txt-off {
+								font-size: 24rpx;
+								font-weight: bold;
+								color: #8A8A8A;
+							}
+						}
+					}
+				}
+			}
+
+			.add-air-bottom {
+				display: flex;
+				justify-content: center;
+				margin: 20rpx 0;
+				padding: 20rpx 0;
+				width: 160rpx;
+				border-radius: 10rpx;
+
+				.add-btn-bottom {
+					font-size: 40rpx;
+					color: #4B8DFB;
+					padding-left: 8rpx;
+				}
+			}
+		}
+	}
+</style>

BIN
pagesAir/static/images/air-pic.png


BIN
pagesAir/static/images/power-off.png


BIN
pagesAir/static/images/power-on.png


BIN
pagesAir/static/images/qidong.png


BIN
pagesAir/static/images/tzgl.png


BIN
pagesAir/static/images/yhye.png


+ 353 - 0
pagesElectric/dfxq/dfxq.vue

@@ -0,0 +1,353 @@
+<template>
+	<view class="container">
+		<view class="line"></view>
+		<view class="same-month">
+			<view class="title">
+				<view class="vertical-line"></view>
+				<view class="title-txt"><text class="caption">当月详情</text><text
+						class="hah">/</text>时间更新到{{sameMonthData.dataTime}}</view>
+			</view>
+			<view class="content-details">
+				<view class="item">
+					<view class="num">{{sameMonthData.zongStart}}</view>
+					<view class="description">起码(度)</view>
+				</view>
+				<view class="item">
+					<view class="num">{{sameMonthData.zongEnd}}</view>
+					<view class="description">止码(度)</view>
+				</view>
+				<view class="item">
+					<view class="num">{{sameMonthData.zongPower}}</view>
+					<view class="description">用量(度)</view>
+				</view>
+				<view class="item">
+					<view class="num">{{sameMonthData.zongMoney}}</view>
+					<view class="description">消费(元)</view>
+				</view>
+			</view>
+			<view class="txt-color">(注:电费标准:{{moneyPer}}元/度)</view>
+		</view>
+		<view class="line"></view>
+		<view class="same-month">
+			<view class="title">
+				<view class="vertical-line"></view>
+				<view class="title-txt"><text class="caption">每月账单</text></view>
+			</view>
+			<view class="content-details">
+				<uni-table :border="true" :stripe="true" emptyText="暂无更多数据">
+					<!-- 表头行 -->
+					<uni-tr>
+						<uni-th width="66" align="center">时间</uni-th>
+						<uni-th width="64" align="center">起码(度)</uni-th>
+						<uni-th width="64" align="center">止码(度)</uni-th>
+						<uni-th width="64" align="center">用量(度)</uni-th>
+						<uni-th width="64" align="center">消费</uni-th>
+					</uni-tr>
+					<!-- 表格数据行 -->
+					<uni-tr v-for="(item, index) in tableData" :key="index">
+						<uni-td align="center">{{item.dataTime}}</uni-td>
+						<uni-td align="center">{{item.zongStart}}</uni-td>
+						<uni-td align="center">{{item.zongEnd}}</uni-td>
+						<uni-td align="center">{{item.totalPower}}</uni-td>
+						<uni-td align="center">{{item.totalMoney}}</uni-td>
+					</uni-tr>
+				</uni-table>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				sameMonthData: {
+					dataTime: '',
+					zongEnd: 0.00.toFixed(2),
+					zongMoney: 0.00.toFixed(2),
+					zongPower: 0.00.toFixed(2),
+					zongStart: 0.00.toFixed(2)
+				},
+				moneyPer: 0.62.toFixed(2),
+				tableData: [],
+				ceshi: 'code',
+				stu_number: '', // 学号
+				roomSelect: '', // 选择的宿舍号
+				dom: ''
+			}
+		},
+		onLoad() {
+			try {
+				// 获取学号
+				this.stu_number = this.$store.state.userInfo.card_number
+				this.roomSelect = this.$store.state.building.roomSelect
+
+				if (this.stu_number == '' || this.roomSelect == '' || typeof(this.stu_number) == 'undefined' || typeof(this
+						.roomSelect) == 'undefined') {
+					const userinfo = uni.getStorageSync('userinfo_storage_key')
+					if (userinfo) {
+						this.stu_number = userinfo.card_number
+						this.roomSelect = userinfo.campus + userinfo.dorm_number
+					} else {
+						uni.redirectTo({
+							url: '../index/index'
+						})
+
+						uni.showToast({
+							icon: 'none',
+							title: '学号或宿舍号为空,请授权',
+							duration: 1500
+						})
+
+						return
+					}
+				}
+				// console.log(this.stu_number);
+				// console.log(this.roomSelect);
+				// 判断是否选择了宿舍号
+				if (this.haveSelectRoom()) {
+					uni.showToast({
+						title: '宿舍号为空',
+						icon: 'success'
+					})
+				}
+			} catch (e) {
+				console.log(e.message)
+			}
+		},
+		methods: {
+			/**
+			 * 判断是否选择了宿舍号
+			 */
+			haveSelectRoom() {
+				if (this.roomSelect != '' && typeof(this.roomSelect) != 'undefined') {
+					// 当月详情
+					try {
+						this.get_sameMonthDetails()
+					} catch (e) {
+						uni.showToast({
+							title: '当月详情'
+						})
+					}
+					// 每月账单
+					try {
+						this.get_history()
+					} catch (e) {
+						uni.showToast({
+							title: '每月账单异常'
+						})
+					}
+				} else {
+					return true
+				}
+			},
+			/**
+			 * 当月详情
+			 */
+			async get_sameMonthDetails() {
+				let res = await this.$myRequest({
+					host: this.ceshi,
+					url: '/HotWaters/elnowElc.action',
+					method: 'POST',
+					header: {
+						'content-type': 'application/x-www-form-urlencoded'
+					},
+					data: {
+						'roomSelect': this.roomSelect
+					}
+				})
+
+				// console.log(res.data)
+				if (res.data.data.length == 0) {
+					return
+				}
+
+				if (res.data.mess === '返回成功') {
+					let zongEnd = res.data.data[0].zongEnd
+					let zongMoney = res.data.data[0].zongMoney
+					let zongPower = res.data.data[0].zongPower
+					let zongStart = res.data.data[0].zongStart
+
+					let dataTime = res.data.data[0].dataTime
+					let dt = dataTime.split('-')
+					this.sameMonthData.dataTime = dt[0] + '年' + parseInt(dt[1]) + '月'
+					this.sameMonthData.zongEnd = zongEnd.toFixed(2)
+					this.sameMonthData.zongMoney = zongMoney.toFixed(2)
+					this.sameMonthData.zongPower = zongPower.toFixed(2)
+					this.sameMonthData.zongStart = zongStart.toFixed(2)
+				} else {
+					uni.showToast({
+						title: '加载数据异常',
+						duration: 1500
+					})
+
+					return
+				}
+			},
+
+			/**
+			 * 每月账单
+			 */
+			async get_history() {
+				var reg = /[\u4e00-\u9fa5]/g;
+				var str = this.roomSelect;
+				this.dom = str.replace(reg, "");
+				let res = await this.$myRequest({
+					host: this.ceshi,
+					url: '/HotWaters/elMonthlist.action',
+					method: 'POST',
+					header: {
+						'content-type': 'application/x-www-form-urlencoded'
+					},
+					data: {
+						'dom': this.dom,
+						'page': 1,
+						'rows': 12
+					}
+				})
+
+				// console.log(res.data)
+				if (res.data.rows.length == 0) {
+					return
+				}
+
+				if (typeof res.data.rows === 'undefined') {
+					uni.showToast({
+						title: '加载数据异常',
+						duration: 1500
+					})
+
+					return
+				} else {
+					for (let i = 0; i < res.data.rows.length; i++) {
+						let dataTime = res.data.rows[i].dataTime
+						let zongStart = res.data.rows[i].zongStart
+						let zongEnd = res.data.rows[i].zongEnd
+						let totalPower = res.data.rows[i].totalPower
+						let totalMoney = res.data.rows[i].totalMoney
+
+						zongStart = zongStart.toFixed(2)
+						zongEnd = zongEnd.toFixed(2)
+						totalPower = totalPower.toFixed(2)
+						totalMoney = totalMoney.toFixed(2)
+
+						if (this.moneyPer <= 0.00) {
+							if (totalPower > 0.00 && totalMoney > 0.00) {
+								let moneyPer = totalMoney / totalPower
+								this.moneyPer = moneyPer.toFixed(2)
+
+								if (this.moneyPer <= 0.00) {
+									this.moneyPer = 0.61
+								}
+							}
+						}
+
+						totalMoney = '¥' + totalMoney
+						this.tableData.push({
+							dataTime,
+							zongStart,
+							zongEnd,
+							totalPower,
+							totalMoney
+						})
+					}
+				}
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.container {
+		display: flex;
+		flex-direction: column;
+		font-size: 29upx;
+		font-family: "Microsoft YaHei";
+
+		.line {
+			height: 10rpx;
+			background-color: #f5f5f5;
+		}
+
+		.same-month {
+			display: flex;
+			flex-direction: column;
+			padding: 20rpx 30rpx;
+
+			.title {
+				display: flex;
+				align-items: center;
+				margin-bottom: 30rpx;
+
+				.vertical-line {
+					display: inline-block;
+					margin-right: 20rpx;
+					width: 10rpx;
+					height: 45rpx;
+					background-color: #0282F8;
+				}
+
+				.title-txt {
+					display: flex;
+					flex-direction: row;
+					align-items: flex-end;
+					color: #C1C1C1;
+
+					.caption {
+						color: #2b2b2b;
+						font-size: 40upx;
+					}
+
+					.hah {
+						display: flex;
+						margin: 0 10rpx;
+					}
+				}
+			}
+
+			.content-details {
+				display: flex;
+				justify-content: space-around;
+
+				.item {
+					display: flex;
+					flex-direction: column;
+					align-items: center;
+
+					.num {
+						font-size: 40upx;
+					}
+
+					.description {
+						color: #9a9a9a;
+					}
+				}
+
+				/deep/ .uni-table {
+
+					.uni-table-th {
+						padding: 6px 8px;
+						font-size: 26upx;
+						white-space: nowrap;
+						text-align: center;
+						background-color: #E5F2FE;
+						color: #5b5b5d;
+					}
+
+					.uni-table-td {
+						padding: 3px 5px;
+						font-size: 26upx;
+						white-space: nowrap;
+						text-align: center;
+						color: #000000;
+					}
+				}
+			}
+
+			.txt-color {
+				margin: 20rpx 0;
+				color: #C1C1C1;
+			}
+		}
+	}
+</style>

pages/jiaofei/ad_dianfei.vue → pagesElectric/jiaofei/ad_dianfei.vue


+ 22 - 0
pages/jiaofei/jiaofei.css

@@ -25,6 +25,28 @@ page {
 	height: 118upx;
 	height: 118upx;
 }
 }
 
 
+.details {
+	display: flex;
+	flex-direction: row;
+	justify-content: space-around;
+	height: 158rpx;
+}
+
+.xiangqing {
+	display: flex;
+	flex-direction: column;
+	justify-content: center;
+	align-items: center;
+	padding: 10rpx;
+	border-radius: 10rpx;
+}
+
+.xiangqing-icon {
+	width: 58rpx;
+	height: 58rpx;
+	margin: 10rpx 0;
+}
+
 .picker-item-logol {
 .picker-item-logol {
 	width: 88upx;
 	width: 88upx;
 	display: flex;
 	display: flex;

+ 59 - 16
pages/jiaofei/jiaofei.vue

@@ -2,27 +2,37 @@
 	<view class="content">
 	<view class="content">
 		<view class="select-item" @tap="navigateToSelect">
 		<view class="select-item" @tap="navigateToSelect">
 			<view class="picker-item-logol">
 			<view class="picker-item-logol">
-				<image class="picker-item-logo-left" src="/static/image/room.png"></image>
+				<image class="picker-item-logo-left" src="../static/images/room.png"></image>
 			</view>
 			</view>
 			<view class="picker-item-label">已选房间</view>
 			<view class="picker-item-label">已选房间</view>
 			<view class="picker-item-content" :class="{'font-txt':add_class==1}">{{roomSelect}}</view>
 			<view class="picker-item-content" :class="{'font-txt':add_class==1}">{{roomSelect}}</view>
 			<view class="picker-item-logor">
 			<view class="picker-item-logor">
-				<image class="picker-item-logo-right" src="/static/image/right.png"></image>
+				<image class="picker-item-logo-right" src="../static/images/right.png"></image>
 			</view>
 			</view>
 		</view>
 		</view>
 		<view class="show-item">
 		<view class="show-item">
 			<view class="picker-item-logol">
 			<view class="picker-item-logol">
-				<image class="picker-item-logo-left" src="/static/image/elec.png"></image>
+				<image class="picker-item-logo-left" src="../static/images/elec.png"></image>
 			</view>
 			</view>
-			<view class="picker-item-label">剩余金额</view>
+			<view class="picker-item-label">账户金额</view>
 			<view class="picker-item-content font-txt">¥ {{remainElec}}</view>
 			<view class="picker-item-content font-txt">¥ {{remainElec}}</view>
 		</view>
 		</view>
+		<view class="show-item details">
+			<view class="xiangqing" @tap="dfxq_click">
+				<image class="xiangqing-icon" src="../static/images/dfxq.png"></image>
+				<view>电费详情</view>
+			</view>
+			<view class="xiangqing" @tap="sfxq_click">
+				<image class="xiangqing-icon" src="../static/images/sfxq.png"></image>
+				<view>水费详情</view>
+			</view>
+		</view>
 		<view class="show-item add-money">
 		<view class="show-item add-money">
 			<view class="add-money-show">
 			<view class="add-money-show">
 				<view class="picker-item-logol money-logo">
 				<view class="picker-item-logol money-logo">
-					<image class="picker-item-logo-left" src="/static/image/money.png"></image>
+					<image class="picker-item-logo-left" src="../static/images/money.png"></image>
 				</view>
 				</view>
-				<view class="picker-item-label money-show">请选择金额</view>
+				<view class="picker-item-label money-show">请选择充值金额</view>
 			</view>
 			</view>
 			<view class="add-money-list">
 			<view class="add-money-list">
 				<view class="add-money-button">
 				<view class="add-money-button">
@@ -62,7 +72,7 @@
 			台账管理
 			台账管理
 		</view>
 		</view>
 		<view class="ad">
 		<view class="ad">
-			<image src="../../static/image/ad_dianfei.png" mode="aspectFit" class="ad_img" @tap="ad_redirect"></image>
+			<image src="../static/images/ad_dianfei.png" mode="aspectFit" class="ad_img" @tap="ad_redirect"></image>
 		</view>
 		</view>
 	</view>
 	</view>
 </template>
 </template>
@@ -88,7 +98,7 @@
 			// console.log(options);
 			// console.log(options);
 			// if (typeof(options.from) != 'undefined' && options.from == 2) {
 			// if (typeof(options.from) != 'undefined' && options.from == 2) {
 			// 	uni.navigateTo({
 			// 	uni.navigateTo({
-			// 		url: '../index/index?from=' + options.from
+			// 		url: '../../pages/index/index?from=' + options.from
 			// 	})
 			// 	})
 			// 	return
 			// 	return
 			// }
 			// }
@@ -101,6 +111,30 @@
 		},
 		},
 		methods: {
 		methods: {
 			/**
 			/**
+			 * 电费详情页面
+			 */
+			dfxq_click() {
+				if (this.haveSelectRoom()) {
+					return
+				}
+				
+				uni.navigateTo({
+					url: '../dfxq/dfxq'
+				})
+			},
+			/**
+			 * 水费详情页面
+			 */
+			sfxq_click() {
+				if (this.haveSelectRoom()) {
+					return
+				}
+				
+				uni.navigateTo({
+					url: '../sfxq/sfxq'
+				})
+			},
+			/**
 			 * 跳转到ad页面
 			 * 跳转到ad页面
 			 */
 			 */
 			ad_redirect() {
 			ad_redirect() {
@@ -122,7 +156,7 @@
 							this.stu_number = userinfo.card_number
 							this.stu_number = userinfo.card_number
 						} else {
 						} else {
 							uni.navigateTo({
 							uni.navigateTo({
-								url: '../index/index?from=' + options.from
+								url: '../../pages/index/index?from=' + options.from
 							})
 							})
 
 
 							uni.showToast({
 							uni.showToast({
@@ -181,7 +215,7 @@
 
 
 							// 跳转到首页
 							// 跳转到首页
 							uni.redirectTo({
 							uni.redirectTo({
-								url: '../index/index?from=0'
+								url: '../../pages/index/index?from=0'
 							});
 							});
 						}
 						}
 					}
 					}
@@ -238,11 +272,11 @@
 						// 跳转到首页
 						// 跳转到首页
 						if (options && typeof(options.from) != 'undefined' && typeof(options.from) != '') {
 						if (options && typeof(options.from) != 'undefined' && typeof(options.from) != '') {
 							uni.navigateTo({
 							uni.navigateTo({
-								url: '../index/index?from=' + options.from
+								url: '../../pages/index/index?from=' + options.from
 							})
 							})
 						} else {
 						} else {
 							uni.redirectTo({
 							uni.redirectTo({
-								url: '../index/index?from=0'
+								url: '../../pages/index/index/index?from=0'
 							});
 							});
 						}
 						}
 					}
 					}
@@ -291,7 +325,7 @@
 					}
 					}
 				} else {
 				} else {
 					uni.showToast({
 					uni.showToast({
-						title: '请先选择宿舍号,\n再查询电量 或 充值',
+						title: '请先选择宿舍号,\n再查询详情 或 充值',
 						icon: 'none',
 						icon: 'none',
 						duration: 3000
 						duration: 3000
 					});
 					});
@@ -304,16 +338,25 @@
 					url: '../select/select',
 					url: '../select/select',
 				});
 				});
 			},
 			},
-
-			//跳转到台账页面
-			navigateToShow(e) {
+			// 是否选择了宿舍号
+			haveSelectRoom() {
 				if (this.roomSelect == '请选择宿舍号') {
 				if (this.roomSelect == '请选择宿舍号') {
 					uni.showToast({
 					uni.showToast({
 						title: '请选择宿舍号',
 						title: '请选择宿舍号',
 						icon: 'success'
 						icon: 'success'
 					})
 					})
+					return true
+				}
+
+				return false
+			},
+
+			//跳转到台账页面
+			navigateToShow(e) {
+				if (this.haveSelectRoom()) {
 					return
 					return
 				}
 				}
+
 				uni.navigateTo({
 				uni.navigateTo({
 					url: '../show/show',
 					url: '../show/show',
 				});
 				});

pages/select/select.css → pagesElectric/select/select.css


+ 8 - 8
pages/select/select.vue

@@ -3,48 +3,48 @@
 		<picker class="picker-item1" @change="changeSelect1" :range="array1" :value="index1" :disabled="dis_num1">
 		<picker class="picker-item1" @change="changeSelect1" :range="array1" :value="index1" :disabled="dis_num1">
 			<view class="select-item">
 			<view class="select-item">
 				<view class="picker-item-logol">
 				<view class="picker-item-logol">
-					<image class="picker-item-logo-left" src="/static/image/school.png"></image>
+					<image class="picker-item-logo-left" src="../static/images/school.png"></image>
 				</view>
 				</view>
 				<view class="picker-item-label">校区</view>
 				<view class="picker-item-label">校区</view>
 				<view class="picker-item-content" :class="{'font-txt':add_class1==1}">{{arr1[index1]}}</view>
 				<view class="picker-item-content" :class="{'font-txt':add_class1==1}">{{arr1[index1]}}</view>
 				<view class="picker-item-logor">
 				<view class="picker-item-logor">
-					<image class="picker-item-logo-right" src="/static/image/right.png"></image>
+					<image class="picker-item-logo-right" src="../static/images/right.png"></image>
 				</view>
 				</view>
 			</view>
 			</view>
 		</picker>
 		</picker>
 		<picker class="picker-item2" @change="changeSelect2" :range="array2" :value="index2" :disabled="dis_num2">
 		<picker class="picker-item2" @change="changeSelect2" :range="array2" :value="index2" :disabled="dis_num2">
 			<view class="select-item">
 			<view class="select-item">
 				<view class="picker-item-logol">
 				<view class="picker-item-logol">
-					<image class="picker-item-logo-left" src="/static/image/building.png"></image>
+					<image class="picker-item-logo-left" src="../static/images/building.png"></image>
 				</view>
 				</view>
 				<view class="picker-item-label">楼栋</view>
 				<view class="picker-item-label">楼栋</view>
 				<view class="picker-item-content" :class="{'font-txt':add_class2==1}">{{arr2[index2]}}</view>
 				<view class="picker-item-content" :class="{'font-txt':add_class2==1}">{{arr2[index2]}}</view>
 				<view class="picker-item-logor">
 				<view class="picker-item-logor">
-					<image class="picker-item-logo-right" src="/static/image/right.png"></image>
+					<image class="picker-item-logo-right" src="../static/images/right.png"></image>
 				</view>
 				</view>
 			</view>
 			</view>
 		</picker>
 		</picker>
 		<picker class="picker-item2" @change="changeSelect3" :range="array3" :value="index3" :disabled="dis_num3">
 		<picker class="picker-item2" @change="changeSelect3" :range="array3" :value="index3" :disabled="dis_num3">
 			<view class="select-item">
 			<view class="select-item">
 				<view class="picker-item-logol">
 				<view class="picker-item-logol">
-					<image class="picker-item-logo-left" src="/static/image/floor.png"></image>
+					<image class="picker-item-logo-left" src="../static/images/floor.png"></image>
 				</view>
 				</view>
 				<view class="picker-item-label">楼层</view>
 				<view class="picker-item-label">楼层</view>
 				<view class="picker-item-content" :class="{'font-txt':add_class3==1}">{{arr3[index3]}}</view>
 				<view class="picker-item-content" :class="{'font-txt':add_class3==1}">{{arr3[index3]}}</view>
 				<view class="picker-item-logor">
 				<view class="picker-item-logor">
-					<image class="picker-item-logo-right" src="/static/image/right.png"></image>
+					<image class="picker-item-logo-right" src="../static/images/right.png"></image>
 				</view>
 				</view>
 			</view>
 			</view>
 		</picker>
 		</picker>
 		<picker class="picker-item2" @change="changeSelect4" :range="array4" :value="index4" :disabled="dis_num4">
 		<picker class="picker-item2" @change="changeSelect4" :range="array4" :value="index4" :disabled="dis_num4">
 			<view class="select-item">
 			<view class="select-item">
 				<view class="picker-item-logol">
 				<view class="picker-item-logol">
-					<image class="picker-item-logo-left" src="/static/image/room.png"></image>
+					<image class="picker-item-logo-left" src="../static/images/room.png"></image>
 				</view>
 				</view>
 				<view class="picker-item-label">房间</view>
 				<view class="picker-item-label">房间</view>
 				<view class="picker-item-content" :class="{'font-txt':add_class4==1}">{{arr4[index4]}}</view>
 				<view class="picker-item-content" :class="{'font-txt':add_class4==1}">{{arr4[index4]}}</view>
 				<view class="picker-item-logor">
 				<view class="picker-item-logor">
-					<image class="picker-item-logo-right" src="/static/image/right.png"></image>
+					<image class="picker-item-logo-right" src="../static/images/right.png"></image>
 				</view>
 				</view>
 			</view>
 			</view>
 		</picker>
 		</picker>

+ 360 - 0
pagesElectric/sfxq/sfxq.vue

@@ -0,0 +1,360 @@
+<template>
+	<view class="container">
+		<view class="line"></view>
+		<view class="same-month">
+			<view class="title">
+				<view class="vertical-line"></view>
+				<view class="title-txt"><text class="caption">当月详情</text><text
+						class="hah">/</text>时间更新到{{sameMonthData.dataTime}}</view>
+			</view>
+			<view class="content-details">
+				<view class="item">
+					<view class="num">{{sameMonthData.zongStart}}</view>
+					<view class="description">起码(吨)</view>
+				</view>
+				<view class="item">
+					<view class="num">{{sameMonthData.zongEnd}}</view>
+					<view class="description">止码(吨)</view>
+				</view>
+				<view class="item">
+					<view class="num">{{sameMonthData.totalPower}}</view>
+					<view class="description">用量(吨)</view>
+				</view>
+				<view class="item">
+					<view class="num">{{sameMonthData.totalMoney}}</view>
+					<view class="description">消费(元)</view>
+				</view>
+			</view>
+			<view class="txt-color">(注:水费标准:{{moneyPer}}元/吨)</view>
+		</view>
+		<view class="line"></view>
+		<view class="same-month">
+			<view class="title">
+				<view class="vertical-line"></view>
+				<view class="title-txt"><text class="caption">每月账单</text></view>
+			</view>
+			<view class="content-details">
+				<uni-table :border="true" :stripe="true" emptyText="暂无更多数据">
+					<!-- 表头行 -->
+					<uni-tr>
+						<uni-th width="66" align="center">时间</uni-th>
+						<uni-th width="64" align="center">起码(吨)</uni-th>
+						<uni-th width="64" align="center">止码(吨)</uni-th>
+						<uni-th width="64" align="center">用量(吨)</uni-th>
+						<uni-th width="64" align="center">消费</uni-th>
+					</uni-tr>
+					<!-- 表格数据行 -->
+					<uni-tr v-for="(item, index) in tableData" :key="index">
+						<uni-td align="center">{{item.dataTime}}</uni-td>
+						<uni-td align="center">{{item.zongStart}}</uni-td>
+						<uni-td align="center">{{item.zongEnd}}</uni-td>
+						<uni-td align="center">{{item.totalPower}}</uni-td>
+						<uni-td align="center">{{item.totalMoney}}</uni-td>
+					</uni-tr>
+				</uni-table>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				sameMonthData: {
+					dataTime: '',
+					zongEnd: 0.00.toFixed(2),
+					totalMoney: 0.00.toFixed(2),
+					totalPower: 0.00.toFixed(2),
+					zongStart: 0.00.toFixed(2)
+				},
+				moneyPer: 2.1.toFixed(2),
+				tableData: [],
+				ceshi: 'code',
+				stu_number: '', // 学号
+				roomSelect: '', // 选择的宿舍号
+				dom: ''
+			}
+		},
+		onLoad() {
+			try {
+				// 获取学号
+				this.stu_number = this.$store.state.userInfo.card_number
+				this.roomSelect = this.$store.state.building.roomSelect
+
+				if (this.stu_number == '' || this.roomSelect == '' || typeof(this.stu_number) == 'undefined' || typeof(this
+						.roomSelect) == 'undefined') {
+					const userinfo = uni.getStorageSync('userinfo_storage_key')
+					if (userinfo) {
+						this.stu_number = userinfo.card_number
+						this.roomSelect = userinfo.campus + userinfo.dorm_number
+					} else {
+						uni.redirectTo({
+							url: '../index/index'
+						})
+
+						uni.showToast({
+							icon: 'none',
+							title: '学号或宿舍号为空,请授权',
+							duration: 1500
+						})
+
+						return
+					}
+				}
+				// console.log(this.stu_number);
+				// console.log(this.roomSelect);
+				// 判断是否选择了宿舍号
+				if (this.haveSelectRoom()) {
+					uni.showToast({
+						title: '宿舍号为空',
+						icon: 'success'
+					})
+				}
+			} catch (e) {
+				console.log(e);
+			}
+		},
+		methods: {
+			/**
+			 * 判断是否选择了宿舍号
+			 */
+			haveSelectRoom() {
+				if (this.roomSelect != '' && typeof(this.roomSelect) != 'undefined') {
+					// 当月详情
+					try {
+						this.get_sameMonthDetails()
+					} catch (e) {
+						uni.showToast({
+							title: '当月详情'
+						})
+					}
+					// 每月账单
+					try {
+						this.get_history()
+					} catch (e) {
+						uni.showToast({
+							title: '每月账单异常'
+						})
+					}
+				} else {
+					return true
+				}
+			},
+			/**
+			 * 当月详情
+			 */
+			async get_sameMonthDetails() {
+				let res = await this.$myRequest({
+					host: this.ceshi,
+					url: '/HotWaters/cwaterqueryNow.action',
+					method: 'POST',
+					header: {
+						'content-type': 'application/x-www-form-urlencoded'
+					},
+					data: {
+						'roomSelect': this.roomSelect
+					}
+				})
+
+				// console.log(res.data)
+				if (res.data.data.length == 0) {
+					return
+				}
+
+				if (res.data.mess === '返回成功') {
+					let zongEnd = res.data.data[0].zongEnd
+					let totalMoney = res.data.data[0].totalMoney
+					let totalPower = res.data.data[0].totalPower
+					let zongStart = res.data.data[0].zongStart
+
+					let dataTime = res.data.data[0].dataTime
+					let dt = dataTime.split('-')
+					this.sameMonthData.dataTime = dt[0] + '年' + parseInt(dt[1]) + '月'
+					this.sameMonthData.zongEnd = zongEnd.toFixed(2)
+					this.sameMonthData.totalMoney = totalMoney.toFixed(2)
+					this.sameMonthData.totalPower = totalPower.toFixed(2)
+					this.sameMonthData.zongStart = zongStart.toFixed(2)
+				} else {
+					uni.showToast({
+						title: '加载数据异常',
+						duration: 1500
+					})
+
+					return
+				}
+			},
+
+			/**
+			 * 每月账单
+			 */
+			async get_history() {
+				uni.showToast({
+					icon: 'none',
+					title: '每月账单开发中...',
+					mask: true,
+					duration: 3000
+				})
+				return
+
+				var reg = /[\u4e00-\u9fa5]/g;
+				var str = this.roomSelect;
+				this.dom = str.replace(reg, "");
+				let res = await this.$myRequest({
+					host: this.ceshi,
+					url: '/HotWaters/cwaterMonthlist.action',
+					method: 'POST',
+					header: {
+						'content-type': 'application/x-www-form-urlencoded'
+					},
+					data: {
+						'dom': this.dom,
+						'page': 1,
+						'rows': 12
+					}
+				})
+
+				// console.log(res.data)
+				if (res.data.rows.length == 0) {
+					return
+				}
+
+				if (typeof res.data.rows === 'undefined') {
+					uni.showToast({
+						title: '加载数据异常',
+						duration: 1500
+					})
+
+					return
+				} else {
+					for (let i = 0; i < res.data.rows.length; i++) {
+						let dataTime = res.data.rows[i].dataTime
+						let zongStart = res.data.rows[i].zongStart
+						let zongEnd = res.data.rows[i].zongEnd
+						let totalPower = res.data.rows[i].totalPower
+						let totalMoney = res.data.rows[i].totalMoney
+
+						zongStart = zongStart.toFixed(2)
+						zongEnd = zongEnd.toFixed(2)
+						totalPower = totalPower.toFixed(2)
+						totalMoney = totalMoney.toFixed(2)
+
+						if (this.moneyPer <= 0.00) {
+							if (totalPower > 0.00 && totalMoney > 0.00) {
+								let moneyPer = totalMoney / totalPower
+								this.moneyPer = moneyPer.toFixed(2)
+
+								if (this.moneyPer <= 0.00) {
+									this.moneyPer = 0.61
+								}
+							}
+						}
+
+						totalMoney = '¥' + totalMoney
+						this.tableData.push({
+							dataTime,
+							zongStart,
+							zongEnd,
+							totalPower,
+							totalMoney
+						})
+					}
+				}
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.container {
+		display: flex;
+		flex-direction: column;
+		font-size: 29upx;
+		font-family: "Microsoft YaHei";
+
+		.line {
+			height: 10rpx;
+			background-color: #f5f5f5;
+		}
+
+		.same-month {
+			display: flex;
+			flex-direction: column;
+			padding: 20rpx 30rpx;
+
+			.title {
+				display: flex;
+				align-items: center;
+				margin-bottom: 30rpx;
+
+				.vertical-line {
+					display: inline-block;
+					margin-right: 20rpx;
+					width: 10rpx;
+					height: 45rpx;
+					background-color: #0282F8;
+				}
+
+				.title-txt {
+					display: flex;
+					flex-direction: row;
+					align-items: flex-end;
+					color: #C1C1C1;
+
+					.caption {
+						color: #2b2b2b;
+						font-size: 40upx;
+					}
+
+					.hah {
+						display: flex;
+						margin: 0 10rpx;
+					}
+				}
+			}
+
+			.content-details {
+				display: flex;
+				justify-content: space-around;
+
+				.item {
+					display: flex;
+					flex-direction: column;
+					align-items: center;
+
+					.num {
+						font-size: 40upx;
+					}
+
+					.description {
+						color: #9a9a9a;
+					}
+				}
+
+				/deep/ .uni-table {
+
+					.uni-table-th {
+						padding: 6px 8px;
+						font-size: 26upx;
+						white-space: nowrap;
+						text-align: center;
+						background-color: #E5F2FE;
+						color: #39393A;
+					}
+
+					.uni-table-td {
+						padding: 3px 5px;
+						font-size: 26upx;
+						white-space: nowrap;
+						text-align: center;
+					}
+				}
+			}
+
+			.txt-color {
+				margin: 20rpx 0;
+				color: #C1C1C1;
+			}
+		}
+	}
+</style>

pages/show/show.css → pagesElectric/show/show.css


+ 62 - 30
pages/show/show.vue

@@ -3,25 +3,25 @@
 		<view class="show-item">
 		<view class="show-item">
 			<view class="show-elec-label">
 			<view class="show-elec-label">
 				<view class="show-item-logol">
 				<view class="show-item-logol">
-					<image class="show-item-logo-left" src="/static/image/show.png"></image>
+					<image class="show-item-logo-left" src="../static/images/show.png"></image>
 				</view>
 				</view>
-				<view class="show-item-label">能耗走势图</view>
+				<view class="show-item-label">消费走势图</view>
 			</view>
 			</view>
 			<view class="charts-box">
 			<view class="charts-box">
-				<qiun-data-charts type="demotype" :chartData="chartData" :opts="chartOpts"
+				<qiun-data-charts type="line" :chartData="chartData" :opts="chartOpts" :ontouch="true"
 					tooltipFormat="tooltipDemo1" />
 					tooltipFormat="tooltipDemo1" />
 			</view>
 			</view>
 			<view class="select-show">
 			<view class="select-show">
 				<button :class="[btn ? 'first-button-bg' : 'first-button']"
 				<button :class="[btn ? 'first-button-bg' : 'first-button']"
-					@tap="getEnergyConsumption('day')">日</button>
-				<button :class="[btn ? 'first-button' : 'first-button-bg']"
 					@tap="getEnergyConsumption('month')">月</button>
 					@tap="getEnergyConsumption('month')">月</button>
+				<button :class="[btn ? 'first-button' : 'first-button-bg']"
+					@tap="getEnergyConsumption('year')">年</button>
 			</view>
 			</view>
 		</view>
 		</view>
 		<view class="show-item-date">
 		<view class="show-item-date">
 			<view class="show-elec-label">
 			<view class="show-elec-label">
 				<view class="show-item-logol">
 				<view class="show-item-logol">
-					<image class="show-item-logo-left" src="/static/image/record.png"></image>
+					<image class="show-item-logo-left" src="../static/images/record.png"></image>
 				</view>
 				</view>
 				<view class="show-item-label show-label">缴费记录</view>
 				<view class="show-item-label show-label">缴费记录</view>
 			</view>
 			</view>
@@ -62,16 +62,27 @@
 				btn: false,
 				btn: false,
 				chartData: {
 				chartData: {
 					categories: [],
 					categories: [],
-					series: [{
-						data: [],
-
-					}]
+					series: []
 				},
 				},
 				chartOpts: {
 				chartOpts: {
+					color: ["#1890FF", "#91CB74", "#FAC858", "#EE6666", "#73C0DE", "#3CA272", "#FC8452", "#9A60B4",
+						"#ea7ccc"
+					],
+					padding: [15, 10, 0, 15],
+					legend: {},
+					xAxis: {
+						disableGrid: true
+					},
 					yAxis: {
 					yAxis: {
 						data: [{
 						data: [{
 							max: 0
 							max: 0
 						}]
 						}]
+					},
+					extra: {
+						line: {
+							type: "curve",
+							width: 2
+						}
 					}
 					}
 				},
 				},
 				date: this.$getDate({
 				date: this.$getDate({
@@ -116,20 +127,22 @@
 				}
 				}
 				// console.log(this.stu_number);
 				// console.log(this.stu_number);
 				// console.log(this.roomSelect);
 				// console.log(this.roomSelect);
-				// 能耗记录
-				this.getEnergyConsumption('month')
 				// 缴费记录
 				// 缴费记录
 				this.get_jiaofeijilu()
 				this.get_jiaofeijilu()
 			} catch (e) {
 			} catch (e) {
 				console.log(e);
 				console.log(e);
 			}
 			}
 		},
 		},
+		onReady() {
+			// 消费走势
+			this.getEnergyConsumption('month')
+		},
 		methods: {
 		methods: {
 			/**
 			/**
-			 * 按日、月获取能耗
+			 * 按月、年获取消费记录
 			 */
 			 */
 			getEnergyConsumption(dayOrMonth) {
 			getEnergyConsumption(dayOrMonth) {
-				// 按日、月显示能耗
+				// 按月、年获取消费记录
 				this.get_nenghaojilu(dayOrMonth)
 				this.get_nenghaojilu(dayOrMonth)
 			},
 			},
 			/**
 			/**
@@ -187,7 +200,7 @@
 				}
 				}
 			},
 			},
 			/**
 			/**
-			 * 能耗记录
+			 * 按月、年获取消费记录
 			 */
 			 */
 			async get_nenghaojilu(dayOrMonth) {
 			async get_nenghaojilu(dayOrMonth) {
 				// console.log(this.roomSelect);
 				// console.log(this.roomSelect);
@@ -196,27 +209,30 @@
 				var dom = str.replace(reg, "");
 				var dom = str.replace(reg, "");
 				if (dom != '' && typeof(dom) != 'undefined') {
 				if (dom != '' && typeof(dom) != 'undefined') {
 					let res = null;
 					let res = null;
-					if (dayOrMonth == 'day') {
+					if (dayOrMonth == 'month') {
 						this.btn = true
 						this.btn = true
 						res = await this.$myRequest({
 						res = await this.$myRequest({
 							host: this.ceshi,
 							host: this.ceshi,
-							url: '/HotWaters/elqueryDayPower.action',
+							// url: '/HotWaters/elqueryDayPower.action',
+							url: '/HotWaters/elMonthlist.action',
 							method: 'POST',
 							method: 'POST',
 							header: {
 							header: {
 								'content-type': 'application/x-www-form-urlencoded'
 								'content-type': 'application/x-www-form-urlencoded'
 							},
 							},
 							data: {
 							data: {
-								'dom': dom
+								'dom': dom,
+								'page': 1,
+								'rows': 12
 							}
 							}
 						})
 						})
 
 
-						// console.log(res.data.data);
+						// console.log(res.data.rows);
 						// console.log(res.data);
 						// console.log(res.data);
-						if (res.data.code != 200) {
+						if (res.data.rows.length == 0) {
 							return
 							return
 						}
 						}
 
 
-						if (typeof res.data.data === 'undefined') {
+						if (typeof res.data.rows === 'undefined') {
 							uni.showToast({
 							uni.showToast({
 								title: '加载数据异常',
 								title: '加载数据异常',
 								duration: 1500
 								duration: 1500
@@ -226,20 +242,27 @@
 
 
 						let chrt_data = {
 						let chrt_data = {
 							categories: [],
 							categories: [],
-							series: [{
-								data: [],
-							}],
+							series: [],
 						}
 						}
 						let elc_max = -1.0
 						let elc_max = -1.0
 						let dt = ''
 						let dt = ''
-						for (var i = 0; i < res.data.data.length; i++) {
-							dt = res.data.data[i].dataTime
-							chrt_data.categories.push(dt.substr(dt.indexOf('-') + 1, dt.length))
-							chrt_data.series[0].data.push(res.data.data[i].use_elc)
-							if (parseFloat(res.data.data[i].use_elc) > parseFloat(elc_max)) {
-								elc_max = res.data.data[i].use_elc
+						let temp = 0
+						let data = []
+						for (var i = 0; i < res.data.rows.length; i++) {
+							dt = res.data.rows[i].dataTime
+							chrt_data.categories.push(parseInt(dt.substr(dt.indexOf('-') + 1, dt.length)) + '月')
+							temp = res.data.rows[i].totalMoney
+							temp = temp.toFixed(2)
+							data.push(temp)
+							if (parseFloat(temp) > parseFloat(elc_max)) {
+								elc_max = temp
 							}
 							}
 						}
 						}
+						let items = {
+							name: '金额',
+							data: data
+						}
+						chrt_data.series.push(items)
 						let m = parseFloat(Math.abs(elc_max))
 						let m = parseFloat(Math.abs(elc_max))
 						// console.log(chrt_data);
 						// console.log(chrt_data);
 						if (elc_max == 0.0) {
 						if (elc_max == 0.0) {
@@ -255,6 +278,15 @@
 						}
 						}
 					} else {
 					} else {
 						this.btn = false
 						this.btn = false
+						let _this = this
+						uni.showToast({
+							mask: true,
+							title: '年消费更新中…',
+							success() {
+								_this.btn = true
+							}
+						})
+						return
 						res = await this.$myRequest({
 						res = await this.$myRequest({
 							host: this.ceshi,
 							host: this.ceshi,
 							url: '/HotWaters/buildgetMonthBill.action',
 							url: '/HotWaters/buildgetMonthBill.action',

static/image/ad_dianfei.png → pagesElectric/static/images/ad_dianfei.png


static/image/building.png → pagesElectric/static/images/building.png


BIN
pagesElectric/static/images/dfxq.png


static/image/elec.png → pagesElectric/static/images/elec.png


static/image/floor.png → pagesElectric/static/images/floor.png


static/image/money.png → pagesElectric/static/images/money.png


static/image/record.png → pagesElectric/static/images/record.png


static/image/right.png → pagesElectric/static/images/right.png


static/image/room.png → pagesElectric/static/images/room.png


static/image/school.png → pagesElectric/static/images/school.png


BIN
pagesElectric/static/images/sfxq.png


static/image/show.png → pagesElectric/static/images/show.png


+ 239 - 0
pagesWater/reshuiDetails/reshuiDetails.vue

@@ -0,0 +1,239 @@
+<template>
+	<view class="container">
+		<view class="line"></view>
+		<view class="same-month">
+			<view class="title">
+				<view class="vertical-line"></view>
+				<view class="title-txt"><text class="caption">充值详情</text></view>
+			</view>
+			<view class="content-details">
+				<uni-table :border="true" :stripe="true" emptyText="暂无更多数据">
+					<!-- 表头行 -->
+					<uni-tr>
+						<uni-th width="30" align="center">姓名</uni-th>
+						<uni-th width="30" align="center">金额</uni-th>
+						<uni-th width="30" align="center">时间</uni-th>
+					</uni-tr>
+					<!-- 表格数据行 -->
+					<uni-tr v-for="(item, index) in tableData" :key="index">
+						<uni-td align="center">{{item.user_name}}</uni-td>
+						<uni-td align="center">{{item.account}}</uni-td>
+						<uni-td align="center">{{item.re_time}}</uni-td>
+					</uni-tr>
+				</uni-table>
+			</view>
+			<view class="uni-pagination-box">
+				<uni-pagination :page-size="pageSize" :current="pageCurrent" :total="totalNum" @change="page_change" />
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				tableData: [],
+				ceshi: 'code',
+				stu_number: '', // 学号
+				// 每页数据量
+				pageSize: 12,
+				// 当前页
+				pageCurrent: 1,
+				// 数据总量
+				totalNum: 0
+			}
+		},
+		onLoad() {
+			try {
+				// 获取学号
+				this.stu_number = this.$store.state.userInfo.card_number
+				this.roomSelect = this.$store.state.building.roomSelect
+
+				if (this.stu_number == '' || this.roomSelect == '' || typeof(this.stu_number) == 'undefined' || typeof(this
+						.roomSelect) == 'undefined') {
+					const userinfo = uni.getStorageSync('userinfo_storage_key')
+					if (userinfo) {
+						this.stu_number = userinfo.card_number
+						this.roomSelect = userinfo.campus + userinfo.dorm_number
+					} else {
+						uni.redirectTo({
+							url: '../index/index'
+						})
+
+						uni.showToast({
+							icon: 'none',
+							title: '学号或宿舍号为空,请授权',
+							duration: 1500
+						})
+
+						return
+					}
+				}
+				// console.log(this.stu_number);
+				this.get_history()
+			} catch (e) {
+				uni.showToast({
+					title: '获取学号异常:' + e.message,
+					duration: 1500
+				})
+				console.log('获取学号异常:' + e.message);
+			}
+		},
+		methods: {
+			/**
+			 * 分页,页码改变
+			 */
+			page_change(e) {
+				this.pageCurrent = e.current
+				this.get_history()
+			},
+			/**
+			 * 充值详情
+			 */
+			async get_history() {
+				let _this = this
+				let res = await this.$myRequest({
+					host: this.ceshi,
+					url: '/HotWaters/wpqueryRecharge.action',
+					method: 'POST',
+					header: {
+						'content-type': 'application/x-www-form-urlencoded'
+					},
+					data: {
+						'stu_number': this.stu_number,
+						// 'stu_number': '360481200301045025',
+						'page': _this.pageCurrent,
+						'rows': _this.pageSize
+					}
+				})
+
+				// console.log(res.data)
+				if (res.data.rows.length == 0) {
+					return
+				}
+
+				if (typeof res.data.rows === 'undefined') {
+					uni.showToast({
+						title: '加载数据异常',
+						duration: 1500
+					})
+
+					return
+				} else {
+					let tdata = []
+					for (let i = 0; i < res.data.rows.length; i++) {
+						let user_name = res.data.rows[i].user_name
+						let account = res.data.rows[i].account
+						let re_time = res.data.rows[i].re_time
+
+						account = '¥' + account.toFixed(2)
+
+						tdata.push({
+							user_name,
+							account,
+							re_time
+						})
+					}
+					// 填充表格
+					this.tableData = tdata
+					// 填充分页参数
+					this.totalNum = res.data.total
+					this.pageSize = res.data.numPerPage
+					this.pageCurrent = res.data.currentPage
+					this.totalPage = res.data.totalPage
+				}
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.container {
+		display: flex;
+		flex-direction: column;
+		font-size: 29upx;
+		font-family: "Microsoft YaHei";
+
+		.line {
+			height: 10rpx;
+			background-color: #f5f5f5;
+		}
+
+		.same-month {
+			display: flex;
+			flex-direction: column;
+			padding: 20rpx 30rpx;
+
+			.title {
+				display: flex;
+				align-items: center;
+				margin-bottom: 30rpx;
+
+				.vertical-line {
+					display: inline-block;
+					margin-right: 20rpx;
+					width: 10rpx;
+					height: 45rpx;
+					background-color: #0282F8;
+				}
+
+				.title-txt {
+					display: flex;
+					flex-direction: row;
+					align-items: flex-end;
+					color: #C1C1C1;
+
+					.caption {
+						color: #2b2b2b;
+						font-size: 40upx;
+					}
+
+					.hah {
+						display: flex;
+						margin: 0 10rpx;
+					}
+				}
+			}
+
+			.content-details {
+				display: flex;
+				justify-content: space-around;
+
+				.item {
+					display: flex;
+					flex-direction: column;
+					align-items: center;
+
+					.num {
+						font-size: 40upx;
+					}
+
+					.description {
+						color: #9a9a9a;
+					}
+				}
+
+				/deep/ .uni-table {
+
+					.uni-table-th {
+						padding: 6px 8px;
+						font-size: 26upx;
+						white-space: nowrap;
+						text-align: center;
+						background-color: #E5F2FE;
+						color: #5b5b5d;
+					}
+
+					.uni-table-td {
+						padding: 3px 5px;
+						font-size: 26upx;
+						white-space: nowrap;
+						text-align: center;
+						color: #000000;
+					}
+				}
+			}
+		}
+	}
+</style>

+ 0 - 1
static/api.js

@@ -1,7 +1,6 @@
 const WEXIN_BASE_URL = 'https://api.mch.weixin.qq.com' // wexin
 const WEXIN_BASE_URL = 'https://api.mch.weixin.qq.com' // wexin
 const WECARD_BASE_URL = 'https://open.wecard.qq.com' // wecard
 const WECARD_BASE_URL = 'https://open.wecard.qq.com' // wecard
 const CODE_BASE_URL = 'https://jtishfw.ncjti.edu.cn/jxch-smartmp' // code
 const CODE_BASE_URL = 'https://jtishfw.ncjti.edu.cn/jxch-smartmp' // code
-// const CODE_BASE_URL = 'http://4hssv8.natappfree.cc' // code
 const IP_BASE_URL = 'https://pv.sohu.com/cityjson' // ip
 const IP_BASE_URL = 'https://pv.sohu.com/cityjson' // ip
 
 
 const myRequest = (options) => {
 const myRequest = (options) => {

BIN
static/image/banner2x.png


BIN
static/image/recharge2x.png


BIN
static/image/shower2x.png


BIN
static/image/sjx.png


static/image/ad_reshui.png → static/images/ad_reshui.png


BIN
static/images/air.png


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

@@ -1,3 +1,80 @@
+## 2.4.3-20220505(2022-05-05)
+- 秋云图表组件 修复开启canvas2d后将series赋值为空数组显示加载图标时,再次赋值后画布闪动的bug
+- 秋云图表组件 修复升级hbx最新版后ECharts的highlight方法报错的bug
+- uCharts.js 雷达图新增参数opts.extra.radar.gridEval,数据点位网格抽希,默认1
+- uCharts.js 雷达图新增参数opts.extra.radar.axisLabel,	是否显示刻度点值,默认false
+- uCharts.js 雷达图新增参数opts.extra.radar.axisLabelTofix,刻度点值小数位数,默认0
+- uCharts.js 雷达图新增参数opts.extra.radar.labelPointShow,是否显示末端刻度圆点,默认false
+- uCharts.js 雷达图新增参数opts.extra.radar.labelPointRadius,刻度圆点的半径,默认3
+- uCharts.js 雷达图新增参数opts.extra.radar.labelPointColor,刻度圆点的颜色,默认#cccccc
+- uCharts.js 雷达图新增参数opts.extra.radar.linearType,渐变色类型,可选值"none"关闭渐变,"custom"开启渐变
+- uCharts.js 雷达图新增参数opts.extra.radar.customColor,自定义渐变颜色,数组类型对应series的数组长度以匹配不同series颜色的不同配色方案,例如["#FA7D8D", "#EB88E2"]
+- uCharts.js 雷达图优化支持series.textColor、series.textSize属性
+- uCharts.js 柱状图中温度计式图标,优化支持全圆角类型,修复边框有缝隙的bug,详见官网【演示】中的温度计图表
+- uCharts.js 柱状图新增参数opts.extra.column.activeWidth,当前点击柱状图的背景宽度,默认一个单元格单位
+- uCharts.js 混合图增加opts.extra.mix.area.gradient 区域图是否开启渐变色
+- uCharts.js 混合图增加opts.extra.mix.area.opacity 区域图透明度,默认0.2
+- uCharts.js 饼图、圆环图、玫瑰图、漏斗图,增加opts.series[0].data[i].labelText,自定义标签文字,避免formatter格式化的繁琐,详见官网【演示】中的饼图
+- uCharts.js 饼图、圆环图、玫瑰图、漏斗图,增加opts.series[0].data[i].labelShow,自定义是否显示某一个指示标签,避免因饼图类别太多导致标签重复或者居多导致图形变形的问题,详见官网【演示】中的饼图
+- uCharts.js 增加opts.series[i].legendText/opts.series[0].data[i].legendText(与series.name同级)自定义图例显示文字的方法
+- uCharts.js 优化X轴、Y轴formatter格式化方法增加形参,统一为fromatter:function(value,index,opts){}
+- uCharts.js 修复横屏模式下无法使用双指缩放方法的bug
+- uCharts.js 修复当只有一条数据或者多条数据值相等的时候Y轴自动计算的最大值错误的bug
+- 【官网模板】增加外部自定义图例与图表交互的例子,[点击跳转](https://www.ucharts.cn/v2/#/layout/info?id=2)
+
+## 注意:非unimodules 版本如因更新 hbx 至 3.4.7 导致报错如下,请到码云更新非 unimodules 版本组件,[点击跳转](https://gitee.com/uCharts/uCharts/tree/master/uni-app/uCharts-%E7%BB%84%E4%BB%B6)
+> Error in callback for immediate watcher "uchartsOpts": "SyntaxError: Unexpected token u in JSON at position 0"
+## 2.4.2-20220421(2022-04-21)
+- 秋云图表组件 修复HBX升级3.4.6.20220420版本后echarts报错的问题
+## 2.4.2-20220420(2022-04-20)
+## 重要!此版本uCharts新增了很多功能,修复了诸多已知问题
+- 秋云图表组件 新增onzoom开启双指缩放功能(仅uCharts),前提需要直角坐标系类图表类型,并且ontouch为true、opts.enableScroll为true,详见实例项目K线图
+- 秋云图表组件 新增optsWatch是否监听opts变化,关闭optsWatch后,动态修改opts不会触发图表重绘
+- 秋云图表组件 修复开启canvas2d功能后,动态更新数据后画布闪动的bug
+- 秋云图表组件 去除directory属性,改为自动获取echarts.min.js路径(升级不受影响)
+- 秋云图表组件 增加getImage()方法及@getImage事件,通过ref调用getImage()方法获,触发@getImage事件获取当前画布的base64图片文件流。
+- 秋云图表组件 支付宝、字节跳动、飞书、快手小程序支持开启canvas2d同层渲染设置。
+- 秋云图表组件 新增加【非uniCloud】版本组件,避免有些不需要uniCloud的使用组件发布至小程序需要提交隐私声明问题,请到码云[【非uniCloud版本】](https://gitee.com/uCharts/uCharts/tree/master/uni-app/uCharts-%E7%BB%84%E4%BB%B6),或npm[【非uniCloud版本】](https://www.npmjs.com/package/@qiun/uni-ucharts)下载使用。
+- uCharts.js 新增dobuleZoom双指缩放功能
+- uCharts.js 新增山峰图type="mount",数据格式为饼图类格式,不需要传入categories,具体详见新版官网在线演示
+- uCharts.js 修复折线图当数据中存在null时tooltip报错的bug
+- uCharts.js 修复饼图类当画布比较小时自动计算的半径是负数报错的bug
+- uCharts.js 统一各图表类型的series.formatter格式化方法的形参为(val, index, series, opts),方便格式化时有更多参数可用
+- uCharts.js 标记线功能增加labelText自定义显示文字,增加labelAlign标签显示位置(左侧或右侧),增加标签显示位置微调labelOffsetX、labelOffsetY
+- uCharts.js 修复条状图当数值很小时开启圆角后样式错误的bug
+- uCharts.js 修复X轴开启disabled后,X轴仍占用空间的bug
+- uCharts.js 修复X轴开启滚动条并且开启rotateLabel后,X轴文字与滚动条重叠的bug
+- uCharts.js 增加X轴rotateAngle文字旋转自定义角度,取值范围(-90至90)
+- uCharts.js 修复地图文字标签层级显示不正确的bug
+- uCharts.js 修复饼图、圆环图、玫瑰图当数据全部为0的时候不显示数据标签的bug
+- uCharts.js 修复当opts.padding上边距为0时,Y轴顶部刻度标签位置不正确的bug
+
+## 另外我们还开发了各大原生小程序组件,已发布至码云和npm
+[https://gitee.com/uCharts/uCharts](https://gitee.com/uCharts/uCharts)
+[https://www.npmjs.com/~qiun](https://www.npmjs.com/~qiun)
+
+## 对于原生uCharts文档我们已上线新版官方网站,详情点击下面链接进入官网
+[https://www.uCharts.cn/v2/](https://www.ucharts.cn/v2/)
+## 2.3.7-20220122(2022-01-22)
+## 重要!使用vue3编译,请使用cli模式并升级至最新依赖,HbuilderX编译需要使用3.3.8以上版本
+- uCharts.js 修复uni-app平台组件模式使用vue3编译到小程序报错的bug。
+## 2.3.7-20220118(2022-01-18)
+## 注意,使用vue3的前提是需要3.3.8.20220114-alpha版本的HBuilder!
+## 2.3.67-20220118(2022-01-18)
+- 秋云图表组件 组件初步支持vue3,全端编译会有些问题,具体详见下面修改:
+1. 小程序端运行时,在uni_modules文件夹的qiun-data-charts.js中搜索 new uni_modules_qiunDataCharts_js_sdk_uCharts_uCharts.uCharts,将.uCharts去掉。
+2. 小程序端发行时,在uni_modules文件夹的qiun-data-charts.js中搜索 new e.uCharts,将.uCharts去掉,变为 new e。
+3. 如果觉得上述步骤比较麻烦,如果您的项目只编译到小程序端,可以修改u-charts.js最后一行导出方式,将 export default uCharts;变更为 export default { uCharts: uCharts }; 这样变更后,H5和App端的renderjs会有问题,请开发者自行选择。(此问题非组件问题,请等待DC官方修复Vue3的小程序端)
+## 2.3.6-20220111(2022-01-11)
+- 秋云图表组件 修改组件 props 属性中的 background 默认值为 rgba(0,0,0,0)
+## 2.3.6-20211201(2021-12-01)
+- uCharts.js 修复bar条状图开启圆角模式时,值很小时圆角渲染错误的bug
+## 2.3.5-20211014(2021-10-15)
+- uCharts.js 增加vue3的编译支持(仅原生uCharts,qiun-data-charts组件后续会支持,请关注更新)
+## 2.3.4-20211012(2021-10-12)
+- 秋云图表组件 修复 mac os x 系统 mouseover 事件丢失的 bug
+## 2.3.3-20210706(2021-07-06)
+- uCharts.js 增加雷达图开启数据点值(opts.dataLabel)的显示
 ## 2.3.2-20210627(2021-06-27)
 ## 2.3.2-20210627(2021-06-27)
 - 秋云图表组件 修复tooltipCustom个别情况下传值不正确报错TypeError: Cannot read property 'name' of undefined的bug
 - 秋云图表组件 修复tooltipCustom个别情况下传值不正确报错TypeError: Cannot read property 'name' of undefined的bug
 ## 2.3.1-20210616(2021-06-16)
 ## 2.3.1-20210616(2021-06-16)

+ 131 - 65
uni_modules/qiun-data-charts/components/qiun-data-charts/qiun-data-charts.vue

@@ -1,5 +1,5 @@
 <!-- 
 <!-- 
- * qiun-data-charts 秋云高性能跨全端图表组件 v2.3.2-20210612
+ * qiun-data-charts 秋云高性能跨全端图表组件
  * Copyright (c) 2021 QIUN® 秋云 https://www.ucharts.cn All rights reserved.
  * Copyright (c) 2021 QIUN® 秋云 https://www.ucharts.cn All rights reserved.
  * Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  * Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  * 复制使用请保留本段注释,感谢支持开源!
  * 复制使用请保留本段注释,感谢支持开源!
@@ -42,13 +42,13 @@
     </block>
     </block>
     <block v-else>
     <block v-else>
       <view
       <view
-        @tap="rdcharts.tap"
-        @mousemove="rdcharts.mouseMove"
-        @mousedown="rdcharts.mouseDown"
-        @mouseup="rdcharts.mouseUp"
-        @touchstart="rdcharts.touchStart"
-        @touchmove="rdcharts.touchMove"
-        @touchend="rdcharts.touchEnd"
+        v-on:tap="rdcharts.tap"
+        v-on:mousemove="rdcharts.mouseMove"
+        v-on:mousedown="rdcharts.mouseDown"
+        v-on:mouseup="rdcharts.mouseUp"
+        v-on:touchstart="rdcharts.touchStart"
+        v-on:touchmove="rdcharts.touchMove"
+        v-on:touchend="rdcharts.touchEnd"
         :id="'UC'+cid"
         :id="'UC'+cid"
         :prop="uchartsOpts"
         :prop="uchartsOpts"
         :change:prop="rdcharts.ucinit"
         :change:prop="rdcharts.ucinit"
@@ -97,7 +97,7 @@
     </block>
     </block>
     <!-- #endif -->
     <!-- #endif -->
     <!-- 其他小程序通过vue渲染图表 -->
     <!-- 其他小程序通过vue渲染图表 -->
-    <!-- #ifdef MP-360 || MP-BAIDU || MP-QQ || MP-TOUTIAO || MP-WEIXIN -->
+    <!-- #ifdef MP-360 || MP-BAIDU || MP-QQ || MP-TOUTIAO || MP-WEIXIN || MP-KUAISHOU || MP-LARK || MP-JD -->
     <block v-if="type2d">
     <block v-if="type2d">
       <view v-if="ontouch" @tap="_tap">
       <view v-if="ontouch" @tap="_tap">
         <canvas
         <canvas
@@ -156,7 +156,7 @@
 </template>
 </template>
 
 
 <script>
 <script>
-import uChartsMp from '../../js_sdk/u-charts/u-charts.js';
+import uCharts from '../../js_sdk/u-charts/u-charts.js';
 import cfu from '../../js_sdk/u-charts/config-ucharts.js';
 import cfu from '../../js_sdk/u-charts/config-ucharts.js';
 // #ifdef APP-VUE || H5
 // #ifdef APP-VUE || H5
 import cfe from '../../js_sdk/u-charts/config-echarts.js';
 import cfe from '../../js_sdk/u-charts/config-echarts.js';
@@ -175,7 +175,7 @@ function deepCloneAssign(origin = {}, ...args) {
 
 
 function formatterAssign(args,formatter) {
 function formatterAssign(args,formatter) {
   for (let key in args) {
   for (let key in args) {
-    if(args[key] !== null && typeof args[key] === 'object'){
+    if(args.hasOwnProperty(key) && args[key] !== null && typeof args[key] === 'object'){
       formatterAssign(args[key],formatter)
       formatterAssign(args[key],formatter)
     }else if(key === 'format' && typeof args[key] === 'string'){
     }else if(key === 'format' && typeof args[key] === 'string'){
       args['formatter'] = formatter[args[key]] ? formatter[args[key]] : undefined;
       args['formatter'] = formatter[args[key]] ? formatter[args[key]] : undefined;
@@ -247,7 +247,7 @@ export default {
     },
     },
     background: {
     background: {
       type: String,
       type: String,
-      default: 'none'
+      default: 'rgba(0,0,0,0)'
     },
     },
     animation: {
     animation: {
       type: Boolean,
       type: Boolean,
@@ -306,6 +306,14 @@ export default {
       type: Boolean,
       type: Boolean,
       default: false
       default: false
     },
     },
+    optsWatch: {
+      type: Boolean,
+      default: true
+    },
+    onzoom: {
+      type: Boolean,
+      default: false
+    },
     ontap: {
     ontap: {
       type: Boolean,
       type: Boolean,
       default: true
       default: true
@@ -373,6 +381,12 @@ export default {
     tapLegend: {
     tapLegend: {
       type: Boolean,
       type: Boolean,
       default: true
       default: true
+    },
+    menus: {
+      type: Array,
+      default () {
+        return []
+      }
     }
     }
   },
   },
   data() {
   data() {
@@ -403,7 +417,7 @@ export default {
   created(){
   created(){
     this.cid = this.canvasId
     this.cid = this.canvasId
     if (this.canvasId == 'uchartsid' || this.canvasId == '') {
     if (this.canvasId == 'uchartsid' || this.canvasId == '') {
-      let t = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
+      let t = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
       let len = t.length
       let len = t.length
       let id = ''
       let id = ''
       for (let i = 0; i < 32; i++) {
       for (let i = 0; i < 32; i++) {
@@ -412,24 +426,25 @@ export default {
       this.cid = id
       this.cid = id
     }
     }
     const systemInfo = uni.getSystemInfoSync()
     const systemInfo = uni.getSystemInfoSync()
-    if(systemInfo.platform === 'windows'){
+    if(systemInfo.platform === 'windows' || systemInfo.platform === 'mac'){
       this.inWin = true;
       this.inWin = true;
     }
     }
     // #ifdef MP-WEIXIN
     // #ifdef MP-WEIXIN
     this.inWx = true;
     this.inWx = true;
-    if (this.canvas2d === false || systemInfo.platform === 'windows') {
+    if (this.canvas2d === false || systemInfo.platform === 'windows' || systemInfo.platform === 'mac') {
       this.type2d = false;
       this.type2d = false;
     }else{
     }else{
+      this.type2d = true;
       this.pixel = systemInfo.pixelRatio;
       this.pixel = systemInfo.pixelRatio;
-      if (this.canvasId === 'uchartsid' || this.canvasId == '') {
-        console.log('[uCharts]:开启canvas2d模式,必须指定canvasId,否则会出现偶尔获取不到dom节点的问题!');
-      }
     }
     }
     // #endif
     // #endif
     //非微信小程序端强制关闭canvas2d模式
     //非微信小程序端强制关闭canvas2d模式
     // #ifndef MP-WEIXIN
     // #ifndef MP-WEIXIN
     this.type2d = false;
     this.type2d = false;
     // #endif
     // #endif
+    // #ifdef  MP-TOUTIAO || MP-LARK || MP-ALIPAY
+    this.type2d = this.canvas2d;
+    // #endif
     // #ifdef MP-ALIPAY
     // #ifdef MP-ALIPAY
     this.inAli = true;
     this.inAli = true;
     this.pixel = systemInfo.pixelRatio;
     this.pixel = systemInfo.pixelRatio;
@@ -505,11 +520,11 @@ export default {
       handler(val, oldval) {
       handler(val, oldval) {
         if (typeof val === 'object') {
         if (typeof val === 'object') {
           if (JSON.stringify(val) !== JSON.stringify(oldval)) {
           if (JSON.stringify(val) !== JSON.stringify(oldval)) {
+            this._clearChart();
             if (val.series && val.series.length > 0) {
             if (val.series && val.series.length > 0) {
               this.beforeInit();
               this.beforeInit();
             }else{
             }else{
               this.mixinDatacomLoading = true;
               this.mixinDatacomLoading = true;
-              this._clearChart();
               this.showchart = false;
               this.showchart = false;
               this.mixinDatacomErrorMessage = null;
               this.mixinDatacomErrorMessage = null;
             }
             }
@@ -543,7 +558,7 @@ export default {
     optsProps: {
     optsProps: {
       handler(val, oldval) {
       handler(val, oldval) {
         if (typeof val === 'object') {
         if (typeof val === 'object') {
-          if (JSON.stringify(val) !== JSON.stringify(oldval) && this.echarts === false) {
+          if (JSON.stringify(val) !== JSON.stringify(oldval) && this.echarts === false && this.optsWatch == true) {
             this.checkData(this.drawData);
             this.checkData(this.drawData);
           }
           }
         } else {
         } else {
@@ -848,10 +863,12 @@ export default {
     },
     },
     _clearChart() {
     _clearChart() {
       let cid = this.cid
       let cid = this.cid
-      if (this.echrts !== true) {
-        const ctx = uni.createCanvasContext(cid, this);
-        ctx.clearRect(0, 0, this.cWidth, this.cHeight);
-        ctx.draw();
+      if (this.echrts !== true && cfu.option[cid] && cfu.option[cid].context) {
+        const ctx = cfu.option[cid].context;
+        if(typeof ctx === "object" && !cfu.option[cid].update){
+          ctx.clearRect(0, 0, this.cWidth, this.cHeight);
+          ctx.draw();
+        }
       }
       }
     },
     },
     init() {
     init() {
@@ -870,12 +887,13 @@ export default {
             this.cWidth = data.width;
             this.cWidth = data.width;
             this.cHeight = data.height;
             this.cHeight = data.height;
             if(this.echarts !== true){
             if(this.echarts !== true){
-              cfu.option[cid].background = this.background == 'none' ? '#FFFFFF' : this.background;
+              cfu.option[cid].background = this.background == 'rgba(0,0,0,0)' ? '#FFFFFF' : this.background;
               cfu.option[cid].canvas2d = this.type2d;
               cfu.option[cid].canvas2d = this.type2d;
               cfu.option[cid].pixelRatio = this.pixel;
               cfu.option[cid].pixelRatio = this.pixel;
               cfu.option[cid].animation = this.animation;
               cfu.option[cid].animation = this.animation;
               cfu.option[cid].width = data.width * this.pixel;
               cfu.option[cid].width = data.width * this.pixel;
               cfu.option[cid].height = data.height * this.pixel;
               cfu.option[cid].height = data.height * this.pixel;
+              cfu.option[cid].onzoom = this.onzoom;
               cfu.option[cid].ontap = this.ontap;
               cfu.option[cid].ontap = this.ontap;
               cfu.option[cid].ontouch = this.ontouch;
               cfu.option[cid].ontouch = this.ontouch;
               cfu.option[cid].onmouse = this.openmouse;
               cfu.option[cid].onmouse = this.openmouse;
@@ -918,14 +936,14 @@ export default {
                         const canvas = res[0].node;
                         const canvas = res[0].node;
                         const ctx = canvas.getContext('2d');
                         const ctx = canvas.getContext('2d');
                         cfu.option[cid].context = ctx;
                         cfu.option[cid].context = ctx;
-                        canvas.width = data.width * this.pixel;
-                        canvas.height = data.height * this.pixel;
-                        canvas._width = data.width * this.pixel;
-                        canvas._height = data.height * this.pixel;
                         cfu.option[cid].rotateLock = cfu.option[cid].rotate;
                         cfu.option[cid].rotateLock = cfu.option[cid].rotate;
                         if(cfu.instance[cid] && cfu.option[cid] && cfu.option[cid].update === true){
                         if(cfu.instance[cid] && cfu.option[cid] && cfu.option[cid].update === true){
                           this._updataUChart(cid)
                           this._updataUChart(cid)
                         }else{
                         }else{
+                          canvas.width = data.width * this.pixel;
+                          canvas.height = data.height * this.pixel;
+                          canvas._width = data.width * this.pixel;
+                          canvas._height = data.height * this.pixel;
                           setTimeout(()=>{
                           setTimeout(()=>{
                             cfu.option[cid].context.restore();
                             cfu.option[cid].context.restore();
                             cfu.option[cid].context.save();
                             cfu.option[cid].context.save();
@@ -977,25 +995,46 @@ export default {
     	    //#endif
     	    //#endif
     	    //#ifndef H5
     	    //#ifndef H5
     	      uni.saveImageToPhotosAlbum({
     	      uni.saveImageToPhotosAlbum({
-    	          filePath: res.tempFilePath,
-    	          success: function () {
-    	              uni.showToast({
-    	                  title: '保存成功',
-    	                  duration: 2000
-    	              });
-    	          }
+              filePath: res.tempFilePath,
+              success: function () {
+                uni.showToast({
+                  title: '保存成功',
+                  duration: 2000
+                });
+              }
     	      });
     	      });
     	    //#endif
     	    //#endif
     	  } 
     	  } 
     	},this);
     	},this);
     },
     },
+    getImage(){
+      if(this.type2d == false){
+        uni.canvasToTempFilePath({
+          canvasId: this.cid,
+          success: res=>{
+            this.emitMsg({name: 'getImage', params: {type:"getImage", base64: res.tempFilePath}});
+          }
+        },this);
+      }else{
+        const query = uni.createSelectorQuery().in(this)
+        query
+          .select('#' + this.cid)
+          .fields({ node: true, size: true })
+          .exec(res => {
+            if (res[0]) {
+              const canvas = res[0].node;
+              this.emitMsg({name: 'getImage', params: {type:"getImage", base64: canvas.toDataURL('image/png')}});
+            }
+          });
+      }
+    },
     // #ifndef APP-VUE || H5
     // #ifndef APP-VUE || H5
     _newChart(cid) {
     _newChart(cid) {
       if (this.mixinDatacomLoading == true) {
       if (this.mixinDatacomLoading == true) {
         return;
         return;
       }
       }
       this.showchart = true;
       this.showchart = true;
-      cfu.instance[cid] = new uChartsMp(cfu.option[cid]);
+      cfu.instance[cid] = new uCharts(cfu.option[cid]);
       cfu.instance[cid].addEventListener('renderComplete', () => {
       cfu.instance[cid].addEventListener('renderComplete', () => {
         this.emitMsg({name: 'complete', params: {type:"complete", complete: true, id: cid}});
         this.emitMsg({name: 'complete', params: {type:"complete", complete: true, id: cid}});
         cfu.instance[cid].delEventListener('renderComplete')
         cfu.instance[cid].delEventListener('renderComplete')
@@ -1118,7 +1157,7 @@ export default {
     _touchStart(e) {
     _touchStart(e) {
       let cid = this.cid
       let cid = this.cid
       lastMoveTime=Date.now();
       lastMoveTime=Date.now();
-      if(cfu.option[cid].enableScroll === true){
+      if(cfu.option[cid].enableScroll === true && e.touches.length == 1){
         cfu.instance[cid].scrollStart(e);
         cfu.instance[cid].scrollStart(e);
       }
       }
       this.emitMsg({name:'getTouchStart', params:{type:"touchStart", event:e.changedTouches[0], id:cid}});
       this.emitMsg({name:'getTouchStart', params:{type:"touchStart", event:e.changedTouches[0], id:cid}});
@@ -1127,19 +1166,23 @@ export default {
       let cid = this.cid
       let cid = this.cid
       let currMoveTime = Date.now();
       let currMoveTime = Date.now();
       let duration = currMoveTime - lastMoveTime;
       let duration = currMoveTime - lastMoveTime;
-      if (duration < Math.floor(1000 / 60)) return;//每秒60帧
+      let touchMoveLimit = cfu.option[cid].touchMoveLimit || 24;
+      if (duration < Math.floor(1000 / touchMoveLimit)) return;//每秒60帧
       lastMoveTime = currMoveTime;
       lastMoveTime = currMoveTime;
-      if(cfu.option[cid].enableScroll === true){
+      if(cfu.option[cid].enableScroll === true && e.changedTouches.length == 1){
         cfu.instance[cid].scroll(e);
         cfu.instance[cid].scroll(e);
       }
       }
-      this.emitMsg({name: 'getTouchMove', params: {type:"touchMove", event:e.changedTouches[0], id: cid}});
       if(this.ontap === true && cfu.option[cid].enableScroll === false && this.onmovetip === true){
       if(this.ontap === true && cfu.option[cid].enableScroll === false && this.onmovetip === true){
         this._tap(e,true)
         this._tap(e,true)
       }
       }
+      if(this.ontouch === true && cfu.option[cid].enableScroll === true && this.onzoom === true && e.changedTouches.length == 2){
+        cfu.instance[cid].dobuleZoom(e);
+      }
+      this.emitMsg({name: 'getTouchMove', params: {type:"touchMove", event:e.changedTouches[0], id: cid}});
     },
     },
     _touchEnd(e) {
     _touchEnd(e) {
       let cid = this.cid
       let cid = this.cid
-      if(cfu.option[cid].enableScroll === true){
+      if(cfu.option[cid].enableScroll === true && e.touches.length == 0){
         cfu.instance[cid].scrollEnd(e);
         cfu.instance[cid].scrollEnd(e);
       }
       }
       this.emitMsg({name:'getTouchEnd', params:{type:"touchEnd", event:e.changedTouches[0], id:cid}});
       this.emitMsg({name:'getTouchEnd', params:{type:"touchEnd", event:e.changedTouches[0], id:cid}});
@@ -1189,7 +1232,7 @@ function rddeepCloneAssign(origin = {}, ...args) {
 
 
 function rdformatterAssign(args,formatter) {
 function rdformatterAssign(args,formatter) {
   for (let key in args) {
   for (let key in args) {
-    if(args[key] !== null && typeof args[key] === 'object'){
+    if(args.hasOwnProperty(key) && args[key] !== null && typeof args[key] === 'object'){
       rdformatterAssign(args[key],formatter)
       rdformatterAssign(args[key],formatter)
     }else if(key === 'format' && typeof args[key] === 'string'){
     }else if(key === 'format' && typeof args[key] === 'string'){
       args['formatter'] = formatter[args[key]] ? formatter[args[key]] : undefined;
       args['formatter'] = formatter[args[key]] ? formatter[args[key]] : undefined;
@@ -1215,7 +1258,7 @@ export default {
     // #endif
     // #endif
     setTimeout(()=>{
     setTimeout(()=>{
       if(this.rid === null){
       if(this.rid === null){
-        this.$ownerInstance.callMethod('getRenderType')
+        this.$ownerInstance && this.$ownerInstance.callMethod('getRenderType')
       }
       }
     },200)
     },200)
   },
   },
@@ -1230,7 +1273,7 @@ export default {
     ecinit(newVal, oldVal, owner, instance){
     ecinit(newVal, oldVal, owner, instance){
       let cid = JSON.stringify(newVal.id)
       let cid = JSON.stringify(newVal.id)
       this.rid = cid
       this.rid = cid
-      that[cid] = this.$ownerInstance
+      that[cid] = this.$ownerInstance || instance
       let eopts = JSON.parse(JSON.stringify(newVal))
       let eopts = JSON.parse(JSON.stringify(newVal))
       let type = eopts.type;
       let type = eopts.type;
       //载入并覆盖默认配置
       //载入并覆盖默认配置
@@ -1240,19 +1283,22 @@ export default {
         cfe.option[cid] = rddeepCloneAssign({}, eopts);
         cfe.option[cid] = rddeepCloneAssign({}, eopts);
       }
       }
       let newData = eopts.chartData;
       let newData = eopts.chartData;
-      //挂载categories和series
-      if(cfe.option[cid].xAxis && cfe.option[cid].xAxis.type && cfe.option[cid].xAxis.type === 'category'){
-        cfe.option[cid].xAxis.data = newData.categories
-      }
-      if(cfe.option[cid].yAxis && cfe.option[cid].yAxis.type && cfe.option[cid].yAxis.type === 'category'){
-        cfe.option[cid].yAxis.data = newData.categories
-      }
-      cfe.option[cid].series = []
-      for (var i = 0; i < newData.series.length; i++) {
-        cfe.option[cid].seriesTemplate = cfe.option[cid].seriesTemplate ? cfe.option[cid].seriesTemplate : {}
-        let Template = rddeepCloneAssign({},cfe.option[cid].seriesTemplate,newData.series[i])
-        cfe.option[cid].series.push(Template)
+      if(newData){
+        //挂载categories和series
+        if(cfe.option[cid].xAxis && cfe.option[cid].xAxis.type && cfe.option[cid].xAxis.type === 'category'){
+          cfe.option[cid].xAxis.data = newData.categories
+        }
+        if(cfe.option[cid].yAxis && cfe.option[cid].yAxis.type && cfe.option[cid].yAxis.type === 'category'){
+          cfe.option[cid].yAxis.data = newData.categories
+        }
+        cfe.option[cid].series = []
+        for (var i = 0; i < newData.series.length; i++) {
+          cfe.option[cid].seriesTemplate = cfe.option[cid].seriesTemplate ? cfe.option[cid].seriesTemplate : {}
+          let Template = rddeepCloneAssign({},cfe.option[cid].seriesTemplate,newData.series[i])
+          cfe.option[cid].series.push(Template)
+        }
       }
       }
+      
       if (typeof window.echarts === 'object') {
       if (typeof window.echarts === 'object') {
           this.newEChart()
           this.newEChart()
       }else{
       }else{
@@ -1261,9 +1307,9 @@ export default {
         script.src = './uni_modules/qiun-data-charts/static/app-plus/echarts.min.js'
         script.src = './uni_modules/qiun-data-charts/static/app-plus/echarts.min.js'
         // #endif
         // #endif
         // #ifdef H5
         // #ifdef H5
-        const rooturl = window.location.origin 
-        const directory = instance.getDataset().directory
-        script.src = rooturl + directory + 'uni_modules/qiun-data-charts/static/h5/echarts.min.js'
+        const { origin, pathname } = window.location
+        const rooturl = origin + pathname
+        script.src = rooturl + 'uni_modules/qiun-data-charts/static/h5/echarts.min.js'
         // #endif
         // #endif
         script.onload = this.newEChart
         script.onload = this.newEChart
         document.head.appendChild(script)
         document.head.appendChild(script)
@@ -1286,6 +1332,10 @@ export default {
             }))
             }))
             that[cid].callMethod('emitMsg',{name:"getIndex", params:{type:"getIndex", event:event, currentIndex:resdata.dataIndex, value:resdata.data, seriesName: resdata.seriesName,id:cid}})
             that[cid].callMethod('emitMsg',{name:"getIndex", params:{type:"getIndex", event:event, currentIndex:resdata.dataIndex, value:resdata.data, seriesName: resdata.seriesName,id:cid}})
           })
           })
+          // 增加ECharts的highlight消息,实现按下移动返回索引功能。add by onefish 创建于 2021-12-11 09:50
+          cfe.instance[cid].on('highlight', resdata => {
+            that[cid].callMethod('emitMsg',{name:"getHighlight", params:{type:"highlight", res:resdata, id:cid}})
+          })
         }
         }
         this.updataEChart(cid,cfe.option[cid])
         this.updataEChart(cid,cfe.option[cid])
       }else{
       }else{
@@ -1344,9 +1394,12 @@ export default {
       if(JSON.stringify(newVal) == JSON.stringify(oldVal)){
       if(JSON.stringify(newVal) == JSON.stringify(oldVal)){
         return;
         return;
       }
       }
+      if(!newVal.canvasId){
+        return;
+      }
       let cid = JSON.parse(JSON.stringify(newVal.canvasId))
       let cid = JSON.parse(JSON.stringify(newVal.canvasId))
       this.rid = cid
       this.rid = cid
-      that[cid] = this.$ownerInstance
+      that[cid] = this.$ownerInstance || instance
       cfu.option[cid] = JSON.parse(JSON.stringify(newVal))
       cfu.option[cid] = JSON.parse(JSON.stringify(newVal))
       cfu.option[cid] = rdformatterAssign(cfu.option[cid],cfu.formatter)
       cfu.option[cid] = rdformatterAssign(cfu.option[cid],cfu.formatter)
       let canvasdom = document.getElementById(cid)
       let canvasdom = document.getElementById(cid)
@@ -1442,6 +1495,7 @@ export default {
       }else{//mouse的事件
       }else{//mouse的事件
         tmpe = { x: e.clientX - rchartdom.left, y:e.clientY - rchartdom.top + rootdom.top}
         tmpe = { x: e.clientX - rchartdom.left, y:e.clientY - rchartdom.top + rootdom.top}
       }
       }
+      e.changedTouches = [];
       e.changedTouches.unshift(tmpe)
       e.changedTouches.unshift(tmpe)
       currentIndex=cfu.instance[cid].getCurrentDataIndex(e)
       currentIndex=cfu.instance[cid].getCurrentDataIndex(e)
       legendIndex=cfu.instance[cid].getLegendDataIndex(e)
       legendIndex=cfu.instance[cid].getLegendDataIndex(e)
@@ -1457,15 +1511,18 @@ export default {
       let cid = this.rid
       let cid = this.rid
       let ontouch = cfu.option[cid].ontouch
       let ontouch = cfu.option[cid].ontouch
       if(ontouch == false) return;
       if(ontouch == false) return;
-      cfu.instance[cid].scrollStart(e)
+      if(cfu.option[cid].enableScroll === true && e.touches.length == 1){
+        cfu.instance[cid].scrollStart(e);
+      }
       that[cid].callMethod('emitMsg',{name:"getTouchStart",params:{type:"touchStart",event:e.changedTouches[0],id:cid}})
       that[cid].callMethod('emitMsg',{name:"getTouchStart",params:{type:"touchStart",event:e.changedTouches[0],id:cid}})
     },
     },
     touchMove(e) {
     touchMove(e) {
       let cid = this.rid
       let cid = this.rid
       let ontouch = cfu.option[cid].ontouch
       let ontouch = cfu.option[cid].ontouch
       if(ontouch == false) return;
       if(ontouch == false) return;
-      cfu.instance[cid].scroll(e)
-      that[cid].callMethod('emitMsg',{name:"getTouchMove",params:{type:"touchMove",event:e.changedTouches[0],id:cid}})
+      if(cfu.option[cid].enableScroll === true && e.changedTouches.length == 1){
+        cfu.instance[cid].scroll(e);
+      }
       if(cfu.option[cid].ontap === true && cfu.option[cid].enableScroll === false && cfu.option[cid].onmovetip === true){
       if(cfu.option[cid].ontap === true && cfu.option[cid].enableScroll === false && cfu.option[cid].onmovetip === true){
         let rchartdom = document.getElementById('UC'+cid).getBoundingClientRect()
         let rchartdom = document.getElementById('UC'+cid).getBoundingClientRect()
         let tmpe = { x: e.changedTouches[0].clientX - rchartdom.left, y:e.changedTouches[0].clientY - rchartdom.top + rootdom.top}
         let tmpe = { x: e.changedTouches[0].clientX - rchartdom.left, y:e.changedTouches[0].clientY - rchartdom.top + rootdom.top}
@@ -1474,12 +1531,18 @@ export default {
           this.showTooltip(e,cid)
           this.showTooltip(e,cid)
         }
         }
       }
       }
+      if(ontouch === true && cfu.option[cid].enableScroll === true && cfu.option[cid].onzoom === true && e.changedTouches.length == 2){
+        cfu.instance[cid].dobuleZoom(e);
+      }
+      that[cid].callMethod('emitMsg',{name:"getTouchMove",params:{type:"touchMove",event:e.changedTouches[0],id:cid}})
     },
     },
     touchEnd(e) {
     touchEnd(e) {
       let cid = this.rid
       let cid = this.rid
       let ontouch = cfu.option[cid].ontouch
       let ontouch = cfu.option[cid].ontouch
       if(ontouch == false) return;
       if(ontouch == false) return;
-      cfu.instance[cid].scrollEnd(e)
+      if(cfu.option[cid].enableScroll === true && e.touches.length == 0){
+        cfu.instance[cid].scrollEnd(e);
+      }
       that[cid].callMethod('emitMsg',{name:"getTouchEnd",params:{type:"touchEnd",event:e.changedTouches[0],id:cid}})
       that[cid].callMethod('emitMsg',{name:"getTouchEnd",params:{type:"touchEnd",event:e.changedTouches[0],id:cid}})
     },
     },
     mouseDown(e) {
     mouseDown(e) {
@@ -1489,6 +1552,7 @@ export default {
       let rchartdom = document.getElementById('UC'+cid).getBoundingClientRect()
       let rchartdom = document.getElementById('UC'+cid).getBoundingClientRect()
       let tmpe = {}
       let tmpe = {}
       tmpe = { x: e.clientX - rchartdom.left, y:e.clientY - rchartdom.top + rootdom.top}
       tmpe = { x: e.clientX - rchartdom.left, y:e.clientY - rchartdom.top + rootdom.top}
+      e.changedTouches = [];
       e.changedTouches.unshift(tmpe)
       e.changedTouches.unshift(tmpe)
       cfu.instance[cid].scrollStart(e)
       cfu.instance[cid].scrollStart(e)
       cfu.option[cid].mousedown=true;
       cfu.option[cid].mousedown=true;
@@ -1502,6 +1566,7 @@ export default {
       let rchartdom = document.getElementById('UC'+cid).getBoundingClientRect()
       let rchartdom = document.getElementById('UC'+cid).getBoundingClientRect()
       let tmpe = {}
       let tmpe = {}
       tmpe = { x: e.clientX - rchartdom.left, y:e.clientY - rchartdom.top + rootdom.top}
       tmpe = { x: e.clientX - rchartdom.left, y:e.clientY - rchartdom.top + rootdom.top}
+      e.changedTouches = [];
       e.changedTouches.unshift(tmpe)
       e.changedTouches.unshift(tmpe)
       if(cfu.option[cid].mousedown){
       if(cfu.option[cid].mousedown){
         cfu.instance[cid].scroll(e)
         cfu.instance[cid].scroll(e)
@@ -1519,6 +1584,7 @@ export default {
       let rchartdom = document.getElementById('UC'+cid).getBoundingClientRect()
       let rchartdom = document.getElementById('UC'+cid).getBoundingClientRect()
       let tmpe = {}
       let tmpe = {}
       tmpe = { x: e.clientX - rchartdom.left, y:e.clientY - rchartdom.top + rootdom.top}
       tmpe = { x: e.clientX - rchartdom.left, y:e.clientY - rchartdom.top + rootdom.top}
+      e.changedTouches = [];
       e.changedTouches.unshift(tmpe)
       e.changedTouches.unshift(tmpe)
       cfu.instance[cid].scrollEnd(e)
       cfu.instance[cid].scrollEnd(e)
       cfu.option[cid].mousedown=false;
       cfu.option[cid].mousedown=false;

+ 4 - 2
uni_modules/qiun-data-charts/js_sdk/u-charts/config-echarts.js

@@ -21,7 +21,7 @@
 // 主题颜色配置:如每个图表类型需要不同主题,请在对应图表类型上更改color属性
 // 主题颜色配置:如每个图表类型需要不同主题,请在对应图表类型上更改color属性
 const color = ['#1890FF', '#91CB74', '#FAC858', '#EE6666', '#73C0DE', '#3CA272', '#FC8452', '#9A60B4', '#ea7ccc'];
 const color = ['#1890FF', '#91CB74', '#FAC858', '#EE6666', '#73C0DE', '#3CA272', '#FC8452', '#9A60B4', '#ea7ccc'];
 
 
-module.exports = {
+const cfe = {
   //demotype为自定义图表类型
   //demotype为自定义图表类型
 	"type": ["pie", "ring", "rose", "funnel", "line", "column", "area", "radar", "gauge","candle","demotype"],
 	"type": ["pie", "ring", "rose", "funnel", "line", "column", "area", "radar", "gauge","candle","demotype"],
   //增加自定义图表类型,如果需要categories,请在这里加入您的图表类型例如最后的"demotype"
   //增加自定义图表类型,如果需要categories,请在这里加入您的图表类型例如最后的"demotype"
@@ -324,7 +324,7 @@ module.exports = {
 			"data": [],
 			"data": [],
 			"radius": "55%",
 			"radius": "55%",
 			"center": ['50%', '50%'],
 			"center": ['50%', '50%'],
-			"rosetype": 'area',
+			"roseType": 'area',
 		},
 		},
 	},
 	},
 	"funnel": {
 	"funnel": {
@@ -418,3 +418,5 @@ module.exports = {
 		},
 		},
 	}
 	}
 }
 }
+
+export default cfe;

+ 290 - 325
uni_modules/qiun-data-charts/js_sdk/u-charts/config-ucharts.js

@@ -20,156 +20,85 @@
 const color = ['#1890FF', '#91CB74', '#FAC858', '#EE6666', '#73C0DE', '#3CA272', '#FC8452', '#9A60B4', '#ea7ccc'];
 const color = ['#1890FF', '#91CB74', '#FAC858', '#EE6666', '#73C0DE', '#3CA272', '#FC8452', '#9A60B4', '#ea7ccc'];
 
 
 //事件转换函数,主要用作格式化x轴为时间轴,根据需求自行修改
 //事件转换函数,主要用作格式化x轴为时间轴,根据需求自行修改
-const formatDateTime = (timeStamp, returnType) => {
-	var date = new Date();
-	date.setTime(timeStamp * 1000);
-	var y = date.getFullYear();
-	var m = date.getMonth() + 1;
-	m = m < 10 ? ('0' + m) : m;
-	var d = date.getDate();
-	d = d < 10 ? ('0' + d) : d;
-	var h = date.getHours();
-	h = h < 10 ? ('0' + h) : h;
-	var minute = date.getMinutes();
-	var second = date.getSeconds();
-	minute = minute < 10 ? ('0' + minute) : minute;
-	second = second < 10 ? ('0' + second) : second;
-	if (returnType == 'full') {
-		return y + '-' + m + '-' + d + ' ' + h + ':' + minute + ':' + second;
-	}
-	if (returnType == 'y-m-d') {
-		return y + '-' + m + '-' + d;
-	}
-	if (returnType == 'h:m') {
-		return h + ':' + minute;
-	}
-	if (returnType == 'h:m:s') {
-		return h + ':' + minute + ':' + second;
-	}
-	return [y, m, d, h, minute, second];
+const formatDateTime = (timeStamp, returnType)=>{
+  var date = new Date();
+  date.setTime(timeStamp * 1000);
+  var y = date.getFullYear();
+  var m = date.getMonth() + 1;
+  m = m < 10 ? ('0' + m) : m;
+  var d = date.getDate();
+  d = d < 10 ? ('0' + d) : d;
+  var h = date.getHours();
+  h = h < 10 ? ('0' + h) : h;
+  var minute = date.getMinutes();
+  var second = date.getSeconds();
+  minute = minute < 10 ? ('0' + minute) : minute;
+  second = second < 10 ? ('0' + second) : second;
+  if(returnType == 'full'){return y + '-' + m + '-' + d + ' '+ h +':' + minute + ':' + second;}
+  if(returnType == 'y-m-d'){return y + '-' + m + '-' + d;}
+  if(returnType == 'h:m'){return  h +':' + minute;}
+  if(returnType == 'h:m:s'){return  h +':' + minute +':' + second;}
+  return [y, m, d, h, minute, second];
 }
 }
 
 
-module.exports = {
-	//demotype为自定义图表类型,一般不需要自定义图表类型,只需要改根节点上对应的类型即可
-	"type": ["pie", "ring", "rose", "word", "funnel", "map", "arcbar", "line", "column", "bar", "area", "radar",
-		"gauge", "candle", "mix", "tline", "tarea", "scatter", "bubble", "demotype"
-	],
-	"range": ["饼状图", "圆环图", "玫瑰图", "词云图", "漏斗图", "地图", "圆弧进度条", "折线图", "柱状图", "条状图", "区域图", "雷达图", "仪表盘", "K线图",
-		"混合图", "时间轴折线", "时间轴区域", "散点图", "气泡图", "自定义类型"
-	],
-	//增加自定义图表类型,如果需要categories,请在这里加入您的图表类型,例如最后的"demotype"
-	//自定义类型时需要注意"tline","tarea","scatter","bubble"等时间轴(矢量x轴)类图表,没有categories,不需要加入categories
-	"categories": ["line", "column", "bar", "area", "radar", "gauge", "candle", "mix", "demotype"],
-	//instance为实例变量承载属性,不要删除
-	"instance": {},
-	//option为opts及eopts承载属性,不要删除
-	"option": {},
-	//下面是自定义format配置,因除H5端外的其他端无法通过props传递函数,只能通过此属性对应下标的方式来替换
-	"formatter": {
-		"yAxisDemo1": function(val) {
-			return val + '元'
-		},
-		"yAxisDemo2": function(val) {
-			return val.toFixed(2)
-		},
-		"xAxisDemo1": function(val) {
-			return val + '年'
-		},
-		"xAxisDemo2": function(val) {
-			return formatDateTime(val, 'h:m')
-		},
-		"seriesDemo1": function(val) {
-			return val + '元'
-		},
-		"tooltipDemo1": function(item, category, index, opts) {
-			if (index == 0) {
-				return '随便用' + item.data + '年'
-			} else {
-				return '其他我没改' + item.data + '天'
-			}
-		},
-		"pieDemo": function(val, index, series) {
-			if (index !== undefined) {
-				return series[index].name + ':' + series[index].data + '元'
-			}
-		},
-		tooltipDemo1: function(item, category, index, opts) {
-			return item.data + '度'
-		},
-	},
-	//这里演示了自定义您的图表类型的option,可以随意命名,之后在组件上 type="demotype" 后,组件会调用这个花括号里的option,如果组件上还存在opts参数,会将demotype与opts中option合并后渲染图表。
-	"demotype": {
-		//我这里把曲线图当做了自定义图表类型,您可以根据需要随意指定类型或配置
-		"type": "line",
-		"color": ["#EF7A2D"],
-		"padding": [15, 10, 10, 15],
-		"dataLabel": false,
-		"dataPointShapeType": "hollow",
-		 "tapLegend": true,
-		 "animation": false,
-		"xAxis": {
-			"disableGrid": true,
-			"fontColor": '#666666',
-			"axisLineColor": "#CCCCCC",
-			"rotateLabel": true,
-			"fontSize": 12,
-		},
-		"yAxis": {
-			"disabled": false,
-			"gridType": "solid",
-			"dashLength": 2,
-			"gridColor": "#CCCCCC",
-			"showTitle": true,
-			"splitNumber": 4,
-			"data": [{
-				"type": "value",
-				"position": "left",
-				"disabled": false,
-				"axisLine": false,
-				"axisLineColor": "#CCCCCC",
-				"calibration": false,
-				"fontColor": "#666666",
-				"fontSize": 12,
-				"textAlign": "right",
-				"title": "度",
-				"titleFontSize": 12,
-				"titleOffsetY": -5,
-				"titleOffsetX": -10,
-				"titleFontColor": "#666666",
-				"min": 0,
-				"max": 80,
-				"tofix": null,
-				"unit": "",
-				"format": ""
-			}]
-		},
-		"legend": {
-		        "show": false,
-		        "position": "bottom",
-		        "float": "center",
-		        "padding": 10,
-		        "margin": 10,
-		        "backgroundColor": "#cccccc",
-		        "borderColor": "#1296DB",
-		        "borderWidth": 0.5,
-		        "fontSize": 14,
-		        "fontColor": "#666666",
-		        "lineHeight": 11,
-		        "hiddenColor": "#CECECE",
-		        "itemGap": 10,
-		    },
-		"extra": {
-			"line": {
-				"type": "curve",
-				"width": 2
-			},
-		}
-	},
-	//下面是自定义配置,请添加项目所需的通用配置
-	"pie": {
+const cfu = {
+  //demotype为自定义图表类型,一般不需要自定义图表类型,只需要改根节点上对应的类型即可
+	"type":["pie","ring","rose","word","funnel","map","arcbar","line","column","mount","bar","area","radar","gauge","candle","mix","tline","tarea","scatter","bubble","demotype"],
+	"range":["饼状图","圆环图","玫瑰图","词云图","漏斗图","地图","圆弧进度条","折线图","柱状图","山峰图","条状图","区域图","雷达图","仪表盘","K线图","混合图","时间轴折线","时间轴区域","散点图","气泡图","自定义类型"],
+  //增加自定义图表类型,如果需要categories,请在这里加入您的图表类型,例如最后的"demotype"
+  //自定义类型时需要注意"tline","tarea","scatter","bubble"等时间轴(矢量x轴)类图表,没有categories,不需要加入categories
+	"categories":["line","column","mount","bar","area","radar","gauge","candle","mix","demotype"],
+  //instance为实例变量承载属性,不要删除
+  "instance":{},
+  //option为opts及eopts承载属性,不要删除
+  "option":{},
+  //下面是自定义format配置,因除H5端外的其他端无法通过props传递函数,只能通过此属性对应下标的方式来替换
+  "formatter":{
+    "yAxisDemo1":function(val, index, opts){return val+'元'},
+    "yAxisDemo2":function(val, index, opts){return val.toFixed(2)},
+    "xAxisDemo1":function(val, index, opts){return val+'元';},
+    "xAxisDemo2":function(val, index, opts){return formatDateTime(val,'h:m')},
+    "seriesDemo1":function(val, index, series, opts){return val+'元'},
+    "tooltipDemo1":function(item, category, index, opts){
+      if(index==0){
+      	return ''+item.data+'元'
+      }else{
+      	return ''+item.data+'元'
+      }
+    },
+    "pieDemo":function(val, index, series, opts){
+      if(index !== undefined){
+        return series[index].name+':'+series[index].data+'元'
+      }
+    },
+  },
+  //这里演示了自定义您的图表类型的option,可以随意命名,之后在组件上 type="demotype" 后,组件会调用这个花括号里的option,如果组件上还存在opts参数,会将demotype与opts中option合并后渲染图表。
+  "demotype":{
+    //我这里把曲线图当做了自定义图表类型,您可以根据需要随意指定类型或配置
+    "type": "line",
+    "color": color,
+    "padding": [15,10,0,15],
+    "xAxis": {
+      "disableGrid": true,
+    },
+    "yAxis": {
+      "gridType": "dash",
+      "dashLength": 2,
+    },
+    "legend": {
+    },
+    "extra": {
+    	"line": {
+    		"type": "curve",
+    		"width": 2
+    	},
+    }
+  },
+  //下面是自定义配置,请添加项目所需的通用配置
+	"pie":{
 		"type": "pie",
 		"type": "pie",
-		"color": color,
-		"padding": [5, 5, 5, 5],
+    "color": color,
+		"padding": [5,5,5,5],
 		"extra": {
 		"extra": {
 			"pie": {
 			"pie": {
 				"activeOpacity": 0.5,
 				"activeOpacity": 0.5,
@@ -182,16 +111,16 @@ module.exports = {
 			},
 			},
 		}
 		}
 	},
 	},
-	"ring": {
+	"ring":{
 		"type": "ring",
 		"type": "ring",
-		"color": color,
-		"padding": [5, 5, 5, 5],
+    "color": color,
+		"padding": [5,5,5,5],
 		"rotate": false,
 		"rotate": false,
 		"dataLabel": true,
 		"dataLabel": true,
 		"legend": {
 		"legend": {
 			"show": true,
 			"show": true,
 			"position": "right",
 			"position": "right",
-			"lineHeight": 25,
+      "lineHeight": 25,
 		},
 		},
 		"title": {
 		"title": {
 			"name": "收益率",
 			"name": "收益率",
@@ -205,7 +134,7 @@ module.exports = {
 		},
 		},
 		"extra": {
 		"extra": {
 			"ring": {
 			"ring": {
-				"ringWidth": 30,
+				"ringWidth":30,
 				"activeOpacity": 0.5,
 				"activeOpacity": 0.5,
 				"activeRadius": 10,
 				"activeRadius": 10,
 				"offsetAngle": 0,
 				"offsetAngle": 0,
@@ -216,14 +145,14 @@ module.exports = {
 			},
 			},
 		},
 		},
 	},
 	},
-	"rose": {
+	"rose":{
 		"type": "rose",
 		"type": "rose",
-		"color": color,
-		"padding": [5, 5, 5, 5],
+    "color": color,
+		"padding": [5,5,5,5],
 		"legend": {
 		"legend": {
 			"show": true,
 			"show": true,
 			"position": "left",
 			"position": "left",
-			"lineHeight": 25,
+      "lineHeight": 25,
 		},
 		},
 		"extra": {
 		"extra": {
 			"rose": {
 			"rose": {
@@ -239,9 +168,9 @@ module.exports = {
 			},
 			},
 		}
 		}
 	},
 	},
-	"word": {
+	"word":{
 		"type": "word",
 		"type": "word",
-		"color": color,
+    "color": color,
 		"extra": {
 		"extra": {
 			"word": {
 			"word": {
 				"type": "normal",
 				"type": "normal",
@@ -249,10 +178,10 @@ module.exports = {
 			}
 			}
 		}
 		}
 	},
 	},
-	"funnel": {
+	"funnel":{
 		"type": "funnel",
 		"type": "funnel",
-		"color": color,
-		"padding": [15, 15, 0, 15],
+    "color": color,
+		"padding": [15,15,0,15],
 		"extra": {
 		"extra": {
 			"funnel": {
 			"funnel": {
 				"activeOpacity": 0.3,
 				"activeOpacity": 0.3,
@@ -265,11 +194,11 @@ module.exports = {
 			},
 			},
 		}
 		}
 	},
 	},
-	"map": {
+	"map":{
 		"type": "map",
 		"type": "map",
-		"color": color,
-		"padding": [0, 0, 0, 0],
-		"dataLabel": true,
+    "color": color,
+		"padding": [0,0,0,0],
+    "dataLabel": true,
 		"extra": {
 		"extra": {
 			"map": {
 			"map": {
 				"border": true,
 				"border": true,
@@ -282,9 +211,9 @@ module.exports = {
 			},
 			},
 		}
 		}
 	},
 	},
-	"arcbar": {
+	"arcbar":{
 		"type": "arcbar",
 		"type": "arcbar",
-		"color": color,
+    "color": color,
 		"title": {
 		"title": {
 			"name": "百分比",
 			"name": "百分比",
 			"fontSize": 25,
 			"fontSize": 25,
@@ -306,135 +235,161 @@ module.exports = {
 			}
 			}
 		}
 		}
 	},
 	},
-	"line": {
+	"line":{
 		"type": "line",
 		"type": "line",
-		"color": color,
-		"padding": [15, 10, 0, 15],
+    "color": color,
+		"padding": [15,10,0,15],
 		"xAxis": {
 		"xAxis": {
-			"disableGrid": true,
+      "disableGrid": true,
 		},
 		},
 		"yAxis": {
 		"yAxis": {
-			"gridType": "dash",
-			"dashLength": 2,
+      "gridType": "dash",
+      "dashLength": 2,
 		},
 		},
-		"legend": {},
-		"extra": {
-			"line": {
-				"type": "straight",
-				"width": 2
-			},
-		}
-	},
-	"tline": {
-		"type": "line",
-		"color": color,
-		"padding": [15, 10, 0, 15],
-		"xAxis": {
-			"disableGrid": false,
-			"boundaryGap": "justify",
-		},
-		"yAxis": {
-			"gridType": "dash",
-			"dashLength": 2,
-			"data": [{
-				"min": 0,
-				"max": 80
-			}]
+		"legend": {
 		},
 		},
-		"legend": {},
 		"extra": {
 		"extra": {
 			"line": {
 			"line": {
-				"type": "curve",
+				"type": "straight",
 				"width": 2
 				"width": 2
 			},
 			},
 		}
 		}
 	},
 	},
-	"tarea": {
-		"type": "area",
-		"color": color,
-		"padding": [15, 10, 0, 15],
-		"xAxis": {
-			"disableGrid": true,
-			"boundaryGap": "justify",
-		},
-		"yAxis": {
-			"gridType": "dash",
-			"dashLength": 2,
-			"data": [{
-				"min": 0,
-				"max": 80
-			}]
-		},
-		"legend": {},
-		"extra": {
-			"area": {
-				"type": "curve",
-				"opacity": 0.2,
-				"addLine": true,
-				"width": 2,
-				"gradient": true
-			},
-		}
-	},
-	"column": {
+  "tline":{
+  	"type": "line",
+    "color": color,
+  	"padding": [15,10,0,15],
+  	"xAxis": {
+      "disableGrid": false,
+      "boundaryGap":"justify",
+  	},
+  	"yAxis": {
+      "gridType": "dash",
+      "dashLength": 2,
+      "data":[
+        {
+          "min":0,
+          "max":80
+        }
+      ]
+  	},
+  	"legend": {
+  	},
+  	"extra": {
+  		"line": {
+  			"type": "curve",
+  			"width": 2
+  		},
+  	}
+  },
+  "tarea":{
+  	"type": "area",
+    "color": color,
+  	"padding": [15,10,0,15],
+  	"xAxis": {
+      "disableGrid": true,
+      "boundaryGap":"justify",
+  	},
+  	"yAxis": {
+      "gridType": "dash",
+      "dashLength": 2,
+      "data":[
+        {
+          "min":0,
+          "max":80
+        }
+      ]
+  	},
+  	"legend": {
+  	},
+  	"extra": {
+  		"area": {
+  			"type": "curve",
+  			"opacity": 0.2,
+  			"addLine": true,
+  			"width": 2,
+  			"gradient": true
+  		},
+  	}
+  },
+	"column":{
 		"type": "column",
 		"type": "column",
-		"color": color,
-		"padding": [15, 15, 0, 5],
+    "color": color,
+		"padding": [15,15,0,5],
 		"xAxis": {
 		"xAxis": {
-			"disableGrid": true,
+      "disableGrid": true,
 		},
 		},
 		"yAxis": {
 		"yAxis": {
-			"data": [{
-				"min": 0
-			}]
+      "data":[{"min":0}]
 		},
 		},
-		"legend": {},
-		"extra": {
-			"column": {
-				"type": "group",
-				"width": 30,
-				"meterBorde": 1,
-				"meterFillColor": "#FFFFFF",
-				"activeBgColor": "#000000",
-				"activeBgOpacity": 0.08
-			},
-		}
-	},
-	"bar": {
-		"type": "bar",
-		"color": color,
-		"padding": [15, 30, 0, 5],
-		"xAxis": {
-			"boundaryGap": "justify",
-			"disableGrid": false,
-			"min": 0,
-			"axisLine": false
+		"legend": {
 		},
 		},
-		"yAxis": {},
-		"legend": {},
 		"extra": {
 		"extra": {
-			"bar": {
+			"column": {
 				"type": "group",
 				"type": "group",
 				"width": 30,
 				"width": 30,
-				"meterBorde": 1,
-				"meterFillColor": "#FFFFFF",
 				"activeBgColor": "#000000",
 				"activeBgColor": "#000000",
 				"activeBgOpacity": 0.08
 				"activeBgOpacity": 0.08
 			},
 			},
 		}
 		}
 	},
 	},
-	"area": {
+  "mount":{
+  	"type": "mount",
+    "color": color,
+  	"padding": [15,15,0,5],
+  	"xAxis": {
+      "disableGrid": true,
+  	},
+  	"yAxis": {
+      "data":[{"min":0}]
+  	},
+  	"legend": {
+  	},
+  	"extra": {
+  		"mount": {
+  			"type": "mount",
+  			"widthRatio": 1.5,
+  		},
+  	}
+  },
+  "bar":{
+  	"type": "bar",
+    "color": color,
+  	"padding": [15,30,0,5],
+  	"xAxis": {
+      "boundaryGap":"justify",
+      "disableGrid":false,
+      "min":0,
+      "axisLine":false
+  	},
+  	"yAxis": {
+  	},
+  	"legend": {
+  	},
+  	"extra": {
+  		"bar": {
+  			"type": "group",
+  			"width": 30,
+  			"meterBorde": 1,
+  			"meterFillColor": "#FFFFFF",
+  			"activeBgColor": "#000000",
+  			"activeBgOpacity": 0.08
+  		},
+  	}
+  },
+	"area":{
 		"type": "area",
 		"type": "area",
 		"color": color,
 		"color": color,
-		"padding": [15, 15, 0, 15],
+		"padding": [15,15,0,15],
 		"xAxis": {
 		"xAxis": {
-			"disableGrid": true,
+      "disableGrid": true,
 		},
 		},
 		"yAxis": {
 		"yAxis": {
-			"gridType": "dash",
-			"dashLength": 2,
+      "gridType": "dash",
+      "dashLength": 2,
+		},
+		"legend": {
 		},
 		},
-		"legend": {},
 		"extra": {
 		"extra": {
 			"area": {
 			"area": {
 				"type": "straight",
 				"type": "straight",
@@ -445,14 +400,15 @@ module.exports = {
 			},
 			},
 		}
 		}
 	},
 	},
-	"radar": {
+	"radar":{
 		"type": "radar",
 		"type": "radar",
 		"color": color,
 		"color": color,
-		"padding": [5, 5, 5, 5],
+		"padding": [5,5,5,5],
+    "dataLabel": false,
 		"legend": {
 		"legend": {
 			"show": true,
 			"show": true,
 			"position": "right",
 			"position": "right",
-			"lineHeight": 25,
+      "lineHeight": 25,
 		},
 		},
 		"extra": {
 		"extra": {
 			"radar": {
 			"radar": {
@@ -464,7 +420,7 @@ module.exports = {
 			},
 			},
 		}
 		}
 	},
 	},
-	"gauge": {
+	"gauge":{
 		"type": "gauge",
 		"type": "gauge",
 		"color": color,
 		"color": color,
 		"title": {
 		"title": {
@@ -504,10 +460,10 @@ module.exports = {
 			}
 			}
 		}
 		}
 	},
 	},
-	"candle": {
+	"candle":{
 		"type": "candle",
 		"type": "candle",
 		"color": color,
 		"color": color,
-		"padding": [15, 15, 0, 15],
+		"padding": [15,15,0,15],
 		"enableScroll": true,
 		"enableScroll": true,
 		"enableMarkLine": true,
 		"enableMarkLine": true,
 		"dataLabel": false,
 		"dataLabel": false,
@@ -523,8 +479,10 @@ module.exports = {
 			"scrollColor": "#A6A6A6",
 			"scrollColor": "#A6A6A6",
 			"scrollBackgroundColor": "#EFEBEF"
 			"scrollBackgroundColor": "#EFEBEF"
 		},
 		},
-		"yAxis": {},
-		"legend": {},
+		"yAxis": {
+		},
+		"legend": {
+		},
 		"extra": {
 		"extra": {
 			"candle": {
 			"candle": {
 				"color": {
 				"color": {
@@ -535,15 +493,16 @@ module.exports = {
 				},
 				},
 				"average": {
 				"average": {
 					"show": true,
 					"show": true,
-					"name": ["MA5", "MA10", "MA30"],
-					"day": [5, 10, 20],
-					"color": ["#1890ff", "#2fc25b", "#facc14"]
+					"name": ["MA5","MA10","MA30"],
+					"day": [5,10,20],
+					"color": ["#1890ff","#2fc25b","#facc14"]
 				}
 				}
 			},
 			},
 			"markLine": {
 			"markLine": {
 				"type": "dash",
 				"type": "dash",
 				"dashLength": 5,
 				"dashLength": 5,
-				"data": [{
+				"data": [
+					{
 						"value": 2150,
 						"value": 2150,
 						"lineColor": "#f04864",
 						"lineColor": "#f04864",
 						"showLabel": true
 						"showLabel": true
@@ -557,12 +516,12 @@ module.exports = {
 			}
 			}
 		}
 		}
 	},
 	},
-	"mix": {
+	"mix":{
 		"type": "mix",
 		"type": "mix",
 		"color": color,
 		"color": color,
-		"padding": [15, 15, 0, 15],
+		"padding": [15,15,0,15],
 		"xAxis": {
 		"xAxis": {
-			"disableGrid": true,
+      "disableGrid": true,
 		},
 		},
 		"yAxis": {
 		"yAxis": {
 			"disabled": false,
 			"disabled": false,
@@ -575,7 +534,8 @@ module.exports = {
 			"showTitle": true,
 			"showTitle": true,
 			"data": []
 			"data": []
 		},
 		},
-		"legend": {},
+		"legend": {
+		},
 		"extra": {
 		"extra": {
 			"mix": {
 			"mix": {
 				"column": {
 				"column": {
@@ -584,53 +544,58 @@ module.exports = {
 			},
 			},
 		}
 		}
 	},
 	},
-	"scatter": {
+	"scatter":{
 		"type": "scatter",
 		"type": "scatter",
-		"color": color,
-		"padding": [15, 15, 0, 15],
-		"dataLabel": false,
-		"xAxis": {
-			"disableGrid": false,
-			"gridType": "dash",
-			"splitNumber": 5,
-			"boundaryGap": "justify",
-			"min": 0
-		},
-		"yAxis": {
-			"disableGrid": false,
-			"gridType": "dash",
-		},
-		"legend": {},
-		"extra": {
-			"scatter": {},
-		}
+		"color":color,
+		"padding":[15,15,0,15],
+    "dataLabel":false,
+    "xAxis": {
+      "disableGrid": false,
+      "gridType":"dash",
+      "splitNumber":5,
+      "boundaryGap":"justify",
+      "min":0
+    },
+    "yAxis": {
+      "disableGrid": false,
+      "gridType":"dash",
+    },
+    "legend": {
+    },
+    "extra": {
+    	"scatter": {
+    	},
+    }
 	},
 	},
-	"bubble": {
+	"bubble":{
 		"type": "bubble",
 		"type": "bubble",
-		"color": color,
-		"padding": [15, 15, 0, 15],
-		"xAxis": {
-			"disableGrid": false,
-			"gridType": "dash",
-			"splitNumber": 5,
-			"boundaryGap": "justify",
-			"min": 0,
-			"max": 250
-		},
-		"yAxis": {
-			"disableGrid": false,
-			"gridType": "dash",
-			"data": [{
-				"min": 0,
-				"max": 150
-			}]
-		},
-		"legend": {},
-		"extra": {
-			"bubble": {
-				"border": 2,
-				"opacity": 0.5,
-			},
-		}
+		"color":color,
+		"padding":[15,15,0,15],
+    "xAxis": {
+      "disableGrid": false,
+      "gridType":"dash",
+      "splitNumber":5,
+      "boundaryGap":"justify",
+      "min":0,
+      "max":250
+    },
+    "yAxis": {
+      "disableGrid": false,
+      "gridType":"dash",
+      "data":[{
+        "min":0,
+        "max":150
+      }]
+    },
+    "legend": {
+    },
+    "extra": {
+    	"bubble": {
+        "border":2,
+        "opacity": 0.5,
+    	},
+    }
 	}
 	}
 }
 }
+
+export default cfu;

+ 3 - 10
uni_modules/qiun-data-charts/js_sdk/u-charts/readme.md

@@ -1,12 +1,5 @@
 # uCharts JSSDK说明
 # uCharts JSSDK说明
-1、如不使用uCharts组件,可直接引用u-charts.js,打包编译后会`自动压缩`,压缩后体积约为`98kb`。
-2、如果100kb的体积仍需压缩,请手动删除u-charts.js内您不需要的图表类型,如k线图candle
+1、如不使用uCharts组件,可直接引用u-charts.js,打包编译后会`自动压缩`,压缩后体积约为`120kb`。
+2、如果120kb的体积仍需压缩,请手到uCharts官网通过在线定制选择您需要的图表
 3、config-ucharts.js为uCharts组件的用户配置文件,升级前请`自行备份config-ucharts.js`文件,以免被强制覆盖。
 3、config-ucharts.js为uCharts组件的用户配置文件,升级前请`自行备份config-ucharts.js`文件,以免被强制覆盖。
-3、config-echarts.js为ECharts组件的用户配置文件,升级前请`自行备份config-echarts.js`文件,以免被强制覆盖。
-
-# v1.0转v2.0注意事项
-1、opts.colors变更为opts.color
-2、ring圆环图的扩展配置由extra.pie变更为extra.ring
-3、混合图借用的扩展配置由extra.column变更为extra.mix.column
-4、全部涉及到format的格式化属性变更为formatter
-5、不需要再传canvasId及$this参数,如果通过uChats获取context,可能会导致this实例混乱,导致小程序开发者工具报错。如果不使用qiun-data-charts官方组件,需要在new uCharts()实例化之前,自行获取canvas的上下文context(ctx),并传入new中的context(opts.context)。为了能跨更多的端,给您带来的不便敬请谅解。
+4、config-echarts.js为ECharts组件的用户配置文件,升级前请`自行备份config-echarts.js`文件,以免被强制覆盖。

Dosya farkı çok büyük olduğundan ihmal edildi
+ 822 - 301
uni_modules/qiun-data-charts/js_sdk/u-charts/u-charts.js


Dosya farkı çok büyük olduğundan ihmal edildi
+ 18 - 0
uni_modules/qiun-data-charts/js_sdk/u-charts/u-charts.min.js


+ 8 - 4
uni_modules/qiun-data-charts/package.json

@@ -1,8 +1,8 @@
 {
 {
   "id": "qiun-data-charts",
   "id": "qiun-data-charts",
   "displayName": "秋云 ucharts echarts 高性能跨全端图表组件",
   "displayName": "秋云 ucharts echarts 高性能跨全端图表组件",
-  "version": "2.3.2-20210627",
-  "description": "uCharts v2.3上线,支持nvue!全新官方图表组件,支持H5及APP用ECharts渲染图表,uniapp可视化首选组件",
+  "version": "2.4.3-20220505",
+  "description": "uCharts 新增双指缩放、新增山峰图!支持H5及APP用 ucharts echarts 渲染图表,uniapp可视化首选组件",
   "keywords": [
   "keywords": [
     "ucharts",
     "ucharts",
     "echarts",
     "echarts",
@@ -12,7 +12,7 @@
 ],
 ],
   "repository": "https://gitee.com/uCharts/uCharts",
   "repository": "https://gitee.com/uCharts/uCharts",
   "engines": {
   "engines": {
-    "HBuilderX": "^3.1.0"
+    "HBuilderX": "^3.3.8"
   },
   },
   "dcloudext": {
   "dcloudext": {
     "category": [
     "category": [
@@ -35,7 +35,7 @@
       "data": "插件不采集任何数据",
       "data": "插件不采集任何数据",
       "permissions": "无"
       "permissions": "无"
     },
     },
-    "npmurl": ""
+    "npmurl": "https://www.npmjs.com/~qiun"
   },
   },
   "uni_modules": {
   "uni_modules": {
     "dependencies": [],
     "dependencies": [],
@@ -73,6 +73,10 @@
         "快应用": {
         "快应用": {
           "华为": "y",
           "华为": "y",
           "联盟": "y"
           "联盟": "y"
+        },
+        "Vue": {
+            "vue2": "y",
+            "vue3": "y"
         }
         }
       }
       }
     }
     }

Dosya farkı çok büyük olduğundan ihmal edildi
+ 74 - 423
uni_modules/qiun-data-charts/readme.md


+ 29 - 0
uni_modules/uni-badge/changelog.md

@@ -0,0 +1,29 @@
+## 1.2.0(2021-11-19)
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-badge](https://uniapp.dcloud.io/component/uniui/uni-badge)
+## 1.1.7(2021-11-08)
+- 优化 升级ui
+- 修改 size 属性默认值调整为 small
+- 修改 type 属性,默认值调整为 error,info 替换 default
+## 1.1.6(2021-09-22)
+- 修复 在字节小程序上样式不生效的 bug
+## 1.1.5(2021-07-30)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 1.1.4(2021-07-29)
+- 修复 去掉 nvue 不支持css 的 align-self 属性,nvue 下不暂支持 absolute 属性
+## 1.1.3(2021-06-24)
+- 优化 示例项目
+## 1.1.1(2021-05-12)
+- 新增 组件示例地址
+## 1.1.0(2021-05-12)
+- 新增 uni-badge 的 absolute 属性,支持定位
+- 新增 uni-badge 的 offset 属性,支持定位偏移
+- 新增 uni-badge 的 is-dot 属性,支持仅显示有一个小点
+- 新增 uni-badge 的 max-num 属性,支持自定义封顶的数字值,超过 99 显示99+
+- 优化 uni-badge 属性 custom-style, 支持以对象形式自定义样式
+## 1.0.7(2021-05-07)
+- 修复 uni-badge 在 App 端,数字小于10时不是圆形的bug
+- 修复 uni-badge 在父元素不是 flex 布局时,宽度缩小的bug
+- 新增 uni-badge 属性 custom-style, 支持自定义样式
+## 1.0.6(2021-02-04)
+- 调整为uni_modules目录规范

+ 268 - 0
uni_modules/uni-badge/components/uni-badge/uni-badge.vue

@@ -0,0 +1,268 @@
+<template>
+	<view class="uni-badge--x">
+		<slot />
+		<text v-if="text" :class="classNames" :style="[badgeWidth, positionStyle, customStyle, dotStyle]"
+			class="uni-badge" @click="onClick()">{{displayValue}}</text>
+	</view>
+</template>
+
+<script>
+	/**
+	 * Badge 数字角标
+	 * @description 数字角标一般和其它控件(列表、9宫格等)配合使用,用于进行数量提示,默认为实心灰色背景
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=21
+	 * @property {String} text 角标内容
+	 * @property {String} size = [normal|small] 角标内容
+	 * @property {String} type = [info|primary|success|warning|error] 颜色类型
+	 * 	@value info 灰色
+	 * 	@value primary 蓝色
+	 * 	@value success 绿色
+	 * 	@value warning 黄色
+	 * 	@value error 红色
+	 * @property {String} inverted = [true|false] 是否无需背景颜色
+	 * @property {Number} maxNum 展示封顶的数字值,超过 99 显示 99+
+	 * @property {String} absolute = [rightTop|rightBottom|leftBottom|leftTop] 开启绝对定位, 角标将定位到其包裹的标签的四角上		
+	 * 	@value rightTop 右上
+	 * 	@value rightBottom 右下
+	 * 	@value leftTop 左上
+	 * 	@value leftBottom 左下
+	 * @property {Array[number]} offset	距定位角中心点的偏移量,只有存在 absolute 属性时有效,例如:[-10, -10] 表示向外偏移 10px,[10, 10] 表示向 absolute 指定的内偏移 10px
+	 * @property {String} isDot = [true|false] 是否显示为一个小点
+	 * @event {Function} click 点击 Badge 触发事件
+	 * @example <uni-badge text="1"></uni-badge>
+	 */
+
+	export default {
+		name: 'UniBadge',
+		emits: ['click'],
+		props: {
+			type: {
+				type: String,
+				default: 'error'
+			},
+			inverted: {
+				type: Boolean,
+				default: false
+			},
+			isDot: {
+				type: Boolean,
+				default: false
+			},
+			maxNum: {
+				type: Number,
+				default: 99
+			},
+			absolute: {
+				type: String,
+				default: ''
+			},
+			offset: {
+				type: Array,
+				default () {
+					return [0, 0]
+				}
+			},
+			text: {
+				type: [String, Number],
+				default: ''
+			},
+			size: {
+				type: String,
+				default: 'small'
+			},
+			customStyle: {
+				type: Object,
+				default () {
+					return {}
+				}
+			}
+		},
+		data() {
+			return {};
+		},
+		computed: {
+			width() {
+				return String(this.text).length * 8 + 12
+			},
+			classNames() {
+				const {
+					inverted,
+					type,
+					size,
+					absolute
+				} = this
+				return [
+					inverted ? 'uni-badge--' + type + '-inverted' : '',
+					'uni-badge--' + type,
+					'uni-badge--' + size,
+					absolute ? 'uni-badge--absolute' : ''
+				].join(' ')
+			},
+			positionStyle() {
+				if (!this.absolute) return {}
+				let w = this.width / 2,
+					h = 10
+				if (this.isDot) {
+					w = 5
+					h = 5
+				}
+				const x = `${- w  + this.offset[0]}px`
+				const y = `${- h + this.offset[1]}px`
+
+				const whiteList = {
+					rightTop: {
+						right: x,
+						top: y
+					},
+					rightBottom: {
+						right: x,
+						bottom: y
+					},
+					leftBottom: {
+						left: x,
+						bottom: y
+					},
+					leftTop: {
+						left: x,
+						top: y
+					}
+				}
+				const match = whiteList[this.absolute]
+				return match ? match : whiteList['rightTop']
+			},
+			badgeWidth() {
+				return {
+					width: `${this.width}px`
+				}
+			},
+			dotStyle() {
+				if (!this.isDot) return {}
+				return {
+					width: '10px',
+					height: '10px',
+					borderRadius: '10px'
+				}
+			},
+			displayValue() {
+				const {
+					isDot,
+					text,
+					maxNum
+				} = this
+				return isDot ? '' : (Number(text) > maxNum ? `${maxNum}+` : text)
+			}
+		},
+		methods: {
+			onClick() {
+				this.$emit('click');
+			}
+		}
+	};
+</script>
+
+<style lang="scss" scoped>
+	$uni-primary: #2979ff !default;
+	$uni-success: #4cd964 !default;
+	$uni-warning: #f0ad4e !default;
+	$uni-error: #dd524d !default;
+	$uni-info: #909399 !default;
+
+
+	$bage-size: 12px;
+	$bage-small: scale(0.8);
+
+	.uni-badge--x {
+		/* #ifdef APP-NVUE */
+		// align-self: flex-start;
+		/* #endif */
+		/* #ifndef APP-NVUE */
+		display: inline-block;
+		/* #endif */
+		position: relative;
+	}
+
+	.uni-badge--absolute {
+		position: absolute;
+	}
+
+	.uni-badge--small {
+		transform: $bage-small;
+		transform-origin: center center;
+	}
+
+	.uni-badge {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		overflow: hidden;
+		box-sizing: border-box;
+		/* #endif */
+		justify-content: center;
+		flex-direction: row;
+		height: 20px;
+		line-height: 18px;
+		color: #fff;
+		border-radius: 100px;
+		background-color: $uni-info;
+		background-color: transparent;
+		border: 1px solid #fff;
+		text-align: center;
+		font-family: 'Helvetica Neue', Helvetica, sans-serif;
+		font-size: $bage-size;
+		/* #ifdef H5 */
+		z-index: 999;
+		cursor: pointer;
+		/* #endif */
+
+		&--info {
+			color: #fff;
+			background-color: $uni-info;
+		}
+
+		&--primary {
+			background-color: $uni-primary;
+		}
+
+		&--success {
+			background-color: $uni-success;
+		}
+
+		&--warning {
+			background-color: $uni-warning;
+		}
+
+		&--error {
+			background-color: $uni-error;
+		}
+
+		&--inverted {
+			padding: 0 5px 0 0;
+			color: $uni-info;
+		}
+
+		&--info-inverted {
+			color: $uni-info;
+			background-color: transparent;
+		}
+
+		&--primary-inverted {
+			color: $uni-primary;
+			background-color: transparent;
+		}
+
+		&--success-inverted {
+			color: $uni-success;
+			background-color: transparent;
+		}
+
+		&--warning-inverted {
+			color: $uni-warning;
+			background-color: transparent;
+		}
+
+		&--error-inverted {
+			color: $uni-error;
+			background-color: transparent;
+		}
+
+	}
+</style>

+ 88 - 0
uni_modules/uni-badge/package.json

@@ -0,0 +1,88 @@
+{
+  "id": "uni-badge",
+  "displayName": "uni-badge 数字角标",
+  "version": "1.2.0",
+  "description": "数字角标(徽章)组件,在元素周围展示消息提醒,一般用于列表、九宫格、按钮等地方。",
+  "keywords": [
+    "",
+    "badge",
+    "uni-ui",
+    "uniui",
+    "数字角标",
+    "徽章"
+],
+  "repository": "https://github.com/dcloudio/uni-ui",
+  "engines": {
+    "HBuilderX": ""
+  },
+  "directories": {
+    "example": "../../temps/example_temps"
+  },
+  "dcloudext": {
+    "category": [
+      "前端组件",
+      "通用组件"
+    ],
+    "sale": {
+      "regular": {
+        "price": "0.00"
+      },
+      "sourcecode": {
+        "price": "0.00"
+      }
+    },
+    "contact": {
+      "qq": ""
+    },
+    "declaration": {
+      "ads": "无",
+      "data": "无",
+      "permissions": "无"
+    },
+    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+  },
+  "uni_modules": {
+    "dependencies": [],
+    "encrypt": [],
+    "platforms": {
+      "cloud": {
+        "tcb": "y",
+        "aliyun": "y"
+      },
+      "client": {
+        "App": {
+          "app-vue": "y",
+          "app-nvue": "y"
+        },
+        "H5-mobile": {
+          "Safari": "y",
+          "Android Browser": "y",
+          "微信浏览器(Android)": "y",
+          "QQ浏览器(Android)": "y"
+        },
+        "H5-pc": {
+          "Chrome": "y",
+          "IE": "y",
+          "Edge": "y",
+          "Firefox": "y",
+          "Safari": "y"
+        },
+        "小程序": {
+          "微信": "y",
+          "阿里": "y",
+          "百度": "y",
+          "字节跳动": "y",
+          "QQ": "y"
+        },
+        "快应用": {
+          "华为": "y",
+          "联盟": "y"
+        },
+        "Vue": {
+            "vue2": "y",
+            "vue3": "y"
+        }
+      }
+    }
+  }
+}

+ 10 - 0
uni_modules/uni-badge/readme.md

@@ -0,0 +1,10 @@
+## Badge 数字角标
+> **组件名:uni-badge**
+> 代码块: `uBadge`
+
+数字角标一般和其它控件(列表、9宫格等)配合使用,用于进行数量提示,默认为实心灰色背景,
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-badge)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 
+
+

+ 83 - 0
uni_modules/uni-datetime-picker/changelog.md

@@ -1,3 +1,86 @@
+## 2.2.4(2022-03-31)
+- 修复 Vue3 下动态赋值,单选类型未响应的 bug
+## 2.2.3(2022-03-28)
+- 修复 Vue3 下动态赋值未响应的 bug
+## 2.2.2(2021-12-10)
+- 修复 clear-icon 属性在小程序平台不生效的 bug
+## 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/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 在移动端的 bug
+- 修复 单选赋默认值时,赋值日期未高亮的 bug
+- 修复 赋默认值时,移动端未正确显示时间的 bug
+## 2.1.3(2021-09-09)
+- 新增 hide-second 属性,支持只使用时分,隐藏秒
+## 2.1.2(2021-09-03)
+- 优化 取消选中时(范围选)直接开始下一次选择, 避免多点一次
+- 优化 移动端支持清除按钮,同时支持通过 ref 调用组件的 clear 方法
+- 优化 调整字号大小,美化日历界面
+- 修复 因国际化导致的 placeholder 失效的 bug
+## 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 错误的 bug
+## 2.0.18(2021-08-05)
+- 修复 type 属性动态赋值无效的 bug
+- 修复 ‘确认’按钮被 tabbar 遮盖 bug
+- 修复 组件未赋值时范围选左、右日历相同的 bug
+## 2.0.17(2021-08-04)
+- 修复 范围选未正确显示当前值的 bug
+- 修复 h5 平台(移动端)报错 'cale' of undefined 的 bug
+## 2.0.16(2021-07-21)
+- 新增 return-type 属性支持返回 date 日期对象
+## 2.0.15(2021-07-14)
+- 修复 单选日期类型,初始赋值后不在当前日历的 bug
+- 新增 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)
+- 修复 范围选择的初始时间在一个月内时,造成无法选择的bug
+## 2.0.11(2021-07-08)
+- 优化 弹出层在超出视窗边缘定位不准确的问题
+## 2.0.10(2021-07-08)
+- 修复 范围起始点样式的背景色与今日样式的字体前景色融合,导致日期字体看不清的 bug
+- 优化 弹出层在超出视窗边缘被遮盖的问题
+## 2.0.9(2021-07-07)
+- 新增 maskClick 事件
+- 修复 特殊情况日历 rpx 布局错误的 bug,rpx -> px
+- 修复 范围选择时清空返回值不合理的bug,['', ''] -> []
+## 2.0.8(2021-07-07)
+- 新增 日期时间显示框支持插槽
+## 2.0.7(2021-07-01)
+- 优化 添加 uni-icons 依赖
+## 2.0.6(2021-05-22)
+- 修复 图标在小程序上不显示的 bug
+- 优化 重命名引用组件,避免潜在组件命名冲突
+## 2.0.5(2021-05-20)
+- 优化 代码目录扁平化
+## 2.0.4(2021-05-12)
+- 新增 组件示例地址
+## 2.0.3(2021-05-10)
+- 修复 ios 下不识别 '-' 日期格式的 bug
+- 优化 pc 下弹出层添加边框和阴影
+## 2.0.2(2021-05-08)
+- 修复 在 admin 中获取弹出层定位错误的bug
+## 2.0.1(2021-05-08)
+- 修复 type 属性向下兼容,默认值从 date 变更为 datetime
+## 2.0.0(2021-04-30)
+- 支持日历形式的日期+时间的范围选择
+ > 注意:此版本不向后兼容,不再支持单独时间选择(type=time)及相关的 hide-second 属性(时间选可使用内置组件 picker)
 ## 1.0.6(2021-03-18)
 ## 1.0.6(2021-03-18)
 - 新增 hide-second 属性,时间支持仅选择时、分
 - 新增 hide-second 属性,时间支持仅选择时、分
 - 修复 选择跟显示的日期不一样的 bug
 - 修复 选择跟显示的日期不一样的 bug

+ 185 - 0
uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar-item.vue

@@ -0,0 +1,185 @@
+<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--isDay': weeks.isDay}"></view>
+	</view>
+</template>
+
+<script>
+	export default {
+		props: {
+			weeks: {
+				type: Object,
+				default () {
+					return {}
+				}
+			},
+			calendar: {
+				type: Object,
+				default: () => {
+					return {}
+				}
+			},
+			selected: {
+				type: Array,
+				default: () => {
+					return []
+				}
+			},
+			lunar: {
+				type: Boolean,
+				default: false
+			},
+			checkHover: {
+				type: Boolean,
+				default: false
+			}
+		},
+		methods: {
+			choiceDate(weeks) {
+				this.$emit('change', weeks)
+			},
+			handleMousemove(weeks) {
+				this.$emit('handleMouse', weeks)
+			}
+		}
+	}
+</script>
+
+<style lang="scss" >
+	.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: #455997;
+	}
+
+	.uni-calendar-item__weeks-lunar-text {
+		font-size: 12px;
+		color: #333;
+	}
+
+	.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 {
+		// background-color: rgba(249, 249, 249, $uni-opacity-disabled);
+		cursor: default;
+	}
+
+	.uni-calendar-item--disable .uni-calendar-item__weeks-box-text-disable {
+		color: #D1D1D1;
+	}
+
+	.uni-calendar-item--isDay {
+		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: #007aff;
+		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: #409eff;
+		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>

+ 898 - 0
uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.vue

@@ -0,0 +1,898 @@
+<template>
+	<view class="uni-calendar" @mouseleave="leaveCale">
+		<view v-if="!insert&&show" class="uni-calendar__mask" :class="{'uni-calendar--mask-show':aniMaskShow}"
+			@click="clean"></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 v-if="left" class="uni-calendar__header-btn-box" @click.stop="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||'') + ' 年 ' + ( nowDate.month||'') +' 月'}}</text>
+				</picker>
+				<view v-if="right" class="uni-calendar__header-btn-box" @click.stop="next">
+					<view class="uni-calendar__header-btn uni-calendar--right"></view>
+				</view>
+				<view v-if="!insert" class="dialog-close" @click="clean">
+					<view class="dialog-close-plus" data-id="close"></view>
+					<view class="dialog-close-plus dialog-close-rotate" data-id="close"></view>
+				</view>
+
+				<!-- <text class="uni-calendar__backtoday" @click="backtoday">回到今天</text> -->
+			</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" :lunar="lunar" :checkHover="range" @change="choiceDate"
+							@handleMouse="handleMouse">
+						</calendar-item>
+					</view>
+				</view>
+			</view>
+			<view v-if="!insert && !range && typeHasTime" 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="reactStartTime" :end="reactEndTime" v-model="time"
+					:disabled="!tempSingleDate" :border="false" :hide-second="hideSecond" class="time-picker-style">
+				</time-picker>
+			</view>
+
+			<view v-if="!insert && range && typeHasTime" 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="reactStartTime" v-model="timeRange.startTime" :border="false"
+						:hide-second="hideSecond" :disabled="!tempRange.before" class="time-picker-style">
+					</time-picker>
+				</view>
+				<uni-icons type="arrowthinright" color="#999" style="line-height: 50px;"></uni-icons>
+				<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="reactEndTime" 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-calendar__header-btn-box">
+					<text class="uni-calendar__button-text uni-calendar--fixed-width">{{okText}}</text>
+				</view> -->
+				<view class="uni-datetime-picker--btn" @click="confirm">确认</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import Calendar from './util.js';
+	import calendarItem from './calendar-item.vue'
+	import timePicker from './time-picker.vue'
+	import {
+		initVueI18n
+	} from '@dcloudio/uni-i18n'
+	import messages from './i18n/index.js'
+	const {
+		t
+	} = initVueI18n(messages)
+	/**
+	 * Calendar 日历
+	 * @description 日历组件可以查看日期,选择任意范围内的日期,打点操作。常用场景如:酒店日期预订、火车机票选择购买日期、上下班打卡等
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=56
+	 * @property {String} date 自定义当前时间,默认为今天
+	 * @property {Boolean} lunar 显示农历
+	 * @property {String} startDate 日期选择范围-开始日期
+	 * @property {String} endDate 日期选择范围-结束日期
+	 * @property {Boolean} range 范围选择
+	 * @property {Boolean} insert = [true|false] 插入模式,默认为false
+	 * 	@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 是否选择月份为背景
+	 * @event {Function} change 日期改变,`insert :ture` 时生效
+	 * @event {Function} confirm 确认选择`insert :false` 时生效
+	 * @event {Function} monthSwitch 切换月份时触发
+	 * @example <uni-calendar :insert="true":lunar="true" :start-date="'2019-3-2'":end-date="'2019-5-20'"@change="change" />
+	 */
+	export default {
+		components: {
+			calendarItem,
+			timePicker
+		},
+		props: {
+			date: {
+				type: String,
+				default: ''
+			},
+			defTime: {
+				type: [String, Object],
+				default: ''
+			},
+			selectableTimes: {
+				type: [Object],
+				default () {
+					return {}
+				}
+			},
+			selected: {
+				type: Array,
+				default () {
+					return []
+				}
+			},
+			lunar: {
+				type: Boolean,
+				default: false
+			},
+			startDate: {
+				type: String,
+				default: ''
+			},
+			endDate: {
+				type: String,
+				default: ''
+			},
+			range: {
+				type: Boolean,
+				default: false
+			},
+			typeHasTime: {
+				type: Boolean,
+				default: false
+			},
+			insert: {
+				type: Boolean,
+				default: true
+			},
+			showMonth: {
+				type: Boolean,
+				default: true
+			},
+			clearDate: {
+				type: Boolean,
+				default: true
+			},
+			left: {
+				type: Boolean,
+				default: true
+			},
+			right: {
+				type: Boolean,
+				default: true
+			},
+			checkHover: {
+				type: Boolean,
+				default: true
+			},
+			hideSecond: {
+				type: [Boolean],
+				default: false
+			},
+			pleStatus: {
+				type: Object,
+				default () {
+					return {
+						before: '',
+						after: '',
+						data: [],
+						fulldate: ''
+					}
+				}
+			}
+		},
+		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, oldVal) {
+					if (!this.range) {
+						this.tempSingleDate = newVal
+						setTimeout(() => {
+							this.init(newVal)
+						}, 100)
+					}
+				}
+			},
+			defTime: {
+				immediate: true,
+				handler(newVal, oldVal) {
+					if (!this.range) {
+						this.time = newVal
+					} else {
+						// console.log('-----', newVal);
+						this.timeRange.startTime = newVal.start
+						this.timeRange.endTime = newVal.end
+					}
+				}
+			},
+			startDate(val) {
+				this.cale.resetSatrtDate(val)
+				this.cale.setDate(this.nowDate.fullDate)
+				this.weeks = this.cale.weeks
+			},
+			endDate(val) {
+				this.cale.resetEndDate(val)
+				this.cale.setDate(this.nowDate.fullDate)
+				this.weeks = this.cale.weeks
+			},
+			selected(newVal) {
+				this.cale.setSelectInfo(this.nowDate.fullDate, newVal)
+				this.weeks = this.cale.weeks
+			},
+			pleStatus: {
+				immediate: true,
+				handler(newVal, oldVal) {
+					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 {
+							this.cale.setDefaultMultiple(before, after)
+							if (which === 'left') {
+								this.setDate(before)
+								this.weeks = this.cale.weeks
+							} else {
+								this.setDate(after)
+								this.weeks = this.cale.weeks
+							}
+							this.cale.lastHover = true
+						}
+					}, 16)
+				}
+			}
+		},
+		computed: {
+			reactStartTime() {
+				const activeDate = this.range ? this.tempRange.before : this.calendar.fullDate
+				const res = activeDate === this.startDate ? this.selectableTimes.start : ''
+				return res
+			},
+			reactEndTime() {
+				const activeDate = this.range ? this.tempRange.after : this.calendar.fullDate
+				const res = activeDate === this.endDate ? this.selectableTimes.end : ''
+				return res
+			},
+			/**
+			 * 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")
+			},
+			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")
+			},
+		},
+		created() {
+			// 获取日历方法实例
+			this.cale = new Calendar({
+				// date: new Date(),
+				selected: this.selected,
+				startDate: this.startDate,
+				endDate: this.endDate,
+				range: this.range,
+				// multipleStatus: this.pleStatus
+			})
+			// 选中某一天
+			// this.cale.setDate(this.date)
+			this.init(this.date)
+			// this.setDay
+		},
+		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
+			},
+
+			// 取消穿透
+			clean() {
+				this.close()
+			},
+
+			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()
+			},
+
+			bindDateChange(e) {
+				const value = e.detail.value + '-1'
+				this.init(value)
+			},
+			/**
+			 * 初始化日期显示
+			 * @param {Object} date
+			 */
+			init(date) {
+				this.cale.setDate(date)
+				this.weeks = this.cale.weeks
+				this.nowDate = this.calendar = this.cale.getInfo(date)
+			},
+			// choiceDate(weeks) {
+			// 	if (weeks.disable) return
+			// 	this.calendar = weeks
+			// 	// 设置多选
+			// 	this.cale.setMultiple(this.calendar.fullDate, true)
+			// 	this.weeks = this.cale.weeks
+			// 	this.tempSingleDate = this.calendar.fullDate
+			// 	this.tempRange.before = this.cale.multipleStatus.before
+			// 	this.tempRange.after = this.cale.multipleStatus.after
+			// 	this.change()
+			// },
+			/**
+			 * 打开日历弹窗
+			 */
+			open() {
+				// 弹窗模式并且清理数据
+				if (this.clearDate && !this.insert) {
+					this.cale.cleanMultipleStatus()
+					// this.cale.setDate(this.date)
+					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() {
+				if (!this.insert) return
+				this.setEmit('change')
+			},
+			/**
+			 * 选择月份触发
+			 */
+			monthSwitch() {
+				let {
+					year,
+					month
+				} = this.nowDate
+				this.$emit('monthSwitch', {
+					year,
+					month: Number(month)
+				})
+			},
+			/**
+			 * 派发事件
+			 * @param {Object} name
+			 */
+			setEmit(name) {
+				let {
+					year,
+					month,
+					date,
+					fullDate,
+					lunar,
+					extraInfo
+				} = this.calendar
+				this.$emit(name, {
+					range: this.cale.multipleStatus,
+					year,
+					month,
+					date,
+					time: this.time,
+					timeRange: this.timeRange,
+					fulldate: fullDate,
+					lunar,
+					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
+				this.tempRange.before = this.cale.multipleStatus.before
+				this.tempRange.after = this.cale.multipleStatus.after
+				this.change()
+			},
+			/**
+			 * 回到今天
+			 */
+			backtoday() {
+				let date = this.cale.getDate(new Date()).fullDate
+				// this.cale.setDate(date)
+				this.init(date)
+				this.change()
+			},
+			/**
+			 * 比较时间大小
+			 */
+			dateCompare(startDate, endDate) {
+				// 计算截止时间
+				startDate = new Date(startDate.replace('-', '/').replace('-', '/'))
+				// 计算详细项的截止时间
+				endDate = new Date(endDate.replace('-', '/').replace('-', '/'))
+				if (startDate <= endDate) {
+					return true
+				} else {
+					return false
+				}
+			},
+			/**
+			 * 上个月
+			 */
+			pre() {
+				const preDate = this.cale.getDate(this.nowDate.fullDate, -1, 'month').fullDate
+				this.setDate(preDate)
+				this.monthSwitch()
+
+			},
+			/**
+			 * 下个月
+			 */
+			next() {
+				const nextDate = this.cale.getDate(this.nowDate.fullDate, +1, 'month').fullDate
+				this.setDate(nextDate)
+				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-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: #007aff;
+		/* #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;
+		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: #007aff;
+		color: #fff;
+		font-size: 16px;
+		letter-spacing: 5px;
+	}
+
+	/* #ifndef APP-NVUE */
+	.uni-datetime-picker--btn:active {
+		opacity: 0.7;
+	}
+	/* #endif */
+</style>

+ 19 - 0
uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/en.json

@@ -0,0 +1,19 @@
+{
+	"uni-datetime-picker.selectDate": "select date",
+	"uni-datetime-picker.selectTime": "select time",
+	"uni-datetime-picker.selectDateTime": "select datetime",
+	"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-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"
+}

+ 8 - 0
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
+}

+ 19 - 0
uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hans.json

@@ -0,0 +1,19 @@
+{
+	"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-calender.SUN": "日",
+	"uni-calender.MON": "一",
+	"uni-calender.TUE": "二",
+	"uni-calender.WED": "三",
+	"uni-calender.THU": "四",
+	"uni-calender.FRI": "五",
+	"uni-calender.SAT": "六"
+}

+ 19 - 0
uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hant.json

@@ -0,0 +1,19 @@
+{
+	"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-calender.SUN": "日",
+	"uni-calender.MON": "一",
+	"uni-calender.TUE": "二",
+	"uni-calender.WED": "三",
+	"uni-calender.THU": "四",
+	"uni-calender.FRI": "五",
+	"uni-calender.SAT": "六"
+}

+ 927 - 0
uni_modules/uni-datetime-picker/components/uni-datetime-picker/time-picker.vue

@@ -0,0 +1,927 @@
+<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>
+		<!-- #ifdef H5 -->
+		<!-- <keypress v-if="visible" @esc="tiggerTimePicker" @enter="setTime" /> -->
+		<!-- #endif -->
+	</view>
+</template>
+
+<script>
+	// #ifdef H5
+	import keypress from './keypress'
+	// #endif
+	import {
+		initVueI18n
+	} from '@dcloudio/uni-i18n'
+	import messages from './i18n/index.js'
+	const {	t	} = initVueI18n(messages)
+
+	/**
+	 * 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',
+		components: {
+			// #ifdef H5
+			keypress
+			// #endif
+		},
+		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,
+			}
+		},
+		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: {
+			value: {
+				handler(newVal, oldVal) {
+					if (newVal) {
+						this.parseValue(this.fixIosDateFormat(newVal)) //兼容 iOS、safari 日期格式
+						this.initTime(false)
+					} else {
+						this.time = ''
+						this.parseValue(Date.now())
+					}
+				},
+				immediate: true
+			},
+			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(this.fixIosDateFormat(newVal), 'start') //兼容 iOS、safari 日期格式
+				},
+				immediate: true
+			},
+			end: {
+				handler(newVal) {
+					this.parseDatetimeRange(this.fixIosDateFormat(newVal), 'end') //兼容 iOS、safari 日期格式
+				},
+				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
+			},
+
+			/**
+			 * 解析时分秒字符串,例如: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])
+				}
+			},
+
+			/**
+			 * 解析选择器初始值,类型可以是字符串、时间戳,例如: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) && typeof value !== NaN) {
+					value = parseInt(value)
+					dateBase = 0
+				}
+				return this.createTimeStamp(dateBase + value)
+			},
+
+			/**
+			 * 解析默认值 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
+				}
+			},
+
+			/**
+			 * 解析可选择时间范围 start、end,年月日字符串、时间戳
+			 * @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) && Number(point) !== NaN) {
+						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();
+			},
+
+			//兼容 iOS、safari 日期格式
+			fixIosDateFormat(value) {
+				if (typeof value === 'string') {
+					value = value.replace(/-/g, '/')
+				}
+				return value
+			},
+
+			/**
+			 * 生成时间戳
+			 * @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 = this.fixIosDateFormat(this.value)
+				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>
+	.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: #007AFF;
+	}
+
+	.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;
+	}
+
+	.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>

Dosya farkı çok büyük olduğundan ihmal edildi
+ 780 - 686
uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue


+ 410 - 0
uni_modules/uni-datetime-picker/components/uni-datetime-picker/util.js

@@ -0,0 +1,410 @@
+class Calendar {
+	constructor({
+		date,
+		selected,
+		startDate,
+		endDate,
+		range,
+		// multipleStatus
+	} = {}) {
+		// 当前日期
+		this.date = this.getDate(new Date()) // 当前初入日期
+		// 打点信息
+		this.selected = selected || [];
+		// 范围开始
+		this.startDate = startDate
+		// 范围结束
+		this.endDate = endDate
+		this.range = range
+		// 多选状态
+		this.cleanMultipleStatus()
+		// 每周日期
+		this.weeks = {}
+		// this._getWeek(this.date.fullDate)
+		// this.multipleStatus = multipleStatus
+		this.lastHover = false
+	}
+	/**
+	 * 设置日期
+	 * @param {Object} date
+	 */
+	setDate(date) {
+		this.selectDate = this.getDate(date)
+		this._getWeek(this.selectDate.fullDate)
+	}
+
+	/**
+	 * 清理多选状态
+	 */
+	cleanMultipleStatus() {
+		this.multipleStatus = {
+			before: '',
+			after: '',
+			data: []
+		}
+	}
+
+	/**
+	 * 重置开始日期
+	 */
+	resetSatrtDate(startDate) {
+		// 范围开始
+		this.startDate = startDate
+
+	}
+
+	/**
+	 * 重置结束日期
+	 */
+	resetEndDate(endDate) {
+		// 范围结束
+		this.endDate = endDate
+	}
+
+	/**
+	 * 获取任意时间
+	 */
+	getDate(date, AddDayCount = 0, str = 'day') {
+		if (!date) {
+			date = new Date()
+		}
+		if (typeof date !== 'object') {
+			date = date.replace(/-/g, '/')
+		}
+		const dd = new Date(date)
+		switch (str) {
+			case 'day':
+				dd.setDate(dd.getDate() + AddDayCount) // 获取AddDayCount天后的日期
+				break
+			case 'month':
+				if (dd.getDate() === 31) {
+					dd.setDate(dd.getDate() + AddDayCount)
+				} else {
+					dd.setMonth(dd.getMonth() + AddDayCount) // 获取AddDayCount天后的日期
+				}
+				break
+			case 'year':
+				dd.setFullYear(dd.getFullYear() + AddDayCount) // 获取AddDayCount天后的日期
+				break
+		}
+		const y = dd.getFullYear()
+		const m = dd.getMonth() + 1 < 10 ? '0' + (dd.getMonth() + 1) : dd.getMonth() + 1 // 获取当前月份的日期,不足10补0
+		const d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate() // 获取当前几号,不足10补0
+		return {
+			fullDate: y + '-' + m + '-' + d,
+			year: y,
+			month: m,
+			date: d,
+			day: dd.getDay()
+		}
+	}
+
+
+	/**
+	 * 获取上月剩余天数
+	 */
+	_getLastMonthDays(firstDay, full) {
+		let dateArr = []
+		for (let i = firstDay; i > 0; i--) {
+			const beforeDate = new Date(full.year, full.month - 1, -i + 1).getDate()
+			dateArr.push({
+				date: beforeDate,
+				month: full.month - 1,
+				disable: true
+			})
+		}
+		return dateArr
+	}
+	/**
+	 * 获取本月天数
+	 */
+	_currentMonthDys(dateData, full) {
+		let dateArr = []
+		let fullDate = this.date.fullDate
+		for (let i = 1; i <= dateData; i++) {
+			let isinfo = false
+			let nowDate = full.year + '-' + (full.month < 10 ?
+				full.month : full.month) + '-' + (i < 10 ?
+				'0' + i : i)
+			// 是否今天
+			let isDay = fullDate === nowDate
+			// 获取打点信息
+			let info = this.selected && this.selected.find((item) => {
+				if (this.dateEqual(nowDate, item.date)) {
+					return item
+				}
+			})
+
+			// 日期禁用
+			let disableBefore = true
+			let disableAfter = true
+			if (this.startDate) {
+				// let dateCompBefore = this.dateCompare(this.startDate, fullDate)
+				// disableBefore = this.dateCompare(dateCompBefore ? this.startDate : fullDate, nowDate)
+				disableBefore = this.dateCompare(this.startDate, nowDate)
+			}
+
+			if (this.endDate) {
+				// let dateCompAfter = this.dateCompare(fullDate, this.endDate)
+				// disableAfter = this.dateCompare(nowDate, dateCompAfter ? this.endDate : fullDate)
+				disableAfter = this.dateCompare(nowDate, this.endDate)
+			}
+			let multiples = this.multipleStatus.data
+			let checked = false
+			let multiplesStatus = -1
+			if (this.range) {
+				if (multiples) {
+					multiplesStatus = multiples.findIndex((item) => {
+						return this.dateEqual(item, nowDate)
+					})
+				}
+				if (multiplesStatus !== -1) {
+					checked = true
+				}
+			}
+			let data = {
+				fullDate: nowDate,
+				year: full.year,
+				date: i,
+				multiple: this.range ? checked : false,
+				beforeMultiple: this.isLogicBefore(nowDate, this.multipleStatus.before, this.multipleStatus.after),
+				afterMultiple: this.isLogicAfter(nowDate, this.multipleStatus.before, this.multipleStatus.after),
+				month: full.month,
+				disable: !(disableBefore && disableAfter),
+				isDay,
+				userChecked: false
+			}
+			if (info) {
+				data.extraInfo = info
+			}
+
+			dateArr.push(data)
+		}
+		return dateArr
+	}
+	/**
+	 * 获取下月天数
+	 */
+	_getNextMonthDays(surplus, full) {
+		let dateArr = []
+		for (let i = 1; i < surplus + 1; i++) {
+			dateArr.push({
+				date: i,
+				month: Number(full.month) + 1,
+				disable: true
+			})
+		}
+		return dateArr
+	}
+
+	/**
+	 * 获取当前日期详情
+	 * @param {Object} date
+	 */
+	getInfo(date) {
+		if (!date) {
+			date = new Date()
+		}
+		const dateInfo = this.canlender.find(item => item.fullDate === this.getDate(date).fullDate)
+		return dateInfo
+	}
+
+	/**
+	 * 比较时间大小
+	 */
+	dateCompare(startDate, endDate) {
+		// 计算截止时间
+		startDate = new Date(startDate.replace('-', '/').replace('-', '/'))
+		// 计算详细项的截止时间
+		endDate = new Date(endDate.replace('-', '/').replace('-', '/'))
+		if (startDate <= endDate) {
+			return true
+		} else {
+			return false
+		}
+	}
+
+	/**
+	 * 比较时间是否相等
+	 */
+	dateEqual(before, after) {
+		// 计算截止时间
+		before = new Date(before.replace('-', '/').replace('-', '/'))
+		// 计算详细项的截止时间
+		after = new Date(after.replace('-', '/').replace('-', '/'))
+		if (before.getTime() - after.getTime() === 0) {
+			return true
+		} else {
+			return false
+		}
+	}
+
+	/**
+	 *  比较真实起始日期
+	 */
+
+	isLogicBefore(currentDay, before, after) {
+		let logicBefore = before
+		if (before && after) {
+			logicBefore = this.dateCompare(before, after) ? before : after
+		}
+		return this.dateEqual(logicBefore, currentDay)
+	}
+
+	isLogicAfter(currentDay, before, after) {
+		let logicAfter = after
+		if (before && after) {
+			logicAfter = this.dateCompare(before, after) ? after : before
+		}
+		return this.dateEqual(logicAfter, currentDay)
+	}
+
+	/**
+	 * 获取日期范围内所有日期
+	 * @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.getDate(new Date(parseInt(k))).fullDate)
+		}
+		return arr
+	}
+
+	/**
+	 *  获取多选状态
+	 */
+	setMultiple(fullDate) {
+		let {
+			before,
+			after
+		} = this.multipleStatus
+		if (!this.range) return
+		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.lastHover = false
+			} else {
+				this.multipleStatus.after = fullDate
+				if (this.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._getWeek(fullDate)
+	}
+
+	/**
+	 *  鼠标 hover 更新多选状态
+	 */
+	setHoverMultiple(fullDate) {
+		let {
+			before,
+			after
+		} = this.multipleStatus
+
+		if (!this.range) return
+		if (this.lastHover) return
+
+		if (!before) {
+			this.multipleStatus.before = fullDate
+		} else {
+			this.multipleStatus.after = fullDate
+			if (this.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._getWeek(fullDate)
+	}
+
+	/**
+	 * 更新默认值多选状态
+	 */
+	setDefaultMultiple(before, after) {
+		this.multipleStatus.before = before
+		this.multipleStatus.after = after
+		if (before && after) {
+			if (this.dateCompare(before, after)) {
+				this.multipleStatus.data = this.geDateAll(before, after);
+				this._getWeek(after)
+			} else {
+				this.multipleStatus.data = this.geDateAll(after, before);
+				this._getWeek(before)
+			}
+		}
+	}
+
+	/**
+	 * 获取每周数据
+	 * @param {Object} dateData
+	 */
+	_getWeek(dateData) {
+		const {
+			fullDate,
+			year,
+			month,
+			date,
+			day
+		} = this.getDate(dateData)
+		let firstDay = new Date(year, month - 1, 1).getDay()
+		let currentDay = new Date(year, month, 0).getDate()
+		let dates = {
+			lastMonthDays: this._getLastMonthDays(firstDay, this.getDate(dateData)), // 上个月末尾几天
+			currentMonthDys: this._currentMonthDys(currentDay, this.getDate(dateData)), // 本月天数
+			nextMonthDays: [], // 下个月开始几天
+			weeks: []
+		}
+		let canlender = []
+		const surplus = 42 - (dates.lastMonthDays.length + dates.currentMonthDys.length)
+		dates.nextMonthDays = this._getNextMonthDays(surplus, this.getDate(dateData))
+		canlender = canlender.concat(dates.lastMonthDays, dates.currentMonthDys, dates.nextMonthDays)
+		let weeks = {}
+		// 拼接数组  上个月开始几天 + 本月天数+ 下个月开始几天
+		for (let i = 0; i < canlender.length; i++) {
+			if (i % 7 === 0) {
+				weeks[parseInt(i / 7)] = new Array(7)
+			}
+			weeks[parseInt(i / 7)][i % 7] = canlender[i]
+		}
+		this.canlender = canlender
+		this.weeks = weeks
+	}
+
+	//静态方法
+	// static init(date) {
+	// 	if (!this.instance) {
+	// 		this.instance = new Calendar(date);
+	// 	}
+	// 	return this.instance;
+	// }
+}
+
+
+export default Calendar

+ 14 - 6
uni_modules/uni-datetime-picker/package.json

@@ -1,11 +1,12 @@
 {
 {
   "id": "uni-datetime-picker",
   "id": "uni-datetime-picker",
-  "displayName": "DatetimePicker 日期选择器",
-  "version": "1.0.6",
-  "description": "DatetimePicker 可以同时选择日期和时间的选择器",
+  "displayName": "uni-datetime-picker 日期选择器",
+  "version": "2.2.4",
+  "description": "uni-datetime-picker 日期时间选择器,支持日历,支持范围选择",
   "keywords": [
   "keywords": [
-    "DatetimePicker",
+    "uni-datetime-picker",
     "uni-ui",
     "uni-ui",
+    "uniui",
     "日期时间选择器",
     "日期时间选择器",
     "日期时间"
     "日期时间"
 ],
 ],
@@ -40,7 +41,10 @@
     "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
     "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
   },
   },
   "uni_modules": {
   "uni_modules": {
-    "dependencies": [],
+    "dependencies": [
+			"uni-scss",
+			"uni-icons"
+		],
     "encrypt": [],
     "encrypt": [],
     "platforms": {
     "platforms": {
       "cloud": {
       "cloud": {
@@ -75,8 +79,12 @@
         "快应用": {
         "快应用": {
           "华为": "u",
           "华为": "u",
           "联盟": "u"
           "联盟": "u"
+        },
+        "Vue": {
+            "vue2": "y",
+            "vue3": "y"
         }
         }
       }
       }
     }
     }
   }
   }
-}
+}

+ 9 - 49
uni_modules/uni-datetime-picker/readme.md

@@ -1,6 +1,10 @@
 
 
 
 
+> `重要通知:组件升级更新 2.0.0 后,支持日期+时间范围选择,组件 ui 将使用日历选择日期,ui 变化较大,同时支持 PC 和 移动端。此版本不向后兼容,不再支持单独的时间选择(type=time)及相关的 hide-second 属性(时间选可使用内置组件 picker)。若仍需使用旧版本,可在插件市场下载*非uni_modules版本*,旧版本将不再维护`
+
 ## DatetimePicker 时间选择器
 ## DatetimePicker 时间选择器
+
+> **组件名:uni-datetime-picker**
 > 代码块: `uDatetimePicker`
 > 代码块: `uDatetimePicker`
 
 
 
 
@@ -8,54 +12,10 @@
 
 
 若只是需要单独选择日期和时间,不需要时间戳输入和输出,可使用原生的 picker 组件。
 若只是需要单独选择日期和时间,不需要时间戳输入和输出,可使用原生的 picker 组件。
 
 
+**_点击 picker 默认值规则:_**
 
 
-___点击 picker 默认值规则:___
-
-- 若设置初始值 value, 会显示在 picker 显示框中; 若无初始值 value,则初始值 value 为当前本地时间 Date.now(), 但不会显示在 picker 显示框中
-	- 设置了起始时间 start、终止时间 end,并 start < value < end,初始值为 value, 否则初始值为 start
-	- 只设置了起始时间 start,并 start < value,初始值为 value,否则初始值为 start
-	- 只设置了终止时间 end,并 value < end,初始值为 value,否则初始值为 end
-	- 无起始终止时间,则初始值为 value
-
-### 安装方式
-
-本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
-
-如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
-
-### 基本用法
-
-在 ``template`` 中使用组件
-
-```html
-<uni-datetime-picker></uni-datetime-picker>
-<uni-datetime-picker v-model="vModelDatetime" start="2010-6-10 08:30:30" end="2021-6-10 08:30:30"></uni-datetime-picker>
-<uni-datetime-picker :value="timestamp" return-type="timestamp" start="1276129830000" end="1623285030000" @change="timestampChange"></uni-datetime-picker>
-<uni-datetime-picker type="date" :value="date" start="2020-6-15" end="2025-6-15" @change="dateChange"></uni-datetime-picker>
-<uni-datetime-picker type="time" :value="time" start="06:30:30" end="12:30:30" @change="timeChange"></uni-datetime-picker>
-```
-
-## API
-
-### DatetimePicker Props
-
-|属性名			|类型						|默认值		|值域									|说明																											|
-|:-:				|:-:						|:-:			|											|:-:																											|
-|type				|String					|datetime	|datetime、date、time	|选择器类型																								|
-|value			|String、Number	|-				|-										|输入框当前值																							|
-|start			|String、Number	|-				|-										|最小值,可以使用日期的字符串(String)、时间戳(Number)	|
-|end				|String、Number	|-				|-										|最大值,可以使用日期的字符串(String)、时间戳(Number)	|
-|return-type|String					|timestamp|timestamp 、string		|返回值格式																								|
-|border			|Boolean、String|true			|											|是否有边框																								|
-|hide-second|Boolean、String|false		|											|是否隐藏秒																								|
-|disabled		|Boolean、String|false		|											|是否不可选择																							|
-
-
-
-注:如 type 为 time 类型,无对应的时间戳,则返回值格式 return-type 无论为何值,都会返回 string
-
-### DatetimePicker Events
+- 若设置初始值 value, 会显示在 picker 显示框中
+- 若无初始值 value,则初始值 value 为当前本地时间 Date.now(), 但不会显示在 picker 显示框中
 
 
-|事件名称	|说明																				|返回值	|
-|:-:		|:-:																				|:-:		|
-|change	|确定日期时间时触发的事件,参数为当前选择的 value	|-			|
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-datetime-picker)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 

+ 22 - 0
uni_modules/uni-icons/changelog.md

@@ -0,0 +1,22 @@
+## 1.3.5(2022-01-24)
+- 优化 size 属性可以传入不带单位的字符串数值
+## 1.3.4(2022-01-24)
+- 优化 size 支持其他单位
+## 1.3.3(2022-01-17)
+- 修复 nvue 有些图标不显示的bug,兼容老版本图标
+## 1.3.2(2021-12-01)
+- 优化 示例可复制图标名称
+## 1.3.1(2021-11-23)
+- 优化 兼容旧组件 type 值
+## 1.3.0(2021-11-19)
+- 新增 更多图标
+- 优化 自定义图标使用方式
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-icons](https://uniapp.dcloud.io/component/uniui/uni-icons)
+## 1.1.7(2021-11-08)
+## 1.2.0(2021-07-30)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 1.1.5(2021-05-12)
+- 新增 组件示例地址
+## 1.1.4(2021-02-05)
+- 调整为uni_modules目录规范

Dosya farkı çok büyük olduğundan ihmal edildi
+ 1169 - 0
uni_modules/uni-icons/components/uni-icons/icons.js


+ 96 - 0
uni_modules/uni-icons/components/uni-icons/uni-icons.vue

@@ -0,0 +1,96 @@
+<template>
+	<!-- #ifdef APP-NVUE -->
+	<text :style="{ color: color, 'font-size': iconSize }" class="uni-icons" @click="_onClick">{{unicode}}</text>
+	<!-- #endif -->
+	<!-- #ifndef APP-NVUE -->
+	<text :style="{ color: color, 'font-size': iconSize }" class="uni-icons" :class="['uniui-'+type,customPrefix,customPrefix?type:'']" @click="_onClick"></text>
+	<!-- #endif -->
+</template>
+
+<script>
+	import icons from './icons.js';
+	const getVal = (val) => {
+		const reg = /^[0-9]*$/g
+		return (typeof val === 'number' || reg.test(val) )? val + 'px' : val;
+	} 
+	// #ifdef APP-NVUE
+	var domModule = weex.requireModule('dom');
+	import iconUrl from './uniicons.ttf'
+	domModule.addRule('fontFace', {
+		'fontFamily': "uniicons",
+		'src': "url('"+iconUrl+"')"
+	});
+	// #endif
+
+	/**
+	 * Icons 图标
+	 * @description 用于展示 icons 图标
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=28
+	 * @property {Number} size 图标大小
+	 * @property {String} type 图标图案,参考示例
+	 * @property {String} color 图标颜色
+	 * @property {String} customPrefix 自定义图标
+	 * @event {Function} click 点击 Icon 触发事件
+	 */
+	export default {
+		name: 'UniIcons',
+		emits:['click'],
+		props: {
+			type: {
+				type: String,
+				default: ''
+			},
+			color: {
+				type: String,
+				default: '#333333'
+			},
+			size: {
+				type: [Number, String],
+				default: 16
+			},
+			customPrefix:{
+				type: String,
+				default: ''
+			}
+		},
+		data() {
+			return {
+				icons: icons.glyphs
+			}
+		},
+		computed:{
+			unicode(){
+				let code = this.icons.find(v=>v.font_class === this.type)
+				if(code){
+					return unescape(`%u${code.unicode}`)
+				}
+				return ''
+			},
+			iconSize(){
+				return getVal(this.size)
+			}
+		},
+		methods: {
+			_onClick() {
+				this.$emit('click')
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	/* #ifndef APP-NVUE */
+	@import './uniicons.css';
+	@font-face {
+		font-family: uniicons;
+		src: url('./uniicons.ttf') format('truetype');
+	}
+
+	/* #endif */
+	.uni-icons {
+		font-family: uniicons;
+		text-decoration: none;
+		text-align: center;
+	}
+
+</style>

+ 663 - 0
uni_modules/uni-icons/components/uni-icons/uniicons.css

@@ -0,0 +1,663 @@
+.uniui-color:before {
+  content: "\e6cf";
+}
+
+.uniui-wallet:before {
+  content: "\e6b1";
+}
+
+.uniui-settings-filled:before {
+  content: "\e6ce";
+}
+
+.uniui-auth-filled:before {
+  content: "\e6cc";
+}
+
+.uniui-shop-filled:before {
+  content: "\e6cd";
+}
+
+.uniui-staff-filled:before {
+  content: "\e6cb";
+}
+
+.uniui-vip-filled:before {
+  content: "\e6c6";
+}
+
+.uniui-plus-filled:before {
+  content: "\e6c7";
+}
+
+.uniui-folder-add-filled:before {
+  content: "\e6c8";
+}
+
+.uniui-color-filled:before {
+  content: "\e6c9";
+}
+
+.uniui-tune-filled:before {
+  content: "\e6ca";
+}
+
+.uniui-calendar-filled:before {
+  content: "\e6c0";
+}
+
+.uniui-notification-filled:before {
+  content: "\e6c1";
+}
+
+.uniui-wallet-filled:before {
+  content: "\e6c2";
+}
+
+.uniui-medal-filled:before {
+  content: "\e6c3";
+}
+
+.uniui-gift-filled:before {
+  content: "\e6c4";
+}
+
+.uniui-fire-filled:before {
+  content: "\e6c5";
+}
+
+.uniui-refreshempty:before {
+  content: "\e6bf";
+}
+
+.uniui-location-filled:before {
+  content: "\e6af";
+}
+
+.uniui-person-filled:before {
+  content: "\e69d";
+}
+
+.uniui-personadd-filled:before {
+  content: "\e698";
+}
+
+.uniui-back:before {
+  content: "\e6b9";
+}
+
+.uniui-forward:before {
+  content: "\e6ba";
+}
+
+.uniui-arrow-right:before {
+  content: "\e6bb";
+}
+
+.uniui-arrowthinright:before {
+  content: "\e6bb";
+}
+
+.uniui-arrow-left:before {
+  content: "\e6bc";
+}
+
+.uniui-arrowthinleft:before {
+  content: "\e6bc";
+}
+
+.uniui-arrow-up:before {
+  content: "\e6bd";
+}
+
+.uniui-arrowthinup:before {
+  content: "\e6bd";
+}
+
+.uniui-arrow-down:before {
+  content: "\e6be";
+}
+
+.uniui-arrowthindown:before {
+  content: "\e6be";
+}
+
+.uniui-bottom:before {
+  content: "\e6b8";
+}
+
+.uniui-arrowdown:before {
+  content: "\e6b8";
+}
+
+.uniui-right:before {
+  content: "\e6b5";
+}
+
+.uniui-arrowright:before {
+  content: "\e6b5";
+}
+
+.uniui-top:before {
+  content: "\e6b6";
+}
+
+.uniui-arrowup:before {
+  content: "\e6b6";
+}
+
+.uniui-left:before {
+  content: "\e6b7";
+}
+
+.uniui-arrowleft:before {
+  content: "\e6b7";
+}
+
+.uniui-eye:before {
+  content: "\e651";
+}
+
+.uniui-eye-filled:before {
+  content: "\e66a";
+}
+
+.uniui-eye-slash:before {
+  content: "\e6b3";
+}
+
+.uniui-eye-slash-filled:before {
+  content: "\e6b4";
+}
+
+.uniui-info-filled:before {
+  content: "\e649";
+}
+
+.uniui-reload:before {
+  content: "\e6b2";
+}
+
+.uniui-micoff-filled:before {
+  content: "\e6b0";
+}
+
+.uniui-map-pin-ellipse:before {
+  content: "\e6ac";
+}
+
+.uniui-map-pin:before {
+  content: "\e6ad";
+}
+
+.uniui-location:before {
+  content: "\e6ae";
+}
+
+.uniui-starhalf:before {
+  content: "\e683";
+}
+
+.uniui-star:before {
+  content: "\e688";
+}
+
+.uniui-star-filled:before {
+  content: "\e68f";
+}
+
+.uniui-calendar:before {
+  content: "\e6a0";
+}
+
+.uniui-fire:before {
+  content: "\e6a1";
+}
+
+.uniui-medal:before {
+  content: "\e6a2";
+}
+
+.uniui-font:before {
+  content: "\e6a3";
+}
+
+.uniui-gift:before {
+  content: "\e6a4";
+}
+
+.uniui-link:before {
+  content: "\e6a5";
+}
+
+.uniui-notification:before {
+  content: "\e6a6";
+}
+
+.uniui-staff:before {
+  content: "\e6a7";
+}
+
+.uniui-vip:before {
+  content: "\e6a8";
+}
+
+.uniui-folder-add:before {
+  content: "\e6a9";
+}
+
+.uniui-tune:before {
+  content: "\e6aa";
+}
+
+.uniui-auth:before {
+  content: "\e6ab";
+}
+
+.uniui-person:before {
+  content: "\e699";
+}
+
+.uniui-email-filled:before {
+  content: "\e69a";
+}
+
+.uniui-phone-filled:before {
+  content: "\e69b";
+}
+
+.uniui-phone:before {
+  content: "\e69c";
+}
+
+.uniui-email:before {
+  content: "\e69e";
+}
+
+.uniui-personadd:before {
+  content: "\e69f";
+}
+
+.uniui-chatboxes-filled:before {
+  content: "\e692";
+}
+
+.uniui-contact:before {
+  content: "\e693";
+}
+
+.uniui-chatbubble-filled:before {
+  content: "\e694";
+}
+
+.uniui-contact-filled:before {
+  content: "\e695";
+}
+
+.uniui-chatboxes:before {
+  content: "\e696";
+}
+
+.uniui-chatbubble:before {
+  content: "\e697";
+}
+
+.uniui-upload-filled:before {
+  content: "\e68e";
+}
+
+.uniui-upload:before {
+  content: "\e690";
+}
+
+.uniui-weixin:before {
+  content: "\e691";
+}
+
+.uniui-compose:before {
+  content: "\e67f";
+}
+
+.uniui-qq:before {
+  content: "\e680";
+}
+
+.uniui-download-filled:before {
+  content: "\e681";
+}
+
+.uniui-pyq:before {
+  content: "\e682";
+}
+
+.uniui-sound:before {
+  content: "\e684";
+}
+
+.uniui-trash-filled:before {
+  content: "\e685";
+}
+
+.uniui-sound-filled:before {
+  content: "\e686";
+}
+
+.uniui-trash:before {
+  content: "\e687";
+}
+
+.uniui-videocam-filled:before {
+  content: "\e689";
+}
+
+.uniui-spinner-cycle:before {
+  content: "\e68a";
+}
+
+.uniui-weibo:before {
+  content: "\e68b";
+}
+
+.uniui-videocam:before {
+  content: "\e68c";
+}
+
+.uniui-download:before {
+  content: "\e68d";
+}
+
+.uniui-help:before {
+  content: "\e679";
+}
+
+.uniui-navigate-filled:before {
+  content: "\e67a";
+}
+
+.uniui-plusempty:before {
+  content: "\e67b";
+}
+
+.uniui-smallcircle:before {
+  content: "\e67c";
+}
+
+.uniui-minus-filled:before {
+  content: "\e67d";
+}
+
+.uniui-micoff:before {
+  content: "\e67e";
+}
+
+.uniui-closeempty:before {
+  content: "\e66c";
+}
+
+.uniui-clear:before {
+  content: "\e66d";
+}
+
+.uniui-navigate:before {
+  content: "\e66e";
+}
+
+.uniui-minus:before {
+  content: "\e66f";
+}
+
+.uniui-image:before {
+  content: "\e670";
+}
+
+.uniui-mic:before {
+  content: "\e671";
+}
+
+.uniui-paperplane:before {
+  content: "\e672";
+}
+
+.uniui-close:before {
+  content: "\e673";
+}
+
+.uniui-help-filled:before {
+  content: "\e674";
+}
+
+.uniui-paperplane-filled:before {
+  content: "\e675";
+}
+
+.uniui-plus:before {
+  content: "\e676";
+}
+
+.uniui-mic-filled:before {
+  content: "\e677";
+}
+
+.uniui-image-filled:before {
+  content: "\e678";
+}
+
+.uniui-locked-filled:before {
+  content: "\e668";
+}
+
+.uniui-info:before {
+  content: "\e669";
+}
+
+.uniui-locked:before {
+  content: "\e66b";
+}
+
+.uniui-camera-filled:before {
+  content: "\e658";
+}
+
+.uniui-chat-filled:before {
+  content: "\e659";
+}
+
+.uniui-camera:before {
+  content: "\e65a";
+}
+
+.uniui-circle:before {
+  content: "\e65b";
+}
+
+.uniui-checkmarkempty:before {
+  content: "\e65c";
+}
+
+.uniui-chat:before {
+  content: "\e65d";
+}
+
+.uniui-circle-filled:before {
+  content: "\e65e";
+}
+
+.uniui-flag:before {
+  content: "\e65f";
+}
+
+.uniui-flag-filled:before {
+  content: "\e660";
+}
+
+.uniui-gear-filled:before {
+  content: "\e661";
+}
+
+.uniui-home:before {
+  content: "\e662";
+}
+
+.uniui-home-filled:before {
+  content: "\e663";
+}
+
+.uniui-gear:before {
+  content: "\e664";
+}
+
+.uniui-smallcircle-filled:before {
+  content: "\e665";
+}
+
+.uniui-map-filled:before {
+  content: "\e666";
+}
+
+.uniui-map:before {
+  content: "\e667";
+}
+
+.uniui-refresh-filled:before {
+  content: "\e656";
+}
+
+.uniui-refresh:before {
+  content: "\e657";
+}
+
+.uniui-cloud-upload:before {
+  content: "\e645";
+}
+
+.uniui-cloud-download-filled:before {
+  content: "\e646";
+}
+
+.uniui-cloud-download:before {
+  content: "\e647";
+}
+
+.uniui-cloud-upload-filled:before {
+  content: "\e648";
+}
+
+.uniui-redo:before {
+  content: "\e64a";
+}
+
+.uniui-images-filled:before {
+  content: "\e64b";
+}
+
+.uniui-undo-filled:before {
+  content: "\e64c";
+}
+
+.uniui-more:before {
+  content: "\e64d";
+}
+
+.uniui-more-filled:before {
+  content: "\e64e";
+}
+
+.uniui-undo:before {
+  content: "\e64f";
+}
+
+.uniui-images:before {
+  content: "\e650";
+}
+
+.uniui-paperclip:before {
+  content: "\e652";
+}
+
+.uniui-settings:before {
+  content: "\e653";
+}
+
+.uniui-search:before {
+  content: "\e654";
+}
+
+.uniui-redo-filled:before {
+  content: "\e655";
+}
+
+.uniui-list:before {
+  content: "\e644";
+}
+
+.uniui-mail-open-filled:before {
+  content: "\e63a";
+}
+
+.uniui-hand-down-filled:before {
+  content: "\e63c";
+}
+
+.uniui-hand-down:before {
+  content: "\e63d";
+}
+
+.uniui-hand-up-filled:before {
+  content: "\e63e";
+}
+
+.uniui-hand-up:before {
+  content: "\e63f";
+}
+
+.uniui-heart-filled:before {
+  content: "\e641";
+}
+
+.uniui-mail-open:before {
+  content: "\e643";
+}
+
+.uniui-heart:before {
+  content: "\e639";
+}
+
+.uniui-loop:before {
+  content: "\e633";
+}
+
+.uniui-pulldown:before {
+  content: "\e632";
+}
+
+.uniui-scan:before {
+  content: "\e62a";
+}
+
+.uniui-bars:before {
+  content: "\e627";
+}
+
+.uniui-cart-filled:before {
+  content: "\e629";
+}
+
+.uniui-checkbox:before {
+  content: "\e62b";
+}
+
+.uniui-checkbox-filled:before {
+  content: "\e62c";
+}
+
+.uniui-shop:before {
+  content: "\e62f";
+}
+
+.uniui-headphones:before {
+  content: "\e630";
+}
+
+.uniui-cart:before {
+  content: "\e631";
+}

BIN
uni_modules/uni-icons/components/uni-icons/uniicons.ttf


+ 86 - 0
uni_modules/uni-icons/package.json

@@ -0,0 +1,86 @@
+{
+  "id": "uni-icons",
+  "displayName": "uni-icons 图标",
+  "version": "1.3.5",
+  "description": "图标组件,用于展示移动端常见的图标,可自定义颜色、大小。",
+  "keywords": [
+    "uni-ui",
+    "uniui",
+    "icon",
+    "图标"
+],
+  "repository": "https://github.com/dcloudio/uni-ui",
+  "engines": {
+    "HBuilderX": "^3.2.14"
+  },
+  "directories": {
+    "example": "../../temps/example_temps"
+  },
+  "dcloudext": {
+    "category": [
+      "前端组件",
+      "通用组件"
+    ],
+    "sale": {
+      "regular": {
+        "price": "0.00"
+      },
+      "sourcecode": {
+        "price": "0.00"
+      }
+    },
+    "contact": {
+      "qq": ""
+    },
+    "declaration": {
+      "ads": "无",
+      "data": "无",
+      "permissions": "无"
+    },
+    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+  },
+  "uni_modules": {
+    "dependencies": ["uni-scss"],
+    "encrypt": [],
+    "platforms": {
+      "cloud": {
+        "tcb": "y",
+        "aliyun": "y"
+      },
+      "client": {
+        "App": {
+          "app-vue": "y",
+          "app-nvue": "y"
+        },
+        "H5-mobile": {
+          "Safari": "y",
+          "Android Browser": "y",
+          "微信浏览器(Android)": "y",
+          "QQ浏览器(Android)": "y"
+        },
+        "H5-pc": {
+          "Chrome": "y",
+          "IE": "y",
+          "Edge": "y",
+          "Firefox": "y",
+          "Safari": "y"
+        },
+        "小程序": {
+          "微信": "y",
+          "阿里": "y",
+          "百度": "y",
+          "字节跳动": "y",
+          "QQ": "y"
+        },
+        "快应用": {
+          "华为": "u",
+          "联盟": "u"
+        },
+        "Vue": {
+            "vue2": "y",
+            "vue3": "y"
+        }
+      }
+    }
+  }
+}

+ 8 - 0
uni_modules/uni-icons/readme.md

@@ -0,0 +1,8 @@
+## Icons 图标
+> **组件名:uni-icons**
+> 代码块: `uIcons`
+
+用于展示 icons 图标 。
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-icons)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 

+ 20 - 0
uni_modules/uni-list/changelog.md

@@ -0,0 +1,20 @@
+## 1.2.1(2022-03-30)
+- 删除无用文件
+## 1.2.0(2021-11-23)
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-list](https://uniapp.dcloud.io/component/uniui/uni-list)
+## 1.1.3(2021-08-30)
+- 修复 在vue3中to属性在发行应用的时候报错的bug
+## 1.1.2(2021-07-30)
+- 优化 vue3下事件警告的问题
+## 1.1.1(2021-07-21)
+- 修复 与其他组件嵌套使用时,点击失效的Bug
+## 1.1.0(2021-07-13)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 1.0.17(2021-05-12)
+- 新增 组件示例地址
+## 1.0.16(2021-02-05)
+- 优化 组件引用关系,通过uni_modules引用组件
+## 1.0.15(2021-02-05)
+- 调整为uni_modules目录规范
+- 修复 uni-list-chat 角标显示不正常的问题

+ 107 - 0
uni_modules/uni-list/components/uni-list-ad/uni-list-ad.vue

@@ -0,0 +1,107 @@
+<template>
+	<!-- #ifdef APP-NVUE -->
+	<cell>
+		<!-- #endif -->
+		<view class="uni-list-ad">
+			<view v-if="borderShow" :class="{'uni-list--border':border,'uni-list-item--first':isFirstChild}"></view>
+			<ad style="width: 200px;height: 300px;border-width: 1px;border-color: red;border-style: solid;" adpid="1111111111"
+			 unit-id="" appid="" apid="" type="feed" @error="aderror" @close="closeAd"></ad>
+		</view>
+		<!-- #ifdef APP-NVUE -->
+	</cell>
+	<!-- #endif -->
+
+</template>
+
+<script>
+	// #ifdef APP-NVUE
+	const dom = uni.requireNativePlugin('dom');
+	// #endif
+	export default {
+		name: 'UniListAd',
+		props: {
+			title: {
+				type: String,
+				default: '',
+
+			}
+		},
+		// inject: ['list'],
+		data() {
+			return {
+				isFirstChild: false,
+				border: false,
+				borderShow: true,
+			}
+		},
+
+		mounted() {
+			this.list = this.getForm()
+			if (this.list) {
+				if (!this.list.firstChildAppend) {
+					this.list.firstChildAppend = true
+					this.isFirstChild = true
+				}
+				this.border = this.list.border
+			}
+		},
+		methods: {
+			/**
+			 * 获取父元素实例
+			 */
+			getForm(name = 'uniList') {
+				let parent = this.$parent;
+				let parentName = parent.$options.name;
+				while (parentName !== name) {
+					parent = parent.$parent;
+					if (!parent) return false
+					parentName = parent.$options.name;
+				}
+				return parent;
+			},
+			aderror(e) {
+				console.log("aderror: " + JSON.stringify(e.detail));
+			},
+			closeAd(e) {
+				this.borderShow = false
+			}
+		}
+	}
+</script>
+
+<style lang="scss" >
+	.uni-list-ad {
+		position: relative;
+		border: 1px red solid;
+	}
+
+	.uni-list--border {
+		position: relative;
+		padding-bottom: 1px;
+		/* #ifdef APP-PLUS */
+		border-top-color: $uni-border-color;
+		border-top-style: solid;
+		border-top-width: 0.5px;
+		/* #endif */
+		margin-left: $uni-spacing-row-lg;
+	}
+
+	/* #ifndef APP-NVUE */
+	.uni-list--border:after {
+		position: absolute;
+		top: 0;
+		right: 0;
+		left: 0;
+		height: 1px;
+		content: '';
+		-webkit-transform: scaleY(.5);
+		transform: scaleY(.5);
+		background-color: $uni-border-color;
+	}
+
+	.uni-list-item--first:after {
+		height: 0px;
+	}
+
+	/* #endif */
+</style>

+ 58 - 0
uni_modules/uni-list/components/uni-list-chat/uni-list-chat.scss

@@ -0,0 +1,58 @@
+/**
+ * 这里是 uni-list 组件内置的常用样式变量
+ * 如果需要覆盖样式,这里提供了基本的组件样式变量,您可以尝试修改这里的变量,去完成样式替换,而不用去修改源码
+ *
+ */
+
+// 背景色
+$background-color : #fff;
+// 分割线颜色
+$divide-line-color : #e5e5e5;
+
+// 默认头像大小,如需要修改此值,注意同步修改 js 中的值 const avatarWidth = xx ,目前只支持方形头像
+// nvue 页面不支持修改头像大小
+$avatar-width : 45px ;
+
+// 头像边框
+$avatar-border-radius: 5px;
+$avatar-border-color: #eee;
+$avatar-border-width: 1px;
+
+// 标题文字样式
+$title-size : 16px;
+$title-color : #3b4144;
+$title-weight : normal;
+
+// 描述文字样式
+$note-size : 12px;
+$note-color : #999;
+$note-weight : normal;
+
+// 右侧额外内容默认样式
+$right-text-size : 12px;
+$right-text-color : #999;
+$right-text-weight : normal;
+
+// 角标样式
+// nvue 页面不支持修改圆点位置以及大小
+// 角标在左侧时,角标的位置,默认为 0 ,负数左/下移动,正数右/上移动
+$badge-left: 0px;
+$badge-top: 0px;
+
+// 显示圆点时,圆点大小
+$dot-width: 10px;
+$dot-height: 10px;
+
+// 显示角标时,角标大小和字体大小
+$badge-size : 18px;
+$badge-font : 12px;
+// 显示角标时,角标前景色
+$badge-color : #fff;
+// 显示角标时,角标背景色
+$badge-background-color : #ff5a5f;
+// 显示角标时,角标左右间距
+$badge-space : 6px;
+
+// 状态样式
+// 选中颜色
+$hover : #f5f5f5;

+ 538 - 0
uni_modules/uni-list/components/uni-list-chat/uni-list-chat.vue

@@ -0,0 +1,538 @@
+<template>
+	<!-- #ifdef APP-NVUE -->
+	<cell>
+		<!-- #endif -->
+		<view :hover-class="!clickable && !link ? '' : 'uni-list-chat--hover'" class="uni-list-chat" @click.stop="onClick">
+			<view :class="{ 'uni-list--border': border, 'uni-list-chat--first': isFirstChild }"></view>
+			<view class="uni-list-chat__container">
+				<view class="uni-list-chat__header-warp">
+					<view v-if="avatarCircle || avatarList.length === 0" class="uni-list-chat__header" :class="{ 'header--circle': avatarCircle }">
+						<image class="uni-list-chat__header-image" :class="{ 'header--circle': avatarCircle }" :src="avatar" mode="aspectFill"></image>
+					</view>
+					<!-- 头像组 -->
+					<view v-else class="uni-list-chat__header">
+						<view v-for="(item, index) in avatarList" :key="index" class="uni-list-chat__header-box" :class="computedAvatar"
+						 :style="{ width: imageWidth + 'px', height: imageWidth + 'px' }">
+							<image class="uni-list-chat__header-image" :style="{ width: imageWidth + 'px', height: imageWidth + 'px' }" :src="item.url"
+							 mode="aspectFill"></image>
+						</view>
+					</view>
+				</view>
+				<view v-if="badgeText && badgePositon === 'left'" class="uni-list-chat__badge uni-list-chat__badge-pos" :class="[isSingle]">
+					<text class="uni-list-chat__badge-text">{{ badgeText === 'dot' ? '' : badgeText }}</text>
+				</view>
+				<view class="uni-list-chat__content">
+					<view class="uni-list-chat__content-main">
+						<text class="uni-list-chat__content-title uni-ellipsis">{{ title }}</text>
+						<text class="uni-list-chat__content-note uni-ellipsis">{{ note }}</text>
+					</view>
+					<view class="uni-list-chat__content-extra">
+						<slot>
+							<text class="uni-list-chat__content-extra-text">{{ time }}</text>
+							<view v-if="badgeText && badgePositon === 'right'" class="uni-list-chat__badge" :class="[isSingle, badgePositon === 'right' ? 'uni-list-chat--right' : '']">
+								<text class="uni-list-chat__badge-text">{{ badgeText === 'dot' ? '' : badgeText }}</text>
+							</view>
+						</slot>
+					</view>
+				</view>
+			</view>
+		</view>
+		<!-- #ifdef APP-NVUE -->
+	</cell>
+	<!-- #endif -->
+</template>
+
+<script>
+	// 头像大小
+	const avatarWidth = 45;
+
+	/**
+	 * ListChat 聊天列表
+	 * @description 聊天列表,用于创建聊天类列表
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=24
+	 * @property {String} 	title 							标题
+	 * @property {String} 	note 							描述
+	 * @property {Boolean} 	clickable = [true|false] 		是否开启点击反馈,默认为false
+	 * @property {String} 	badgeText						数字角标内容
+	 * @property {String}  	badgePositon = [left|right]		角标位置,默认为 right
+	 * @property {String} 	link = [false|navigateTo|redirectTo|reLaunch|switchTab] 是否展示右侧箭头并开启点击反馈,默认为false
+	 *  @value false	 	不开启
+	 *  @value navigateTo 	同 uni.navigateTo()
+	 * 	@value redirectTo 	同 uni.redirectTo()
+	 * 	@value reLaunch   	同 uni.reLaunch()
+	 * 	@value switchTab  	同 uni.switchTab()
+	 * @property {String | PageURIString} 	to  			跳转目标页面
+	 * @property {String} 	time							右侧时间显示
+	 * @property {Boolean} 	avatarCircle = [true|false]		是否显示圆形头像,默认为false
+	 * @property {String} 	avatar							头像地址,avatarCircle 不填时生效
+	 * @property {Array} 	avatarList 						头像组,格式为 [{url:''}]
+	 * @event {Function} 	click 							点击 uniListChat 触发事件
+	 */
+	export default {
+		name: 'UniListChat',
+		emits:['click'],
+		props: {
+			title: {
+				type: String,
+				default: ''
+			},
+			note: {
+				type: String,
+				default: ''
+			},
+			clickable: {
+				type: Boolean,
+				default: false
+			},
+			link: {
+				type: [Boolean, String],
+				default: false
+			},
+			to: {
+				type: String,
+				default: ''
+			},
+			badgeText: {
+				type: [String, Number],
+				default: ''
+			},
+			badgePositon: {
+				type: String,
+				default: 'right'
+			},
+			time: {
+				type: String,
+				default: ''
+			},
+			avatarCircle: {
+				type: Boolean,
+				default: false
+			},
+			avatar: {
+				type: String,
+				default: ''
+			},
+			avatarList: {
+				type: Array,
+				default () {
+					return [];
+				}
+			}
+		},
+		// inject: ['list'],
+		computed: {
+			isSingle() {
+				if (this.badgeText === 'dot') {
+					return 'uni-badge--dot';
+				} else {
+					const badgeText = this.badgeText.toString();
+					if (badgeText.length > 1) {
+						return 'uni-badge--complex';
+					} else {
+						return 'uni-badge--single';
+					}
+				}
+			},
+			computedAvatar() {
+				if (this.avatarList.length > 4) {
+					this.imageWidth = avatarWidth * 0.31;
+					return 'avatarItem--3';
+				} else if (this.avatarList.length > 1) {
+					this.imageWidth = avatarWidth * 0.47;
+					return 'avatarItem--2';
+				} else {
+					this.imageWidth = avatarWidth;
+					return 'avatarItem--1';
+				}
+			}
+		},
+		data() {
+			return {
+				isFirstChild: false,
+				border: true,
+				// avatarList: 3,
+				imageWidth: 50
+			};
+		},
+		mounted() {
+			this.list = this.getForm()
+			if (this.list) {
+				if (!this.list.firstChildAppend) {
+					this.list.firstChildAppend = true;
+					this.isFirstChild = true;
+				}
+				this.border = this.list.border;
+			}
+		},
+		methods: {
+			/**
+			 * 获取父元素实例
+			 */
+			getForm(name = 'uniList') {
+				let parent = this.$parent;
+				let parentName = parent.$options.name;
+				while (parentName !== name) {
+					parent = parent.$parent;
+					if (!parent) return false
+					parentName = parent.$options.name;
+				}
+				return parent;
+			},
+			onClick() {
+				if (this.to !== '') {
+					this.openPage();
+					return;
+				}
+
+				if (this.clickable || this.link) {
+					this.$emit('click', {
+						data: {}
+					});
+				}
+			},
+			openPage() {
+				if (['navigateTo', 'redirectTo', 'reLaunch', 'switchTab'].indexOf(this.link) !== -1) {
+					this.pageApi(this.link);
+				} else {
+					this.pageApi('navigateTo');
+				}
+			},
+			pageApi(api) {
+				uni[api]({
+					url: this.to,
+					success: res => {
+						this.$emit('click', {
+							data: res
+						});
+					},
+					fail: err => {
+						this.$emit('click', {
+							data: err
+						});
+						console.error(err.errMsg);
+					}
+				});
+			}
+		}
+	};
+</script>
+
+<style lang="scss" >
+	$uni-font-size-lg:16px;
+	$uni-spacing-row-sm: 5px;
+	$uni-spacing-row-base: 10px;
+	$uni-spacing-row-lg: 15px;
+	$background-color: #fff;
+	$divide-line-color: #e5e5e5;
+	$avatar-width: 45px;
+	$avatar-border-radius: 5px;
+	$avatar-border-color: #eee;
+	$avatar-border-width: 1px;
+	$title-size: 16px;
+	$title-color: #3b4144;
+	$title-weight: normal;
+	$note-size: 12px;
+	$note-color: #999;
+	$note-weight: normal;
+	$right-text-size: 12px;
+	$right-text-color: #999;
+	$right-text-weight: normal;
+	$badge-left: 0px;
+	$badge-top: 0px;
+	$dot-width: 10px;
+	$dot-height: 10px;
+	$badge-size: 18px;
+	$badge-font: 12px;
+	$badge-color: #fff;
+	$badge-background-color: #ff5a5f;
+	$badge-space: 6px;
+	$hover: #f5f5f5;
+
+	.uni-list-chat {
+		font-size: $uni-font-size-lg;
+		position: relative;
+		flex-direction: column;
+		justify-content: space-between;
+		background-color: $background-color;
+	}
+
+	// .uni-list-chat--disabled {
+	// 	opacity: 0.3;
+	// }
+
+	.uni-list-chat--hover {
+		background-color: $hover;
+	}
+
+	.uni-list--border {
+		position: relative;
+		margin-left: $uni-spacing-row-lg;
+		/* #ifdef APP-PLUS */
+		border-top-color: $divide-line-color;
+		border-top-style: solid;
+		border-top-width: 0.5px;
+		/* #endif */
+	}
+
+	/* #ifndef APP-NVUE */
+	.uni-list--border:after {
+		position: absolute;
+		top: 0;
+		right: 0;
+		left: 0;
+		height: 1px;
+		content: '';
+		-webkit-transform: scaleY(0.5);
+		transform: scaleY(0.5);
+		background-color: $divide-line-color;
+	}
+
+	.uni-list-item--first:after {
+		height: 0px;
+	}
+
+	/* #endif */
+
+	.uni-list-chat--first {
+		border-top-width: 0px;
+	}
+
+	.uni-ellipsis {
+		/* #ifndef APP-NVUE */
+		overflow: hidden;
+		white-space: nowrap;
+		text-overflow: ellipsis;
+		/* #endif */
+		/* #ifdef APP-NVUE */
+		lines: 1;
+		/* #endif */
+	}
+
+	.uni-ellipsis-2 {
+		/* #ifndef APP-NVUE */
+		overflow: hidden;
+		text-overflow: ellipsis;
+		display: -webkit-box;
+		-webkit-line-clamp: 2;
+		-webkit-box-orient: vertical;
+		/* #endif */
+
+		/* #ifdef APP-NVUE */
+		lines: 2;
+		/* #endif */
+	}
+
+	.uni-list-chat__container {
+		position: relative;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		flex: 1;
+		padding: $uni-spacing-row-base $uni-spacing-row-lg;
+		position: relative;
+		overflow: hidden;
+	}
+
+	.uni-list-chat__header-warp {
+		position: relative;
+	}
+
+	.uni-list-chat__header {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		align-content: center;
+		/* #endif */
+		flex-direction: row;
+		justify-content: center;
+		align-items: center;
+		flex-wrap: wrap-reverse;
+		/* #ifdef APP-NVUE */
+		width: 50px;
+		height: 50px;
+		/* #endif */
+		/* #ifndef APP-NVUE */
+		width: $avatar-width;
+		height: $avatar-width;
+		/* #endif */
+
+		border-radius: $avatar-border-radius;
+		border-color: $avatar-border-color;
+		border-width: $avatar-border-width;
+		border-style: solid;
+		overflow: hidden;
+	}
+
+	.uni-list-chat__header-box {
+		/* #ifndef APP-PLUS */
+		box-sizing: border-box;
+		display: flex;
+		width: $avatar-width;
+		height: $avatar-width;
+		/* #endif */
+		/* #ifdef APP-NVUE */
+		width: 50px;
+		height: 50px;
+		/* #endif */
+		overflow: hidden;
+		border-radius: 2px;
+	}
+
+	.uni-list-chat__header-image {
+		margin: 1px;
+		/* #ifdef APP-NVUE */
+		width: 50px;
+		height: 50px;
+		/* #endif */
+		/* #ifndef APP-NVUE */
+		width: $avatar-width;
+		height: $avatar-width;
+		/* #endif */
+	}
+
+	/* #ifndef APP-NVUE */
+	.uni-list-chat__header-image {
+		display: block;
+		width: 100%;
+		height: 100%;
+	}
+
+	.avatarItem--1 {
+		width: 100%;
+		height: 100%;
+	}
+
+	.avatarItem--2 {
+		width: 47%;
+		height: 47%;
+	}
+
+	.avatarItem--3 {
+		width: 32%;
+		height: 32%;
+	}
+
+	/* #endif */
+	.header--circle {
+		border-radius: 50%;
+	}
+
+	.uni-list-chat__content {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		flex: 1;
+		overflow: hidden;
+		padding: 2px 0;
+	}
+
+	.uni-list-chat__content-main {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: column;
+		justify-content: space-between;
+		padding-left: $uni-spacing-row-base;
+		flex: 1;
+		overflow: hidden;
+	}
+
+	.uni-list-chat__content-title {
+		font-size: $title-size;
+		color: $title-color;
+		font-weight: $title-weight;
+		overflow: hidden;
+	}
+
+	.uni-list-chat__content-note {
+		margin-top: 3px;
+		color: $note-color;
+		font-size: $note-size;
+		font-weight: $title-weight;
+		overflow: hidden;
+	}
+
+	.uni-list-chat__content-extra {
+		/* #ifndef APP-NVUE */
+		flex-shrink: 0;
+		display: flex;
+		/* #endif */
+		flex-direction: column;
+		justify-content: space-between;
+		align-items: flex-end;
+		margin-left: 5px;
+	}
+
+	.uni-list-chat__content-extra-text {
+		color: $right-text-color;
+		font-size: $right-text-size;
+		font-weight: $right-text-weight;
+		overflow: hidden;
+	}
+
+	.uni-list-chat__badge-pos {
+		position: absolute;
+		/* #ifdef APP-NVUE */
+		left: 55px;
+		top: 3px;
+		/* #endif */
+		/* #ifndef APP-NVUE */
+		left: calc(#{$avatar-width} + 10px - #{$badge-space} + #{$badge-left});
+		top: calc(#{$uni-spacing-row-base}/ 2 + 1px + #{$badge-top});
+		/* #endif */
+	}
+
+	.uni-list-chat__badge {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		justify-content: center;
+		align-items: center;
+		border-radius: 100px;
+		background-color: $badge-background-color;
+	}
+
+	.uni-list-chat__badge-text {
+		color: $badge-color;
+		font-size: $badge-font;
+	}
+
+	.uni-badge--single {
+		/* #ifndef APP-NVUE */
+		// left: calc(#{$avatar-width} + 7px + #{$badge-left});
+		/* #endif */
+		width: $badge-size;
+		height: $badge-size;
+	}
+
+	.uni-badge--complex {
+		/* #ifdef APP-NVUE */
+		left: 50px;
+		/* #endif */
+		/* #ifndef APP-NVUE */
+		width: auto;
+		/* #endif */
+		height: $badge-size;
+		padding: 0 $badge-space;
+	}
+
+	.uni-badge--dot {
+		/* #ifdef APP-NVUE */
+		left: 60px;
+		top: 6px;
+		/* #endif */
+		/* #ifndef APP-NVUE */
+		left: calc(#{$avatar-width} + 15px - #{$dot-width}/ 2 + 1px + #{$badge-left});
+		/* #endif */
+		width: $dot-width;
+		height: $dot-height;
+		padding: 0;
+	}
+
+	.uni-list-chat--right {
+		/* #ifdef APP-NVUE */
+		left: 0;
+		/* #endif */
+	}
+</style>

+ 454 - 0
uni_modules/uni-list/components/uni-list-item/uni-list-item.vue

@@ -0,0 +1,454 @@
+<template>
+	<!-- #ifdef APP-NVUE -->
+	<cell>
+		<!-- #endif -->
+
+		<view :class="{ 'uni-list-item--disabled': disabled }"
+			:hover-class="(!clickable && !link) || disabled || showSwitch ? '' : 'uni-list-item--hover'"
+			class="uni-list-item" @click="onClick">
+			<view v-if="!isFirstChild" class="border--left" :class="{ 'uni-list--border': border }"></view>
+			<view class="uni-list-item__container"
+				:class="{ 'container--right': showArrow || link, 'flex--direction': direction === 'column' }">
+				<slot name="header">
+					<view class="uni-list-item__header">
+						<view v-if="thumb" class="uni-list-item__icon">
+							<image :src="thumb" class="uni-list-item__icon-img" :class="['uni-list--' + thumbSize]" />
+						</view>
+						<view v-else-if="showExtraIcon" class="uni-list-item__icon">
+							<uni-icons :color="extraIcon.color" :size="extraIcon.size" :type="extraIcon.type" />
+						</view>
+					</view>
+				</slot>
+				<slot name="body">
+					<view class="uni-list-item__content"
+						:class="{ 'uni-list-item__content--center': thumb || showExtraIcon || showBadge || showSwitch }">
+						<text v-if="title" class="uni-list-item__content-title"
+							:class="[ellipsis !== 0 && ellipsis <= 2 ? 'uni-ellipsis-' + ellipsis : '']">{{ title }}</text>
+						<text v-if="note" class="uni-list-item__content-note">{{ note }}</text>
+					</view>
+				</slot>
+				<slot name="footer">
+					<view v-if="rightText || showBadge || showSwitch" class="uni-list-item__extra"
+						:class="{ 'flex--justify': direction === 'column' }">
+						<text v-if="rightText" class="uni-list-item__extra-text">{{ rightText }}</text>
+						<uni-badge v-if="showBadge" :type="badgeType" :text="badgeText" :custom-style="badgeStyle" />
+						<switch v-if="showSwitch" :disabled="disabled" :checked="switchChecked"
+							@change="onSwitchChange" />
+					</view>
+				</slot>
+			</view>
+			<uni-icons v-if="showArrow || link" :size="16" class="uni-icon-wrapper" color="#bbb" type="arrowright" />
+		</view>
+		<!-- #ifdef APP-NVUE -->
+	</cell>
+	<!-- #endif -->
+</template>
+
+<script>
+	/**
+	 * ListItem 列表子组件
+	 * @description 列表子组件
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=24
+	 * @property {String} 	title 							标题
+	 * @property {String} 	note 							描述
+	 * @property {String} 	thumb 							左侧缩略图,若thumb有值,则不会显示扩展图标
+	 * @property {String}  	thumbSize = [lg|base|sm]		略缩图大小
+	 * 	@value 	 lg			大图
+	 * 	@value 	 base		一般
+	 * 	@value 	 sm			小图
+	 * @property {String} 	badgeText						数字角标内容
+	 * @property {String} 	badgeType 						数字角标类型,参考[uni-icons](https://ext.dcloud.net.cn/plugin?id=21)
+	 * @property {Object}   badgeStyle           数字角标样式
+	 * @property {String} 	rightText 						右侧文字内容
+	 * @property {Boolean} 	disabled = [true|false]			是否禁用
+	 * @property {Boolean} 	clickable = [true|false] 		是否开启点击反馈
+	 * @property {String} 	link = [navigateTo|redirectTo|reLaunch|switchTab] 是否展示右侧箭头并开启点击反馈
+	 *  @value 	navigateTo 	同 uni.navigateTo()
+	 * 	@value redirectTo 	同 uni.redirectTo()
+	 * 	@value reLaunch   	同 uni.reLaunch()
+	 * 	@value switchTab  	同 uni.switchTab()
+	 * @property {String | PageURIString} 	to  			跳转目标页面
+	 * @property {Boolean} 	showBadge = [true|false] 		是否显示数字角标
+	 * @property {Boolean} 	showSwitch = [true|false] 		是否显示Switch
+	 * @property {Boolean} 	switchChecked = [true|false] 	Switch是否被选中
+	 * @property {Boolean} 	showExtraIcon = [true|false] 	左侧是否显示扩展图标
+	 * @property {Object} 	extraIcon 						扩展图标参数,格式为 {color: '#4cd964',size: '22',type: 'spinner'}
+	 * @property {String} 	direction = [row|column]		排版方向
+	 * @value row 			水平排列
+	 * @value column 		垂直排列
+	 * @event {Function} 	click 							点击 uniListItem 触发事件
+	 * @event {Function} 	switchChange 					点击切换 Switch 时触发
+	 */
+	export default {
+		name: 'UniListItem',
+		emits: ['click', 'switchChange'],
+		props: {
+			direction: {
+				type: String,
+				default: 'row'
+			},
+			title: {
+				type: String,
+				default: ''
+			},
+			note: {
+				type: String,
+				default: ''
+			},
+			ellipsis: {
+				type: [Number,String],
+				default: 0
+			},
+			disabled: {
+				type: [Boolean, String],
+				default: false
+			},
+			clickable: {
+				type: Boolean,
+				default: false
+			},
+			showArrow: {
+				type: [Boolean, String],
+				default: false
+			},
+			link: {
+				type: [Boolean, String],
+				default: false
+			},
+			to: {
+				type: String,
+				default: ''
+			},
+			showBadge: {
+				type: [Boolean, String],
+				default: false
+			},
+			showSwitch: {
+				type: [Boolean, String],
+				default: false
+			},
+			switchChecked: {
+				type: [Boolean, String],
+				default: false
+			},
+			badgeText: {
+				type: String,
+				default: ''
+			},
+			badgeType: {
+				type: String,
+				default: 'success'
+			},
+			badgeStyle:{
+				type: Object,
+				default () {
+					return {}
+				}
+			},
+			rightText: {
+				type: String,
+				default: ''
+			},
+			thumb: {
+				type: String,
+				default: ''
+			},
+			thumbSize: {
+				type: String,
+				default: 'base'
+			},
+			showExtraIcon: {
+				type: [Boolean, String],
+				default: false
+			},
+			extraIcon: {
+				type: Object,
+				default () {
+					return {
+						type: '',
+						color: '#000000',
+						size: 20
+					};
+				}
+			},
+			border: {
+				type: Boolean,
+				default: true
+			}
+		},
+		// inject: ['list'],
+		data() {
+			return {
+				isFirstChild: false
+			};
+		},
+		mounted() {
+			this.list = this.getForm()
+			// 判断是否存在 uni-list 组件
+			if (this.list) {
+				if (!this.list.firstChildAppend) {
+					this.list.firstChildAppend = true;
+					this.isFirstChild = true;
+				}
+			}
+		},
+		methods: {
+			/**
+			 * 获取父元素实例
+			 */
+			getForm(name = 'uniList') {
+				let parent = this.$parent;
+				let parentName = parent.$options.name;
+				while (parentName !== name) {
+					parent = parent.$parent;
+					if (!parent) return false
+					parentName = parent.$options.name;
+				}
+				return parent;
+			},
+			onClick() {
+				if (this.to !== '') {
+					this.openPage();
+					return;
+				}
+				if (this.clickable || this.link) {
+					this.$emit('click', {
+						data: {}
+					});
+				}
+			},
+			onSwitchChange(e) {
+				this.$emit('switchChange', e.detail);
+			},
+			openPage() {
+				if (['navigateTo', 'redirectTo', 'reLaunch', 'switchTab'].indexOf(this.link) !== -1) {
+					this.pageApi(this.link);
+				} else {
+					this.pageApi('navigateTo');
+				}
+			},
+			pageApi(api) {
+				let callback = {
+					url: this.to,
+					success: res => {
+						this.$emit('click', {
+							data: res
+						});
+					},
+					fail: err => {
+						this.$emit('click', {
+							data: err
+						});
+					}
+				}
+				switch (api) {
+					case 'navigateTo':
+						uni.navigateTo(callback)
+						break
+					case 'redirectTo':
+						uni.redirectTo(callback)
+						break
+					case 'reLaunch':
+						uni.reLaunch(callback)
+						break
+					case 'switchTab':
+						uni.switchTab(callback)
+						break
+					default:
+					uni.navigateTo(callback)
+				}
+			}
+		}
+	};
+</script>
+
+<style lang="scss">
+	$uni-font-size-sm:12px;
+	$uni-font-size-base:14px;
+	$uni-font-size-lg:16px;
+	$uni-spacing-col-lg: 12px;
+	$uni-spacing-row-lg: 15px;
+	$uni-img-size-sm:20px;
+	$uni-img-size-base:26px;
+	$uni-img-size-lg:40px;
+	$uni-border-color:#e5e5e5;
+	$uni-bg-color-hover:#f1f1f1;
+	$uni-text-color-grey:#999;
+	$list-item-pd: $uni-spacing-col-lg $uni-spacing-row-lg;
+	.uni-list-item {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		font-size: $uni-font-size-lg;
+		position: relative;
+		justify-content: space-between;
+		align-items: center;
+		background-color: #fff;
+		flex-direction: row;
+		/* #ifdef H5 */
+		cursor: pointer;
+		/* #endif */
+	}
+	.uni-list-item--disabled {
+		opacity: 0.3;
+	}
+	.uni-list-item--hover {
+		background-color: $uni-bg-color-hover;
+	}
+	.uni-list-item__container {
+		position: relative;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		padding: $list-item-pd;
+		padding-left: $uni-spacing-row-lg;
+		flex: 1;
+		overflow: hidden;
+		// align-items: center;
+	}
+	.container--right {
+		padding-right: 0;
+	}
+	// .border--left {
+	// 	margin-left: $uni-spacing-row-lg;
+	// }
+	.uni-list--border {
+		position: absolute;
+		top: 0;
+		right: 0;
+		left: 0;
+		/* #ifdef APP-NVUE */
+		border-top-color: $uni-border-color;
+		border-top-style: solid;
+		border-top-width: 0.5px;
+		/* #endif */
+	}
+	/* #ifndef APP-NVUE */
+	.uni-list--border:after {
+		position: absolute;
+		top: 0;
+		right: 0;
+		left: 0;
+		height: 1px;
+		content: '';
+		-webkit-transform: scaleY(0.5);
+		transform: scaleY(0.5);
+		background-color: $uni-border-color;
+	}
+	/* #endif */
+	.uni-list-item__content {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		padding-right: 8px;
+		flex: 1;
+		color: #3b4144;
+		// overflow: hidden;
+		flex-direction: column;
+		justify-content: space-between;
+		overflow: hidden;
+	}
+	.uni-list-item__content--center {
+		justify-content: center;
+	}
+	.uni-list-item__content-title {
+		font-size: $uni-font-size-base;
+		color: #3b4144;
+		overflow: hidden;
+	}
+	.uni-list-item__content-note {
+		margin-top: 6rpx;
+		color: $uni-text-color-grey;
+		font-size: $uni-font-size-sm;
+		overflow: hidden;
+	}
+	.uni-list-item__extra {
+		// width: 25%;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		justify-content: flex-end;
+		align-items: center;
+	}
+	.uni-list-item__header {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		align-items: center;
+	}
+	.uni-list-item__icon {
+		margin-right: 18rpx;
+		flex-direction: row;
+		justify-content: center;
+		align-items: center;
+	}
+	.uni-list-item__icon-img {
+		/* #ifndef APP-NVUE */
+		display: block;
+		/* #endif */
+		height: $uni-img-size-base;
+		width: $uni-img-size-base;
+		margin-right: 10px;
+	}
+	.uni-icon-wrapper {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		align-items: center;
+		padding: 0 10px;
+	}
+	.flex--direction {
+		flex-direction: column;
+		/* #ifndef APP-NVUE */
+		align-items: initial;
+		/* #endif */
+	}
+	.flex--justify {
+		/* #ifndef APP-NVUE */
+		justify-content: initial;
+		/* #endif */
+	}
+	.uni-list--lg {
+		height: $uni-img-size-lg;
+		width: $uni-img-size-lg;
+	}
+	.uni-list--base {
+		height: $uni-img-size-base;
+		width: $uni-img-size-base;
+	}
+	.uni-list--sm {
+		height: $uni-img-size-sm;
+		width: $uni-img-size-sm;
+	}
+	.uni-list-item__extra-text {
+		color: $uni-text-color-grey;
+		font-size: $uni-font-size-sm;
+	}
+	.uni-ellipsis-1 {
+		/* #ifndef APP-NVUE */
+		overflow: hidden;
+		white-space: nowrap;
+		text-overflow: ellipsis;
+		/* #endif */
+		/* #ifdef APP-NVUE */
+		lines: 1;
+		text-overflow:ellipsis;
+		/* #endif */
+	}
+	.uni-ellipsis-2 {
+		/* #ifndef APP-NVUE */
+		overflow: hidden;
+		text-overflow: ellipsis;
+		display: -webkit-box;
+		-webkit-line-clamp: 2;
+		-webkit-box-orient: vertical;
+		/* #endif */
+		/* #ifdef APP-NVUE */
+		lines: 2;
+		text-overflow:ellipsis;
+		/* #endif */
+	}
+</style>

+ 108 - 0
uni_modules/uni-list/components/uni-list/uni-list.vue

@@ -0,0 +1,108 @@
+<template>
+	<!-- #ifndef APP-NVUE -->
+	<view class="uni-list uni-border-top-bottom">
+		<view v-if="border" class="uni-list--border-top"></view>
+		<slot />
+		<view v-if="border" class="uni-list--border-bottom"></view>
+	</view>
+	<!-- #endif -->
+	<!-- #ifdef APP-NVUE -->
+	<list class="uni-list" :class="{ 'uni-list--border': border }" :enableBackToTop="enableBackToTop" loadmoreoffset="15"><slot /></list>
+	<!-- #endif -->
+</template>
+
+<script>
+/**
+ * List 列表
+ * @description 列表组件
+ * @tutorial https://ext.dcloud.net.cn/plugin?id=24
+ * @property {String} 	border = [true|false] 		标题
+ */
+export default {
+	name: 'uniList',
+	'mp-weixin': {
+		options: {
+			multipleSlots: false
+		}
+	},
+	props: {
+		enableBackToTop: {
+			type: [Boolean, String],
+			default: false
+		},
+		scrollY: {
+			type: [Boolean, String],
+			default: false
+		},
+		border: {
+			type: Boolean,
+			default: true
+		}
+	},
+	// provide() {
+	// 	return {
+	// 		list: this
+	// 	};
+	// },
+	created() {
+		this.firstChildAppend = false;
+	},
+	methods: {
+		loadMore(e) {
+			this.$emit('scrolltolower');
+		}
+	}
+};
+</script>
+<style lang="scss" >
+$uni-bg-color:#ffffff;
+$uni-border-color:#e5e5e5;
+.uni-list {
+	/* #ifndef APP-NVUE */
+	display: flex;
+	/* #endif */
+	background-color: $uni-bg-color;
+	position: relative;
+	flex-direction: column;
+}
+
+.uni-list--border {
+	position: relative;
+	/* #ifdef APP-NVUE */
+	border-top-color: $uni-border-color;
+	border-top-style: solid;
+	border-top-width: 0.5px;
+	border-bottom-color: $uni-border-color;
+	border-bottom-style: solid;
+	border-bottom-width: 0.5px;
+	/* #endif */
+	z-index: -1;
+}
+
+/* #ifndef APP-NVUE */
+
+.uni-list--border-top {
+	position: absolute;
+	top: 0;
+	right: 0;
+	left: 0;
+	height: 1px;
+	-webkit-transform: scaleY(0.5);
+	transform: scaleY(0.5);
+	background-color: $uni-border-color;
+	z-index: 1;
+}
+
+.uni-list--border-bottom {
+	position: absolute;
+	bottom: 0;
+	right: 0;
+	left: 0;
+	height: 1px;
+	-webkit-transform: scaleY(0.5);
+	transform: scaleY(0.5);
+	background-color: $uni-border-color;
+}
+
+/* #endif */
+</style>

+ 65 - 0
uni_modules/uni-list/components/uni-list/uni-refresh.vue

@@ -0,0 +1,65 @@
+<template>
+    <!-- #ifdef APP-NVUE -->
+    <refresh :display="display" @refresh="onrefresh" @pullingdown="onpullingdown">
+        <slot />
+    </refresh>
+    <!-- #endif -->
+    <!-- #ifndef APP-NVUE -->
+    <view ref="uni-refresh" class="uni-refresh" v-show="isShow">
+        <slot />
+    </view>
+    <!-- #endif -->
+</template>
+
+<script>
+    export default {
+        name: 'UniRefresh',
+        props: {
+            display: {
+                type: [String],
+                default: "hide"
+            }
+        },
+        data() {
+            return {
+                pulling: false
+            }
+        },
+        computed: {
+            isShow() {
+                if (this.display === "show" || this.pulling === true) {
+                    return true;
+                }
+                return false;
+            }
+        },
+        created() {},
+        methods: {
+            onchange(value) {
+                this.pulling = value;
+            },
+            onrefresh(e) {
+                this.$emit("refresh", e);
+            },
+            onpullingdown(e) {
+                // #ifdef APP-NVUE
+                this.$emit("pullingdown", e);
+                // #endif
+                // #ifndef APP-NVUE
+                var detail = {
+                    viewHeight: 90,
+                    pullingDistance: e.height
+                }
+                this.$emit("pullingdown", detail);
+                // #endif
+            }
+        }
+    }
+</script>
+
+<style>
+    .uni-refresh {
+        height: 0;
+        overflow: hidden;
+    }
+</style>

+ 87 - 0
uni_modules/uni-list/components/uni-list/uni-refresh.wxs

@@ -0,0 +1,87 @@
+var pullDown = {
+    threshold: 95,
+    maxHeight: 200,
+    callRefresh: 'onrefresh',
+    callPullingDown: 'onpullingdown',
+    refreshSelector: '.uni-refresh'
+};
+
+function ready(newValue, oldValue, ownerInstance, instance) {
+    var state = instance.getState()
+    state.canPullDown = newValue;
+    // console.log(newValue);
+}
+
+function touchStart(e, instance) {
+    var state = instance.getState();
+    state.refreshInstance = instance.selectComponent(pullDown.refreshSelector);
+    state.canPullDown = (state.refreshInstance != null && state.refreshInstance != undefined);
+    if (!state.canPullDown) {
+        return
+    }
+
+    // console.log("touchStart");
+
+    state.height = 0;
+    state.touchStartY = e.touches[0].pageY || e.changedTouches[0].pageY;
+    state.refreshInstance.setStyle({
+        'height': 0
+    });
+    state.refreshInstance.callMethod("onchange", true);
+}
+
+function touchMove(e, ownerInstance) {
+    var instance = e.instance;
+    var state = instance.getState();
+    if (!state.canPullDown) {
+        return
+    }
+
+    var oldHeight = state.height;
+    var endY = e.touches[0].pageY || e.changedTouches[0].pageY;
+    var height = endY - state.touchStartY;
+    if (height > pullDown.maxHeight) {
+        return;
+    }
+
+    var refreshInstance = state.refreshInstance;
+    refreshInstance.setStyle({
+        'height': height + 'px'
+    });
+
+    height = height < pullDown.maxHeight ? height : pullDown.maxHeight;
+    state.height = height;
+    refreshInstance.callMethod(pullDown.callPullingDown, {
+        height: height
+    });
+}
+
+function touchEnd(e, ownerInstance) {
+    var state = e.instance.getState();
+    if (!state.canPullDown) {
+        return
+    }
+
+    state.refreshInstance.callMethod("onchange", false);
+
+    var refreshInstance = state.refreshInstance;
+    if (state.height > pullDown.threshold) {
+        refreshInstance.callMethod(pullDown.callRefresh);
+        return;
+    }
+
+    refreshInstance.setStyle({
+        'height': 0
+    });
+}
+
+function propObserver(newValue, oldValue, instance) {
+    pullDown = newValue;
+}
+
+module.exports = {
+    touchmove: touchMove,
+    touchstart: touchStart,
+    touchend: touchEnd,
+    propObserver: propObserver
+}

+ 91 - 0
uni_modules/uni-list/package.json

@@ -0,0 +1,91 @@
+{
+  "id": "uni-list",
+  "displayName": "uni-list 列表",
+  "version": "1.2.1",
+  "description": "List 组件 ,帮助使用者快速构建列表。",
+  "keywords": [
+    "",
+    "uni-ui",
+    "uniui",
+    "列表",
+    "",
+    "list"
+],
+  "repository": "https://github.com/dcloudio/uni-ui",
+  "engines": {
+    "HBuilderX": ""
+  },
+  "directories": {
+    "example": "../../temps/example_temps"
+  },
+  "dcloudext": {
+    "category": [
+      "前端组件",
+      "通用组件"
+    ],
+    "sale": {
+      "regular": {
+        "price": "0.00"
+      },
+      "sourcecode": {
+        "price": "0.00"
+      }
+    },
+    "contact": {
+      "qq": ""
+    },
+    "declaration": {
+      "ads": "无",
+      "data": "无",
+      "permissions": "无"
+    },
+    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+  },
+  "uni_modules": {
+    "dependencies": [
+      "uni-badge",
+      "uni-icons"
+    ],
+    "encrypt": [],
+    "platforms": {
+      "cloud": {
+        "tcb": "y",
+        "aliyun": "y"
+      },
+      "client": {
+        "App": {
+          "app-vue": "y",
+          "app-nvue": "y"
+        },
+        "H5-mobile": {
+          "Safari": "y",
+          "Android Browser": "y",
+          "微信浏览器(Android)": "y",
+          "QQ浏览器(Android)": "y"
+        },
+        "H5-pc": {
+          "Chrome": "y",
+          "IE": "y",
+          "Edge": "y",
+          "Firefox": "y",
+          "Safari": "y"
+        },
+        "小程序": {
+          "微信": "y",
+          "阿里": "y",
+          "百度": "y",
+          "字节跳动": "y",
+          "QQ": "y"
+        },
+        "快应用": {
+          "华为": "u",
+          "联盟": "u"
+        },
+        "Vue": {
+            "vue2": "y",
+            "vue3": "y"
+        }
+      }
+    }
+  }
+}

+ 346 - 0
uni_modules/uni-list/readme.md

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

+ 20 - 0
uni_modules/uni-pagination/changelog.md

@@ -0,0 +1,20 @@
+## 1.2.1(2021-11-22)
+- 修复 vue3中某些scss变量无法找到的问题
+## 1.2.0(2021-11-19)
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-pagination](https://uniapp.dcloud.io/component/uniui/uni-pagination)
+## 1.1.2(2021-10-08)
+- 修复 current 、value 属性未监听,导致高亮样式失效的 bug
+## 1.1.1(2021-08-20)
+- 新增 支持国际化
+## 1.1.0(2021-07-30)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 1.0.7(2021-05-12)
+- 新增 组件示例地址
+## 1.0.6(2021-04-12)
+- 新增 PC 和 移动端适配不同的 ui 
+## 1.0.5(2021-02-05)
+- 优化 组件引用关系,通过uni_modules引用组件
+
+## 1.0.4(2021-02-05)
+- 调整为uni_modules目录规范

+ 4 - 0
uni_modules/uni-pagination/components/uni-pagination/i18n/en.json

@@ -0,0 +1,4 @@
+{
+	"uni-pagination.prevText": "prev",
+	"uni-pagination.nextText": "next"
+}

+ 4 - 0
uni_modules/uni-pagination/components/uni-pagination/i18n/es.json

@@ -0,0 +1,4 @@
+{
+	"uni-pagination.prevText": "anterior",
+	"uni-pagination.nextText": "próxima"
+}

+ 4 - 0
uni_modules/uni-pagination/components/uni-pagination/i18n/fr.json

@@ -0,0 +1,4 @@
+{
+	"uni-pagination.prevText": "précédente",
+	"uni-pagination.nextText": "suivante"
+}

+ 12 - 0
uni_modules/uni-pagination/components/uni-pagination/i18n/index.js

@@ -0,0 +1,12 @@
+import en from './en.json'
+import es from './es.json'
+import fr from './fr.json'
+import zhHans from './zh-Hans.json'
+import zhHant from './zh-Hant.json'
+export default {
+	en,
+	es,
+	fr,
+	'zh-Hans': zhHans,
+	'zh-Hant': zhHant
+}

+ 4 - 0
uni_modules/uni-pagination/components/uni-pagination/i18n/zh-Hans.json

@@ -0,0 +1,4 @@
+{
+	"uni-pagination.prevText": "上一页",
+	"uni-pagination.nextText": "下一页"
+}

+ 4 - 0
uni_modules/uni-pagination/components/uni-pagination/i18n/zh-Hant.json

@@ -0,0 +1,4 @@
+{
+	"uni-pagination.prevText": "上一頁",
+	"uni-pagination.nextText": "下一頁"
+}

+ 409 - 0
uni_modules/uni-pagination/components/uni-pagination/uni-pagination.vue

@@ -0,0 +1,409 @@
+<template>
+	<view class="uni-pagination">
+		<!-- #ifndef APP-NVUE -->
+		<view class="uni-pagination__total is-phone-hide">共 {{ total }} 条</view>
+		<!-- #endif -->
+		<view class="uni-pagination__btn"
+			:class="currentIndex === 1 ? 'uni-pagination--disabled' : 'uni-pagination--enabled'"
+			:hover-class="currentIndex === 1 ? '' : 'uni-pagination--hover'" :hover-start-time="20"
+			:hover-stay-time="70" @click="clickLeft">
+			<template v-if="showIcon === true || showIcon === 'true'">
+				<uni-icons color="#666" size="16" type="left" />
+			</template>
+			<template v-else>
+				<text class="uni-pagination__child-btn">{{ prevPageText }}</text>
+			</template>
+		</view>
+		<view class="uni-pagination__num uni-pagination__num-flex-none">
+			<view class="uni-pagination__num-current">
+				<text class="uni-pagination__num-current-text is-pc-hide"
+					style="color:#409EFF">{{ currentIndex }}</text>
+				<text class="uni-pagination__num-current-text is-pc-hide">/{{ maxPage || 0 }}</text>
+				<!-- #ifndef APP-NVUE -->
+				<view v-for="(item, index) in paper" :key="index" :class="{ 'page--active': item === currentIndex }"
+					class="uni-pagination__num-tag tag--active is-phone-hide" @click.top="selectPage(item, index)">
+					<text>{{ item }}</text>
+				</view>
+				<!-- #endif -->
+
+			</view>
+		</view>
+		<view class="uni-pagination__btn"
+			:class="currentIndex >= maxPage ? 'uni-pagination--disabled' : 'uni-pagination--enabled'"
+			:hover-class="currentIndex === maxPage ? '' : 'uni-pagination--hover'" :hover-start-time="20"
+			:hover-stay-time="70" @click="clickRight">
+			<template v-if="showIcon === true || showIcon === 'true'">
+				<uni-icons color="#666" size="16" type="right" />
+			</template>
+			<template v-else>
+				<text class="uni-pagination__child-btn">{{ nextPageText }}</text>
+			</template>
+		</view>
+	</view>
+</template>
+
+<script>
+	/**
+	 * Pagination 分页器
+	 * @description 分页器组件,用于展示页码、请求数据等
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=32
+	 * @property {String} prevText 左侧按钮文字
+	 * @property {String} nextText 右侧按钮文字
+	 * @property {Number} current 当前页
+	 * @property {Number} total 数据总量
+	 * @property {Number} pageSize 每页数据量
+	 * @property {Number} showIcon = [true|false] 是否以 icon 形式展示按钮
+	 * @event {Function} change 点击页码按钮时触发 ,e={type,current} current为当前页,type值为:next/prev,表示点击的是上一页还是下一个
+	 */
+
+	import {
+		initVueI18n
+	} from '@dcloudio/uni-i18n'
+	import messages from './i18n/index.js'
+	const {
+		t
+	} = initVueI18n(messages)
+	export default {
+		name: 'UniPagination',
+		emits: ['update:modelValue', 'input', 'change'],
+		props: {
+			value: {
+				type: [Number, String],
+				default: 1
+			},
+			modelValue: {
+				type: [Number, String],
+				default: 1
+			},
+			prevText: {
+				type: String,
+			},
+			nextText: {
+				type: String,
+			},
+			current: {
+				type: [Number, String],
+				default: 1
+			},
+			total: {
+				// 数据总量
+				type: [Number, String],
+				default: 0
+			},
+			pageSize: {
+				// 每页数据量
+				type: [Number, String],
+				default: 10
+			},
+			showIcon: {
+				// 是否以 icon 形式展示按钮
+				type: [Boolean, String],
+				default: false
+			},
+			pagerCount: {
+				type: Number,
+				default: 7
+			}
+		},
+		data() {
+			return {
+				currentIndex: 1,
+				paperData: []
+			}
+		},
+		computed: {
+			prevPageText() {
+				return this.prevText || t('uni-pagination.prevText')
+			},
+			nextPageText() {
+				return this.nextText || t('uni-pagination.nextText')
+			},
+			maxPage() {
+				let maxPage = 1
+				let total = Number(this.total)
+				let pageSize = Number(this.pageSize)
+				if (total && pageSize) {
+					maxPage = Math.ceil(total / pageSize)
+				}
+				return maxPage
+			},
+			paper() {
+				const num = this.currentIndex
+				// TODO 最大页数
+				const pagerCount = this.pagerCount
+				// const total = 181
+				const total = this.total
+				const pageSize = this.pageSize
+				let totalArr = []
+				let showPagerArr = []
+				let pagerNum = Math.ceil(total / pageSize)
+				for (let i = 0; i < pagerNum; i++) {
+					totalArr.push(i + 1)
+				}
+				showPagerArr.push(1)
+				const totalNum = totalArr[totalArr.length - (pagerCount + 1) / 2]
+				totalArr.forEach((item, index) => {
+					if ((pagerCount + 1) / 2 >= num) {
+						if (item < pagerCount + 1 && item > 1) {
+							showPagerArr.push(item)
+						}
+					} else if (num + 2 <= totalNum) {
+						if (item > num - (pagerCount + 1) / 2 && item < num + (pagerCount + 1) / 2) {
+							showPagerArr.push(item)
+						}
+					} else {
+						if ((item > num - (pagerCount + 1) / 2 || pagerNum - pagerCount < item) && item < totalArr[
+								totalArr.length - 1]) {
+							showPagerArr.push(item)
+						}
+					}
+				})
+				if (pagerNum > pagerCount) {
+					if ((pagerCount + 1) / 2 >= num) {
+						showPagerArr[showPagerArr.length - 1] = '...'
+					} else if (num + 2 <= totalNum) {
+						showPagerArr[1] = '...'
+						showPagerArr[showPagerArr.length - 1] = '...'
+					} else {
+						showPagerArr[1] = '...'
+					}
+					showPagerArr.push(totalArr[totalArr.length - 1])
+				} else {
+					if ((pagerCount + 1) / 2 >= num) {} else if (num + 2 <= totalNum) {} else {
+						showPagerArr.shift()
+						showPagerArr.push(totalArr[totalArr.length - 1])
+					}
+				}
+
+				return showPagerArr
+			}
+		},
+		watch: {
+			current: {
+				immediate: true,
+				handler(val, old) {
+					if (val < 1) {
+						this.currentIndex = 1
+					} else {
+						this.currentIndex = val
+					}
+				}
+			},
+			value: {
+				immediate: true,
+				handler(val) {
+					if (Number(this.current) !== 1) return
+					if (val < 1) {
+						this.currentIndex = 1
+					} else {
+						this.currentIndex = val
+					}
+				}
+			}
+		},
+		methods: {
+			// 选择标签
+			selectPage(e, index) {
+				if (parseInt(e)) {
+					this.currentIndex = e
+					this.change('current')
+				} else {
+					let pagerNum = Math.ceil(this.total / this.pageSize)
+					// let pagerNum = Math.ceil(181 / this.pageSize)
+					// 上一页
+					if (index <= 1) {
+						if (this.currentIndex - 5 > 1) {
+							this.currentIndex -= 5
+						} else {
+							this.currentIndex = 1
+						}
+						return
+					}
+					// 下一页
+					if (index >= 6) {
+						if (this.currentIndex + 5 > pagerNum) {
+							this.currentIndex = pagerNum
+						} else {
+							this.currentIndex += 5
+						}
+						return
+					}
+				}
+			},
+			clickLeft() {
+				if (Number(this.currentIndex) === 1) {
+					return
+				}
+				this.currentIndex -= 1
+				this.change('prev')
+			},
+			clickRight() {
+				if (Number(this.currentIndex) >= this.maxPage) {
+					return
+				}
+				this.currentIndex += 1
+				this.change('next')
+			},
+			change(e) {
+				this.$emit('input', this.currentIndex)
+				this.$emit('update:modelValue', this.currentIndex)
+				this.$emit('change', {
+					type: e,
+					current: this.currentIndex
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	$uni-primary: #2979ff;
+	.uni-pagination {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		position: relative;
+		overflow: hidden;
+		flex-direction: row;
+		justify-content: center;
+		align-items: center;
+	}
+
+	.uni-pagination__total {
+		font-size: 14px;
+		color: #999;
+		margin-right: 15px;
+	}
+
+	.uni-pagination__btn {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		cursor: pointer;
+		/* #endif */
+		padding: 0 8px;
+		line-height: 30px;
+		font-size: 12px;
+		position: relative;
+		background-color: #F0F0F0;
+		flex-direction: row;
+		justify-content: center;
+		align-items: center;
+		text-align: center;
+		border-radius: 5px;
+		// border-width: 1px;
+		// border-style: solid;
+		// border-color: $uni-border-color;
+	}
+
+	.uni-pagination__child-btn {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		font-size: 12px;
+		position: relative;
+		flex-direction: row;
+		justify-content: center;
+		align-items: center;
+		text-align: center;
+		color: #666;
+		font-size: 12px;
+	}
+
+	.uni-pagination__num {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex: 1;
+		flex-direction: row;
+		justify-content: center;
+		align-items: center;
+		height: 30px;
+		line-height: 30px;
+		font-size: 12px;
+		color: #666;
+		margin: 0 5px;
+	}
+
+	.uni-pagination__num-tag {
+		/* #ifdef H5 */
+		cursor: pointer;
+		min-width: 30px;
+		/* #endif */
+		margin: 0 5px;
+		height: 30px;
+		text-align: center;
+		line-height: 30px;
+		// border: 1px red solid;
+		color: #999;
+		border-radius: 4px;
+		// border-width: 1px;
+		// border-style: solid;
+		// border-color: $uni-border-color;
+	}
+
+	.uni-pagination__num-current {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+	}
+
+	.uni-pagination__num-current-text {
+		font-size: 15px;
+	}
+
+	.uni-pagination--enabled {
+		color: #333333;
+		opacity: 1;
+	}
+
+	.uni-pagination--disabled {
+		opacity: 0.5;
+		/* #ifdef H5 */
+		cursor: default;
+		/* #endif */
+	}
+
+	.uni-pagination--hover {
+		color: rgba(0, 0, 0, 0.6);
+		background-color: #eee;
+	}
+
+	.tag--active:hover {
+		color: $uni-primary;
+	}
+
+	.page--active {
+		color: #fff;
+		background-color: $uni-primary;
+	}
+
+	.page--active:hover {
+		color: #fff;
+	}
+
+	/* #ifndef APP-NVUE */
+	.is-pc-hide {
+		display: block;
+	}
+
+	.is-phone-hide {
+		display: none;
+	}
+
+	@media screen and (min-width: 450px) {
+		.is-pc-hide {
+			display: none;
+		}
+
+		.is-phone-hide {
+			display: block;
+		}
+
+		.uni-pagination__num-flex-none {
+			flex: none;
+		}
+	}
+
+	/* #endif */
+</style>

+ 86 - 0
uni_modules/uni-pagination/package.json

@@ -0,0 +1,86 @@
+{
+  "id": "uni-pagination",
+  "displayName": "uni-pagination 分页器",
+  "version": "1.2.1",
+  "description": "Pagination 分页器组件,用于展示页码、请求数据等。",
+  "keywords": [
+    "uni-ui",
+    "uniui",
+    "分页器",
+    "页码"
+],
+  "repository": "https://github.com/dcloudio/uni-ui",
+  "engines": {
+    "HBuilderX": ""
+  },
+  "directories": {
+    "example": "../../temps/example_temps"
+  },
+  "dcloudext": {
+    "category": [
+      "前端组件",
+      "通用组件"
+    ],
+    "sale": {
+      "regular": {
+        "price": "0.00"
+      },
+      "sourcecode": {
+        "price": "0.00"
+      }
+    },
+    "contact": {
+      "qq": ""
+    },
+    "declaration": {
+      "ads": "无",
+      "data": "无",
+      "permissions": "无"
+    },
+    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+  },
+  "uni_modules": {
+    "dependencies": ["uni-scss","uni-icons"],
+    "encrypt": [],
+    "platforms": {
+      "cloud": {
+        "tcb": "y",
+        "aliyun": "y"
+      },
+      "client": {
+        "App": {
+          "app-vue": "y",
+          "app-nvue": "y"
+        },
+        "H5-mobile": {
+          "Safari": "y",
+          "Android Browser": "y",
+          "微信浏览器(Android)": "y",
+          "QQ浏览器(Android)": "y"
+        },
+        "H5-pc": {
+          "Chrome": "y",
+          "IE": "y",
+          "Edge": "y",
+          "Firefox": "y",
+          "Safari": "y"
+        },
+        "小程序": {
+          "微信": "y",
+          "阿里": "y",
+          "百度": "y",
+          "字节跳动": "y",
+          "QQ": "y"
+        },
+        "快应用": {
+          "华为": "u",
+          "联盟": "u"
+        },
+        "Vue": {
+            "vue2": "y",
+            "vue3": "y"
+        }
+      }
+    }
+  }
+}

+ 13 - 0
uni_modules/uni-pagination/readme.md

@@ -0,0 +1,13 @@
+
+
+## Pagination 分页器
+> **组件名:uni-pagination**
+> 代码块: `uPagination`
+
+
+分页器组件,用于展示页码、请求数据等。
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-pagination)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 
+
+

+ 8 - 0
uni_modules/uni-scss/changelog.md

@@ -0,0 +1,8 @@
+## 1.0.3(2022-01-21)
+- 优化 组件示例
+## 1.0.2(2021-11-22)
+- 修复 / 符号在 vue 不同版本兼容问题引起的报错问题
+## 1.0.1(2021-11-22)
+- 修复 vue3中scss语法兼容问题
+## 1.0.0(2021-11-18)
+- init

+ 1 - 0
uni_modules/uni-scss/index.scss

@@ -0,0 +1 @@
+@import './styles/index.scss';

+ 82 - 0
uni_modules/uni-scss/package.json

@@ -0,0 +1,82 @@
+{
+  "id": "uni-scss",
+  "displayName": "uni-scss 辅助样式",
+  "version": "1.0.3",
+  "description": "uni-sass是uni-ui提供的一套全局样式 ,通过一些简单的类名和sass变量,实现简单的页面布局操作,比如颜色、边距、圆角等。",
+  "keywords": [
+    "uni-scss",
+    "uni-ui",
+    "辅助样式"
+],
+  "repository": "https://github.com/dcloudio/uni-ui",
+  "engines": {
+    "HBuilderX": "^3.1.0"
+  },
+  "dcloudext": {
+    "category": [
+        "JS SDK",
+        "通用 SDK"
+    ],
+    "sale": {
+      "regular": {
+        "price": "0.00"
+      },
+      "sourcecode": {
+        "price": "0.00"
+      }
+    },
+    "contact": {
+      "qq": ""
+    },
+    "declaration": {
+      "ads": "无",
+      "data": "无",
+      "permissions": "无"
+    },
+    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+  },
+  "uni_modules": {
+    "dependencies": [],
+    "encrypt": [],
+    "platforms": {
+      "cloud": {
+        "tcb": "y",
+        "aliyun": "y"
+      },
+      "client": {
+        "App": {
+          "app-vue": "y",
+          "app-nvue": "u"
+        },
+        "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"
+        },
+        "快应用": {
+          "华为": "n",
+          "联盟": "n"
+        },
+        "Vue": {
+            "vue2": "y",
+            "vue3": "y"
+        }
+      }
+    }
+  }
+}

+ 4 - 0
uni_modules/uni-scss/readme.md

@@ -0,0 +1,4 @@
+`uni-sass` 是 `uni-ui`提供的一套全局样式 ,通过一些简单的类名和`sass`变量,实现简单的页面布局操作,比如颜色、边距、圆角等。
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-sass)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 

+ 7 - 0
uni_modules/uni-scss/styles/index.scss

@@ -0,0 +1,7 @@
+@import './setting/_variables.scss';
+@import './setting/_border.scss';
+@import './setting/_color.scss';
+@import './setting/_space.scss';
+@import './setting/_radius.scss';
+@import './setting/_text.scss';
+@import './setting/_styles.scss';

+ 3 - 0
uni_modules/uni-scss/styles/setting/_border.scss

@@ -0,0 +1,3 @@
+.uni-border {
+	border: 1px $uni-border-1 solid;
+}

+ 0 - 0
uni_modules/uni-scss/styles/setting/_color.scss


Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor